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/webm/webm_stream_parser.h"
6
7 #include <string>
8
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"
18
19 namespace media {
20
WebMStreamParser()21 WebMStreamParser::WebMStreamParser()
22 : state_(kWaitingForInit),
23 unknown_segment_size_(false) {
24 }
25
~WebMStreamParser()26 WebMStreamParser::~WebMStreamParser() {
27 }
28
Init(const InitCB & init_cb,const NewConfigCB & config_cb,const NewBuffersCB & new_buffers_cb,bool ignore_text_tracks,const NeedKeyCB & need_key_cb,const NewMediaSegmentCB & new_segment_cb,const base::Closure & end_of_segment_cb,const LogCB & log_cb)29 void WebMStreamParser::Init(const InitCB& init_cb,
30 const NewConfigCB& config_cb,
31 const NewBuffersCB& new_buffers_cb,
32 bool ignore_text_tracks,
33 const NeedKeyCB& need_key_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(!need_key_cb.is_null());
43 DCHECK(!new_segment_cb.is_null());
44 DCHECK(!end_of_segment_cb.is_null());
45
46 ChangeState(kParsingHeaders);
47 init_cb_ = init_cb;
48 config_cb_ = config_cb;
49 new_buffers_cb_ = new_buffers_cb;
50 ignore_text_tracks_ = ignore_text_tracks;
51 need_key_cb_ = need_key_cb;
52 new_segment_cb_ = new_segment_cb;
53 end_of_segment_cb_ = end_of_segment_cb;
54 log_cb_ = log_cb;
55 }
56
Flush()57 void WebMStreamParser::Flush() {
58 DCHECK_NE(state_, kWaitingForInit);
59
60 byte_queue_.Reset();
61 if (cluster_parser_)
62 cluster_parser_->Reset();
63 if (state_ == kParsingClusters) {
64 ChangeState(kParsingHeaders);
65 end_of_segment_cb_.Run();
66 }
67 }
68
Parse(const uint8 * buf,int size)69 bool WebMStreamParser::Parse(const uint8* buf, int size) {
70 DCHECK_NE(state_, kWaitingForInit);
71
72 if (state_ == kError)
73 return false;
74
75 byte_queue_.Push(buf, size);
76
77 int result = 0;
78 int bytes_parsed = 0;
79 const uint8* cur = NULL;
80 int cur_size = 0;
81
82 byte_queue_.Peek(&cur, &cur_size);
83 while (cur_size > 0) {
84 State oldState = state_;
85 switch (state_) {
86 case kParsingHeaders:
87 result = ParseInfoAndTracks(cur, cur_size);
88 break;
89
90 case kParsingClusters:
91 result = ParseCluster(cur, cur_size);
92 break;
93
94 case kWaitingForInit:
95 case kError:
96 return false;
97 }
98
99 if (result < 0) {
100 ChangeState(kError);
101 return false;
102 }
103
104 if (state_ == oldState && result == 0)
105 break;
106
107 DCHECK_GE(result, 0);
108 cur += result;
109 cur_size -= result;
110 bytes_parsed += result;
111 }
112
113 byte_queue_.Pop(bytes_parsed);
114 return true;
115 }
116
ChangeState(State new_state)117 void WebMStreamParser::ChangeState(State new_state) {
118 DVLOG(1) << "ChangeState() : " << state_ << " -> " << new_state;
119 state_ = new_state;
120 }
121
ParseInfoAndTracks(const uint8 * data,int size)122 int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
123 DVLOG(2) << "ParseInfoAndTracks()";
124 DCHECK(data);
125 DCHECK_GT(size, 0);
126
127 const uint8* cur = data;
128 int cur_size = size;
129 int bytes_parsed = 0;
130
131 int id;
132 int64 element_size;
133 int result = WebMParseElementHeader(cur, cur_size, &id, &element_size);
134
135 if (result <= 0)
136 return result;
137
138 switch (id) {
139 case kWebMIdEBMLHeader:
140 case kWebMIdSeekHead:
141 case kWebMIdVoid:
142 case kWebMIdCRC32:
143 case kWebMIdCues:
144 case kWebMIdChapters:
145 case kWebMIdTags:
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.
150 return 0;
151 }
152 // Skip the element.
153 return result + element_size;
154 break;
155 case kWebMIdCluster:
156 if (!cluster_parser_) {
157 MEDIA_LOG(log_cb_) << "Found Cluster element before Info.";
158 return -1;
159 }
160 ChangeState(kParsingClusters);
161 new_segment_cb_.Run();
162 return 0;
163 break;
164 case kWebMIdSegment:
165 // Segment of unknown size indicates live stream.
166 if (element_size == kWebMUnknownSize)
167 unknown_segment_size_ = true;
168 // Just consume the segment header.
169 return result;
170 break;
171 case kWebMIdInfo:
172 // We've found the element we are looking for.
173 break;
174 default: {
175 MEDIA_LOG(log_cb_) << "Unexpected element ID 0x" << std::hex << id;
176 return -1;
177 }
178 }
179
180 WebMInfoParser info_parser;
181 result = info_parser.Parse(cur, cur_size);
182
183 if (result <= 0)
184 return result;
185
186 cur += result;
187 cur_size -= result;
188 bytes_parsed += result;
189
190 WebMTracksParser tracks_parser(log_cb_, ignore_text_tracks_);
191 result = tracks_parser.Parse(cur, cur_size);
192
193 if (result <= 0)
194 return result;
195
196 bytes_parsed += result;
197
198 double timecode_scale_in_us = info_parser.timecode_scale() / 1000.0;
199 InitParameters params(kInfiniteDuration());
200
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);
204 }
205
206 params.timeline_offset = info_parser.date_utc();
207
208 if (unknown_segment_size_ && (info_parser.duration() <= 0) &&
209 !info_parser.date_utc().is_null()) {
210 params.liveness = Demuxer::LIVENESS_LIVE;
211 } else if (info_parser.duration() >= 0) {
212 params.liveness = Demuxer::LIVENESS_RECORDED;
213 } else {
214 params.liveness = Demuxer::LIVENESS_UNKNOWN;
215 }
216
217 const AudioDecoderConfig& audio_config = tracks_parser.audio_decoder_config();
218 if (audio_config.is_encrypted())
219 FireNeedKey(tracks_parser.audio_encryption_key_id());
220
221 const VideoDecoderConfig& video_config = tracks_parser.video_decoder_config();
222 if (video_config.is_encrypted())
223 FireNeedKey(tracks_parser.video_encryption_key_id());
224
225 if (!config_cb_.Run(audio_config,
226 video_config,
227 tracks_parser.text_tracks())) {
228 DVLOG(1) << "New config data isn't allowed.";
229 return -1;
230 }
231
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 log_cb_));
243
244 if (!init_cb_.is_null())
245 base::ResetAndReturn(&init_cb_).Run(true, params);
246
247 return bytes_parsed;
248 }
249
ParseCluster(const uint8 * data,int size)250 int WebMStreamParser::ParseCluster(const uint8* data, int size) {
251 if (!cluster_parser_)
252 return -1;
253
254 int bytes_parsed = cluster_parser_->Parse(data, size);
255 if (bytes_parsed < 0)
256 return bytes_parsed;
257
258 const BufferQueue& audio_buffers = cluster_parser_->GetAudioBuffers();
259 const BufferQueue& video_buffers = cluster_parser_->GetVideoBuffers();
260 const TextBufferQueueMap& text_map = cluster_parser_->GetTextBuffers();
261
262 bool cluster_ended = cluster_parser_->cluster_ended();
263
264 if ((!audio_buffers.empty() || !video_buffers.empty() ||
265 !text_map.empty()) &&
266 !new_buffers_cb_.Run(audio_buffers, video_buffers, text_map)) {
267 return -1;
268 }
269
270 if (cluster_ended) {
271 ChangeState(kParsingHeaders);
272 end_of_segment_cb_.Run();
273 }
274
275 return bytes_parsed;
276 }
277
FireNeedKey(const std::string & key_id)278 void WebMStreamParser::FireNeedKey(const std::string& key_id) {
279 std::vector<uint8> key_id_vector(key_id.begin(), key_id.end());
280 need_key_cb_.Run(kWebMEncryptInitDataType, key_id_vector);
281 }
282
283 } // namespace media
284