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.
5 #include "media/formats/mp2t/es_parser_h264.h"
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/geometry/rect.h"
18 #include "ui/gfx/geometry/size.h"
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;
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) {
36 EsParserH264::~EsParserH264() {
39 void EsParserH264::Flush() {
40 DVLOG(1) << __FUNCTION__
;
41 if (!FindAUD(¤t_access_unit_pos_
))
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
));
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();
62 bool EsParserH264::FindAUD(int64
* stream_pos
) {
66 es_queue_
->PeekAt(*stream_pos
, &es
, &size
);
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
;
75 // No H264 start code found or NALU type not available yet.
76 if (!start_code_found
|| start_code_offset
+ start_code_size
>= size
)
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
)
86 // The current NALU is not an AUD, skip the start code
87 // and continue parsing the stream.
88 *stream_pos
+= start_code_size
;
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());
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
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(¤t_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_
;
109 // Resume parsing later if no AUD was found.
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());
118 if (!FindAUD(&next_access_unit_pos_
))
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;
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
);
136 switch (h264_parser_
->AdvanceToNextNALU(&nalu
)) {
137 case H264Parser::kOk
:
139 case H264Parser::kInvalidStream
:
140 case H264Parser::kUnsupportedStream
:
142 case H264Parser::kEOStream
:
149 switch (nalu
.nal_unit_type
) {
150 case H264NALU::kAUD
: {
151 DVLOG(LOG_LEVEL_ES
) << "NALU: AUD";
154 case H264NALU::kSPS
: {
155 DVLOG(LOG_LEVEL_ES
) << "NALU: SPS";
157 if (h264_parser_
->ParseSPS(&sps_id
) != H264Parser::kOk
)
161 case H264NALU::kPPS
: {
162 DVLOG(LOG_LEVEL_ES
) << "NALU: PPS";
164 if (h264_parser_
->ParsePPS(&pps_id
) != H264Parser::kOk
)
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())
181 pps_id_for_access_unit
= shdr
.pic_parameter_set_id
;
186 DVLOG(LOG_LEVEL_ES
) << "NALU: " << nalu
.nal_unit_type
;
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_
);
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
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";
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
);
220 // Update the video decoder configuration if needed.
221 const H264PPS
* pps
= h264_parser_
->GetPPS(pps_id
);
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())
231 const H264SPS
* sps
= h264_parser_
->GetSPS(pps
->seq_parameter_set_id
);
234 RCHECK(UpdateVideoDecoderConfig(sps
));
238 DVLOG(LOG_LEVEL_ES
) << "Emit frame: stream_pos=" << current_access_unit_pos_
239 << " size=" << access_unit_size
;
242 es_queue_
->PeekAt(current_access_unit_pos_
, &es
, &es_size
);
243 CHECK_GE(es_size
, access_unit_size
);
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(
252 DemuxerStream::VIDEO
,
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
);
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
;
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)
277 gfx::Size
natural_size(
278 (visible_rect
.width() * sar_width
) / sar_height
,
279 visible_rect
.height());
280 if (natural_size
.width() == 0)
283 VideoDecoderConfig
video_decoder_config(
285 VIDEO_CODEC_PROFILE_UNKNOWN
,
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
);