use h264_reader::nal::slice::PicOrderCountLsb;
use super::nalu_parser::Slice;
#[derive(Default)]
pub(crate) struct AUSplitter {
buffered_nals: Vec<(Slice, Option<u64>)>,
}
impl AUSplitter {
pub(crate) fn put_slice(
&mut self,
slice: Slice,
pts: Option<u64>,
) -> Option<Vec<(Slice, Option<u64>)>> {
if self.is_new_au(&slice) {
let au = std::mem::take(&mut self.buffered_nals);
self.buffered_nals.push((slice, pts));
if !au.is_empty() {
Some(au)
} else {
None
}
} else {
self.buffered_nals.push((slice, pts));
None
}
}
fn is_new_au(&self, slice: &Slice) -> bool {
let Some((last, _)) = self.buffered_nals.last() else {
return true;
};
first_mb_in_slice_zero(slice)
|| frame_num_differs(last, slice)
|| pps_id_differs(last, slice)
|| field_pic_flag_differs(last, slice)
|| nal_ref_idc_differs_one_zero(last, slice)
|| pic_order_cnt_zero_check(last, slice)
|| idr_and_non_idr(last, slice)
|| idrs_where_idr_pic_id_differs(last, slice)
}
}
fn first_mb_in_slice_zero(slice: &Slice) -> bool {
slice.header.first_mb_in_slice == 0
}
fn frame_num_differs(last: &Slice, curr: &Slice) -> bool {
last.header.frame_num != curr.header.frame_num
}
fn pps_id_differs(last: &Slice, curr: &Slice) -> bool {
last.pps_id != curr.pps_id
}
fn field_pic_flag_differs(last: &Slice, curr: &Slice) -> bool {
last.header.field_pic != curr.header.field_pic
}
fn nal_ref_idc_differs_one_zero(last: &Slice, curr: &Slice) -> bool {
(last.nal_header.nal_ref_idc() == 0 || curr.nal_header.nal_ref_idc() == 0)
&& last.nal_header.nal_ref_idc() != curr.nal_header.nal_ref_idc()
}
fn pic_order_cnt_zero_check(last: &Slice, curr: &Slice) -> bool {
let (last_pic_order_cnt_lsb, last_delta_pic_order_cnt_bottom) =
match last.header.pic_order_cnt_lsb {
Some(PicOrderCountLsb::Frame(pic_order_cnt_lsb)) => (pic_order_cnt_lsb, 0),
Some(PicOrderCountLsb::FieldsAbsolute {
pic_order_cnt_lsb,
delta_pic_order_cnt_bottom,
}) => (pic_order_cnt_lsb, delta_pic_order_cnt_bottom),
_ => return false,
};
let (curr_pic_order_cnt_lsb, curr_delta_pic_order_cnt_bottom) =
match curr.header.pic_order_cnt_lsb {
Some(PicOrderCountLsb::Frame(pic_order_cnt_lsb)) => (pic_order_cnt_lsb, 0),
Some(PicOrderCountLsb::FieldsAbsolute {
pic_order_cnt_lsb,
delta_pic_order_cnt_bottom,
}) => (pic_order_cnt_lsb, delta_pic_order_cnt_bottom),
_ => return false,
};
last_pic_order_cnt_lsb != curr_pic_order_cnt_lsb
|| last_delta_pic_order_cnt_bottom != curr_delta_pic_order_cnt_bottom
}
fn idr_and_non_idr(last: &Slice, curr: &Slice) -> bool {
(last.nal_header.nal_unit_type().id() == 5) ^ (curr.nal_header.nal_unit_type().id() == 5)
}
fn idrs_where_idr_pic_id_differs(last: &Slice, curr: &Slice) -> bool {
match (last.header.idr_pic_id, curr.header.idr_pic_id) {
(Some(last), Some(curr)) => last != curr,
_ => false,
}
}