1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use crate::codec::h265::parser::NaluType;
use crate::codec::h265::parser::Pps;
use crate::codec::h265::parser::Slice;

#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub enum Reference {
    #[default]
    None,
    ShortTerm,
    LongTerm,
}

/// Data associated with an h.265 picture. Most fields are extracted from the
/// slice header and kept for future processing.
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct PictureData {
    // Fields extracted from the slice header. These are the CamelCase
    // variables, unless noted otherwise.
    pub nalu_type: NaluType,
    pub no_rasl_output_flag: bool,
    pub pic_output_flag: bool,
    pub valid_for_prev_tid0_pic: bool,
    pub slice_pic_order_cnt_lsb: i32,
    pub pic_order_cnt_msb: i32,
    pub pic_order_cnt_val: i32,
    pub no_output_of_prior_pics_flag: bool,

    // Internal state.
    pub is_irap: bool,
    pub first_picture_after_eos: bool,
    reference: Reference,
    pub pic_latency_cnt: i32,
    pub needed_for_output: bool,
    pub short_term_ref_pic_set_size_bits: u32,
}

impl PictureData {
    /// Instantiates a new `PictureData` from a slice.
    ///
    /// See 8.1.3 Decoding process for a coded picture with nuh_layer_id equal
    /// to 0.
    ///
    /// This will also call the picture order count process (clause 8.3.1) to
    /// correctly initialize the POC values.
    pub fn new_from_slice(
        slice: &Slice<&[u8]>,
        pps: &Pps,
        first_picture_in_bitstream: bool,
        first_picture_after_eos: bool,
        prev_tid0_pic: Option<&PictureData>,
        max_pic_order_cnt_lsb: i32,
        _timestamp: u64,
    ) -> Self {
        let hdr = slice.header();
        let nalu_type = slice.nalu().header().nalu_type();
        let is_irap = nalu_type.is_irap();

        // We assume HandleCraAsBlafFLag == 0, as it is only set through
        // external means, which we do not provide.

        let mut pic_order_cnt_msb = 0;
        let slice_pic_order_cnt_lsb: i32 = hdr.pic_order_cnt_lsb().into();

        // Compute the output flags:
        // The value of NoRaslOutputFlag is equal to 1 for each IDR access
        // unit, each BLA access unit, and each CRA access unit that is the
        // first access unit in the bitstream in decoding order, is the first
        // access unit that follows an end of sequence NAL unit in decoding
        // order, or has HandleCraAsBlaFlag equal to 1.
        let no_rasl_output_flag = nalu_type.is_idr()
            || nalu_type.is_bla()
            || (nalu_type.is_cra() && first_picture_in_bitstream)
            || first_picture_after_eos;

        let pic_output_flag = if slice.nalu().header().nalu_type().is_rasl() && no_rasl_output_flag
        {
            false
        } else {
            hdr.pic_output_flag()
        };

        // Compute the Picture Order Count. See 8.3.1 Decoding Process for
        // Picture Order Count
        if !(is_irap && no_rasl_output_flag) {
            if let Some(prev_tid0_pic) = prev_tid0_pic {
                // Equation (8-1)
                let prev_pic_order_cnt_lsb = prev_tid0_pic.slice_pic_order_cnt_lsb;
                let prev_pic_order_cnt_msb = prev_tid0_pic.pic_order_cnt_msb;
                if (slice_pic_order_cnt_lsb < prev_pic_order_cnt_lsb)
                    && (prev_pic_order_cnt_lsb - slice_pic_order_cnt_lsb)
                        >= (max_pic_order_cnt_lsb / 2)
                {
                    pic_order_cnt_msb = prev_pic_order_cnt_msb + max_pic_order_cnt_lsb;
                } else if (slice_pic_order_cnt_lsb > prev_pic_order_cnt_lsb)
                    && (slice_pic_order_cnt_lsb - prev_pic_order_cnt_lsb)
                        > (max_pic_order_cnt_lsb / 2)
                {
                    pic_order_cnt_msb = prev_pic_order_cnt_msb - max_pic_order_cnt_lsb;
                } else {
                    pic_order_cnt_msb = prev_pic_order_cnt_msb;
                }
            }
        }

        // Compute whether this picture will be a valid prevTid0Pic, i.e.:
        //
        // Let prevTid0Pic be the previous picture in decoding order that has
        // TemporalId equal to 0 and that is not a RASL, RADL or SLNR picture.
        //
        // Use this flag to correctly set up the field in the decoder during
        // `finish_picture`.
        let valid_for_prev_tid0_pic = pps.temporal_id() == 0
            && !nalu_type.is_radl()
            && !nalu_type.is_rasl()
            && !nalu_type.is_slnr();

        let no_output_of_prior_pics_flag =
            if nalu_type.is_irap() && no_rasl_output_flag && !first_picture_in_bitstream {
                nalu_type.is_cra() || hdr.no_output_of_prior_pics_flag()
            } else {
                false
            };

        Self {
            nalu_type,
            no_rasl_output_flag,
            no_output_of_prior_pics_flag,
            pic_output_flag,
            valid_for_prev_tid0_pic,
            slice_pic_order_cnt_lsb,
            pic_order_cnt_msb,
            // Equation (8-2)
            pic_order_cnt_val: pic_order_cnt_msb + slice_pic_order_cnt_lsb,
            is_irap,
            first_picture_after_eos,
            reference: Default::default(),
            pic_latency_cnt: 0,
            needed_for_output: false,
            short_term_ref_pic_set_size_bits: hdr.st_rps_bits(),
        }
    }

    /// Whether the current picture is a reference, either ShortTerm or LongTerm.
    pub fn is_ref(&self) -> bool {
        !matches!(self.reference, Reference::None)
    }

    pub fn set_reference(&mut self, reference: Reference) {
        log::debug!(
            "Set reference of POC {} to {:?}",
            self.pic_order_cnt_val,
            reference
        );

        self.reference = reference;
    }

    pub fn reference(&self) -> &Reference {
        &self.reference
    }
}