Update To 11.40.268.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 }
25
26 WebMStreamParser::~WebMStreamParser() {
27 }
28
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
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
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
117 void WebMStreamParser::ChangeState(State new_state) {
118   DVLOG(1) << "ChangeState() : " << state_ << " -> " << new_state;
119   state_ = new_state;
120 }
121
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
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
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(kWebMInitDataType, key_id_vector);
281 }
282
283 }  // namespace media