File
Blob: firmware/vendor/str0m/src/packet/contiguity.rs
| 1 | use super::CodecExtra; |
| 2 | use super::contiguity_vp8::Vp8Contiguity; |
| 3 | use super::contiguity_vp9::Vp9Contiguity; |
| 4 | |
| 5 | #[derive(Debug)] |
| 6 | pub enum Contiguity { |
| 7 | Vp8(Vp8Contiguity), |
| 8 | Vp9(Vp9Contiguity), |
| 9 | None, |
| 10 | } |
| 11 | |
| 12 | impl Contiguity { |
| 13 | pub fn check(&mut self, next: &CodecExtra, contiguous_seq: bool) -> (bool, bool) { |
| 14 | match (self, next) { |
| 15 | (Self::Vp8(contiguity), CodecExtra::Vp8(next)) => { |
| 16 | contiguity.check(next, contiguous_seq) |
| 17 | } |
| 18 | (Self::Vp9(contiguity), CodecExtra::Vp9(next)) => { |
| 19 | contiguity.check(next, contiguous_seq) |
| 20 | } |
| 21 | (Self::Vp8(_) | Self::Vp9(_) | Self::None, _) => (true, contiguous_seq), |
| 22 | } |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | #[derive(Debug)] |
| 27 | pub(crate) struct FrameContiguityState { |
| 28 | /// last picture id of layer 0 that we allowed emitting |
| 29 | pub(crate) last_picture_id: Option<u64>, |
| 30 | |
| 31 | /// last picture id of any layer that we allowed emitting |
| 32 | pub(crate) last_tl0_picture_id: Option<u64>, |
| 33 | } |
| 34 | |
| 35 | impl FrameContiguityState { |
| 36 | /// Returns whether we can emit such frame and whether it's decodable with contiguity |
| 37 | pub(crate) fn next_frame( |
| 38 | &mut self, |
| 39 | picture_id: Option<u64>, |
| 40 | tl0_picture_id: Option<u64>, |
| 41 | layer_index: Option<u64>, |
| 42 | contiguous_seq: bool, |
| 43 | ) -> (bool, bool) { |
| 44 | let Some(picture_id) = picture_id else { |
| 45 | // picture id is not enabled or not progressing anyway |
| 46 | return (true, contiguous_seq); |
| 47 | }; |
| 48 | |
| 49 | let Some(tl0_picture_id) = tl0_picture_id else { |
| 50 | return (true, contiguous_seq); |
| 51 | }; |
| 52 | |
| 53 | let (Some(last_tl0_picture_id), Some(last_picture_id)) = |
| 54 | (self.last_tl0_picture_id, self.last_picture_id) |
| 55 | else { |
| 56 | self.last_tl0_picture_id = Some(tl0_picture_id); |
| 57 | self.last_picture_id = Some(picture_id); |
| 58 | return (true, true); |
| 59 | }; |
| 60 | |
| 61 | // discard older pictures if any |
| 62 | if picture_id <= last_picture_id { |
| 63 | return (false, true); |
| 64 | } |
| 65 | |
| 66 | if layer_index == Some(0) { |
| 67 | if tl0_picture_id == last_tl0_picture_id { |
| 68 | warn!( |
| 69 | "VP8 or VP9: 2 subsequent frames on layer zero must \ |
| 70 | have different tl0 picture id: encoding problem?" |
| 71 | ); |
| 72 | } |
| 73 | |
| 74 | // Frame on layer 0: always emit and report discontinuity if not subsequent |
| 75 | let emit = true; |
| 76 | // note: we use wrapping add because the encoder can restart if the |
| 77 | // camera is closed / reopened and here we only care about |
| 78 | // contiguity |
| 79 | let contiguous = tl0_picture_id == last_tl0_picture_id.wrapping_add(1); |
| 80 | |
| 81 | self.last_tl0_picture_id = Some(tl0_picture_id); |
| 82 | self.last_picture_id = Some(picture_id); |
| 83 | |
| 84 | return (emit, contiguous); |
| 85 | } |
| 86 | |
| 87 | // Frame on layer 1 or 2: only emit if they refer to the current layer 0 |
| 88 | // and they are subsequent |
| 89 | let emit = |
| 90 | tl0_picture_id == last_tl0_picture_id && picture_id == last_picture_id.wrapping_add(1); |
| 91 | |
| 92 | if emit { |
| 93 | self.last_picture_id = Some(picture_id); |
| 94 | if !contiguous_seq { |
| 95 | // this as happened in Safari + very lossy network (very rare) |
| 96 | debug!( |
| 97 | "VP8 or VP9: contiguous pictures implies contiguous seq numbers: encoding issue ?" |
| 98 | ) |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | (emit, true) |
| 103 | } |
| 104 | } |