簡體   English   中英

HTML5 Canvas 第一次繪制時未顯示來自視頻的圖像

[英]HTML5 Canvas drawImage from video not showing on first draw

我有一個帶有 canvas 疊加層的視頻元素。 然后我有一個繪圖工具設置來繪制視頻和一個保存按鈕,它從視頻和 canvas 中執行 drawImage 以保存壓縮幀。 但是,我第一次按“保存”時,我只從 canvas drawImage 獲得結果,視頻沒有顯示。 在隨后的保存中,我收到了正確分層的兩個圖像。 我認為這可能是加載視頻圖像的問題,但在我點擊保存之前視頻已完全加載,甚至可以推進幀並使其在第二次保存時正常工作。

這是代碼...

<div style="width:960px; height:540px; display:inline-block;">
    <video id="video" src="media/_tmp/AA_017_COMP_v37.mov" width="960" height="540" ></video>
</div>
<canvas id="canvas" width="960" height="540" style="position:absolute; top:40px; left:9px; z-index:100;"></canvas>
<input type="button" value="save" id="btn" size="30" onclick="save()" style="float:left; padding:4px; margin-right:4px;" >
<div id="saved" style="border:1px solid #000; position:absolute; top:626px; left:10px; bottom:40px; width:958px; overflow:auto;">SAVED:</div>


function save() {

    //COMP CANVAS OVER VIDEOFRAME
    var video = document.getElementById("video");
    var currentFrame = Math.floor((<?php echo $mov_frames ?> / video.duration) * video.currentTime);

    var compCanvas = document.createElement('canvas');
    compCanvas.width = video.width;
    compCanvas.height = video.height;
    compContext = compCanvas.getContext('2d');
    compContext.drawImage(video, 0, 0);
    compContext.drawImage(canvas, 0, 0);
    var dataURL = compCanvas.toDataURL();

    $("#saved").append('<div style="width:954px; border-bottom:1px solid #000; padding:2px 2px 0 2px;"><img id="compFrame_'+currentFrame+'" width="180" height="90" src="'+dataURL+'" />Frame: '+currentFrame+'</div>');
}

由於這是在帶有Safari的OSX上,因此有一些壞消息:

注意:iOS當前不支持將視頻作為canvas drawImage()方法的源。

資源

如果這是過時的信息,我不知道,但是無論哪種情況,當前的實現都有問題。 正如已經確定的那樣(在注釋中),該問題不太可能與編解碼器有關,因為其他格式也可能出現這種情況。 小提琴消除了toDataURL()方法作為源,因此剩下的是drawImage()方法。

由於這可以通過提供的代碼在其他平台上使用,並且從外觀上看,這也不是問題的根源,因此,您在這里查看的是OSX平台上Safari瀏覽器的一個非常可能的問題(錯誤)。

上面引用的官方文檔還指出不支持此功能,因此這可能是一個非常早期的實現,仍然存在一些問題。

在這方面您無能為力,只能等待並報告為問題(我尋找了已報告的問題,但找不到任何問題,因此建議您這樣做)。

最近,我本人也遇到了同樣的問題,並通過將視頻繪制到“虛擬”畫布上來進行處理,然后再進行“實際”處理。 這與我代碼中嘗試解析視頻的所有方法等到視頻上觸發了“ canplaythrough”事件一樣,效果很好。 我將“ canplaythrough”事件處理程序包裝在Promise中,並且僅在收到“ canplaythrough”事件並且試圖將視頻繪制到虛擬畫布上時解決承諾。 這似乎是解決 Safari錯誤的有效方法

例如:

var readyPromise = new Promise(function(resolve) {
    video.addEventListener("canplaythrough", function() {
        var canvas = document.createElement("canvas"),
            context = canvas.getContext("2d");

        context.drawImage(video, 0, 0);

        resolve(video);
    });
});

readyPromise.then(function() {
    // NOW manipulate the video, draw it onto a canvas, etc
});

我遇到了同樣的問題,並在最后一條評論中嘗試了解決方案。 它對我來說還行不通。

后來我想出了一個解決方法:

在我的代碼中,我還有其他一些繪圖以及視頻中的drawImage

context.rect(0, 0, 50, 50);
context.fillStyle = 'black';
context.fill();

有了這些,即使在“ canplaythrough”事件后重新繪制,第二次繪制仍然不起作用。

因此,我刪除了上述三行內容,只是在事件“ canplaythrough”之后進行了第二次抽簽。 然后它起作用了。

簡單來說,對我有用的代碼是這樣的:

context.drawImage(video, 0, 0);
video.addEventListener('canplaythrough', function () {
    context.drawImage(video, 0, 0);
});

這些都不適合我。 似乎 chrome(atm 是97版)在后台做了一些討厭的優化。

  • canplaythrough似乎很懶惰,並且不保證第一幀已加載
  • 如果video有 style display: none它也不會被加載,因此繪圖也不會工作。
  • 視頻元素應附加到 DOM
  • canvas 元素不應有任何與其寬度或大小相關的 css。

唯一有用的是setTimeout ,這是一個令人討厭的 hack,但它就是這樣。

 fileinput.addEventListener('change', function (e) { var ctx = canvas.getContext("2d"); video.addEventListener('loadedmetadata', function () { canvas.width = video.videoWidth; canvas.height = video.videoHeight; setTimeout(() => { ctx.drawImage(video, 0, 0); }, 100) }); video.querySelector("source").setAttribute('src', URL.createObjectURL(fileinput.files[0])); video.load(); });
 video { opacity: 0; width: 0; height: 0; }
 <input type="file" id="fileinput" name="file"> <video id="video" controls> <source type="video/mp4"> </video> <canvas id="canvas"></canvas>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM