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/webm/webm_stream_parser.h"
9 #include "base/callback.h"
10 #include "base/callback_helpers.h"
11 #include "base/logging.h"
12 #include "media/base/timestamp_constants.h"
13 #include "media/formats/webm/webm_cluster_parser.h"
14 #include "media/formats/webm/webm_constants.h"
15 #include "media/formats/webm/webm_content_encodings.h"
16 #include "media/formats/webm/webm_info_parser.h"
17 #include "media/formats/webm/webm_tracks_parser.h"
21 WebMStreamParser::WebMStreamParser()
22 : state_(kWaitingForInit
),
23 unknown_segment_size_(false) {
26 WebMStreamParser::~WebMStreamParser() {
29 void WebMStreamParser::Init(
30 const InitCB
& init_cb
,
31 const NewConfigCB
& config_cb
,
32 const NewBuffersCB
& new_buffers_cb
,
33 bool ignore_text_tracks
,
34 const EncryptedMediaInitDataCB
& encrypted_media_init_data_cb
,
35 const NewMediaSegmentCB
& new_segment_cb
,
36 const base::Closure
& end_of_segment_cb
,
37 const scoped_refptr
<MediaLog
>& media_log
) {
38 DCHECK_EQ(state_
, kWaitingForInit
);
39 DCHECK(init_cb_
.is_null());
40 DCHECK(!init_cb
.is_null());
41 DCHECK(!config_cb
.is_null());
42 DCHECK(!new_buffers_cb
.is_null());
43 DCHECK(!encrypted_media_init_data_cb
.is_null());
44 DCHECK(!new_segment_cb
.is_null());
45 DCHECK(!end_of_segment_cb
.is_null());
47 ChangeState(kParsingHeaders
);
49 config_cb_
= config_cb
;
50 new_buffers_cb_
= new_buffers_cb
;
51 ignore_text_tracks_
= ignore_text_tracks
;
52 encrypted_media_init_data_cb_
= encrypted_media_init_data_cb
;
53 new_segment_cb_
= new_segment_cb
;
54 end_of_segment_cb_
= end_of_segment_cb
;
55 media_log_
= media_log
;
58 void WebMStreamParser::Flush() {
59 DCHECK_NE(state_
, kWaitingForInit
);
63 cluster_parser_
->Reset();
64 if (state_
== kParsingClusters
) {
65 ChangeState(kParsingHeaders
);
66 end_of_segment_cb_
.Run();
70 bool WebMStreamParser::Parse(const uint8
* buf
, int size
) {
71 DCHECK_NE(state_
, kWaitingForInit
);
76 byte_queue_
.Push(buf
, size
);
80 const uint8
* cur
= NULL
;
83 byte_queue_
.Peek(&cur
, &cur_size
);
84 while (cur_size
> 0) {
85 State oldState
= state_
;
88 result
= ParseInfoAndTracks(cur
, cur_size
);
91 case kParsingClusters
:
92 result
= ParseCluster(cur
, cur_size
);
105 if (state_
== oldState
&& result
== 0)
108 DCHECK_GE(result
, 0);
111 bytes_parsed
+= result
;
114 byte_queue_
.Pop(bytes_parsed
);
118 void WebMStreamParser::ChangeState(State new_state
) {
119 DVLOG(1) << "ChangeState() : " << state_
<< " -> " << new_state
;
123 int WebMStreamParser::ParseInfoAndTracks(const uint8
* data
, int size
) {
124 DVLOG(2) << "ParseInfoAndTracks()";
128 const uint8
* cur
= data
;
130 int bytes_parsed
= 0;
134 int result
= WebMParseElementHeader(cur
, cur_size
, &id
, &element_size
);
140 case kWebMIdEBMLHeader
:
141 case kWebMIdSeekHead
:
145 case kWebMIdChapters
:
147 case kWebMIdAttachments
:
148 // TODO(matthewjheaney): Implement support for chapters.
149 if (cur_size
< (result
+ element_size
)) {
150 // We don't have the whole element yet. Signal we need more data.
154 return result
+ element_size
;
157 if (!cluster_parser_
) {
158 MEDIA_LOG(ERROR
, media_log_
) << "Found Cluster element before Info.";
161 ChangeState(kParsingClusters
);
162 new_segment_cb_
.Run();
166 // Segment of unknown size indicates live stream.
167 if (element_size
== kWebMUnknownSize
)
168 unknown_segment_size_
= true;
169 // Just consume the segment header.
173 // We've found the element we are looking for.
176 MEDIA_LOG(ERROR
, media_log_
) << "Unexpected element ID 0x" << std::hex
182 WebMInfoParser info_parser
;
183 result
= info_parser
.Parse(cur
, cur_size
);
190 bytes_parsed
+= result
;
192 WebMTracksParser
tracks_parser(media_log_
, ignore_text_tracks_
);
193 result
= tracks_parser
.Parse(cur
, cur_size
);
198 bytes_parsed
+= result
;
200 double timecode_scale_in_us
= info_parser
.timecode_scale() / 1000.0;
201 InitParameters
params(kInfiniteDuration());
203 if (info_parser
.duration() > 0) {
204 int64 duration_in_us
= info_parser
.duration() * timecode_scale_in_us
;
205 params
.duration
= base::TimeDelta::FromMicroseconds(duration_in_us
);
208 params
.timeline_offset
= info_parser
.date_utc();
210 if (unknown_segment_size_
&& (info_parser
.duration() <= 0) &&
211 !info_parser
.date_utc().is_null()) {
212 params
.liveness
= DemuxerStream::LIVENESS_LIVE
;
213 } else if (info_parser
.duration() >= 0) {
214 params
.liveness
= DemuxerStream::LIVENESS_RECORDED
;
216 params
.liveness
= DemuxerStream::LIVENESS_UNKNOWN
;
219 const AudioDecoderConfig
& audio_config
= tracks_parser
.audio_decoder_config();
220 if (audio_config
.is_encrypted())
221 OnEncryptedMediaInitData(tracks_parser
.audio_encryption_key_id());
223 const VideoDecoderConfig
& video_config
= tracks_parser
.video_decoder_config();
224 if (video_config
.is_encrypted())
225 OnEncryptedMediaInitData(tracks_parser
.video_encryption_key_id());
227 if (!config_cb_
.Run(audio_config
,
229 tracks_parser
.text_tracks())) {
230 DVLOG(1) << "New config data isn't allowed.";
234 cluster_parser_
.reset(new WebMClusterParser(
235 info_parser
.timecode_scale(), tracks_parser
.audio_track_num(),
236 tracks_parser
.GetAudioDefaultDuration(timecode_scale_in_us
),
237 tracks_parser
.video_track_num(),
238 tracks_parser
.GetVideoDefaultDuration(timecode_scale_in_us
),
239 tracks_parser
.text_tracks(), tracks_parser
.ignored_tracks(),
240 tracks_parser
.audio_encryption_key_id(),
241 tracks_parser
.video_encryption_key_id(), audio_config
.codec(),
244 if (!init_cb_
.is_null())
245 base::ResetAndReturn(&init_cb_
).Run(params
);
250 int WebMStreamParser::ParseCluster(const uint8
* data
, int size
) {
251 if (!cluster_parser_
)
254 int bytes_parsed
= cluster_parser_
->Parse(data
, size
);
255 if (bytes_parsed
< 0)
258 const BufferQueue
& audio_buffers
= cluster_parser_
->GetAudioBuffers();
259 const BufferQueue
& video_buffers
= cluster_parser_
->GetVideoBuffers();
260 const TextBufferQueueMap
& text_map
= cluster_parser_
->GetTextBuffers();
262 bool cluster_ended
= cluster_parser_
->cluster_ended();
264 if ((!audio_buffers
.empty() || !video_buffers
.empty() ||
265 !text_map
.empty()) &&
266 !new_buffers_cb_
.Run(audio_buffers
, video_buffers
, text_map
)) {
271 ChangeState(kParsingHeaders
);
272 end_of_segment_cb_
.Run();
278 void WebMStreamParser::OnEncryptedMediaInitData(const std::string
& key_id
) {
279 std::vector
<uint8
> key_id_vector(key_id
.begin(), key_id
.end());
280 encrypted_media_init_data_cb_
.Run(EmeInitDataType::WEBM
, key_id_vector
);