rtc_media/io/h26x_reader/
sample_reader.rs1use bytes::{Bytes, BytesMut};
2use shared::error::{Error, Result};
3use std::io::Read;
4
5use super::{H26xNAL, H26xReader, H264NalUnitType, H265NalUnitType};
6
7const ANNEXB_START_CODE: [u8; 4] = [0x00, 0x00, 0x00, 0x01];
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct H26xSample {
12 pub data: Bytes,
14 pub timed: bool,
16}
17
18pub struct H26xSampleReader<R: Read> {
20 reader: H26xReader<R>,
21 is_hevc: bool,
22 pending_hevc_nals: Vec<BytesMut>,
23}
24
25impl<R: Read> H26xSampleReader<R> {
26 pub fn new(reader: R, capacity: usize, is_hevc: bool) -> Self {
30 Self {
31 reader: H26xReader::new(reader, capacity, is_hevc),
32 is_hevc,
33 pending_hevc_nals: vec![],
34 }
35 }
36
37 pub fn next_sample(&mut self) -> Result<H26xSample> {
43 loop {
44 let nal = match self.reader.next_nal() {
45 Ok(nal) => nal,
46 Err(Error::ErrIoEOF) if self.is_hevc && !self.pending_hevc_nals.is_empty() => {
47 let data = build_hevc_access_unit(&mut self.pending_hevc_nals, None);
48 return Ok(H26xSample { data, timed: false });
49 }
50 Err(err) => return Err(err),
51 };
52
53 let timed = !should_skip_timing(&nal);
54 if self.is_hevc && should_buffer_with_next_hevc_vcl(&nal) {
55 self.pending_hevc_nals.push(nal.data().clone());
56 continue;
57 }
58
59 let data = if self.is_hevc && !self.pending_hevc_nals.is_empty() {
60 build_hevc_access_unit(&mut self.pending_hevc_nals, Some(nal.data()))
61 } else {
62 nal.data().clone().freeze()
63 };
64
65 return Ok(H26xSample { data, timed });
66 }
67 }
68}
69
70fn should_skip_timing(nal: &H26xNAL) -> bool {
71 match nal {
72 H26xNAL::H264(nal) => {
73 matches!(
74 nal.unit_type,
75 H264NalUnitType::SPS
76 | H264NalUnitType::PPS
77 | H264NalUnitType::SEI
78 | H264NalUnitType::AUD
79 )
80 }
81 H26xNAL::H265(nal) => {
82 matches!(
83 nal.unit_type,
84 H265NalUnitType::VPS
85 | H265NalUnitType::SPS
86 | H265NalUnitType::PPS
87 | H265NalUnitType::PrefixSEI
88 | H265NalUnitType::SuffixSEI
89 | H265NalUnitType::AUD
90 )
91 }
92 }
93}
94
95fn should_buffer_with_next_hevc_vcl(nal: &H26xNAL) -> bool {
96 matches!(
97 nal,
98 H26xNAL::H265(nal)
99 if matches!(
100 nal.unit_type,
101 H265NalUnitType::VPS
102 | H265NalUnitType::SPS
103 | H265NalUnitType::PPS
104 | H265NalUnitType::PrefixSEI
105 | H265NalUnitType::SuffixSEI
106 | H265NalUnitType::AUD
107 )
108 )
109}
110
111fn build_hevc_access_unit(
112 buffered_nals: &mut Vec<BytesMut>,
113 current_nal: Option<&BytesMut>,
114) -> Bytes {
115 let total_len = buffered_nals
116 .iter()
117 .map(|nal| ANNEXB_START_CODE.len() + nal.len())
118 .sum::<usize>()
119 + current_nal.map_or(0, |nal| ANNEXB_START_CODE.len() + nal.len());
120 let mut access_unit = BytesMut::with_capacity(total_len);
121
122 for nal in buffered_nals.drain(..) {
123 access_unit.extend_from_slice(&ANNEXB_START_CODE);
124 access_unit.extend_from_slice(&nal);
125 }
126 if let Some(current_nal) = current_nal {
127 access_unit.extend_from_slice(&ANNEXB_START_CODE);
128 access_unit.extend_from_slice(current_nal);
129 }
130
131 access_unit.freeze()
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use std::io::Cursor;
138
139 #[test]
140 fn h265_sample_reader_groups_parameter_sets_with_following_vcl() -> Result<()> {
141 let stream = vec![
142 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x44, 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x28, 0x01, 0xaa, ];
147 let mut reader = H26xSampleReader::new(Cursor::new(stream), 1024, true);
148
149 let sample = reader.next_sample()?;
150
151 assert!(sample.timed);
152 assert_eq!(
153 sample.data,
154 Bytes::from_static(&[
155 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x44, 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x28, 0x01, 0xaa, ])
160 );
161 assert!(matches!(reader.next_sample(), Err(Error::ErrIoEOF)));
162
163 Ok(())
164 }
165
166 #[test]
167 fn h264_sample_reader_keeps_parameter_sets_separate_and_untimed() -> Result<()> {
168 let stream = vec![
169 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x06, 0xe2, 0x00, 0x00, 0x00, 0x01, 0x65, 0x88, 0x84, 0x21, ];
173 let mut reader = H26xSampleReader::new(Cursor::new(stream), 1024, false);
174
175 let sps = reader.next_sample()?;
176 assert!(!sps.timed);
177 assert_eq!(sps.data, Bytes::from_static(&[0x67, 0x42, 0x00, 0x1f]));
178
179 let pps = reader.next_sample()?;
180 assert!(!pps.timed);
181 assert_eq!(pps.data, Bytes::from_static(&[0x68, 0xce, 0x06, 0xe2]));
182
183 let idr = reader.next_sample()?;
184 assert!(idr.timed);
185 assert_eq!(idr.data, Bytes::from_static(&[0x65, 0x88, 0x84, 0x21]));
186
187 Ok(())
188 }
189}