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 // TODO(matthewjheaney): Implement support for chapters. 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 kWebMIdCluster: 154 if (!cluster_parser_) { 155 MEDIA_LOG(log_cb_) << "Found Cluster element before Info."; 156 return -1; 157 } 158 ChangeState(kParsingClusters); 159 new_segment_cb_.Run(); 160 return 0; 161 break; 162 case kWebMIdSegment: 163 // Segment of unknown size indicates live stream. 164 if (element_size == kWebMUnknownSize) 165 unknown_segment_size_ = true; 166 // Just consume the segment header. 167 return result; 168 break; 169 case kWebMIdInfo: 170 // We've found the element we are looking for. 171 break; 172 default: { 173 MEDIA_LOG(log_cb_) << "Unexpected element ID 0x" << std::hex << id; 174 return -1; 175 } 176 } 177 178 WebMInfoParser info_parser; 179 result = info_parser.Parse(cur, cur_size); 180 181 if (result <= 0) 182 return result; 183 184 cur += result; 185 cur_size -= result; 186 bytes_parsed += result; 187 188 WebMTracksParser tracks_parser(log_cb_, ignore_text_tracks_); 189 result = tracks_parser.Parse(cur, cur_size); 190 191 if (result <= 0) 192 return result; 193 194 bytes_parsed += result; 195 196 double timecode_scale_in_us = info_parser.timecode_scale() / 1000.0; 197 InitParameters params(kInfiniteDuration()); 198 199 if (info_parser.duration() > 0) { 200 int64 duration_in_us = info_parser.duration() * timecode_scale_in_us; 201 params.duration = base::TimeDelta::FromMicroseconds(duration_in_us); 202 } 203 204 params.timeline_offset = info_parser.date_utc(); 205 206 if (unknown_segment_size_ && (info_parser.duration() <= 0) && 207 !info_parser.date_utc().is_null()) { 208 params.liveness = Demuxer::LIVENESS_LIVE; 209 } else if (info_parser.duration() >= 0) { 210 params.liveness = Demuxer::LIVENESS_RECORDED; 211 } else { 212 params.liveness = Demuxer::LIVENESS_UNKNOWN; 213 } 214 215 const AudioDecoderConfig& audio_config = tracks_parser.audio_decoder_config(); 216 if (audio_config.is_encrypted()) 217 FireNeedKey(tracks_parser.audio_encryption_key_id()); 218 219 const VideoDecoderConfig& video_config = tracks_parser.video_decoder_config(); 220 if (video_config.is_encrypted()) 221 FireNeedKey(tracks_parser.video_encryption_key_id()); 222 223 if (!config_cb_.Run(audio_config, 224 video_config, 225 tracks_parser.text_tracks())) { 226 DVLOG(1) << "New config data isn't allowed."; 227 return -1; 228 } 229 230 cluster_parser_.reset(new WebMClusterParser( 231 info_parser.timecode_scale(), 232 tracks_parser.audio_track_num(), 233 tracks_parser.GetAudioDefaultDuration(timecode_scale_in_us), 234 tracks_parser.video_track_num(), 235 tracks_parser.GetVideoDefaultDuration(timecode_scale_in_us), 236 tracks_parser.text_tracks(), 237 tracks_parser.ignored_tracks(), 238 tracks_parser.audio_encryption_key_id(), 239 tracks_parser.video_encryption_key_id(), 240 log_cb_)); 241 242 if (!init_cb_.is_null()) 243 base::ResetAndReturn(&init_cb_).Run(true, params); 244 245 return bytes_parsed; 246 } 247 248 int WebMStreamParser::ParseCluster(const uint8* data, int size) { 249 if (!cluster_parser_) 250 return -1; 251 252 int bytes_parsed = cluster_parser_->Parse(data, size); 253 if (bytes_parsed < 0) 254 return bytes_parsed; 255 256 const BufferQueue& audio_buffers = cluster_parser_->GetAudioBuffers(); 257 const BufferQueue& video_buffers = cluster_parser_->GetVideoBuffers(); 258 const TextBufferQueueMap& text_map = cluster_parser_->GetTextBuffers(); 259 260 bool cluster_ended = cluster_parser_->cluster_ended(); 261 262 if ((!audio_buffers.empty() || !video_buffers.empty() || 263 !text_map.empty()) && 264 !new_buffers_cb_.Run(audio_buffers, video_buffers, text_map)) { 265 return -1; 266 } 267 268 if (cluster_ended) { 269 ChangeState(kParsingHeaders); 270 end_of_segment_cb_.Run(); 271 } 272 273 return bytes_parsed; 274 } 275 276 void WebMStreamParser::FireNeedKey(const std::string& key_id) { 277 std::vector<uint8> key_id_vector(key_id.begin(), key_id.end()); 278 need_key_cb_.Run(kWebMEncryptInitDataType, key_id_vector); 279 } 280 281 } // namespace media 282