Closed Barahten closed 2 years ago
Do you know if there's an existing FFmpeg command or solution that we can use?
Do you know if there's an existing FFmpeg command or solution that we can use?
I solved this problem as follows: I broke the whole process of creating VTT-Tumbnails into two steps
$media = FFMpeg::fromDisk('public')->open('tmp/test.mp4');
// Duration
$duration = $media->getDurationInSeconds();
// Dimension
$dimension = $media->getVideoStream()->getDimensions();
$width = $dimension->getWidth();
$height = $dimension->getHeight();
// Interval
$interval = 5 // In seconds
// Thumb tile size
$ratio = $width / $height;
$thumb_width = 160;
$thum_height = round($thumb_width/$ratio);
$media
->addFilter('-vf', 'select=isnan(prev_selected_t)+gte(t-prev_selected_t\,' . $interval . '),scale=' . $thumb_width . ':' . $thum_height . ',tile=5x5')
->addFilter('-qscale:v', 3)
->addFilter('-vsync', 'vfr')
->export()
->onProgress(function ($percentage) {
// Some code, if need
})
->toDisk('public')
->save('video/thumbnails/sprite_%d.jpg')
->cleanupTemporaryFiles();
This command will create sprites in which 160px wide thumbnails will be assembled into tiles (5 rows of 5 in each row). This is how it looks
$vtt = "WEBVTT\n";
$counter = 0;
$max_sprites = ceil(($duration / $interval)/(5 * 5)); // Where 5 * 5 is FFMPEG video filter params tile, see above
for($jpg = 1; $jpg <= $max_sprites; $jpg++){
for($col = 0; $col < 5; $col++){ // 5 - the number of miniatures in one row
for($row = 0; $row < 5; $row++){ // 5 - the number of rows in the final sprite
$vtt .= "\n"
. sprintf('%02d:%02d:%02d.000', ($counter * $interval) / 3600, ($counter * $interval) / 60 % 60, ($counter * $interval) % 60) . " --> "
. sprintf('%02d:%02d:%02d.000', (($counter + 1) * $interval) / 3600, (($counter + 1) * $interval) / 60 % 60, (($counter + 1) * $interval) % 60) . "\n"
. "sprite_" . $jpg . ".jpg#xywh=" . ($row * $thumb_width) . "," . ($col * $thum_height) . "," . $thumb_width . "," . $thum_height . "\n";
$counter++;
}
}
}
// Save vtt file
Storage::disk('public')->put('video/thumbnails/thumbnail.vtt', $vtt);
As a result, we get the file thumbnail.vtt with the following content
WEBVTT
00:00:00.000 --> 00:00:05.000
sprite_1.jpg#xywh=0,0,160,90
00:00:05.000 --> 00:00:10.000
sprite_1.jpg#xywh=160,0,160,90
00:00:10.000 --> 00:00:15.000
sprite_1.jpg#xywh=320,0,160,90
...
00:05:50.000 --> 00:05:55.000
sprite_3.jpg#xywh=0,360,160,90
00:05:55.000 --> 00:06:00.000
sprite_3.jpg#xywh=160,360,160,90
00:06:00.000 --> 00:06:05.000
sprite_3.jpg#xywh=320,360,160,90
00:06:05.000 --> 00:06:10.000
sprite_3.jpg#xywh=480,360,160,90
00:06:10.000 --> 00:06:15.000
sprite_3.jpg#xywh=640,360,160,90
The whole operation to create sprites and vtt file for a more then 6 minute video took about 8 seconds on a laptop with a processor Intel Core i7-9750H (6 cores / 12 logical processors)
Impressive work! I'm a bit preoccupied momentarily, but I'll try to find a place for this in the package soon :)
This is now available in v7.7.0
It would be nice to add a method for generating preview thumbnails: a .vtt file with markup of the timedes and coordinates of the sprite and the sprite itself in the form of a tile. Now all modern js-players can show a preview when hovering over the timeline. As a parameter, you could set the width and height of the thumbnail, as well as the number in one row