Skip to content

Commit 70bd1bf

Browse files
committed
fix(mmclient): support decoding HDR with VideoToolbox on mac
1 parent 3ae66d2 commit 70bd1bf

File tree

3 files changed

+60
-27
lines changed

3 files changed

+60
-27
lines changed

mm-client/src/bin/mmclient.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ fn init_logging() -> Result<()> {
925925

926926
// Squash ffmpeg logs.
927927
unsafe {
928-
ffmpeg_sys::av_log_set_level(ffmpeg_sys::AV_LOG_QUIET);
928+
ffmpeg_sys::av_log_set_level(ffmpeg_sys::AV_LOG_VERBOSE);
929929
// TODO: the callback has to be variadic, which means using nightly rust.
930930
// ffmpeg_sys::av_log_set_callback(Some(ffmpeg_log_callback))
931931
}

mm-client/src/render.slang

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ float3 bt2020_pq_to_display(float3 color, int vk_color_space)
7878
switch (vk_color_space)
7979
{
8080
case VK_COLOR_SPACE_SRGB_NONLINEAR_EXT:
81-
return srgb_inverse_eotf(clamp(linear, 0.0, 1.0));
81+
return srgb_inverse_eotf(linear);
8282
VK_COLOR_SPACE_BT709_NONLINEAR_EXT:
8383
return bt709_inverse_eotf(clamp(linear, 0.0, 1.0));
8484
case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:

mm-client/src/video.rs

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -392,8 +392,28 @@ impl DecoderInit {
392392
Ok(()) => {
393393
self.first_frame = match frame.format() {
394394
ffmpeg::format::Pixel::VIDEOTOOLBOX => {
395+
let sw_format = unsafe {
396+
let ctx_ref = (*self.decoder.as_ptr()).hw_frames_ctx;
397+
assert!(!ctx_ref.is_null());
398+
399+
let mut transfer_fmt_list = std::ptr::null_mut();
400+
if ffmpeg_sys::av_hwframe_transfer_get_formats(
401+
ctx_ref,
402+
ffmpeg_sys::AVHWFrameTransferDirection::AV_HWFRAME_TRANSFER_DIRECTION_FROM,
403+
&mut transfer_fmt_list,
404+
0) < 0
405+
{
406+
bail!("call to av_hwframe_transfer_get_formats failed");
407+
};
408+
409+
let transfer_formats = read_format_list(transfer_fmt_list);
410+
assert!(!transfer_formats.is_empty());
411+
412+
transfer_formats[0]
413+
};
414+
395415
let mut sw_frame = ffmpeg::frame::Video::new(
396-
ffmpeg::format::Pixel::P010LE, // xxx
416+
sw_format,
397417
self.decoder.width(),
398418
self.decoder.height(),
399419
);
@@ -1025,38 +1045,51 @@ fn copy_frame(
10251045
#[no_mangle]
10261046
unsafe extern "C" fn get_hw_format_videotoolbox(
10271047
ctx: *mut ffmpeg_sys::AVCodecContext,
1028-
mut formats: *const ffmpeg_sys::AVPixelFormat,
1048+
list: *const ffmpeg_sys::AVPixelFormat,
10291049
) -> ffmpeg_sys::AVPixelFormat {
10301050
use ffmpeg_sys::AVPixelFormat::*;
10311051

1032-
while *formats != AV_PIX_FMT_NONE {
1033-
if *formats == AV_PIX_FMT_VIDEOTOOLBOX {
1034-
let frames_ctx_ref = ffmpeg_sys::av_hwframe_ctx_alloc((*ctx).hw_device_ctx);
1035-
if frames_ctx_ref.is_null() {
1036-
error!("call to av_hwframe_ctx_alloc failed");
1037-
break;
1038-
}
1052+
let sw_pix_fmt = (*ctx).sw_pix_fmt;
1053+
let formats = read_format_list(list);
1054+
1055+
if formats.contains(&ffmpeg::format::Pixel::VIDEOTOOLBOX) {
1056+
let frames_ctx_ref = ffmpeg_sys::av_hwframe_ctx_alloc((*ctx).hw_device_ctx);
1057+
if frames_ctx_ref.is_null() {
1058+
error!("call to av_hwframe_ctx_alloc failed");
1059+
return sw_pix_fmt;
1060+
}
10391061

1040-
let frames_ctx = (*frames_ctx_ref).data as *mut ffmpeg_sys::AVHWFramesContext;
1041-
(*frames_ctx).width = (*ctx).width;
1042-
(*frames_ctx).height = (*ctx).height;
1043-
(*frames_ctx).format = AV_PIX_FMT_VIDEOTOOLBOX;
1044-
(*frames_ctx).sw_format = (*ctx).sw_pix_fmt;
1062+
debug!(?formats, sw_pix_fmt = ?sw_pix_fmt, "get_hw_format_videotoolbox");
10451063

1046-
let res = ffmpeg_sys::av_hwframe_ctx_init(frames_ctx_ref);
1047-
if res < 0 {
1048-
error!("call to av_hwframe_ctx_init failed");
1049-
break;
1050-
}
1064+
let frames_ctx = (*frames_ctx_ref).data as *mut ffmpeg_sys::AVHWFramesContext;
1065+
(*frames_ctx).width = (*ctx).width;
1066+
(*frames_ctx).height = (*ctx).height;
1067+
(*frames_ctx).format = AV_PIX_FMT_VIDEOTOOLBOX;
1068+
(*frames_ctx).sw_format = AV_PIX_FMT_YUV420P;
10511069

1052-
debug!("using VideoToolbox hardware encoder");
1053-
(*ctx).hw_frames_ctx = frames_ctx_ref;
1054-
return *formats;
1070+
let res = ffmpeg_sys::av_hwframe_ctx_init(frames_ctx_ref);
1071+
if res < 0 {
1072+
error!("call to av_hwframe_ctx_init failed");
1073+
return sw_pix_fmt;
10551074
}
10561075

1057-
formats = formats.add(1);
1076+
debug!("using VideoToolbox hardware encoder");
1077+
(*ctx).hw_frames_ctx = frames_ctx_ref;
1078+
return AV_PIX_FMT_VIDEOTOOLBOX;
1079+
}
1080+
1081+
warn!("unable to determine ffmpeg hw format");
1082+
sw_pix_fmt
1083+
}
1084+
1085+
unsafe fn read_format_list(
1086+
mut ptr: *const ffmpeg_sys::AVPixelFormat,
1087+
) -> Vec<ffmpeg::format::Pixel> {
1088+
let mut formats = Vec::new();
1089+
while !ptr.is_null() && *ptr != ffmpeg_sys::AVPixelFormat::AV_PIX_FMT_NONE {
1090+
formats.push((*ptr).into());
1091+
ptr = ptr.add(1);
10581092
}
10591093

1060-
warn!("VideoToolbox setup failed, falling back to CPU decoder");
1061-
AV_PIX_FMT_YUV420P10LE
1094+
formats
10621095
}

0 commit comments

Comments
 (0)