cros_codecs/decoder/stateless/
h265.rs

1// Copyright 2023 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#[cfg(test)]
6mod dummy;
7#[cfg(feature = "vaapi")]
8mod vaapi;
9
10use std::cell::RefCell;
11use std::io::Cursor;
12use std::os::fd::AsFd;
13use std::os::fd::BorrowedFd;
14use std::rc::Rc;
15
16use anyhow::anyhow;
17use anyhow::Context;
18
19use crate::codec::h265::dpb::Dpb;
20use crate::codec::h265::dpb::DpbEntry;
21use crate::codec::h265::parser::Nalu;
22use crate::codec::h265::parser::NaluType;
23use crate::codec::h265::parser::Parser;
24use crate::codec::h265::parser::Pps;
25use crate::codec::h265::parser::ShortTermRefPicSet;
26use crate::codec::h265::parser::Slice;
27use crate::codec::h265::parser::SliceHeader;
28use crate::codec::h265::parser::Sps;
29use crate::codec::h265::picture::PictureData;
30use crate::codec::h265::picture::Reference;
31use crate::decoder::stateless::DecodeError;
32use crate::decoder::stateless::DecodingState;
33use crate::decoder::stateless::NewPictureResult;
34use crate::decoder::stateless::PoolLayer;
35use crate::decoder::stateless::StatelessBackendResult;
36use crate::decoder::stateless::StatelessCodec;
37use crate::decoder::stateless::StatelessDecoder;
38use crate::decoder::stateless::StatelessDecoderBackend;
39use crate::decoder::stateless::StatelessDecoderBackendPicture;
40use crate::decoder::stateless::StatelessVideoDecoder;
41use crate::decoder::stateless::TryFormat;
42use crate::decoder::BlockingMode;
43use crate::decoder::DecodedHandle;
44use crate::decoder::DecoderEvent;
45use crate::decoder::StreamInfo;
46use crate::Resolution;
47
48const MAX_DPB_SIZE: usize = 16;
49
50// Equation 5-8
51pub(crate) fn clip3(x: i32, y: i32, z: i32) -> i32 {
52    if z < x {
53        x
54    } else if z > y {
55        y
56    } else {
57        z
58    }
59}
60
61// See 6.5.3
62const fn up_right_diagonal<const N: usize, const ROWS: usize>() -> [usize; N] {
63    // Generics can't be used in const operations for now, so [0; ROWS * ROWS]
64    // is rejected by the compiler
65    assert!(ROWS * ROWS == N);
66
67    let mut i = 0;
68    let mut x = 0i32;
69    let mut y = 0i32;
70    let mut ret = [0; N];
71
72    loop {
73        while y >= 0 {
74            if x < (ROWS as i32) && y < (ROWS as i32) {
75                ret[i] = (x + ROWS as i32 * y) as usize;
76                i += 1;
77            }
78            y -= 1;
79            x += 1;
80        }
81
82        y = x;
83        x = 0;
84        if i >= N {
85            break;
86        }
87    }
88
89    ret
90}
91
92const UP_RIGHT_DIAGONAL_4X4: [usize; 16] = up_right_diagonal::<16, 4>();
93const UP_RIGHT_DIAGONAL_8X8: [usize; 64] = up_right_diagonal::<64, 8>();
94
95fn get_raster_from_up_right_diagonal_8x8(src: [u8; 64], dst: &mut [u8; 64]) {
96    for i in 0..64 {
97        dst[UP_RIGHT_DIAGONAL_8X8[i]] = src[i];
98    }
99}
100
101fn get_raster_from_up_right_diagonal_4x4(src: [u8; 16], dst: &mut [u8; 16]) {
102    for i in 0..16 {
103        dst[UP_RIGHT_DIAGONAL_4X4[i]] = src[i];
104    }
105}
106
107/// Stateless backend methods specific to H.265.
108pub trait StatelessH265DecoderBackend:
109    StatelessDecoderBackend + StatelessDecoderBackendPicture<H265>
110{
111    /// Called when a new SPS is parsed.
112    fn new_sequence(&mut self, sps: &Sps) -> StatelessBackendResult<()>;
113
114    /// Called when the decoder determines that a frame or field was found.
115    fn new_picture(
116        &mut self,
117        coded_resolution: Resolution,
118        timestamp: u64,
119    ) -> NewPictureResult<Self::Picture>;
120
121    /// Called by the decoder for every frame or field found.
122    #[allow(clippy::too_many_arguments)]
123    fn begin_picture(
124        &mut self,
125        picture: &mut Self::Picture,
126        picture_data: &PictureData,
127        sps: &Sps,
128        pps: &Pps,
129        dpb: &Dpb<Self::Handle>,
130        rps: &RefPicSet<Self::Handle>,
131        slice: &Slice,
132    ) -> StatelessBackendResult<()>;
133
134    /// Called to dispatch a decode operation to the backend.
135    #[allow(clippy::too_many_arguments)]
136    fn decode_slice(
137        &mut self,
138        picture: &mut Self::Picture,
139        slice: &Slice,
140        sps: &Sps,
141        pps: &Pps,
142        ref_pic_list0: &[Option<RefPicListEntry<Self::Handle>>; 16],
143        ref_pic_list1: &[Option<RefPicListEntry<Self::Handle>>; 16],
144    ) -> StatelessBackendResult<()>;
145
146    /// Called when the decoder wants the backend to finish the decoding
147    /// operations for `picture`. At this point, `decode_slice` has been called
148    /// for all slices.
149    fn submit_picture(&mut self, picture: Self::Picture) -> StatelessBackendResult<Self::Handle>;
150}
151
152/// An entry in the Reference Picture Lists. Unlike H.264, H.265 can use the
153/// current picture itself as a reference.
154#[derive(Clone)]
155pub enum RefPicListEntry<T> {
156    CurrentPicture(PictureData),
157    DpbEntry(DpbEntry<T>),
158}
159
160enum BumpingType {
161    BeforeDecoding,
162    AfterDecoding,
163}
164
165enum RenegotiationType<'a> {
166    CurrentSps,
167    NewSps(&'a Sps),
168}
169
170/// Keeps track of the last values seen for negotiation purposes.
171#[derive(Clone, Debug, Default, PartialEq, Eq)]
172struct NegotiationInfo {
173    /// The current coded resolution
174    coded_resolution: Resolution,
175    general_profile_idc: u8,
176    bit_depth_luma_minus8: u8,
177    bit_depth_chroma_minus8: u8,
178    chroma_format_idc: u8,
179}
180
181impl From<&Sps> for NegotiationInfo {
182    fn from(sps: &Sps) -> Self {
183        NegotiationInfo {
184            coded_resolution: Resolution {
185                width: sps.width().into(),
186                height: sps.height().into(),
187            },
188            general_profile_idc: sps.profile_tier_level.general_profile_idc,
189            bit_depth_luma_minus8: sps.bit_depth_luma_minus8,
190            bit_depth_chroma_minus8: sps.bit_depth_chroma_minus8,
191            chroma_format_idc: sps.chroma_format_idc,
192        }
193    }
194}
195
196/// The RefPicSet data, derived once per picture.
197#[derive(Clone, Debug)]
198pub struct RefPicSet<T> {
199    curr_delta_poc_msb_present_flag: [bool; MAX_DPB_SIZE],
200    foll_delta_poc_msb_present_flag: [bool; MAX_DPB_SIZE],
201
202    num_poc_st_curr_before: usize,
203    num_poc_st_curr_after: usize,
204    num_poc_st_foll: usize,
205    num_poc_lt_curr: usize,
206    num_poc_lt_foll: usize,
207
208    poc_st_curr_before: [i32; MAX_DPB_SIZE],
209    poc_st_curr_after: [i32; MAX_DPB_SIZE],
210    poc_st_foll: [i32; MAX_DPB_SIZE],
211    poc_lt_curr: [i32; MAX_DPB_SIZE],
212    poc_lt_foll: [i32; MAX_DPB_SIZE],
213
214    ref_pic_set_lt_curr: [Option<DpbEntry<T>>; MAX_DPB_SIZE],
215    ref_pic_set_st_curr_after: [Option<DpbEntry<T>>; MAX_DPB_SIZE],
216    ref_pic_set_st_curr_before: [Option<DpbEntry<T>>; MAX_DPB_SIZE],
217    ref_pic_set_st_foll: [Option<DpbEntry<T>>; MAX_DPB_SIZE],
218    ref_pic_set_lt_foll: [Option<DpbEntry<T>>; MAX_DPB_SIZE],
219}
220
221impl<T: Clone> Default for RefPicSet<T> {
222    fn default() -> Self {
223        Self {
224            curr_delta_poc_msb_present_flag: Default::default(),
225            foll_delta_poc_msb_present_flag: Default::default(),
226            num_poc_st_curr_before: Default::default(),
227            num_poc_st_curr_after: Default::default(),
228            num_poc_st_foll: Default::default(),
229            num_poc_lt_curr: Default::default(),
230            num_poc_lt_foll: Default::default(),
231            poc_st_curr_before: Default::default(),
232            poc_st_curr_after: Default::default(),
233            poc_st_foll: Default::default(),
234            poc_lt_curr: Default::default(),
235            poc_lt_foll: Default::default(),
236            ref_pic_set_lt_curr: Default::default(),
237            ref_pic_set_st_curr_after: Default::default(),
238            ref_pic_set_st_curr_before: Default::default(),
239            ref_pic_set_st_foll: Default::default(),
240            ref_pic_set_lt_foll: Default::default(),
241        }
242    }
243}
244
245/// State of the picture being currently decoded.
246///
247/// Stored between calls to [`StatelessDecoder::handle_slice`] that belong to the same picture.
248struct CurrentPicState<H: DecodedHandle, P> {
249    /// Data for the current picture as extracted from the stream.
250    pic: PictureData,
251    /// Backend-specific data for that picture.
252    backend_pic: P,
253    /// List of reference pictures, used once per slice.
254    ref_pic_lists: ReferencePicLists<H>,
255}
256
257/// All the reference picture lists used to decode a stream.
258struct ReferencePicLists<T> {
259    /// Reference picture list 0 for P and B slices. Retains the same meaning as
260    /// in the specification. Points into the pictures stored in the DPB.
261    /// Derived once per slice.
262    ref_pic_list0: [Option<RefPicListEntry<T>>; MAX_DPB_SIZE],
263    /// Reference picture list 1 for B slices. Retains the same meaning as in
264    /// the specification. Points into the pictures stored in the DPB. Derived
265    /// once per slice.
266    ref_pic_list1: [Option<RefPicListEntry<T>>; MAX_DPB_SIZE],
267}
268
269impl<T> Default for ReferencePicLists<T> {
270    fn default() -> Self {
271        Self {
272            ref_pic_list0: Default::default(),
273            ref_pic_list1: Default::default(),
274        }
275    }
276}
277
278pub struct H265DecoderState<H: DecodedHandle, P> {
279    /// A parser to extract bitstream metadata
280    parser: Parser,
281
282    /// Keeps track of the last values seen for negotiation purposes.
283    negotiation_info: NegotiationInfo,
284    /// The set of reference pictures.
285    rps: RefPicSet<H>,
286
287    /// The decoded picture buffer
288    dpb: Dpb<H>,
289
290    /// The current active SPS id.
291    cur_sps_id: u8,
292
293    /// Used to identify first picture in decoding order or first picture that
294    /// follows an EOS NALU.
295    first_picture_after_eos: bool,
296
297    /// Whether this is the first picture in the bitstream in decoding order.
298    first_picture_in_bitstream: bool,
299    // Same as PrevTid0Pic in the specification.
300    prev_tid_0_pic: Option<PictureData>,
301
302    /// A H.265 syntax element.
303    max_pic_order_cnt_lsb: i32,
304    /// The value of NoRaslOutputFlag for the last IRAP picture.
305    irap_no_rasl_output_flag: bool,
306
307    /// We keep track of the last independent header so we can copy that into
308    /// dependent slices.
309    last_independent_slice_header: Option<SliceHeader>,
310
311    /// The picture currently being decoded. We need to preserve it between
312    /// calls to `decode` because multiple slices will be processed in different
313    /// calls to `decode`.
314    current_pic: Option<CurrentPicState<H, P>>,
315
316    pending_pps: Vec<Nalu<'static>>,
317}
318
319impl<H, P> Default for H265DecoderState<H, P>
320where
321    H: DecodedHandle + Clone,
322{
323    fn default() -> Self {
324        H265DecoderState {
325            parser: Default::default(),
326            negotiation_info: Default::default(),
327            rps: Default::default(),
328            dpb: Default::default(),
329            cur_sps_id: Default::default(),
330            first_picture_after_eos: true,
331            first_picture_in_bitstream: true,
332            prev_tid_0_pic: Default::default(),
333            max_pic_order_cnt_lsb: Default::default(),
334            irap_no_rasl_output_flag: Default::default(),
335            last_independent_slice_header: Default::default(),
336            current_pic: Default::default(),
337            pending_pps: Default::default(),
338        }
339    }
340}
341
342/// [`StatelessCodec`] structure to use in order to create a H.265 stateless decoder.
343///
344/// # Accepted input
345///
346/// A decoder using this codec processes exactly one NAL unit of input per call to
347/// [`StatelessDecoder::decode`], and returns the number of bytes until the end of this NAL unit.
348/// This makes it possible to call [`Decode`](StatelessDecoder::decode) repeatedly on some unsplit
349/// Annex B stream and shrinking it by the number of bytes processed after each call, until the
350/// stream ends up being empty.
351pub struct H265;
352
353impl StatelessCodec for H265 {
354    type FormatInfo = Sps;
355    type DecoderState<H: DecodedHandle, P> = H265DecoderState<H, P>;
356}
357
358impl<B> StatelessDecoder<H265, B>
359where
360    B: StatelessH265DecoderBackend + TryFormat<H265>,
361    B::Handle: Clone,
362{
363    /// Whether the stream parameters have changed, indicating that a negotiation window has opened.
364    fn negotiation_possible(
365        sps: &Sps,
366        dpb: &Dpb<B::Handle>,
367        old_negotiation_info: &NegotiationInfo,
368    ) -> bool {
369        let negotiation_info = NegotiationInfo::from(sps);
370        let max_dpb_size = std::cmp::min(sps.max_dpb_size(), 16);
371        let prev_max_dpb_size = dpb.max_num_pics();
372
373        *old_negotiation_info != negotiation_info || prev_max_dpb_size != max_dpb_size
374    }
375
376    /// Apply the parameters of `sps` to the decoder.
377    fn apply_sps(&mut self, sps: &Sps) -> anyhow::Result<()> {
378        self.drain()?;
379        self.codec.negotiation_info = NegotiationInfo::from(sps);
380
381        let max_dpb_size = std::cmp::min(sps.max_dpb_size(), 16);
382        self.codec.dpb.set_max_num_pics(max_dpb_size);
383        self.coded_resolution = Resolution {
384            width: u32::from(sps.width()),
385            height: u32::from(sps.height()),
386        };
387        Ok(())
388    }
389
390    // See 8.3.2, Note 2.
391    fn st_ref_pic_set<'a>(hdr: &'a SliceHeader, sps: &'a Sps) -> &'a ShortTermRefPicSet {
392        if hdr.curr_rps_idx == sps.num_short_term_ref_pic_sets {
393            &hdr.short_term_ref_pic_set
394        } else {
395            &sps.short_term_ref_pic_set[usize::from(hdr.curr_rps_idx)]
396        }
397    }
398
399    // See 8.3.2.
400    fn decode_rps(&mut self, slice: &Slice, cur_pic: &PictureData) -> anyhow::Result<()> {
401        let hdr = &slice.header;
402
403        if cur_pic.nalu_type.is_irap() && cur_pic.no_rasl_output_flag {
404            self.codec.dpb.mark_all_as_unused_for_ref();
405        }
406
407        if slice.nalu.header.type_.is_idr() {
408            self.codec.rps.poc_st_curr_before = Default::default();
409            self.codec.rps.poc_st_curr_after = Default::default();
410            self.codec.rps.poc_st_foll = Default::default();
411            self.codec.rps.poc_lt_curr = Default::default();
412            self.codec.rps.poc_lt_foll = Default::default();
413
414            self.codec.rps.num_poc_st_curr_before = 0;
415            self.codec.rps.num_poc_st_curr_after = 0;
416            self.codec.rps.num_poc_st_foll = 0;
417            self.codec.rps.num_poc_lt_curr = 0;
418            self.codec.rps.num_poc_lt_foll = 0;
419        } else {
420            let sps = self
421                .codec
422                .parser
423                .get_sps(self.codec.cur_sps_id)
424                .context("Invalid SPS")?;
425
426            let curr_st_rps = Self::st_ref_pic_set(hdr, sps);
427            let mut j = 0;
428            let mut k = 0;
429            for i in 0..usize::from(curr_st_rps.num_negative_pics) {
430                let poc = cur_pic.pic_order_cnt_val + curr_st_rps.delta_poc_s0[i];
431
432                if curr_st_rps.used_by_curr_pic_s0[i] {
433                    self.codec.rps.poc_st_curr_before[j] = poc;
434                    j += 1;
435                } else {
436                    self.codec.rps.poc_st_foll[k] = poc;
437                    k += 1;
438                }
439            }
440
441            self.codec.rps.num_poc_st_curr_before = j as _;
442
443            let mut j = 0;
444            for i in 0..usize::from(curr_st_rps.num_positive_pics) {
445                let poc = cur_pic.pic_order_cnt_val + curr_st_rps.delta_poc_s1[i];
446
447                if curr_st_rps.used_by_curr_pic_s1[i] {
448                    self.codec.rps.poc_st_curr_after[j] = poc;
449                    j += 1;
450                } else {
451                    self.codec.rps.poc_st_foll[k] = poc;
452                    k += 1;
453                }
454            }
455
456            self.codec.rps.num_poc_st_curr_after = j as _;
457            self.codec.rps.num_poc_st_foll = k as _;
458
459            let mut j = 0;
460            let mut k = 0;
461            for i in 0..usize::from(hdr.num_long_term_sps + hdr.num_long_term_pics) {
462                let mut poc_lt = hdr.poc_lsb_lt[i] as i32;
463                if hdr.delta_poc_msb_present_flag[i] {
464                    poc_lt += cur_pic.pic_order_cnt_val;
465                    let delta_poc =
466                        hdr.delta_poc_msb_cycle_lt[i] as i32 * self.codec.max_pic_order_cnt_lsb;
467
468                    poc_lt -= delta_poc;
469                    poc_lt -= cur_pic.pic_order_cnt_val & (self.codec.max_pic_order_cnt_lsb - 1);
470                }
471
472                if hdr.used_by_curr_pic_lt[i] {
473                    self.codec.rps.poc_lt_curr[j] = poc_lt;
474                    self.codec.rps.curr_delta_poc_msb_present_flag[j] =
475                        hdr.delta_poc_msb_present_flag[i];
476                    j += 1;
477                } else {
478                    self.codec.rps.poc_lt_foll[k] = poc_lt;
479                    self.codec.rps.foll_delta_poc_msb_present_flag[k] =
480                        hdr.delta_poc_msb_present_flag[i];
481                    k += 1;
482                }
483            }
484
485            self.codec.rps.num_poc_lt_curr = j as _;
486            self.codec.rps.num_poc_lt_foll = k as _;
487        }
488
489        self.derive_and_mark_rps()?;
490        Ok(())
491    }
492
493    // See the derivation process in the second half of 8.3.2.
494    fn derive_and_mark_rps(&mut self) -> anyhow::Result<()> {
495        let max_pic_order_cnt_lsb = self.codec.max_pic_order_cnt_lsb;
496
497        // Equation 8-6
498        for i in 0..self.codec.rps.num_poc_lt_curr {
499            if !self.codec.rps.curr_delta_poc_msb_present_flag[i] {
500                let poc = self.codec.rps.poc_lt_curr[i];
501                let mask = max_pic_order_cnt_lsb - 1;
502                let reference = self.codec.dpb.find_ref_by_poc_masked(poc, mask);
503
504                if reference.is_none() {
505                    log::warn!("No reference found for poc {} and mask {}", poc, mask);
506                }
507
508                self.codec.rps.ref_pic_set_lt_curr[i] = reference;
509            } else {
510                let poc = self.codec.rps.poc_lt_curr[i];
511                let reference = self.codec.dpb.find_ref_by_poc(poc);
512
513                if reference.is_none() {
514                    log::warn!("No reference found for poc {}", poc);
515                }
516
517                self.codec.rps.ref_pic_set_lt_curr[i] = reference;
518            }
519        }
520
521        for i in 0..self.codec.rps.num_poc_lt_foll {
522            if !self.codec.rps.foll_delta_poc_msb_present_flag[i] {
523                let poc = self.codec.rps.poc_lt_foll[i];
524                let mask = max_pic_order_cnt_lsb - 1;
525                let reference = self.codec.dpb.find_ref_by_poc_masked(poc, mask);
526
527                if reference.is_none() {
528                    log::warn!("No reference found for poc {} and mask {}", poc, mask);
529                }
530
531                self.codec.rps.ref_pic_set_lt_foll[i] = reference;
532            } else {
533                let poc = self.codec.rps.poc_lt_foll[i];
534                let reference = self.codec.dpb.find_ref_by_poc(poc);
535
536                if reference.is_none() {
537                    log::warn!("No reference found for poc {}", poc);
538                }
539
540                self.codec.rps.ref_pic_set_lt_foll[i] = reference;
541            }
542        }
543
544        for pic in self.codec.rps.ref_pic_set_lt_curr.iter().flatten() {
545            pic.0.borrow_mut().set_reference(Reference::LongTerm);
546        }
547
548        for pic in self.codec.rps.ref_pic_set_lt_foll.iter().flatten() {
549            pic.0.borrow_mut().set_reference(Reference::LongTerm);
550        }
551
552        // Equation 8-7
553        for i in 0..self.codec.rps.num_poc_st_curr_before {
554            let poc = self.codec.rps.poc_st_curr_before[i];
555            let reference = self.codec.dpb.find_short_term_ref_by_poc(poc);
556
557            if reference.is_none() {
558                log::warn!("No reference found for poc {}", poc);
559            }
560
561            self.codec.rps.ref_pic_set_st_curr_before[i] = reference;
562        }
563
564        for i in 0..self.codec.rps.num_poc_st_curr_after {
565            let poc = self.codec.rps.poc_st_curr_after[i];
566            let reference = self.codec.dpb.find_short_term_ref_by_poc(poc);
567
568            if reference.is_none() {
569                log::warn!("No reference found for poc {}", poc);
570            }
571
572            self.codec.rps.ref_pic_set_st_curr_after[i] = reference;
573        }
574
575        for i in 0..self.codec.rps.num_poc_st_foll {
576            let poc = self.codec.rps.poc_st_foll[i];
577            let reference = self.codec.dpb.find_short_term_ref_by_poc(poc);
578
579            if reference.is_none() {
580                log::warn!("No reference found for poc {}", poc);
581            }
582
583            self.codec.rps.ref_pic_set_st_foll[i] = reference;
584        }
585
586        // 4. All reference pictures in the DPB that are not included in
587        // RefPicSetLtCurr, RefPicSetLtFoll, RefPicSetStCurrBefore,
588        // RefPicSetStCurrAfter, or RefPicSetStFoll and have nuh_layer_id equal
589        // to currPicLayerId are marked as "unused for reference"
590        for dpb_pic in self.codec.dpb.entries() {
591            let find_predicate = |p: &Option<DpbEntry<B::Handle>>| match p {
592                Some(p) => p.0.borrow().pic_order_cnt_val == dpb_pic.0.borrow().pic_order_cnt_val,
593                None => false,
594            };
595
596            if !self.codec.rps.ref_pic_set_lt_curr[0..self.codec.rps.num_poc_lt_curr]
597                .iter()
598                .any(find_predicate)
599                && !self.codec.rps.ref_pic_set_lt_foll[0..self.codec.rps.num_poc_lt_foll]
600                    .iter()
601                    .any(find_predicate)
602                && !self.codec.rps.ref_pic_set_st_curr_after
603                    [0..self.codec.rps.num_poc_st_curr_after]
604                    .iter()
605                    .any(find_predicate)
606                && !self.codec.rps.ref_pic_set_st_curr_before
607                    [0..self.codec.rps.num_poc_st_curr_before]
608                    .iter()
609                    .any(find_predicate)
610                && !self.codec.rps.ref_pic_set_st_foll[0..self.codec.rps.num_poc_st_foll]
611                    .iter()
612                    .any(find_predicate)
613            {
614                dpb_pic.0.borrow_mut().set_reference(Reference::None);
615            }
616        }
617
618        let total_rps_len = self.codec.rps.ref_pic_set_lt_curr[0..self.codec.rps.num_poc_lt_curr]
619            .len()
620            + self.codec.rps.ref_pic_set_lt_foll[0..self.codec.rps.num_poc_lt_foll].len()
621            + self.codec.rps.ref_pic_set_st_curr_after[0..self.codec.rps.num_poc_st_curr_after]
622                .len()
623            + self.codec.rps.ref_pic_set_st_curr_before[0..self.codec.rps.num_poc_st_curr_before]
624                .len()
625            + self.codec.rps.ref_pic_set_st_foll[0..self.codec.rps.num_poc_st_foll].len();
626
627        let dpb_len = self.codec.dpb.entries().len();
628        if dpb_len != total_rps_len {
629            log::warn!(
630                "The total RPS length {} is not the same as the DPB length {}",
631                total_rps_len,
632                dpb_len
633            );
634            log::warn!("A reference pic may be in more than one RPS list. This is against the specification. See 8.3.2. NOTE 5")
635        }
636
637        // According to Chromium, unavailable reference pictures are handled by
638        // the accelerators internally.
639        Ok(())
640    }
641
642    // See 8.3.4.
643    // Builds the reference picture list for `hdr` for P and B slices.
644    fn build_ref_pic_lists(
645        &self,
646        hdr: &SliceHeader,
647        cur_pic: &PictureData,
648    ) -> anyhow::Result<ReferencePicLists<B::Handle>> {
649        let mut ref_pic_lists = ReferencePicLists::default();
650
651        // I slices do not use inter prediction.
652        if !hdr.type_.is_p() && !hdr.type_.is_b() {
653            return Ok(ref_pic_lists);
654        }
655
656        let pps = self
657            .codec
658            .parser
659            .get_pps(hdr.pic_parameter_set_id)
660            .context("Invalid PPS in build_ref_pic_lists")?;
661
662        if self.codec.rps.num_poc_st_curr_before == 0
663            && self.codec.rps.num_poc_st_curr_after == 0
664            && self.codec.rps.num_poc_lt_curr == 0
665            && pps.scc_extension_flag
666            && !pps.scc_extension.curr_pic_ref_enabled_flag
667        {
668            // Let's try and keep going, if it is a broken stream then maybe it
669            // will sort itself out as we go. In any case, we must not loop
670            // infinitely here.
671            log::error!("Bug or broken stream: out of pictures and can't build ref pic lists.");
672            return Ok(ref_pic_lists);
673        }
674
675        let rplm = &hdr.ref_pic_list_modification;
676
677        let num_rps_curr_temp_list0 = std::cmp::max(
678            u32::from(hdr.num_ref_idx_l0_active_minus1) + 1,
679            hdr.num_pic_total_curr,
680        );
681
682        // This could be simplified using a Vec, but lets not change the
683        // algorithm from the spec too much.
684        let mut ref_pic_list_temp0: [Option<RefPicListEntry<B::Handle>>; MAX_DPB_SIZE] =
685            Default::default();
686
687        // Equation 8-8
688        let mut r_idx = 0;
689        assert!(num_rps_curr_temp_list0 as usize <= MAX_DPB_SIZE);
690        while r_idx < num_rps_curr_temp_list0 {
691            let mut i = 0;
692            while i < self.codec.rps.num_poc_st_curr_before && r_idx < num_rps_curr_temp_list0 {
693                ref_pic_list_temp0[r_idx as usize] = self.codec.rps.ref_pic_set_st_curr_before[i]
694                    .clone()
695                    .map(RefPicListEntry::DpbEntry);
696
697                i += 1;
698                r_idx += 1;
699            }
700
701            let mut i = 0;
702            while i < self.codec.rps.num_poc_st_curr_after && r_idx < num_rps_curr_temp_list0 {
703                ref_pic_list_temp0[r_idx as usize] = self.codec.rps.ref_pic_set_st_curr_after[i]
704                    .clone()
705                    .map(RefPicListEntry::DpbEntry);
706
707                i += 1;
708                r_idx += 1;
709            }
710
711            let mut i = 0;
712            while i < self.codec.rps.num_poc_lt_curr && r_idx < num_rps_curr_temp_list0 {
713                ref_pic_list_temp0[r_idx as usize] = self.codec.rps.ref_pic_set_lt_curr[i]
714                    .clone()
715                    .map(RefPicListEntry::DpbEntry);
716
717                i += 1;
718                r_idx += 1;
719            }
720
721            if pps.scc_extension.curr_pic_ref_enabled_flag {
722                ref_pic_list_temp0[r_idx as usize] =
723                    Some(RefPicListEntry::CurrentPicture(cur_pic.clone()));
724
725                r_idx += 1;
726            }
727        }
728
729        // Equation 8-9
730        for r_idx in 0..=usize::from(hdr.num_ref_idx_l0_active_minus1) {
731            let entry = if rplm.ref_pic_list_modification_flag_l0 {
732                let idx = rplm.list_entry_l0[r_idx];
733                ref_pic_list_temp0[idx as usize].clone()
734            } else {
735                ref_pic_list_temp0[r_idx].clone()
736            };
737
738            ref_pic_lists.ref_pic_list0[r_idx] = entry;
739        }
740
741        if pps.scc_extension.curr_pic_ref_enabled_flag
742            && !rplm.ref_pic_list_modification_flag_l0
743            && num_rps_curr_temp_list0 > (u32::from(hdr.num_ref_idx_l0_active_minus1) + 1)
744        {
745            ref_pic_lists.ref_pic_list0[r_idx as usize] =
746                Some(RefPicListEntry::CurrentPicture(cur_pic.clone()));
747        }
748
749        if hdr.type_.is_b() {
750            let mut ref_pic_list_temp1: [Option<RefPicListEntry<B::Handle>>; MAX_DPB_SIZE] =
751                Default::default();
752
753            let num_rps_curr_temp_list1 = std::cmp::max(
754                u32::from(hdr.num_ref_idx_l1_active_minus1) + 1,
755                hdr.num_pic_total_curr,
756            );
757
758            // Equation 8-10
759            let mut r_idx = 0;
760            assert!(num_rps_curr_temp_list1 as usize <= MAX_DPB_SIZE);
761            while r_idx < num_rps_curr_temp_list1 {
762                let mut i = 0;
763                while i < self.codec.rps.num_poc_st_curr_after && r_idx < num_rps_curr_temp_list1 {
764                    ref_pic_list_temp1[r_idx as usize] = self.codec.rps.ref_pic_set_st_curr_after
765                        [i]
766                        .clone()
767                        .map(RefPicListEntry::DpbEntry);
768                    i += 1;
769                    r_idx += 1;
770                }
771
772                let mut i = 0;
773                while i < self.codec.rps.num_poc_st_curr_before && r_idx < num_rps_curr_temp_list1 {
774                    ref_pic_list_temp1[r_idx as usize] = self.codec.rps.ref_pic_set_st_curr_before
775                        [i]
776                        .clone()
777                        .map(RefPicListEntry::DpbEntry);
778                    i += 1;
779                    r_idx += 1;
780                }
781
782                let mut i = 0;
783                while i < self.codec.rps.num_poc_lt_curr && r_idx < num_rps_curr_temp_list1 {
784                    ref_pic_list_temp1[r_idx as usize] = self.codec.rps.ref_pic_set_lt_curr[i]
785                        .clone()
786                        .map(RefPicListEntry::DpbEntry);
787                    i += 1;
788                    r_idx += 1;
789                }
790
791                if pps.scc_extension.curr_pic_ref_enabled_flag {
792                    ref_pic_list_temp1[r_idx as usize] =
793                        Some(RefPicListEntry::CurrentPicture(cur_pic.clone()));
794
795                    r_idx += 1;
796                }
797            }
798
799            // Equation 8-11
800            for r_idx in 0..=usize::from(hdr.num_ref_idx_l1_active_minus1) {
801                let entry = if rplm.ref_pic_list_modification_flag_l1 {
802                    let idx = rplm.list_entry_l1[r_idx];
803                    ref_pic_list_temp1[idx as usize].clone()
804                } else {
805                    ref_pic_list_temp1[r_idx].clone()
806                };
807
808                ref_pic_lists.ref_pic_list1[r_idx] = entry;
809            }
810        }
811
812        Ok(ref_pic_lists)
813    }
814
815    /// Drain the decoder, processing all pending frames.
816    fn drain(&mut self) -> anyhow::Result<()> {
817        log::debug!("Draining the decoder");
818
819        // Finish the current picture if there is one pending.
820        if let Some(cur_pic) = self.codec.current_pic.take() {
821            self.finish_picture(cur_pic)?;
822        }
823
824        let pics = self.codec.dpb.drain();
825
826        log::debug!(
827            "Adding POCs {:?} to the ready queue while draining",
828            pics.iter()
829                .map(|p| p.0.borrow().pic_order_cnt_val)
830                .collect::<Vec<_>>()
831        );
832
833        log::trace!(
834            "{:#?}",
835            pics.iter().map(|p| p.0.borrow()).collect::<Vec<_>>()
836        );
837
838        self.ready_queue.extend(pics.into_iter().map(|h| h.1));
839        self.codec.dpb.clear();
840
841        Ok(())
842    }
843
844    fn clear_ref_lists(&mut self) {
845        if let Some(pic) = self.codec.current_pic.as_mut() {
846            pic.ref_pic_lists = Default::default();
847        }
848
849        self.codec.rps.ref_pic_set_lt_curr = Default::default();
850        self.codec.rps.ref_pic_set_st_curr_after = Default::default();
851        self.codec.rps.ref_pic_set_st_curr_before = Default::default();
852
853        self.codec.rps.num_poc_lt_curr = Default::default();
854        self.codec.rps.num_poc_lt_foll = Default::default();
855        self.codec.rps.num_poc_st_curr_after = Default::default();
856        self.codec.rps.num_poc_st_curr_before = Default::default();
857        self.codec.rps.num_poc_st_foll = Default::default();
858    }
859
860    /// Bumps the DPB if needed.
861    fn bump_as_needed(
862        &mut self,
863        bumping_type: BumpingType,
864    ) -> anyhow::Result<Vec<DpbEntry<B::Handle>>> {
865        let mut pics = vec![];
866
867        let needs_bumping = match bumping_type {
868            BumpingType::BeforeDecoding => Dpb::<B::Handle>::needs_bumping,
869            BumpingType::AfterDecoding => Dpb::<B::Handle>::needs_additional_bumping,
870        };
871
872        let sps = self
873            .codec
874            .parser
875            .get_sps(self.codec.cur_sps_id)
876            .context("Invalid SPS id")?;
877
878        while needs_bumping(&mut self.codec.dpb, sps) {
879            match self.codec.dpb.bump(false) {
880                Some(pic) => pics.push(pic),
881                None => return Ok(pics),
882            }
883        }
884
885        Ok(pics)
886    }
887
888    // See C.5.2.2
889    fn update_dpb_before_decoding(&mut self, cur_pic: &PictureData) -> anyhow::Result<()> {
890        if cur_pic.is_irap && cur_pic.no_rasl_output_flag && !self.codec.first_picture_after_eos {
891            if cur_pic.no_output_of_prior_pics_flag {
892                self.codec.dpb.clear();
893            } else {
894                self.drain()?;
895            }
896        } else {
897            self.codec.dpb.remove_unused();
898            let bumped = self.bump_as_needed(BumpingType::BeforeDecoding)?;
899
900            log::debug!(
901                "Adding POCs {:?} to the ready queue before decoding",
902                bumped
903                    .iter()
904                    .map(|p| p.0.borrow().pic_order_cnt_val)
905                    .collect::<Vec<_>>()
906            );
907
908            log::trace!(
909                "{:#?}",
910                bumped.iter().map(|p| p.0.borrow()).collect::<Vec<_>>()
911            );
912
913            let bumped = bumped.into_iter().map(|p| p.1).collect::<Vec<_>>();
914            self.ready_queue.extend(bumped);
915        }
916
917        Ok(())
918    }
919
920    /// Called once per picture to start it.
921    #[allow(clippy::type_complexity)]
922    fn begin_picture(
923        &mut self,
924        timestamp: u64,
925        slice: &Slice,
926    ) -> Result<Option<CurrentPicState<B::Handle, B::Picture>>, DecodeError> {
927        self.update_current_set_ids(slice.header.pic_parameter_set_id)?;
928        self.renegotiate_if_needed(RenegotiationType::CurrentSps)?;
929        // We renegotiated and must return the NALU and wait.
930        if matches!(self.decoding_state, DecodingState::AwaitingFormat(_)) {
931            return Err(DecodeError::CheckEvents);
932        }
933
934        let mut backend_pic = self.backend.new_picture(self.coded_resolution, timestamp)?;
935
936        let pic = PictureData::new_from_slice(
937            slice,
938            self.codec
939                .parser
940                .get_pps(slice.header.pic_parameter_set_id)
941                .context("Invalid PPS")?,
942            self.codec.first_picture_in_bitstream,
943            self.codec.first_picture_after_eos,
944            self.codec.prev_tid_0_pic.as_ref(),
945            self.codec.max_pic_order_cnt_lsb,
946        );
947
948        self.codec.first_picture_after_eos = false;
949        self.codec.first_picture_in_bitstream = false;
950
951        if pic.is_irap {
952            self.codec.irap_no_rasl_output_flag = pic.no_rasl_output_flag;
953        } else if pic.nalu_type.is_rasl() && self.codec.irap_no_rasl_output_flag {
954            // NOTE – All RASL pictures are leading pictures of an associated
955            // BLA or CRA picture. When the associated IRAP picture has
956            // NoRaslOutputFlag equal to 1, the RASL picture is not output and
957            // may not be correctly decodable, as the RASL picture may contain
958            // references to pictures that are not present in the bitstream.
959            // RASL pictures are not used as reference pictures for the decoding
960            // process of non-RASL pictures.
961            log::debug!(
962                "Dropping POC {}, as it may not be decodable according to the specification",
963                pic.pic_order_cnt_val
964            );
965
966            return Ok(None);
967        }
968
969        log::debug!("Decode picture POC {}", pic.pic_order_cnt_val);
970
971        self.decode_rps(slice, &pic)?;
972        self.update_dpb_before_decoding(&pic)?;
973
974        let pps = self
975            .codec
976            .parser
977            .get_pps(slice.header.pic_parameter_set_id)
978            .context("invalid PPS ID")?;
979        let sps = self
980            .codec
981            .parser
982            .get_sps(pps.seq_parameter_set_id)
983            .context("invalid SPS ID")?;
984        self.backend.begin_picture(
985            &mut backend_pic,
986            &pic,
987            sps,
988            pps,
989            &self.codec.dpb,
990            &self.codec.rps,
991            slice,
992        )?;
993
994        Ok(Some(CurrentPicState {
995            pic,
996            backend_pic,
997            ref_pic_lists: Default::default(),
998        }))
999    }
1000
1001    fn update_current_set_ids(&mut self, pps_id: u8) -> anyhow::Result<()> {
1002        let pps = self.codec.parser.get_pps(pps_id).context("Invalid PPS")?;
1003
1004        self.codec.cur_sps_id = pps.seq_parameter_set_id;
1005        Ok(())
1006    }
1007
1008    /// Handle a slice. Called once per slice NALU.
1009    fn handle_slice(
1010        &mut self,
1011        pic: &mut CurrentPicState<B::Handle, B::Picture>,
1012        slice: &Slice,
1013    ) -> anyhow::Result<()> {
1014        // A dependent slice may refer to a previous SPS which
1015        // is not the one currently in use.
1016        self.update_current_set_ids(slice.header.pic_parameter_set_id)?;
1017
1018        let sps = self
1019            .codec
1020            .parser
1021            .get_sps(self.codec.cur_sps_id)
1022            .context("Invalid SPS")?;
1023
1024        // Make sure that no negotiation is possible mid-picture. How could it?
1025        // We'd lose the context with the previous slices on it.
1026        assert!(!Self::negotiation_possible(
1027            sps,
1028            &self.codec.dpb,
1029            &self.codec.negotiation_info,
1030        ));
1031
1032        pic.ref_pic_lists = self.build_ref_pic_lists(&slice.header, &pic.pic)?;
1033
1034        let pps = self
1035            .codec
1036            .parser
1037            .get_pps(slice.header.pic_parameter_set_id)
1038            .context("invalid PPS ID")?;
1039        let sps = self
1040            .codec
1041            .parser
1042            .get_sps(pps.seq_parameter_set_id)
1043            .context("invalid SPS ID")?;
1044        self.backend.decode_slice(
1045            &mut pic.backend_pic,
1046            slice,
1047            sps,
1048            pps,
1049            &pic.ref_pic_lists.ref_pic_list0,
1050            &pic.ref_pic_lists.ref_pic_list1,
1051        )?;
1052
1053        Ok(())
1054    }
1055
1056    fn finish_picture(
1057        &mut self,
1058        pic: CurrentPicState<B::Handle, B::Picture>,
1059    ) -> anyhow::Result<()> {
1060        log::debug!("Finishing picture POC {:?}", pic.pic.pic_order_cnt_val);
1061
1062        // Submit the picture to the backend.
1063        let handle = self.submit_picture(pic.backend_pic)?;
1064        let pic = pic.pic;
1065
1066        // 8.3.1
1067        if pic.valid_for_prev_tid0_pic {
1068            self.codec.prev_tid_0_pic = Some(pic.clone());
1069        }
1070
1071        self.clear_ref_lists();
1072
1073        // First store the current picture in the DPB, only then we should
1074        // decide whether to bump.
1075        self.codec
1076            .dpb
1077            .store_picture(Rc::new(RefCell::new(pic)), handle)?;
1078        let bumped = self.bump_as_needed(BumpingType::AfterDecoding)?;
1079
1080        log::debug!(
1081            "Adding POCs {:?} to the ready queue after decoding",
1082            bumped
1083                .iter()
1084                .map(|p| p.0.borrow().pic_order_cnt_val)
1085                .collect::<Vec<_>>()
1086        );
1087
1088        log::trace!(
1089            "{:#?}",
1090            bumped.iter().map(|p| p.0.borrow()).collect::<Vec<_>>()
1091        );
1092
1093        let bumped = bumped.into_iter().map(|p| p.1).collect::<Vec<_>>();
1094        self.ready_queue.extend(bumped);
1095
1096        Ok(())
1097    }
1098
1099    fn renegotiate_if_needed(
1100        &mut self,
1101        renegotiation_type: RenegotiationType,
1102    ) -> anyhow::Result<()> {
1103        let sps = match renegotiation_type {
1104            RenegotiationType::CurrentSps => self
1105                .codec
1106                .parser
1107                .get_sps(self.codec.cur_sps_id)
1108                .context("Invalid SPS")?,
1109            RenegotiationType::NewSps(sps) => sps,
1110        };
1111
1112        if Self::negotiation_possible(sps, &self.codec.dpb, &self.codec.negotiation_info) {
1113            // Make sure all the frames we decoded so far are in the ready queue.
1114            self.drain()?;
1115            let sps = match renegotiation_type {
1116                RenegotiationType::CurrentSps => self
1117                    .codec
1118                    .parser
1119                    .get_sps(self.codec.cur_sps_id)
1120                    .context("Invalid SPS")?,
1121                RenegotiationType::NewSps(sps) => sps,
1122            };
1123            self.backend.new_sequence(sps)?;
1124            self.await_format_change(sps.clone());
1125        }
1126
1127        Ok(())
1128    }
1129
1130    fn process_nalu(&mut self, timestamp: u64, nalu: Nalu) -> Result<(), DecodeError> {
1131        log::debug!(
1132            "Processing NALU {:?}, length is {}",
1133            nalu.header.type_,
1134            nalu.size
1135        );
1136
1137        match nalu.header.type_ {
1138            NaluType::VpsNut => {
1139                self.codec.parser.parse_vps(&nalu)?;
1140            }
1141            NaluType::SpsNut => {
1142                let sps = self.codec.parser.parse_sps(&nalu)?;
1143                self.codec.max_pic_order_cnt_lsb = 1 << (sps.log2_max_pic_order_cnt_lsb_minus4 + 4);
1144
1145                let pending_pps = std::mem::take(&mut self.codec.pending_pps);
1146
1147                // Try parsing the PPS again.
1148                for pps in pending_pps.into_iter() {
1149                    if self.codec.parser.parse_pps(&pps).is_err() {
1150                        // Failed to parse PPS add it again to pending
1151                        self.codec.pending_pps.push(pps);
1152                    }
1153                }
1154            }
1155
1156            NaluType::PpsNut => {
1157                if self.codec.parser.parse_pps(&nalu).is_err() {
1158                    self.codec.pending_pps.push(nalu.into_owned())
1159                }
1160            }
1161
1162            NaluType::BlaWLp
1163            | NaluType::BlaWRadl
1164            | NaluType::BlaNLp
1165            | NaluType::IdrWRadl
1166            | NaluType::IdrNLp
1167            | NaluType::TrailN
1168            | NaluType::TrailR
1169            | NaluType::TsaN
1170            | NaluType::TsaR
1171            | NaluType::StsaN
1172            | NaluType::StsaR
1173            | NaluType::RadlN
1174            | NaluType::RadlR
1175            | NaluType::RaslN
1176            | NaluType::RaslR
1177            | NaluType::CraNut => {
1178                let mut slice = self.codec.parser.parse_slice_header(nalu)?;
1179
1180                let first_slice_segment_in_pic_flag = slice.header.first_slice_segment_in_pic_flag;
1181
1182                if slice.header.dependent_slice_segment_flag {
1183                    let previous_independent_header = self.codec.last_independent_slice_header.as_ref().ok_or(anyhow!("Cannot process an dependent slice without first processing and independent one"))?.clone();
1184                    slice.replace_header(previous_independent_header)?;
1185                } else {
1186                    self.codec.last_independent_slice_header = Some(slice.header.clone());
1187                }
1188
1189                let cur_pic = match self.codec.current_pic.take() {
1190                    // No current picture, start a new one.
1191                    None => self.begin_picture(timestamp, &slice)?,
1192                    Some(cur_pic) if first_slice_segment_in_pic_flag => {
1193                        self.finish_picture(cur_pic)?;
1194                        self.begin_picture(timestamp, &slice)?
1195                    }
1196                    Some(cur_pic) => Some(cur_pic),
1197                };
1198
1199                // Picture may have been dropped during begin_picture()
1200                if let Some(mut cur_pic) = cur_pic {
1201                    self.handle_slice(&mut cur_pic, &slice)?;
1202                    self.codec.current_pic = Some(cur_pic);
1203                }
1204            }
1205
1206            NaluType::EosNut => {
1207                self.codec.first_picture_after_eos = true;
1208            }
1209
1210            NaluType::EobNut => {
1211                self.codec.first_picture_in_bitstream = true;
1212            }
1213
1214            other => {
1215                log::debug!("Unsupported NAL unit type {:?}", other,);
1216            }
1217        }
1218
1219        Ok(())
1220    }
1221
1222    /// Submits the picture to the accelerator.
1223    fn submit_picture(&mut self, backend_pic: B::Picture) -> Result<B::Handle, DecodeError> {
1224        let handle = self.backend.submit_picture(backend_pic)?;
1225
1226        if self.blocking_mode == BlockingMode::Blocking {
1227            handle.sync()?;
1228        }
1229
1230        Ok(handle)
1231    }
1232}
1233
1234impl<B> StatelessVideoDecoder for StatelessDecoder<H265, B>
1235where
1236    B: StatelessH265DecoderBackend + TryFormat<H265>,
1237    B::Handle: Clone + 'static,
1238{
1239    type Handle = B::Handle;
1240    type FramePool = B::FramePool;
1241
1242    fn decode(&mut self, timestamp: u64, bitstream: &[u8]) -> Result<usize, DecodeError> {
1243        let mut cursor = Cursor::new(bitstream);
1244        let nalu = Nalu::next(&mut cursor)?;
1245
1246        if nalu.header.type_ == NaluType::SpsNut {
1247            let sps = self.codec.parser.parse_sps(&nalu)?.clone();
1248            if matches!(self.decoding_state, DecodingState::AwaitingStreamInfo) {
1249                // If more SPS come along we will renegotiate in begin_picture().
1250                self.renegotiate_if_needed(RenegotiationType::NewSps(&sps))?;
1251            } else if matches!(self.decoding_state, DecodingState::Reset) {
1252                // We can resume decoding since the decoding parameters have not changed.
1253                self.decoding_state = DecodingState::Decoding;
1254            }
1255        } else if matches!(self.decoding_state, DecodingState::Reset) {
1256            let mut cursor = Cursor::new(bitstream);
1257
1258            while let Ok(nalu) = Nalu::next(&mut cursor) {
1259                // In the Reset state we can resume decoding from any key frame.
1260                if nalu.header.type_.is_idr() {
1261                    self.decoding_state = DecodingState::Decoding;
1262                    break;
1263                }
1264            }
1265        }
1266
1267        let nalu_len = nalu.offset + nalu.size;
1268
1269        match &mut self.decoding_state {
1270            // Process parameter sets, but skip input until we get information
1271            // from the stream.
1272            DecodingState::AwaitingStreamInfo | DecodingState::Reset => {
1273                if matches!(
1274                    nalu.header.type_,
1275                    NaluType::VpsNut | NaluType::SpsNut | NaluType::PpsNut
1276                ) {
1277                    self.process_nalu(timestamp, nalu)?;
1278                }
1279            }
1280            // Ask the client to confirm the format before we can process this.
1281            DecodingState::AwaitingFormat(_) => return Err(DecodeError::CheckEvents),
1282            DecodingState::Decoding => {
1283                self.process_nalu(timestamp, nalu)?;
1284            }
1285        }
1286
1287        Ok(nalu_len)
1288    }
1289
1290    fn flush(&mut self) -> Result<(), DecodeError> {
1291        self.drain()?;
1292        self.decoding_state = DecodingState::Reset;
1293
1294        Ok(())
1295    }
1296
1297    fn next_event(&mut self) -> Option<DecoderEvent<B::Handle>> {
1298        self.query_next_event(|decoder, sps| {
1299            // Apply the SPS settings to the decoder so we don't enter the AwaitingFormat state
1300            // on the next decode() call.
1301            // TODO: unwrap this for now, but ideally change this closure to return Result
1302            decoder.apply_sps(sps).unwrap();
1303        })
1304    }
1305
1306    fn frame_pool(&mut self, layer: PoolLayer) -> Vec<&mut B::FramePool> {
1307        self.backend.frame_pool(layer)
1308    }
1309
1310    fn stream_info(&self) -> Option<&StreamInfo> {
1311        self.backend.stream_info()
1312    }
1313
1314    fn poll_fd(&self) -> BorrowedFd {
1315        self.epoll_fd.0.as_fd()
1316    }
1317}
1318
1319#[cfg(test)]
1320pub mod tests {
1321
1322    use crate::codec::h265::parser::Nalu;
1323    use crate::decoder::stateless::h265::H265;
1324    use crate::decoder::stateless::tests::test_decode_stream;
1325    use crate::decoder::stateless::tests::TestStream;
1326    use crate::decoder::stateless::StatelessDecoder;
1327    use crate::decoder::BlockingMode;
1328    use crate::utils::simple_playback_loop;
1329    use crate::utils::simple_playback_loop_owned_frames;
1330    use crate::utils::NalIterator;
1331    use crate::DecodedFormat;
1332
1333    /// Run `test` using the dummy decoder, in both blocking and non-blocking modes.
1334    fn test_decoder_dummy(test: &TestStream, blocking_mode: BlockingMode) {
1335        let decoder = StatelessDecoder::<H265, _>::new_dummy(blocking_mode).unwrap();
1336
1337        test_decode_stream(
1338            |d, s, f| {
1339                simple_playback_loop(
1340                    d,
1341                    NalIterator::<Nalu>::new(s),
1342                    f,
1343                    &mut simple_playback_loop_owned_frames,
1344                    DecodedFormat::NV12,
1345                    blocking_mode,
1346                )
1347            },
1348            decoder,
1349            test,
1350            false,
1351            false,
1352        );
1353    }
1354
1355    /// A 64x64 progressive byte-stream encoded I-frame to make it easier to
1356    /// spot errors on the libva trace.
1357    /// Encoded with the following GStreamer pipeline:
1358    ///
1359    /// gst-launch-1.0 videotestsrc num-buffers=1 ! video/x-raw,format=I420,width=64,height=64 ! x265enc ! video/x-h265,profile=main ! filesink location="64x64-I.h265"
1360    pub const DECODE_64X64_PROGRESSIVE_I: TestStream = TestStream {
1361        stream: include_bytes!("../../codec/h265/test_data/64x64-I.h265"),
1362        crcs: include_str!("../../codec/h265/test_data/64x64-I.h265.crc"),
1363    };
1364
1365    #[test]
1366    fn test_64x64_progressive_i_block() {
1367        test_decoder_dummy(&DECODE_64X64_PROGRESSIVE_I, BlockingMode::Blocking);
1368    }
1369
1370    #[test]
1371    fn test_64x64_progressive_i_nonblock() {
1372        test_decoder_dummy(&DECODE_64X64_PROGRESSIVE_I, BlockingMode::NonBlocking);
1373    }
1374
1375    /// A 64x64 progressive byte-stream encoded I-frame and P-frame to make
1376    /// it easier to spot errors on the libva trace.
1377    /// Encoded with the following GStreamer pipeline:
1378    /// gst-launch-1.0 videotestsrc num-buffers=2 ! video/x-raw,format=I420,width=64,height=64 ! x265enc option-string="b-adapt=0" ! video/x-h265,profile=main ! filesink location="64x64-I-P.h265"
1379    pub const DECODE_64X64_PROGRESSIVE_I_P: TestStream = TestStream {
1380        stream: include_bytes!("../../codec/h265/test_data/64x64-I-P.h265"),
1381        crcs: include_str!("../../codec/h265/test_data/64x64-I-P.h265.crc"),
1382    };
1383
1384    #[test]
1385    fn test_64x64_progressive_i_p_block() {
1386        test_decoder_dummy(&DECODE_64X64_PROGRESSIVE_I_P, BlockingMode::Blocking);
1387    }
1388
1389    #[test]
1390    fn test_64x64_progressive_i_p_nonblock() {
1391        test_decoder_dummy(&DECODE_64X64_PROGRESSIVE_I_P, BlockingMode::NonBlocking);
1392    }
1393
1394    /// A 64x64 progressive byte-stream encoded I-P-B-P sequence to make it
1395    /// easier to it easier to spot errors on the libva trace.
1396    /// Encoded with the following GStreamer pipeline:
1397    /// gst-launch-1.0 videotestsrc num-buffers=3 ! video/x-raw,format=I420,width=64,height=64 ! x265enc option-string="b-adapt=0:bframes=1" ! video/x-h265,profile=main ! filesink location="64x64-I-P-B-P.h265"
1398    pub const DECODE_64X64_PROGRESSIVE_I_P_B_P: TestStream = TestStream {
1399        stream: include_bytes!("../../codec/h265/test_data/64x64-I-P-B-P.h265"),
1400        crcs: include_str!("../../codec/h265/test_data/64x64-I-P-B-P.h265.crc"),
1401    };
1402
1403    #[test]
1404    fn test_64x64_progressive_i_p_b_p_block() {
1405        test_decoder_dummy(&DECODE_64X64_PROGRESSIVE_I_P_B_P, BlockingMode::Blocking);
1406    }
1407
1408    #[test]
1409    fn test_64x64_progressive_i_p_b_p_nonblock() {
1410        test_decoder_dummy(&DECODE_64X64_PROGRESSIVE_I_P_B_P, BlockingMode::NonBlocking);
1411    }
1412
1413    /// Same as Chromium's test-25fps.h265
1414    pub const DECODE_TEST_25FPS: TestStream = TestStream {
1415        stream: include_bytes!("../../codec/h265/test_data/test-25fps.h265"),
1416        crcs: include_str!("../../codec/h265/test_data/test-25fps.h265.crc"),
1417    };
1418
1419    #[test]
1420    fn test_25fps_block() {
1421        test_decoder_dummy(&DECODE_TEST_25FPS, BlockingMode::Blocking);
1422    }
1423
1424    #[test]
1425    fn test_25fps_nonblock() {
1426        test_decoder_dummy(&DECODE_TEST_25FPS, BlockingMode::NonBlocking);
1427    }
1428
1429    /// Same as Chromium's bear.h265
1430    pub const DECODE_BEAR: TestStream = TestStream {
1431        stream: include_bytes!("../../codec/h265/test_data/bear.h265"),
1432        crcs: include_str!("../../codec/h265/test_data/bear.h265.crc"),
1433    };
1434
1435    #[test]
1436    fn test_bear_block() {
1437        test_decoder_dummy(&DECODE_BEAR, BlockingMode::Blocking);
1438    }
1439
1440    #[test]
1441    fn test_bear_nonblock() {
1442        test_decoder_dummy(&DECODE_BEAR, BlockingMode::NonBlocking);
1443    }
1444
1445    /// Same as Chromium's bbb.h265
1446    pub const DECODE_BBB: TestStream = TestStream {
1447        stream: include_bytes!("../../codec/h265/test_data/bbb.h265"),
1448        crcs: include_str!("../../codec/h265/test_data/bbb.h265.crc"),
1449    };
1450
1451    #[test]
1452    fn test_bbb_block() {
1453        test_decoder_dummy(&DECODE_BBB, BlockingMode::Blocking);
1454    }
1455
1456    #[test]
1457    fn test_bbb_nonblock() {
1458        test_decoder_dummy(&DECODE_BBB, BlockingMode::NonBlocking);
1459    }
1460}