खोज…
टिप्पणियों
यह विषय विभिन्न मीडिया प्रकारों को कवर करने के लिए है और उन्हें 2 डी इंटरफेस में कैनवास के साथ कैसे उपयोग किया जा सकता है।
मीडिया प्रकारों में सामान्य और प्रारूपिक श्रेणियां होती हैं
मीडिया प्रकार
- एनिमेशन
- वीडियो
- इमेजिस
- HD छवियों
- वेक्टर छवि
- एनिमेटेड छवियाँ
मीडिया प्रारूप
- JPG / JPEG
- Png
- Gif
- एसवीजी
- एम-जेपीईजी
- webm
- webp
इमेजिस
ब्राउज़र द्वारा समर्थित कई प्रकार के छवि प्रारूप हैं, हालांकि कोई भी ब्राउज़र उन सभी का समर्थन नहीं करता है। यदि आपके पास विशेष छवि प्रारूप हैं, तो आप विकी ब्राउज़र का उपयोग करना चाहते हैं और समर्थित छवि प्रारूप एक अच्छा अवलोकन प्रदान करता है।
सबसे अच्छा समर्थन 3 मुख्य प्रारूपों के लिए है, "जेपीईजी", "पीएनजी", और "जीआईएफ" सभी प्रमुख ब्राउज़रों के साथ समर्थन प्रदान करते हैं।
जेपीईजी
JPEG छवियां फ़ोटो और फ़ोटो जैसी छवियों के लिए सबसे उपयुक्त हैं। वे उन्हें चार्ट, आरेख और पाठ के लिए अच्छी तरह से उधार नहीं देते हैं। JPEG छवियां पारदर्शिता का समर्थन नहीं करती हैं।
के माध्यम से कैनवास कर सकते हैं उत्पादन JPEG चित्रों canvas.toDataURL
और canvas.toBlob
और एक गुणवत्ता सेटिंग प्रदान करता है। चूंकि जेपीईजी पारदर्शिता का समर्थन नहीं करता है इसलिए किसी भी पारदर्शी पिक्सल को अंतिम आउटपुट जेपीजी के लिए काले रंग के साथ मिश्रित किया जाएगा। परिणामी छवि कैनवास की एक संपूर्ण प्रतिलिपि नहीं होगी।
पीएनजी
पीएनजी छवि उच्चतम गुणवत्ता वाली छवियां हैं और इसमें पारदर्शी पिक्सल के लिए एक अल्फा चैनल भी शामिल हो सकता है। छवि डेटा संपीड़ित है, लेकिन जेपीजी छवियों जैसी कलाकृतियों का उत्पादन नहीं करता है।
दोषरहित संपीड़न और अल्फा चैनल सपोर्ट की वजह से PNG का उपयोग गेम्स, यूआई कंपोनेंट इमेज, चार्ट, डायग्राम, टेक्स्ट के लिए किया जाता है। फ़ोटो और फ़ोटो जैसी छवियों के लिए उनका उपयोग करते समय उनकी फ़ाइल का आकार JPEG की तुलना में बहुत बड़ा हो सकता है। ।
PNG प्रारूप भी एनीमेशन समर्थन प्रदान करता है हालांकि ब्राउज़र समर्थन सीमित है, और कैनवास पर उपयोग के लिए एनीमेशन तक पहुंच केवल जावास्क्रिप्ट एपीआई और पुस्तकालयों के माध्यम से किया जा सकता है
THe कैनवस का उपयोग पीएनजी छवियों को canvas.toDataURL
माध्यम से एन्कोड करने के लिए किया जा सकता है canvas.toDataURL
और canvas.toBlob
हालांकि आउटपुट फॉर्मेट canvas.toBlob
RGBA को संकुचित करने के लिए सीमित है। PNG कैनवास की एक पिक्सेल सही प्रतिलिपि प्रदान करेगा।
GIF
GIF का उपयोग लघु एनिमेशन के लिए किया जाता है, लेकिन इसका उपयोग उच्च गुणवत्ता वाले चार्ट, आरेख और चित्र जैसे पाठ प्रदान करने के लिए भी किया जा सकता है। जीआईएफ में प्रति फ्रेम अधिकतम 256 रंगों के साथ बहुत सीमित रंग का समर्थन है। क्लीवर इमेज प्रोसेसिंग के साथ जिफ इमेज आश्चर्यजनक रूप से अच्छे परिणाम दे सकती हैं, खासकर जब एनिमेटेड। Gifs पारदर्शिता प्रदान करते हैं, हालांकि यह चालू या बंद है
पीएनजी के साथ, जीआईएफ एनिमेशन सीधे कैनवास पर उपयोग के लिए सुलभ नहीं हैं और एक्सेस पाने के लिए आपको जावास्क्रिप्ट एपीआई या लाइब्रेरी की आवश्यकता होगी। जीआईएफ को कैनवास के माध्यम से नहीं बचाया जा सकता है और ऐसा करने के लिए एपीआई और लाइब्रेरी की आवश्यकता होगी।
एक छवि को लोड करना और प्रदर्शित करना
एक छवि को लोड करने और कैनवास पर रखने के लिए
var image = new Image(); // see note on creating an image
image.src = "imageURL";
image.onload = function(){
ctx.drawImage(this,0,0);
}
एक छवि बनाना
छवि बनाने के कई तरीके हैं
-
new Image()
-
document.createElement("img")
-
<img src = 'imageUrl' id='myImage'>
HTML बॉडी के हिस्से के रूप में औरdocument.getElementById('myImage')
साथ पुनः प्राप्त किया गयाdocument.getElementById('myImage')
छवि एक HTMLImageElement
छवि। संपत्ति संपत्ति
छवि src
किसी भी मान्य छवि URL या एन्कोडेड dataURL हो सकती है। छवि स्वरूपों और समर्थन के बारे में अधिक जानकारी के लिए इस विषय के रिमार्क्स देखें।
-
image.src = "http://my.domain.com/images/myImage.jpg"
-
image.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="
*
* DataURL एक 1 बाय 1 पिक्सेल gif छवि वाला काला है
लोडिंग और त्रुटियों पर टिप्पणी
जब उसकी src प्रॉपर्टी सेट हो जाएगी तो इमेज लोड होना शुरू हो जाएगी। लोड हो रहा है syncriouse है, लेकिन onload
/ लौटे जब तक समारोह या कोड से बाहर निकल गया है घटना कहा जाता नहीं किया जाएगा।
यदि आपको पृष्ठ से छवि मिलती है (उदाहरण के लिए document.getElementById("myImage")
) और इसका src
सेट है तो यह लोड हो सकता है या नहीं भी हो सकता है। आप HTMLImageElement.complete
साथ छवि की स्थिति की जांच कर सकते हैं जो पूर्ण होने पर true
होगी। इसका मतलब यह नहीं है कि छवि लोड हो गई है, इसका मतलब है कि यह या तो है
- लदा हुआ
- एक त्रुटि हुई
- src गुण सेट नहीं किया गया है और खाली स्ट्रिंग के बराबर है
""
यदि छवि एक अविश्वसनीय स्रोत से है और कई कारणों से सुलभ नहीं हो सकती है तो यह एक त्रुटि घटना उत्पन्न करेगा। जब ऐसा होता है तो छवि टूटी अवस्था में होगी। यदि आप इसे कैनवास पर खींचने का प्रयास करते हैं, तो यह निम्न त्रुटि देगा
Uncaught DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.
image.onerror = myImgErrorHandler
घटना को आपूर्ति करके आप त्रुटियों को रोकने के लिए उचित कार्रवाई कर सकते हैं।
एक svg छवि खींचना
एक वेक्टर एसवीजी छवि बनाने के लिए, ऑपरेशन एक रेखापुंज छवि से अलग नहीं है:
आपको पहले अपनी SVG छवि को HTMLImage तत्व में लोड करने की आवश्यकता है, फिर drawImage drawImage()
विधि का उपयोग करें।
var image = new Image();
image.onload = function(){
ctx.drawImage(this, 0,0);
}
image.src = "someFile.SVG";
एसवीजी छवियों के रैस्टर पर कुछ फायदे हैं, क्योंकि आप गुणवत्ता को ढीले नहीं करेंगे, जो भी आप इसे अपने कैनवास पर खींचेंगे। लेकिन सावधान रहना, यह एक रेखापुंज छवि बनाने की तुलना में थोड़ा धीमा हो सकता है।
हालांकि, एसवीजी छवियां रेखापुंज छवियों की तुलना में अधिक प्रतिबंधों के साथ आती हैं।
सुरक्षा उद्देश्य के लिए, किसी भी बाहरी सामग्री को HTMLImageElement (
<img>
) में संदर्भित एसवीजी छवि से लोड नहीं किया जा सकता है
कोई बाहरी स्टाइलशीट, SVGImage (<image/>
) तत्वों में संदर्भित कोई बाहरी छवि, xlink द्वारा लिंक किया गया कोई बाहरी फ़िल्टर या तत्व नहींxlink:href
विशेषता (<use xlink:href="anImage.SVG#anElement"/>
) या funcIRI (url()
) विशेषता विधि आदि।
HTMLImage तत्व में संदर्भित होने के बाद, मुख्य दस्तावेज़ में संलग्न स्टाइलशीट का SVG दस्तावेज़ पर कोई प्रभाव नहीं पड़ेगा।
अंत में, एसवीजी छवि के अंदर कोई स्क्रिप्ट निष्पादित नहीं की जाएगी।
समाधान: आपको HTMLImage तत्व का संदर्भ देने से पहले SVG के अंदर सभी बाहरी तत्वों को जोड़ना होगा। (छवियों या फोंट के लिए, आपको अपने बाहरी संसाधनों के डेटा संस्करण को संलग्न करना होगा)।मूल तत्व (
<svg>
) की चौड़ाई और ऊंचाई के गुण एक निरपेक्ष मान के लिए निर्धारित होने चाहिए।
यदि आप सापेक्ष लंबाई (जैसे%
) का उपयोग करने वाले थे, तो ब्राउज़र को यह पता नहीं चल पाएगा कि यह क्या है। कुछ ब्राउज़र (ब्लिंक) एक अनुमान लगाने की कोशिश करेंगे, लेकिन अधिकांश बस आपकी छवि को अनदेखा करेंगे और चेतावनी के बिना, कुछ भी आकर्षित नहीं करेंगे।कुछ ब्राउज़र कैनवस को तब दागदार करेंगे जब एक एसवीजी छवि को इसके लिए तैयार किया गया है।
विशेष रूप से, इंटरनेट-एक्सप्लोरर <एज किसी भी मामले में, और सफारी 9 जब एक<foreignObject>
एसवीजी छवि में मौजूद है।
मूल लोड हो रहा है और कैनवास पर एक वीडियो चला रहा है।
विभिन्न स्रोतों से वीडियो प्रदर्शित करने के लिए कैनवास का उपयोग किया जा सकता है। यह उदाहरण दिखाता है कि वीडियो को फ़ाइल संसाधन के रूप में कैसे लोड किया जाए, इसे प्रदर्शित करें और स्क्रीन प्ले / पॉज टॉगल पर एक साधारण क्लिक जोड़ें।
यह स्टैकओवरफ़्लो स्वप्रमाणित प्रश्न है कि मैं एचटीएमएल 5 कैनवास टैग का उपयोग करके वीडियो कैसे प्रदर्शित करता हूं , निम्न उदाहरण कोड को कार्रवाई में दिखाता है।
बस एक छवि
एक वीडियो सिर्फ एक छवि है जहां तक कैनवास का संबंध है। आप इसे किसी भी छवि की तरह आकर्षित कर सकते हैं। वीडियो के खेलने और ध्वनि में अंतर हो सकता है।
कैनवास और मूल सेटअप प्राप्त करें
// It is assumed you know how to add a canvas and correctly size it.
var canvas = document.getElementById("myCanvas"); // get the canvas from the page
var ctx = canvas.getContext("2d");
var videoContainer; // object to hold video and associated info
वीडियो बनाना और लोड करना
var video = document.createElement("video"); // create a video element
video.src = "urlOffVideo.webm";
// the video will now begin to load.
// As some additional info is needed we will place the video in a
// containing object for convenience
video.autoPlay = false; // ensure that the video does not auto play
video.loop = true; // set the video to loop.
videoContainer = { // we will add properties as needed
video : video,
ready : false,
};
छवियों तत्वों के विपरीत वीडियो को कैनवास पर प्रदर्शित होने के लिए पूरी तरह से लोड होने की आवश्यकता नहीं है। वीडियो अतिरिक्त घटनाओं की एक मेजबान भी प्रदान करते हैं जिनका उपयोग वीडियो की स्थिति की निगरानी के लिए किया जा सकता है।
इस मामले में हम जानना चाहते हैं कि वीडियो कब खेलने के लिए तैयार है। oncanplay
मतलब है कि इसमें से कुछ को खेलने के लिए पर्याप्त वीडियो लोड किया गया है, लेकिन अंत तक खेलने के लिए पर्याप्त नहीं हो सकता है।
video.oncanplay = readyToPlayVideo; // set the event to the play function that
// can be found below
वैकल्पिक रूप से आप oncanplaythrough
उपयोग कर सकते हैं जो कि पर्याप्त वीडियो लोड होने पर आग oncanplaythrough
ताकि इसे अंत तक खेला जा सके।
video.oncanplaythrough = readyToPlayVideo; // set the event to the play function that
// can be found below
केवल canPlay घटनाओं में से एक का उपयोग करें दोनों नहीं।
ईवेंट खेल सकते हैं (छवि भार के बराबर)
function readyToPlayVideo(event){ // this is a referance to the video
// the video may not match the canvas size so find a scale to fit
videoContainer.scale = Math.min(
canvas.width / this.videoWidth,
canvas.height / this.videoHeight);
videoContainer.ready = true;
// the video can be played so hand it off to the display function
requestAnimationFrame(undateCanvas);
}
प्रदर्शित
वीडियो कैनवास पर खुद नहीं चलेगा। आपको इसे हर नए फ्रेम के लिए तैयार करना होगा। जैसा कि सटीक फ्रेम दर को जानना मुश्किल है और जब वे सबसे अच्छे होते हैं तो वीडियो प्रदर्शित करना होता है जैसे कि 60fps पर चल रहा हो। यदि फ्रेम दर कम है, तो डब्ल्यू एक ही फ्रेम को दो बार प्रस्तुत करना चाहिए। यदि फ्रेम दर अधिक है तो ऐसा कुछ भी नहीं है जो अतिरिक्त फ्रेम को देखने के लिए डॉन नहीं हो सकता है इसलिए हम उन्हें अनदेखा करते हैं।
वीडियो तत्व सिर्फ एक छवि तत्व है और इसे किसी भी छवि की तरह आकर्षित किया जा सकता है, आप वीडियो को स्केल कर सकते हैं, घुमा सकते हैं, इसे मिरर कर सकते हैं, इसे फीका कर सकते हैं, इसे क्लिप कर सकते हैं और केवल भागों को प्रदर्शित कर सकते हैं, इसे दूसरी बार एक वैश्विक समग्र मोड के साथ दो बार ड्रा कर सकते हैं। प्रकाश, स्क्रीन, आदि जैसे FX जोड़ने के लिए।
function updateCanvas(){
ctx.clearRect(0,0,canvas.width,canvas.height); // Though not always needed
// you may get bad pixels from
// previous videos so clear to be
// safe
// only draw if loaded and ready
if(videoContainer !== undefined && videoContainer.ready){
// find the top left of the video on the canvas
var scale = videoContainer.scale;
var vidH = videoContainer.video.videoHeight;
var vidW = videoContainer.video.videoWidth;
var top = canvas.height / 2 - (vidH /2 ) * scale;
var left = canvas.width / 2 - (vidW /2 ) * scale;
// now just draw the video the correct size
ctx.drawImage(videoContainer.video, left, top, vidW * scale, vidH * scale);
if(videoContainer.video.paused){ // if not playing show the paused screen
drawPayIcon();
}
}
// all done for display
// request the next frame in 1/60th of a second
requestAnimationFrame(updateCanvas);
}
बेसिक प्ले पॉज़ कंट्रोल
अब हमारे पास वीडियो लोड है और हमें जो भी चाहिए वह है प्ले कंट्रोल। हम इसे स्क्रीन पर एक क्लिक टॉगल प्ले के रूप में बनाएंगे। जब वीडियो चल रहा होता है और उपयोगकर्ता क्लिक करता है तो वीडियो रोक दिया जाता है। जब रुका हुआ प्ले फिर से शुरू होता है। हम वीडियो को काला करने के लिए एक फ़ंक्शन जोड़ेंगे और एक प्ले आइकन (त्रिकोण) आकर्षित करेंगे
function drawPayIcon(){
ctx.fillStyle = "black"; // darken display
ctx.globalAlpha = 0.5;
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "#DDD"; // colour of play icon
ctx.globalAlpha = 0.75; // partly transparent
ctx.beginPath(); // create the path for the icon
var size = (canvas.height / 2) * 0.5; // the size of the icon
ctx.moveTo(canvas.width/2 + size/2, canvas.height / 2); // start at the pointy end
ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 + size);
ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 - size);
ctx.closePath();
ctx.fill();
ctx.globalAlpha = 1; // restore alpha
}
अब नाटक रुकने की घटना
function playPauseClick(){
if(videoContainer !== undefined && videoContainer.ready){
if(videoContainer.video.paused){
videoContainer.video.play();
}else{
videoContainer.video.pause();
}
}
}
// register the event
canvas.addEventListener("click",playPauseClick);
सारांश
कैनवास का उपयोग करके वीडियो चलाना बहुत आसान है, वास्तविक समय में प्रभाव जोड़ना भी आसान है। हालांकि स्वरूपों पर कुछ सीमाएँ हैं, आप कैसे खेल सकते हैं। MDN HTMLMediaElement वीडियो ऑब्जेक्ट के लिए पूर्ण संदर्भ प्राप्त करने का स्थान है।
एक बार छवि को कैनवास पर खींचा जाने के बाद आप इसमें शामिल पिक्सेल तक पहुंचने के लिए ctx.getImageData
का उपयोग कर सकते हैं। या आप अभी भी स्नैप और इसे डाउनलोड करने के लिए canvas.toDataURL
का उपयोग कर सकते हैं। (केवल अगर वीडियो एक विश्वसनीय स्रोत से है और कैनवस को दागी नहीं करता है)।
ध्यान दें अगर वीडियो में साउंड है तो उसे प्ले करने से भी साउंड बजा होगा।
हैप्पी वीडियोिंग।
वेब कैमरा वीडियो के रूप में कैनवस और सेव कैप्चर करें
कैनवास फ्रेम से एक वेबएम वीडियो बनाना और कैनवास में खेलना, या अपलोड या डाउनलोड करना।
उदाहरण कैद और प्ले कैनवास
name = "CanvasCapture"; // Placed into the Mux and Write Application Name fields of the WebM header
quality = 0.7; // good quality 1 Best < 0.7 ok to poor
fps = 30; // I have tried all sorts of frame rates and all seem to work
// Do some test to workout what your machine can handle as there
// is a lot of variation between machines.
var video = new Groover.Video(fps,quality,name)
function capture(){
if(video.timecode < 5000){ // 5 seconds
setTimeout(capture,video.frameDelay);
}else{
var videoElement = document.createElement("video");
videoElement.src = URL.createObjectURL(video.toBlob());
document.body.appendChild(videoElement);
video = undefined; // DeReference as it is memory hungry.
return;
}
// first frame sets the video size
video.addFrame(canvas); // Add current canvas frame
}
capture(); // start capture
केवल अस्वीकार किए जाने वाले भारी प्रयास में डालने के बजाय, यह स्वीकार्य है कि देखने के लिए एक त्वरित प्रविष्टि है। स्वीकार किए जाने पर पूर्ण विवरण देंगे। बेहतर HD कैप्चर दरों के लिए अतिरिक्त कैप्चर विकल्प भी शामिल करें (इस संस्करण से हटाए गए, अच्छी मशीनों पर 50fps पर HD 1080 पर कब्जा कर सकते हैं।)
यह वाममी से प्रेरित था, लेकिन एनकोड के साथ पूरी तरह से फिर से लिखना है क्योंकि आप कार्यप्रणाली पर जाते हैं, कैप्चर के दौरान आवश्यक मेमोरी को बहुत कम करते हैं। एल्गोरिदम को संभालते हुए 30 सेकंड से अधिक बेहतर डेटा पर कब्जा कर सकते हैं।
नोट फ़्रेम वेबप छवियों में एन्कोड किए गए हैं। केवल Chrome वेबप कैनवास एन्कोडिंग का समर्थन करता है। अन्य ब्राउज़रों (फ़ायरफ़ॉक्स और एज) के लिए आपको एक 3 पार्टी वेबपीस एनकोडर का उपयोग करना होगा जैसे कि जावास्क्रिप्ट के माध्यम से लिबवेप जावास्क्रिप्ट एनकोडिंग वेबपी छवियों को धीमा करना। (यदि स्वीकार किए जाते हैं तो कच्चे वेबप छवियों का समर्थन शामिल होगा)।
WebM एनकोडर Whammy से प्रेरित : एक वास्तविक समय जावास्क्रिप्ट WebM
var Groover = (function(){
// ensure webp is supported
function canEncode(){
var canvas = document.createElement("canvas");
canvas.width = 8;
canvas.height = 8;
return canvas.toDataURL("image/webp",0.1).indexOf("image/webp") > -1;
}
if(!canEncode()){
return undefined;
}
var webmData = null;
var clusterTimecode = 0;
var clusterCounter = 0;
var CLUSTER_MAX_DURATION = 30000;
var frameNumber = 0;
var width;
var height;
var frameDelay;
var quality;
var name;
const videoMimeType = "video/webm"; // the only one.
const frameMimeType = 'image/webp'; // can be no other
const S = String.fromCharCode;
const dataTypes = {
object : function(data){ return toBlob(data);},
number : function(data){ return stream.num(data);},
string : function(data){ return stream.str(data);},
array : function(data){ return data;},
double2Str : function(num){
var c = new Uint8Array((new Float64Array([num])).buffer);
return S(c[7]) + S(c[6]) + S(c[5]) + S(c[4]) + S(c[3]) + S(c[2]) + S(c[1]) + S(c[0]);
}
};
const stream = {
num : function(num){ // writes int
var parts = [];
while(num > 0){ parts.push(num & 0xff); num = num >> 8; }
return new Uint8Array(parts.reverse());
},
str : function(str){ // writes string
var i, len, arr;
len = str.length;
arr = new Uint8Array(len);
for(i = 0; i < len; i++){arr[i] = str.charCodeAt(i);}
return arr;
},
compInt : function(num){ // could not find full details so bit of a guess
if(num < 128){ // number is prefixed with a bit (1000 is on byte 0100 two, 0010 three and so on)
num += 0x80;
return new Uint8Array([num]);
}else
if(num < 0x4000){
num += 0x4000;
return new Uint8Array([num>>8, num])
}else
if(num < 0x200000){
num += 0x200000;
return new Uint8Array([num>>16, num>>8, num])
}else
if(num < 0x10000000){
num += 0x10000000;
return new Uint8Array([num>>24, num>>16, num>>8, num])
}
}
}
const ids = { // header names and values
videoData : 0x1a45dfa3,
Version : 0x4286,
ReadVersion : 0x42f7,
MaxIDLength : 0x42f2,
MaxSizeLength : 0x42f3,
DocType : 0x4282,
DocTypeVersion : 0x4287,
DocTypeReadVersion : 0x4285,
Segment : 0x18538067,
Info : 0x1549a966,
TimecodeScale : 0x2ad7b1,
MuxingApp : 0x4d80,
WritingApp : 0x5741,
Duration : 0x4489,
Tracks : 0x1654ae6b,
TrackEntry : 0xae,
TrackNumber : 0xd7,
TrackUID : 0x63c5,
FlagLacing : 0x9c,
Language : 0x22b59c,
CodecID : 0x86,
CodecName : 0x258688,
TrackType : 0x83,
Video : 0xe0,
PixelWidth : 0xb0,
PixelHeight : 0xba,
Cluster : 0x1f43b675,
Timecode : 0xe7,
Frame : 0xa3,
Keyframe : 0x9d012a,
FrameBlock : 0x81,
};
const keyframeD64Header = '\x9d\x01\x2a'; //VP8 keyframe header 0x9d012a
const videoDataPos = 1; // data pos of frame data header
const defaultDelay = dataTypes.double2Str(1000/25);
const header = [ // structure of webM header/chunks what ever they are called.
ids.videoData,[
ids.Version, 1,
ids.ReadVersion, 1,
ids.MaxIDLength, 4,
ids.MaxSizeLength, 8,
ids.DocType, 'webm',
ids.DocTypeVersion, 2,
ids.DocTypeReadVersion, 2
],
ids.Segment, [
ids.Info, [
ids.TimecodeScale, 1000000,
ids.MuxingApp, 'Groover',
ids.WritingApp, 'Groover',
ids.Duration, 0
],
ids.Tracks,[
ids.TrackEntry,[
ids.TrackNumber, 1,
ids.TrackUID, 1,
ids.FlagLacing, 0, // always o
ids.Language, 'und', // undefined I think this means
ids.CodecID, 'V_VP8', // These I think must not change
ids.CodecName, 'VP8', // These I think must not change
ids.TrackType, 1,
ids.Video, [
ids.PixelWidth, 0,
ids.PixelHeight, 0
]
]
]
]
];
function getHeader(){
header[3][2][3] = name;
header[3][2][5] = name;
header[3][2][7] = dataTypes.double2Str(frameDelay);
header[3][3][1][15][1] = width;
header[3][3][1][15][3] = height;
function create(dat){
var i,kv,data;
data = [];
for(i = 0; i < dat.length; i += 2){
kv = {i : dat[i]};
if(Array.isArray(dat[i + 1])){
kv.d = create(dat[i + 1]);
}else{
kv.d = dat[i + 1];
}
data.push(kv);
}
return data;
}
return create(header);
}
function addCluster(){
webmData[videoDataPos].d.push({ i: ids.Cluster,d: [{ i: ids.Timecode, d: Math.round(clusterTimecode)}]}); // Fixed bug with Round
clusterCounter = 0;
}
function addFrame(frame){
var VP8, kfS,riff;
riff = getWebPChunks(atob(frame.toDataURL(frameMimeType, quality).slice(23)));
VP8 = riff.RIFF[0].WEBP[0];
kfS = VP8.indexOf(keyframeD64Header) + 3;
frame = {
width: ((VP8.charCodeAt(kfS + 1) << 8) | VP8.charCodeAt(kfS)) & 0x3FFF,
height: ((VP8.charCodeAt(kfS + 3) << 8) | VP8.charCodeAt(kfS + 2)) & 0x3FFF,
data: VP8,
riff: riff
};
if(clusterCounter > CLUSTER_MAX_DURATION){
addCluster();
}
webmData[videoDataPos].d[webmData[videoDataPos].d.length-1].d.push({
i: ids.Frame,
d: S(ids.FrameBlock) + S( Math.round(clusterCounter) >> 8) + S( Math.round(clusterCounter) & 0xff) + S(128) + frame.data.slice(4),
});
clusterCounter += frameDelay;
clusterTimecode += frameDelay;
webmData[videoDataPos].d[0].d[3].d = dataTypes.double2Str(clusterTimecode);
}
function startEncoding(){
frameNumber = clusterCounter = clusterTimecode = 0;
webmData = getHeader();
addCluster();
}
function toBlob(vidData){
var data,i,vData, len;
vData = [];
for(i = 0; i < vidData.length; i++){
data = dataTypes[typeof vidData[i].d](vidData[i].d);
len = data.size || data.byteLength || data.length;
vData.push(stream.num(vidData[i].i));
vData.push(stream.compInt(len));
vData.push(data)
}
return new Blob(vData, {type: videoMimeType});
}
function getWebPChunks(str){
var offset, chunks, id, len, data;
offset = 0;
chunks = {};
while (offset < str.length) {
id = str.substr(offset, 4);
// value will have top bit on (bit 32) so not simply a bitwise operation
// Warning little endian (Will not work on big endian systems)
len = new Uint32Array(
new Uint8Array([
str.charCodeAt(offset + 7),
str.charCodeAt(offset + 6),
str.charCodeAt(offset + 5),
str.charCodeAt(offset + 4)
]).buffer)[0];
id = str.substr(offset, 4);
chunks[id] = chunks[id] === undefined ? [] : chunks[id];
if (id === 'RIFF' || id === 'LIST') {
chunks[id].push(getWebPChunks(str.substr(offset + 8, len)));
offset += 8 + len;
} else if (id === 'WEBP') {
chunks[id].push(str.substr(offset + 8));
break;
} else {
chunks[id].push(str.substr(offset + 4));
break;
}
}
return chunks;
}
function Encoder(fps, _quality = 0.8, _name = "Groover"){
this.fps = fps;
this.quality = quality = _quality;
this.frameDelay = frameDelay = 1000 / fps;
this.frame = 0;
this.width = width = null;
this.timecode = 0;
this.name = name = _name;
}
Encoder.prototype = {
addFrame : function(frame){
if('canvas' in frame){
frame = frame.canvas;
}
if(width === null){
this.width = width = frame.width,
this.height = height = frame.height
startEncoding();
}else
if(width !== frame.width || height !== frame.height){
throw RangeError("Frame size error. Frames must be the same size.");
}
addFrame(frame);
this.frame += 1;
this.timecode = clusterTimecode;
},
toBlob : function(){
return toBlob(webmData);
}
}
return {
Video: Encoder,
}
})()