Bug 194986 - Incorrect initial video frame drawn to canvas with canvas.drawImage(video, ...)
Summary: Incorrect initial video frame drawn to canvas with canvas.drawImage(video, ...)
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Media (show other bugs)
Version: Safari 12
Hardware: Mac macOS 10.14
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2019-02-23 19:06 PST by kuwerty
Modified: 2019-02-27 19:14 PST (History)
5 users (show)

See Also:


Attachments
Self contained test. (1.34 MB, text/html)
2019-02-23 19:06 PST, kuwerty
no flags Details
Second test using MSE, video not copied to canvas at all. (105.61 KB, text/html)
2019-02-27 19:14 PST, kuwerty
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description kuwerty 2019-02-23 19:06:41 PST
Created attachment 362846 [details]
Self contained test.

I'm trying to get Safari to seek and draw a single frame of video on a canvas element.

It seems impossible to reliably get anything other than the first frame of video.

The sample code below just tries to seek and draw a single frame but exposes at least 2 bugs:

1. Video element claims it has seeked to the target time but when drawImage is called it draws the first frame.

2. onseeked event may not even be called.


Although not in the code below, I've also tried various hacks like seeking multiple times to wildly different points in the video to try and force different behaviour. These work most of the time but there's still cases where the onseeked event is not called and everything falls apart.


Added a complete, self-contained repro as an attachment.

Typical log looks like:
[Log] onloadedmetadata (tmp.html, line 42)
[Log] onloadeddata: time:2 (tmp.html, line 58)
[Log] ontimeupdate: time:2 (tmp.html, line 66)
[Log] onseeked: time:2 (tmp.html, line 48)
[Log] updateCanvas: time:2 (tmp.html, line 71)
But updateCanvas renders the wrong frame.


When onseeked is not called, the log reads:
[Log] onloadedmetadata (tmp.html, line 42)
[Log] onloadeddata: time:0 (tmp.html, line 58)
and the browser does nothing else.




var canvas = null
var video = null

// BUG1: If we litter currentTime all over the place to try and get the right
// thing to happen, we find that onseeked is not called half the time.
// When set to false, only a single seek in onloadedmetadata is used. Even then
// onseeked is not called sporadically (<5% failure rate).
// 
let redundantSetCurrentTime = false

function startLoad() {
  if(redundantSetCurrentTime) {
    video.currentTime = 2
  }

  video.src = data

  if(redundantSetCurrentTime) {
    video.currentTime = 2
  }
}

function onloadedmetadata() {
  console.log("onloadedmetadata")

  video.currentTime = 2
}

// BUG: onseeked may not be called
function onseeked() {
  console.log(`onseeked: time:${video.currentTime}`)

  // BUG2: video is always rendered at time=0, not time=2
  updateCanvas()

  // BUG3(?): timer will not fire occasionally (comment out updateCanvas above)
  //setTimeout(updateCanvas, 500)
}

function onloadeddata() {
  console.log(`onloadeddata: time:${video.currentTime}`)
}

function onplaying() {
  console.log(`onplaying: time:${video.currentTime}`)
}

function ontimeupdate() {
  console.log(`ontimeupdate: time:${video.currentTime}`)
}


function updateCanvas() {
  console.log(`updateCanvas: time:${video.currentTime}`)
  canvas.width = video.videoWidth
  canvas.height = video.videoHeight
  let ctx = canvas.getContext('2d')
  // Inconsistent bug: browser goes away for 10 seconds or so in the drawImage
  ctx.drawImage(video, 0, 0)
}

function onload() {
  canvas = document.getElementById("canvas")
  video = document.createElement("video")

  video.onloadedmetadata = onloadedmetadata
  video.onloadeddata = onloadeddata
  video.onseeked = onseeked
  video.onplaying = onplaying
  video.ontimeupdate = ontimeupdate
  video.crossOrigin = 'anonymous'

  document.body.appendChild(video)

  startLoad()
}
Comment 1 kuwerty 2019-02-27 19:14:03 PST
Created attachment 363182 [details]
Second test using MSE, video not copied to canvas at all.

Added a second test using MediaSource where the video is not copied to the canvas at all. You should click the video element to copy the data to the canvas, on Chrome/Firefox this happens but not on Safari or Safari Tech preview.
Comment 2 Radar WebKit Bug Importer 2019-02-27 19:14:30 PST
<rdar://problem/48460630>