Make webm parser compile and unittest pass

Change-Id: Ib93fbb3eba6f0638f3aa57a9a47e73e8738792d1
This commit is contained in:
KongQun Yang 2015-10-14 16:12:10 -07:00
parent 5a4234f4da
commit 845766f69a
16 changed files with 240 additions and 232 deletions

View File

@ -69,6 +69,8 @@
'stream_info.h',
'text_track.h',
'timestamp.h',
'text_track_config.cc',
'text_track_config.h',
'video_stream_info.cc',
'video_stream_info.h',
'widevine_key_source.cc',

View File

@ -19,6 +19,7 @@ enum StreamType {
kStreamUnknown = 0,
kStreamAudio,
kStreamVideo,
kStreamText,
};
/// Abstract class holds stream information.

View File

@ -5,7 +5,6 @@
#include "packager/media/formats/webm/cluster_builder.h"
#include "packager/base/logging.h"
#include "packager/media/base/data_buffer.h"
#include "packager/media/formats/webm/webm_constants.h"
namespace edash_packager {

View File

@ -0,0 +1,69 @@
# Copyright 2015 Google Inc. All rights reserved.
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd
{
'includes': [
'../../../common.gypi',
],
'targets': [
{
'target_name': 'webm',
'type': '<(component)',
'sources': [
'webm_audio_client.cc',
'webm_audio_client.h',
'webm_cluster_parser.cc',
'webm_cluster_parser.h',
'webm_constants.cc',
'webm_constants.h',
'webm_content_encodings.cc',
'webm_content_encodings.h',
'webm_content_encodings_client.cc',
'webm_content_encodings_client.h',
'webm_crypto_helpers.cc',
'webm_crypto_helpers.h',
'webm_info_parser.cc',
'webm_info_parser.h',
'webm_parser.cc',
'webm_parser.h',
'webm_stream_parser.cc',
'webm_stream_parser.h',
'webm_tracks_parser.cc',
'webm_tracks_parser.h',
'webm_video_client.cc',
'webm_video_client.h',
'webm_webvtt_parser.cc',
'webm_webvtt_parser.h'
],
'dependencies': [
'../../base/media_base.gyp:base',
],
},
{
'target_name': 'webm_unittest',
'type': '<(gtest_target_type)',
'sources': [
'cluster_builder.cc',
'cluster_builder.h',
'opus_packet_builder.cc',
'opus_packet_builder.h',
'tracks_builder.cc',
'tracks_builder.h',
'webm_cluster_parser_unittest.cc',
'webm_content_encodings_client_unittest.cc',
'webm_parser_unittest.cc',
'webm_tracks_parser_unittest.cc',
'webm_webvtt_parser_unittest.cc',
],
'dependencies': [
'../../../testing/gtest.gyp:gtest',
'../../../testing/gmock.gyp:gmock',
'../../test/media_test.gyp:media_test_support',
'webm',
]
},
],
}

View File

@ -4,10 +4,14 @@
#include "packager/media/formats/webm/webm_audio_client.h"
#include "packager/media/base/audio_decoder_config.h"
#include "packager/media/base/channel_layout.h"
#include "packager/base/logging.h"
#include "packager/media/formats/webm/webm_constants.h"
namespace {
// Timestamps are represented in double in WebM. Convert to uint64_t in us.
const uint32_t kWebMTimeScale = 1000000u;
} // namespace
namespace edash_packager {
namespace media {
@ -24,16 +28,12 @@ void WebMAudioClient::Reset() {
output_samples_per_second_ = -1;
}
bool WebMAudioClient::InitializeConfig(
scoped_refptr<AudioStreamInfo> WebMAudioClient::GetAudioStreamInfo(
int64_t track_num,
const std::string& codec_id,
const std::vector<uint8_t>& codec_private,
int64_t seek_preroll,
int64_t codec_delay,
bool is_encrypted,
AudioDecoderConfig* config) {
DCHECK(config);
SampleFormat sample_format = kSampleFormatPlanarF32;
const std::string& language,
bool is_encrypted) {
AudioCodec audio_codec = kUnknownAudioCodec;
if (codec_id == "A_VORBIS") {
audio_codec = kCodecVorbis;
@ -41,32 +41,21 @@ bool WebMAudioClient::InitializeConfig(
audio_codec = kCodecOpus;
} else {
LOG(ERROR) << "Unsupported audio codec_id " << codec_id;
return false;
return scoped_refptr<AudioStreamInfo>();
}
if (samples_per_second_ <= 0)
return false;
return scoped_refptr<AudioStreamInfo>();
// 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) {
LOG(ERROR) << "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_;
uint32_t sampling_frequency = samples_per_second_;
// Always use 48kHz for OPUS. See the "Input Sample Rate" section of the
// spec: http://tools.ietf.org/html/draft-terriberry-oggopus-01#page-11
if (audio_codec == kCodecOpus) {
samples_per_second = 48000;
sample_format = kSampleFormatF32;
sampling_frequency = 48000;
}
const uint8_t* extra_data = NULL;
@ -76,27 +65,12 @@ bool WebMAudioClient::InitializeConfig(
extra_data_size = codec_private.size();
}
// Convert |codec_delay| from nanoseconds into frames.
int codec_delay_in_frames = 0;
if (codec_delay != -1) {
codec_delay_in_frames =
0.5 +
samples_per_second * (static_cast<double>(codec_delay) /
base::Time::kNanosecondsPerSecond);
}
config->Initialize(
audio_codec,
sample_format,
channel_layout,
samples_per_second,
extra_data,
extra_data_size,
is_encrypted,
base::TimeDelta::FromMicroseconds(
(seek_preroll != -1 ? seek_preroll : 0) / 1000),
codec_delay_in_frames);
return config->IsValidConfig();
const uint32_t kSampleSizeInBits = 4u;
return scoped_refptr<AudioStreamInfo>(new AudioStreamInfo(
track_num, kWebMTimeScale, 0, audio_codec,
AudioStreamInfo::GetCodecString(audio_codec, 0), language,
kSampleSizeInBits, channels_, sampling_frequency, extra_data,
extra_data_size, is_encrypted));
}
bool WebMAudioClient::OnUInt(int id, int64_t val) {

View File

@ -8,6 +8,8 @@
#include <string>
#include <vector>
#include "packager/base/memory/scoped_ptr.h"
#include "packager/media/base/audio_stream_info.h"
#include "packager/media/formats/webm/webm_parser.h"
namespace edash_packager {
@ -23,18 +25,18 @@ class WebMAudioClient : public WebMParserClient {
// 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,
// Create an AudioStreamInfo with the data in |track_num|, |codec_id|,
// |codec_private|, |is_encrypted| and the fields parsed from the last audio
// track element this object was used to parse.
// Returns an AudioStreamInfo scoped_refptr if successful.
// Returns an empty scoped_refptr if there was unexpected values in the
// provided parameters or audio track element fields.
scoped_refptr<AudioStreamInfo> GetAudioStreamInfo(
int64_t track_num,
const std::string& codec_id,
const std::vector<uint8_t>& codec_private,
const int64_t seek_preroll,
const int64_t codec_delay,
bool is_encrypted,
AudioDecoderConfig* config);
const std::string& language,
bool is_encrypted);
private:
// WebMParserClient implementation.

View File

@ -54,9 +54,9 @@ bool WebMCreateDecryptConfig(const uint8_t* data,
}
decrypt_config->reset(new DecryptConfig(
std::string(reinterpret_cast<const char*>(key_id), key_id_size),
counter_block,
std::vector<SubsampleEntry>()));
std::vector<uint8_t>(key_id, key_id + key_id_size),
std::vector<uint8_t>(counter_block.begin(), counter_block.end()),
frame_offset, std::vector<SubsampleEntry>()));
*data_offset = frame_offset;
return true;

View File

@ -9,7 +9,7 @@
#include "packager/base/macros.h"
#include "packager/base/memory/scoped_ptr.h"
#include "packager/media/base/decoder_buffer.h"
#include "packager/media/base/decrypt_config.h"
namespace edash_packager {
namespace media {

View File

@ -9,7 +9,7 @@
#include "packager/base/callback.h"
#include "packager/base/callback_helpers.h"
#include "packager/base/logging.h"
#include "packager/media/base/timestamp_constants.h"
#include "packager/media/base/timestamp.h"
#include "packager/media/formats/webm/webm_cluster_parser.h"
#include "packager/media/formats/webm/webm_constants.h"
#include "packager/media/formats/webm/webm_content_encodings.h"
@ -29,29 +29,18 @@ WebMStreamParser::~WebMStreamParser() {
void WebMStreamParser::Init(
const InitCB& init_cb,
const NewConfigCB& config_cb,
const NewBuffersCB& new_buffers_cb,
bool ignore_text_tracks,
const EncryptedMediaInitDataCB& encrypted_media_init_data_cb,
const NewMediaSegmentCB& new_segment_cb,
const base::Closure& end_of_segment_cb) {
const NewSampleCB& new_sample_cb,
KeySource* decryption_key_source) {
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(!encrypted_media_init_data_cb.is_null());
DCHECK(!new_segment_cb.is_null());
DCHECK(!end_of_segment_cb.is_null());
DCHECK(!new_sample_cb.is_null());
ChangeState(kParsingHeaders);
init_cb_ = init_cb;
config_cb_ = config_cb;
new_buffers_cb_ = new_buffers_cb;
ignore_text_tracks_ = ignore_text_tracks;
encrypted_media_init_data_cb_ = encrypted_media_init_data_cb;
new_segment_cb_ = new_segment_cb;
end_of_segment_cb_ = end_of_segment_cb;
new_sample_cb_ = new_sample_cb;
decryption_key_source_ = decryption_key_source;
ignore_text_tracks_ = true;
}
void WebMStreamParser::Flush() {
@ -62,7 +51,6 @@ void WebMStreamParser::Flush() {
cluster_parser_->Reset();
if (state_ == kParsingClusters) {
ChangeState(kParsingHeaders);
end_of_segment_cb_.Run();
}
}
@ -158,7 +146,6 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8_t* data, int size) {
return -1;
}
ChangeState(kParsingClusters);
new_segment_cb_.Run();
return 0;
break;
case kWebMIdSegment:
@ -196,38 +183,22 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8_t* data, int size) {
bytes_parsed += result;
double timecode_scale_in_us = info_parser.timecode_scale() / 1000.0;
InitParameters params(kInfiniteDuration());
if (info_parser.duration() > 0) {
int64_t duration_in_us = info_parser.duration() * timecode_scale_in_us;
params.duration = base::TimeDelta::FromMicroseconds(duration_in_us);
}
params.timeline_offset = info_parser.date_utc();
if (unknown_segment_size_ && (info_parser.duration() <= 0) &&
!info_parser.date_utc().is_null()) {
params.liveness = DemuxerStream::LIVENESS_LIVE;
} else if (info_parser.duration() >= 0) {
params.liveness = DemuxerStream::LIVENESS_RECORDED;
} else {
params.liveness = DemuxerStream::LIVENESS_UNKNOWN;
}
const AudioDecoderConfig& audio_config = tracks_parser.audio_decoder_config();
if (audio_config.is_encrypted())
std::vector<scoped_refptr<StreamInfo>> streams;
scoped_refptr<AudioStreamInfo> audio_stream_info =
tracks_parser.audio_stream_info();
streams.push_back(tracks_parser.audio_stream_info());
streams.back()->set_duration(duration_in_us);
if (streams.back()->is_encrypted())
OnEncryptedMediaInitData(tracks_parser.audio_encryption_key_id());
const VideoDecoderConfig& video_config = tracks_parser.video_decoder_config();
if (video_config.is_encrypted())
streams.push_back(tracks_parser.video_stream_info());
streams.back()->set_duration(duration_in_us);
if (streams.back()->is_encrypted())
OnEncryptedMediaInitData(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;
}
init_cb_.Run(streams);
cluster_parser_.reset(new WebMClusterParser(
info_parser.timecode_scale(), tracks_parser.audio_track_num(),
@ -236,10 +207,8 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8_t* data, int size) {
tracks_parser.GetVideoDefaultDuration(timecode_scale_in_us),
tracks_parser.text_tracks(), tracks_parser.ignored_tracks(),
tracks_parser.audio_encryption_key_id(),
tracks_parser.video_encryption_key_id(), audio_config.codec());
if (!init_cb_.is_null())
base::ResetAndReturn(&init_cb_).Run(params);
tracks_parser.video_encryption_key_id(), audio_stream_info->codec(),
new_sample_cb_));
return bytes_parsed;
}
@ -252,29 +221,16 @@ int WebMStreamParser::ParseCluster(const uint8_t* data, int size) {
if (bytes_parsed < 0)
return bytes_parsed;
const BufferQueue& audio_buffers = cluster_parser_->GetAudioBuffers();
const BufferQueue& video_buffers = cluster_parser_->GetVideoBuffers();
const TextBufferQueueMap& text_map = cluster_parser_->GetTextBuffers();
bool cluster_ended = cluster_parser_->cluster_ended();
if ((!audio_buffers.empty() || !video_buffers.empty() ||
!text_map.empty()) &&
!new_buffers_cb_.Run(audio_buffers, video_buffers, text_map)) {
return -1;
}
if (cluster_ended) {
ChangeState(kParsingHeaders);
end_of_segment_cb_.Run();
}
return bytes_parsed;
}
void WebMStreamParser::OnEncryptedMediaInitData(const std::string& key_id) {
std::vector<uint8_t> key_id_vector(key_id.begin(), key_id.end());
encrypted_media_init_data_cb_.Run(EmeInitDataType::WEBM, key_id_vector);
NOTIMPLEMENTED() << "WebM decryption is not implemented yet.";
}
} // namespace media

View File

@ -7,29 +7,23 @@
#include "packager/base/callback_forward.h"
#include "packager/base/memory/ref_counted.h"
#include "packager/media/base/audio_decoder_config.h"
#include "packager/media/base/byte_queue.h"
#include "packager/media/base/stream_parser.h"
#include "packager/media/base/video_decoder_config.h"
#include "packager/media/base/media_parser.h"
namespace edash_packager {
namespace media {
class WebMClusterParser;
class WebMStreamParser : public StreamParser {
class WebMStreamParser : public MediaParser {
public:
WebMStreamParser();
~WebMStreamParser() override;
// StreamParser implementation.
void Init(const InitCB& init_cb,
const NewConfigCB& config_cb,
const NewBuffersCB& new_buffers_cb,
bool ignore_text_tracks,
const EncryptedMediaInitDataCB& encrypted_media_init_data_cb,
const NewMediaSegmentCB& new_segment_cb,
const base::Closure& end_of_segment_cb) override;
const NewSampleCB& new_sample_cb,
KeySource* decryption_key_source) override;
void Flush() override;
bool Parse(const uint8_t* buf, int size) override;
@ -67,13 +61,9 @@ class WebMStreamParser : public StreamParser {
State state_;
InitCB init_cb_;
NewConfigCB config_cb_;
NewBuffersCB new_buffers_cb_;
NewSampleCB new_sample_cb_;
KeySource* decryption_key_source_;
bool ignore_text_tracks_;
EncryptedMediaInitDataCB encrypted_media_init_data_cb_;
NewMediaSegmentCB new_segment_cb_;
base::Closure end_of_segment_cb_;
bool unknown_segment_size_;

View File

@ -7,7 +7,7 @@
#include "packager/base/logging.h"
#include "packager/base/strings/string_number_conversions.h"
#include "packager/base/strings/string_util.h"
#include "packager/media/base/timestamp_constants.h"
#include "packager/media/base/timestamp.h"
#include "packager/media/formats/webm/webm_constants.h"
#include "packager/media/formats/webm/webm_content_encodings.h"
@ -30,19 +30,19 @@ static TextKind CodecIdToTextKind(const std::string& codec_id) {
return kTextNone;
}
static base::TimeDelta PrecisionCappedDefaultDuration(
static int64_t PrecisionCappedDefaultDuration(
const double timecode_scale_in_us,
const int64_t duration_in_ns) {
if (duration_in_ns <= 0)
return kNoTimestamp();
return kNoTimestamp;
int64_t mult = duration_in_ns / 1000;
mult /= timecode_scale_in_us;
if (mult == 0)
return kNoTimestamp();
return kNoTimestamp;
mult = static_cast<double>(mult) * timecode_scale_in_us;
return base::TimeDelta::FromMicroseconds(mult);
return mult;
}
WebMTracksParser::WebMTracksParser(bool ignore_text_tracks)
@ -70,10 +70,10 @@ int WebMTracksParser::Parse(const uint8_t* buf, int size) {
track_language_.clear();
audio_track_num_ = -1;
audio_default_duration_ = -1;
audio_decoder_config_ = AudioDecoderConfig();
audio_stream_info_ = nullptr;
video_track_num_ = -1;
video_default_duration_ = -1;
video_decoder_config_ = VideoDecoderConfig();
video_stream_info_ = nullptr;
text_tracks_.clear();
ignored_tracks_.clear();
@ -87,13 +87,13 @@ int WebMTracksParser::Parse(const uint8_t* buf, int size) {
return parser.IsParsingComplete() ? result : 0;
}
base::TimeDelta WebMTracksParser::GetAudioDefaultDuration(
int64_t WebMTracksParser::GetAudioDefaultDuration(
const double timecode_scale_in_us) const {
return PrecisionCappedDefaultDuration(timecode_scale_in_us,
audio_default_duration_);
}
base::TimeDelta WebMTracksParser::GetVideoDefaultDuration(
int64_t WebMTracksParser::GetVideoDefaultDuration(
const double timecode_scale_in_us) const {
return PrecisionCappedDefaultDuration(timecode_scale_in_us,
video_default_duration_);
@ -201,12 +201,12 @@ bool WebMTracksParser::OnListEnd(int id) {
}
audio_default_duration_ = default_duration_;
DCHECK(!audio_decoder_config_.IsValidConfig());
if (!audio_client_.InitializeConfig(
codec_id_, codec_private_, seek_preroll_, codec_delay_,
!audio_encryption_key_id_.empty(), &audio_decoder_config_)) {
DCHECK(!audio_stream_info_);
audio_stream_info_ = audio_client_.GetAudioStreamInfo(
audio_track_num_, codec_id_, codec_private_, track_language_,
!audio_encryption_key_id_.empty());
if (!audio_stream_info_)
return false;
}
} else {
DLOG(INFO) << "Ignoring audio track " << track_num_;
ignored_tracks_.insert(track_num_);
@ -223,12 +223,12 @@ bool WebMTracksParser::OnListEnd(int id) {
}
video_default_duration_ = default_duration_;
DCHECK(!video_decoder_config_.IsValidConfig());
if (!video_client_.InitializeConfig(
codec_id_, codec_private_, !video_encryption_key_id_.empty(),
&video_decoder_config_)) {
DCHECK(!video_stream_info_);
video_stream_info_ = video_client_.GetVideoStreamInfo(
video_track_num_, codec_id_, codec_private_,
!video_encryption_key_id_.empty());
if (!video_stream_info_)
return false;
}
} else {
DLOG(INFO) << "Ignoring video track " << track_num_;
ignored_tracks_.insert(track_num_);

View File

@ -13,9 +13,9 @@
#include "packager/base/compiler_specific.h"
#include "packager/base/memory/scoped_ptr.h"
#include "packager/base/time/time.h"
#include "packager/media/base/audio_decoder_config.h"
#include "packager/media/base/audio_stream_info.h"
#include "packager/media/base/text_track_config.h"
#include "packager/media/base/video_decoder_config.h"
#include "packager/media/base/video_stream_info.h"
#include "packager/media/formats/webm/webm_audio_client.h"
#include "packager/media/formats/webm/webm_content_encodings_client.h"
#include "packager/media/formats/webm/webm_parser.h"
@ -44,10 +44,8 @@ class WebMTracksParser : public WebMParserClient {
// video track, returns that value converted from ns to base::TimeDelta with
// precision not greater than |timecode_scale_in_us|. Defaults to
// kNoTimestamp().
base::TimeDelta GetAudioDefaultDuration(
const double timecode_scale_in_us) const;
base::TimeDelta GetVideoDefaultDuration(
const double timecode_scale_in_us) const;
int64_t GetAudioDefaultDuration(const double timecode_scale_in_us) const;
int64_t GetVideoDefaultDuration(const double timecode_scale_in_us) const;
const std::set<int64_t>& ignored_tracks() const { return ignored_tracks_; }
@ -55,16 +53,16 @@ class WebMTracksParser : public WebMParserClient {
return audio_encryption_key_id_;
}
const AudioDecoderConfig& audio_decoder_config() {
return audio_decoder_config_;
scoped_refptr<AudioStreamInfo> audio_stream_info() {
return audio_stream_info_;
}
const std::string& video_encryption_key_id() const {
return video_encryption_key_id_;
}
const VideoDecoderConfig& video_decoder_config() {
return video_decoder_config_;
scoped_refptr<VideoStreamInfo> video_stream_info() {
return video_stream_info_;
}
typedef std::map<int, TextTrackConfig> TextTracks;
@ -104,10 +102,10 @@ class WebMTracksParser : public WebMParserClient {
std::string video_encryption_key_id_;
WebMAudioClient audio_client_;
AudioDecoderConfig audio_decoder_config_;
scoped_refptr<AudioStreamInfo> audio_stream_info_;
WebMVideoClient video_client_;
VideoDecoderConfig video_decoder_config_;
scoped_refptr<VideoStreamInfo> video_stream_info_;
DISALLOW_COPY_AND_ASSIGN(WebMTracksParser);
};

View File

@ -8,8 +8,7 @@
#include <gtest/gtest.h>
#include "packager/base/logging.h"
#include "packager/media/base/channel_layout.h"
#include "packager/media/base/timestamp_constants.h"
#include "packager/media/base/timestamp.h"
#include "packager/media/formats/webm/tracks_builder.h"
#include "packager/media/formats/webm/webm_constants.h"
@ -140,20 +139,22 @@ TEST_F(WebMTracksParserTest, AudioVideoDefaultDurationUnset) {
EXPECT_LE(0, result);
EXPECT_EQ(static_cast<int>(buf.size()), result);
EXPECT_EQ(kNoTimestamp(),
EXPECT_EQ(kNoTimestamp,
parser->GetAudioDefaultDuration(kDefaultTimecodeScaleInUs));
EXPECT_EQ(kNoTimestamp(),
EXPECT_EQ(kNoTimestamp,
parser->GetVideoDefaultDuration(kDefaultTimecodeScaleInUs));
const VideoDecoderConfig& video_config = parser->video_decoder_config();
EXPECT_TRUE(video_config.IsValidConfig());
EXPECT_EQ(320, video_config.coded_size().width());
EXPECT_EQ(240, video_config.coded_size().height());
scoped_refptr<VideoStreamInfo> video_stream_info =
parser->video_stream_info();
EXPECT_TRUE(video_stream_info);
EXPECT_EQ(320u, video_stream_info->width());
EXPECT_EQ(240u, video_stream_info->height());
const AudioDecoderConfig& audio_config = parser->audio_decoder_config();
EXPECT_TRUE(audio_config.IsValidConfig());
EXPECT_EQ(CHANNEL_LAYOUT_STEREO, audio_config.channel_layout());
EXPECT_EQ(8000, audio_config.samples_per_second());
scoped_refptr<AudioStreamInfo> audio_stream_info =
parser->audio_stream_info();
EXPECT_TRUE(audio_stream_info);
EXPECT_EQ(2u, audio_stream_info->num_channels());
EXPECT_EQ(8000u, audio_stream_info->sampling_frequency());
}
TEST_F(WebMTracksParserTest, AudioVideoDefaultDurationSet) {
@ -169,14 +170,12 @@ TEST_F(WebMTracksParserTest, AudioVideoDefaultDurationSet) {
EXPECT_LE(0, result);
EXPECT_EQ(static_cast<int>(buf.size()), result);
EXPECT_EQ(base::TimeDelta::FromMicroseconds(12000),
parser->GetAudioDefaultDuration(kDefaultTimecodeScaleInUs));
EXPECT_EQ(base::TimeDelta::FromMicroseconds(985000),
EXPECT_EQ(12000, parser->GetAudioDefaultDuration(kDefaultTimecodeScaleInUs));
EXPECT_EQ(985000,
parser->GetVideoDefaultDuration(5000.0)); // 5 ms resolution
EXPECT_EQ(kNoTimestamp(), parser->GetAudioDefaultDuration(12346.0));
EXPECT_EQ(base::TimeDelta::FromMicroseconds(12345),
parser->GetAudioDefaultDuration(12345.0));
EXPECT_EQ(base::TimeDelta::FromMicroseconds(12003),
EXPECT_EQ(kNoTimestamp, parser->GetAudioDefaultDuration(12346.0));
EXPECT_EQ(12345, parser->GetAudioDefaultDuration(12345.0));
EXPECT_EQ(12003,
parser->GetAudioDefaultDuration(1000.3)); // 1.0003 ms resolution
}

View File

@ -4,9 +4,25 @@
#include "packager/media/formats/webm/webm_video_client.h"
#include "packager/media/base/video_decoder_config.h"
#include "packager/base/logging.h"
#include "packager/media/formats/webm/webm_constants.h"
namespace {
// Timestamps are represented in double in WebM. Convert to uint64_t in us.
const uint32_t kWebMTimeScale = 1000000u;
int64_t GetGreatestCommonDivisor(int64_t a, int64_t b) {
while (b) {
int64_t temp = b;
b = a % b;
a = temp;
}
return a;
}
} // namespace
namespace edash_packager {
namespace media {
@ -30,31 +46,23 @@ void WebMVideoClient::Reset() {
alpha_mode_ = -1;
}
bool WebMVideoClient::InitializeConfig(
scoped_refptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
int64_t track_num,
const std::string& codec_id,
const std::vector<uint8_t>& codec_private,
bool is_encrypted,
VideoDecoderConfig* config) {
DCHECK(config);
bool is_encrypted) {
VideoCodec video_codec = kUnknownVideoCodec;
VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN;
if (codec_id == "V_VP8") {
video_codec = kCodecVP8;
profile = VP8PROFILE_ANY;
} else if (codec_id == "V_VP9") {
video_codec = kCodecVP9;
profile = VP9PROFILE_ANY;
} else {
LOG(ERROR) << "Unsupported video codec_id " << codec_id;
return false;
return scoped_refptr<VideoStreamInfo>();
}
VideoPixelFormat format =
(alpha_mode_ == 1) ? PIXEL_FORMAT_YV12A : PIXEL_FORMAT_YV12;
if (pixel_width_ <= 0 || pixel_height_ <= 0)
return false;
return scoped_refptr<VideoStreamInfo>();
// Set crop and display unit defaults if these elements are not present.
if (crop_bottom_ == -1)
@ -72,23 +80,28 @@ bool WebMVideoClient::InitializeConfig(
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_));
uint16_t width_after_crop = pixel_width_ - (crop_left_ + crop_right_);
uint16_t height_after_crop = pixel_height_ - (crop_top_ + crop_bottom_);
if (display_unit_ == 0) {
if (display_width_ <= 0)
display_width_ = visible_rect.width();
display_width_ = width_after_crop;
if (display_height_ <= 0)
display_height_ = visible_rect.height();
display_height_ = height_after_crop;
} else if (display_unit_ == 3) {
if (display_width_ <= 0 || display_height_ <= 0)
return false;
return scoped_refptr<VideoStreamInfo>();
} else {
LOG(ERROR) << "Unsupported display unit type " << display_unit_;
return false;
return scoped_refptr<VideoStreamInfo>();
}
gfx::Size natural_size = gfx::Size(display_width_, display_height_);
// Calculate sample aspect ratio.
int64_t sar_x = display_width_ * height_after_crop;
int64_t sar_y = display_height_ * width_after_crop;
int64_t gcd = GetGreatestCommonDivisor(sar_x, sar_y);
sar_x /= gcd;
sar_y /= gcd;
const uint8_t* extra_data = NULL;
size_t extra_data_size = 0;
if (codec_private.size() > 0) {
@ -96,10 +109,11 @@ bool WebMVideoClient::InitializeConfig(
extra_data_size = codec_private.size();
}
config->Initialize(video_codec, profile, format, COLOR_SPACE_HD_REC709,
coded_size, visible_rect, natural_size, extra_data,
extra_data_size, is_encrypted);
return config->IsValidConfig();
return scoped_refptr<VideoStreamInfo>(
new VideoStreamInfo(track_num, kWebMTimeScale, 0, video_codec,
VideoStreamInfo::GetCodecString(video_codec, 0, 0, 0),
"", width_after_crop, height_after_crop, sar_x, sar_y,
0, 0, extra_data, extra_data_size, is_encrypted));
}
bool WebMVideoClient::OnUInt(int id, int64_t val) {

View File

@ -8,6 +8,8 @@
#include <string>
#include <vector>
#include "packager/base/memory/scoped_ptr.h"
#include "packager/media/base/video_stream_info.h"
#include "packager/media/formats/webm/webm_parser.h"
namespace edash_packager {
@ -23,17 +25,17 @@ class WebMVideoClient : public WebMParserClient {
// 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,
// Create a VideoStreamInfo with the data in |track_num|, |codec_id|,
// |codec_private|, |is_encrypted| and the fields parsed from the last video
// track element this object was used to parse.
// Returns a VideoStreamInfo scoped_refptr if successful.
// Returns an empty scoped_refptr if there was unexpected values in the
// provided parameters or video track element fields.
scoped_refptr<VideoStreamInfo> GetVideoStreamInfo(
int64_t track_num,
const std::string& codec_id,
const std::vector<uint8_t>& codec_private,
bool is_encrypted,
VideoDecoderConfig* config);
bool is_encrypted);
private:
// WebMParserClient implementation.

View File

@ -38,6 +38,7 @@
'media/formats/mp2t/mp2t.gyp:mp2t',
'media/formats/mp4/mp4.gyp:mp4',
'media/formats/mpeg/mpeg.gyp:mpeg',
'media/formats/webm/webm.gyp:webm',
'media/formats/wvm/wvm.gyp:wvm',
'mpd/mpd.gyp:mpd_builder',
'third_party/boringssl/boringssl.gyp:boringssl',
@ -97,6 +98,7 @@
'media/filters/filters.gyp:filters_unittest',
'media/formats/mp2t/mp2t.gyp:mp2t_unittest',
'media/formats/mp4/mp4.gyp:mp4_unittest',
'media/formats/webm/webm.gyp:webm_unittest',
'media/formats/wvm/wvm.gyp:wvm_unittest',
'mpd/mpd.gyp:mpd_unittest',
'packager_test',