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