I have an issue getting screenshots of videos in Chrome, and I've exhausted all the internets and all Stackoverflow answers on it; no luck.
No matter what I try, when I try to use the canvas
element to take a screenshot of a video that is on a different domain, or even just a different port, then I end up with a Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
error.
Here is my setup:
Web app URL
http://client.myapp.com/home.html
CDN URLs (I've tried both)
http://client.myapp.com:8181/somevideo.mp4
http://cdn.myapp.com/somevideo.mp4
Headers sent back with MP4 from CDN:
Accept-Ranges:bytes
Access-Control-Allow-Origin:*
Access-Control-Expose-Headers:x-ms-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,Accept-Ranges,Content-Length,Date,Transfer-Encoding
Content-Length:5253832
Content-Range:bytes 48-5253879/5253880
Content-Type:video/mp4
Date:Sat, 06 Feb 2016 17:24:05 GMT
ETag:"0x8D32E3EDB17EC00"
Last-Modified:Fri, 05 Feb 2016 15:13:08 GMT
Server:Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-blob-type:BlockBlob
x-ms-lease-state:available
x-ms-lease-status:unlocked
x-ms-request-id:88d3aaef-0629-4316-995f-021aa0153c32
x-ms-version:2015-04-05
I have:
crossOrigin="anonymous"
to the video element, but this just makes the video fail to load altogetherAccess-Control-Allow-Origin
is coming back with *
(as above)Yet, still the blasted error.
Edit
Added code:
var getScreenshotDataUrl = function(video, canvas, type) {
type = type || "image/jpeg";
var context = canvas.getContext("2d");
var w = video.videoWidth;
var h = video.videoHeight;
canvas.width = w;
canvas.height = h;
context.fillRect(0, 0, w, h);
context.drawImage(video, 0, 0, w, h);
video.crossorigin = "anonymous";// makes no difference
return canvas.toDataURL(type);
}
Please help.
I have answered my own question.
What a horrible headache I now have.
The problem lies somewhere in the nuanced specification of the HTML5 video crossorigin/CORS specification.
I only tested in Chrome and Edge, but here is what you need to know at the time of writing:
Loading your HTML5 video will fail if you have crossOrigin
set, but your video is being served from any port other than 80 and is not using https
:
THIS WILL FAIL
Client at http://www.myapp.com/player.html:
<video crossOrigin="anonymous" src="http://cdn.myapp.com:81/video.mp4"></video>
THIS WILL SUCCEED
Client at http://www.myapp.com/player.html:
<video crossOrigin="anonymous" src="https://cdn.myapp.com:81/video.mp4"></video>
getImageData()
and toDataURL()
will be security blocked unless:
anonymous
or use-credentials
(as defined here) before the video is loaded. If you do this too late, it will still fail.Finally, if you are going to set crossOrigin
in javascript, be sure to use the correct casing for the javascript property: crossOrigin
(NOT crossorigin
)
I have written this up in a little more detail in my blog.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With