xref: /aosp_15_r20/external/webrtc/modules/rtp_rtcp/source/video_rtp_depacketizer_vp9.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/rtp_rtcp/source/video_rtp_depacketizer_vp9.h"
12 
13 #include <string.h>
14 
15 #include "api/video/video_codec_constants.h"
16 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
17 #include "modules/video_coding/codecs/interface/common_constants.h"
18 #include "rtc_base/bitstream_reader.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21 
22 namespace webrtc {
23 namespace {
24 
25 // Picture ID:
26 //
27 //      +-+-+-+-+-+-+-+-+
28 // I:   |M| PICTURE ID  |   M:0 => picture id is 7 bits.
29 //      +-+-+-+-+-+-+-+-+   M:1 => picture id is 15 bits.
30 // M:   | EXTENDED PID  |
31 //      +-+-+-+-+-+-+-+-+
32 //
ParsePictureId(BitstreamReader & parser,RTPVideoHeaderVP9 * vp9)33 void ParsePictureId(BitstreamReader& parser, RTPVideoHeaderVP9* vp9) {
34   if (parser.ReadBit()) {  // m_bit
35     vp9->picture_id = parser.ReadBits(15);
36     vp9->max_picture_id = kMaxTwoBytePictureId;
37   } else {
38     vp9->picture_id = parser.ReadBits(7);
39     vp9->max_picture_id = kMaxOneBytePictureId;
40   }
41 }
42 
43 // Layer indices :
44 //
45 //      +-+-+-+-+-+-+-+-+
46 // L:   |  T  |U|  S  |D|
47 //      +-+-+-+-+-+-+-+-+
48 //      |   TL0PICIDX   |  (non-flexible mode only)
49 //      +-+-+-+-+-+-+-+-+
50 //
ParseLayerInfo(BitstreamReader & parser,RTPVideoHeaderVP9 * vp9)51 void ParseLayerInfo(BitstreamReader& parser, RTPVideoHeaderVP9* vp9) {
52   vp9->temporal_idx = parser.ReadBits(3);
53   vp9->temporal_up_switch = parser.Read<bool>();
54   vp9->spatial_idx = parser.ReadBits(3);
55   vp9->inter_layer_predicted = parser.Read<bool>();
56   if (vp9->spatial_idx >= kMaxSpatialLayers) {
57     parser.Invalidate();
58     return;
59   }
60 
61   if (!vp9->flexible_mode) {
62     vp9->tl0_pic_idx = parser.Read<uint8_t>();
63   }
64 }
65 
66 // Reference indices:
67 //
68 //      +-+-+-+-+-+-+-+-+                P=1,F=1: At least one reference index
69 // P,F: | P_DIFF      |N|  up to 3 times          has to be specified.
70 //      +-+-+-+-+-+-+-+-+                    N=1: An additional P_DIFF follows
71 //                                                current P_DIFF.
72 //
ParseRefIndices(BitstreamReader & parser,RTPVideoHeaderVP9 * vp9)73 void ParseRefIndices(BitstreamReader& parser, RTPVideoHeaderVP9* vp9) {
74   if (vp9->picture_id == kNoPictureId) {
75     parser.Invalidate();
76     return;
77   }
78 
79   vp9->num_ref_pics = 0;
80   bool n_bit;
81   do {
82     if (vp9->num_ref_pics == kMaxVp9RefPics) {
83       parser.Invalidate();
84       return;
85     }
86 
87     uint8_t p_diff = parser.ReadBits(7);
88     n_bit = parser.Read<bool>();
89 
90     vp9->pid_diff[vp9->num_ref_pics] = p_diff;
91     uint32_t scaled_pid = vp9->picture_id;
92     if (p_diff > scaled_pid) {
93       // TODO(asapersson): Max should correspond to the picture id of last wrap.
94       scaled_pid += vp9->max_picture_id + 1;
95     }
96     vp9->ref_picture_id[vp9->num_ref_pics++] = scaled_pid - p_diff;
97   } while (n_bit);
98 }
99 
100 // Scalability structure (SS).
101 //
102 //      +-+-+-+-+-+-+-+-+
103 // V:   | N_S |Y|G|-|-|-|
104 //      +-+-+-+-+-+-+-+-+              -|
105 // Y:   |     WIDTH     | (OPTIONAL)    .
106 //      +               +               .
107 //      |               | (OPTIONAL)    .
108 //      +-+-+-+-+-+-+-+-+               . N_S + 1 times
109 //      |     HEIGHT    | (OPTIONAL)    .
110 //      +               +               .
111 //      |               | (OPTIONAL)    .
112 //      +-+-+-+-+-+-+-+-+              -|
113 // G:   |      N_G      | (OPTIONAL)
114 //      +-+-+-+-+-+-+-+-+                           -|
115 // N_G: |  T  |U| R |-|-| (OPTIONAL)                 .
116 //      +-+-+-+-+-+-+-+-+              -|            . N_G times
117 //      |    P_DIFF     | (OPTIONAL)    . R times    .
118 //      +-+-+-+-+-+-+-+-+              -|           -|
119 //
ParseSsData(BitstreamReader & parser,RTPVideoHeaderVP9 * vp9)120 void ParseSsData(BitstreamReader& parser, RTPVideoHeaderVP9* vp9) {
121   vp9->num_spatial_layers = parser.ReadBits(3) + 1;
122   vp9->spatial_layer_resolution_present = parser.Read<bool>();
123   bool g_bit = parser.Read<bool>();
124   parser.ConsumeBits(3);
125   vp9->gof.num_frames_in_gof = 0;
126 
127   if (vp9->spatial_layer_resolution_present) {
128     for (size_t i = 0; i < vp9->num_spatial_layers; ++i) {
129       vp9->width[i] = parser.Read<uint16_t>();
130       vp9->height[i] = parser.Read<uint16_t>();
131     }
132   }
133   if (g_bit) {
134     vp9->gof.num_frames_in_gof = parser.Read<uint8_t>();
135   }
136   for (size_t i = 0; i < vp9->gof.num_frames_in_gof; ++i) {
137     vp9->gof.temporal_idx[i] = parser.ReadBits(3);
138     vp9->gof.temporal_up_switch[i] = parser.Read<bool>();
139     vp9->gof.num_ref_pics[i] = parser.ReadBits(2);
140     parser.ConsumeBits(2);
141 
142     for (uint8_t p = 0; p < vp9->gof.num_ref_pics[i]; ++p) {
143       vp9->gof.pid_diff[i][p] = parser.Read<uint8_t>();
144     }
145   }
146 }
147 }  // namespace
148 
149 absl::optional<VideoRtpDepacketizer::ParsedRtpPayload>
Parse(rtc::CopyOnWriteBuffer rtp_payload)150 VideoRtpDepacketizerVp9::Parse(rtc::CopyOnWriteBuffer rtp_payload) {
151   absl::optional<ParsedRtpPayload> result(absl::in_place);
152   int offset = ParseRtpPayload(rtp_payload, &result->video_header);
153   if (offset == 0)
154     return absl::nullopt;
155   RTC_DCHECK_LT(offset, rtp_payload.size());
156   result->video_payload =
157       rtp_payload.Slice(offset, rtp_payload.size() - offset);
158   return result;
159 }
160 
ParseRtpPayload(rtc::ArrayView<const uint8_t> rtp_payload,RTPVideoHeader * video_header)161 int VideoRtpDepacketizerVp9::ParseRtpPayload(
162     rtc::ArrayView<const uint8_t> rtp_payload,
163     RTPVideoHeader* video_header) {
164   RTC_DCHECK(video_header);
165   // Parse mandatory first byte of payload descriptor.
166   BitstreamReader parser(rtp_payload);
167   uint8_t first_byte = parser.Read<uint8_t>();
168   bool i_bit = first_byte & 0b1000'0000;  // PictureId present .
169   bool p_bit = first_byte & 0b0100'0000;  // Inter-picture predicted.
170   bool l_bit = first_byte & 0b0010'0000;  // Layer indices present.
171   bool f_bit = first_byte & 0b0001'0000;  // Flexible mode.
172   bool b_bit = first_byte & 0b0000'1000;  // Begins frame flag.
173   bool e_bit = first_byte & 0b0000'0100;  // Ends frame flag.
174   bool v_bit = first_byte & 0b0000'0010;  // Scalability structure present.
175   bool z_bit = first_byte & 0b0000'0001;  // Not used for inter-layer prediction
176 
177   // Parsed payload.
178   video_header->width = 0;
179   video_header->height = 0;
180   video_header->simulcastIdx = 0;
181   video_header->codec = kVideoCodecVP9;
182 
183   video_header->frame_type =
184       p_bit ? VideoFrameType::kVideoFrameDelta : VideoFrameType::kVideoFrameKey;
185 
186   auto& vp9_header =
187       video_header->video_type_header.emplace<RTPVideoHeaderVP9>();
188   vp9_header.InitRTPVideoHeaderVP9();
189   vp9_header.inter_pic_predicted = p_bit;
190   vp9_header.flexible_mode = f_bit;
191   vp9_header.beginning_of_frame = b_bit;
192   vp9_header.end_of_frame = e_bit;
193   vp9_header.ss_data_available = v_bit;
194   vp9_header.non_ref_for_inter_layer_pred = z_bit;
195 
196   // Parse fields that are present.
197   if (i_bit) {
198     ParsePictureId(parser, &vp9_header);
199   }
200   if (l_bit) {
201     ParseLayerInfo(parser, &vp9_header);
202   }
203   if (p_bit && f_bit) {
204     ParseRefIndices(parser, &vp9_header);
205   }
206   if (v_bit) {
207     ParseSsData(parser, &vp9_header);
208     if (vp9_header.spatial_layer_resolution_present) {
209       // TODO(asapersson): Add support for spatial layers.
210       video_header->width = vp9_header.width[0];
211       video_header->height = vp9_header.height[0];
212     }
213   }
214   video_header->is_first_packet_in_frame = b_bit;
215   video_header->is_last_packet_in_frame = e_bit;
216 
217   int num_remaining_bits = parser.RemainingBitCount();
218   if (num_remaining_bits <= 0) {
219     // Failed to parse or empty vp9 payload data.
220     return 0;
221   }
222   // vp9 descriptor is byte aligned.
223   RTC_DCHECK_EQ(num_remaining_bits % 8, 0);
224   return rtp_payload.size() - num_remaining_bits / 8;
225 }
226 }  // namespace webrtc
227