Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / media / formats / webm / webm_stream_parser.cc
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
21 WebMStreamParser::WebMStreamParser()
22     : state_(kWaitingForInit),
23       unknown_segment_size_(false),
24       parsing_cluster_(false) {
25 }
26
27 WebMStreamParser::~WebMStreamParser() {
28 }
29
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());
46
47   ChangeState(kParsingHeaders);
48   init_cb_ = init_cb;
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;
55   log_cb_ = log_cb;
56 }
57
58 void WebMStreamParser::Flush() {
59   DCHECK_NE(state_, kWaitingForInit);
60
61   byte_queue_.Reset();
62   parsing_cluster_ = false;
63
64   if (state_ != kParsingClusters)
65     return;
66
67   cluster_parser_->Reset();
68 }
69
70 bool WebMStreamParser::Parse(const uint8* buf, int size) {
71   DCHECK_NE(state_, kWaitingForInit);
72
73   if (state_ == kError)
74     return false;
75
76   byte_queue_.Push(buf, size);
77
78   int result = 0;
79   int bytes_parsed = 0;
80   const uint8* cur = NULL;
81   int cur_size = 0;
82
83   byte_queue_.Peek(&cur, &cur_size);
84   while (cur_size > 0) {
85     State oldState = state_;
86     switch (state_) {
87       case kParsingHeaders:
88         result = ParseInfoAndTracks(cur, cur_size);
89         break;
90
91       case kParsingClusters:
92         result = ParseCluster(cur, cur_size);
93         break;
94
95       case kWaitingForInit:
96       case kError:
97         return false;
98     }
99
100     if (result < 0) {
101       ChangeState(kError);
102       return false;
103     }
104
105     if (state_ == oldState && result == 0)
106       break;
107
108     DCHECK_GE(result, 0);
109     cur += result;
110     cur_size -= result;
111     bytes_parsed += result;
112   }
113
114   byte_queue_.Pop(bytes_parsed);
115   return true;
116 }
117
118 void WebMStreamParser::ChangeState(State new_state) {
119   DVLOG(1) << "ChangeState() : " << state_ << " -> " << new_state;
120   state_ = new_state;
121 }
122
123 int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
124   DVLOG(2) << "ParseInfoAndTracks()";
125   DCHECK(data);
126   DCHECK_GT(size, 0);
127
128   const uint8* cur = data;
129   int cur_size = size;
130   int bytes_parsed = 0;
131
132   int id;
133   int64 element_size;
134   int result = WebMParseElementHeader(cur, cur_size, &id, &element_size);
135
136   if (result <= 0)
137     return result;
138
139   switch (id) {
140     case kWebMIdEBMLHeader:
141     case kWebMIdSeekHead:
142     case kWebMIdVoid:
143     case kWebMIdCRC32:
144     case kWebMIdCues:
145     case kWebMIdChapters:
146       if (cur_size < (result + element_size)) {
147         // We don't have the whole element yet. Signal we need more data.
148         return 0;
149       }
150       // Skip the element.
151       return result + element_size;
152       break;
153     case kWebMIdSegment:
154       // Segment of unknown size indicates live stream.
155       if (element_size == kWebMUnknownSize)
156         unknown_segment_size_ = true;
157       // Just consume the segment header.
158       return result;
159       break;
160     case kWebMIdInfo:
161       // We've found the element we are looking for.
162       break;
163     default: {
164       MEDIA_LOG(log_cb_) << "Unexpected element ID 0x" << std::hex << id;
165       return -1;
166     }
167   }
168
169   WebMInfoParser info_parser;
170   result = info_parser.Parse(cur, cur_size);
171
172   if (result <= 0)
173     return result;
174
175   cur += result;
176   cur_size -= result;
177   bytes_parsed += result;
178
179   WebMTracksParser tracks_parser(log_cb_, ignore_text_tracks_);
180   result = tracks_parser.Parse(cur, cur_size);
181
182   if (result <= 0)
183     return result;
184
185   bytes_parsed += result;
186
187   double timecode_scale_in_us = info_parser.timecode_scale() / 1000.0;
188   InitParameters params(kInfiniteDuration());
189
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);
193   }
194
195   params.timeline_offset = info_parser.date_utc();
196
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;
202   } else {
203     params.liveness = Demuxer::LIVENESS_UNKNOWN;
204   }
205
206   const AudioDecoderConfig& audio_config = tracks_parser.audio_decoder_config();
207   if (audio_config.is_encrypted())
208     FireNeedKey(tracks_parser.audio_encryption_key_id());
209
210   const VideoDecoderConfig& video_config = tracks_parser.video_decoder_config();
211   if (video_config.is_encrypted())
212     FireNeedKey(tracks_parser.video_encryption_key_id());
213
214   if (!config_cb_.Run(audio_config,
215                       video_config,
216                       tracks_parser.text_tracks())) {
217     DVLOG(1) << "New config data isn't allowed.";
218     return -1;
219   }
220
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(),
231       log_cb_));
232
233   ChangeState(kParsingClusters);
234
235   if (!init_cb_.is_null())
236     base::ResetAndReturn(&init_cb_).Run(true, params);
237
238   return bytes_parsed;
239 }
240
241 int WebMStreamParser::ParseCluster(const uint8* data, int size) {
242   if (!cluster_parser_)
243     return -1;
244
245   int id;
246   int64 element_size;
247   int result = WebMParseElementHeader(data, size, &id, &element_size);
248
249   if (result <= 0)
250     return result;
251
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.
258       return 0;
259     }
260     // Skip the element.
261     return result + element_size;
262   }
263
264   if (id == kWebMIdEBMLHeader) {
265     // TODO(wolenetz): Handle unknown-sized cluster parse completion correctly.
266     // See http://crbug.com/335676.
267     ChangeState(kParsingHeaders);
268     return 0;
269   }
270
271   int bytes_parsed = cluster_parser_->Parse(data, size);
272
273   if (bytes_parsed <= 0)
274     return bytes_parsed;
275
276   // If cluster detected, immediately notify new segment if we have not already
277   // done this.
278   if (id == kWebMIdCluster && !parsing_cluster_) {
279     parsing_cluster_ = true;
280     new_segment_cb_.Run();
281   }
282
283   const BufferQueue& audio_buffers = cluster_parser_->GetAudioBuffers();
284   const BufferQueue& video_buffers = cluster_parser_->GetVideoBuffers();
285   const TextBufferQueueMap& text_map = cluster_parser_->GetTextBuffers();
286
287   bool cluster_ended = cluster_parser_->cluster_ended();
288
289   if ((!audio_buffers.empty() || !video_buffers.empty() || !text_map.empty()) &&
290       !new_buffers_cb_.Run(audio_buffers, video_buffers, text_map)) {
291     return -1;
292   }
293
294   if (cluster_ended) {
295     parsing_cluster_ = false;
296     end_of_segment_cb_.Run();
297   }
298
299   return bytes_parsed;
300 }
301
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);
305 }
306
307 }  // namespace media