6

I am trying to embed a thumbnail in a .mkv file with h265 video encoding using ffmpeg from the Linux command line. I am able to embed thumbnails in h264-encoded .mp4 files using the following command:

ffmpeg -i video-in.mp4 -i thumb.png -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic out.mp4

However, a similar command substituting .mkv files does not correctly embed the thumbnail:

ffmpeg -i video-in.mkv -i thumb.png -map 0 -map 1 -c copy -c:v:1 png -disposition:v:1 attached_pic out.mkv

ffmpeg will run just fine, throwing no warnings or errors, but the thumbnail that shows in Dolphin after it's run its course is a generic auto-generated thumbnail instead of the one I specified with -i thumb.png.

I first learned how to do this while reading the ffmpeg documentation here (a bit further down, where it explains dispositions). I noticed that it says "Not all muxers support embedded thumbnails, and those who do, only support a few formats, like JPEG or PNG." This makes me think that maybe the matroska/mkv muxer simply doesn't support embedded thumbnails. However, further research has me confused.

The ffmpeg Formats documentation doesn't list thumbnail(s) as an option in the metadata section of the matroska muxer docs, which further supports the theory that embedding is impossible. I figured I'd double-check that thumbnails are listed as an option for mp4s just to be sure. However, the mov/mp4/ismv muxer section doesn't even have a Metadata sub-section.

The MP4 File Format Documentation I've been able to find isn't very helpful. I can't tell whether thumbnail embedding is possible based on this documentation alone (though obviously I know from experience that it's possible).

The MKV Container Documentation is a lot more thorough, though, and it says in the first section ("What is an MKV File?") that "MKV also supports descriptions, ratings, cover art, and even chapter points" (emphasis mine). In the "Matroska Structure" section it also lists "Attachments" as one of the top-level elements of the container structure. All of this leads me to believe that embedded thumbnails are in fact possible with .mkv files.

So, to summarize: on the one hand, ffmpeg's documentation makes me think I can't embed thumbnails in .mkv files. But the MKV file format documentation makes me think I should be able to. I haven't been able to figure out for sure either way, though, and even if it is possible, the method for doing so differs from the method I use for .mp4 files.

Is it possible to embed thumbnails in .mkv files? If so, how would I do it (preferably using ffmpeg on Linux)?

2 Answers 2

2

I was also going down this rabbit hole and found that there's an option -attach filename that's more specific to mkv files. It's at the end of the "Main Options" section of the manual: https://ffmpeg.org/ffmpeg.html#Main-options

ffmpeg -i video.mkv -attach cover.jpg -metadata:s:t:0 mimetype=image/jpeg -c copy out.mkv

The -metadata:s:t:0 specifically selects the first attachment stream (which should be just the cover photo).

5
  • 2
    This works but I still would like to remind that the thumbnail image must have "cover" as its file name, such as "cover.jpg" or "cover.png". If we use file names like "thumb.png", FFmpeg won't report an error, but the thumbnail also won't display properly on the MKV output.
    – wklchris
    Commented Oct 6, 2023 at 5:20
  • How to do this in Windows, it doesn't work for me in Windows 11... Commented Jul 13 at 20:52
  • @RicardoBohner Windows seems to not read MKV cover art. I use third-party software like Icaros to replace Windows built-in thumbnail provider. (But Windows can read MP3 and MP4 cover art...)
    – rint
    Commented Aug 17 at 23:29
  • @rint I noticed, when I open the movie in VLC media player and press CTRL + I I can actually see the thumbnail, but it doesn't show on File Explorer i.imgur.com/qbStjay.jpeg Commented Aug 17 at 23:56
  • @RicardoBohner Based on the software I think, PotPlayer cannot display the embedded thumbnail.
    – rint
    Commented Aug 18 at 12:29
0

It turns out that the Matroska format also demands that the image ( ONLY a .jpg or a .png can be used ) must not only be named "cover.jpg" or "cover.png"; there is an obscure ADDITIONAL REQUIREMENT that the cover image's smallest dimension ( width or height ) MUST BE NO LARGER THAN 600 PIXELS! The relevant Matroska specification is here: https://www.matroska.org/technical/attachments.html Here's a back-up copy of the same page of the spec at the Internet Archive's Wayback Machine: https://web.archive.org/web/20240918125616/https://www.matroska.org/technical/attachments.html

Read the specification closely! If your cover image file has a square or portrait mode orientation, you can simply use the "cover.ext" naming convention for the file. BUT if your cover image file has a LANDSCAPE mode orientation, the Matroska spec says you SHOULD use the suffix "_land" on the filename(!!!), like this: "cover_land.ext" ( "cover_land.jpg" or "cover_land.png", depending upon your filetype ).

AND... The Matroska spec ALSO says you may include 1 smaller thumbnail image if you want to, with a shortest dimension no greater than 120 pixels! The normal size cover image must be the 1st attachment, though, and the smaller thumbnail is required to follow a "small_" prefix naming convention: "small_cover.ext" or "small_cover_land.ext"

Resize an image with ffmpeg To retain aspect ratio:

ffmpeg -i art_image_for_use_as_cover.jpg -vf scale="-1:600" cover.jpg

or if you want to resize based on input width and height, where '2' is used in both dimensions here to shrink them down by 1/2

ffmpeg -i input_art_image.png -vf scale="iw/2:ih/2" cover.png

where ( this happens automatically, you don't need to replace "iw" or "ih" in that command )

  • iw: input width
  • ih: input height

Here's where the FFMPEG manual describes "scaling" and the parameters you can use: https://ffmpeg.org/ffmpeg-filters.html#scale-1

If by some chance you're also using YT-DLP to get videos from YouTube, you can command yt-dlp to grab the images of various sizes that it uses for a particular video with this --write-all-thumb command option:

"C:\yt-dlp\yt-dlp.exe" --skip-download --write-all-thumb https://www.youtube.com/watch?v=mRtKmFknE0o

The --skip-download option will prevent yt-dlp from downloading the actual video file, but --write-all-thumb will give you the entire set of thumbnails for that video in various sizes, in both .jpg and .webp formats, sequentially numbered from smallest to largest. There is currently ( in 2024 ) no method to retrieve just 1 specific size, you have to download the entire set ( about 42 images ) and then just delete the ones you don't need.

It turns out that for this given example video, none of the widths or heights is exactly 600 pixels. And the thumbnails of the art for this example video has black bars to the left & right, which are ugly & unnecessary, so we can simply crop them off. I pick the thumbnail .jpg index numbered at 40, since that is first index of the largest size .jpg thumbnail returned, I presume it will have the most detail:

"The Old Ways Podcast - Six Seasons in Sartar - Episode 22 - Tears of the Vale [mRtKmFknE0o].40.jpg"

A higher index number, 43, also exists, but it has the same file size & image width & height, so I presume it is no different than #40.

What the FFMPEG manual has to say about using it to crop still images & video:

https://ffmpeg.org/ffmpeg-filters.html#crop

So to crop the black bars ( which are 280 pixels wide ) off of the #40 thumbnail of this example:

"C:\Program Files\FFMPEG For YT-DLP\ffmpeg.exe" -i "The Old Ways Podcast - Six Seasons in Sartar - Episode 22 - Tears of the Vale [mRtKmFknE0o].40.jpg" -vf "crop=720:720:280:0" cover_crop.jpg

I see that I cut off too much of the left & right sides of the art, discovering my initial guess that the art width was 720 pixels wide was off. Using Photoshop, I see the image is 1280 wide & 720 pixels tall. when I use the crop tool by hand to chop off the black bars, it becomes 869 pixels wide... I did that by hand so I just round that off to nearest ten, 870 pixels wide... Then 1280 - 870 = 410 total width of black pixels were cropped out from left & right, so to get the starting x position value of a proper crop with FFMPEG, we divide that by 2: 410 / 2 = 205... It only makes sense to go to this trouble, to expend this effort, if we plan to use a batch file to crop, scale & add thumbnails to LOTS of videos at once, or many, many times in the future!

The cropping command looks like this, generically:

"C:\Path_To_FFMPEG\ffmpeg.exe" -i input_image.jpg -vf "crop=720:720:280:0" output_image.jpg 

Cropping in my specific example case:

"C:\Program Files\FFMPEG For YT-DLP\ffmpeg.exe" -i "The Old Ways Podcast - Six Seasons in Sartar - Episode 22 - Tears of the Vale [mRtKmFknE0o].40.jpg" -vf "crop=870:720:205:0" cover_crop.jpg 

This leaves behind an output_image.jpg with 870x720 dimensions, still too large to use for the normal size .mkv cover art. We could have just cropped the input file down to a square 600x600 and be done with it, like so:

"C:\Path_To_FFMPEG\ffmpeg.exe" -i input_image.jpg -vf  "crop=out_w=600:out_h=600" cover.jpg

That just cuts out the center of the input image by default, like a cookie cutter. That might be "good enough" in some cases, but in this case it leaves an ugly art result, so we choose to follow the cropping-off of black bars with a scaling down from 870x720 to some_new_scaled_down_widthx600 instead:

ffmpeg -i cover_crop.jpg -vf scale="-1:600" cover.jpg

The actual command I applied to do this in my specific case is:

"C:\Program Files\FFMPEG For YT-DLP\ffmpeg.exe" -i "C:\yt-dlp\The Old Ways\cover_crop.jpg" -vf scale="-1:600" cover.jpg

In the end, I made a batch file to handle adding both normal & small thumbnails to 25 videos at once. I moved the index number "(filename_is_YouTube_video_title).40.jpg" thumbnails I got from the --write-all-thumbs of yt-dlp into a folder called "C:\yt-dlp\The Old Ways\Fast_Cover", and the matching .mkv files, "(filename_is_YouTube_video_title).mkv" are sitting in a folder named "C:\yt-dlp\The Old Ways\temp". Here's the batch file I used on Windows 10 to generate & combine the normal & small landscape orientation thumbnails to each video. I open a command prompt window at the "Fast_Cover" working directory, and run this batch file from that folder:

chcp 65001 >NUL
@ECHO OFF
TITLE Add Cover Thumbnails To .mkv Files

SETLOCAL EnableExtensions EnableDelayedExpansion

set /a count=0

for %%A IN ("C:\yt-dlp\The Old Ways\temp\*.mkv") DO (
 set filename=%%~nA
 set extension=%%~xA
 set /a count+=1
 echo Loop #:!count!
 set "output[!count!]=!filename!"
)

For /L %%i in (1,1,%count%) Do (
 Call :Action "!output[%%i]!"
)

REM DEL "*.jpg"

exit /b 0

::*******************************************************
:Action

echo ACTION:%~1

"C:\Program Files\FFMPEG For YT-DLP\ffmpeg.exe" -y -i "%~1.40.jpg" -vf scale="-1:600" cover_land.jpg
"C:\Program Files\FFMPEG For YT-DLP\ffmpeg.exe" -y -i "%~1.40.jpg" -vf scale="-1:120" small_cover_land.jpg

"C:\Program Files\FFMPEG For YT-DLP\ffmpeg.exe" -y ^
-i "C:\yt-dlp\The Old Ways\temp\%~1.mkv" ^
-attach "cover_land.jpg" ^
-attach "small_cover_land.jpg" ^
-map 0 ^
-c copy ^
-metadata:s:t mimetype=image/jpg ^
-metadata:s:t:0 filename=cover_land.jpg ^
-metadata:s:t:0 filename=small_cover_land.jpg ^
"%~1.mkv" 

exit /b 0
::*******************************************************

The very 1st line, "chcp 65001 >NUL" is there to help the batch file handle Unicode characters that show up all of the time in YouTube video titles.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.