Skip to content

Commit 39e3d00

Browse files
committed
decoder/h264: process one NAL unit per call to decode
1 parent 66bf1d2 commit 39e3d00

File tree

3 files changed

+95
-198
lines changed

3 files changed

+95
-198
lines changed

src/codec/h264/parser.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub struct Rect<T> {
5858
pub max: Point<T>,
5959
}
6060

61-
#[derive(N, Debug)]
61+
#[derive(N, Debug, PartialEq, Eq, Clone, Copy)]
6262
pub enum NaluType {
6363
Unknown = 0,
6464
Slice = 1,
@@ -2452,8 +2452,8 @@ impl NaluHeader {
24522452
}
24532453

24542454
/// Get a reference to the nalu header's type.
2455-
pub fn nalu_type(&self) -> &NaluType {
2456-
&self.type_
2455+
pub fn nalu_type(&self) -> NaluType {
2456+
self.type_
24572457
}
24582458

24592459
/// Get a reference to the nalu header's idr pic flag.

src/decoder/stateless/h264.rs

+83-83
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ pub struct H264DecoderState<B: StatelessDecoderBackend<Sps>> {
233233
/// We are not using `DbpEntry<T>` as the type because contrary to a DPB entry,
234234
/// the handle of this member is always valid.
235235
last_field: Option<(Rc<RefCell<PictureData>>, B::Handle)>,
236+
237+
/// The picture currently being decoded. We need to preserve it between calls to `decode`
238+
/// because multiple slices will be processed in different calls to `decode`.
239+
current_pic: Option<CurrentPicState<B>>,
236240
}
237241

238242
impl<B> Default for H264DecoderState<B>
@@ -250,10 +254,20 @@ where
250254
prev_pic_info: Default::default(),
251255
max_long_term_frame_idx: Default::default(),
252256
last_field: Default::default(),
257+
current_pic: None,
253258
}
254259
}
255260
}
256261

262+
/// [`StatelessCodec`] structure to use in order to create a H.264 stateless decoder.
263+
///
264+
/// # Accepted input
265+
///
266+
/// A decoder using this codec processes exactly one NAL unit of input per call to
267+
/// [`StatelessDecoder::decode`], and returns the number of bytes until the end of this NAL unit.
268+
/// This makes it possible to call [`Decode`](StatelessDecoder::decode) repeatedly on some unsplit
269+
/// Annex B stream and shrinking it by the number of bytes processed after each call, until the
270+
/// stream ends up being empty.
257271
pub struct H264;
258272

259273
impl StatelessCodec for H264 {
@@ -617,8 +631,6 @@ where
617631
max_num_order_frames
618632
};
619633

620-
self.ready_queue.extend(self.codec.drain());
621-
622634
self.coded_resolution = resolution;
623635

624636
self.codec
@@ -627,6 +639,17 @@ where
627639
self.codec.dpb.set_interlaced(interlaced);
628640
}
629641

642+
fn drain(&mut self) -> anyhow::Result<()> {
643+
// Finish the current picture if there is one pending.
644+
if let Some(cur_pic) = self.codec.current_pic.take() {
645+
self.finish_picture(cur_pic)?;
646+
}
647+
648+
self.ready_queue.extend(self.codec.drain());
649+
650+
Ok(())
651+
}
652+
630653
fn sort_pic_num_descending(pics: &mut [DpbEntry<B::Handle>]) {
631654
pics.sort_by_key(|h| std::cmp::Reverse(h.0.borrow().pic_num));
632655
}
@@ -1245,7 +1268,7 @@ where
12451268
// Clause 3:
12461269
// The current picture has memory_management_control_operation equal
12471270
// to 5, as specified in clause C.4.4.
1248-
self.ready_queue.extend(self.codec.drain());
1271+
self.drain()?;
12491272
}
12501273

12511274
// Bump the DPB as per C.4.5.3 to cover clauses 1, 4, 5 and 6.
@@ -1418,7 +1441,7 @@ where
14181441
// no_output_of_prior_pics_flag is not equal to 1 and is not
14191442
// inferred to be equal to 1, as specified in clause C.4.4.
14201443
if !pic.ref_pic_marking.no_output_of_prior_pics_flag() {
1421-
self.ready_queue.extend(self.codec.drain());
1444+
self.drain()?;
14221445
} else {
14231446
// C.4.4 When no_output_of_prior_pics_flag is equal to 1 or is
14241447
// inferred to be equal to 1, all frame buffers in the DPB are
@@ -1440,7 +1463,11 @@ where
14401463
&mut self,
14411464
timestamp: u64,
14421465
slice: &Slice<&[u8]>,
1443-
) -> anyhow::Result<CurrentPicState<B>> {
1466+
) -> Result<CurrentPicState<B>, DecodeError> {
1467+
if self.backend.surface_pool().num_free_surfaces() == 0 {
1468+
return Err(DecodeError::NotEnoughOutputBuffers(1));
1469+
}
1470+
14441471
let nalu_hdr = slice.nalu().header();
14451472

14461473
if nalu_hdr.idr_pic_flag() {
@@ -1793,77 +1820,47 @@ where
17931820
Ok(handle)
17941821
}
17951822

1796-
fn peek_sps(parser: &mut Parser, bitstream: &[u8]) -> Option<Sps> {
1797-
let mut cursor = Cursor::new(bitstream);
1798-
1799-
while let Ok(nalu) = Nalu::next(&mut cursor) {
1800-
if matches!(nalu.header().nalu_type(), NaluType::Sps) {
1801-
let sps = parser.parse_sps(&nalu).ok()?;
1802-
return Some(sps.clone());
1823+
fn process_nalu(&mut self, timestamp: u64, nalu: Nalu<&[u8]>) -> Result<(), DecodeError> {
1824+
match nalu.header().nalu_type() {
1825+
NaluType::Sps => {
1826+
self.codec.parser.parse_sps(&nalu)?;
18031827
}
1804-
}
1805-
1806-
None
1807-
}
1808-
1809-
fn decode_access_unit(&mut self, timestamp: u64, bitstream: &[u8]) -> Result<(), DecodeError> {
1810-
if self.backend.surface_pool().num_free_surfaces() == 0 {
1811-
return Err(DecodeError::NotEnoughOutputBuffers(1));
1812-
}
1813-
1814-
let mut cursor = Cursor::new(bitstream);
1815-
1816-
let mut cur_pic_opt: Option<CurrentPicState<B>> = None;
1817-
1818-
while let Ok(nalu) = Nalu::next(&mut cursor) {
1819-
match nalu.header().nalu_type() {
1820-
NaluType::Sps => {
1821-
self.codec.parser.parse_sps(&nalu)?;
1822-
}
1823-
1824-
NaluType::Pps => {
1825-
self.codec.parser.parse_pps(&nalu)?;
1826-
}
1827-
1828-
NaluType::Slice
1829-
| NaluType::SliceDpa
1830-
| NaluType::SliceDpb
1831-
| NaluType::SliceDpc
1832-
| NaluType::SliceIdr
1833-
| NaluType::SliceExt => {
1834-
let slice = self.codec.parser.parse_slice_header(nalu)?;
1835-
let mut cur_pic = match cur_pic_opt {
1836-
// No current picture, start a new one.
1837-
None => self.begin_picture(timestamp, &slice)?,
1838-
// We have a current picture but are starting a new field, or first_mb_in_slice
1839-
// indicates that a new picture is starting: finish the current picture and
1840-
// start a new one.
1841-
Some(cur_pic)
1842-
if (self.codec.dpb.interlaced()
1843-
&& matches!(cur_pic.pic.field, Field::Frame)
1844-
&& !cur_pic.pic.is_second_field()
1845-
&& cur_pic.pic.field != slice.header().field())
1846-
|| (slice.header().first_mb_in_slice == 0) =>
1847-
{
1848-
self.finish_picture(cur_pic)?;
1849-
self.begin_picture(timestamp, &slice)?
1850-
}
1851-
// This slice is part of the current picture.
1852-
Some(cur_pic) => cur_pic,
1853-
};
1854-
1855-
self.handle_slice(&mut cur_pic, &slice)?;
1856-
cur_pic_opt = Some(cur_pic);
1857-
}
1858-
1859-
other => {
1860-
debug!("Unsupported NAL unit type {:?}", other,);
1861-
}
1828+
NaluType::Pps => {
1829+
self.codec.parser.parse_pps(&nalu)?;
18621830
}
1863-
}
1831+
NaluType::Slice
1832+
| NaluType::SliceDpa
1833+
| NaluType::SliceDpb
1834+
| NaluType::SliceDpc
1835+
| NaluType::SliceIdr
1836+
| NaluType::SliceExt => {
1837+
let slice = self.codec.parser.parse_slice_header(nalu)?;
1838+
let mut cur_pic = match self.codec.current_pic.take() {
1839+
// No current picture, start a new one.
1840+
None => self.begin_picture(timestamp, &slice)?,
1841+
// We have a current picture but are starting a new field, or first_mb_in_slice
1842+
// indicates that a new picture is starting: finish the current picture and
1843+
// start a new one.
1844+
Some(cur_pic)
1845+
if (self.codec.dpb.interlaced()
1846+
&& matches!(cur_pic.pic.field, Field::Frame)
1847+
&& !cur_pic.pic.is_second_field()
1848+
&& cur_pic.pic.field != slice.header().field())
1849+
|| (slice.header().first_mb_in_slice == 0) =>
1850+
{
1851+
self.finish_picture(cur_pic)?;
1852+
self.begin_picture(timestamp, &slice)?
1853+
}
1854+
// This slice is part of the current picture.
1855+
Some(cur_pic) => cur_pic,
1856+
};
18641857

1865-
if let Some(cur_pic) = cur_pic_opt.take() {
1866-
self.finish_picture(cur_pic)?;
1858+
self.handle_slice(&mut cur_pic, &slice)?;
1859+
self.codec.current_pic = Some(cur_pic);
1860+
}
1861+
other => {
1862+
debug!("Unsupported NAL unit type {:?}", other,);
1863+
}
18671864
}
18681865

18691866
Ok(())
@@ -1876,13 +1873,15 @@ where
18761873
B: StatelessH264DecoderBackend,
18771874
B::Handle: Clone + 'static,
18781875
{
1879-
fn decode(&mut self, timestamp: u64, mut bitstream: &[u8]) -> Result<usize, DecodeError> {
1880-
let sps = Self::peek_sps(&mut self.codec.parser, bitstream);
1876+
fn decode(&mut self, timestamp: u64, bitstream: &[u8]) -> Result<usize, DecodeError> {
1877+
let mut cursor = Cursor::new(bitstream);
1878+
let nalu = Nalu::next(&mut cursor)?;
18811879

1882-
if let Some(sps) = sps {
1880+
if nalu.header().nalu_type() == NaluType::Sps {
1881+
let sps = self.codec.parser.parse_sps(&nalu)?.clone();
18831882
if Self::negotiation_possible(&sps, &self.codec.dpb, self.coded_resolution) {
18841883
// Make sure all the frames we decoded so far are in the ready queue.
1885-
self.ready_queue.extend(self.codec.drain());
1884+
self.drain()?;
18861885
self.backend.new_sequence(&sps)?;
18871886
self.decoding_state = DecodingState::AwaitingFormat(sps);
18881887
} else if matches!(self.decoding_state, DecodingState::Reset) {
@@ -1895,28 +1894,29 @@ where
18951894
while let Ok(nalu) = Nalu::next(&mut cursor) {
18961895
// In the Reset state we can resume decoding from any key frame.
18971896
if matches!(nalu.header().nalu_type(), NaluType::SliceIdr) {
1898-
bitstream = &bitstream[nalu.sc_offset()..];
18991897
self.decoding_state = DecodingState::Decoding;
19001898
break;
19011899
}
19021900
}
19031901
}
19041902

1905-
let frame_len = bitstream.len();
1903+
let nalu_len = nalu.offset() + nalu.size();
19061904

19071905
match &mut self.decoding_state {
19081906
// Skip input until we get information from the stream.
19091907
DecodingState::AwaitingStreamInfo | DecodingState::Reset => (),
19101908
// Ask the client to confirm the format before we can process this.
19111909
DecodingState::AwaitingFormat(_) => return Err(DecodeError::CheckEvents),
1912-
DecodingState::Decoding => self.decode_access_unit(timestamp, bitstream)?,
1913-
};
1910+
DecodingState::Decoding => {
1911+
self.process_nalu(timestamp, nalu)?;
1912+
}
1913+
}
19141914

1915-
Ok(frame_len)
1915+
Ok(nalu_len)
19161916
}
19171917

19181918
fn flush(&mut self) -> Result<(), DecodeError> {
1919-
self.ready_queue.extend(self.codec.drain());
1919+
self.drain()?;
19201920
self.decoding_state = DecodingState::Reset;
19211921

19221922
Ok(())

0 commit comments

Comments
 (0)