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

Side by Side Diff: media/mp2t/es_parser_h264.cc

Issue 23566013: Mpeg2 TS stream parser for media source. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 3 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 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/mp2t/es_parser_h264.h"
6
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "media/base/bit_reader.h"
10 #include "media/base/buffers.h"
11 #include "media/base/stream_parser_buffer.h"
12 #include "media/base/video_decoder_config.h"
13 #include "media/base/video_frame.h"
14 #include "media/mp2t/mp2t_common.h"
15 #include "ui/gfx/rect.h"
16 #include "ui/gfx/size.h"
17
18 static const int kExtendedSar = 255;
19
20 // ISO 14496 part 10
21 // VUI parameters: Table E-1 "Meaning of sample aspect ration indicator"
22 static const int kTableSarWidth[14] = {
23 1, 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160
24 };
25
26 static const int kTableSarHeight[14] = {
27 1, 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99
28 };
29
30 // Remove the start code emulation prevention ( 0x000003 )
31 // and return the size of the converted buffer.
32 // Note: Size of |buf_rbsp| should be at least |size| to accomodate
33 // the worst case.
34 static int ConvertToRbsp(const uint8* buf, int size, uint8* buf_rbsp) {
35 int rbsp_size = 0;
36 int zero_count = 0;
37 for (int k = 0; k < size; k++) {
38 if (buf[k] == 0x3 && zero_count >= 2)
damienv1 2013/09/17 16:11:52 { zero_count = 0; continue; }
damienv1 2013/09/17 22:07:44 Done.
39 continue;
40 if (buf[k] == 0)
41 zero_count++;
42 else
43 zero_count = 0;
44 buf_rbsp[rbsp_size++] = buf[k];
45 }
46 return rbsp_size;
47 }
48
49 namespace media {
50 namespace mp2t {
51
52 // ISO 14496 - Part 10: Table 7-1 "NAL unit type codes"
53 enum NalUnitType {
54 kNalUnitTypeNonIdrSlice = 1,
55 kNalUnitTypeIdrSlice = 5,
56 kNalUnitTypeSPS = 7,
57 kNalUnitTypePPS = 8,
58 kNalUnitTypeAUD = 9,
59 };
60
61 class BitReaderH264 : public BitReader {
62 public:
63 BitReaderH264(const uint8* data, off_t size)
64 : BitReader(data, size) { }
65
66 // Read an unsigned exp-golomb value.
67 // Return true if successful.
68 bool ReadBitsExpGolomb(uint32* exp_golomb_value);
69 };
70
71 bool BitReaderH264::ReadBitsExpGolomb(uint32* exp_golomb_value) {
72 // Get the number of leading zeros.
73 int zero_count = 0;
74 while (true) {
75 int one_bit;
76 RCHECK(ReadBits(1, &one_bit));
77 if (one_bit != 0)
78 break;
79 zero_count++;
80 }
81
82 // If zero_count is greater than 31, the calculated value will overflow.
83 if (zero_count > 31) {
84 SkipBits(zero_count);
85 return false;
86 }
87
88 // Read the actual value.
89 uint32 base = (1 << zero_count) - 1;
90 uint32 offset;
91 RCHECK(ReadBits(zero_count, &offset));
92 *exp_golomb_value = base + offset;
93
94 return true;
95 }
96
97 EsParserH264::EsParserH264(
98 const NewVideoConfigCB& new_video_config_cb,
99 const EmitBufferCB& emit_buffer_cb)
100 : new_video_config_cb_(new_video_config_cb),
101 emit_buffer_cb_(emit_buffer_cb),
102 es_pos_(0),
103 current_nal_pos_(-1),
104 current_access_unit_pos_(-1),
105 is_key_frame_(false),
106 is_video_config_known_(false),
107 profile_idc_(0),
108 level_idc_(0),
109 pic_width_in_mbs_minus1_(0),
110 pic_height_in_map_units_minus1_(0) {
111 }
112
113 EsParserH264::~EsParserH264() {
114 }
115
116 bool EsParserH264::Parse(const uint8* buf, int size,
117 base::TimeDelta pts,
118 base::TimeDelta dts) {
119 // Note: Parse is invoked each time a PES packet has been reassembled.
120 // Unfortunately, a PES packet does not necessarily map
121 // to an h264 access unit, although the HLS recommendation is to use one PES
122 // for each access unit (but this is just a recommendation and some streams
123 // do not comply with this recommendation).
124
125 // Link position |raw_es_size| in the ES stream with a timing descriptor.
126 // HLS recommendation: "In AVC video, you should have both a DTS and a
127 // PTS in each PES header".
128 if (dts == kNoTimestamp() && pts == kNoTimestamp()) {
129 DVLOG(1) << "A timestamp must be provided for each reassembled PES";
130 return false;
131 }
132 TimingDesc timing_desc;
133 timing_desc.pts = pts;
134 timing_desc.dts = (dts != kNoTimestamp()) ? dts : pts;
135
136 int raw_es_size;
137 const uint8* raw_es;
138 es_byte_queue_.Peek(&raw_es, &raw_es_size);
139 timing_desc_list_.push_back(
140 std::pair<int, TimingDesc>(raw_es_size, timing_desc));
141
142 // Add the incoming bytes to the ES queue.
143 es_byte_queue_.Push(buf, size);
144
145 // Add NALs from the incoming buffer.
146 if (!ParseInternal())
147 return false;
148
149 // Discard emitted frames
150 // or every byte that was parsed so far if there is no current frame.
151 int skip_count =
152 (current_access_unit_pos_ >= 0) ? current_access_unit_pos_ : es_pos_;
153 DiscardEs(skip_count);
154
155 return true;
156 }
157
158 void EsParserH264::Flush() {
159 if (current_access_unit_pos_ < 0)
160 return;
161
162 // Force emitting the last access unit.
163 int next_aud_pos;
164 const uint8* raw_es;
165 es_byte_queue_.Peek(&raw_es, &next_aud_pos);
166 EmitFrameIfNeeded(next_aud_pos);
167 current_nal_pos_ = -1;
168 current_access_unit_pos_ = -1;
169
170 // Discard the emitted frame.
171 DiscardEs(next_aud_pos);
172 }
173
174 void EsParserH264::Reset() {
175 DVLOG(1) << "EsParserH264::Reset";
176 es_byte_queue_.Reset();
177 timing_desc_list_.clear();
178 es_pos_ = 0;
179 current_nal_pos_ = -1;
180 current_access_unit_pos_ = -1;
181 is_key_frame_ = false;
182 is_video_config_known_ = false;
183 }
184
185 bool EsParserH264::ParseInternal() {
186 int raw_es_size;
187 const uint8* raw_es;
188 es_byte_queue_.Peek(&raw_es, &raw_es_size);
189
190 DCHECK_GE(es_pos_, 0);
191 DCHECK_LT(es_pos_, raw_es_size);
192
193 // Resume NAL segmentation where it was left.
damienv1 2013/09/17 16:11:52 Comment should be updated.
damienv1 2013/09/17 22:07:44 Done.
194 for ( ; es_pos_ < raw_es_size - 4; es_pos_++) {
damienv1 2013/09/17 16:11:52 Should be "- 5" to account for the size of the syn
damienv1 2013/09/17 22:07:44 My mistake, 4 is the right value. If syncword_leng
195 // Make sure the syncword is either 00 00 00 01 or 00 00 01
196 if (raw_es[es_pos_ + 0] != 0 || raw_es[es_pos_ + 1] != 0)
197 continue;
198 int syncword_length = 0;
199 if (raw_es[es_pos_ + 2] == 0 && raw_es[es_pos_ + 3] == 1)
200 syncword_length = 4;
201 else if (raw_es[es_pos_ + 2] == 1)
202 syncword_length = 3;
203 else
204 continue;
205
206 // Parse the current NAL (and the new NAL then becomes the current one).
207 if (current_nal_pos_ >= 0) {
208 int nal_size = es_pos_ - current_nal_pos_;
209 DCHECK_GT(nal_size, 0);
210 RCHECK(NalParser(&raw_es[current_nal_pos_], nal_size));
damienv1 2013/09/17 16:11:52 The NAL parser should receive a pointer to the NAL
damienv1 2013/09/17 22:07:44 Done.
211 }
212 current_nal_pos_ = es_pos_;
213
214 // Retrieve the NAL type.
215 int nal_header = raw_es[es_pos_ + syncword_length];
216 int forbidden_zero_bit = (nal_header >> 7) & 0x1;
217 RCHECK(forbidden_zero_bit == 0);
218 NalUnitType nal_unit_type = static_cast<NalUnitType>(nal_header & 0x1f);
219 DVLOG(LOG_LEVEL_ES) << "nal: offset=" << es_pos_
220 << " type=" << nal_unit_type;
221
222 // Emit a frame if needed.
223 if (nal_unit_type == kNalUnitTypeAUD)
224 EmitFrameIfNeeded(es_pos_);
225
226 // Skip the syncword.
227 es_pos_ += syncword_length;
228 }
229
230 return true;
231 }
232
233 void EsParserH264::EmitFrameIfNeeded(int next_aud_pos) {
234 // There is no current frame: start a new frame.
235 if (current_access_unit_pos_ < 0) {
236 current_access_unit_pos_ = next_aud_pos;
237 is_key_frame_ = true;
238 return;
239 }
240
241 // Get the access unit timing info.
242 TimingDesc current_timing_desc;
243 while (!timing_desc_list_.empty() &&
244 timing_desc_list_.front().first <= current_access_unit_pos_) {
245 current_timing_desc = timing_desc_list_.front().second;
246 timing_desc_list_.pop_front();
247 }
248
249 // Emit a frame.
250 int raw_es_size;
251 const uint8* raw_es;
252 es_byte_queue_.Peek(&raw_es, &raw_es_size);
253 int access_unit_size = next_aud_pos - current_access_unit_pos_;
254 scoped_refptr<StreamParserBuffer> stream_parser_buffer =
255 StreamParserBuffer::CopyFrom(
256 &raw_es[current_access_unit_pos_],
257 access_unit_size,
258 is_key_frame_);
259 stream_parser_buffer->SetDecodeTimestamp(current_timing_desc.dts);
260 stream_parser_buffer->set_timestamp(current_timing_desc.pts);
261 emit_buffer_cb_.Run(stream_parser_buffer);
262
263 // Start a new frame.
264 // |is_key_frame_| will be updated while parsing the NALs of that frame.
265 current_access_unit_pos_ = es_pos_;
266 is_key_frame_ = true;
267 }
268
269 void EsParserH264::DiscardEs(int nbytes) {
270 DCHECK_GE(nbytes, 0);
271 if (nbytes == 0)
272 return;
273
274 // Update the position of
275 // - the parser,
276 // - the current NAL,
277 // - the current access unit.
278 es_pos_ -= nbytes;
279 if (es_pos_ < 0)
280 es_pos_ = 0;
281
282 if (current_nal_pos_ >= 0) {
283 DCHECK_GE(current_nal_pos_, nbytes);
284 current_nal_pos_ -= nbytes;
285 }
286 if (current_access_unit_pos_ >= 0) {
287 DCHECK_GE(current_access_unit_pos_, nbytes);
288 current_access_unit_pos_ -= nbytes;
289 }
290
291 // Update the timing information accordingly.
292 std::list<std::pair<int, TimingDesc> >::iterator timing_it
293 = timing_desc_list_.begin();
294 for (; timing_it != timing_desc_list_.end(); ++timing_it)
295 timing_it->first -= nbytes;
296
297 // Discard |nbytes| of ES.
298 es_byte_queue_.Pop(nbytes);
299 }
300
301 bool EsParserH264::NalParser(const uint8* buf, int size) {
302 // Discard the annexB syncword.
303 if (size < 3 || buf[0] != 0 || buf[1] != 0 ||
304 !(buf[2] == 1 || (size >= 4 && buf[2] == 0 && buf[3] == 1))) {
305 DVLOG(1) << "NalParser: bad annexB start code";
306 return false;
307 }
308 if (buf[2] == 1) {
309 buf += 3;
310 size -= 3;
311 } else {
312 buf += 4;
313 size -= 4;
314 }
damienv1 2013/09/17 16:11:52 All this can be removed if we assume |buf| is poin
315
316 // Get the NAL header.
317 if (size < 1) {
318 DVLOG(1) << "NalParser: incomplete NAL";
319 return false;
320 }
321 int nal_header = buf[0];
322 buf += 1;
323 size -= 1;
324
325 int forbidden_zero_bit = (nal_header >> 7) & 0x1;
326 if (forbidden_zero_bit != 0)
327 return false;
328 int nal_ref_idc = (nal_header >> 5) & 0x3;
329 int nal_unit_type = nal_header & 0x1f;
330
331 // Process the NAL content.
332 switch (nal_unit_type) {
333 case kNalUnitTypeSPS:
334 DVLOG(LOG_LEVEL_ES) << "NAL: SPS";
335 // |nal_ref_idc| should not be 0 for a SPS.
336 if (nal_ref_idc == 0)
337 return false;
338 return ProcessSPS(buf, size);
339 case kNalUnitTypeIdrSlice:
340 DVLOG(LOG_LEVEL_ES) << "NAL: IDR slice";
341 return true;
342 case kNalUnitTypeNonIdrSlice:
343 DVLOG(LOG_LEVEL_ES) << "NAL: Non IDR slice";
344 is_key_frame_ = false;
345 return true;
346 case kNalUnitTypePPS:
347 DVLOG(LOG_LEVEL_ES) << "NAL: PPS";
348 return true;
349 case kNalUnitTypeAUD:
350 DVLOG(LOG_LEVEL_ES) << "NAL: AUD";
351 return true;
352 default:
353 DVLOG(LOG_LEVEL_ES) << "NAL: " << nal_unit_type;
354 return true;
355 }
356
357 NOTREACHED();
358 return false;
359 }
360
361 bool EsParserH264::ProcessSPS(const uint8* buf, int size) {
362 if (size <= 0)
363 return false;
364
365 // Removes start code emulation prevention.
366 // TODO(damienv): refactoring in media/base
367 // so as to have a unique H264 bit reader in Chrome.
368 scoped_ptr<uint8[]> buf_rbsp(new uint8[size]);
369 int rbsp_size = ConvertToRbsp(buf, size, buf_rbsp.get());
370
371 BitReaderH264 bit_reader(buf_rbsp.get(), rbsp_size);
372
373 int profile_idc;
374 int constraint_setX_flag;
375 int level_idc;
376 uint32 seq_parameter_set_id;
377 uint32 log2_max_frame_num_minus4;
378 uint32 pic_order_cnt_type;
379 RCHECK(bit_reader.ReadBits(8, &profile_idc));
380 RCHECK(bit_reader.ReadBits(8, &constraint_setX_flag));
381 RCHECK(bit_reader.ReadBits(8, &level_idc));
382 RCHECK(bit_reader.ReadBitsExpGolomb(&seq_parameter_set_id));
383 RCHECK(bit_reader.ReadBitsExpGolomb(&log2_max_frame_num_minus4));
384 RCHECK(bit_reader.ReadBitsExpGolomb(&pic_order_cnt_type));
385
386 // |pic_order_cnt_type| shall be in the range of 0 to 2.
387 RCHECK(pic_order_cnt_type <= 2);
388 if (pic_order_cnt_type == 0) {
389 uint32 log2_max_pic_order_cnt_lsb_minus4;
390 RCHECK(bit_reader.ReadBitsExpGolomb(&log2_max_pic_order_cnt_lsb_minus4));
391 } else if (pic_order_cnt_type == 1) {
392 // Note: |offset_for_non_ref_pic| and |offset_for_top_to_bottom_field|
393 // corresponds to their codenum not to their actual value.
394 bool delta_pic_order_always_zero_flag;
395 uint32 offset_for_non_ref_pic;
396 uint32 offset_for_top_to_bottom_field;
397 uint32 num_ref_frames_in_pic_order_cnt_cycle;
398 RCHECK(bit_reader.ReadBits(1, &delta_pic_order_always_zero_flag));
399 RCHECK(bit_reader.ReadBitsExpGolomb(&offset_for_non_ref_pic));
400 RCHECK(bit_reader.ReadBitsExpGolomb(&offset_for_top_to_bottom_field));
401 RCHECK(
402 bit_reader.ReadBitsExpGolomb(&num_ref_frames_in_pic_order_cnt_cycle));
403 for (uint32 i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) {
404 uint32 offset_for_ref_frame_codenum;
405 RCHECK(bit_reader.ReadBitsExpGolomb(&offset_for_ref_frame_codenum));
406 }
407 }
408
409 uint32 num_ref_frames;
410 int gaps_in_frame_num_value_allowed_flag;
411 uint32 pic_width_in_mbs_minus1;
412 uint32 pic_height_in_map_units_minus1;
413 RCHECK(bit_reader.ReadBitsExpGolomb(&num_ref_frames));
414 RCHECK(bit_reader.ReadBits(1, &gaps_in_frame_num_value_allowed_flag));
415 RCHECK(bit_reader.ReadBitsExpGolomb(&pic_width_in_mbs_minus1));
416 RCHECK(bit_reader.ReadBitsExpGolomb(&pic_height_in_map_units_minus1));
417
418 int frame_mbs_only_flag;
419 RCHECK(bit_reader.ReadBits(1, &frame_mbs_only_flag));
420 if (!frame_mbs_only_flag) {
421 int mb_adaptive_frame_field_flag;
422 RCHECK(bit_reader.ReadBits(1, &mb_adaptive_frame_field_flag));
423 }
424
425 int direct_8x8_inference_flag;
426 RCHECK(bit_reader.ReadBits(1, &direct_8x8_inference_flag));
427
428 bool frame_cropping_flag;
429 uint32 frame_crop_left_offset = 0;
430 uint32 frame_crop_right_offset = 0;
431 uint32 frame_crop_top_offset = 0;
432 uint32 frame_crop_bottom_offset = 0;
433 RCHECK(bit_reader.ReadBits(1, &frame_cropping_flag));
434 if (frame_cropping_flag) {
435 RCHECK(bit_reader.ReadBitsExpGolomb(&frame_crop_left_offset));
436 RCHECK(bit_reader.ReadBitsExpGolomb(&frame_crop_right_offset));
437 RCHECK(bit_reader.ReadBitsExpGolomb(&frame_crop_top_offset));
438 RCHECK(bit_reader.ReadBitsExpGolomb(&frame_crop_bottom_offset));
439 }
440
441 bool vui_parameters_present_flag;
442 RCHECK(bit_reader.ReadBits(1, &vui_parameters_present_flag));
443 int sar_width = 1;
444 int sar_height = 1;
445 if (vui_parameters_present_flag) {
446 // Read only the aspect ratio information from the VUI section.
447 // TODO(damienv): check whether other VUI info are useful.
448 bool aspect_ratio_info_present_flag = false;
449 RCHECK(bit_reader.ReadBits(1, &aspect_ratio_info_present_flag));
450 if (aspect_ratio_info_present_flag) {
451 int aspect_ratio_idc;
452 RCHECK(bit_reader.ReadBits(8, &aspect_ratio_idc));
453 if (aspect_ratio_idc == kExtendedSar) {
454 RCHECK(bit_reader.ReadBits(16, &sar_width));
455 RCHECK(bit_reader.ReadBits(16, &sar_height));
456 } else if (aspect_ratio_idc < 14) {
457 sar_width = kTableSarWidth[aspect_ratio_idc];
458 sar_height = kTableSarHeight[aspect_ratio_idc];
459 }
460 }
461 }
462
463 if (sar_width != sar_height) {
464 // TODO(damienv): Support non square pixels.
465 DVLOG(1)
466 << "Non square pixel not supported yet:"
467 << " sar_width=" << sar_width
468 << " sar_height=" << sar_height;
469 return false;
470 }
471
472 if (is_video_config_known_ &&
473 profile_idc == profile_idc_ &&
474 level_idc == level_idc_ &&
475 pic_width_in_mbs_minus1 == pic_width_in_mbs_minus1_ &&
476 pic_height_in_map_units_minus1 == pic_height_in_map_units_minus1_) {
477 // This is the same SPS as the previous one.
478 return true;
479 }
480 is_video_config_known_ = true;
481 profile_idc_ = profile_idc;
482 level_idc_ = level_idc;
483 pic_width_in_mbs_minus1_ = pic_width_in_mbs_minus1;
484 pic_height_in_map_units_minus1_ = pic_height_in_map_units_minus1;
485
486 // TODO(damienv):
487 // Assuming the SPS is used right away by the PPS
488 // and the slice headers is a strong assumption.
489 // In theory, we should process the SPS and PPS
490 // and only when one of the slice header is switching
491 // the PPS id, the video decoder config should be changed.
492 DVLOG(1) << "Profile IDC: " << profile_idc;
493 DVLOG(1) << "Level IDC: " << level_idc;
494 DVLOG(1) << "Pic width: " << (pic_width_in_mbs_minus1 + 1) * 16;
495 DVLOG(1) << "Pic height: " << (pic_height_in_map_units_minus1 + 1) * 16;
496 DVLOG(1) << "log2_max_frame_num_minus4: " << log2_max_frame_num_minus4;
497
498 // TODO(damienv): a MAP unit can be either 16 or 32 pixels.
499 // although it's 16 pixels for progressive non MBAFF frames.
500 gfx::Size coded_size((pic_width_in_mbs_minus1 + 1) * 16,
501 (pic_height_in_map_units_minus1 + 1) * 16);
502 gfx::Rect visible_rect(
503 frame_crop_left_offset,
504 frame_crop_top_offset,
505 (coded_size.width() - frame_crop_right_offset) - frame_crop_left_offset,
506 (coded_size.height() - frame_crop_bottom_offset) - frame_crop_top_offset);
507
508 // TODO(damienv): calculate the natural size based
509 // on the possible aspect ratio coded in the VUI parameters.
510 gfx::Size natural_size(visible_rect.width(),
511 visible_rect.height());
512
513 VideoDecoderConfig video_decoder_config(
514 kCodecH264,
515 VIDEO_CODEC_PROFILE_UNKNOWN, // TODO(damienv)
516 VideoFrame::YV12,
517 coded_size,
518 visible_rect,
519 natural_size,
520 NULL, 0,
521 false);
522 new_video_config_cb_.Run(video_decoder_config);
523
524 return true;
525 }
526
527 } // namespace mp2t
528 } // namespace media
529
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698