StanislavL
StanislavL

Reputation: 57421

Creating Thumbnail from video on S3 without downloading

There are some video files (mostly .mp4) stored in S3. They could be rather big. I need to get a thumbnail images for the video files - let's say 0.5 second's frame (to skip possible black screen etc.).

I can create the thumbnail if I download whole file but it's too long and I am trying to avoid this and download some minimal fragment.

I know how to download first N bytes from AWS S3 - request with specified range but the problem is the video file piece is corrupted and is not recognized as correct video.

I tried to emulate header bytes retrieving with the code

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Test {
    public static void main(String[] args) throws Exception {
        try(FileInputStream fis = new FileInputStream("D://temp//1.mp4");
            FileOutputStream fos = new FileOutputStream("D://temp//1_cut.mp4");
        ) {
            byte[] buf=new byte[1000000];
            fis.read(buf);
            fos.write(buf);
            fos.flush();
            System.out.println("Done");
        }
    }

}

To work with static file but the result 1_cut.mp4 is not valid. Neither player can recognize it nor avconv library.

Is there any way to download just fragment of video file and create an image from the fragment?

Upvotes: 4

Views: 4670

Answers (2)

Babl
Babl

Reputation: 7646

Not sure if you need full java implementation but in case your file is accessible with direct or signed URL at S3 and you are ok to use ffmpeg than following should do the trick.

ffmpeg -i $amazon_s3_signed_url -ss 00:00:00.500 -vframes 1 thumbnail.png

You can use Amazon Java SDK to create a pre-signed URL and then execute the command above to create a thumbnail.

GeneratePresignedUrlRequest generatePresignedUrlRequest = 
                new GeneratePresignedUrlRequest(bucketName, objectKey);
generatePresignedUrlRequest.setMethod(HttpMethod.GET); 
generatePresignedUrlRequest.setExpiration(expiration);

URL url = s3client.generatePresignedUrl(generatePresignedUrlRequest); 
String urlString = url.toString();

Runtime run  = Runtime.getRuntime();
Process proc = run.exec("ffmpeg -i " + urlString +" -ss 00:00:00.500 -vframes 1 thumbnail.png");

Upvotes: 9

Harry
Harry

Reputation: 1263

Your current approach just to download a random number of sequencial bytes would require you to do repair the partial file that you downloaded... a huge amount of work.

One alternative solution to your question above might be like that:

enter image description here

You would need to forward all Disk I/O read requests from your decoder to the S3 bucket. In case your decoder (avconv) supports reading from an inputstream, here is a good example how to override the read method:

How InputStream's read() method is implemented?

Another alternative is to use existing drivers that just let you access the S3 bucket as it was a local drive:

Windows: https://tntdrive.com/

Linux: https://tecadmin.net/mount-s3-bucket-centosrhel-ubuntu-using-s3fs/#

Upvotes: 3

Related Questions