Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / media / formats / mp2t / es_parser_h264.cc
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
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
36 EsParserH264::~EsParserH264() {
37 }
38
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
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
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
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
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   // Note: |current_timing_desc.pts| might be |kNoTimestamp()| at this point
204   // if:
205   // - the stream is not fully MPEG-2 compliant.
206   // - or if the stream relies on H264 VUI parameters to compute the timestamps.
207   //   See H.222 spec: section 2.7.5 "Conditional coding of timestamps".
208   //   This part is not yet implemented in EsParserH264.
209   // |es_adapter_| will take care of the missing timestamps.
210   TimingDesc current_timing_desc = GetTimingDescriptor(access_unit_pos);
211   DVLOG_IF(1, current_timing_desc.pts == kNoTimestamp())
212       << "Missing timestamp";
213
214   // If only the PTS is provided, copy the PTS into the DTS.
215   if (current_timing_desc.dts == kNoDecodeTimestamp()) {
216     current_timing_desc.dts =
217         DecodeTimestamp::FromPresentationTime(current_timing_desc.pts);
218   }
219
220   // Update the video decoder configuration if needed.
221   const H264PPS* pps = h264_parser_->GetPPS(pps_id);
222   if (!pps) {
223     // Only accept an invalid PPS at the beginning when the stream
224     // does not necessarily start with an SPS/PPS/IDR.
225     // In this case, the initial frames are conveyed to the upper layer with
226     // an invalid VideoDecoderConfig and it's up to the upper layer
227     // to process this kind of frame accordingly.
228     if (last_video_decoder_config_.IsValidConfig())
229       return false;
230   } else {
231     const H264SPS* sps = h264_parser_->GetSPS(pps->seq_parameter_set_id);
232     if (!sps)
233       return false;
234     RCHECK(UpdateVideoDecoderConfig(sps));
235   }
236
237   // Emit a frame.
238   DVLOG(LOG_LEVEL_ES) << "Emit frame: stream_pos=" << current_access_unit_pos_
239                       << " size=" << access_unit_size;
240   int es_size;
241   const uint8* es;
242   es_queue_->PeekAt(current_access_unit_pos_, &es, &es_size);
243   CHECK_GE(es_size, access_unit_size);
244
245   // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
246   // type and allow multiple video tracks. See https://crbug.com/341581.
247   scoped_refptr<StreamParserBuffer> stream_parser_buffer =
248       StreamParserBuffer::CopyFrom(
249           es,
250           access_unit_size,
251           is_key_frame,
252           DemuxerStream::VIDEO,
253           0);
254   stream_parser_buffer->SetDecodeTimestamp(current_timing_desc.dts);
255   stream_parser_buffer->set_timestamp(current_timing_desc.pts);
256   return es_adapter_.OnNewBuffer(stream_parser_buffer);
257 }
258
259 bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps) {
260   // Set the SAR to 1 when not specified in the H264 stream.
261   int sar_width = (sps->sar_width == 0) ? 1 : sps->sar_width;
262   int sar_height = (sps->sar_height == 0) ? 1 : sps->sar_height;
263
264   // TODO(damienv): a MAP unit can be either 16 or 32 pixels.
265   // although it's 16 pixels for progressive non MBAFF frames.
266   gfx::Size coded_size((sps->pic_width_in_mbs_minus1 + 1) * 16,
267                        (sps->pic_height_in_map_units_minus1 + 1) * 16);
268   gfx::Rect visible_rect(
269       sps->frame_crop_left_offset,
270       sps->frame_crop_top_offset,
271       (coded_size.width() - sps->frame_crop_right_offset) -
272       sps->frame_crop_left_offset,
273       (coded_size.height() - sps->frame_crop_bottom_offset) -
274       sps->frame_crop_top_offset);
275   if (visible_rect.width() <= 0 || visible_rect.height() <= 0)
276     return false;
277   gfx::Size natural_size(
278       (visible_rect.width() * sar_width) / sar_height,
279       visible_rect.height());
280   if (natural_size.width() == 0)
281     return false;
282
283   VideoDecoderConfig video_decoder_config(
284       kCodecH264,
285       VIDEO_CODEC_PROFILE_UNKNOWN,
286       VideoFrame::YV12,
287       coded_size,
288       visible_rect,
289       natural_size,
290       NULL, 0,
291       false);
292
293   if (!video_decoder_config.Matches(last_video_decoder_config_)) {
294     DVLOG(1) << "Profile IDC: " << sps->profile_idc;
295     DVLOG(1) << "Level IDC: " << sps->level_idc;
296     DVLOG(1) << "Pic width: " << coded_size.width();
297     DVLOG(1) << "Pic height: " << coded_size.height();
298     DVLOG(1) << "log2_max_frame_num_minus4: "
299              << sps->log2_max_frame_num_minus4;
300     DVLOG(1) << "SAR: width=" << sps->sar_width
301              << " height=" << sps->sar_height;
302     last_video_decoder_config_ = video_decoder_config;
303     es_adapter_.OnConfigChanged(video_decoder_config);
304   }
305
306   return true;
307 }
308
309 }  // namespace mp2t
310 }  // namespace media