diff options
-rw-r--r-- | media/media.gyp | 10 | ||||
-rw-r--r-- | media/webm/webm_audio_client.cc | 112 | ||||
-rw-r--r-- | media/webm/webm_audio_client.h | 52 | ||||
-rw-r--r-- | media/webm/webm_stream_parser.cc | 199 | ||||
-rw-r--r-- | media/webm/webm_stream_parser.h | 3 | ||||
-rw-r--r-- | media/webm/webm_tracks_parser.cc | 109 | ||||
-rw-r--r-- | media/webm/webm_tracks_parser.h | 25 | ||||
-rw-r--r-- | media/webm/webm_video_client.cc | 154 | ||||
-rw-r--r-- | media/webm/webm_video_client.h | 60 |
9 files changed, 483 insertions, 241 deletions
diff --git a/media/media.gyp b/media/media.gyp index 82bab1c..c6977e4 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -412,6 +412,8 @@ 'video/picture.h', 'video/video_decode_accelerator.cc', 'video/video_decode_accelerator.h', + 'webm/webm_audio_client.cc', + 'webm/webm_audio_client.h', 'webm/webm_cluster_parser.cc', 'webm/webm_cluster_parser.h', 'webm/webm_constants.h', @@ -429,6 +431,8 @@ 'webm/webm_stream_parser.h', 'webm/webm_tracks_parser.cc', 'webm/webm_tracks_parser.h', + 'webm/webm_video_client.cc', + 'webm/webm_video_client.h', ], 'direct_dependent_settings': { 'include_dirs': [ @@ -465,8 +469,6 @@ 'ffmpeg/ffmpeg_common.h', 'filters/audio_file_reader.cc', 'filters/audio_file_reader.h', - 'filters/chunk_demuxer.cc', - 'filters/chunk_demuxer.h', 'filters/blocking_url_protocol.cc', 'filters/blocking_url_protocol.h', 'filters/ffmpeg_audio_decoder.cc', @@ -479,10 +481,6 @@ 'filters/ffmpeg_h264_to_annex_b_bitstream_converter.h', 'filters/ffmpeg_video_decoder.cc', 'filters/ffmpeg_video_decoder.h', - 'webm/webm_cluster_parser.cc', - 'webm/webm_cluster_parser.h', - 'webm/webm_stream_parser.cc', - 'webm/webm_stream_parser.h', ], }], ['media_use_libvpx == 1', { diff --git a/media/webm/webm_audio_client.cc b/media/webm/webm_audio_client.cc new file mode 100644 index 0000000..e52f44b --- /dev/null +++ b/media/webm/webm_audio_client.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2013 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_audio_client.h" + +#include "media/base/audio_decoder_config.h" +#include "media/base/channel_layout.h" +#include "media/webm/webm_constants.h" + +namespace media { + +WebMAudioClient::WebMAudioClient(const LogCB& log_cb) + : log_cb_(log_cb) { + Reset(); +} + +WebMAudioClient::~WebMAudioClient() { +} + +void WebMAudioClient::Reset() { + channels_ = -1; + samples_per_second_ = -1; + output_samples_per_second_ = -1; +} + +bool WebMAudioClient::InitializeConfig( + const std::string& codec_id, const std::vector<uint8>& codec_private, + bool is_encrypted, AudioDecoderConfig* config) { + DCHECK(config); + + AudioCodec audio_codec = kUnknownAudioCodec; + if (codec_id == "A_VORBIS") { + audio_codec = kCodecVorbis; + } else { + MEDIA_LOG(log_cb_) << "Unsupported audio codec_id " << codec_id; + return false; + } + + if (samples_per_second_ <= 0) + return false; + + // Set channel layout default if a Channels element was not present. + if (channels_ == -1) + channels_ = 1; + + ChannelLayout channel_layout = GuessChannelLayout(channels_); + + if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) { + MEDIA_LOG(log_cb_) << "Unsupported channel count " << channels_; + return false; + } + + int samples_per_second = samples_per_second_; + if (output_samples_per_second_ > 0) + samples_per_second = output_samples_per_second_; + + const uint8* extra_data = NULL; + size_t extra_data_size = 0; + if (codec_private.size() > 0) { + extra_data = &codec_private[0]; + extra_data_size = codec_private.size(); + } + + config->Initialize( + audio_codec, kSampleFormatPlanarF32, channel_layout, + samples_per_second, extra_data, extra_data_size, is_encrypted, true); + return config->IsValidConfig(); +} + +bool WebMAudioClient::OnUInt(int id, int64 val) { + if (id == kWebMIdChannels) { + if (channels_ != -1) { + MEDIA_LOG(log_cb_) << "Multiple values for id " << std::hex << id + << " specified. (" << channels_ << " and " << val + << ")"; + return false; + } + + channels_ = val; + } + return true; +} + +bool WebMAudioClient::OnFloat(int id, double val) { + double* dst = NULL; + + switch (id) { + case kWebMIdSamplingFrequency: + dst = &samples_per_second_; + break; + case kWebMIdOutputSamplingFrequency: + dst = &output_samples_per_second_; + break; + default: + return true; + } + + if (val <= 0) + return false; + + if (*dst != -1) { + MEDIA_LOG(log_cb_) << "Multiple values for id " << std::hex << id + << " specified (" << *dst << " and " << val << ")"; + return false; + } + + *dst = val; + return true; +} + +} // namespace media diff --git a/media/webm/webm_audio_client.h b/media/webm/webm_audio_client.h new file mode 100644 index 0000000..1338f5c --- /dev/null +++ b/media/webm/webm_audio_client.h @@ -0,0 +1,52 @@ +// Copyright (c) 2013 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. + +#ifndef MEDIA_WEBM_WEBM_AUDIO_CLIENT_H_ +#define MEDIA_WEBM_WEBM_AUDIO_CLIENT_H_ + +#include <string> +#include <vector> + +#include "media/base/media_log.h" +#include "media/webm/webm_parser.h" + +namespace media { +class AudioDecoderConfig; + +// Helper class used to parse an Audio element inside a TrackEntry element. +class WebMAudioClient : public WebMParserClient { + public: + explicit WebMAudioClient(const LogCB& log_cb); + virtual ~WebMAudioClient(); + + // Reset this object's state so it can process a new audio track element. + void Reset(); + + // Initialize |config| with the data in |codec_id|, |codec_private|, + // |is_encrypted| and the fields parsed from the last audio track element this + // object was used to parse. + // Returns true if |config| was successfully initialized. + // Returns false if there was unexpected values in the provided parameters or + // audio track element fields. + bool InitializeConfig(const std::string& codec_id, + const std::vector<uint8>& codec_private, + bool is_encrypted, + AudioDecoderConfig* config); + + private: + // WebMParserClient implementation. + virtual bool OnUInt(int id, int64 val) OVERRIDE; + virtual bool OnFloat(int id, double val) OVERRIDE; + + LogCB log_cb_; + int channels_; + double samples_per_second_; + double output_samples_per_second_; + + DISALLOW_COPY_AND_ASSIGN(WebMAudioClient); +}; + +} // namespace media + +#endif // MEDIA_WEBM_WEBM_AUDIO_CLIENT_H_ diff --git a/media/webm/webm_stream_parser.cc b/media/webm/webm_stream_parser.cc index f47fa41..514a6d0 100644 --- a/media/webm/webm_stream_parser.cc +++ b/media/webm/webm_stream_parser.cc @@ -8,9 +8,6 @@ #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_content_encodings.h" @@ -20,156 +17,6 @@ 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: - static const uint8 kWebMHeader[]; - static const int kSegmentSizeOffset; - static const uint8 kEmptyCluster[]; - - bool OpenFormatContext(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 FFmpegGlue. It must outlive the context object. - scoped_ptr<InMemoryUrlProtocol> url_protocol_; - - // Glue for interfacing InMemoryUrlProtocol with FFmpeg. - scoped_ptr<FFmpegGlue> glue_; - - 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() {} - -FFmpegConfigHelper::~FFmpegConfigHelper() { - if (url_protocol_.get()) { - url_protocol_.reset(); - url_protocol_buffer_.reset(); - } - - if (glue_.get()) - glue_.reset(); -} - -bool FFmpegConfigHelper::Parse(const uint8* data, int size) { - return OpenFormatContext(data, size) && SetupStreamConfigs(); -} - -const AudioDecoderConfig& FFmpegConfigHelper::audio_config() const { - return audio_config_; -} - -const VideoDecoderConfig& FFmpegConfigHelper::video_config() const { - return video_config_; -} - -bool FFmpegConfigHelper::OpenFormatContext(const uint8* data, int size) { - DCHECK(!url_protocol_.get()); - DCHECK(!url_protocol_buffer_.get()); - DCHECK(!glue_.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)); - glue_.reset(new FFmpegGlue(url_protocol_.get())); - - // Open FFmpeg AVFormatContext. - return glue_->OpenContext(); -} - -bool FFmpegConfigHelper::SetupStreamConfigs() { - AVFormatContext* format_context = glue_->format_context(); - int result = avformat_find_stream_info(format_context, NULL); - - 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]; - AVMediaType codec_type = stream->codec->codec_type; - - if (codec_type == AVMEDIA_TYPE_AUDIO && - stream->codec->codec_id == CODEC_ID_VORBIS && - !audio_config_.IsValidConfig()) { - AVStreamToAudioDecoderConfig(stream, &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_(kWaitingForInit), waiting_for_buffers_(false) { @@ -338,51 +185,13 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) { duration = base::TimeDelta::FromMicroseconds(duration_in_us); } - FFmpegConfigHelper config_helper; - if (!config_helper.Parse(data, bytes_parsed)) { - DVLOG(1) << "Failed to parse config data."; - return -1; - } - - bool is_audio_encrypted = !tracks_parser.audio_encryption_key_id().empty(); - AudioDecoderConfig audio_config; - if (is_audio_encrypted) { - const AudioDecoderConfig& original_audio_config = - config_helper.audio_config(); - - audio_config.Initialize(original_audio_config.codec(), - original_audio_config.sample_format(), - original_audio_config.channel_layout(), - original_audio_config.samples_per_second(), - original_audio_config.extra_data(), - original_audio_config.extra_data_size(), - is_audio_encrypted, - false); - + const AudioDecoderConfig& audio_config = tracks_parser.audio_decoder_config(); + if (audio_config.is_encrypted()) FireNeedKey(tracks_parser.audio_encryption_key_id()); - } else { - audio_config = config_helper.audio_config(); - } - - bool is_video_encrypted = !tracks_parser.video_encryption_key_id().empty(); - VideoDecoderConfig video_config; - if (is_video_encrypted) { - const VideoDecoderConfig& original_video_config = - config_helper.video_config(); - video_config.Initialize(original_video_config.codec(), - original_video_config.profile(), - original_video_config.format(), - original_video_config.coded_size(), - original_video_config.visible_rect(), - original_video_config.natural_size(), - original_video_config.extra_data(), - original_video_config.extra_data_size(), - is_video_encrypted, false); + const VideoDecoderConfig& video_config = tracks_parser.video_decoder_config(); + if (video_config.is_encrypted()) FireNeedKey(tracks_parser.video_encryption_key_id()); - } else { - video_config = config_helper.video_config(); - } if (!config_cb_.Run(audio_config, video_config)) { DVLOG(1) << "New config data isn't allowed."; diff --git a/media/webm/webm_stream_parser.h b/media/webm/webm_stream_parser.h index c98805a..7407542 100644 --- a/media/webm/webm_stream_parser.h +++ b/media/webm/webm_stream_parser.h @@ -12,10 +12,11 @@ #include "media/base/byte_queue.h" #include "media/base/stream_parser.h" #include "media/base/video_decoder_config.h" -#include "media/webm/webm_cluster_parser.h" namespace media { +class WebMClusterParser; + class WebMStreamParser : public StreamParser { public: WebMStreamParser(); diff --git a/media/webm/webm_tracks_parser.cc b/media/webm/webm_tracks_parser.cc index 2dbac41..7703504 100644 --- a/media/webm/webm_tracks_parser.cc +++ b/media/webm/webm_tracks_parser.cc @@ -18,13 +18,30 @@ static const int kWebMTrackTypeAudio = 2; static const int kWebMTrackTypeSubtitlesOrCaptions = 0x11; static const int kWebMTrackTypeDescriptionsOrMetadata = 0x21; +static TextKind CodecIdToTextKind(const std::string& codec_id) { + if (codec_id == "D_WEBVTT/SUBTITLES") + return kTextSubtitles; + + if (codec_id == "D_WEBVTT/CAPTIONS") + return kTextCaptions; + + if (codec_id == "D_WEBVTT/DESCRIPTIONS") + return kTextDescriptions; + + if (codec_id == "D_WEBVTT/METADATA") + return kTextMetadata; + + return kTextNone; +} + WebMTracksParser::WebMTracksParser(const LogCB& log_cb) : track_type_(-1), track_num_(-1), - text_track_kind_(kTextNone), audio_track_num_(-1), video_track_num_(-1), - log_cb_(log_cb) { + log_cb_(log_cb), + audio_client_(log_cb), + video_client_(log_cb) { } WebMTracksParser::~WebMTracksParser() {} @@ -32,9 +49,10 @@ WebMTracksParser::~WebMTracksParser() {} int WebMTracksParser::Parse(const uint8* buf, int size) { track_type_ =-1; track_num_ = -1; - text_track_kind_ = kTextNone; audio_track_num_ = -1; + audio_decoder_config_ = AudioDecoderConfig(); video_track_num_ = -1; + video_decoder_config_ = VideoDecoderConfig(); text_tracks_.clear(); ignored_tracks_.clear(); @@ -59,10 +77,19 @@ WebMParserClient* WebMTracksParser::OnListStart(int id) { if (id == kWebMIdTrackEntry) { track_type_ = -1; track_num_ = -1; - text_track_kind_ = kTextNone; + codec_id_ = ""; + codec_private_.clear(); + audio_client_.Reset(); + video_client_.Reset(); return this; } + if (id == kWebMIdAudio) + return &audio_client_; + + if (id == kWebMIdVideo) + return &video_client_; + return this; } @@ -89,27 +116,29 @@ bool WebMTracksParser::OnListEnd(int id) { } if (track_type_ == kWebMTrackTypeSubtitlesOrCaptions) { - if (text_track_kind_ == kTextNone) { + TextKind text_track_kind = CodecIdToTextKind(codec_id_); + if (text_track_kind == kTextNone) { MEDIA_LOG(log_cb_) << "Missing TrackEntry CodecID" << " TrackNum " << track_num_; return false; } - if (text_track_kind_ != kTextSubtitles && - text_track_kind_ != kTextCaptions) { + if (text_track_kind != kTextSubtitles && + text_track_kind != kTextCaptions) { MEDIA_LOG(log_cb_) << "Wrong TrackEntry CodecID" << " TrackNum " << track_num_; return false; } } else if (track_type_ == kWebMTrackTypeDescriptionsOrMetadata) { - if (text_track_kind_ == kTextNone) { + TextKind text_track_kind = CodecIdToTextKind(codec_id_); + if (text_track_kind == kTextNone) { MEDIA_LOG(log_cb_) << "Missing TrackEntry CodecID" << " TrackNum " << track_num_; return false; } - if (text_track_kind_ != kTextDescriptions && - text_track_kind_ != kTextMetadata) { + if (text_track_kind != kTextDescriptions && + text_track_kind != kTextMetadata) { MEDIA_LOG(log_cb_) << "Wrong TrackEntry CodecID" << " TrackNum " << track_num_; return false; @@ -129,6 +158,13 @@ bool WebMTracksParser::OnListEnd(int id) { if (audio_track_num_ == -1) { audio_track_num_ = track_num_; audio_encryption_key_id_ = encryption_key_id; + + DCHECK(!audio_decoder_config_.IsValidConfig()); + if (!audio_client_.InitializeConfig( + codec_id_, codec_private_, !audio_encryption_key_id_.empty(), + &audio_decoder_config_)) { + return false; + } } else { MEDIA_LOG(log_cb_) << "Ignoring audio track " << track_num_; ignored_tracks_.insert(track_num_); @@ -137,6 +173,13 @@ bool WebMTracksParser::OnListEnd(int id) { if (video_track_num_ == -1) { video_track_num_ = track_num_; video_encryption_key_id_ = encryption_key_id; + + DCHECK(!video_decoder_config_.IsValidConfig()); + if (!video_client_.InitializeConfig( + codec_id_, codec_private_, !video_encryption_key_id_.empty(), + &video_decoder_config_)) { + return false; + } } else { MEDIA_LOG(log_cb_) << "Ignoring video track " << track_num_; ignored_tracks_.insert(track_num_); @@ -151,8 +194,12 @@ bool WebMTracksParser::OnListEnd(int id) { track_type_ = -1; track_num_ = -1; + codec_id_ = ""; + codec_private_.clear(); track_content_encodings_client_.reset(); - text_track_kind_ = kTextNone; + + audio_client_.Reset(); + video_client_.Reset(); return true; } @@ -188,39 +235,27 @@ bool WebMTracksParser::OnFloat(int id, double val) { } bool WebMTracksParser::OnBinary(int id, const uint8* data, int size) { + if (id == kWebMIdCodecPrivate) { + if (!codec_private_.empty()) { + MEDIA_LOG(log_cb_) << "Multiple CodecPrivate fields in a track."; + return false; + } + + codec_private_.assign(data, data + size); + return true; + } return true; } bool WebMTracksParser::OnString(int id, const std::string& str) { if (id == kWebMIdCodecID) { - if (str == "V_VP8") - return true; - - if (str == "A_VORBIS") - return true; - - if (str == "D_WEBVTT/SUBTITLES") { - text_track_kind_ = kTextSubtitles; - return true; - } - - if (str == "D_WEBVTT/CAPTIONS") { - text_track_kind_ = kTextCaptions; - return true; - } - - if (str == "D_WEBVTT/DESCRIPTIONS") { - text_track_kind_ = kTextDescriptions; - return true; - } - - if (str == "D_WEBVTT/METADATA") { - text_track_kind_ = kTextMetadata; - return true; + if (!codec_id_.empty()) { + MEDIA_LOG(log_cb_) << "Multiple CodecID fields in a track"; + return false; } - MEDIA_LOG(log_cb_) << "Unexpected CodecID " << str; - return false; + codec_id_ = str; + return true; } return true; diff --git a/media/webm/webm_tracks_parser.h b/media/webm/webm_tracks_parser.h index 5593349..79d8888 100644 --- a/media/webm/webm_tracks_parser.h +++ b/media/webm/webm_tracks_parser.h @@ -7,12 +7,17 @@ #include <set> #include <string> +#include <vector> #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" +#include "media/base/audio_decoder_config.h" #include "media/base/media_log.h" +#include "media/base/video_decoder_config.h" +#include "media/webm/webm_audio_client.h" #include "media/webm/webm_content_encodings_client.h" #include "media/webm/webm_parser.h" +#include "media/webm/webm_video_client.h" namespace media { @@ -36,16 +41,25 @@ class WebMTracksParser : public WebMParserClient { const std::string& audio_encryption_key_id() const { return audio_encryption_key_id_; } + + const AudioDecoderConfig& audio_decoder_config() { + return audio_decoder_config_; + } + const std::string& video_encryption_key_id() const { return video_encryption_key_id_; } + const VideoDecoderConfig& video_decoder_config() { + return video_decoder_config_; + } + const std::set<int>& text_tracks() const { return text_tracks_; } private: - // WebMParserClient methods + // WebMParserClient implementation. virtual WebMParserClient* OnListStart(int id) OVERRIDE; virtual bool OnListEnd(int id) OVERRIDE; virtual bool OnUInt(int id, int64 val) OVERRIDE; @@ -55,8 +69,9 @@ class WebMTracksParser : public WebMParserClient { int64 track_type_; int64 track_num_; + std::string codec_id_; + std::vector<uint8> codec_private_; scoped_ptr<WebMContentEncodingsClient> track_content_encodings_client_; - TextKind text_track_kind_; int64 audio_track_num_; int64 video_track_num_; @@ -66,6 +81,12 @@ class WebMTracksParser : public WebMParserClient { std::string video_encryption_key_id_; LogCB log_cb_; + WebMAudioClient audio_client_; + AudioDecoderConfig audio_decoder_config_; + + WebMVideoClient video_client_; + VideoDecoderConfig video_decoder_config_; + DISALLOW_COPY_AND_ASSIGN(WebMTracksParser); }; diff --git a/media/webm/webm_video_client.cc b/media/webm/webm_video_client.cc new file mode 100644 index 0000000..bb4b111 --- /dev/null +++ b/media/webm/webm_video_client.cc @@ -0,0 +1,154 @@ +// Copyright (c) 2013 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_video_client.h" + +#include "media/base/video_decoder_config.h" +#include "media/webm/webm_constants.h" + +namespace media { + +WebMVideoClient::WebMVideoClient(const LogCB& log_cb) + : log_cb_(log_cb) { + Reset(); +} + +WebMVideoClient::~WebMVideoClient() { +} + +void WebMVideoClient::Reset() { + pixel_width_ = -1; + pixel_height_ = -1; + crop_bottom_ = -1; + crop_top_ = -1; + crop_left_ = -1; + crop_right_ = -1; + display_width_ = -1; + display_height_ = -1; + display_unit_ = -1; +} + +bool WebMVideoClient::InitializeConfig( + const std::string& codec_id, const std::vector<uint8>& codec_private, + bool is_encrypted, VideoDecoderConfig* config) { + DCHECK(config); + + VideoCodec video_codec = kUnknownVideoCodec; + VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN; + if (codec_id == "V_VP8") { + video_codec = kCodecVP8; + profile = VP8PROFILE_MAIN; + } else { + MEDIA_LOG(log_cb_) << "Unsupported video codec_id " << codec_id; + return false; + } + + if (pixel_width_ <= 0 || pixel_height_ <= 0) + return false; + + // Set crop and display unit defaults if these elements are not present. + if (crop_bottom_ == -1) + crop_bottom_ = 0; + + if (crop_top_ == -1) + crop_top_ = 0; + + if (crop_left_ == -1) + crop_left_ = 0; + + if (crop_right_ == -1) + crop_right_ = 0; + + if (display_unit_ == -1) + display_unit_ = 0; + + gfx::Size coded_size(pixel_width_, pixel_height_); + gfx::Rect visible_rect(crop_top_, crop_left_, + pixel_width_ - (crop_left_ + crop_right_), + pixel_height_ - (crop_top_ + crop_bottom_)); + gfx::Size natural_size = coded_size; + if (display_unit_ == 0) { + if (display_width_ <= 0) + display_width_ = pixel_width_; + if (display_height_ <= 0) + display_height_ = pixel_height_; + natural_size = gfx::Size(display_width_, display_height_); + } else if (display_unit_ == 3) { + if (display_width_ <= 0 || display_height_ <= 0) + return false; + natural_size = gfx::Size(display_width_, display_height_); + } else { + MEDIA_LOG(log_cb_) << "Unsupported display unit type " << display_unit_; + return false; + } + const uint8* extra_data = NULL; + size_t extra_data_size = 0; + if (codec_private.size() > 0) { + extra_data = &codec_private[0]; + extra_data_size = codec_private.size(); + } + + config->Initialize( + video_codec, profile, VideoFrame::YV12, coded_size, + visible_rect, natural_size, extra_data, extra_data_size, + is_encrypted, true); + return config->IsValidConfig(); +} + +bool WebMVideoClient::OnUInt(int id, int64 val) { + int64* dst = NULL; + + switch (id) { + case kWebMIdPixelWidth: + dst = &pixel_width_; + break; + case kWebMIdPixelHeight: + dst = &pixel_height_; + break; + case kWebMIdPixelCropTop: + dst = &crop_top_; + break; + case kWebMIdPixelCropBottom: + dst = &crop_bottom_; + break; + case kWebMIdPixelCropLeft: + dst = &crop_left_; + break; + case kWebMIdPixelCropRight: + dst = &crop_right_; + break; + case kWebMIdDisplayWidth: + dst = &display_width_; + break; + case kWebMIdDisplayHeight: + dst = &display_height_; + break; + case kWebMIdDisplayUnit: + dst = &display_unit_; + break; + default: + return true; + } + + if (*dst != -1) { + MEDIA_LOG(log_cb_) << "Multiple values for id " << std::hex << id + << " specified (" << *dst << " and " << val << ")"; + return false; + } + + *dst = val; + return true; +} + +bool WebMVideoClient::OnBinary(int id, const uint8* data, int size) { + // Accept binary fields we don't care about for now. + return true; +} + +bool WebMVideoClient::OnFloat(int id, double val) { + // Accept float fields we don't care about for now. + return true; +} + +} // namespace media diff --git a/media/webm/webm_video_client.h b/media/webm/webm_video_client.h new file mode 100644 index 0000000..eb6be6d --- /dev/null +++ b/media/webm/webm_video_client.h @@ -0,0 +1,60 @@ +// Copyright (c) 2013 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. + +#ifndef MEDIA_WEBM_WEBM_VIDEO_CLIENT_H_ +#define MEDIA_WEBM_WEBM_VIDEO_CLIENT_H_ + +#include <string> +#include <vector> + +#include "media/base/media_log.h" +#include "media/webm/webm_parser.h" + +namespace media { +class VideoDecoderConfig; + +// Helper class used to parse a Video element inside a TrackEntry element. +class WebMVideoClient : public WebMParserClient { + public: + explicit WebMVideoClient(const LogCB& log_cb); + virtual ~WebMVideoClient(); + + // Reset this object's state so it can process a new video track element. + void Reset(); + + // Initialize |config| with the data in |codec_id|, |codec_private|, + // |is_encrypted| and the fields parsed from the last video track element this + // object was used to parse. + // Returns true if |config| was successfully initialized. + // Returns false if there was unexpected values in the provided parameters or + // video track element fields. The contents of |config| are undefined in this + // case and should not be relied upon. + bool InitializeConfig(const std::string& codec_id, + const std::vector<uint8>& codec_private, + bool is_encrypted, + VideoDecoderConfig* config); + + private: + // WebMParserClient implementation. + virtual bool OnUInt(int id, int64 val) OVERRIDE; + virtual bool OnBinary(int id, const uint8* data, int size) OVERRIDE; + virtual bool OnFloat(int id, double val) OVERRIDE; + + LogCB log_cb_; + int64 pixel_width_; + int64 pixel_height_; + int64 crop_bottom_; + int64 crop_top_; + int64 crop_left_; + int64 crop_right_; + int64 display_width_; + int64 display_height_; + int64 display_unit_; + + DISALLOW_COPY_AND_ASSIGN(WebMVideoClient); +}; + +} // namespace media + +#endif // MEDIA_WEBM_WEBM_VIDEO_CLIENT_H_ |