javascript - HTML5 Canvas drawImage dari video tidak muncul saat gambar pertama


Saya memiliki elemen video dengan overlay kanvas. Lalu saya memiliki alat menggambar yang disiapkan untuk menggambar di atas video dan tombol simpan yang melakukan drawImage dari video dan kemudian dari kanvas untuk menyimpan frame gabungan. Namun, pertama kali saya menekan Simpan, saya hanya mendapatkan hasil dari drawImage kanvas, videonya tidak muncul. Pada Simpan berikutnya, saya menerima kedua gambar yang tersusun dengan benar. Saya pikir ini mungkin masalah dengan pemuatan gambar video, tapi video sudah sepenuhnya dimuat sebelum saya menekan simpan dan bahkan bisa memajukan frame dan bekerja dengan baik pada Simpan ke-2.

Berikut kodenya...

<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>');
}

Jawaban #1

Saya baru-baru ini mengalami masalah yang sama, dan mengakalinya dengan menggambar video ke sebuah kanvas 'palsu' sebelum melakukan pekerjaan 'nyata' dengan video tersebut. Ini berhasil dengan baik karena semua metode dalam kode saya yang mencoba untuk mengurai video menunggu sampai acara 'canplaythrough' dipicu pada video. Saya membungkus penangan acara 'canplaythrough' dalam sebuah Promise, dan hanya menyelesaikan promise tersebut ketika acara 'canplaythrough' telah diterima DAN upaya telah dilakukan untuk menggambar video ke kanvas palsu. Ini tampaknya merupakan solusi sementara yang efektif untuk bug Safari.

Sebagai contoh:

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
});

Jawaban #2

Saya mengalami masalah yang sama dan mencoba solusi di komentar terakhir. Itu belum berhasil untuk saya.

Saya baru sadar kemudian dan menemukan jalan keluarnya:

dalam kode saya saya memiliki beberapa gambar lain bersama dengan drawImage dari video seperti

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

dan dengan ini, undian kedua masih tidak akan berhasil bahkan ketika menggambarnya kembali setelah acara 'canplaythrough'.

Jadi saya menghapus tiga baris di atas, dan hanya melakukan tarik kedua setelah event 'canplaythrough'. Lalu berhasil.

Sederhananya, kode yang berhasil untuk saya adalah seperti ini:

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