diff options
author | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-23 03:40:36 +0000 |
---|---|---|
committer | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-23 03:40:36 +0000 |
commit | 278df3052aa195ee1a865e470877ece21edce2ec (patch) | |
tree | 933bacb2ccb71968e78e88e4a26eb483b322b420 /media/formats/webm/webm_stream_parser.cc | |
parent | ce631ee54387703370a8924fcba68a2f6b7c79ac (diff) | |
download | chromium_src-278df3052aa195ee1a865e470877ece21edce2ec.zip chromium_src-278df3052aa195ee1a865e470877ece21edce2ec.tar.gz chromium_src-278df3052aa195ee1a865e470877ece21edce2ec.tar.bz2 |
Move MSE parsers under "formats" root directory.
Changes made programatically:
find -name \*.cc -o -name \*.h | xargs sed -r -i 's,media/(mp2t|mp3|mp4|webm)/,media/formats/\1/,g'
find -name \*.cc -o -name \*.h | xargs sed -r -i 's,MEDIA_(MP2T|MP3|MP4|WEBM)_,MEDIA_FORMATS_\1_,g'
find -name \*.gyp | xargs sed -r -i "s,'(mp2t|mp3|mp4|webm)/,'formats/\1/,g"
BUG=none
TEST=compiles
Review URL: https://codereview.chromium.org/136053003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@246512 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/formats/webm/webm_stream_parser.cc')
-rw-r--r-- | media/formats/webm/webm_stream_parser.cc | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/media/formats/webm/webm_stream_parser.cc b/media/formats/webm/webm_stream_parser.cc new file mode 100644 index 0000000..f39a8e3 --- /dev/null +++ b/media/formats/webm/webm_stream_parser.cc @@ -0,0 +1,300 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/formats/webm/webm_stream_parser.h" + +#include <string> + +#include "base/callback.h" +#include "base/logging.h" +#include "media/formats/webm/webm_cluster_parser.h" +#include "media/formats/webm/webm_constants.h" +#include "media/formats/webm/webm_content_encodings.h" +#include "media/formats/webm/webm_crypto_helpers.h" +#include "media/formats/webm/webm_info_parser.h" +#include "media/formats/webm/webm_tracks_parser.h" + +namespace media { + +WebMStreamParser::WebMStreamParser() + : state_(kWaitingForInit), + parsing_cluster_(false) { +} + +WebMStreamParser::~WebMStreamParser() { +} + +void WebMStreamParser::Init(const InitCB& init_cb, + const NewConfigCB& config_cb, + const NewBuffersCB& new_buffers_cb, + const NewTextBuffersCB& text_cb, + const NeedKeyCB& need_key_cb, + const NewMediaSegmentCB& new_segment_cb, + const base::Closure& end_of_segment_cb, + const LogCB& log_cb) { + DCHECK_EQ(state_, kWaitingForInit); + DCHECK(init_cb_.is_null()); + DCHECK(!init_cb.is_null()); + DCHECK(!config_cb.is_null()); + DCHECK(!new_buffers_cb.is_null()); + DCHECK(!need_key_cb.is_null()); + DCHECK(!new_segment_cb.is_null()); + DCHECK(!end_of_segment_cb.is_null()); + + ChangeState(kParsingHeaders); + init_cb_ = init_cb; + config_cb_ = config_cb; + new_buffers_cb_ = new_buffers_cb; + text_cb_ = text_cb; + need_key_cb_ = need_key_cb; + new_segment_cb_ = new_segment_cb; + end_of_segment_cb_ = end_of_segment_cb; + log_cb_ = log_cb; +} + +void WebMStreamParser::Flush() { + DCHECK_NE(state_, kWaitingForInit); + + byte_queue_.Reset(); + parsing_cluster_ = false; + + if (state_ != kParsingClusters) + return; + + cluster_parser_->Reset(); +} + +bool WebMStreamParser::Parse(const uint8* buf, int size) { + DCHECK_NE(state_, kWaitingForInit); + + if (state_ == kError) + return false; + + byte_queue_.Push(buf, size); + + int result = 0; + int bytes_parsed = 0; + const uint8* cur = NULL; + int cur_size = 0; + + byte_queue_.Peek(&cur, &cur_size); + while (cur_size > 0) { + State oldState = state_; + switch (state_) { + case kParsingHeaders: + result = ParseInfoAndTracks(cur, cur_size); + break; + + case kParsingClusters: + result = ParseCluster(cur, cur_size); + break; + + case kWaitingForInit: + case kError: + return false; + } + + if (result < 0) { + ChangeState(kError); + return false; + } + + if (state_ == oldState && result == 0) + break; + + DCHECK_GE(result, 0); + cur += result; + cur_size -= result; + bytes_parsed += result; + } + + byte_queue_.Pop(bytes_parsed); + return true; +} + +void WebMStreamParser::ChangeState(State new_state) { + DVLOG(1) << "ChangeState() : " << state_ << " -> " << new_state; + state_ = new_state; +} + +int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) { + DVLOG(2) << "ParseInfoAndTracks()"; + DCHECK(data); + DCHECK_GT(size, 0); + + const uint8* cur = data; + int cur_size = size; + int bytes_parsed = 0; + + int id; + int64 element_size; + int result = WebMParseElementHeader(cur, cur_size, &id, &element_size); + + if (result <= 0) + return result; + + switch (id) { + case kWebMIdEBMLHeader: + case kWebMIdSeekHead: + case kWebMIdVoid: + case kWebMIdCRC32: + case kWebMIdCues: + case kWebMIdChapters: + if (cur_size < (result + element_size)) { + // We don't have the whole element yet. Signal we need more data. + return 0; + } + // Skip the element. + return result + element_size; + break; + case kWebMIdSegment: + // Just consume the segment header. + return result; + break; + case kWebMIdInfo: + // We've found the element we are looking for. + break; + default: { + MEDIA_LOG(log_cb_) << "Unexpected element ID 0x" << std::hex << id; + return -1; + } + } + + WebMInfoParser info_parser; + result = info_parser.Parse(cur, cur_size); + + if (result <= 0) + return result; + + cur += result; + cur_size -= result; + bytes_parsed += result; + + WebMTracksParser tracks_parser(log_cb_, text_cb_.is_null()); + result = tracks_parser.Parse(cur, cur_size); + + if (result <= 0) + return result; + + bytes_parsed += result; + + base::TimeDelta duration = kInfiniteDuration(); + + if (info_parser.duration() > 0) { + double mult = info_parser.timecode_scale() / 1000.0; + int64 duration_in_us = info_parser.duration() * mult; + duration = base::TimeDelta::FromMicroseconds(duration_in_us); + } + + const AudioDecoderConfig& audio_config = tracks_parser.audio_decoder_config(); + if (audio_config.is_encrypted()) + FireNeedKey(tracks_parser.audio_encryption_key_id()); + + const VideoDecoderConfig& video_config = tracks_parser.video_decoder_config(); + if (video_config.is_encrypted()) + FireNeedKey(tracks_parser.video_encryption_key_id()); + + if (!config_cb_.Run(audio_config, + video_config, + tracks_parser.text_tracks())) { + DVLOG(1) << "New config data isn't allowed."; + return -1; + } + + cluster_parser_.reset(new WebMClusterParser( + info_parser.timecode_scale(), + tracks_parser.audio_track_num(), + tracks_parser.video_track_num(), + tracks_parser.text_tracks(), + tracks_parser.ignored_tracks(), + tracks_parser.audio_encryption_key_id(), + tracks_parser.video_encryption_key_id(), + log_cb_)); + + ChangeState(kParsingClusters); + + if (!init_cb_.is_null()) { + init_cb_.Run(true, duration); + init_cb_.Reset(); + } + + return bytes_parsed; +} + +int WebMStreamParser::ParseCluster(const uint8* data, int size) { + if (!cluster_parser_) + return -1; + + int id; + int64 element_size; + int result = WebMParseElementHeader(data, size, &id, &element_size); + + if (result <= 0) + return result; + + // TODO(matthewjheaney): implement support for chapters + if (id == kWebMIdCues || id == kWebMIdChapters) { + // TODO(wolenetz): Handle unknown-sized cluster parse completion correctly. + // See http://crbug.com/335676. + if (size < (result + element_size)) { + // We don't have the whole element yet. Signal we need more data. + return 0; + } + // Skip the element. + return result + element_size; + } + + if (id == kWebMIdEBMLHeader) { + // TODO(wolenetz): Handle unknown-sized cluster parse completion correctly. + // See http://crbug.com/335676. + ChangeState(kParsingHeaders); + return 0; + } + + int bytes_parsed = cluster_parser_->Parse(data, size); + + if (bytes_parsed <= 0) + return bytes_parsed; + + // If cluster detected, immediately notify new segment if we have not already + // done this. + if (id == kWebMIdCluster && !parsing_cluster_) { + parsing_cluster_ = true; + new_segment_cb_.Run(); + } + + const BufferQueue& audio_buffers = cluster_parser_->audio_buffers(); + const BufferQueue& video_buffers = cluster_parser_->video_buffers(); + bool cluster_ended = cluster_parser_->cluster_ended(); + + if ((!audio_buffers.empty() || !video_buffers.empty()) && + !new_buffers_cb_.Run(audio_buffers, video_buffers)) { + return -1; + } + + WebMClusterParser::TextTrackIterator text_track_iter = + cluster_parser_->CreateTextTrackIterator(); + + int text_track_num; + const BufferQueue* text_buffers; + + while (text_track_iter(&text_track_num, &text_buffers)) { + if (!text_buffers->empty() && !text_cb_.Run(text_track_num, *text_buffers)) + return -1; + } + + if (cluster_ended) { + parsing_cluster_ = false; + end_of_segment_cb_.Run(); + } + + return bytes_parsed; +} + +void WebMStreamParser::FireNeedKey(const std::string& key_id) { + std::vector<uint8> key_id_vector(key_id.begin(), key_id.end()); + need_key_cb_.Run(kWebMEncryptInitDataType, key_id_vector); +} + +} // namespace media |