Bug 153588

Summary: REGRESSION (Safari 9): drawImage doesn't paint the current frame of a video
Product: WebKit Reporter: @fregante <bugs>
Component: CanvasAssignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Normal CC: acrong3, calipoop, dbates, denny.ferrassoli, dino, electroteque, eric.carlson, gruan, info, jer.noble, justin.hamm, lucas, mail, marc.tremblay, masotime, simon.fraser, sinagra, solo, staffan.klashed, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: Safari 9   
Hardware: Mac   
OS: OS X 10.11   
Attachments:
Description Flags
Reduced case
none
Test case to reproduce bug
none
Fully Self-contained bug reproduction none

Description @fregante 2016-01-28 03:56:10 PST
Created attachment 270106 [details]
Reduced case

`ctx.drawImage(video, ...)` only paints the first frame of `video` regardless of its `currentTime`

This works in all other browsers, including Yosemite's Safari 8, but not on Safari 9.0.3 on El Capitan.

This bugs appears on all the demos on the following site, albeit only occasionally http://html5doctor.com/video-canvas-magic/
Comment 1 Alexey Proskuryakov 2016-01-30 23:06:03 PST
I cannot reproduce this using the attached test case in Safari 9.0.3 on El Capitan.
Comment 2 @fregante 2016-02-09 12:29:40 PST
Please try again, other people are experiencing it. http://stackoverflow.com/questions/35060414/safari-9-paints-only-the-first-frame-of-a-video-on-canvas-bug
Comment 3 Justin Hamm 2016-03-09 12:46:19 PST
Also getting this bug... It seems to be very intermittent, and takes multiple refreshes sometimes for the bug to occur. In addition if multiple browser tabs are open with the attached example, and one tab has the issue after a refresh, it will affect the other tab.
Comment 4 Jer Noble 2016-03-09 20:51:18 PST
I've only managed to catch this bug live once, in a shipping version of Safari. Some dtrace debugging showed that MediaPlayerPrivateAVFoundationObjC::videoOutputHasAvailableFrame() was repeatedly returning false, due to [m_videoOutput hasNewPixelBufferForItemTime:[m_avPlayerItem currentTime]] returning NO. <http://trac.webkit.org/browser/trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm#L2204>
Comment 5 Marc Tremblay 2016-03-14 14:52:01 PDT
Tested Federico's test case using Safari 9.0.3 on El Capitan (10.11.3) and it only ever draws the first frame. This is the same behavior I see everywhere else that I try to draw a frame of video to a canvas.

The only exception I have found is Apple's Listing 17-2 Breaking video into tiles from https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/PuttingVideoonCanvas/PuttingVideoonCanvas.html - note that the embedded example is a rendered movie. If I drop that code in a file, it works reliably with the same config as above. One caveat may be that I've only tested with a video that is bigger than the one in Apple demo and haven't adjusted the code, so only a part of the larger video is being tiled/rotated.
Comment 6 Fran Solo 2016-03-18 05:11:51 PDT
I am having similar issues drawing a canvas on another canvas with simple drawImage
canvas.drawImage(canvas2,0,0);

It works on all browsers but not Safari 9 on Mavericks, neither IOS9

BUT ... if i resize the browser ... tadaa ... the problem is magically fixed !! WTF ??
Comment 7 Andre Venancio 2016-05-17 22:02:55 PDT
I'm using Safari (Version 9.1.1 (11601.6.17)) on Mac OS El Capitan (10.11.5 (15F34))
And when I open this example, I can only pain the 1st frame of the video.

http://jsfiddle.net/on1kh4o0/422/

Is there any work around?
Comment 8 George Ruan 2016-05-26 14:32:16 PDT
Created attachment 279912 [details]
Test case to reproduce bug

vid2.mov in video source is Big Buck Bunny short movie.

Bug does not reproduce every time 100%. But, should after a number of refreshes.
Comment 9 George Ruan 2016-05-26 14:35:14 PDT
Existing test case media/video-canvas-drawing-output.html shows the bug, but does not catch it because it is looking at pixels that do not change between frames.
Comment 10 Daniel Rossi 2016-06-27 21:26:53 PDT
This is a known issue and requires drawing twice. 

Simply before doing the real draw and capture

 context.drawImage(video, 0, 0);

Call this with a 1 second delay before capturing again. 

 var canvas = this.createCanvas(),
    context = canvas.getContext("2d");
    context.drawImage(container, 0, 0);
    this.clearCanvas(canvas);

    setTimeout(function() {
        onSuccess(container);
    }, 1000);

Saying that you still need to use a CORS proxy for Safari so bring up a second stream and seek, then pre capture then do the real capture. Alot of mucking around for Safari. Even with mediasource it requires the same reloading of the stream and seeking.
Comment 11 Daniel Rossi 2016-06-27 21:28:56 PDT
So you don't exactly need to use the same canvas just a temporary one. 

It's something to do with the mediaelement just like the nasty cors bug that is breaking 360 video rendering.
Comment 12 Radar WebKit Bug Importer 2016-06-27 21:35:29 PDT
<rdar://problem/27047668>
Comment 13 Benjamin Goh 2016-07-05 13:45:24 PDT
Created attachment 282814 [details]
Fully Self-contained bug reproduction

A fully self-contained HTML file with a video encoded as a base64 data URL to reproduce the issue.
Comment 14 Benjamin Goh 2016-07-05 13:46:44 PDT
I've successfully reproduced the issue in a consistent way, with the newly uploaded HTML file I've added.

If you hide the video player and start playing it, then the video capture works fine. Also, playing, pausing, switching to another tab then switching back seem to "refresh" the video and fix the issue.

This is a definite bug, please fix it.
Comment 15 Andrew Sinagra 2016-07-15 13:05:13 PDT
I was able to consistently reproduce this bug on OSX 10.11.3 with Safari 9.0.3.  Switching to a new desktop and back to the one with Safari and then calling drawImage will work properly.
Comment 16 Lucas Correia 2016-09-01 00:20:45 PDT
I am also experiencing the same issue on Safari 9.0.3 & Mac OS 10.11.3l (El Capitan).

The previous examples all show the issue. Switching desktop, going fullscreen or switching browser tab before copying the video will result in the correct frame.

I have not found any way to workaround the issue.
Comment 17 Denny 2016-09-20 14:12:25 PDT
I tried two of the test cases above with Safari 10.0 and the capture is working. I'm on 10.11.6 and Safari 10.0 (11602.1.50.0.10).

Anyone else verify this?
Comment 18 Lucas Correia 2016-09-26 05:38:00 PDT
(In reply to comment #17)
> I tried two of the test cases above with Safari 10.0 and the capture is
> working. I'm on 10.11.6 and Safari 10.0 (11602.1.50.0.10).
> 
> Anyone else verify this?

I still experience the same issues on OS X 10.11.6 (15G1004), Safari 10.0 (11602.1.50.0.10).

I am however not able to reproduce the issue consistently. Some times capture works, sometimes it doesn't. It was easiest reproduced by repeatedly reloading the JSFiddle posted earlier (http://jsfiddle.net/on1kh4o0/422/) and checking if the canvas to the right played back the video.
Comment 19 Jer Noble 2016-09-26 07:11:29 PDT
For those of you who are able to consistently reproduce, would you please gather a sysdiagnose while reproducing, attach that sysdiagnose to a new Radar at bugreport.apple.com, and then send me the Radar #? This is likely an underlying OS issue and the sysdiagnose will have valuable logs for figuring out what is going on.
Comment 20 calipoop 2017-01-25 22:58:32 PST
Any update on this?  It's still an issue, and very troublesome given that it's intermittent and there doesn't appear to be a work-around...
Comment 21 Daniel Rossi 2017-01-25 23:03:34 PST
call draw image then a timeout then draw image again for Safari. It stops the black frame issue. 

Here is an es6 util of mine before I do the actual capture

preCapture(container, onSuccess) {
        const canvas = this.createCanvas(),
            context = canvas.getContext("2d");
        context.drawImage(container, 0, 0);
        this.clearCanvas(canvas);

        setTimeout(() => {
            onSuccess(container);
        }, 1000);
    }

Maybe its only required once no idea. 

I've become a master of finding work around for all these faulty webkit flaws.

 I even copped abuse on one ticket for eventually reporting a work around in that ticket and telling them not to bother after months of no response hahah.
Comment 22 calipoop 2017-01-26 08:35:48 PST
(In reply to comment #21)
> call draw image then a timeout then draw image again for Safari. It stops
> the black frame issue. 
> 
> Here is an es6 util of mine before I do the actual capture
> 
> preCapture(container, onSuccess) {
>         const canvas = this.createCanvas(),
>             context = canvas.getContext("2d");
>         context.drawImage(container, 0, 0);
>         this.clearCanvas(canvas);
> 
>         setTimeout(() => {
>             onSuccess(container);
>         }, 1000);
>     }
> 
> Maybe its only required once no idea. 
> 
> I've become a master of finding work around for all these faulty webkit
> flaws.
> 
>  I even copped abuse on one ticket for eventually reporting a work around in
> that ticket and telling them not to bother after months of no response hahah.

Thanks for the tip - I'll give it a whirl.
Comment 23 Staffan Klashed 2020-02-26 00:38:00 PST
I am encountering this bug on Safari on iOS 13.3.1, when attempting to capture a video poster at a user-defined currentTime by rendering video into a canvas + toDataURL. It reliably happens if the video file's EXIF rotation is non-zero. Any thoughts?