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/formats/webm/webm_cluster_parser.h"
13 #include "media/formats/webm/webm_constants.h"
14 #include "media/formats/webm/webm_content_encodings.h"
15 #include "media/formats/webm/webm_info_parser.h"
16 #include "media/formats/webm/webm_tracks_parser.h"
20 WebMStreamParser::WebMStreamParser()
21 : state_(kWaitingForInit
),
22 unknown_segment_size_(false) {
25 WebMStreamParser::~WebMStreamParser() {
28 void WebMStreamParser::Init(
29 const InitCB
& init_cb
,
30 const NewConfigCB
& config_cb
,
31 const NewBuffersCB
& new_buffers_cb
,
32 bool ignore_text_tracks
,
33 const EncryptedMediaInitDataCB
& encrypted_media_init_data_cb
,
34 const NewMediaSegmentCB
& new_segment_cb
,
35 const base::Closure
& end_of_segment_cb
,
36 const LogCB
& log_cb
) {
37 DCHECK_EQ(state_
, kWaitingForInit
);
38 DCHECK(init_cb_
.is_null());
39 DCHECK(!init_cb
.is_null());
40 DCHECK(!config_cb
.is_null());
41 DCHECK(!new_buffers_cb
.is_null());
42 DCHECK(!encrypted_media_init_data_cb
.is_null());
43 DCHECK(!new_segment_cb
.is_null());
44 DCHECK(!end_of_segment_cb
.is_null());
46 ChangeState(kParsingHeaders
);
48 config_cb_
= config_cb
;
49 new_buffers_cb_
= new_buffers_cb
;
50 ignore_text_tracks_
= ignore_text_tracks
;
51 encrypted_media_init_data_cb_
= encrypted_media_init_data_cb
;
52 new_segment_cb_
= new_segment_cb
;
53 end_of_segment_cb_
= end_of_segment_cb
;
57 void WebMStreamParser::Flush() {
58 DCHECK_NE(state_
, kWaitingForInit
);
62 cluster_parser_
->Reset();
63 if (state_
== kParsingClusters
) {
64 ChangeState(kParsingHeaders
);
65 end_of_segment_cb_
.Run();
69 bool WebMStreamParser::Parse(const uint8
* buf
, int size
) {
70 DCHECK_NE(state_
, kWaitingForInit
);
75 byte_queue_
.Push(buf
, size
);
79 const uint8
* cur
= NULL
;
82 byte_queue_
.Peek(&cur
, &cur_size
);
83 while (cur_size
> 0) {
84 State oldState
= state_
;
87 result
= ParseInfoAndTracks(cur
, cur_size
);
90 case kParsingClusters
:
91 result
= ParseCluster(cur
, cur_size
);
104 if (state_
== oldState
&& result
== 0)
107 DCHECK_GE(result
, 0);
110 bytes_parsed
+= result
;
113 byte_queue_
.Pop(bytes_parsed
);
117 void WebMStreamParser::ChangeState(State new_state
) {
118 DVLOG(1) << "ChangeState() : " << state_
<< " -> " << new_state
;
122 int WebMStreamParser::ParseInfoAndTracks(const uint8
* data
, int size
) {
123 DVLOG(2) << "ParseInfoAndTracks()";
127 const uint8
* cur
= data
;
129 int bytes_parsed
= 0;
133 int result
= WebMParseElementHeader(cur
, cur_size
, &id
, &element_size
);
139 case kWebMIdEBMLHeader
:
140 case kWebMIdSeekHead
:
144 case kWebMIdChapters
:
146 case kWebMIdAttachments
:
147 // TODO(matthewjheaney): Implement support for chapters.
148 if (cur_size
< (result
+ element_size
)) {
149 // We don't have the whole element yet. Signal we need more data.
153 return result
+ element_size
;
156 if (!cluster_parser_
) {
157 MEDIA_LOG(ERROR
, log_cb_
) << "Found Cluster element before Info.";
160 ChangeState(kParsingClusters
);
161 new_segment_cb_
.Run();
165 // Segment of unknown size indicates live stream.
166 if (element_size
== kWebMUnknownSize
)
167 unknown_segment_size_
= true;
168 // Just consume the segment header.
172 // We've found the element we are looking for.
175 MEDIA_LOG(ERROR
, log_cb_
) << "Unexpected element ID 0x" << std::hex
<< id
;
180 WebMInfoParser info_parser
;
181 result
= info_parser
.Parse(cur
, cur_size
);
188 bytes_parsed
+= result
;
190 WebMTracksParser
tracks_parser(log_cb_
, ignore_text_tracks_
);
191 result
= tracks_parser
.Parse(cur
, cur_size
);
196 bytes_parsed
+= result
;
198 double timecode_scale_in_us
= info_parser
.timecode_scale() / 1000.0;
199 InitParameters
params(kInfiniteDuration());
201 if (info_parser
.duration() > 0) {
202 int64 duration_in_us
= info_parser
.duration() * timecode_scale_in_us
;
203 params
.duration
= base::TimeDelta::FromMicroseconds(duration_in_us
);
206 params
.timeline_offset
= info_parser
.date_utc();
208 if (unknown_segment_size_
&& (info_parser
.duration() <= 0) &&
209 !info_parser
.date_utc().is_null()) {
210 params
.liveness
= DemuxerStream::LIVENESS_LIVE
;
211 } else if (info_parser
.duration() >= 0) {
212 params
.liveness
= DemuxerStream::LIVENESS_RECORDED
;
214 params
.liveness
= DemuxerStream::LIVENESS_UNKNOWN
;
217 const AudioDecoderConfig
& audio_config
= tracks_parser
.audio_decoder_config();
218 if (audio_config
.is_encrypted())
219 OnEncryptedMediaInitData(tracks_parser
.audio_encryption_key_id());
221 const VideoDecoderConfig
& video_config
= tracks_parser
.video_decoder_config();
222 if (video_config
.is_encrypted())
223 OnEncryptedMediaInitData(tracks_parser
.video_encryption_key_id());
225 if (!config_cb_
.Run(audio_config
,
227 tracks_parser
.text_tracks())) {
228 DVLOG(1) << "New config data isn't allowed.";
232 cluster_parser_
.reset(new WebMClusterParser(
233 info_parser
.timecode_scale(),
234 tracks_parser
.audio_track_num(),
235 tracks_parser
.GetAudioDefaultDuration(timecode_scale_in_us
),
236 tracks_parser
.video_track_num(),
237 tracks_parser
.GetVideoDefaultDuration(timecode_scale_in_us
),
238 tracks_parser
.text_tracks(),
239 tracks_parser
.ignored_tracks(),
240 tracks_parser
.audio_encryption_key_id(),
241 tracks_parser
.video_encryption_key_id(),
242 audio_config
.codec(),
245 if (!init_cb_
.is_null())
246 base::ResetAndReturn(&init_cb_
).Run(params
);
251 int WebMStreamParser::ParseCluster(const uint8
* data
, int size
) {
252 if (!cluster_parser_
)
255 int bytes_parsed
= cluster_parser_
->Parse(data
, size
);
256 if (bytes_parsed
< 0)
259 const BufferQueue
& audio_buffers
= cluster_parser_
->GetAudioBuffers();
260 const BufferQueue
& video_buffers
= cluster_parser_
->GetVideoBuffers();
261 const TextBufferQueueMap
& text_map
= cluster_parser_
->GetTextBuffers();
263 bool cluster_ended
= cluster_parser_
->cluster_ended();
265 if ((!audio_buffers
.empty() || !video_buffers
.empty() ||
266 !text_map
.empty()) &&
267 !new_buffers_cb_
.Run(audio_buffers
, video_buffers
, text_map
)) {
272 ChangeState(kParsingHeaders
);
273 end_of_segment_cb_
.Run();
279 void WebMStreamParser::OnEncryptedMediaInitData(const std::string
& key_id
) {
280 std::vector
<uint8
> key_id_vector(key_id
.begin(), key_id
.end());
281 encrypted_media_init_data_cb_
.Run(EmeInitDataType::WEBM
, key_id_vector
);