use crate::{
define::{TH_ESStreamInfo, *},
helper::packet::{packet_final::CPacketViewRela, traits::AsCPacketView as _},
};
type RelaRef<'a> = Vec<CPacketViewRela<'a>>;
struct DataLifeTime<'a> {
datas: Vec<*const u8>,
datas_life_time: Vec<&'a [u8]>,
}
impl<'a> DataLifeTime<'a> {
fn new() -> Self {
Self {
datas: Vec::new(),
datas_life_time: Vec::new(),
}
}
fn push(&mut self, data: &'a [u8]) {
self.datas_life_time.push(data);
self.datas.push(data.as_ptr());
}
fn as_dptr(&self) -> *const *const u8 {
self.datas.as_ptr()
}
}
pub struct ThEsstreamInfoGuard<'a> {
#[allow(dead_code)]
datas: DataLifeTime<'a>,
#[allow(dead_code)]
lens: Vec<usize>,
#[allow(dead_code)]
infos: Vec<&'a TH_ESStreamInfo>,
info: TH_ESStreamInfo,
}
impl<'a> ThEsstreamInfoGuard<'a> {
fn new(relas: &'a RelaRef, base_info: &TH_ESStreamInfo) -> Self {
let mut lens = Vec::with_capacity(relas.len());
let mut infos: Vec<&'a TH_ESStreamInfo> = Vec::with_capacity(relas.len());
let mut datas = DataLifeTime::new();
for rela in relas.iter() {
datas.push(rela.get_data());
lens.push(rela.get_data().len());
infos.push(rela.get_info());
}
let mut info = *base_info;
info.rela_count = infos.len() as _;
info.rela_info = infos.as_ptr() as _;
info.rela_data = datas.as_dptr() as _;
info.rela_data_len = lens.as_ptr() as _;
ThEsstreamInfoGuard {
datas,
lens,
infos,
info,
}
}
pub fn info(&self) -> &TH_ESStreamInfo {
&self.info
}
}
#[must_use = "Guard here"]
pub fn set_info_relas<'a>(base_info: &TH_ESStreamInfo, relas: &'a RelaRef) -> ThEsstreamInfoGuard<'a> {
ThEsstreamInfoGuard::new(relas, base_info)
}
pub fn get_info_relas(info: &'_ TH_ESStreamInfo) -> RelaRef<'_> {
let mut infos = Vec::new();
if info.rela_count == 0 {
return infos;
}
if info.rela_count > 10000 {
tracing::warn!("Invalid rela packet, skip parse rela packet, info:{:?}", info);
return infos;
}
for index in 0..info.rela_count {
let index: isize = index as _;
let info_ptr = unsafe { *(info.rela_info as *const *const TH_ESStreamInfo).offset(index) };
let rela_data = unsafe {
let ptr = *(info.rela_data as *const *const u8).offset(index);
let len = *(info.rela_data_len as *const usize).offset(index);
std::slice::from_raw_parts(ptr, len)
};
let rela = CPacketViewRela::new(rela_data, unsafe { &*info_ptr });
infos.push(rela)
}
infos
}
pub fn clear_info_relas(info: &mut TH_ESStreamInfo) {
info.rela_count = 0;
info.rela_data = 0;
info.rela_data_len = 0;
info.rela_info = 0;
}
pub fn is_es_decodable_vcodec(info: &TH_ESStreamInfo) -> bool {
info.vCodecType == TH_VIDEOCODECTYPE_TH_VCT_H265
|| info.vCodecType == TH_VIDEOCODECTYPE_TH_VCT_H264
|| info.vCodecType == TH_VIDEOCODECTYPE_TH_VCT_SVAC
|| info.vCodecType == 6
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_case_mix() {
let data1 = vec![1u8, 2, 3];
let data2 = vec![4u8, 5, 6, 7];
let rela_info1 = TH_ESStreamInfo {
streamType: 1,
..Default::default()
};
let rela_info2 = TH_ESStreamInfo {
streamType: 2,
..Default::default()
};
let rela_infos = vec![
CPacketViewRela::new(&data1, &rela_info1),
CPacketViewRela::new(&data2, &rela_info2),
];
let base_info = TH_ESStreamInfo {
streamType: 3,
..Default::default()
};
let guard = set_info_relas(&base_info, &rela_infos);
{
let out_info = get_info_relas(guard.info());
assert_eq!(out_info.len(), 2);
assert_eq!(out_info[0].stream_type(), 1);
assert_eq!(out_info[0].as_slice(), [1, 2, 3]);
assert_eq!(out_info[1].stream_type(), 2);
assert_eq!(out_info[1].as_slice().len(), 4);
assert_eq!(out_info[1].as_slice(), [4, 5, 6, 7]);
}
{
let mut info_cloned = *guard.info();
clear_info_relas(&mut info_cloned);
let out_info = get_info_relas(&info_cloned);
assert_eq!(out_info.len(), 0);
}
}
}