Generate Preview Image from Video File

Create a video preview image like youtube or whatsapp from a Video file (.mp4) using JAVA Code

Check this code, as it successfully creates the file. Have made a few changes.This is the solution for Issue1.
If you are unable to see the logs, then the issue is with the logger. You can paste the logger you are using or google the issue with your logger.

public static boolean generatePreviewImage(String filePath,
String previewFileName) throws IOException, Exception {
logger.info("Request received to generate thumbnail for video. VideoFilePath : "
+ filePath + ", resultFileName " + previewFileName);
boolean isPreviewGenerated = false;
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(filePath);
logger.info("FrameGrabber found " + grabber);
grabber.start();
logger.info("FrameGrabber started.. " + grabber);
for (int i = 20; i < 22; i++) {
logger.info("Reading first 2 images..");
ImageIO.write(grabber.grab().getBufferedImage(), "jpg", new File(
previewFileName + "_" + i));
logger.info(i + " image written successfully as " + previewFileName
+ "_" + i + ".jpg");
isPreviewGenerated = true;
}
grabber.stop();
logger.info("Is preview generated.." + isPreviewGenerated);
return isPreviewGenerated;

}

Angular - Generate thumbnails for uploaded image/video

You can try to create a video element and set your video to it. After loading the video inside the element a canvas can be used to extract an image from that video.
This might be useful https://stackoverflow.com/a/63474748/10143503

How to generate a thumbnail from videos without load the whole video?

You could use ffmpeg, example from the docs:

ffmpeg -i input.flv -ss 00:00:14.435 -vframes 1 out.png

This example will seek to the position of 0h:0m:14sec:435msec and output one frame (-vframes 1) from that position into a PNG file.

Generate a thumbnail/snapshot of a video file selected by a file input at a specific time

There are four major steps:

  1. Create <canvas> and <video> elements.
  2. Load the src of the video file generated by URL.createObjectURL into the <video> element and wait for it to load by listening for specific events being fired.
  3. Set the time of the video to the point where you want to take a snapshot and listen for additional events.
  4. Use the canvas to grab the image.

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):

var canvasElem = $( '<canvas class="snapshot-generator"></canvas>' ).appendTo(document.body)[0];
var $video = $( '<video muted class="snapshot-generator"></video>' ).appendTo(document.body);

Notice that the video element has the attribute muted. Don't put any other attributes like autoplay or controls. Also notice that they both have the class snapshot-generator. This is so we can set the style for both of them so that they are out of the way:

.snapshot-generator {
display: block;
height: 1px;
left: 0;
object-fit: contain;
position: fixed;
top: 0;
width: 1px;
z-index: -1;
}

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:

  • loadedmetadata
  • loadeddata
  • suspend

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.

var step_2_events_fired = 0;
$video.one('loadedmetadata loadeddata suspend', function() {
if (++step_2_events_fired == 3) {
// Ready for next step
}
}).prop('src', insert_source_here);

The source should just be the object URL created via URL.createObjectURL(file), where file 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:

$video.one('seeked', function() {
// Ready for next step
}).prop('currentTime', insert_time_here_in_seconds);

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 our seeked event handler:

canvas_elem.height = this.videoHeight;
canvas_elem.width = this.videoWidth;
canvas_elem.getContext('2d').drawImage(this, 0, 0);
var snapshot = canvas_elem.toDataURL();

// Remove elements as they are no longer needed
$video.remove();
$(canvas_elem).remove();

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:

var step_2_events_fired = 0;
$video.one('loadedmetadata loadeddata suspend', function() {
if (++step_2_events_fired == 3) {
$video.one('seeked', function() {
canvas_elem.height = this.videoHeight;
canvas_elem.width = this.videoWidth;
canvas_elem.getContext('2d').drawImage(this, 0, 0);
var snapshot = canvas_elem.toDataURL();

// Delete the elements as they are no longer needed
$video.remove();
$(canvas_elem).remove();
}).prop('currentTime', insert_time_here_in_seconds);
}
}).prop('src', insert_source_here);

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).



Related Topics



Leave a reply



Submit