2015-09-21 9 views
7

निकालें मैं क्लाइंट-साइड प्रोजेक्ट पर काम कर रहा हूं जो उपयोगकर्ता को वीडियो फ़ाइल की आपूर्ति करने और इसमें बुनियादी कुशलता लागू करने देता है। मैं विश्वसनीय रूप से वीडियो से फ्रेम निकालने की कोशिश कर रहा हूं।जावास्क्रिप्ट: वीडियो फ्रेम को विश्वसनीय रूप से

  1. शुरुआत
  2. पर सीक वीडियो रोकें
  3. एक <canvas>
  4. को ड्रा <video>: इस समय मैं एक <video> जो मैं में चयनित वीडियो लोड हो रहा है कर रहा हूँ, और फिर प्रत्येक फ्रेम बाहर खींच के रूप में निम्नानुसार है
  5. .toDataUrl()
  6. के साथ कैनवास से फ्रेम को कैप्चर करें 1/30 सेकंड (1 फ्रेम) द्वारा आगे की तलाश करें।
  7. रिंस और दोहराने

यह एक नहीं बल्कि अक्षम प्रक्रिया है, और अधिक विशेष रूप से, अविश्वसनीय साबित के रूप में मैं अक्सर हूँ हो रही फ्रेम फंस गया है। ऐसा लगता है कि यह कैनवास पर आकर्षित होने से पहले वास्तविक <video> तत्व अद्यतन नहीं कर रहा है।

मुझे फ़्रेम को विभाजित करने के लिए सर्वर पर मूल वीडियो अपलोड करने की आवश्यकता नहीं है, और फिर उन्हें क्लाइंट पर वापस डाउनलोड करना होगा।

ऐसा करने के बेहतर तरीके के लिए कोई सुझाव बहुत सराहना की जाती है। एकमात्र चेतावनी यह है कि मुझे ब्राउजर का समर्थन करने वाले किसी प्रारूप के साथ काम करने की आवश्यकता है (जेएस में डीकोडिंग एक अच्छा विकल्प नहीं है)।

+0

:

तो, मैं तो जैसे कि यह करना होगा। लेकिन स्पष्ट रूप से, यदि आपको क्लाइंट पक्ष पर ऐसा करने की आवश्यकता नहीं है, तो उसके लिए ब्राउज़र का उपयोग न करें, ffmpeg या कोई भी वीडियो टूल इसके लिए अधिक शक्तिशाली होगा। – Kaiido

+0

@ Kalido मैं इसे सर्वर की तरफ संभालता हूं, लेकिन वीडियो क्लाइंट से आता है, और मुझे क्लाइंट पर फ्रेम की आवश्यकता है, इसलिए यदि मैं अपलोड/डाउनलोड चक्र से बच सकता हूं, तो मैं बहुत बेहतर होगा। साथ ही, जहां तक ​​मांग है, मुझे धीमे डिवाइसों को फ्रेम छोड़ने में समस्याएं थीं क्योंकि वे फ्रेम डेटा को जल्दी से पकड़ने में संभाल नहीं सकते हैं, हालांकि, मैं 'टाइमअपडेट' ईवेंट से परिचित नहीं हूं, इसलिए मैं इसे देखूंगा । साथ ही, प्रत्येक फ्रेम के लिए खोज समय निर्दिष्ट करके, यदि आवश्यकता हो तो मैं फ़्रेमेट को नियंत्रित कर सकता हूं। –

+0

ठीक है, तो कृपया आप अपने प्रश्न के संपादन में इस बिंदु को स्पष्ट कर सकते हैं (कि यह एक वेबसाइट, क्लाइंट साइड के लिए है), जो बिल्कुल स्पष्ट नहीं था। साथ ही, ब्राउज़र में फ़्रेमेट बिल्कुल स्थिर नहीं है, इसलिए आपको उस पर भरोसा नहीं करना चाहिए। लेकिन चित्रित प्रत्येक नए फ्रेम पर, टाइमअपडेट घटना ट्रिगर होनी चाहिए, इसलिए मेरा मानना ​​है कि यह अधिक विश्वसनीय होगा। – Kaiido

उत्तर

7

GameAlchemist द्वारा Mostly taken from this great answer:

ब्राउज़रों वीडियो 'फ़्रेमदर सम्मान नहीं करता है के बाद से, लेकिन इसके बजाय "कुछ चाल के उपयोग फिल्म के फ्रेम दर और स्क्रीन के ताज़ा दर के बीच एक मैच बनाने के लिए" , आपकी धारणा है कि एक सेकंड के हर 30 वें, एक नया फ्रेम चित्रित किया जाएगा काफी गलत है।
हालांकि, वर्तमान समय बदलने पर timeupdate event आग लगनी चाहिए, और हम मान सकते हैं कि एक नया फ्रेम चित्रित किया गया था। बजाय मांग 1/30 के आगे, आप `वीडियो के timeupdate` घटना पर एक समारोह देते हैं चाहिए की

document.querySelector('input').addEventListener('change', extractFrames, false); 
 

 
function extractFrames() { 
 
    var video = document.createElement('video'); 
 
    var array = []; 
 
    var canvas = document.createElement('canvas'); 
 
    var ctx = canvas.getContext('2d'); 
 
    var pro = document.querySelector('#progress'); 
 

 
    function initCanvas(e) { 
 
    canvas.width = this.videoWidth; 
 
    canvas.height = this.videoHeight; 
 
    } 
 

 
    function drawFrame(e) { 
 
    this.pause(); 
 
    ctx.drawImage(this, 0, 0); 
 
    /* 
 
    this will save as a Blob, less memory consumptive than toDataURL 
 
    a polyfill can be found at 
 
    https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob#Polyfill 
 
    */ 
 
    canvas.toBlob(saveFrame, 'image/jpeg'); 
 
    pro.innerHTML = ((this.currentTime/this.duration) * 100).toFixed(2) + ' %'; 
 
    if (this.currentTime < this.duration) { 
 
     this.play(); 
 
    } 
 
    } 
 

 
    function saveFrame(blob) { 
 
    array.push(blob); 
 
    } 
 

 
    function revokeURL(e) { 
 
    URL.revokeObjectURL(this.src); 
 
    } 
 
    
 
    function onend(e) { 
 
    var img; 
 
    // do whatever with the frames 
 
    for (var i = 0; i < array.length; i++) { 
 
     img = new Image(); 
 
     img.onload = revokeURL; 
 
     img.src = URL.createObjectURL(array[i]); 
 
     document.body.appendChild(img); 
 
    } 
 
    // we don't need the video's objectURL anymore 
 
    URL.revokeObjectURL(this.src); 
 
    } 
 
    
 
    video.autoplay = true; 
 
    video.muted = true; 
 

 
    video.addEventListener('loadedmetadata', initCanvas, false); 
 
    video.addEventListener('timeupdate', drawFrame, false); 
 
    video.addEventListener('ended', onend, false); 
 

 
    video.src = URL.createObjectURL(this.files[0]); 
 
}
<input type="file" accept="video/*" /> 
 
<p id="progress"></p>

+1

मेरी धारणा यह नहीं है कि एक सेकंड के हर 30 वें स्थान पर एक नया फ्रेम होगा, लेकिन अगर मुझे हर 1/30 सेकेंड में 1 फ्रेम मिलता है, तो मैं 30 एफपीएस के साथ समाप्त हो जाऊंगा। मैंने जो गलती की है, वह यह मान रहा है कि मुझे जो फ्रेम मिलते हैं वह वास्तव में सही और वर्तमान फ्रेम होगा। मैं मदद की सराहना करता हूं।टाइमअपडेट घटना बहुत उपयोगी है। टीवाई :) –

+0

यह विधि बिल्कुल विश्वसनीय नहीं है: यह एक बार 4172 फ्रेम देता है, और फिर 4573 एक दूसरे रन पर, एक वीडियो पर जो वास्तव में ffmpeg के अनुसार केवल 250 फ्रेम है। 10 सेकंड @ 25 एफपीएस: http://www.w3schools.com/html/mov_bbb.mp4 –

+0

@ दिनेश बोल्केनस्टेन, क्या आपने इस उत्तर के हेडर और लिंक किए गए उत्तर को पढ़ा? नहीं, यह विधि फ़ाइल में मौजूद सभी वीडियो फ्रेमों को विश्वसनीय रूप से निकालने में सक्षम नहीं है, केवल ब्राउज़र द्वारा चित्रित किए गए हैं, जो वीडियो के फ़्रेमेट का सम्मान नहीं करते हैं। – Kaiido

संबंधित मुद्दे