Implemented WebM VP9 subsample encryption and decryption.

Change-Id: I98f02c05ec8bcc976e01ff41478e92b8809c0076
This commit is contained in:
Thomas Inskip 2016-07-26 17:51:08 -07:00
parent 336ea5cb34
commit db92c9a22b
48 changed files with 534 additions and 561 deletions

View File

@ -50,4 +50,5 @@ DEFINE_string(temp_dir,
"",
"Specify a directory in which to store temporary (intermediate) "
" files. Used only if single_segment=true.");
DEFINE_bool(webm_subsample_encryption, true,
"Enable WebM subsample encryption.");

View File

@ -20,5 +20,6 @@ DECLARE_double(fragment_duration);
DECLARE_bool(fragment_sap_aligned);
DECLARE_int32(num_subsegments_per_sidx);
DECLARE_string(temp_dir);
DECLARE_bool(webm_subsample_encryption);
#endif // APP_MUXER_FLAGS_H_

View File

@ -154,7 +154,7 @@ bool GetMuxerOptions(MuxerOptions* muxer_options) {
muxer_options->segment_sap_aligned = FLAGS_segment_sap_aligned;
muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned;
muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx;
muxer_options->webm_subsample_encryption = FLAGS_webm_subsample_encryption;
if (FLAGS_mp4_use_decoding_timestamp_in_timeline) {
LOG(WARNING) << "Flag --mp4_use_decoding_timestamp_in_timeline is set. "
"Note that it is a temporary hack to workaround Chromium "

View File

@ -195,6 +195,16 @@ class PackagerAppTest(unittest.TestCase):
self._VerifyDecryption(self.output[0], 'bear-640x360-a-golden.mp4')
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
def testPackageWithWebmSubsampleEncryption(self):
self.packager.Package(
self._GetStreams(['video'],
output_format='webm',
test_files=['bear-640x360-vp9-altref.webm']),
self._GetFlags(encryption=True))
self._DiffGold(self.output[0], 'bear-640x360-vp9-altref-enc-golden.webm')
self._VerifyDecryption(self.output[0],
'bear-640x360-vp9-altref-dec-golden.webm')
def testPackageAvcTsWithEncryption(self):
# Currently we only support live packaging for ts.
self.packager.Package(

Binary file not shown.

Binary file not shown.

View File

@ -17,8 +17,8 @@ namespace shaka {
namespace media {
namespace {
std::string AudioCodecToString(AudioCodec audio_codec) {
switch (audio_codec) {
std::string AudioCodecToString(Codec codec) {
switch (codec) {
case kCodecAAC:
return "AAC";
case kCodecAC3:
@ -42,38 +42,22 @@ std::string AudioCodecToString(AudioCodec audio_codec) {
case kCodecVorbis:
return "Vorbis";
default:
NOTIMPLEMENTED() << "Unknown Audio Codec: " << audio_codec;
return "UnknownAudioCodec";
NOTIMPLEMENTED() << "Unknown Audio Codec: " << codec;
return "UnknownCodec";
}
}
} // namespace
AudioStreamInfo::AudioStreamInfo(int track_id,
uint32_t time_scale,
uint64_t duration,
AudioCodec codec,
const std::string& codec_string,
const std::string& language,
uint8_t sample_bits,
uint8_t num_channels,
uint32_t sampling_frequency,
uint64_t seek_preroll_ns,
uint64_t codec_delay_ns,
uint32_t max_bitrate,
uint32_t avg_bitrate,
const uint8_t* codec_config,
size_t codec_config_size,
bool is_encrypted)
: StreamInfo(kStreamAudio,
track_id,
time_scale,
duration,
codec_string,
language,
codec_config,
codec_config_size,
AudioStreamInfo::AudioStreamInfo(
int track_id, uint32_t time_scale, uint64_t duration, Codec codec,
const std::string& codec_string, const uint8_t* codec_config,
size_t codec_config_size, uint8_t sample_bits, uint8_t num_channels,
uint32_t sampling_frequency, uint64_t seek_preroll_ns,
uint64_t codec_delay_ns, uint32_t max_bitrate, uint32_t avg_bitrate,
const std::string& language, bool is_encrypted)
: StreamInfo(kStreamAudio, track_id, time_scale, duration, codec,
codec_string, codec_config, codec_config_size, language,
is_encrypted),
codec_(codec),
sample_bits_(sample_bits),
num_channels_(num_channels),
sampling_frequency_(sampling_frequency),
@ -85,10 +69,9 @@ AudioStreamInfo::AudioStreamInfo(int track_id,
AudioStreamInfo::~AudioStreamInfo() {}
bool AudioStreamInfo::IsValidConfig() const {
return codec_ != kUnknownAudioCodec && num_channels_ != 0 &&
return codec() != kUnknownCodec && num_channels_ != 0 &&
num_channels_ <= limits::kMaxChannels && sample_bits_ > 0 &&
sample_bits_ <= limits::kMaxBitsPerSample &&
sampling_frequency_ > 0 &&
sample_bits_ <= limits::kMaxBitsPerSample && sampling_frequency_ > 0 &&
sampling_frequency_ <= limits::kMaxSampleRate;
}
@ -96,7 +79,7 @@ std::string AudioStreamInfo::ToString() const {
std::string str = base::StringPrintf(
"%s codec: %s\n sample_bits: %d\n num_channels: %d\n "
"sampling_frequency: %d\n language: %s\n",
StreamInfo::ToString().c_str(), AudioCodecToString(codec_).c_str(),
StreamInfo::ToString().c_str(), AudioCodecToString(codec()).c_str(),
sample_bits_, num_channels_, sampling_frequency_, language().c_str());
if (seek_preroll_ns_ != 0) {
base::StringAppendF(&str, " seek_preroll_ns: %" PRIu64 "\n",
@ -109,7 +92,7 @@ std::string AudioStreamInfo::ToString() const {
return str;
}
std::string AudioStreamInfo::GetCodecString(AudioCodec codec,
std::string AudioStreamInfo::GetCodecString(Codec codec,
uint8_t audio_object_type) {
switch (codec) {
case kCodecVorbis:

View File

@ -14,42 +14,17 @@
namespace shaka {
namespace media {
enum AudioCodec {
kUnknownAudioCodec = 0,
kCodecAAC,
kCodecAC3,
kCodecDTSC,
kCodecDTSE,
kCodecDTSH,
kCodecDTSL,
kCodecDTSM,
kCodecDTSP,
kCodecEAC3,
kCodecOpus,
kCodecVorbis,
kNumAudioCodec
};
/// Holds audio stream information.
class AudioStreamInfo : public StreamInfo {
public:
/// Construct an initialized audio stream info object.
AudioStreamInfo(int track_id,
uint32_t time_scale,
uint64_t duration,
AudioCodec codec,
const std::string& codec_string,
const std::string& language,
uint8_t sample_bits,
uint8_t num_channels,
uint32_t sampling_frequency,
uint64_t seek_preroll_ns,
uint64_t codec_delay_ns,
uint32_t max_bitrate,
uint32_t avg_bitrate,
const uint8_t* codec_config,
size_t codec_config_size,
AudioStreamInfo(int track_id, uint32_t time_scale, uint64_t duration,
Codec codec, const std::string& codec_string,
const uint8_t* codec_config, size_t codec_config_size,
uint8_t sample_bits, uint8_t num_channels,
uint32_t sampling_frequency, uint64_t seek_preroll_ns,
uint64_t codec_delay_ns, uint32_t max_bitrate,
uint32_t avg_bitrate, const std::string& language,
bool is_encrypted);
/// @name StreamInfo implementation overrides.
@ -58,7 +33,6 @@ class AudioStreamInfo : public StreamInfo {
std::string ToString() const override;
/// @}
AudioCodec codec() const { return codec_; }
uint8_t sample_bits() const { return sample_bits_; }
uint8_t sample_bytes() const { return sample_bits_ / 8; }
uint8_t num_channels() const { return num_channels_; }
@ -71,20 +45,17 @@ class AudioStreamInfo : public StreamInfo {
uint32_t max_bitrate() const { return max_bitrate_; }
uint32_t avg_bitrate() const { return avg_bitrate_; }
void set_codec(AudioCodec codec) { codec_ = codec; }
void set_sampling_frequency(const uint32_t sampling_frequency) {
sampling_frequency_ = sampling_frequency;
}
/// @param audio_object_type is only used by AAC Codec, ignored otherwise.
/// @return The codec string.
static std::string GetCodecString(AudioCodec codec,
uint8_t audio_object_type);
static std::string GetCodecString(Codec codec, uint8_t audio_object_type);
private:
~AudioStreamInfo() override;
AudioCodec codec_;
uint8_t sample_bits_;
uint8_t num_channels_;
uint32_t sampling_frequency_;

View File

@ -17,7 +17,8 @@ MuxerOptions::MuxerOptions()
fragment_sap_aligned(false),
num_subsegments_per_sidx(0),
mp4_use_decoding_timestamp_in_timeline(false),
bandwidth(0) {}
bandwidth(0),
webm_subsample_encryption(true) {}
MuxerOptions::~MuxerOptions() {}
} // namespace media

View File

@ -73,6 +73,9 @@ struct MuxerOptions {
/// User-specified bit rate for the media stream. If zero, the muxer will
/// attempt to estimate.
uint32_t bandwidth;
// Enable/disable subsample encryption for WebM containers.
bool webm_subsample_encryption;
};
} // namespace media

View File

@ -14,19 +14,16 @@
namespace shaka {
namespace media {
StreamInfo::StreamInfo(StreamType stream_type,
int track_id,
uint32_t time_scale,
uint64_t duration,
StreamInfo::StreamInfo(StreamType stream_type, int track_id,
uint32_t time_scale, uint64_t duration, Codec codec,
const std::string& codec_string,
const std::string& language,
const uint8_t* codec_config,
size_t codec_config_size,
bool is_encrypted)
const uint8_t* codec_config, size_t codec_config_size,
const std::string& language, bool is_encrypted)
: stream_type_(stream_type),
track_id_(track_id),
time_scale_(time_scale),
duration_(duration),
codec_(codec),
codec_string_(codec_string),
language_(language),
is_encrypted_(is_encrypted) {

View File

@ -22,18 +22,40 @@ enum StreamType {
kStreamText,
};
enum Codec {
kUnknownCodec = 0,
kCodecH264,
kCodecHEV1,
kCodecHVC1,
kCodecVC1,
kCodecMPEG2,
kCodecMPEG4,
kCodecTheora,
kCodecVP8,
kCodecVP9,
kCodecVP10,
kCodecAAC,
kCodecAC3,
kCodecDTSC,
kCodecDTSE,
kCodecDTSH,
kCodecDTSL,
kCodecDTSM,
kCodecDTSP,
kCodecEAC3,
kCodecOpus,
kCodecVorbis,
kCodecText,
kNumCodec
};
/// Abstract class holds stream information.
class StreamInfo : public base::RefCountedThreadSafe<StreamInfo> {
public:
StreamInfo(StreamType stream_type,
int track_id,
uint32_t time_scale,
uint64_t duration,
const std::string& codec_string,
const std::string& language,
const uint8_t* codec_config,
size_t codec_config_size,
bool is_encrypted);
StreamInfo(StreamType stream_type, int track_id, uint32_t time_scale,
uint64_t duration, Codec codec, const std::string& codec_string,
const uint8_t* codec_config, size_t codec_config_size,
const std::string& language, bool is_encrypted);
/// @return true if this object has appropriate configuration values, false
/// otherwise.
@ -46,21 +68,18 @@ class StreamInfo : public base::RefCountedThreadSafe<StreamInfo> {
uint32_t track_id() const { return track_id_; }
uint32_t time_scale() const { return time_scale_; }
uint64_t duration() const { return duration_; }
Codec codec() const { return codec_; }
const std::string& codec_string() const { return codec_string_; }
const std::vector<uint8_t>& codec_config() const { return codec_config_; }
const std::string& language() const { return language_; }
bool is_encrypted() const { return is_encrypted_; }
const std::vector<uint8_t>& codec_config() const { return codec_config_; }
void set_duration(int duration) { duration_ = duration; }
void set_codec(Codec codec) { codec_ = codec; }
void set_codec_config(const std::vector<uint8_t>& data) { codec_config_ = data; }
void set_codec_string(const std::string& codec_string) {
codec_string_ = codec_string;
}
void set_language(const std::string& language) { language_ = language; }
protected:
@ -75,6 +94,7 @@ class StreamInfo : public base::RefCountedThreadSafe<StreamInfo> {
uint32_t time_scale_;
// Duration base on time_scale.
uint64_t duration_;
Codec codec_;
std::string codec_string_;
std::string language_;
// Whether the stream is potentially encrypted.

View File

@ -9,23 +9,15 @@
namespace shaka {
namespace media {
TextStreamInfo::TextStreamInfo(int track_id,
uint32_t time_scale,
TextStreamInfo::TextStreamInfo(int track_id, uint32_t time_scale,
uint64_t duration,
const std::string& codec_string,
const std::string& language,
const std::string& codec_config,
uint16_t width,
uint16_t height)
: StreamInfo(kStreamText,
track_id,
time_scale,
duration,
const std::string& codec_config, uint16_t width,
uint16_t height, const std::string& language)
: StreamInfo(kStreamText, track_id, time_scale, duration, kCodecText,
codec_string,
language,
reinterpret_cast<const uint8_t*>(codec_config.data()),
codec_config.size(),
false),
codec_config.size(), language, false),
width_(width),
height_(height) {}

View File

@ -21,20 +21,16 @@ class TextStreamInfo : public StreamInfo {
/// @param time_scale is the time scale of this stream.
/// @param duration is the duration of this stream.
/// @param codec_string is the codec.
/// @param language is the language of this stream. This may be empty.
/// @param codec_config is configuration for this text stream. This could be
/// the metadata that applies to all the samples of this stream. This
/// may be empty.
/// @param width of the text. This may be 0.
/// @param height of the text. This may be 0.
TextStreamInfo(int track_id,
uint32_t time_scale,
uint64_t duration,
/// @param language is the language of this stream. This may be empty.
TextStreamInfo(int track_id, uint32_t time_scale, uint64_t duration,
const std::string& codec_string,
const std::string& language,
const std::string& codec_config,
uint16_t width,
uint16_t height);
const std::string& codec_config, uint16_t width,
uint16_t height, const std::string& language);
bool IsValidConfig() const override;

View File

@ -17,8 +17,8 @@ namespace shaka {
namespace media {
namespace {
std::string VideoCodecToString(VideoCodec video_codec) {
switch (video_codec) {
std::string VideoCodecToString(Codec codec) {
switch (codec) {
case kCodecH264:
return "H264";
case kCodecHEV1:
@ -40,52 +40,35 @@ std::string VideoCodecToString(VideoCodec video_codec) {
case kCodecVP10:
return "VP10";
default:
NOTIMPLEMENTED() << "Unknown Video Codec: " << video_codec;
return "UnknownVideoCodec";
NOTIMPLEMENTED() << "Unknown Video Codec: " << codec;
return "UnknownCodec";
}
}
} // namespace
VideoStreamInfo::VideoStreamInfo(int track_id,
uint32_t time_scale,
uint64_t duration,
VideoCodec codec,
const std::string& codec_string,
const std::string& language,
uint16_t width,
uint16_t height,
uint32_t pixel_width,
uint32_t pixel_height,
int16_t trick_play_rate,
uint8_t nalu_length_size,
const uint8_t* codec_config,
size_t codec_config_size,
bool is_encrypted)
: StreamInfo(kStreamVideo,
track_id,
time_scale,
duration,
codec_string,
language,
codec_config,
codec_config_size,
VideoStreamInfo::VideoStreamInfo(
int track_id, uint32_t time_scale, uint64_t duration, Codec codec,
const std::string& codec_string, const uint8_t* codec_config,
size_t codec_config_size, uint16_t width, uint16_t height,
uint32_t pixel_width, uint32_t pixel_height, int16_t trick_play_rate,
uint8_t nalu_length_size, const std::string& language, bool is_encrypted)
: StreamInfo(kStreamVideo, track_id, time_scale, duration, codec,
codec_string, codec_config, codec_config_size, language,
is_encrypted),
codec_(codec),
width_(width),
height_(height),
pixel_width_(pixel_width),
pixel_height_(pixel_height),
trick_play_rate_(trick_play_rate),
nalu_length_size_(nalu_length_size) {
}
nalu_length_size_(nalu_length_size) {}
VideoStreamInfo::~VideoStreamInfo() {}
bool VideoStreamInfo::IsValidConfig() const {
return codec_ != kUnknownVideoCodec &&
width_ > 0 && width_ <= limits::kMaxDimension &&
height_ > 0 && height_ <= limits::kMaxDimension &&
return codec() != kUnknownCodec && width_ > 0 &&
width_ <= limits::kMaxDimension && height_ > 0 &&
height_ <= limits::kMaxDimension &&
(nalu_length_size_ <= 2 || nalu_length_size_ == 4);
}
@ -93,7 +76,7 @@ std::string VideoStreamInfo::ToString() const {
return base::StringPrintf(
"%s codec: %s\n width: %d\n height: %d\n pixel_aspect_ratio: %d:%d\n "
"trick_play_rate: %d\n nalu_length_size: %d\n",
StreamInfo::ToString().c_str(), VideoCodecToString(codec_).c_str(),
StreamInfo::ToString().c_str(), VideoCodecToString(codec()).c_str(),
width_, height_, pixel_width_, pixel_height_, trick_play_rate_,
nalu_length_size_);
}

View File

@ -12,41 +12,18 @@
namespace shaka {
namespace media {
enum VideoCodec {
kUnknownVideoCodec = 0,
kCodecH264,
kCodecHEV1,
kCodecHVC1,
kCodecVC1,
kCodecMPEG2,
kCodecMPEG4,
kCodecTheora,
kCodecVP8,
kCodecVP9,
kCodecVP10,
kNumVideoCodec
};
/// Holds video stream information.
class VideoStreamInfo : public StreamInfo {
public:
/// Construct an initialized video stream info object.
/// @param pixel_width is the width of the pixel. 0 if unknown.
/// @param pixel_height is the height of the pixels. 0 if unknown.
VideoStreamInfo(int track_id,
uint32_t time_scale,
uint64_t duration,
VideoCodec codec,
const std::string& codec_string,
const std::string& language,
uint16_t width,
uint16_t height,
uint32_t pixel_width,
uint32_t pixel_height,
int16_t trick_play_rate,
uint8_t nalu_length_size,
const uint8_t* codec_config,
size_t codec_config_size,
VideoStreamInfo(int track_id, uint32_t time_scale, uint64_t duration,
Codec codec, const std::string& codec_string,
const uint8_t* codec_config, size_t codec_config_size,
uint16_t width, uint16_t height, uint32_t pixel_width,
uint32_t pixel_height, int16_t trick_play_rate,
uint8_t nalu_length_size, const std::string& language,
bool is_encrypted);
/// @name StreamInfo implementation overrides.
@ -55,7 +32,6 @@ class VideoStreamInfo : public StreamInfo {
std::string ToString() const override;
/// @}
VideoCodec codec() const { return codec_; }
uint16_t width() const { return width_; }
uint16_t height() const { return height_; }
/// Returns the pixel width.
@ -67,7 +43,6 @@ class VideoStreamInfo : public StreamInfo {
uint8_t nalu_length_size() const { return nalu_length_size_; }
int16_t trick_play_rate() const { return trick_play_rate_; }
void set_codec(VideoCodec codec) { codec_ = codec; }
void set_width(uint32_t width) { width_ = width; }
void set_height(uint32_t height) { height_ = height; }
void set_pixel_width(uint32_t pixel_width) { pixel_width_ = pixel_width; }
@ -76,7 +51,6 @@ class VideoStreamInfo : public StreamInfo {
private:
~VideoStreamInfo() override;
VideoCodec codec_;
uint16_t width_;
uint16_t height_;

View File

@ -59,7 +59,7 @@ std::string ReverseBitsAndHexEncode(uint32_t x) {
return TrimLeadingZeros(base::HexEncode(bytes, arraysize(bytes)));
}
std::string CodecAsString(VideoCodec codec) {
std::string CodecAsString(Codec codec) {
switch (codec) {
case kCodecHEV1:
return "hev1";
@ -132,8 +132,7 @@ bool HEVCDecoderConfigurationRecord::ParseInternal() {
return true;
}
std::string HEVCDecoderConfigurationRecord::GetCodecString(
VideoCodec codec) const {
std::string HEVCDecoderConfigurationRecord::GetCodecString(Codec codec) const {
// ISO/IEC 14496-15:2014 Annex E.
std::vector<std::string> fields;
fields.push_back(CodecAsString(codec));

View File

@ -25,7 +25,7 @@ class HEVCDecoderConfigurationRecord : public DecoderConfigurationRecord {
~HEVCDecoderConfigurationRecord() override;
/// @return The codec string.
std::string GetCodecString(VideoCodec codec) const;
std::string GetCodecString(Codec codec) const;
private:
bool ParseInternal() override;

View File

@ -24,7 +24,7 @@ enum VP9CodecFeatures {
kFeatureChromaSubsampling = 4,
};
std::string VPCodecAsString(VideoCodec codec) {
std::string VPCodecAsString(Codec codec) {
switch (codec) {
case kCodecVP8:
return "vp08";
@ -205,7 +205,7 @@ void VPCodecConfigurationRecord::WriteWebM(std::vector<uint8_t>* data) const {
writer.SwapBuffer(data);
}
std::string VPCodecConfigurationRecord::GetCodecString(VideoCodec codec) const {
std::string VPCodecConfigurationRecord::GetCodecString(Codec codec) const {
const std::string fields[] = {
base::IntToString(profile_),
base::IntToString(level_),

View File

@ -68,7 +68,7 @@ class VPCodecConfigurationRecord {
void WriteWebM(std::vector<uint8_t>* data) const;
/// @return The codec string.
std::string GetCodecString(VideoCodec codec) const;
std::string GetCodecString(Codec codec) const;
// Merges the values from the given configuration. If there are values in
// both |*this| and |other|, the values in |other| take precedence.

View File

@ -16,29 +16,19 @@ VideoStreamInfoParameters::~VideoStreamInfoParameters() {}
scoped_refptr<StreamInfo> CreateVideoStreamInfo(
const VideoStreamInfoParameters& param) {
return scoped_refptr<StreamInfo>(
new VideoStreamInfo(param.track_id,
param.time_scale,
param.duration,
param.codec,
param.codec_string,
param.language,
param.width,
param.height,
param.pixel_width,
param.pixel_height,
0, // trick_play_rate
param.nalu_length_size,
param.codec_config.data(),
param.codec_config.size(),
param.is_encrypted));
return scoped_refptr<StreamInfo>(new VideoStreamInfo(
param.track_id, param.time_scale, param.duration, param.codec,
param.codec_string, param.codec_config.data(), param.codec_config.size(),
param.width, param.height, param.pixel_width, param.pixel_height,
0, // trick_play_rate
param.nalu_length_size, param.language, param.is_encrypted));
}
VideoStreamInfoParameters GetDefaultVideoStreamInfoParams() {
const int kTrackId = 0;
const uint32_t kTimeScale = 10;
const uint64_t kVideoStreamDuration = 200;
const VideoCodec kH264Codec = kCodecH264;
const Codec kH264Codec = kCodecH264;
const char* kCodecString = "avc1.010101";
const char* kLanuageUndefined = "und";
const uint16_t kWidth = 720;

View File

@ -60,7 +60,7 @@ struct VideoStreamInfoParameters {
int track_id;
uint32_t time_scale;
uint64_t duration;
VideoCodec codec;
Codec codec;
std::string codec_string;
std::string language;
uint16_t width;

View File

@ -221,25 +221,13 @@ bool EsParserAdts::UpdateAudioConfiguration(const uint8_t* adts_frame,
? std::min(2 * samples_per_second, 48000)
: samples_per_second;
last_audio_decoder_config_ = scoped_refptr<StreamInfo>(
new AudioStreamInfo(
pid(),
kMpeg2Timescale,
kInfiniteDuration,
kCodecAAC,
AudioStreamInfo::GetCodecString(kCodecAAC,
adts_header.GetObjectType()),
std::string(),
kAacSampleSizeBits,
adts_header.GetNumChannels(),
extended_samples_per_second,
0 /* seek preroll */,
0 /* codec delay */,
0 /* max bitrate */,
0 /* avg bitrate */,
audio_specific_config.data(),
audio_specific_config.size(),
false));
last_audio_decoder_config_ = scoped_refptr<StreamInfo>(new AudioStreamInfo(
pid(), kMpeg2Timescale, kInfiniteDuration, kCodecAAC,
AudioStreamInfo::GetCodecString(kCodecAAC, adts_header.GetObjectType()),
audio_specific_config.data(), audio_specific_config.size(),
kAacSampleSizeBits, adts_header.GetNumChannels(),
extended_samples_per_second, 0 /* seek preroll */, 0 /* codec delay */,
0 /* max bitrate */, 0 /* avg bitrate */, std::string(), false));
DVLOG(1) << "Sampling frequency: " << samples_per_second;
DVLOG(1) << "Extended sampling frequency: " << extended_samples_per_second;

View File

@ -148,9 +148,10 @@ bool EsParserH264::UpdateVideoDecoderConfig(int pps_id) {
AVCDecoderConfigurationRecord::GetCodecString(decoder_config_record[1],
decoder_config_record[2],
decoder_config_record[3]),
std::string(), coded_width, coded_height, pixel_width, pixel_height, 0,
H264ByteToUnitStreamConverter::kUnitStreamNaluLengthSize,
decoder_config_record.data(), decoder_config_record.size(), false));
decoder_config_record.data(), decoder_config_record.size(), coded_width,
coded_height, pixel_width, pixel_height, 0,
H264ByteToUnitStreamConverter::kUnitStreamNaluLengthSize, std::string(),
false));
DVLOG(1) << "Profile IDC: " << sps->profile_idc;
DVLOG(1) << "Level IDC: " << sps->level_idc;
DVLOG(1) << "log2_max_frame_num_minus4: " << sps->log2_max_frame_num_minus4;

View File

@ -148,23 +148,12 @@ bool EsParserH265::UpdateVideoDecoderConfig(int pps_id) {
return false;
}
last_video_decoder_config_ = scoped_refptr<StreamInfo>(
new VideoStreamInfo(
pid(),
kMpeg2Timescale,
kInfiniteDuration,
kCodecHVC1,
decoder_config.GetCodecString(kCodecHVC1),
std::string(),
coded_width,
coded_height,
pixel_width,
pixel_height,
0,
H26xByteToUnitStreamConverter::kUnitStreamNaluLengthSize,
decoder_config_record.data(),
decoder_config_record.size(),
false));
last_video_decoder_config_ = scoped_refptr<StreamInfo>(new VideoStreamInfo(
pid(), kMpeg2Timescale, kInfiniteDuration, kCodecHVC1,
decoder_config.GetCodecString(kCodecHVC1), decoder_config_record.data(),
decoder_config_record.size(), coded_width, coded_height, pixel_width,
pixel_height, 0, H26xByteToUnitStreamConverter::kUnitStreamNaluLengthSize,
std::string(), false));
// Video config notification.
new_stream_info_cb_.Run(last_video_decoder_config_);

View File

@ -97,7 +97,7 @@ bool PesPacketGenerator::Initialize(const StreamInfo& stream_info) {
if (stream_type_ == kStreamVideo) {
const VideoStreamInfo& video_stream_info =
static_cast<const VideoStreamInfo&>(stream_info);
if (video_stream_info.codec() != VideoCodec::kCodecH264) {
if (video_stream_info.codec() != Codec::kCodecH264) {
NOTIMPLEMENTED() << "Video codec " << video_stream_info.codec()
<< " is not supported.";
return false;
@ -110,7 +110,7 @@ bool PesPacketGenerator::Initialize(const StreamInfo& stream_info) {
} else if (stream_type_ == kStreamAudio) {
const AudioStreamInfo& audio_stream_info =
static_cast<const AudioStreamInfo&>(stream_info);
if (audio_stream_info.codec() != AudioCodec::kCodecAAC) {
if (audio_stream_info.codec() != Codec::kCodecAAC) {
NOTIMPLEMENTED() << "Audio codec " << audio_stream_info.codec()
<< " is not supported yet.";
return false;

View File

@ -34,10 +34,10 @@ const uint8_t kAnyData[] = {
const bool kIsKeyFrame = true;
// Only {Audio,Video}Codec and extra data matter for this test. Other values are
// Only Codec and extra data matter for this test. Other values are
// bogus.
const VideoCodec kH264VideoCodec = VideoCodec::kCodecH264;
const AudioCodec kAacAudioCodec = AudioCodec::kCodecAAC;
const Codec kH264Codec = Codec::kCodecH264;
const Codec kAacCodec = Codec::kCodecAAC;
// TODO(rkuroiwa): It might make sense to inject factory functions to create
// NalUnitToByteStreamConverter and AACAudioSpecificConfig so that these
@ -102,20 +102,19 @@ class MockAACAudioSpecificConfig : public AACAudioSpecificConfig {
MOCK_CONST_METHOD1(ConvertToADTS, bool(std::vector<uint8_t>* buffer));
};
scoped_refptr<VideoStreamInfo> CreateVideoStreamInfo(VideoCodec codec) {
scoped_refptr<VideoStreamInfo> CreateVideoStreamInfo(Codec codec) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, codec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kVideoExtraData, arraysize(kVideoExtraData),
kIsEncrypted));
kTrackId, kTimeScale, kDuration, codec, kCodecString, kVideoExtraData,
arraysize(kVideoExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
return stream_info;
}
scoped_refptr<AudioStreamInfo> CreateAudioStreamInfo(AudioCodec codec) {
scoped_refptr<AudioStreamInfo> CreateAudioStreamInfo(Codec codec) {
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, codec, kCodecString, kLanguage,
kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay,
kMaxBitrate, kAverageBitrate, kAudioExtraData, arraysize(kAudioExtraData),
kTrackId, kTimeScale, kDuration, codec, kCodecString, kAudioExtraData,
arraysize(kAudioExtraData), kSampleBits, kNumChannels, kSamplingFrequency,
kSeekPreroll, kCodecDelay, kMaxBitrate, kAverageBitrate, kLanguage,
kIsEncrypted));
return stream_info;
}
@ -140,7 +139,7 @@ class PesPacketGeneratorTest : public ::testing::Test {
const uint8_t* expected_output,
size_t expected_output_size) {
scoped_refptr<VideoStreamInfo> stream_info(
CreateVideoStreamInfo(kH264VideoCodec));
CreateVideoStreamInfo(kH264Codec));
EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -189,7 +188,7 @@ class PesPacketGeneratorTest : public ::testing::Test {
const uint8_t* expected_output,
size_t expected_output_size) {
scoped_refptr<AudioStreamInfo> stream_info(
CreateAudioStreamInfo(kAacAudioCodec));
CreateAudioStreamInfo(kAacCodec));
EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -224,26 +223,24 @@ class PesPacketGeneratorTest : public ::testing::Test {
};
TEST_F(PesPacketGeneratorTest, InitializeVideo) {
scoped_refptr<VideoStreamInfo> stream_info(
CreateVideoStreamInfo(kH264VideoCodec));
scoped_refptr<VideoStreamInfo> stream_info(CreateVideoStreamInfo(kH264Codec));
EXPECT_TRUE(generator_.Initialize(*stream_info));
}
TEST_F(PesPacketGeneratorTest, InitializeVideoNonH264) {
scoped_refptr<VideoStreamInfo> stream_info(
CreateVideoStreamInfo(VideoCodec::kCodecVP9));
CreateVideoStreamInfo(Codec::kCodecVP9));
EXPECT_FALSE(generator_.Initialize(*stream_info));
}
TEST_F(PesPacketGeneratorTest, InitializeAudio) {
scoped_refptr<AudioStreamInfo> stream_info(
CreateAudioStreamInfo(kAacAudioCodec));
scoped_refptr<AudioStreamInfo> stream_info(CreateAudioStreamInfo(kAacCodec));
EXPECT_TRUE(generator_.Initialize(*stream_info));
}
TEST_F(PesPacketGeneratorTest, InitializeAudioNonAac) {
scoped_refptr<AudioStreamInfo> stream_info(
CreateAudioStreamInfo(AudioCodec::kCodecOpus));
CreateAudioStreamInfo(Codec::kCodecOpus));
EXPECT_FALSE(generator_.Initialize(*stream_info));
}
@ -251,13 +248,12 @@ TEST_F(PesPacketGeneratorTest, InitializeAudioNonAac) {
TEST_F(PesPacketGeneratorTest, InitializeTextInfo) {
scoped_refptr<TextStreamInfo> stream_info(
new TextStreamInfo(kTrackId, kTimeScale, kDuration, kCodecString,
kLanguage, std::string(), kWidth, kHeight));
std::string(), kWidth, kHeight, kLanguage));
EXPECT_FALSE(generator_.Initialize(*stream_info));
}
TEST_F(PesPacketGeneratorTest, AddVideoSample) {
scoped_refptr<VideoStreamInfo> stream_info(
CreateVideoStreamInfo(kH264VideoCodec));
scoped_refptr<VideoStreamInfo> stream_info(CreateVideoStreamInfo(kH264Codec));
EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -293,8 +289,7 @@ TEST_F(PesPacketGeneratorTest, AddVideoSample) {
}
TEST_F(PesPacketGeneratorTest, AddVideoSampleFailedToConvert) {
scoped_refptr<VideoStreamInfo> stream_info(
CreateVideoStreamInfo(kH264VideoCodec));
scoped_refptr<VideoStreamInfo> stream_info(CreateVideoStreamInfo(kH264Codec));
EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -316,8 +311,7 @@ TEST_F(PesPacketGeneratorTest, AddVideoSampleFailedToConvert) {
}
TEST_F(PesPacketGeneratorTest, AddAudioSample) {
scoped_refptr<AudioStreamInfo> stream_info(
CreateAudioStreamInfo(kAacAudioCodec));
scoped_refptr<AudioStreamInfo> stream_info(CreateAudioStreamInfo(kAacCodec));
EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -345,8 +339,7 @@ TEST_F(PesPacketGeneratorTest, AddAudioSample) {
}
TEST_F(PesPacketGeneratorTest, AddAudioSampleFailedToConvert) {
scoped_refptr<AudioStreamInfo> stream_info(
CreateAudioStreamInfo(kAacAudioCodec));
scoped_refptr<AudioStreamInfo> stream_info(CreateAudioStreamInfo(kAacCodec));
EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -368,10 +361,9 @@ TEST_F(PesPacketGeneratorTest, AddAudioSampleFailedToConvert) {
TEST_F(PesPacketGeneratorTest, TimeStampScaling) {
const uint32_t kTestTimescale = 1000;
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTestTimescale, kDuration, kH264VideoCodec, kCodecString,
kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kVideoExtraData, arraysize(kVideoExtraData),
kIsEncrypted));
kTrackId, kTestTimescale, kDuration, kH264Codec, kCodecString,
kVideoExtraData, arraysize(kVideoExtraData), kWidth, kHeight, kPixelWidth,
kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());

View File

@ -29,7 +29,7 @@ namespace {
// All data here is bogus. They are used to create VideoStreamInfo but the
// actual values don't matter at all.
const bool kIsKeyFrame = true;
const VideoCodec kH264VideoCodec = VideoCodec::kCodecH264;
const Codec kH264Codec = Codec::kCodecH264;
const uint8_t kExtraData[] = {
0x00,
};
@ -107,9 +107,9 @@ class TsSegmenterTest : public ::testing::Test {
TEST_F(TsSegmenterTest, Initialize) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options;
options.segment_template = "file$Number$.ts";
TsSegmenter segmenter(options, nullptr);
@ -127,9 +127,9 @@ TEST_F(TsSegmenterTest, Initialize) {
TEST_F(TsSegmenterTest, AddSample) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options;
options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts";
@ -182,9 +182,9 @@ TEST_F(TsSegmenterTest, PassedSegmentDuration) {
// done correctly in the segmenter.
const uint32_t kInputTimescale = 1001;
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kInputTimescale, kDuration, kH264VideoCodec, kCodecString,
kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kInputTimescale, kDuration, kH264Codec, kCodecString,
kExtraData, arraysize(kExtraData), kWidth, kHeight, kPixelWidth,
kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options;
options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts";
@ -281,9 +281,9 @@ TEST_F(TsSegmenterTest, PassedSegmentDuration) {
// Finalize right after Initialize(). The writer will not be initialized.
TEST_F(TsSegmenterTest, InitializeThenFinalize) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options;
options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts";
@ -310,9 +310,9 @@ TEST_F(TsSegmenterTest, InitializeThenFinalize) {
// writer with a mock.
TEST_F(TsSegmenterTest, Finalize) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options;
options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts";
@ -339,9 +339,9 @@ TEST_F(TsSegmenterTest, Finalize) {
// Verify that it won't finish a segment if the sample is not a key frame.
TEST_F(TsSegmenterTest, SegmentOnlyBeforeKeyFrame) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options;
options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts";
@ -445,9 +445,9 @@ TEST_F(TsSegmenterTest, SegmentOnlyBeforeKeyFrame) {
TEST_F(TsSegmenterTest, WithEncryptionNoClearLead) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options;
options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts";
@ -485,9 +485,9 @@ TEST_F(TsSegmenterTest, WithEncryptionNoClearLead) {
// not null.
TEST_F(TsSegmenterTest, WithEncryptionNoClearLeadNoMuxerListener) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options;
options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts";
@ -522,9 +522,9 @@ TEST_F(TsSegmenterTest, WithEncryptionNoClearLeadNoMuxerListener) {
// Verify that encryption notification is sent to objects after clear lead.
TEST_F(TsSegmenterTest, WithEncryptionWithClearLead) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString,
kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options;
options.segment_duration = 1.0;

View File

@ -174,7 +174,7 @@ bool TsWriter::Initialize(const StreamInfo& stream_info) {
if (stream_info.stream_type() == StreamType::kStreamVideo) {
const VideoStreamInfo& video_stream_info =
static_cast<const VideoStreamInfo&>(stream_info);
if (video_stream_info.codec() != VideoCodec::kCodecH264) {
if (video_stream_info.codec() != Codec::kCodecH264) {
LOG(ERROR) << "TsWriter cannot handle video codec "
<< video_stream_info.codec() << " yet.";
return false;
@ -184,7 +184,7 @@ bool TsWriter::Initialize(const StreamInfo& stream_info) {
DCHECK_EQ(stream_type, StreamType::kStreamAudio);
const AudioStreamInfo& audio_stream_info =
static_cast<const AudioStreamInfo&>(stream_info);
if (audio_stream_info.codec() != AudioCodec::kCodecAAC) {
if (audio_stream_info.codec() != Codec::kCodecAAC) {
LOG(ERROR) << "TsWriter cannot handle audio codec "
<< audio_stream_info.codec() << " yet.";
return false;

View File

@ -28,8 +28,8 @@ namespace {
const int kTsPacketSize = 188;
// Only {Audio,Video}Codec matter for this test. Other values are bogus.
const VideoCodec kH264VideoCodec = VideoCodec::kCodecH264;
const AudioCodec kAacAudioCodec = AudioCodec::kCodecAAC;
const Codec kH264Codec = Codec::kCodecH264;
const Codec kAacCodec = Codec::kCodecAAC;
const int kTrackId = 0;
const uint32_t kTimeScale = 90000;
const uint64_t kDuration = 180000;
@ -158,35 +158,35 @@ class TsWriterTest : public ::testing::Test {
TEST_F(TsWriterTest, InitializeVideoH264) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
}
TEST_F(TsWriterTest, InitializeVideoNonH264) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, VideoCodec::kCodecVP9, kCodecString,
kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, Codec::kCodecVP9, kCodecString,
kExtraData, arraysize(kExtraData), kWidth, kHeight, kPixelWidth,
kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_FALSE(ts_writer_.Initialize(*stream_info));
}
TEST_F(TsWriterTest, InitializeAudioAac) {
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, kAacAudioCodec, kCodecString, kLanguage,
kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay,
kMaxBitrate, kAverageBitrate, kExtraData, arraysize(kExtraData),
kTrackId, kTimeScale, kDuration, kAacCodec, kCodecString, kExtraData,
arraysize(kExtraData), kSampleBits, kNumChannels, kSamplingFrequency,
kSeekPreroll, kCodecDelay, kMaxBitrate, kAverageBitrate, kLanguage,
kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
}
TEST_F(TsWriterTest, InitializeAudioNonAac) {
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, AudioCodec::kCodecOpus, kCodecString,
kLanguage, kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll,
kCodecDelay, kMaxBitrate, kAverageBitrate, kExtraData,
arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, Codec::kCodecOpus, kCodecString,
kExtraData, arraysize(kExtraData), kSampleBits, kNumChannels,
kSamplingFrequency, kSeekPreroll, kCodecDelay, kMaxBitrate,
kAverageBitrate, kLanguage, kIsEncrypted));
EXPECT_FALSE(ts_writer_.Initialize(*stream_info));
}
@ -199,9 +199,9 @@ TEST_F(TsWriterTest, ClearH264Psi) {
EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(WriteOnePmt());
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -253,10 +253,10 @@ TEST_F(TsWriterTest, ClearAacPmt) {
EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(WriteOnePmt());
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, kAacAudioCodec, kCodecString, kLanguage,
kTrackId, kTimeScale, kDuration, kAacCodec, kCodecString,
kAacBasicProfileExtraData, arraysize(kAacBasicProfileExtraData),
kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay,
kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData,
arraysize(kAacBasicProfileExtraData), kIsEncrypted));
kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -281,9 +281,9 @@ TEST_F(TsWriterTest, ClearLeadH264Pmt) {
.WillOnce(WriteTwoPmts());
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -310,9 +310,9 @@ TEST_F(TsWriterTest, EncryptedSegmentsH264Pmt) {
EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(WriteOnePmt());
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -341,10 +341,10 @@ TEST_F(TsWriterTest, ClearLeadAacPmt) {
.WillOnce(WriteTwoPmts());
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, kAacAudioCodec, kCodecString, kLanguage,
kTrackId, kTimeScale, kDuration, kAacCodec, kCodecString,
kAacBasicProfileExtraData, arraysize(kAacBasicProfileExtraData),
kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay,
kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData,
arraysize(kAacBasicProfileExtraData), kIsEncrypted));
kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -371,10 +371,10 @@ TEST_F(TsWriterTest, EncryptedSegmentsAacPmt) {
EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(WriteOnePmt());
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, kAacAudioCodec, kCodecString, kLanguage,
kTrackId, kTimeScale, kDuration, kAacCodec, kCodecString,
kAacBasicProfileExtraData, arraysize(kAacBasicProfileExtraData),
kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay,
kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData,
arraysize(kAacBasicProfileExtraData), kIsEncrypted));
kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -398,9 +398,9 @@ TEST_F(TsWriterTest, EncryptedSegmentsAacPmt) {
TEST_F(TsWriterTest, AddPesPacket) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_));
@ -463,9 +463,9 @@ TEST_F(TsWriterTest, AddPesPacket) {
// Verify that PES packet > 64KiB can be handled.
TEST_F(TsWriterTest, BigPesPacket) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_));
@ -499,9 +499,9 @@ TEST_F(TsWriterTest, BigPesPacket) {
// PTS (implicilty) cast to bool is true.
TEST_F(TsWriterTest, PesPtsZeroNoDts) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_));
@ -559,9 +559,9 @@ TEST_F(TsWriterTest, PesPtsZeroNoDts) {
// adaptation_field_length should be 0.
TEST_F(TsWriterTest, TsPacketPayload183Bytes) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted));
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_));

View File

@ -41,9 +41,8 @@ void AddSubsamples(uint64_t clear_bytes,
subsamples->push_back(SubsampleEntry(clear_bytes, cipher_bytes));
}
VideoCodec GetVideoCodec(const StreamInfo& stream_info) {
if (stream_info.stream_type() != kStreamVideo)
return kUnknownVideoCodec;
Codec GetCodec(const StreamInfo& stream_info) {
if (stream_info.stream_type() != kStreamVideo) return kUnknownCodec;
const VideoStreamInfo& video_stream_info =
static_cast<const VideoStreamInfo&>(stream_info);
return video_stream_info.codec();
@ -60,19 +59,15 @@ uint8_t GetNaluLengthSize(const StreamInfo& stream_info) {
} // namespace
EncryptingFragmenter::EncryptingFragmenter(
scoped_refptr<StreamInfo> info,
TrackFragment* traf,
scoped_ptr<EncryptionKey> encryption_key,
int64_t clear_time,
FourCC protection_scheme,
uint8_t crypt_byte_block,
uint8_t skip_byte_block,
scoped_refptr<StreamInfo> info, TrackFragment* traf,
scoped_ptr<EncryptionKey> encryption_key, int64_t clear_time,
FourCC protection_scheme, uint8_t crypt_byte_block, uint8_t skip_byte_block,
MuxerListener* listener)
: Fragmenter(info, traf),
info_(info),
encryption_key_(encryption_key.Pass()),
nalu_length_size_(GetNaluLengthSize(*info)),
video_codec_(GetVideoCodec(*info)),
video_codec_(GetCodec(*info)),
clear_time_(clear_time),
protection_scheme_(protection_scheme),
crypt_byte_block_(crypt_byte_block),

View File

@ -92,7 +92,7 @@ class EncryptingFragmenter : public Fragmenter {
// and type of NAL units remain unencrypted. This function returns the size of
// the size field in bytes. Can be 1, 2 or 4 bytes.
const uint8_t nalu_length_size_;
const VideoCodec video_codec_;
const Codec video_codec_;
int64_t clear_time_;
const FourCC protection_scheme_;
const uint8_t crypt_byte_block_;

View File

@ -40,7 +40,7 @@ uint64_t Rescale(uint64_t time_in_old_scale,
return (static_cast<double>(time_in_old_scale) / old_scale) * new_scale;
}
VideoCodec FourCCToVideoCodec(FourCC fourcc) {
Codec FourCCToCodec(FourCC fourcc) {
switch (fourcc) {
case FOURCC_avc1:
return kCodecH264;
@ -54,13 +54,6 @@ VideoCodec FourCCToVideoCodec(FourCC fourcc) {
return kCodecVP9;
case FOURCC_vp10:
return kCodecVP10;
default:
return kUnknownVideoCodec;
}
}
AudioCodec FourCCToAudioCodec(FourCC fourcc) {
switch(fourcc) {
case FOURCC_Opus:
return kCodecOpus;
case FOURCC_dtsc:
@ -80,7 +73,7 @@ AudioCodec FourCCToAudioCodec(FourCC fourcc) {
case FOURCC_ec_3:
return kCodecEAC3;
default:
return kUnknownAudioCodec;
return kUnknownCodec;
}
}
@ -343,7 +336,7 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx];
const FourCC actual_format = entry.GetActualFormat();
AudioCodec codec = FourCCToAudioCodec(actual_format);
Codec codec = FourCCToCodec(actual_format);
uint8_t num_channels = 0;
uint32_t sampling_frequency = 0;
uint64_t codec_delay_ns = 0;
@ -473,21 +466,11 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
entry.sinf.info.track_encryption.default_is_protected == 1;
DVLOG(1) << "is_audio_track_encrypted_: " << is_encrypted;
streams.push_back(new AudioStreamInfo(
track->header.track_id,
timescale,
duration,
codec,
track->header.track_id, timescale, duration, codec,
AudioStreamInfo::GetCodecString(codec, audio_object_type),
track->media.header.language.code,
entry.samplesize,
num_channels,
sampling_frequency,
seek_preroll_ns,
codec_delay_ns,
max_bitrate,
avg_bitrate,
codec_config.data(),
codec_config.size(),
codec_config.data(), codec_config.size(), entry.samplesize,
num_channels, sampling_frequency, seek_preroll_ns, codec_delay_ns,
max_bitrate, avg_bitrate, track->media.header.language.code,
is_encrypted));
}
@ -509,7 +492,7 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
uint8_t nalu_length_size = 0;
const FourCC actual_format = entry.GetActualFormat();
const VideoCodec video_codec = FourCCToVideoCodec(actual_format);
const Codec video_codec = FourCCToCodec(actual_format);
switch (actual_format) {
case FOURCC_avc1: {
AVCDecoderConfigurationRecord avc_config;
@ -580,11 +563,11 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted;
streams.push_back(new VideoStreamInfo(
track->header.track_id, timescale, duration, video_codec,
codec_string, track->media.header.language.code, coded_width,
coded_height, pixel_width, pixel_height,
codec_string, entry.codec_configuration.data.data(),
entry.codec_configuration.data.size(), coded_width, coded_height,
pixel_width, pixel_height,
0, // trick_play_rate
nalu_length_size, entry.codec_configuration.data.data(),
entry.codec_configuration.data.size(), is_encrypted));
nalu_length_size, track->media.header.language.code, is_encrypted));
}
}

View File

@ -40,7 +40,7 @@ void SetStartAndEndFromOffsetAndSize(size_t offset,
*end = *start + static_cast<uint32_t>(size) - 1;
}
FourCC VideoCodecToFourCC(VideoCodec codec) {
FourCC CodecToFourCC(Codec codec) {
switch (codec) {
case kCodecH264:
return FOURCC_avc1;
@ -54,13 +54,6 @@ FourCC VideoCodecToFourCC(VideoCodec codec) {
return FOURCC_vp09;
case kCodecVP10:
return FOURCC_vp10;
default:
return FOURCC_NULL;
}
}
FourCC AudioCodecToFourCC(AudioCodec codec) {
switch (codec) {
case kCodecAAC:
return FOURCC_mp4a;
case kCodecAC3:
@ -100,7 +93,7 @@ Status MP4Muxer::Initialize() {
ftyp->compatible_brands.push_back(FOURCC_mp41);
if (streams().size() == 1 &&
streams()[0]->info()->stream_type() == kStreamVideo) {
const FourCC codec_fourcc = VideoCodecToFourCC(
const FourCC codec_fourcc = CodecToFourCC(
static_cast<VideoStreamInfo*>(streams()[0]->info().get())->codec());
if (codec_fourcc != FOURCC_NULL)
ftyp->compatible_brands.push_back(codec_fourcc);
@ -226,7 +219,7 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info,
trak->header.height = video_info->height() * 0x10000;
VideoSampleEntry video;
video.format = VideoCodecToFourCC(video_info->codec());
video.format = CodecToFourCC(video_info->codec());
video.width = video_info->width();
video.height = video_info->height();
video.codec_configuration.data = video_info->codec_config();
@ -249,7 +242,7 @@ void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info,
trak->header.volume = 0x100;
AudioSampleEntry audio;
audio.format = AudioCodecToFourCC(audio_info->codec());
audio.format = CodecToFourCC(audio_info->codec());
switch(audio_info->codec()){
case kCodecAAC:
audio.esds.es_descriptor.set_object_type(kISO_14496_3); // MPEG4 AAC.

View File

@ -6,15 +6,21 @@
#include "packager/media/formats/webm/encryptor.h"
#include <gflags/gflags.h>
#include "packager/media/base/aes_encryptor.h"
#include "packager/media/base/buffer_writer.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/base/media_sample.h"
#include "packager/media/codecs/vp9_parser.h"
#include "packager/media/formats/webm/webm_constants.h"
namespace shaka {
namespace media {
namespace webm {
namespace {
const size_t kAesBlockSize = 16;
Status CreateContentEncryption(mkvmuxer::Track* track, EncryptionKey* key) {
if (!track->AddContentEncoding()) {
return Status(error::INTERNAL_ERROR,
@ -54,9 +60,12 @@ Encryptor::~Encryptor() {}
Status Encryptor::Initialize(MuxerListener* muxer_listener,
KeySource::TrackType track_type,
KeySource* key_source) {
Codec codec,
KeySource* key_source,
bool webm_subsample_encryption) {
DCHECK(key_source);
return CreateEncryptor(muxer_listener, track_type, key_source);
return CreateEncryptor(muxer_listener, track_type, codec, key_source,
webm_subsample_encryption);
}
Status Encryptor::AddTrackInfo(mkvmuxer::Track* track) {
@ -69,26 +78,88 @@ Status Encryptor::EncryptFrame(scoped_refptr<MediaSample> sample,
DCHECK(encryptor_);
const size_t sample_size = sample->data_size();
if (encrypt_frame) {
// | 1 | iv | enc_data |
const size_t iv_size = encryptor_->iv().size();
sample->resize_data(sample_size + iv_size + 1);
uint8_t* sample_data = sample->writable_data();
// Encrypt the data in-place.
if (!encryptor_->Crypt(sample_data, sample_size, sample_data)) {
return Status(error::MUXER_FAILURE, "Failed to encrypt the frame.");
// We need to parse the frame (which also updates the vpx parser) even if the
// frame is not encrypted as the next (encrypted) frame may be dependent on
// this clear frame.
std::vector<VPxFrameInfo> vpx_frames;
if (vpx_parser_) {
if (!vpx_parser_->Parse(sample->data(), sample_size, &vpx_frames)) {
return Status(error::MUXER_FAILURE, "Failed to parse VPx frame.");
}
}
// First move the sample data to after the IV; then write the IV and signal
// byte.
memmove(sample_data + iv_size + 1, sample_data, sample_size);
sample_data[0] = 0x01;
memcpy(sample_data + 1, encryptor_->iv().data(), iv_size);
if (encrypt_frame) {
const size_t iv_size = encryptor_->iv().size();
if (iv_size != kWebMIvSize) {
return Status(error::MUXER_FAILURE,
"Incorrect size WebM encryption IV.");
}
if (vpx_frames.size()) {
// Use partitioned subsample encryption: | signal_byte(3) | iv
// | num_partitions | partition_offset * n | enc_data |
if (vpx_frames.size() > kWebMMaxSubsamples) {
return Status(error::MUXER_FAILURE,
"Maximum number of VPx encryption partitions exceeded.");
}
uint8_t num_partitions =
vpx_frames.size() == 1 ? 1 : vpx_frames.size() * 2;
size_t header_size = kWebMSignalByteSize + iv_size +
kWebMNumPartitionsSize +
(kWebMPartitionOffsetSize * num_partitions);
sample->resize_data(header_size + sample_size);
uint8_t* sample_data = sample->writable_data();
memmove(sample_data + header_size, sample_data, sample_size);
sample_data[0] = kWebMEncryptedSignal | kWebMPartitionedSignal;
memcpy(sample_data + kWebMSignalByteSize, encryptor_->iv().data(),
iv_size);
sample_data[kWebMSignalByteSize + kWebMIvSize] = num_partitions;
uint32 partition_offset = 0;
BufferWriter offsets_buffer(kWebMPartitionOffsetSize * num_partitions);
for (const auto& vpx_frame : vpx_frames) {
uint32_t encrypted_size =
vpx_frame.frame_size - vpx_frame.uncompressed_header_size;
encrypted_size -= encrypted_size % kAesBlockSize;
uint32_t clear_size = vpx_frame.frame_size - encrypted_size;
partition_offset += clear_size;
offsets_buffer.AppendInt(partition_offset);
if (encrypted_size > 0) {
uint8_t* encrypted_ptr = sample_data + header_size + partition_offset;
if (!encryptor_->Crypt(encrypted_ptr, encrypted_size, encrypted_ptr)) {
return Status(error::MUXER_FAILURE, "Failed to encrypt the frame.");
}
partition_offset += encrypted_size;
}
if (num_partitions > 1) {
offsets_buffer.AppendInt(partition_offset);
}
}
DCHECK_EQ(num_partitions * kWebMPartitionOffsetSize,
offsets_buffer.Size());
memcpy(sample_data + kWebMSignalByteSize + kWebMIvSize +
kWebMNumPartitionsSize,
offsets_buffer.Buffer(), offsets_buffer.Size());
} else {
// Use whole-frame encryption: | signal_byte(1) | iv | enc_data |
sample->resize_data(sample_size + iv_size + kWebMSignalByteSize);
uint8_t* sample_data = sample->writable_data();
// Encrypt the data in-place.
if (!encryptor_->Crypt(sample_data, sample_size, sample_data)) {
return Status(error::MUXER_FAILURE, "Failed to encrypt the frame.");
}
// First move the sample data to after the IV; then write the IV and
// signal byte.
memmove(sample_data + iv_size + kWebMSignalByteSize, sample_data,
sample_size);
sample_data[0] = kWebMEncryptedSignal;
memcpy(sample_data + 1, encryptor_->iv().data(), iv_size);
}
encryptor_->UpdateIv();
} else {
// | 0 | data |
// Clear sample: | signal_byte(0) | data |
sample->resize_data(sample_size + 1);
uint8_t* sample_data = sample->writable_data();
memmove(sample_data + 1, sample_data, sample_size);
@ -100,7 +171,9 @@ Status Encryptor::EncryptFrame(scoped_refptr<MediaSample> sample,
Status Encryptor::CreateEncryptor(MuxerListener* muxer_listener,
KeySource::TrackType track_type,
KeySource* key_source) {
Codec codec,
KeySource* key_source,
bool webm_subsample_encryption) {
scoped_ptr<EncryptionKey> encryption_key(new EncryptionKey());
Status status = key_source->GetKey(track_type, encryption_key.get());
if (!status.ok())
@ -109,13 +182,18 @@ Status Encryptor::CreateEncryptor(MuxerListener* muxer_listener,
if (!AesCryptor::GenerateRandomIv(FOURCC_cenc, &encryption_key->iv))
return Status(error::INTERNAL_ERROR, "Failed to generate random iv.");
}
DCHECK_EQ(kWebMIvSize, encryption_key->iv.size());
scoped_ptr<AesCtrEncryptor> encryptor(new AesCtrEncryptor());
const bool initialized =
encryptor->InitializeWithIv(encryption_key->key, encryption_key->iv);
if (!initialized)
return Status(error::INTERNAL_ERROR, "Failed to create the encryptor.");
if (webm_subsample_encryption && codec == kCodecVP9) {
// Allocate VP9 parser to do subsample encryption of VP9.
vpx_parser_.reset(new VP9Parser);
}
if (muxer_listener) {
const bool kInitialEncryptionInfo = true;
muxer_listener->OnEncryptionInfoReady(

View File

@ -11,6 +11,8 @@
#include "packager/base/memory/scoped_ptr.h"
#include "packager/media/base/key_source.h"
#include "packager/media/base/status.h"
#include "packager/media/base/stream_info.h"
#include "packager/media/codecs/vpx_parser.h"
#include "packager/media/event/muxer_listener.h"
#include "packager/third_party/libwebm/src/mkvmuxer.hpp"
@ -33,7 +35,9 @@ class Encryptor {
/// @return OK on success, an error status otherwise.
Status Initialize(MuxerListener* muxer_listener,
KeySource::TrackType track_type,
KeySource* key_source);
Codec codec,
KeySource* key_source,
bool webm_subsample_encryption);
/// Adds the encryption info to the given track. Initialize must be called
/// first.
@ -50,11 +54,14 @@ class Encryptor {
// Create the encryptor for the internal encryption key.
Status CreateEncryptor(MuxerListener* muxer_listener,
KeySource::TrackType track_type,
KeySource* key_source);
Codec codec,
KeySource* key_source,
bool webm_subsample_encryption);
private:
scoped_ptr<EncryptionKey> key_;
scoped_ptr<AesCtrEncryptor> encryptor_;
scoped_ptr<VPxParser> vpx_parser_;
};
} // namespace webm

View File

@ -79,7 +79,8 @@ Status Segmenter::Initialize(scoped_ptr<MkvWriter> writer,
Status status;
if (encryption_key_source) {
status = InitializeEncryptor(encryption_key_source, max_sd_pixels);
status = InitializeEncryptor(encryption_key_source,
max_sd_pixels);
if (!status.ok())
return status;
}
@ -362,7 +363,8 @@ Status Segmenter::InitializeEncryptor(KeySource* key_source,
GetTrackTypeForEncryption(*info_, max_sd_pixels);
if (track_type == KeySource::TrackType::TRACK_TYPE_UNKNOWN)
return Status::OK;
return encryptor_->Initialize(muxer_listener_, track_type, key_source);
return encryptor_->Initialize(muxer_listener_, track_type, info_->codec(),
key_source, options_.webm_subsample_encryption);
}
Status Segmenter::WriteFrame(bool write_duration) {

View File

@ -25,7 +25,7 @@ const uint8_t kTestMediaSampleSideData[] = {
const int kTrackId = 1;
const uint32_t kTimeScale = 1000;
const uint64_t kDuration = 8000;
const VideoCodec kVideoCodec = kCodecVP8;
const Codec kCodec = kCodecVP8;
const std::string kCodecString = "vp8";
const std::string kLanguage = "en";
const uint16_t kWidth = 100;
@ -92,10 +92,10 @@ MuxerOptions SegmentTestBase::CreateMuxerOptions() const {
}
VideoStreamInfo* SegmentTestBase::CreateVideoStreamInfo() const {
return new VideoStreamInfo(kTrackId, kTimeScale, kDuration, kVideoCodec,
kCodecString, kLanguage, kWidth, kHeight,
return new VideoStreamInfo(kTrackId, kTimeScale, kDuration, kCodec,
kCodecString, NULL, 0, kWidth, kHeight,
kPixelWidth, kPixelHeight, kTrickPlayRate,
kNaluLengthSize, NULL, 0, false);
kNaluLengthSize, kLanguage, false);
}
std::string SegmentTestBase::OutputFileName() const {
@ -200,4 +200,3 @@ bool SegmentTestBase::ClusterParser::OnString(int id, const std::string& str) {
} // namespace media
} // namespace shaka

View File

@ -56,6 +56,7 @@
],
'dependencies': [
'../../../third_party/boringssl/boringssl.gyp:boringssl',
'../../../third_party/gflags/gflags.gyp:gflags',
'../../../third_party/libwebm/libwebm.gyp:mkvmuxer',
'../../base/media_base.gyp:media_base',
'../../codecs/codecs.gyp:codecs'

View File

@ -36,7 +36,7 @@ scoped_refptr<AudioStreamInfo> WebMAudioClient::GetAudioStreamInfo(
int64_t codec_delay,
const std::string& language,
bool is_encrypted) {
AudioCodec audio_codec = kUnknownAudioCodec;
Codec audio_codec = kUnknownCodec;
if (codec_id == "A_VORBIS") {
audio_codec = kCodecVorbis;
} else if (codec_id == "A_OPUS") {
@ -70,10 +70,10 @@ scoped_refptr<AudioStreamInfo> WebMAudioClient::GetAudioStreamInfo(
const uint8_t kSampleSizeInBits = 16u;
return scoped_refptr<AudioStreamInfo>(new AudioStreamInfo(
track_num, kWebMTimeScale, 0, audio_codec,
AudioStreamInfo::GetCodecString(audio_codec, 0), language,
kSampleSizeInBits, channels_, sampling_frequency,
AudioStreamInfo::GetCodecString(audio_codec, 0), codec_config,
codec_config_size, kSampleSizeInBits, channels_, sampling_frequency,
seek_preroll < 0 ? 0 : seek_preroll, codec_delay < 0 ? 0 : codec_delay, 0,
0, codec_config, codec_config_size, is_encrypted));
0, language, is_encrypted));
}
bool WebMAudioClient::OnUInt(int id, int64_t val) {

View File

@ -27,10 +27,7 @@ const int64_t kMicrosecondsPerMillisecond = 1000;
// block is a keyframe.
// |data| contains the bytes in the block.
// |size| indicates the number of bytes in |data|.
bool IsKeyframe(bool is_video,
VideoCodec codec,
const uint8_t* data,
int size) {
bool IsKeyframe(bool is_video, Codec codec, const uint8_t* data, int size) {
// For now, assume that all blocks are keyframes for datatypes other than
// video. This is a valid assumption for Vorbis, WebVTT, & Opus.
if (!is_video)
@ -370,7 +367,7 @@ bool WebMClusterParser::OnBlock(bool is_simple_block,
? (flags & 0x80) != 0
: IsKeyframe(stream_type == kStreamVideo,
video_stream_info_ ? video_stream_info_->codec()
: kUnknownVideoCodec,
: kUnknownCodec,
data, size);
// Every encrypted Block has a signal byte and IV prepended to it. Current
@ -390,8 +387,7 @@ bool WebMClusterParser::OnBlock(bool is_simple_block,
buffer = MediaSample::CopyFrom(data + data_offset, size - data_offset,
additional, additional_size, is_keyframe);
// An empty iv indicates that this sample is not encrypted.
if (decrypt_config && !decrypt_config->iv().empty()) {
if (decrypt_config) {
if (!decryptor_source_) {
LOG(ERROR) << "Encrypted media sample encountered, but decryption is "
"not enabled";

View File

@ -84,6 +84,7 @@ const uint8_t kNumChannels = 2u;
const uint32_t kSamplingFrequency = 48000u;
const uint64_t kSeekPreroll = 0u;
const uint64_t kCodecDelay = 0u;
const uint8_t* kExtraData = nullptr;
const size_t kExtraDataSize = 0u;
const bool kEncrypted = true;
const uint16_t kWidth = 320u;
@ -316,37 +317,16 @@ bool VerifyTextBuffers(const BlockInfo* block_info_ptr,
class WebMClusterParserTest : public testing::Test {
public:
WebMClusterParserTest()
: audio_stream_info_(new AudioStreamInfo(kAudioTrackNum,
kTimeScale,
kDuration,
kUnknownAudioCodec,
kCodecString,
kLanguage,
kBitsPerSample,
kNumChannels,
kSamplingFrequency,
kSeekPreroll,
kCodecDelay,
0,
0,
NULL,
kExtraDataSize,
!kEncrypted)),
video_stream_info_(new VideoStreamInfo(kVideoTrackNum,
kTimeScale,
kDuration,
kCodecVP8,
kCodecString,
kLanguage,
kWidth,
kHeight,
kPixelWidth,
kPixelHeight,
kTrickPlayRate,
kNaluLengthSize,
NULL,
kExtraDataSize,
!kEncrypted)),
: audio_stream_info_(new AudioStreamInfo(
kAudioTrackNum, kTimeScale, kDuration, kUnknownCodec, kCodecString,
kExtraData, kExtraDataSize, kBitsPerSample, kNumChannels,
kSamplingFrequency, kSeekPreroll, kCodecDelay, 0, 0, kLanguage,
!kEncrypted)),
video_stream_info_(new VideoStreamInfo(
kVideoTrackNum, kTimeScale, kDuration, kCodecVP8, kCodecString,
kExtraData, kExtraDataSize, kWidth, kHeight, kPixelWidth,
kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage,
!kEncrypted)),
parser_(CreateDefaultParser()) {}
protected:
@ -390,15 +370,12 @@ class WebMClusterParserTest : public testing::Test {
// Helper that hard-codes some non-varying constructor parameters.
WebMClusterParser* CreateParserHelper(
int64_t audio_default_duration,
int64_t video_default_duration,
int64_t audio_default_duration, int64_t video_default_duration,
const WebMTracksParser::TextTracks& text_tracks,
const std::set<int64_t>& ignored_tracks,
const std::string& audio_encryption_key_id,
const std::string& video_encryption_key_id,
const AudioCodec audio_codec,
const VideoCodec video_codec,
const MediaParser::InitCB& init_cb) {
const std::string& video_encryption_key_id, const Codec audio_codec,
const Codec video_codec, const MediaParser::InitCB& init_cb) {
audio_stream_info_->set_codec(audio_codec);
video_stream_info_->set_codec(video_codec);
return new WebMClusterParser(
@ -414,8 +391,7 @@ class WebMClusterParserTest : public testing::Test {
WebMClusterParser* CreateDefaultParser() {
return CreateParserHelper(kNoTimestamp, kNoTimestamp, TextTracks(),
std::set<int64_t>(), std::string(), std::string(),
kUnknownAudioCodec, kCodecVP8,
MediaParser::InitCB());
kUnknownCodec, kCodecVP8, MediaParser::InitCB());
}
// Create a parser for test with custom audio and video default durations, and
@ -426,23 +402,22 @@ class WebMClusterParserTest : public testing::Test {
const WebMTracksParser::TextTracks& text_tracks = TextTracks()) {
return CreateParserHelper(audio_default_duration, video_default_duration,
text_tracks, std::set<int64_t>(), std::string(),
std::string(), kUnknownAudioCodec, kCodecVP8,
std::string(), kUnknownCodec, kCodecVP8,
MediaParser::InitCB());
}
// Create a parser for test with custom ignored tracks.
WebMClusterParser* CreateParserWithIgnoredTracks(
std::set<int64_t>& ignored_tracks) {
return CreateParserHelper(
kNoTimestamp, kNoTimestamp, TextTracks(), ignored_tracks, std::string(),
std::string(), kUnknownAudioCodec, kCodecVP8, MediaParser::InitCB());
return CreateParserHelper(kNoTimestamp, kNoTimestamp, TextTracks(),
ignored_tracks, std::string(), std::string(),
kUnknownCodec, kCodecVP8, MediaParser::InitCB());
}
// Create a parser for test with custom encryption key ids and audio codec.
WebMClusterParser* CreateParserWithKeyIdsAndAudioCodec(
WebMClusterParser* CreateParserWithKeyIdsAndCodec(
const std::string& audio_encryption_key_id,
const std::string& video_encryption_key_id,
const AudioCodec audio_codec) {
const std::string& video_encryption_key_id, const Codec audio_codec) {
return CreateParserHelper(kNoTimestamp, kNoTimestamp, TextTracks(),
std::set<int64_t>(), audio_encryption_key_id,
video_encryption_key_id, audio_codec, kCodecVP8,
@ -451,10 +426,10 @@ class WebMClusterParserTest : public testing::Test {
// Create a parser for test with custom video codec, also check for init
// events.
WebMClusterParser* CreateParserWithVideoCodec(const VideoCodec video_codec) {
WebMClusterParser* CreateParserWithCodec(const Codec video_codec) {
return CreateParserHelper(
kNoTimestamp, kNoTimestamp, TextTracks(), std::set<int64_t>(),
std::string(), std::string(), kUnknownAudioCodec, video_codec,
std::string(), std::string(), kUnknownCodec, video_codec,
base::Bind(&WebMClusterParserTest::InitEvent, base::Unretained(this)));
}
@ -807,7 +782,7 @@ TEST_F(WebMClusterParserTest, ParseMultipleTextTracks) {
TEST_F(WebMClusterParserTest, ParseVP8) {
scoped_ptr<Cluster> cluster(CreateCluster(kVP8Frame, arraysize(kVP8Frame)));
parser_.reset(CreateParserWithVideoCodec(kCodecVP8));
parser_.reset(CreateParserWithCodec(kCodecVP8));
EXPECT_EQ(cluster->size(), parser_->Parse(cluster->data(), cluster->size()));
@ -820,7 +795,7 @@ TEST_F(WebMClusterParserTest, ParseVP8) {
TEST_F(WebMClusterParserTest, ParseVP9) {
scoped_ptr<Cluster> cluster(CreateCluster(kVP9Frame, arraysize(kVP9Frame)));
parser_.reset(CreateParserWithVideoCodec(kCodecVP9));
parser_.reset(CreateParserWithCodec(kCodecVP9));
EXPECT_EQ(cluster->size(), parser_->Parse(cluster->data(), cluster->size()));
@ -844,8 +819,8 @@ TEST_F(WebMClusterParserTest, ParseEncryptedBlock) {
scoped_ptr<Cluster> cluster(
CreateCluster(kEncryptedFrame, arraysize(kEncryptedFrame)));
parser_.reset(CreateParserWithKeyIdsAndAudioCodec(std::string(), video_key_id,
kUnknownAudioCodec));
parser_.reset(CreateParserWithKeyIdsAndCodec(std::string(), video_key_id,
kUnknownCodec));
int result = parser_->Parse(cluster->data(), cluster->size());
EXPECT_EQ(cluster->size(), result);
@ -865,8 +840,8 @@ TEST_F(WebMClusterParserTest, ParseEncryptedBlockGetKeyFailed) {
scoped_ptr<Cluster> cluster(
CreateCluster(kEncryptedFrame, arraysize(kEncryptedFrame)));
parser_.reset(CreateParserWithKeyIdsAndAudioCodec(
std::string(), "video_key_id", kUnknownAudioCodec));
parser_.reset(CreateParserWithKeyIdsAndCodec(std::string(), "video_key_id",
kUnknownCodec));
int result = parser_->Parse(cluster->data(), cluster->size());
EXPECT_EQ(-1, result);
@ -876,8 +851,8 @@ TEST_F(WebMClusterParserTest, ParseBadEncryptedBlock) {
scoped_ptr<Cluster> cluster(
CreateCluster(kEncryptedFrame, arraysize(kEncryptedFrame) - 2));
parser_.reset(CreateParserWithKeyIdsAndAudioCodec(
std::string(), "video_key_id", kUnknownAudioCodec));
parser_.reset(CreateParserWithKeyIdsAndCodec(std::string(), "video_key_id",
kUnknownCodec));
int result = parser_->Parse(cluster->data(), cluster->size());
EXPECT_EQ(-1, result);
}
@ -886,8 +861,8 @@ TEST_F(WebMClusterParserTest, ParseClearFrameInEncryptedTrack) {
scoped_ptr<Cluster> cluster(CreateCluster(
kClearFrameInEncryptedTrack, arraysize(kClearFrameInEncryptedTrack)));
parser_.reset(CreateParserWithKeyIdsAndAudioCodec(
std::string(), "video_key_id", kUnknownAudioCodec));
parser_.reset(CreateParserWithKeyIdsAndCodec(std::string(), "video_key_id",
kUnknownCodec));
int result = parser_->Parse(cluster->data(), cluster->size());
EXPECT_EQ(cluster->size(), result);

View File

@ -5,6 +5,7 @@
#ifndef MEDIA_FORMATS_WEBM_WEBM_CONSTANTS_H_
#define MEDIA_FORMATS_WEBM_WEBM_CONSTANTS_H_
#include <stddef.h>
#include <stdint.h>
namespace shaka {
@ -207,9 +208,13 @@ const uint8_t kWebMFlagKeyframe = 0x80;
/// Current encrypted WebM request for comments specification is here
/// http://wiki.webmproject.org/encryption/webm-encryption-rfc
const uint8_t kWebMFlagEncryptedFrame = 0x1;
const int kWebMIvSize = 8;
const int kWebMSignalByteSize = 1;
const size_t kWebMIvSize = 8;
const size_t kWebMSignalByteSize = 1;
const uint8_t kWebMEncryptedSignal = 0x01;
const uint8_t kWebMPartitionedSignal = 0x02;
const size_t kWebMNumPartitionsSize = 1;
const size_t kWebMPartitionOffsetSize = sizeof(uint32_t);
const uint8_t kWebMMaxSubsamples = 127;
/// Current specification for WebVTT embedded in WebM
/// http://wiki.webmproject.org/webm-metadata/temporal-metadata/webvtt-in-webm

View File

@ -6,6 +6,7 @@
#include "packager/base/logging.h"
#include "packager/base/sys_byteorder.h"
#include "packager/media/base/buffer_reader.h"
#include "packager/media/formats/webm/webm_constants.h"
namespace shaka {
@ -16,48 +17,96 @@ namespace {
// CTR IV appended with a CTR block counter. |iv| is an 8 byte CTR IV.
// |iv_size| is the size of |iv| in btyes. Returns a string of
// kDecryptionKeySize bytes.
std::string GenerateWebMCounterBlock(const uint8_t* iv, int iv_size) {
std::string counter_block(reinterpret_cast<const char*>(iv), iv_size);
counter_block.append(DecryptConfig::kDecryptionKeySize - iv_size, 0);
std::vector<uint8_t> GenerateWebMCounterBlock(const uint8_t* iv, int iv_size) {
std::vector<uint8_t> counter_block(iv, iv + iv_size);
counter_block.insert(counter_block.end(),
DecryptConfig::kDecryptionKeySize - iv_size, 0);
return counter_block;
}
} // namespace anonymous
// TODO(tinskip): Add unit test for this function.
bool WebMCreateDecryptConfig(const uint8_t* data,
int data_size,
const uint8_t* key_id,
int key_id_size,
scoped_ptr<DecryptConfig>* decrypt_config,
int* data_offset) {
if (data_size < kWebMSignalByteSize) {
DVLOG(1) << "Got a block from an encrypted stream with no data.";
int header_size = kWebMSignalByteSize;
if (data_size < header_size) {
DVLOG(1) << "Empty WebM sample.";
return false;
}
uint8_t signal_byte = data[0];
int frame_offset = sizeof(signal_byte);
// Setting the DecryptConfig object of the buffer while leaving the
// initialization vector empty will tell the decryptor that the frame is
// unencrypted.
std::string counter_block;
if (signal_byte & kWebMFlagEncryptedFrame) {
if (data_size < kWebMSignalByteSize + kWebMIvSize) {
DVLOG(1) << "Got an encrypted block with not enough data " << data_size;
if (signal_byte & kWebMEncryptedSignal) {
// Encrypted sample.
header_size += kWebMIvSize;
if (data_size < header_size) {
DVLOG(1) << "Encrypted WebM sample too small to hold IV: " << data_size;
return false;
}
counter_block = GenerateWebMCounterBlock(data + frame_offset, kWebMIvSize);
frame_offset += kWebMIvSize;
std::vector<SubsampleEntry> subsamples;
if (signal_byte & kWebMPartitionedSignal) {
// Encrypted sample with subsamples / partitioning.
header_size += kWebMNumPartitionsSize;
if (data_size < header_size) {
DVLOG(1)
<< "Encrypted WebM sample too small to hold number of partitions: "
<< data_size;
return false;
}
uint8_t num_partitions = data[kWebMSignalByteSize + kWebMIvSize];
BufferReader offsets_buffer(data + header_size, data_size - header_size);
header_size += num_partitions * kWebMPartitionOffsetSize;
uint32_t subsample_offset = 0;
bool encrypted_subsample = false;
uint16_t clear_size = 0;
uint32_t encrypted_size = 0;
for (uint8_t partition_idx = 0; partition_idx < num_partitions;
++partition_idx) {
uint32_t partition_offset;
if (!offsets_buffer.Read4(&partition_offset)) {
DVLOG(1)
<< "Encrypted WebM sample too small to hold partition offsets: "
<< data_size;
return false;
}
if (partition_offset < subsample_offset) {
DVLOG(1) << "Partition offsets out of order.";
return false;
}
if (encrypted_subsample) {
encrypted_size = partition_offset - subsample_offset;
subsamples.push_back(SubsampleEntry(clear_size, encrypted_size));
} else {
clear_size = partition_offset - subsample_offset;
if (partition_idx == (num_partitions - 1)) {
encrypted_size = data_size - header_size - subsample_offset - clear_size;
subsamples.push_back(SubsampleEntry(clear_size, encrypted_size));
}
}
subsample_offset = partition_offset;
encrypted_subsample = !encrypted_subsample;
}
if (!(num_partitions % 2)) {
// Even number of partitions. Add one last all-clear subsample.
clear_size = data_size - header_size - subsample_offset;
encrypted_size = 0;
subsamples.push_back(SubsampleEntry(clear_size, encrypted_size));
}
}
decrypt_config->reset(new DecryptConfig(
std::vector<uint8_t>(key_id, key_id + key_id_size),
GenerateWebMCounterBlock(data + kWebMSignalByteSize, kWebMIvSize),
subsamples));
} else {
// Clear sample.
decrypt_config->reset();
}
decrypt_config->reset(new DecryptConfig(
std::vector<uint8_t>(key_id, key_id + key_id_size),
std::vector<uint8_t>(counter_block.begin(), counter_block.end()),
std::vector<SubsampleEntry>()));
*data_offset = frame_offset;
*data_offset = header_size;
return true;
}

View File

@ -53,7 +53,7 @@ scoped_refptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
const std::string& codec_id,
const std::vector<uint8_t>& codec_private,
bool is_encrypted) {
VideoCodec video_codec = kUnknownVideoCodec;
Codec video_codec = kUnknownCodec;
if (codec_id == "V_VP8") {
video_codec = kCodecVP8;
} else if (codec_id == "V_VP9") {
@ -110,9 +110,9 @@ scoped_refptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
sar_y /= gcd;
return scoped_refptr<VideoStreamInfo>(new VideoStreamInfo(
track_num, kWebMTimeScale, 0, video_codec, std::string(), std::string(),
width_after_crop, height_after_crop, sar_x, sar_y, 0, 0,
codec_private.data(), codec_private.size(), is_encrypted));
track_num, kWebMTimeScale, 0, video_codec, std::string(),
codec_private.data(), codec_private.size(), width_after_crop,
height_after_crop, sar_x, sar_y, 0, 0, std::string(), is_encrypted));
}
bool WebMVideoClient::OnUInt(int id, int64_t val) {

View File

@ -294,15 +294,12 @@ bool WebVttMediaParser::Parse(const uint8_t* buf, int size) {
// There is no one metadata to determine what the language is. Parts
// of the text may be annotated as some specific language.
const char kLanguage[] = "";
streams.push_back(new TextStreamInfo(
kTrackId,
kTimescale,
kDuration,
"wvtt",
kLanguage,
base::JoinString(header_, "\n"),
0, // Not necessary.
0)); // Not necessary.
streams.push_back(new TextStreamInfo(kTrackId, kTimescale, kDuration,
"wvtt",
base::JoinString(header_, "\n"),
0, // Not necessary.
0,
kLanguage)); // Not necessary.
init_cb_.Run(streams);
state_ = kCueIdentifierOrTimingOrComment;

View File

@ -739,31 +739,33 @@ bool WvmMediaParser::ParseIndexEntry() {
index_size = read_ptr - index_data_.data();
if (has_video) {
VideoCodec video_codec = kCodecH264;
Codec video_codec = kCodecH264;
stream_infos_.push_back(new VideoStreamInfo(
stream_id_count_, time_scale, track_duration, video_codec,
std::string(), std::string(), video_width, video_height, pixel_width,
pixel_height, trick_play_rate, nalu_length_size,
video_codec_config.data(), video_codec_config.size(), true));
std::string(), video_codec_config.data(), video_codec_config.size(),
video_width, video_height, pixel_width, pixel_height, trick_play_rate,
nalu_length_size, std::string(), true));
program_demux_stream_map_[base::UintToString(index_program_id_) + ":" +
base::UintToString(video_pes_stream_id ?
video_pes_stream_id :
kDefaultVideoStreamId)] =
base::UintToString(
video_pes_stream_id
? video_pes_stream_id
: kDefaultVideoStreamId)] =
stream_id_count_++;
}
if (has_audio) {
const AudioCodec audio_codec = kCodecAAC;
const Codec audio_codec = kCodecAAC;
// TODO(beil): Pass in max and average bitrate in wvm container.
stream_infos_.push_back(new AudioStreamInfo(
stream_id_count_, time_scale, track_duration, audio_codec,
std::string(), std::string(), kAacSampleSizeBits, num_channels,
sampling_frequency, 0 /* seek preroll */, 0 /* codec delay */,
0 /* max bitrate */, 0 /* avg bitrate */, audio_codec_config.data(),
audio_codec_config.size(), true));
std::string(), audio_codec_config.data(), audio_codec_config.size(),
kAacSampleSizeBits, num_channels, sampling_frequency,
0 /* seek preroll */, 0 /* codec delay */, 0 /* max bitrate */,
0 /* avg bitrate */, std::string(), true));
program_demux_stream_map_[base::UintToString(index_program_id_) + ":" +
base::UintToString(audio_pes_stream_id ?
audio_pes_stream_id :
kDefaultAudioStreamId)] =
base::UintToString(
audio_pes_stream_id
? audio_pes_stream_id
: kDefaultAudioStreamId)] =
stream_id_count_++;
}
}

Binary file not shown.