Make webm parser compile and unittest pass
Change-Id: Ib93fbb3eba6f0638f3aa57a9a47e73e8738792d1
This commit is contained in:
parent
5a4234f4da
commit
845766f69a
|
@ -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',
|
||||
|
|
|
@ -19,6 +19,7 @@ enum StreamType {
|
|||
kStreamUnknown = 0,
|
||||
kStreamAudio,
|
||||
kStreamVideo,
|
||||
kStreamText,
|
||||
};
|
||||
|
||||
/// Abstract class holds stream information.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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',
|
||||
]
|
||||
},
|
||||
],
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
const std::vector<uint8_t>& codec_private,
|
||||
const int64_t seek_preroll,
|
||||
const int64_t codec_delay,
|
||||
bool is_encrypted,
|
||||
AudioDecoderConfig* config);
|
||||
// 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 std::string& language,
|
||||
bool is_encrypted);
|
||||
|
||||
private:
|
||||
// WebMParserClient implementation.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
int64_t duration_in_us = info_parser.duration() * timecode_scale_in_us;
|
||||
|
||||
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
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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_);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
const std::vector<uint8_t>& codec_private,
|
||||
bool is_encrypted,
|
||||
VideoDecoderConfig* config);
|
||||
// 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);
|
||||
|
||||
private:
|
||||
// WebMParserClient implementation.
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue