• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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/formats/mp2t/es_parser_h264.h"
6 
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "media/base/buffers.h"
11 #include "media/base/stream_parser_buffer.h"
12 #include "media/base/video_frame.h"
13 #include "media/filters/h264_parser.h"
14 #include "media/formats/common/offset_byte_queue.h"
15 #include "media/formats/mp2t/es_adapter_video.h"
16 #include "media/formats/mp2t/mp2t_common.h"
17 #include "ui/gfx/rect.h"
18 #include "ui/gfx/size.h"
19 
20 namespace media {
21 namespace mp2t {
22 
23 // An AUD NALU is at least 4 bytes:
24 // 3 bytes for the start code + 1 byte for the NALU type.
25 const int kMinAUDSize = 4;
26 
EsParserH264(const NewVideoConfigCB & new_video_config_cb,const EmitBufferCB & emit_buffer_cb)27 EsParserH264::EsParserH264(
28     const NewVideoConfigCB& new_video_config_cb,
29     const EmitBufferCB& emit_buffer_cb)
30     : es_adapter_(new_video_config_cb, emit_buffer_cb),
31       h264_parser_(new H264Parser()),
32       current_access_unit_pos_(0),
33       next_access_unit_pos_(0) {
34 }
35 
~EsParserH264()36 EsParserH264::~EsParserH264() {
37 }
38 
Flush()39 void EsParserH264::Flush() {
40   DVLOG(1) << __FUNCTION__;
41   if (!FindAUD(&current_access_unit_pos_))
42     return;
43 
44   // Simulate an additional AUD to force emitting the last access unit
45   // which is assumed to be complete at this point.
46   uint8 aud[] = { 0x00, 0x00, 0x01, 0x09 };
47   es_queue_->Push(aud, sizeof(aud));
48   ParseFromEsQueue();
49 
50   es_adapter_.Flush();
51 }
52 
ResetInternal()53 void EsParserH264::ResetInternal() {
54   DVLOG(1) << __FUNCTION__;
55   h264_parser_.reset(new H264Parser());
56   current_access_unit_pos_ = 0;
57   next_access_unit_pos_ = 0;
58   last_video_decoder_config_ = VideoDecoderConfig();
59   es_adapter_.Reset();
60 }
61 
FindAUD(int64 * stream_pos)62 bool EsParserH264::FindAUD(int64* stream_pos) {
63   while (true) {
64     const uint8* es;
65     int size;
66     es_queue_->PeekAt(*stream_pos, &es, &size);
67 
68     // Find a start code and move the stream to the start code parser position.
69     off_t start_code_offset;
70     off_t start_code_size;
71     bool start_code_found = H264Parser::FindStartCode(
72         es, size, &start_code_offset, &start_code_size);
73     *stream_pos += start_code_offset;
74 
75     // No H264 start code found or NALU type not available yet.
76     if (!start_code_found || start_code_offset + start_code_size >= size)
77       return false;
78 
79     // Exit the parser loop when an AUD is found.
80     // Note: NALU header for an AUD:
81     // - nal_ref_idc must be 0
82     // - nal_unit_type must be H264NALU::kAUD
83     if (es[start_code_offset + start_code_size] == H264NALU::kAUD)
84       break;
85 
86     // The current NALU is not an AUD, skip the start code
87     // and continue parsing the stream.
88     *stream_pos += start_code_size;
89   }
90 
91   return true;
92 }
93 
ParseFromEsQueue()94 bool EsParserH264::ParseFromEsQueue() {
95   DCHECK_LE(es_queue_->head(), current_access_unit_pos_);
96   DCHECK_LE(current_access_unit_pos_, next_access_unit_pos_);
97   DCHECK_LE(next_access_unit_pos_, es_queue_->tail());
98 
99   // Find the next AUD located at or after |current_access_unit_pos_|. This is
100   // needed since initially |current_access_unit_pos_| might not point to
101   // an AUD.
102   // Discard all the data before the updated |current_access_unit_pos_|
103   // since it won't be used again.
104   bool aud_found = FindAUD(&current_access_unit_pos_);
105   es_queue_->Trim(current_access_unit_pos_);
106   if (next_access_unit_pos_ < current_access_unit_pos_)
107     next_access_unit_pos_ = current_access_unit_pos_;
108 
109   // Resume parsing later if no AUD was found.
110   if (!aud_found)
111     return true;
112 
113   // Find the next AUD to make sure we have a complete access unit.
114   if (next_access_unit_pos_ < current_access_unit_pos_ + kMinAUDSize) {
115     next_access_unit_pos_ = current_access_unit_pos_ + kMinAUDSize;
116     DCHECK_LE(next_access_unit_pos_, es_queue_->tail());
117   }
118   if (!FindAUD(&next_access_unit_pos_))
119     return true;
120 
121   // At this point, we know we have a full access unit.
122   bool is_key_frame = false;
123   int pps_id_for_access_unit = -1;
124 
125   const uint8* es;
126   int size;
127   es_queue_->PeekAt(current_access_unit_pos_, &es, &size);
128   int access_unit_size = base::checked_cast<int, int64>(
129       next_access_unit_pos_ - current_access_unit_pos_);
130   DCHECK_LE(access_unit_size, size);
131   h264_parser_->SetStream(es, access_unit_size);
132 
133   while (true) {
134     bool is_eos = false;
135     H264NALU nalu;
136     switch (h264_parser_->AdvanceToNextNALU(&nalu)) {
137       case H264Parser::kOk:
138         break;
139       case H264Parser::kInvalidStream:
140       case H264Parser::kUnsupportedStream:
141         return false;
142       case H264Parser::kEOStream:
143         is_eos = true;
144         break;
145     }
146     if (is_eos)
147       break;
148 
149     switch (nalu.nal_unit_type) {
150       case H264NALU::kAUD: {
151         DVLOG(LOG_LEVEL_ES) << "NALU: AUD";
152         break;
153       }
154       case H264NALU::kSPS: {
155         DVLOG(LOG_LEVEL_ES) << "NALU: SPS";
156         int sps_id;
157         if (h264_parser_->ParseSPS(&sps_id) != H264Parser::kOk)
158           return false;
159         break;
160       }
161       case H264NALU::kPPS: {
162         DVLOG(LOG_LEVEL_ES) << "NALU: PPS";
163         int pps_id;
164         if (h264_parser_->ParsePPS(&pps_id) != H264Parser::kOk)
165           return false;
166         break;
167       }
168       case H264NALU::kIDRSlice:
169       case H264NALU::kNonIDRSlice: {
170         is_key_frame = (nalu.nal_unit_type == H264NALU::kIDRSlice);
171         DVLOG(LOG_LEVEL_ES) << "NALU: slice IDR=" << is_key_frame;
172         H264SliceHeader shdr;
173         if (h264_parser_->ParseSliceHeader(nalu, &shdr) != H264Parser::kOk) {
174           // Only accept an invalid SPS/PPS at the beginning when the stream
175           // does not necessarily start with an SPS/PPS/IDR.
176           // TODO(damienv): Should be able to differentiate a missing SPS/PPS
177           // from a slice header parsing error.
178           if (last_video_decoder_config_.IsValidConfig())
179             return false;
180         } else {
181           pps_id_for_access_unit = shdr.pic_parameter_set_id;
182         }
183         break;
184       }
185       default: {
186         DVLOG(LOG_LEVEL_ES) << "NALU: " << nalu.nal_unit_type;
187       }
188     }
189   }
190 
191   // Emit a frame and move the stream to the next AUD position.
192   RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size,
193                    is_key_frame, pps_id_for_access_unit));
194   current_access_unit_pos_ = next_access_unit_pos_;
195   es_queue_->Trim(current_access_unit_pos_);
196 
197   return true;
198 }
199 
EmitFrame(int64 access_unit_pos,int access_unit_size,bool is_key_frame,int pps_id)200 bool EsParserH264::EmitFrame(int64 access_unit_pos, int access_unit_size,
201                              bool is_key_frame, int pps_id) {
202   // Get the access unit timing info.
203   TimingDesc current_timing_desc = GetTimingDescriptor(access_unit_pos);
204   if (current_timing_desc.pts == kNoTimestamp())
205     return false;
206 
207   if (current_timing_desc.dts == kNoDecodeTimestamp()) {
208     current_timing_desc.dts =
209         DecodeTimestamp::FromPresentationTime(current_timing_desc.pts);
210   }
211 
212   // Update the video decoder configuration if needed.
213   const H264PPS* pps = h264_parser_->GetPPS(pps_id);
214   if (!pps) {
215     // Only accept an invalid PPS at the beginning when the stream
216     // does not necessarily start with an SPS/PPS/IDR.
217     // In this case, the initial frames are conveyed to the upper layer with
218     // an invalid VideoDecoderConfig and it's up to the upper layer
219     // to process this kind of frame accordingly.
220     if (last_video_decoder_config_.IsValidConfig())
221       return false;
222   } else {
223     const H264SPS* sps = h264_parser_->GetSPS(pps->seq_parameter_set_id);
224     if (!sps)
225       return false;
226     RCHECK(UpdateVideoDecoderConfig(sps));
227   }
228 
229   // Emit a frame.
230   DVLOG(LOG_LEVEL_ES) << "Emit frame: stream_pos=" << current_access_unit_pos_
231                       << " size=" << access_unit_size;
232   int es_size;
233   const uint8* es;
234   es_queue_->PeekAt(current_access_unit_pos_, &es, &es_size);
235   CHECK_GE(es_size, access_unit_size);
236 
237   // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
238   // type and allow multiple video tracks. See https://crbug.com/341581.
239   scoped_refptr<StreamParserBuffer> stream_parser_buffer =
240       StreamParserBuffer::CopyFrom(
241           es,
242           access_unit_size,
243           is_key_frame,
244           DemuxerStream::VIDEO,
245           0);
246   stream_parser_buffer->SetDecodeTimestamp(current_timing_desc.dts);
247   stream_parser_buffer->set_timestamp(current_timing_desc.pts);
248   es_adapter_.OnNewBuffer(stream_parser_buffer);
249   return true;
250 }
251 
UpdateVideoDecoderConfig(const H264SPS * sps)252 bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps) {
253   // Set the SAR to 1 when not specified in the H264 stream.
254   int sar_width = (sps->sar_width == 0) ? 1 : sps->sar_width;
255   int sar_height = (sps->sar_height == 0) ? 1 : sps->sar_height;
256 
257   // TODO(damienv): a MAP unit can be either 16 or 32 pixels.
258   // although it's 16 pixels for progressive non MBAFF frames.
259   gfx::Size coded_size((sps->pic_width_in_mbs_minus1 + 1) * 16,
260                        (sps->pic_height_in_map_units_minus1 + 1) * 16);
261   gfx::Rect visible_rect(
262       sps->frame_crop_left_offset,
263       sps->frame_crop_top_offset,
264       (coded_size.width() - sps->frame_crop_right_offset) -
265       sps->frame_crop_left_offset,
266       (coded_size.height() - sps->frame_crop_bottom_offset) -
267       sps->frame_crop_top_offset);
268   if (visible_rect.width() <= 0 || visible_rect.height() <= 0)
269     return false;
270   gfx::Size natural_size(
271       (visible_rect.width() * sar_width) / sar_height,
272       visible_rect.height());
273   if (natural_size.width() == 0)
274     return false;
275 
276   VideoDecoderConfig video_decoder_config(
277       kCodecH264,
278       VIDEO_CODEC_PROFILE_UNKNOWN,
279       VideoFrame::YV12,
280       coded_size,
281       visible_rect,
282       natural_size,
283       NULL, 0,
284       false);
285 
286   if (!video_decoder_config.Matches(last_video_decoder_config_)) {
287     DVLOG(1) << "Profile IDC: " << sps->profile_idc;
288     DVLOG(1) << "Level IDC: " << sps->level_idc;
289     DVLOG(1) << "Pic width: " << coded_size.width();
290     DVLOG(1) << "Pic height: " << coded_size.height();
291     DVLOG(1) << "log2_max_frame_num_minus4: "
292              << sps->log2_max_frame_num_minus4;
293     DVLOG(1) << "SAR: width=" << sps->sar_width
294              << " height=" << sps->sar_height;
295     last_video_decoder_config_ = video_decoder_config;
296     es_adapter_.OnConfigChanged(video_decoder_config);
297   }
298 
299   return true;
300 }
301 
302 }  // namespace mp2t
303 }  // namespace media
304