Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(276)

Side by Side Diff: webrtc/modules/rtp_rtcp/source/h264/bitstream_rewriter.cc

Issue 1979443004: Add H264 bitstream rewriting to limit frame reordering marker in header (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Rewriting on the receiver side as well Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "webrtc/modules/rtp_rtcp/source/h264/bitstream_rewriter.h"
13
14 #include <algorithm>
15 #include <memory>
16
17 #include "webrtc/base/bitbuffer.h"
18 #include "webrtc/base/bytebuffer.h"
19 #include "webrtc/base/checks.h"
20 #include "webrtc/base/logging.h"
21
22 #include "webrtc/modules/rtp_rtcp/source/h264/h264_common.h"
23 #include "webrtc/modules/rtp_rtcp/source/h264/sps_parser.h"
24
25 namespace webrtc {
26
27 // The maximum expected growth from adding a VUI to the SPS. It's actually
28 // closer to 24 or so, but better safe than sorry.
29 const size_t kMaxVuiSpsIncrease = 64;
30 const size_t kNaluTypeSize = 1;
31
32 #define RETURN_FALSE_ON_FAIL(x) \
33 if (!(x)) { \
34 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 bool H264BitstreamRewriter::ParseAndRewriteSps(const uint8_t* buffer,
60 size_t length) {
61 if (length <= kNaluTypeSize)
62 return false;
63 static const uint8_t kTypeMask = 0x1F;
64 uint8_t nal_type = buffer[0] & kTypeMask;
65 if (nal_type != H264Common::kSps) {
66 LOG(LS_ERROR) << "NALU is not an SPS.";
67 return false;
68 }
69 // Parse out the SPS RBSP. It should be small, so it's ok that we create a
70 // copy. We'll eventually write this back.
71 std::unique_ptr<rtc::ByteBufferWriter> sps_rbsp(
72 H264Common::ParseRbsp(buffer + kNaluTypeSize, length - kNaluTypeSize));
73 rtc::BitBuffer parsed_sps(reinterpret_cast<const uint8_t*>(sps_rbsp->Data()),
74 sps_rbsp->Length());
75 SpsParser sps_parser;
76 if (!sps_parser.ParseFromRbspDecodedBitBuffer(&parsed_sps))
77 return false;
78
79 sps_state_ = sps_parser.GetState();
noahric 2016/05/18 01:35:06 If you want sps_state_ to be exposed, have it as a
sprang_webrtc 2016/05/20 16:10:59 Done.
80 if (sps_state_->pic_order_cnt_type >= 2) {
81 // No need to rewrite VUI in this case.
82 return false;
83 }
84
85 // Create a new SPS buffer, large enough to hold our modifications.
86 // Also make sure these are zeroed out, since the last byte, if unaligned,
87 // needs to end in zeroes.
88 std::unique_ptr<uint8_t[]> translated_sps_rbsp(
89 new uint8_t[length + kMaxVuiSpsIncrease]());
90 // We're going to completely muck up alignment, so we need a BitBuffer to
91 // write with.
92 rtc::BitBufferWriter sps_writer(translated_sps_rbsp.get(),
93 length + kMaxVuiSpsIncrease);
94
95 // Check how far the SpsParser has read, and copy that data in bulk.
96 size_t byte_offset;
97 size_t bit_offset;
98 parsed_sps.GetCurrentOffset(&byte_offset, &bit_offset);
99 memcpy(translated_sps_rbsp.get(), sps_rbsp->Data(),
100 byte_offset + (bit_offset > 0 ? 1 : 0)); // OK to copy the last bits.
101
102 // SpsParser will have read the vui_params_present flag, which we want to
noahric 2016/05/18 01:35:06 That's a suuuuuper dangerous coupling. I think you
sprang_webrtc 2016/05/20 16:10:59 Yeah, this was a bit iffy. Screwups should be caug
103 // modify, so back off one bit;
104 if (bit_offset == 0) {
105 --byte_offset;
106 bit_offset = 7;
107 } else {
108 --bit_offset;
109 }
110 sps_writer.Seek(byte_offset, bit_offset);
111
112 bool vui_updated;
113 if (!CopyAndRewriteVui(&parsed_sps, &sps_writer, &vui_updated)) {
114 LOG(LS_ERROR) << "Failed to parse/copy SPS VUI.";
115 return false;
116 }
117
118 if (!vui_updated)
119 return false;
120
121 if (!CopyRemainingBits(&parsed_sps, &sps_writer))
122 return false;
123
124 // Pad up to next byte with zeros.
125 sps_writer.GetCurrentOffset(&byte_offset, &bit_offset);
126 if (bit_offset > 0) {
127 sps_writer.WriteBits(0, 8 - bit_offset);
128 ++byte_offset;
129 bit_offset = 0;
130 }
131 RTC_DCHECK(byte_offset <= length + kMaxVuiSpsIncrease);
132
133 // Parsed and rewritten successfully, so go ahead and start writing to
134 // destination and mark that we're rewriting the picture order count type.
135 // Start by writing over the NALU header.
136 output_buffer_.reset(new rtc::ByteBufferWriter());
137 output_buffer_->WriteBytes(reinterpret_cast<const char*>(buffer),
138 kNaluTypeSize);
139 H264Common::WriteRbsp(translated_sps_rbsp.get(), byte_offset,
140 output_buffer_.get());
141 return true;
142 }
143
144 bool H264BitstreamRewriter::CopyAndRewriteVui(rtc::BitBuffer* source,
noahric 2016/05/18 01:35:06 If you pass sps_state as an arg, the class doesn't
sprang_webrtc 2016/05/20 16:10:59 Done.
145 rtc::BitBufferWriter* destination,
146 bool* out_vui_rewritten) {
147 uint32_t golomb_tmp;
148 uint32_t bits_tmp;
149 *out_vui_rewritten = false;
150
151 //
152 // vui_parameters_present_flag: u(1)
153 //
154 RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
155
156 // ********* IMPORTANT! **********
157 // Now we're at the VUI, so we want to (1) add it if it isn't present, and
158 // (2) rewrite frame reordering values so no reordering is allowed.
159 if (!sps_state_->vui_params_present) {
160 // Write a simple VUI with the parameters we want and 0 for all other flags.
161 // There are 8 flags to be off before the bitstream restriction flag.
162 RETURN_FALSE_ON_FAIL(destination->WriteBits(0, 8));
163 // bitstream_restriction_flag: u(1)
164 RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
165 RETURN_FALSE_ON_FAIL(
166 AddBitstreamRestriction(destination, sps_state_->max_num_ref_frames));
167 } else {
168 // Parse out the full VUI.
169 // aspect_ratio_info_present_flag: u(1)
170 COPY_BITS(source, destination, bits_tmp, 1);
171 if (bits_tmp == 1) {
172 // aspect_ratio_idc: u(8)
173 COPY_BITS(source, destination, bits_tmp, 8);
174 if (bits_tmp == 255u) { // Extended_SAR
175 // sar_width/sar_height: u(16) each.
176 COPY_BITS(source, destination, bits_tmp, 32);
177 }
178 }
179 // overscan_info_present_flag: u(1)
180 COPY_BITS(source, destination, bits_tmp, 1);
181 if (bits_tmp == 1) {
182 // overscan_appropriate_flag: u(1)
183 COPY_BITS(source, destination, bits_tmp, 1);
184 }
185 // video_signal_type_present_flag: u(1)
186 COPY_BITS(source, destination, bits_tmp, 1);
187 if (bits_tmp == 1) {
188 // video_format + video_full_range_flag: u(3) + u(1)
189 COPY_BITS(source, destination, bits_tmp, 4);
190 // colour_description_present_flag: u(1)
191 COPY_BITS(source, destination, bits_tmp, 1);
192 if (bits_tmp == 1) {
193 // colour_primaries, transfer_characteristics, matrix_coefficients:
194 // u(8) each.
195 COPY_BITS(source, destination, bits_tmp, 24);
196 }
197 }
198 // chroma_loc_info_present_flag: u(1)
199 COPY_BITS(source, destination, bits_tmp, 1);
200 if (bits_tmp == 1) {
201 // chroma_sample_loc_type_(top|bottom)_field: ue(v) each.
202 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
203 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
204 }
205 // timing_info_present_flag: u(1)
206 COPY_BITS(source, destination, bits_tmp, 1);
207 if (bits_tmp == 1) {
208 // num_units_in_tick, time_scale: u(32) each
209 COPY_BITS(source, destination, bits_tmp, 32);
210 COPY_BITS(source, destination, bits_tmp, 32);
211 // fixed_frame_rate_flag: u(1)
212 COPY_BITS(source, destination, bits_tmp, 1);
213 }
214 // nal_hrd_parameters_present_flag: u(1)
215 uint32_t nal_hrd_parameters_present_flag;
216 COPY_BITS(source, destination, nal_hrd_parameters_present_flag, 1);
217 if (nal_hrd_parameters_present_flag == 1) {
218 RETURN_FALSE_ON_FAIL(CopyHrdParameters(source, destination));
219 }
220 // vcl_hrd_parameters_present_flag: u(1)
221 uint32_t vcl_hrd_parameters_present_flag;
222 COPY_BITS(source, destination, vcl_hrd_parameters_present_flag, 1);
223 if (vcl_hrd_parameters_present_flag == 1) {
224 RETURN_FALSE_ON_FAIL(CopyHrdParameters(source, destination));
225 }
226 if (nal_hrd_parameters_present_flag == 1 ||
227 vcl_hrd_parameters_present_flag == 1) {
228 // low_delay_hrd_flag: u(1)
229 COPY_BITS(source, destination, bits_tmp, 1);
230 }
231 // pic_struct_present_flag: u(1)
232 COPY_BITS(source, destination, bits_tmp, 1);
233
234 // bitstream_restriction_flag: u(1)
235 uint32_t bitstream_restriction_flag;
236 RETURN_FALSE_ON_FAIL(source->ReadBits(&bitstream_restriction_flag, 1));
237 RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
238 if (bitstream_restriction_flag == 0) {
239 // We're adding one from scratch.
240 RETURN_FALSE_ON_FAIL(
241 AddBitstreamRestriction(destination, sps_state_->max_num_ref_frames));
242 } else {
243 // We're replacing.
244 // motion_vectors_over_pic_boundaries_flag: u(1)
245 COPY_BITS(source, destination, bits_tmp, 1);
246 // max_bytes_per_pic_denom: ue(v)
247 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
248 // max_bits_per_mb_denom: ue(v)
249 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
250 // log2_max_mv_length_horizontal: ue(v)
251 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
252 // log2_max_mv_length_vertical: ue(v)
253 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
254 // ********* IMPORTANT! **********
255 // The next two are the ones we need to set to low numbers:
256 // max_num_reorder_frames: ue(v)
257 // max_dec_frame_buffering: ue(v)
258 // However, if they are already set to no greater than the numbers we
259 // want, then we don't need to be rewriting.
260 uint32_t max_num_reorder_frames, max_dec_frame_buffering;
261 RETURN_FALSE_ON_FAIL(
262 source->ReadExponentialGolomb(&max_num_reorder_frames));
263 RETURN_FALSE_ON_FAIL(
264 source->ReadExponentialGolomb(&max_dec_frame_buffering));
265 if (max_num_reorder_frames == 0 &&
266 max_dec_frame_buffering <= sps_state_->max_num_ref_frames) {
267 LOG(LS_INFO) << "VUI bitstream already contains an optimal VUI.";
268 return true;
269 }
270 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(0));
271 RETURN_FALSE_ON_FAIL(
272 destination->WriteExponentialGolomb(sps_state_->max_num_ref_frames));
273 }
274 }
275 *out_vui_rewritten = true;
276 return true;
277 }
278
279 // Copies a VUI HRD parameters segment.
280 bool H264BitstreamRewriter::CopyHrdParameters(
281 rtc::BitBuffer* source,
282 rtc::BitBufferWriter* destination) {
283 uint32_t golomb_tmp;
284 uint32_t bits_tmp;
285
286 // cbp_cnt_minus1: ue(v)
287 uint32_t cbp_cnt_minus1;
288 COPY_EXP_GOLOMB(source, destination, cbp_cnt_minus1);
289 // bit_rate_scale and cbp_size_scale: u(4) each
290 COPY_BITS(source, destination, bits_tmp, 8);
291 for (size_t i = 0; i <= cbp_cnt_minus1; ++i) {
292 // bit_rate_value_minus1 and cbp_size_value_minus1: ue(v) each
293 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
294 COPY_EXP_GOLOMB(source, destination, golomb_tmp);
295 // cbr_flag: u(1)
296 COPY_BITS(source, destination, bits_tmp, 1);
297 }
298 // initial_cbp_removal_delay_length_minus1: u(5)
299 COPY_BITS(source, destination, bits_tmp, 5);
300 // cbp_removal_delay_length_minus1: u(5)
301 COPY_BITS(source, destination, bits_tmp, 5);
302 // dbp_output_delay_length_minus1: u(5)
303 COPY_BITS(source, destination, bits_tmp, 5);
304 // time_offset_length: u(5)
305 COPY_BITS(source, destination, bits_tmp, 5);
306 return true;
307 }
308
309 // These functions are similar to webrtc::H264SpsParser::Parse, and based on the
310 // same version of the H.264 standard. You can find it here:
311 // http://www.itu.int/rec/T-REC-H.264
312
313 // Adds a bitstream restriction VUI segment.
314 bool H264BitstreamRewriter::AddBitstreamRestriction(
315 rtc::BitBufferWriter* destination,
316 uint32_t max_num_ref_frames) {
317 // motion_vectors_over_pic_boundaries_flag: u(1)
318 // Default is 1 when not present.
319 RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
320 // max_bytes_per_pic_denom: ue(v)
321 // Default is 2 when not present.
322 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(2));
323 // max_bits_per_mb_denom: ue(v)
324 // Default is 1 when not present.
325 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(1));
326 // log2_max_mv_length_horizontal: ue(v)
327 // log2_max_mv_length_vertical: ue(v)
328 // Both default to 16 when not present.
329 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(16));
330 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(16));
331
332 // ********* IMPORTANT! **********
333 // max_num_reorder_frames: ue(v)
334 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(0));
335 // max_dec_frame_buffering: ue(v)
336 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(max_num_ref_frames));
337 return true;
338 }
339
340 bool H264BitstreamRewriter::CopyRemainingBits(
341 rtc::BitBuffer* source,
342 rtc::BitBufferWriter* destination) {
343 uint32_t bits_tmp;
344 // Try to get at least the destination aligned.
345 if (source->RemainingBitCount() > 0 && source->RemainingBitCount() % 8 != 0) {
346 size_t misaligned_bits = source->RemainingBitCount() % 8;
347 COPY_BITS(source, destination, bits_tmp, misaligned_bits);
348 }
349 while (source->RemainingBitCount() > 0) {
350 size_t count = std::min(static_cast<size_t>(32u),
351 static_cast<size_t>(source->RemainingBitCount()));
352 COPY_BITS(source, destination, bits_tmp, count);
353 }
354 // TODO(noahric): The last byte could be all zeroes now, which we should just
355 // strip.
356 return true;
357 }
358
359 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698