I'm trying to embed a custom ICC profile in an MP4, but can't find how to do it with ffmpeg.
I have the frames of an animation saved in PNGs with an embedded custom ICC profile. The PNGs are shown color managed, on a profiled wide gamut displayed.
I've tried, unsuccessfully, to write the same ICC profile in videos.
At https://ffmpeg.org/ffmpeg-codecs.html I've found the "flags2 icc_profiles" but since I don't see a way to specify the ICC file, I presumed the profile embedded in the first PNG would be used. But it's not working.
At https://vectronic.io/posts/ffmpeg-now-supports-icc-profiles-in-mp4/ there is an MP4 with an embedded ICC profile, but there is no explanation on how the profile was written into the sample.
My batch command is:
ffmpeg -i "frame%%4d.png" -c:v libsvtav1 -pix_fmt yuv420p10le -color_range pc -svtav1-params crf=10:mbr=20M -movflags faststart output.mp4
("color_range" doesn't make a difference in my case)
If I use the options "-colorspace bt709 -color_primaries bt709 -color_trc bt709" Firefox and Ffplay show the video color managed (looks like BT709 or close enough).
If I use the "movflags +write_colr+prefer_icc" the video is also color managed (and looks the same as BT709 above).
EDIT (log):
C:\icctest>"C:\icctest\ffmpeg.exe" -y -framerate 30 -i "C:\icctest\frames\frame%4d.png" -c:v libsvtav1 -pix_fmt yuv420p10le -flags2 icc_profiles -color_range pc -svtav1-params crf=10:mbr=20M:keyint=2s -movflags faststart "C:\icctest\output.mp4"
ffmpeg version 2022年08月22日-git-f23e3ce858-full_build-www.gyan.dev Copyright (c) 2000-2022 the FFmpeg developers
built with gcc 12.1.0 (Rev2, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libdavs2 --enable-libuavs3d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libaom --enable-libjxl --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-liblensfun --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libshaderc --enable-vulkan --enable-libplacebo --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
libavutil 57. 33.101 / 57. 33.101
libavcodec 59. 42.102 / 59. 42.102
libavformat 59. 30.100 / 59. 30.100
libavdevice 59. 8.101 / 59. 8.101
libavfilter 8. 46.103 / 8. 46.103
libswscale 6. 8.103 / 6. 8.103
libswresample 4. 8.100 / 4. 8.100
libpostproc 56. 7.100 / 56. 7.100
Input #0, image2, from 'C:\icctest\frames\frame%4d.png':
Duration: 00:00:00.30, start: 0.000000, bitrate: N/A
Stream #0:0: Video: png, rgb48be(pc), 1920x1080 [SAR 3780:3780 DAR 16:9], 30 fps, 30 tbr, 30 tbn
Stream mapping:
Stream #0:0 -> #0:0 (png (native) -> av1 (libsvtav1))
Press [q] to stop, [?] for help
[image2 @ 000002a6a9063cc0] Thread message queue blocking; consider raising the thread_queue_size option (current value: 1)
Svt[info]: -------------------------------------------
Svt[info]: SVT [version]: SVT-AV1 Encoder Lib v1.2.1-7-g5f4c0fe8
Svt[info]: SVT [build] : GCC 12.2.0 64 bit
Svt[info]: LIB Build date: Aug 21 2022 13:29:44
Svt[info]: -------------------------------------------
Svt[info]: Number of logical cores available: 4
Svt[info]: Number of PPCS 37
Svt[info]: [asm level on system : up to avx2]
Svt[info]: [asm level selected : up to avx2]
Svt[info]: -------------------------------------------
Svt[info]: SVT [config]: main profile tier (auto) level (auto)
Svt[info]: SVT [config]: width / height / fps numerator / fps denominator : 1920 / 1080 / 30 / 1
Svt[info]: SVT [config]: bit-depth / color format / compressed 10-bit format : 10 / YUV420 / 0
Svt[info]: SVT [config]: preset / tune / pred struct : 10 / PSNR / random access
Svt[info]: SVT [config]: gop size / mini-gop size / key-frame type : 61 / 16 / key frame
Svt[info]: SVT [config]: BRC mode / rate factor / max bitrate (kbps) : capped CRF / 10 / 20000
Svt[info]: -------------------------------------------
Output #0, mp4, to 'C:\icctest\output.mp4':
Metadata:
encoder : Lavf59.30.100
Stream #0:0: Video: av1 (av01 / 0x31307661), yuv420p10le(pc, progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 30 fps, 15360 tbn
Metadata:
encoder : Lavc59.42.102 libsvtav1
Side data:
cpb: bitrate max/min/avg: 20000000/0/0 buffer size: 0 vbv_delay: N/A
frame= 0 fps=0.0 q=0.0 size= 0kB time=-577014:32:22.77 bitrate= -0.0kb[mp4 @ 000002a6a90730c0] Starting second pass: moving the moov atom to the beginning of the file
frame= 9 fps=5.5 q=10.0 Lsize= 2431kB time=00:00:00.26 bitrate=74668.8kbits/s speed=0.163x
video:2430kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.036133%
EDIT2 (ffprobe):
C:\icctest>"C:\icctest\ffprobe.exe" "C:\icctest\output.mp4"
ffprobe version 2022年08月22日-git-f23e3ce858-full_build-www.gyan.dev Copyright (c) 2007-2022 the FFmpeg developers
built with gcc 12.1.0 (Rev2, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libdavs2 --enable-libuavs3d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libaom --enable-libjxl --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-liblensfun --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libshaderc --enable-vulkan --enable-libplacebo --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
libavutil 57. 33.101 / 57. 33.101
libavcodec 59. 42.102 / 59. 42.102
libavformat 59. 30.100 / 59. 30.100
libavdevice 59. 8.101 / 59. 8.101
libavfilter 8. 46.103 / 8. 46.103
libswscale 6. 8.103 / 6. 8.103
libswresample 4. 8.100 / 4. 8.100
libpostproc 56. 7.100 / 56. 7.100
[libdav1d @ 0000026b98308e40] libdav1d 1.0.0-46-gcd5e415
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\icctest\output.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomav01iso2mp41
encoder : Lavf59.30.100
Duration: 00:00:00.30, start: 0.000000, bitrate: 66372 kb/s
Stream #0:0[0x1](und): Video: av1 (Main) (av01 / 0x31307661), yuv420p10le(pc, progressive), 1920x1080, 66347 kb/s, SAR 1:1 DAR 16:9, 30 fps, 30 tbr, 15360 tbn (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
encoder : Lavc59.42.102 libsvtav1
[libdav1d @ 0000026b988a3c80] libdav1d 1.0.0-46-gcd5e415
-
1Share full log of the command you tried.Gyan– Gyan2022年08月26日 04:13:16 +00:00Commented Aug 26, 2022 at 4:13
-
@Gyan I've added the log to the question.Mark– Mark2022年08月26日 06:50:38 +00:00Commented Aug 26, 2022 at 6:50
-
@Gyan I've also added the ffprobe log to the question. You can see there is no side data / ICC profile even though the convert used "-flags2 icc_profiles"Mark– Mark2022年08月26日 07:06:02 +00:00Commented Aug 26, 2022 at 7:06
1 Answer 1
Searching through the documentation of FFmpeg, it looks like there is no support for adding custom ICC profile to MP4 file.
We may use MP4Box instead:
- Create the MP4 video without the embedded ICC profile.
- Extract the ICC profile from the PNG image using ImageMagick or exiftool.
- Using ImageMagick:
magick icc_image.png profile.icc - Using exiftool:
exiftool -icc_profile -b icc_image.png > profile.icc
- Using ImageMagick:
- Add the ICC profile to the MP4 video file using MP4Box (create new video file with the ICC profile as side data):
MP4Box -add video.mp4#video:colr=prof,profile.icc -new icc_video.mp4
Example:
I used GIMP for adding ICC profile to chelsea.png:
icc_chelsea.png:
enter image description here
Creating MP4 video without ICC profile (for testing):
ffmpeg -y -loop 1 -framerate 1 -i icc_chelsea.png -vcodec libx265 -t 10 chelsea.mp4
Extracting the ICC profile:
magick icc_chelsea.png profile.icc
Adding the ICC profile to the MP4 video file using MP4Box:
MP4Box -add video.mp4#video:colr=prof,profile.icc -new icc_video.mp4
Testing with FFprobe:
ffprobe icc_chelsea.mp4
Result:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'icc_chelsea.mp4':
Metadata:
major_brand : isom
minor_version : 1
compatible_brands: isom
creation_time : 2022年08月26日T09:15:00.000000Z
Duration: 00:00:10.00, start: 0.000000, bitrate: 44 kb/s
Stream #0:0[0x1](und): Video: hevc (Rext) (hev1 / 0x31766568), gbrp(pc, gbr/unknown/unknown, progressive), 385x256 [SAR 1:1 DAR 385:256], 40 kb/s, 1 fps, 1 tbr, 16384 tbn (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
encoder : Lavc59.37.100 libx265
Side data:
ICC Profile
-
Thank you for this! I'll try it out. I already have the ICC profile since it's my display's profile (but other people will surely appreciate your details).Mark– Mark2022年08月26日 10:45:50 +00:00Commented Aug 26, 2022 at 10:45
-
I've tested this and it worked (at least ffprobe says the video has an ICC profile). Unfortunately, the result isn't color managed, not fully, like images are. So, either the embedded or display profile isn't used, and the video looks like it's shown on an sRGB display. Following more investigation, it looks like the video data has to be in the colorspace expected for the type of video: BT709 for HD.Mark– Mark2022年08月26日 23:59:15 +00:00Commented Aug 26, 2022 at 23:59
-
I assume that all common video players ignore the embedded ICC profile. Maybe there are professional video editing software that use it. You may enable color management in MPC-HC Player. I suppose MPC-HC uses the ICC profile according to Windows display settings. I never tried it.Rotem– Rotem2022年08月27日 08:11:59 +00:00Commented Aug 27, 2022 at 8:11
-
I've tried MPC-HC because it allows the user to enable or disable color management. When it's disabled, the image looks native, like the Windows wallpaper. When it's enabled, the image looks like Firefox and FFPlayer show: washed-out color, sRGB-like. My display can simulate sRGB, so I can switch to that mode to compare. I've also seen the images and videos on narrow gamut and wide gamut displays, side by side. In any case, my real concern is how the videos would look like on wide gamut smart TVs. I might have to convert the frame data to another colorspace.Mark– Mark2022年08月27日 11:28:16 +00:00Commented Aug 27, 2022 at 11:28
-
For anyone else interested, I saw an interesting conversation at forum.luminous-landscape.com/index.php?topic=129232.0Mark– Mark2022年08月27日 11:31:06 +00:00Commented Aug 27, 2022 at 11:31