1 // Copyright (c) 2012 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/webm/webm_stream_parser.h" 6 7 #include <string> 8 9 #include "base/callback.h" 10 #include "base/logging.h" 11 #include "media/webm/webm_cluster_parser.h" 12 #include "media/webm/webm_constants.h" 13 #include "media/webm/webm_content_encodings.h" 14 #include "media/webm/webm_crypto_helpers.h" 15 #include "media/webm/webm_info_parser.h" 16 #include "media/webm/webm_tracks_parser.h" 17 18 namespace media { 19 20 WebMStreamParser::WebMStreamParser() 21 : state_(kWaitingForInit), 22 waiting_for_buffers_(false) { 23 } 24 25 WebMStreamParser::~WebMStreamParser() { 26 } 27 28 void WebMStreamParser::Init(const InitCB& init_cb, 29 const NewConfigCB& config_cb, 30 const NewBuffersCB& new_buffers_cb, 31 const NewTextBuffersCB& text_cb, 32 const NeedKeyCB& need_key_cb, 33 const NewMediaSegmentCB& new_segment_cb, 34 const base::Closure& end_of_segment_cb, 35 const LogCB& log_cb) { 36 DCHECK_EQ(state_, kWaitingForInit); 37 DCHECK(init_cb_.is_null()); 38 DCHECK(!init_cb.is_null()); 39 DCHECK(!config_cb.is_null()); 40 DCHECK(!new_buffers_cb.is_null()); 41 DCHECK(!need_key_cb.is_null()); 42 DCHECK(!new_segment_cb.is_null()); 43 DCHECK(!end_of_segment_cb.is_null()); 44 45 ChangeState(kParsingHeaders); 46 init_cb_ = init_cb; 47 config_cb_ = config_cb; 48 new_buffers_cb_ = new_buffers_cb; 49 text_cb_ = text_cb; 50 need_key_cb_ = need_key_cb; 51 new_segment_cb_ = new_segment_cb; 52 end_of_segment_cb_ = end_of_segment_cb; 53 log_cb_ = log_cb; 54 } 55 56 void WebMStreamParser::Flush() { 57 DCHECK_NE(state_, kWaitingForInit); 58 59 byte_queue_.Reset(); 60 61 if (state_ != kParsingClusters) 62 return; 63 64 cluster_parser_->Reset(); 65 } 66 67 bool WebMStreamParser::Parse(const uint8* buf, int size) { 68 DCHECK_NE(state_, kWaitingForInit); 69 70 if (state_ == kError) 71 return false; 72 73 byte_queue_.Push(buf, size); 74 75 int result = 0; 76 int bytes_parsed = 0; 77 const uint8* cur = NULL; 78 int cur_size = 0; 79 80 byte_queue_.Peek(&cur, &cur_size); 81 while (cur_size > 0) { 82 State oldState = state_; 83 switch (state_) { 84 case kParsingHeaders: 85 result = ParseInfoAndTracks(cur, cur_size); 86 break; 87 88 case kParsingClusters: 89 result = ParseCluster(cur, cur_size); 90 break; 91 92 case kWaitingForInit: 93 case kError: 94 return false; 95 } 96 97 if (result < 0) { 98 ChangeState(kError); 99 return false; 100 } 101 102 if (state_ == oldState && result == 0) 103 break; 104 105 DCHECK_GE(result, 0); 106 cur += result; 107 cur_size -= result; 108 bytes_parsed += result; 109 } 110 111 byte_queue_.Pop(bytes_parsed); 112 return true; 113 } 114 115 void WebMStreamParser::ChangeState(State new_state) { 116 DVLOG(1) << "ChangeState() : " << state_ << " -> " << new_state; 117 state_ = new_state; 118 } 119 120 int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) { 121 DVLOG(2) << "ParseInfoAndTracks()"; 122 DCHECK(data); 123 DCHECK_GT(size, 0); 124 125 const uint8* cur = data; 126 int cur_size = size; 127 int bytes_parsed = 0; 128 129 int id; 130 int64 element_size; 131 int result = WebMParseElementHeader(cur, cur_size, &id, &element_size); 132 133 if (result <= 0) 134 return result; 135 136 switch (id) { 137 case kWebMIdEBMLHeader: 138 case kWebMIdSeekHead: 139 case kWebMIdVoid: 140 case kWebMIdCRC32: 141 case kWebMIdCues: 142 case kWebMIdChapters: 143 if (cur_size < (result + element_size)) { 144 // We don't have the whole element yet. Signal we need more data. 145 return 0; 146 } 147 // Skip the element. 148 return result + element_size; 149 break; 150 case kWebMIdSegment: 151 // Just consume the segment header. 152 return result; 153 break; 154 case kWebMIdInfo: 155 // We've found the element we are looking for. 156 break; 157 default: { 158 MEDIA_LOG(log_cb_) << "Unexpected element ID 0x" << std::hex << id; 159 return -1; 160 } 161 } 162 163 WebMInfoParser info_parser; 164 result = info_parser.Parse(cur, cur_size); 165 166 if (result <= 0) 167 return result; 168 169 cur += result; 170 cur_size -= result; 171 bytes_parsed += result; 172 173 WebMTracksParser tracks_parser(log_cb_, text_cb_.is_null()); 174 result = tracks_parser.Parse(cur, cur_size); 175 176 if (result <= 0) 177 return result; 178 179 bytes_parsed += result; 180 181 base::TimeDelta duration = kInfiniteDuration(); 182 183 if (info_parser.duration() > 0) { 184 double mult = info_parser.timecode_scale() / 1000.0; 185 int64 duration_in_us = info_parser.duration() * mult; 186 duration = base::TimeDelta::FromMicroseconds(duration_in_us); 187 } 188 189 const AudioDecoderConfig& audio_config = tracks_parser.audio_decoder_config(); 190 if (audio_config.is_encrypted()) 191 FireNeedKey(tracks_parser.audio_encryption_key_id()); 192 193 const VideoDecoderConfig& video_config = tracks_parser.video_decoder_config(); 194 if (video_config.is_encrypted()) 195 FireNeedKey(tracks_parser.video_encryption_key_id()); 196 197 if (!config_cb_.Run(audio_config, 198 video_config, 199 tracks_parser.text_tracks())) { 200 DVLOG(1) << "New config data isn't allowed."; 201 return -1; 202 } 203 204 cluster_parser_.reset(new WebMClusterParser( 205 info_parser.timecode_scale(), 206 tracks_parser.audio_track_num(), 207 tracks_parser.video_track_num(), 208 tracks_parser.text_tracks(), 209 tracks_parser.ignored_tracks(), 210 tracks_parser.audio_encryption_key_id(), 211 tracks_parser.video_encryption_key_id(), 212 log_cb_)); 213 214 ChangeState(kParsingClusters); 215 216 if (!init_cb_.is_null()) { 217 init_cb_.Run(true, duration); 218 init_cb_.Reset(); 219 } 220 221 return bytes_parsed; 222 } 223 224 int WebMStreamParser::ParseCluster(const uint8* data, int size) { 225 if (!cluster_parser_) 226 return -1; 227 228 int id; 229 int64 element_size; 230 int result = WebMParseElementHeader(data, size, &id, &element_size); 231 232 if (result <= 0) 233 return result; 234 235 if (id == kWebMIdCluster) 236 waiting_for_buffers_ = true; 237 238 // TODO(matthewjheaney): implement support for chapters 239 if (id == kWebMIdCues || id == kWebMIdChapters) { 240 if (size < (result + element_size)) { 241 // We don't have the whole element yet. Signal we need more data. 242 return 0; 243 } 244 // Skip the element. 245 return result + element_size; 246 } 247 248 if (id == kWebMIdEBMLHeader) { 249 ChangeState(kParsingHeaders); 250 return 0; 251 } 252 253 int bytes_parsed = cluster_parser_->Parse(data, size); 254 255 if (bytes_parsed <= 0) 256 return bytes_parsed; 257 258 const BufferQueue& audio_buffers = cluster_parser_->audio_buffers(); 259 const BufferQueue& video_buffers = cluster_parser_->video_buffers(); 260 bool cluster_ended = cluster_parser_->cluster_ended(); 261 262 if (waiting_for_buffers_ && 263 cluster_parser_->cluster_start_time() != kNoTimestamp()) { 264 new_segment_cb_.Run(); 265 waiting_for_buffers_ = false; 266 } 267 268 if ((!audio_buffers.empty() || !video_buffers.empty()) && 269 !new_buffers_cb_.Run(audio_buffers, video_buffers)) { 270 return -1; 271 } 272 273 WebMClusterParser::TextTrackIterator text_track_iter = 274 cluster_parser_->CreateTextTrackIterator(); 275 276 int text_track_num; 277 const BufferQueue* text_buffers; 278 279 while (text_track_iter(&text_track_num, &text_buffers)) { 280 if (!text_buffers->empty() && !text_cb_.Run(text_track_num, *text_buffers)) 281 return -1; 282 } 283 284 if (cluster_ended) 285 end_of_segment_cb_.Run(); 286 287 return bytes_parsed; 288 } 289 290 void WebMStreamParser::FireNeedKey(const std::string& key_id) { 291 std::vector<uint8> key_id_vector(key_id.begin(), key_id.end()); 292 need_key_cb_.Run(kWebMEncryptInitDataType, key_id_vector); 293 } 294 295 } // namespace media 296