1 /*
2 * Copyright (c) 2016 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
12 #include "common_video/h264/sps_vui_rewriter.h"
13
14 #include <algorithm>
15 #include <memory>
16 #include <vector>
17
18 #include "rtc_base/bitbuffer.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21 #include "rtc_base/numerics/safe_minmax.h"
22
23 #include "common_video/h264/h264_common.h"
24 #include "common_video/h264/sps_parser.h"
25
26 namespace webrtc {
27
28 // The maximum expected growth from adding a VUI to the SPS. It's actually
29 // closer to 24 or so, but better safe than sorry.
30 const size_t kMaxVuiSpsIncrease = 64;
31
32 #define RETURN_FALSE_ON_FAIL(x) \
33 if (!(x)) { \
34 RTC_LOG_F(LS_ERROR) << " (line:" << __LINE__ << ") FAILED: " #x; \
35 return false; \
36 }
37
38 #define COPY_UINT8(src, dest, tmp) \
39 do { \
40 RETURN_FALSE_ON_FAIL((src)->ReadUInt8(&tmp)); \
41 if (dest) \
42 RETURN_FALSE_ON_FAIL((dest)->WriteUInt8(tmp)); \
43 } while (0)
44
45 #define COPY_EXP_GOLOMB(src, dest, tmp) \
46 do { \
47 RETURN_FALSE_ON_FAIL((src)->ReadExponentialGolomb(&tmp)); \
48 if (dest) \
49 RETURN_FALSE_ON_FAIL((dest)->WriteExponentialGolomb(tmp)); \
50 } while (0)
51
52 #define COPY_BITS(src, dest, tmp, bits) \
53 do { \
54 RETURN_FALSE_ON_FAIL((src)->ReadBits(&tmp, bits)); \
55 if (dest) \
56 RETURN_FALSE_ON_FAIL((dest)->WriteBits(tmp, bits)); \
57 } while (0)
58
59 typedef const SpsParser::SpsState& Sps;
60
61 bool CopyAndRewriteVui(Sps sps,
62 rtc::BitBuffer* source,
63 rtc::BitBufferWriter* destination,
64 SpsVuiRewriter::ParseResult* out_vui_rewritten);
65 bool CopyHrdParameters(rtc::BitBuffer* source,
66 rtc::BitBufferWriter* destination);
67 bool AddBitstreamRestriction(rtc::BitBufferWriter* destination,
68 uint32_t max_num_ref_frames);
69 bool CopyRemainingBits(rtc::BitBuffer* source,
70 rtc::BitBufferWriter* destination);
71
ParseAndRewriteSps(const uint8_t * buffer,size_t length,rtc::Optional<SpsParser::SpsState> * sps,rtc::Buffer * destination)72 SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
73 const uint8_t* buffer,
74 size_t length,
75 rtc::Optional<SpsParser::SpsState>* sps,
76 rtc::Buffer* destination) {
77 // Create temporary RBSP decoded buffer of the payload (exlcuding the
78 // leading nalu type header byte (the SpsParser uses only the payload).
79 std::vector<uint8_t> rbsp_buffer = H264::ParseRbsp(buffer, length);
80 rtc::BitBuffer source_buffer(rbsp_buffer.data(), rbsp_buffer.size());
81 rtc::Optional<SpsParser::SpsState> sps_state =
82 SpsParser::ParseSpsUpToVui(&source_buffer);
83 if (!sps_state)
84 return ParseResult::kFailure;
85
86 *sps = sps_state;
87
88 if (sps_state->pic_order_cnt_type >= 2) {
89 // No need to rewrite VUI in this case.
90 return ParseResult::kPocOk;
91 }
92
93 // We're going to completely muck up alignment, so we need a BitBuffer to
94 // write with.
95 rtc::Buffer out_buffer(length + kMaxVuiSpsIncrease);
96 rtc::BitBufferWriter sps_writer(out_buffer.data(), out_buffer.size());
97
98 // Check how far the SpsParser has read, and copy that data in bulk.
99 size_t byte_offset;
100 size_t bit_offset;
101 source_buffer.GetCurrentOffset(&byte_offset, &bit_offset);
102 memcpy(out_buffer.data(), rbsp_buffer.data(),
103 byte_offset + (bit_offset > 0 ? 1 : 0)); // OK to copy the last bits.
104
105 // SpsParser will have read the vui_params_present flag, which we want to
106 // modify, so back off a bit;
107 if (bit_offset == 0) {
108 --byte_offset;
109 bit_offset = 7;
110 } else {
111 --bit_offset;
112 }
113 sps_writer.Seek(byte_offset, bit_offset);
114
115 ParseResult vui_updated;
116 if (!CopyAndRewriteVui(*sps_state, &source_buffer, &sps_writer,
117 &vui_updated)) {
118 RTC_LOG(LS_ERROR) << "Failed to parse/copy SPS VUI.";
119 return ParseResult::kFailure;
120 }
121
122 if (vui_updated == ParseResult::kVuiOk) {
123 // No update necessary after all, just return.
124 return vui_updated;
125 }
126
127 if (!CopyRemainingBits(&source_buffer, &sps_writer)) {
128 RTC_LOG(LS_ERROR) << "Failed to parse/copy SPS VUI.";
129 return ParseResult::kFailure;
130 }
131
132 // Pad up to next byte with zero bits.
133 sps_writer.GetCurrentOffset(&byte_offset, &bit_offset);
134 if (bit_offset > 0) {
135 sps_writer.WriteBits(0, 8 - bit_offset);
136 ++byte_offset;
137 bit_offset = 0;
138 }
139
140 RTC_DCHECK(byte_offset <= length + kMaxVuiSpsIncrease);
141 RTC_CHECK(destination != nullptr);
142
143 out_buffer.SetSize(byte_offset);
144
145 // Write updates SPS to destination with added RBSP
146 H264::WriteRbsp(out_buffer.data(), out_buffer.size(), destination);
147
148 return ParseResult::kVuiRewritten;
149 }
150
CopyAndRewriteVui(Sps sps,rtc::BitBuffer * source,rtc::BitBufferWriter * destination,SpsVuiRewriter::ParseResult * out_vui_rewritten)151 bool CopyAndRewriteVui(Sps sps,
152 rtc::BitBuffer* source,
153 rtc::BitBufferWriter* destination,
154 SpsVuiRewriter::ParseResult* out_vui_rewritten) {
155 uint32_t golomb_tmp;
156 uint32_t bits_tmp;
157
158 //
159 // vui_parameters_present_flag: u(1)
160 //
161 RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
162
163 // ********* IMPORTANT! **********
164 // Now we're at the VUI, so we want to (1) add it if it isn't present, and
165 // (2) rewrite frame reordering values so no reordering is allowed.
166 if (!sps.vui_params_present) {
167 // Write a simple VUI with the parameters we want and 0 for all other flags.
168 // There are 8 flags to be off before the bitstream restriction flag.
169 RETURN_FALSE_ON_FAIL(destination->WriteBits(0, 8));
170 // bitstream_restriction_flag: u(1)
171 RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
172 RETURN_FALSE_ON_FAIL(
173 AddBitstreamRestriction(destination, sps.max_num_ref_frames));
174 } else {
175 // Parse out the full VUI.
176 // aspect_ratio_info_present_flag: u(1)
177 COPY_BITS(source, destination, bits_tmp, 1);
178 if (bits_tmp == 1) {
179 // aspect_ratio_idc: u(8)
180 COPY_BITS(source, destination, bits_tmp, 8);
181 if (bits_tmp == 255u) { // Extended_SAR
182 // sar_width/sar_height: u(16) each.
183 COPY_BITS(source, destination, bits_tmp, 32);
184 }
185 }
186 // overscan_info_present_flag: u(1)
187 COPY_BITS(source, destination, bits_tmp, 1);
188 if (bits_tmp == 1) {
189 // overscan_appropriate_flag: u(1)
190 COPY_BITS(source, destination, bits_tmp, 1);
191 }
192 // video_signal_type_present_flag: u(1)
193 COPY_BITS(source, destination, bits_tmp, 1);
194 if (bits_tmp == 1) {
195 // video_format + video_full_range_flag: u(3) + u(1)
196 COPY_BITS(source, destination, bits_tmp, 4);
197 // colour_description_present_flag: u(1)
198 COPY_BITS(source, destination, bits_tmp, 1);
199 if (bits_tmp == 1) {
200 // colour_primaries, transfer_characteristics, matrix_coefficients:
201 // u(8) each.
202 COPY_BITS(source, destination, bits_tmp, 24);
203 }
204 }
205 // chroma_loc_info_present_flag: u(1)
206 COPY_BITS(source, destination, bits_tmp, 1);
207 if (bits_tmp == 1) {
208 // chroma_sample_loc_type_(top|bottom)_field: ue(v) each.
209 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
210 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
211 }
212 // timing_info_present_flag: u(1)
213 COPY_BITS(source, destination, bits_tmp, 1);
214 if (bits_tmp == 1) {
215 // num_units_in_tick, time_scale: u(32) each
216 COPY_BITS(source, destination, bits_tmp, 32);
217 COPY_BITS(source, destination, bits_tmp, 32);
218 // fixed_frame_rate_flag: u(1)
219 COPY_BITS(source, destination, bits_tmp, 1);
220 }
221 // nal_hrd_parameters_present_flag: u(1)
222 uint32_t nal_hrd_parameters_present_flag;
223 COPY_BITS(source, destination, nal_hrd_parameters_present_flag, 1);
224 if (nal_hrd_parameters_present_flag == 1) {
225 RETURN_FALSE_ON_FAIL(CopyHrdParameters(source, destination));
226 }
227 // vcl_hrd_parameters_present_flag: u(1)
228 uint32_t vcl_hrd_parameters_present_flag;
229 COPY_BITS(source, destination, vcl_hrd_parameters_present_flag, 1);
230 if (vcl_hrd_parameters_present_flag == 1) {
231 RETURN_FALSE_ON_FAIL(CopyHrdParameters(source, destination));
232 }
233 if (nal_hrd_parameters_present_flag == 1 ||
234 vcl_hrd_parameters_present_flag == 1) {
235 // low_delay_hrd_flag: u(1)
236 COPY_BITS(source, destination, bits_tmp, 1);
237 }
238 // pic_struct_present_flag: u(1)
239 COPY_BITS(source, destination, bits_tmp, 1);
240
241 // bitstream_restriction_flag: u(1)
242 uint32_t bitstream_restriction_flag;
243 RETURN_FALSE_ON_FAIL(source->ReadBits(&bitstream_restriction_flag, 1));
244 RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
245 if (bitstream_restriction_flag == 0) {
246 // We're adding one from scratch.
247 RETURN_FALSE_ON_FAIL(
248 AddBitstreamRestriction(destination, sps.max_num_ref_frames));
249 } else {
250 // We're replacing.
251 // motion_vectors_over_pic_boundaries_flag: u(1)
252 COPY_BITS(source, destination, bits_tmp, 1);
253 // max_bytes_per_pic_denom: ue(v)
254 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
255 // max_bits_per_mb_denom: ue(v)
256 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
257 // log2_max_mv_length_horizontal: ue(v)
258 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
259 // log2_max_mv_length_vertical: ue(v)
260 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
261 // ********* IMPORTANT! **********
262 // The next two are the ones we need to set to low numbers:
263 // max_num_reorder_frames: ue(v)
264 // max_dec_frame_buffering: ue(v)
265 // However, if they are already set to no greater than the numbers we
266 // want, then we don't need to be rewriting.
267 uint32_t max_num_reorder_frames, max_dec_frame_buffering;
268 RETURN_FALSE_ON_FAIL(
269 source->ReadExponentialGolomb(&max_num_reorder_frames));
270 RETURN_FALSE_ON_FAIL(
271 source->ReadExponentialGolomb(&max_dec_frame_buffering));
272 if (max_num_reorder_frames == 0 &&
273 max_dec_frame_buffering <= sps.max_num_ref_frames) {
274 RTC_LOG(LS_INFO) << "VUI bitstream already contains an optimal VUI.";
275 *out_vui_rewritten = SpsVuiRewriter::ParseResult::kVuiOk;
276 return true;
277 }
278 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(0));
279 RETURN_FALSE_ON_FAIL(
280 destination->WriteExponentialGolomb(sps.max_num_ref_frames));
281 }
282 }
283 *out_vui_rewritten = SpsVuiRewriter::ParseResult::kVuiRewritten;
284 return true;
285 }
286
287 // Copies a VUI HRD parameters segment.
CopyHrdParameters(rtc::BitBuffer * source,rtc::BitBufferWriter * destination)288 bool CopyHrdParameters(rtc::BitBuffer* source,
289 rtc::BitBufferWriter* destination) {
290 uint32_t golomb_tmp;
291 uint32_t bits_tmp;
292
293 // cbp_cnt_minus1: ue(v)
294 uint32_t cbp_cnt_minus1;
295 COPY_EXP_GOLOMB(source, destination, cbp_cnt_minus1);
296 // bit_rate_scale and cbp_size_scale: u(4) each
297 COPY_BITS(source, destination, bits_tmp, 8);
298 for (size_t i = 0; i <= cbp_cnt_minus1; ++i) {
299 // bit_rate_value_minus1 and cbp_size_value_minus1: ue(v) each
300 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
301 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
302 // cbr_flag: u(1)
303 COPY_BITS(source, destination, bits_tmp, 1);
304 }
305 // initial_cbp_removal_delay_length_minus1: u(5)
306 COPY_BITS(source, destination, bits_tmp, 5);
307 // cbp_removal_delay_length_minus1: u(5)
308 COPY_BITS(source, destination, bits_tmp, 5);
309 // dbp_output_delay_length_minus1: u(5)
310 COPY_BITS(source, destination, bits_tmp, 5);
311 // time_offset_length: u(5)
312 COPY_BITS(source, destination, bits_tmp, 5);
313 return true;
314 }
315
316 // These functions are similar to webrtc::H264SpsParser::Parse, and based on the
317 // same version of the H.264 standard. You can find it here:
318 // http://www.itu.int/rec/T-REC-H.264
319
320 // Adds a bitstream restriction VUI segment.
AddBitstreamRestriction(rtc::BitBufferWriter * destination,uint32_t max_num_ref_frames)321 bool AddBitstreamRestriction(rtc::BitBufferWriter* destination,
322 uint32_t max_num_ref_frames) {
323 // motion_vectors_over_pic_boundaries_flag: u(1)
324 // Default is 1 when not present.
325 RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
326 // max_bytes_per_pic_denom: ue(v)
327 // Default is 2 when not present.
328 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(2));
329 // max_bits_per_mb_denom: ue(v)
330 // Default is 1 when not present.
331 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(1));
332 // log2_max_mv_length_horizontal: ue(v)
333 // log2_max_mv_length_vertical: ue(v)
334 // Both default to 16 when not present.
335 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(16));
336 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(16));
337
338 // ********* IMPORTANT! **********
339 // max_num_reorder_frames: ue(v)
340 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(0));
341 // max_dec_frame_buffering: ue(v)
342 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(max_num_ref_frames));
343 return true;
344 }
345
CopyRemainingBits(rtc::BitBuffer * source,rtc::BitBufferWriter * destination)346 bool CopyRemainingBits(rtc::BitBuffer* source,
347 rtc::BitBufferWriter* destination) {
348 uint32_t bits_tmp;
349 // Try to get at least the destination aligned.
350 if (source->RemainingBitCount() > 0 && source->RemainingBitCount() % 8 != 0) {
351 size_t misaligned_bits = source->RemainingBitCount() % 8;
352 COPY_BITS(source, destination, bits_tmp, misaligned_bits);
353 }
354 while (source->RemainingBitCount() > 0) {
355 auto count = rtc::SafeMin<size_t>(32u, source->RemainingBitCount());
356 COPY_BITS(source, destination, bits_tmp, count);
357 }
358 // TODO(noahric): The last byte could be all zeroes now, which we should just
359 // strip.
360 return true;
361 }
362
363 } // namespace webrtc
364