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_crypto_helpers.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),
24 parsing_cluster_(false) {
27 WebMStreamParser::~WebMStreamParser() {
30 void WebMStreamParser::Init(const InitCB& init_cb,
31 const NewConfigCB& config_cb,
32 const NewBuffersCB& new_buffers_cb,
33 bool ignore_text_tracks,
34 const NeedKeyCB& need_key_cb,
35 const NewMediaSegmentCB& new_segment_cb,
36 const base::Closure& end_of_segment_cb,
37 const LogCB& log_cb) {
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(!need_key_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 need_key_cb_ = need_key_cb;
53 new_segment_cb_ = new_segment_cb;
54 end_of_segment_cb_ = end_of_segment_cb;
58 void WebMStreamParser::Flush() {
59 DCHECK_NE(state_, kWaitingForInit);
62 parsing_cluster_ = false;
64 if (state_ != kParsingClusters)
67 cluster_parser_->Reset();
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:
146 if (cur_size < (result + element_size)) {
147 // We don't have the whole element yet. Signal we need more data.
151 return result + element_size;
154 // Segment of unknown size indicates live stream.
155 if (element_size == kWebMUnknownSize)
156 unknown_segment_size_ = true;
157 // Just consume the segment header.
161 // We've found the element we are looking for.
164 MEDIA_LOG(log_cb_) << "Unexpected element ID 0x" << std::hex << id;
169 WebMInfoParser info_parser;
170 result = info_parser.Parse(cur, cur_size);
177 bytes_parsed += result;
179 WebMTracksParser tracks_parser(log_cb_, ignore_text_tracks_);
180 result = tracks_parser.Parse(cur, cur_size);
185 bytes_parsed += result;
187 double timecode_scale_in_us = info_parser.timecode_scale() / 1000.0;
188 InitParameters params(kInfiniteDuration());
190 if (info_parser.duration() > 0) {
191 int64 duration_in_us = info_parser.duration() * timecode_scale_in_us;
192 params.duration = base::TimeDelta::FromMicroseconds(duration_in_us);
195 params.timeline_offset = info_parser.date_utc();
197 if (unknown_segment_size_ && (info_parser.duration() <= 0) &&
198 !info_parser.date_utc().is_null()) {
199 params.liveness = Demuxer::LIVENESS_LIVE;
200 } else if (info_parser.duration() >= 0) {
201 params.liveness = Demuxer::LIVENESS_RECORDED;
203 params.liveness = Demuxer::LIVENESS_UNKNOWN;
206 const AudioDecoderConfig& audio_config = tracks_parser.audio_decoder_config();
207 if (audio_config.is_encrypted())
208 FireNeedKey(tracks_parser.audio_encryption_key_id());
210 const VideoDecoderConfig& video_config = tracks_parser.video_decoder_config();
211 if (video_config.is_encrypted())
212 FireNeedKey(tracks_parser.video_encryption_key_id());
214 if (!config_cb_.Run(audio_config,
216 tracks_parser.text_tracks())) {
217 DVLOG(1) << "New config data isn't allowed.";
221 cluster_parser_.reset(new WebMClusterParser(
222 info_parser.timecode_scale(),
223 tracks_parser.audio_track_num(),
224 tracks_parser.GetAudioDefaultDuration(timecode_scale_in_us),
225 tracks_parser.video_track_num(),
226 tracks_parser.GetVideoDefaultDuration(timecode_scale_in_us),
227 tracks_parser.text_tracks(),
228 tracks_parser.ignored_tracks(),
229 tracks_parser.audio_encryption_key_id(),
230 tracks_parser.video_encryption_key_id(),
233 ChangeState(kParsingClusters);
235 if (!init_cb_.is_null())
236 base::ResetAndReturn(&init_cb_).Run(true, params);
241 int WebMStreamParser::ParseCluster(const uint8* data, int size) {
242 if (!cluster_parser_)
247 int result = WebMParseElementHeader(data, size, &id, &element_size);
252 // TODO(matthewjheaney): implement support for chapters
253 if (id == kWebMIdCues || id == kWebMIdChapters) {
254 // TODO(wolenetz): Handle unknown-sized cluster parse completion correctly.
255 // See http://crbug.com/335676.
256 if (size < (result + element_size)) {
257 // We don't have the whole element yet. Signal we need more data.
261 return result + element_size;
264 if (id == kWebMIdEBMLHeader) {
265 // TODO(wolenetz): Handle unknown-sized cluster parse completion correctly.
266 // See http://crbug.com/335676.
267 ChangeState(kParsingHeaders);
271 int bytes_parsed = cluster_parser_->Parse(data, size);
273 if (bytes_parsed <= 0)
276 // If cluster detected, immediately notify new segment if we have not already
278 if (id == kWebMIdCluster && !parsing_cluster_) {
279 parsing_cluster_ = true;
280 new_segment_cb_.Run();
283 const BufferQueue& audio_buffers = cluster_parser_->GetAudioBuffers();
284 const BufferQueue& video_buffers = cluster_parser_->GetVideoBuffers();
285 const TextBufferQueueMap& text_map = cluster_parser_->GetTextBuffers();
287 bool cluster_ended = cluster_parser_->cluster_ended();
289 if ((!audio_buffers.empty() || !video_buffers.empty() || !text_map.empty()) &&
290 !new_buffers_cb_.Run(audio_buffers, video_buffers, text_map)) {
295 parsing_cluster_ = false;
296 end_of_segment_cb_.Run();
302 void WebMStreamParser::FireNeedKey(const std::string& key_id) {
303 std::vector<uint8> key_id_vector(key_id.begin(), key_id.end());
304 need_key_cb_.Run(kWebMEncryptInitDataType, key_id_vector);