#![allow(unsafe_code)]
use mediaway_common::Bytes;
use objc2_core_media::{
CMFormatDescription, CMVideoFormatDescriptionGetH264ParameterSetAtIndex,
CMVideoFormatDescriptionGetHEVCParameterSetAtIndex,
};
const NO_ERROR: i32 = 0;
pub(super) fn extract_h264(format_desc: &CMFormatDescription) -> Option<Bytes> {
let (sps_ptr, sps_len, param_count) = h264_parameter_set_at_index(format_desc, 0)?;
if param_count < 2 {
return None;
}
let (pps_ptr, pps_len, _) = h264_parameter_set_at_index(format_desc, 1)?;
let (sps, pps) = unsafe {
(
std::slice::from_raw_parts(sps_ptr, sps_len),
std::slice::from_raw_parts(pps_ptr, pps_len),
)
};
let mut annex_b = Vec::with_capacity(8 + sps.len() + pps.len());
annex_b.extend_from_slice(&[0, 0, 0, 1]);
annex_b.extend_from_slice(sps);
annex_b.extend_from_slice(&[0, 0, 0, 1]);
annex_b.extend_from_slice(pps);
iso_bmff::bitstream::avc::to_avcc(&annex_b).avcc
}
pub(super) fn extract_hevc(format_desc: &CMFormatDescription) -> Option<Bytes> {
let (vps_ptr, vps_len, param_count) = hevc_parameter_set_at_index(format_desc, 0)?;
if param_count < 3 {
return None;
}
let (sps_ptr, sps_len, _) = hevc_parameter_set_at_index(format_desc, 1)?;
let (pps_ptr, pps_len, _) = hevc_parameter_set_at_index(format_desc, 2)?;
let (vps, sps, pps) = unsafe {
(
std::slice::from_raw_parts(vps_ptr, vps_len),
std::slice::from_raw_parts(sps_ptr, sps_len),
std::slice::from_raw_parts(pps_ptr, pps_len),
)
};
let mut annex_b = Vec::with_capacity(12 + vps.len() + sps.len() + pps.len());
for nal in [vps, sps, pps] {
annex_b.extend_from_slice(&[0, 0, 0, 1]);
annex_b.extend_from_slice(nal);
}
iso_bmff::bitstream::hevc::to_hvcc(&annex_b).hvcc
}
fn h264_parameter_set_at_index(
format_desc: &CMFormatDescription,
index: usize,
) -> Option<(*const u8, usize, usize)> {
let mut ptr: *const u8 = std::ptr::null();
let mut len: usize = 0;
let mut count: usize = 0;
let status = unsafe {
CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
format_desc,
index,
&raw mut ptr,
&raw mut len,
&raw mut count,
std::ptr::null_mut(),
)
};
if status != NO_ERROR || ptr.is_null() {
return None;
}
Some((ptr, len, count))
}
fn hevc_parameter_set_at_index(
format_desc: &CMFormatDescription,
index: usize,
) -> Option<(*const u8, usize, usize)> {
let mut ptr: *const u8 = std::ptr::null();
let mut len: usize = 0;
let mut count: usize = 0;
let status = unsafe {
CMVideoFormatDescriptionGetHEVCParameterSetAtIndex(
format_desc,
index,
&raw mut ptr,
&raw mut len,
&raw mut count,
std::ptr::null_mut(),
)
};
if status != NO_ERROR || ptr.is_null() {
return None;
}
Some((ptr, len, count))
}