How do I grab a snapshot of a video file selected via <input type="file">
at a specific time in the video silently in-the-background (i.e. no visible elements, flickering, sound, etc.)?
相关问题
- Is there a limit to how many levels you can nest i
- How to toggle on Order in ReactJS
- How to fix IE ClearType + jQuery opacity problem i
- void before promise syntax
- jQuery add and remove delay
There are four major steps:
<canvas>
and<video>
elements.src
of the video file generated byURL.createObjectURL
into the<video>
element and wait for it to load by listening for specific events being fired.Step 1 - Create the elements
This is very easy: just create one
<canvas>
and one<video>
element and append them to<body>
(or anywhere really, it doesn't really matter):Notice that the video element has the attribute
muted
. Don't put any other attributes likeautoplay
orcontrols
. Also notice that they both have the classsnapshot-generator
. This is so we can set the style for both of them so that they are out of the way:Some browsers work with them set to
display: none
, but other browsers will have serious problems unless they are rendered on the page, so we just make them minuscule so that they are essentially invisible. (Don't move them outside the viewport though, as otherwise you may see some ugly scrollbars on your page.)Step 2 - Load the video
Here's where things start to get tricky. You need to listen to events to know when to continue. Different browsers will fire different events, different times and in different orders, so I'll save you the effort. There are three events that must always fire at least once before the video is ready; they are:
Set up the event handler for these events and keep track how many have fired. Once all three have fired, you are ready to proceed. Keep in mind that, since some of these events may fire more than once, you only want to handle the first event of each type that is fired, and discard subsequent firings. I used jQuery's
.one
, which takes care of this.The source should just be the object URL created via
URL.createObjectURL(file)
, wherefile
is the file object.Step 3 - Set the time
This stage is similar to the previous: set the time and then listen for an event. Inside our
if
block from the previous code:Luckily its only one event this time, so it's pretty clear and concise. Finally...
Step 4 - Grab the snapshot
This part is just using the
<canvas>
element to grab a screenshot. Inside ourseeked
event handler:The canvas needs to match the dimensions of the video (not the
<video>
element) to get a proper image. Also, we are setting the canvas's internal.height
and.width
properties, not the canvas height/width CSS style values.The value of snapshot is a data URI, which is basically just a string that starts with
data:image/jpeg;base64
and then the base64 data.Our final JS code should look like:
Celebrate!
You have your image in base64! Send this to your server, put it as the
src
of an<img>
element, or whatever.For example, you can decode it into binary and directly write it to a file (trim the prefix first), which will become a JPEG image file.
You could also use this to offer previews of videos while they are uploaded. If you are putting it as the
src
of an<img>
, use the full data URI (don't remove the prefix).