javascript - HTML5 Canvas drawImage från video visas inte vid första ritningen


Jag har ett videoelement med ett canvas-överlägg. Sedan har jag ett ritverktyg uppsatt för att rita över videon och en spara-knapp som gör ett drawImage från både videon och sedan canvasen för att spara en sammansatt bildruta. Men första gången jag trycker på Spara får jag bara resultatet från canvasens drawImage, videon visas inte. Vid efterföljande sparningar får jag båda bilderna korrekt lagerlagda. Jag trodde detta kunde vara ett problem med inladdningen av videobilden, men videon är helt inläst innan jag trycker på spara och jag kan till och med avancera ramar och det fungerar korrekt vid andra sparningen.

Här är koden...

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

Svar #1

Jag stötte nyligen på samma problem själv och arbetade runt det genom att rita videon på en "dummy"-canvas innan jag gjorde "verkligt" arbete med den. Detta fungerar bra eftersom alla metoder i min kod som försöker analysera videon väntar tills "canplaythrough"-händelsen har utlösts på videon. Jag kapslar in "canplaythrough"-händelsehanteraren i ett Promise och lösar bara promisen när "canplaythrough"-händelsen har mottagits OCH ett försök har gjorts att rita videon på en dummy-canvas. Detta verkar vara en effektiv lösning för Safari-buggen.

Till exempel:

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

Svar #2

Jag stötte på samma problem och provade lösningen i den sista kommentaren. Det fungerade inte riktigt för mig än.

Jag kom på det senare och hittade en lösning:

i min kod har jag några andra ritningar tillsammans med drawImage från video som

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

och med dessa kommer den andra dragningen fortfarande inte att fungera även när den dras om efter 'canplaythrough'-händelsen.

Så jag tog bort de ovanstående tre raderna, och gjorde bara en andra ritning efter händelsen 'canplaythrough'. Då fungerade det.

Enkelt sagt, koden som fungerade för mig är så här:

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