diff options
Diffstat (limited to 'media/webm/webm_stream_parser.cc')
-rw-r--r-- | media/webm/webm_stream_parser.cc | 350 |
1 files changed, 0 insertions, 350 deletions
diff --git a/media/webm/webm_stream_parser.cc b/media/webm/webm_stream_parser.cc deleted file mode 100644 index 45c57f3..0000000 --- a/media/webm/webm_stream_parser.cc +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright (c) 2012 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/webm/webm_stream_parser.h" - -#include "base/callback.h" -#include "base/logging.h" -#include "media/ffmpeg/ffmpeg_common.h" -#include "media/filters/ffmpeg_glue.h" -#include "media/filters/in_memory_url_protocol.h" -#include "media/webm/webm_cluster_parser.h" -#include "media/webm/webm_constants.h" -#include "media/webm/webm_info_parser.h" -#include "media/webm/webm_tracks_parser.h" - -namespace media { - -// Helper class that uses FFmpeg to create AudioDecoderConfig & -// VideoDecoderConfig objects. -// -// This dependency on FFmpeg can be removed once we update WebMTracksParser -// to parse the necessary data to construct AudioDecoderConfig & -// VideoDecoderConfig objects. http://crbug.com/108756 -class FFmpegConfigHelper { - public: - FFmpegConfigHelper(); - ~FFmpegConfigHelper(); - - bool Parse(const uint8* data, int size); - - const AudioDecoderConfig& audio_config() const; - const VideoDecoderConfig& video_config() const; - - private: - AVFormatContext* CreateFormatContext(const uint8* data, int size); - bool SetupStreamConfigs(); - - AudioDecoderConfig audio_config_; - VideoDecoderConfig video_config_; - - // Backing buffer for |url_protocol_|. - scoped_array<uint8> url_protocol_buffer_; - - // Protocol used by |format_context_|. It must outlive the context object. - scoped_ptr<FFmpegURLProtocol> url_protocol_; - - // FFmpeg format context for this demuxer. It is created by - // av_open_input_file() during demuxer initialization and cleaned up with - // DestroyAVFormatContext() in the destructor. - AVFormatContext* format_context_; - - static const uint8 kWebMHeader[]; - static const int kSegmentSizeOffset; - static const uint8 kEmptyCluster[]; - - DISALLOW_COPY_AND_ASSIGN(FFmpegConfigHelper); -}; - -// WebM File Header. This is prepended to the INFO & TRACKS -// data passed to Init() before handing it to FFmpeg. Essentially -// we are making the INFO & TRACKS data look like a small WebM -// file so we can use FFmpeg to initialize the AVFormatContext. -const uint8 FFmpegConfigHelper::kWebMHeader[] = { - 0x1A, 0x45, 0xDF, 0xA3, 0x9F, // EBML (size = 0x1f) - 0x42, 0x86, 0x81, 0x01, // EBMLVersion = 1 - 0x42, 0xF7, 0x81, 0x01, // EBMLReadVersion = 1 - 0x42, 0xF2, 0x81, 0x04, // EBMLMaxIDLength = 4 - 0x42, 0xF3, 0x81, 0x08, // EBMLMaxSizeLength = 8 - 0x42, 0x82, 0x84, 0x77, 0x65, 0x62, 0x6D, // DocType = "webm" - 0x42, 0x87, 0x81, 0x02, // DocTypeVersion = 2 - 0x42, 0x85, 0x81, 0x02, // DocTypeReadVersion = 2 - // EBML end - 0x18, 0x53, 0x80, 0x67, // Segment - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segment(size = 0) - // INFO goes here. -}; - -// Offset of the segment size field in kWebMHeader. Used to update -// the segment size field before handing the buffer to FFmpeg. -const int FFmpegConfigHelper::kSegmentSizeOffset = sizeof(kWebMHeader) - 8; - -const uint8 FFmpegConfigHelper::kEmptyCluster[] = { - 0x1F, 0x43, 0xB6, 0x75, 0x80 // CLUSTER (size = 0) -}; - -FFmpegConfigHelper::FFmpegConfigHelper() : format_context_(NULL) {} - -FFmpegConfigHelper::~FFmpegConfigHelper() { - if (!format_context_) - return; - - DestroyAVFormatContext(format_context_); - format_context_ = NULL; - - if (url_protocol_.get()) { - FFmpegGlue::GetInstance()->RemoveProtocol(url_protocol_.get()); - url_protocol_.reset(); - url_protocol_buffer_.reset(); - } -} - -bool FFmpegConfigHelper::Parse(const uint8* data, int size) { - format_context_ = CreateFormatContext(data, size); - return format_context_ && SetupStreamConfigs(); -} - -const AudioDecoderConfig& FFmpegConfigHelper::audio_config() const { - return audio_config_; -} - -const VideoDecoderConfig& FFmpegConfigHelper::video_config() const { - return video_config_; -} - -AVFormatContext* FFmpegConfigHelper::CreateFormatContext(const uint8* data, - int size) { - DCHECK(!url_protocol_.get()); - DCHECK(!url_protocol_buffer_.get()); - - int segment_size = size + sizeof(kEmptyCluster); - int buf_size = sizeof(kWebMHeader) + segment_size; - url_protocol_buffer_.reset(new uint8[buf_size]); - uint8* buf = url_protocol_buffer_.get(); - memcpy(buf, kWebMHeader, sizeof(kWebMHeader)); - memcpy(buf + sizeof(kWebMHeader), data, size); - memcpy(buf + sizeof(kWebMHeader) + size, kEmptyCluster, - sizeof(kEmptyCluster)); - - // Update the segment size in the buffer. - int64 tmp = (segment_size & GG_LONGLONG(0x00FFFFFFFFFFFFFF)) | - GG_LONGLONG(0x0100000000000000); - for (int i = 0; i < 8; i++) { - buf[kSegmentSizeOffset + i] = (tmp >> (8 * (7 - i))) & 0xff; - } - - url_protocol_.reset(new InMemoryUrlProtocol(buf, buf_size, true)); - std::string key = FFmpegGlue::GetInstance()->AddProtocol(url_protocol_.get()); - - // Open FFmpeg AVFormatContext. - AVFormatContext* context = NULL; - int result = av_open_input_file(&context, key.c_str(), NULL, 0, NULL); - - if (result < 0) - return NULL; - - return context; -} - -bool FFmpegConfigHelper::SetupStreamConfigs() { - int result = av_find_stream_info(format_context_); - - if (result < 0) - return false; - - bool no_supported_streams = true; - for (size_t i = 0; i < format_context_->nb_streams; ++i) { - AVStream* stream = format_context_->streams[i]; - AVCodecContext* codec_context = stream->codec; - AVMediaType codec_type = codec_context->codec_type; - - if (codec_type == AVMEDIA_TYPE_AUDIO && - stream->codec->codec_id == CODEC_ID_VORBIS && - !audio_config_.IsValidConfig()) { - AVCodecContextToAudioDecoderConfig(stream->codec, &audio_config_); - no_supported_streams = false; - continue; - } - - if (codec_type == AVMEDIA_TYPE_VIDEO && - stream->codec->codec_id == CODEC_ID_VP8 && - !video_config_.IsValidConfig()) { - AVStreamToVideoDecoderConfig(stream, &video_config_); - no_supported_streams = false; - continue; - } - } - - return !no_supported_streams; -} - -WebMStreamParser::WebMStreamParser() - : state_(WAITING_FOR_INIT), - host_(NULL) { -} - -WebMStreamParser::~WebMStreamParser() {} - -void WebMStreamParser::Init(const InitCB& init_cb, StreamParserHost* host) { - DCHECK_EQ(state_, WAITING_FOR_INIT); - DCHECK(init_cb_.is_null()); - DCHECK(!host_); - DCHECK(!init_cb.is_null()); - DCHECK(host); - - ChangeState(PARSING_HEADERS); - init_cb_ = init_cb; - host_ = host; -} - -void WebMStreamParser::Flush() { - DCHECK_NE(state_, WAITING_FOR_INIT); - - if (state_ != PARSING_CLUSTERS) - return; - - cluster_parser_->Reset(); -} - -int WebMStreamParser::Parse(const uint8* buf, int size) { - DCHECK_NE(state_, WAITING_FOR_INIT); - - if (state_ == PARSING_HEADERS) - return ParseInfoAndTracks(buf, size); - - if (state_ == PARSING_CLUSTERS) - return ParseCluster(buf, size); - - return -1; -} - -void WebMStreamParser::ChangeState(State new_state) { - state_ = new_state; -} - -int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) { - 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 kWebMIdEBML: - case kWebMIdSeekHead: - case kWebMIdVoid: - case kWebMIdCRC32: - case kWebMIdCues: - 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: - DVLOG(1) << "Unexpected 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(info_parser.timecode_scale()); - result = tracks_parser.Parse(cur, cur_size); - - if (result <= 0) - return result; - - bytes_parsed += result; - - double mult = info_parser.timecode_scale() / 1000.0; - base::TimeDelta duration = - base::TimeDelta::FromMicroseconds(info_parser.duration() * mult); - - FFmpegConfigHelper config_helper; - - if (!config_helper.Parse(data, bytes_parsed)) - return -1; - - if (config_helper.audio_config().IsValidConfig()) - host_->OnNewAudioConfig(config_helper.audio_config()); - - if (config_helper.video_config().IsValidConfig()) - host_->OnNewVideoConfig(config_helper.video_config()); - - cluster_parser_.reset(new WebMClusterParser( - info_parser.timecode_scale(), - tracks_parser.audio_track_num(), - tracks_parser.audio_default_duration(), - tracks_parser.video_track_num(), - tracks_parser.video_default_duration())); - - ChangeState(PARSING_CLUSTERS); - init_cb_.Run(true, duration); - - return bytes_parsed; -} - -int WebMStreamParser::ParseCluster(const uint8* data, int size) { - if (!cluster_parser_.get()) - return -1; - - int id; - int64 element_size; - int result = WebMParseElementHeader(data, size, &id, &element_size); - - if (result <= 0) - return result; - - if (id == kWebMIdCues) { - 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; - } - - int bytes_parsed = cluster_parser_->Parse(data, size); - - if (bytes_parsed <= 0) - return bytes_parsed; - - if (cluster_parser_->audio_buffers().empty() && - cluster_parser_->video_buffers().empty()) - return bytes_parsed; - - if (!host_->OnAudioBuffers(cluster_parser_->audio_buffers())) - return -1; - - if (!host_->OnVideoBuffers(cluster_parser_->video_buffers())) - return -1; - - return bytes_parsed; -} - -} // namespace media |