1

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
asked Aug 25, 2022 at 22:55
3
  • 1
    Share full log of the command you tried. Commented Aug 26, 2022 at 4:13
  • @Gyan I've added the log to the question. Commented 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" Commented Aug 26, 2022 at 7:06

1 Answer 1

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
  • 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
answered Aug 26, 2022 at 9:50
5
  • 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). Commented 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. Commented 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. Commented 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. Commented Aug 27, 2022 at 11:28
  • For anyone else interested, I saw an interesting conversation at forum.luminous-landscape.com/index.php?topic=129232.0 Commented Aug 27, 2022 at 11:31

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.