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) " "Specify a directory in which to store temporary (intermediate) "
" files. Used only if single_segment=true."); " 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_bool(fragment_sap_aligned);
DECLARE_int32(num_subsegments_per_sidx); DECLARE_int32(num_subsegments_per_sidx);
DECLARE_string(temp_dir); DECLARE_string(temp_dir);
DECLARE_bool(webm_subsample_encryption);
#endif // APP_MUXER_FLAGS_H_ #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->segment_sap_aligned = FLAGS_segment_sap_aligned;
muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned; muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned;
muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx; 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) { if (FLAGS_mp4_use_decoding_timestamp_in_timeline) {
LOG(WARNING) << "Flag --mp4_use_decoding_timestamp_in_timeline is set. " LOG(WARNING) << "Flag --mp4_use_decoding_timestamp_in_timeline is set. "
"Note that it is a temporary hack to workaround Chromium " "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[0], 'bear-640x360-a-golden.mp4')
self._VerifyDecryption(self.output[1], 'bear-640x360-v-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): def testPackageAvcTsWithEncryption(self):
# Currently we only support live packaging for ts. # Currently we only support live packaging for ts.
self.packager.Package( self.packager.Package(

Binary file not shown.

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,18 +22,40 @@ enum StreamType {
kStreamText, 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. /// Abstract class holds stream information.
class StreamInfo : public base::RefCountedThreadSafe<StreamInfo> { class StreamInfo : public base::RefCountedThreadSafe<StreamInfo> {
public: public:
StreamInfo(StreamType stream_type, StreamInfo(StreamType stream_type, int track_id, uint32_t time_scale,
int track_id, uint64_t duration, Codec codec, const std::string& codec_string,
uint32_t time_scale, const uint8_t* codec_config, size_t codec_config_size,
uint64_t duration, const std::string& language, bool is_encrypted);
const std::string& codec_string,
const std::string& language,
const uint8_t* codec_config,
size_t codec_config_size,
bool is_encrypted);
/// @return true if this object has appropriate configuration values, false /// @return true if this object has appropriate configuration values, false
/// otherwise. /// otherwise.
@ -46,21 +68,18 @@ class StreamInfo : public base::RefCountedThreadSafe<StreamInfo> {
uint32_t track_id() const { return track_id_; } uint32_t track_id() const { return track_id_; }
uint32_t time_scale() const { return time_scale_; } uint32_t time_scale() const { return time_scale_; }
uint64_t duration() const { return duration_; } uint64_t duration() const { return duration_; }
Codec codec() const { return codec_; }
const std::string& codec_string() const { return codec_string_; } 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_; } const std::string& language() const { return language_; }
bool is_encrypted() const { return is_encrypted_; } 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_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_config(const std::vector<uint8_t>& data) { codec_config_ = data; }
void set_codec_string(const std::string& codec_string) { void set_codec_string(const std::string& codec_string) {
codec_string_ = codec_string; codec_string_ = codec_string;
} }
void set_language(const std::string& language) { language_ = language; } void set_language(const std::string& language) { language_ = language; }
protected: protected:
@ -75,6 +94,7 @@ class StreamInfo : public base::RefCountedThreadSafe<StreamInfo> {
uint32_t time_scale_; uint32_t time_scale_;
// Duration base on time_scale. // Duration base on time_scale.
uint64_t duration_; uint64_t duration_;
Codec codec_;
std::string codec_string_; std::string codec_string_;
std::string language_; std::string language_;
// Whether the stream is potentially encrypted. // Whether the stream is potentially encrypted.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -221,25 +221,13 @@ bool EsParserAdts::UpdateAudioConfiguration(const uint8_t* adts_frame,
? std::min(2 * samples_per_second, 48000) ? std::min(2 * samples_per_second, 48000)
: samples_per_second; : samples_per_second;
last_audio_decoder_config_ = scoped_refptr<StreamInfo>( last_audio_decoder_config_ = scoped_refptr<StreamInfo>(new AudioStreamInfo(
new AudioStreamInfo( pid(), kMpeg2Timescale, kInfiniteDuration, kCodecAAC,
pid(), AudioStreamInfo::GetCodecString(kCodecAAC, adts_header.GetObjectType()),
kMpeg2Timescale, audio_specific_config.data(), audio_specific_config.size(),
kInfiniteDuration, kAacSampleSizeBits, adts_header.GetNumChannels(),
kCodecAAC, extended_samples_per_second, 0 /* seek preroll */, 0 /* codec delay */,
AudioStreamInfo::GetCodecString(kCodecAAC, 0 /* max bitrate */, 0 /* avg bitrate */, std::string(), false));
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));
DVLOG(1) << "Sampling frequency: " << samples_per_second; DVLOG(1) << "Sampling frequency: " << samples_per_second;
DVLOG(1) << "Extended sampling frequency: " << extended_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], AVCDecoderConfigurationRecord::GetCodecString(decoder_config_record[1],
decoder_config_record[2], decoder_config_record[2],
decoder_config_record[3]), decoder_config_record[3]),
std::string(), coded_width, coded_height, pixel_width, pixel_height, 0, decoder_config_record.data(), decoder_config_record.size(), coded_width,
H264ByteToUnitStreamConverter::kUnitStreamNaluLengthSize, coded_height, pixel_width, pixel_height, 0,
decoder_config_record.data(), decoder_config_record.size(), false)); H264ByteToUnitStreamConverter::kUnitStreamNaluLengthSize, std::string(),
false));
DVLOG(1) << "Profile IDC: " << sps->profile_idc; DVLOG(1) << "Profile IDC: " << sps->profile_idc;
DVLOG(1) << "Level IDC: " << sps->level_idc; DVLOG(1) << "Level IDC: " << sps->level_idc;
DVLOG(1) << "log2_max_frame_num_minus4: " << sps->log2_max_frame_num_minus4; 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; return false;
} }
last_video_decoder_config_ = scoped_refptr<StreamInfo>( last_video_decoder_config_ = scoped_refptr<StreamInfo>(new VideoStreamInfo(
new VideoStreamInfo( pid(), kMpeg2Timescale, kInfiniteDuration, kCodecHVC1,
pid(), decoder_config.GetCodecString(kCodecHVC1), decoder_config_record.data(),
kMpeg2Timescale, decoder_config_record.size(), coded_width, coded_height, pixel_width,
kInfiniteDuration, pixel_height, 0, H26xByteToUnitStreamConverter::kUnitStreamNaluLengthSize,
kCodecHVC1, std::string(), false));
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));
// Video config notification. // Video config notification.
new_stream_info_cb_.Run(last_video_decoder_config_); 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) { if (stream_type_ == kStreamVideo) {
const VideoStreamInfo& video_stream_info = const VideoStreamInfo& video_stream_info =
static_cast<const VideoStreamInfo&>(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() NOTIMPLEMENTED() << "Video codec " << video_stream_info.codec()
<< " is not supported."; << " is not supported.";
return false; return false;
@ -110,7 +110,7 @@ bool PesPacketGenerator::Initialize(const StreamInfo& stream_info) {
} else if (stream_type_ == kStreamAudio) { } else if (stream_type_ == kStreamAudio) {
const AudioStreamInfo& audio_stream_info = const AudioStreamInfo& audio_stream_info =
static_cast<const AudioStreamInfo&>(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() NOTIMPLEMENTED() << "Audio codec " << audio_stream_info.codec()
<< " is not supported yet."; << " is not supported yet.";
return false; return false;

View File

@ -34,10 +34,10 @@ const uint8_t kAnyData[] = {
const bool kIsKeyFrame = true; 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. // bogus.
const VideoCodec kH264VideoCodec = VideoCodec::kCodecH264; const Codec kH264Codec = Codec::kCodecH264;
const AudioCodec kAacAudioCodec = AudioCodec::kCodecAAC; const Codec kAacCodec = Codec::kCodecAAC;
// TODO(rkuroiwa): It might make sense to inject factory functions to create // TODO(rkuroiwa): It might make sense to inject factory functions to create
// NalUnitToByteStreamConverter and AACAudioSpecificConfig so that these // NalUnitToByteStreamConverter and AACAudioSpecificConfig so that these
@ -102,20 +102,19 @@ class MockAACAudioSpecificConfig : public AACAudioSpecificConfig {
MOCK_CONST_METHOD1(ConvertToADTS, bool(std::vector<uint8_t>* buffer)); 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( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, codec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, codec, kCodecString, kVideoExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kVideoExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kVideoExtraData, arraysize(kVideoExtraData), kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
kIsEncrypted));
return stream_info; return stream_info;
} }
scoped_refptr<AudioStreamInfo> CreateAudioStreamInfo(AudioCodec codec) { scoped_refptr<AudioStreamInfo> CreateAudioStreamInfo(Codec codec) {
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo( scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, codec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, codec, kCodecString, kAudioExtraData,
kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, arraysize(kAudioExtraData), kSampleBits, kNumChannels, kSamplingFrequency,
kMaxBitrate, kAverageBitrate, kAudioExtraData, arraysize(kAudioExtraData), kSeekPreroll, kCodecDelay, kMaxBitrate, kAverageBitrate, kLanguage,
kIsEncrypted)); kIsEncrypted));
return stream_info; return stream_info;
} }
@ -140,7 +139,7 @@ class PesPacketGeneratorTest : public ::testing::Test {
const uint8_t* expected_output, const uint8_t* expected_output,
size_t expected_output_size) { size_t expected_output_size) {
scoped_refptr<VideoStreamInfo> stream_info( scoped_refptr<VideoStreamInfo> stream_info(
CreateVideoStreamInfo(kH264VideoCodec)); CreateVideoStreamInfo(kH264Codec));
EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -189,7 +188,7 @@ class PesPacketGeneratorTest : public ::testing::Test {
const uint8_t* expected_output, const uint8_t* expected_output,
size_t expected_output_size) { size_t expected_output_size) {
scoped_refptr<AudioStreamInfo> stream_info( scoped_refptr<AudioStreamInfo> stream_info(
CreateAudioStreamInfo(kAacAudioCodec)); CreateAudioStreamInfo(kAacCodec));
EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -224,26 +223,24 @@ class PesPacketGeneratorTest : public ::testing::Test {
}; };
TEST_F(PesPacketGeneratorTest, InitializeVideo) { TEST_F(PesPacketGeneratorTest, InitializeVideo) {
scoped_refptr<VideoStreamInfo> stream_info( scoped_refptr<VideoStreamInfo> stream_info(CreateVideoStreamInfo(kH264Codec));
CreateVideoStreamInfo(kH264VideoCodec));
EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_TRUE(generator_.Initialize(*stream_info));
} }
TEST_F(PesPacketGeneratorTest, InitializeVideoNonH264) { TEST_F(PesPacketGeneratorTest, InitializeVideoNonH264) {
scoped_refptr<VideoStreamInfo> stream_info( scoped_refptr<VideoStreamInfo> stream_info(
CreateVideoStreamInfo(VideoCodec::kCodecVP9)); CreateVideoStreamInfo(Codec::kCodecVP9));
EXPECT_FALSE(generator_.Initialize(*stream_info)); EXPECT_FALSE(generator_.Initialize(*stream_info));
} }
TEST_F(PesPacketGeneratorTest, InitializeAudio) { TEST_F(PesPacketGeneratorTest, InitializeAudio) {
scoped_refptr<AudioStreamInfo> stream_info( scoped_refptr<AudioStreamInfo> stream_info(CreateAudioStreamInfo(kAacCodec));
CreateAudioStreamInfo(kAacAudioCodec));
EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_TRUE(generator_.Initialize(*stream_info));
} }
TEST_F(PesPacketGeneratorTest, InitializeAudioNonAac) { TEST_F(PesPacketGeneratorTest, InitializeAudioNonAac) {
scoped_refptr<AudioStreamInfo> stream_info( scoped_refptr<AudioStreamInfo> stream_info(
CreateAudioStreamInfo(AudioCodec::kCodecOpus)); CreateAudioStreamInfo(Codec::kCodecOpus));
EXPECT_FALSE(generator_.Initialize(*stream_info)); EXPECT_FALSE(generator_.Initialize(*stream_info));
} }
@ -251,13 +248,12 @@ TEST_F(PesPacketGeneratorTest, InitializeAudioNonAac) {
TEST_F(PesPacketGeneratorTest, InitializeTextInfo) { TEST_F(PesPacketGeneratorTest, InitializeTextInfo) {
scoped_refptr<TextStreamInfo> stream_info( scoped_refptr<TextStreamInfo> stream_info(
new TextStreamInfo(kTrackId, kTimeScale, kDuration, kCodecString, new TextStreamInfo(kTrackId, kTimeScale, kDuration, kCodecString,
kLanguage, std::string(), kWidth, kHeight)); std::string(), kWidth, kHeight, kLanguage));
EXPECT_FALSE(generator_.Initialize(*stream_info)); EXPECT_FALSE(generator_.Initialize(*stream_info));
} }
TEST_F(PesPacketGeneratorTest, AddVideoSample) { TEST_F(PesPacketGeneratorTest, AddVideoSample) {
scoped_refptr<VideoStreamInfo> stream_info( scoped_refptr<VideoStreamInfo> stream_info(CreateVideoStreamInfo(kH264Codec));
CreateVideoStreamInfo(kH264VideoCodec));
EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -293,8 +289,7 @@ TEST_F(PesPacketGeneratorTest, AddVideoSample) {
} }
TEST_F(PesPacketGeneratorTest, AddVideoSampleFailedToConvert) { TEST_F(PesPacketGeneratorTest, AddVideoSampleFailedToConvert) {
scoped_refptr<VideoStreamInfo> stream_info( scoped_refptr<VideoStreamInfo> stream_info(CreateVideoStreamInfo(kH264Codec));
CreateVideoStreamInfo(kH264VideoCodec));
EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -316,8 +311,7 @@ TEST_F(PesPacketGeneratorTest, AddVideoSampleFailedToConvert) {
} }
TEST_F(PesPacketGeneratorTest, AddAudioSample) { TEST_F(PesPacketGeneratorTest, AddAudioSample) {
scoped_refptr<AudioStreamInfo> stream_info( scoped_refptr<AudioStreamInfo> stream_info(CreateAudioStreamInfo(kAacCodec));
CreateAudioStreamInfo(kAacAudioCodec));
EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -345,8 +339,7 @@ TEST_F(PesPacketGeneratorTest, AddAudioSample) {
} }
TEST_F(PesPacketGeneratorTest, AddAudioSampleFailedToConvert) { TEST_F(PesPacketGeneratorTest, AddAudioSampleFailedToConvert) {
scoped_refptr<AudioStreamInfo> stream_info( scoped_refptr<AudioStreamInfo> stream_info(CreateAudioStreamInfo(kAacCodec));
CreateAudioStreamInfo(kAacAudioCodec));
EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
@ -368,10 +361,9 @@ TEST_F(PesPacketGeneratorTest, AddAudioSampleFailedToConvert) {
TEST_F(PesPacketGeneratorTest, TimeStampScaling) { TEST_F(PesPacketGeneratorTest, TimeStampScaling) {
const uint32_t kTestTimescale = 1000; const uint32_t kTestTimescale = 1000;
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTestTimescale, kDuration, kH264VideoCodec, kCodecString, kTrackId, kTestTimescale, kDuration, kH264Codec, kCodecString,
kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kVideoExtraData, arraysize(kVideoExtraData), kWidth, kHeight, kPixelWidth,
kNaluLengthSize, kVideoExtraData, arraysize(kVideoExtraData), kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
kIsEncrypted));
EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_TRUE(generator_.Initialize(*stream_info));
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); 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 // All data here is bogus. They are used to create VideoStreamInfo but the
// actual values don't matter at all. // actual values don't matter at all.
const bool kIsKeyFrame = true; const bool kIsKeyFrame = true;
const VideoCodec kH264VideoCodec = VideoCodec::kCodecH264; const Codec kH264Codec = Codec::kCodecH264;
const uint8_t kExtraData[] = { const uint8_t kExtraData[] = {
0x00, 0x00,
}; };
@ -107,9 +107,9 @@ class TsSegmenterTest : public ::testing::Test {
TEST_F(TsSegmenterTest, Initialize) { TEST_F(TsSegmenterTest, Initialize) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options; MuxerOptions options;
options.segment_template = "file$Number$.ts"; options.segment_template = "file$Number$.ts";
TsSegmenter segmenter(options, nullptr); TsSegmenter segmenter(options, nullptr);
@ -127,9 +127,9 @@ TEST_F(TsSegmenterTest, Initialize) {
TEST_F(TsSegmenterTest, AddSample) { TEST_F(TsSegmenterTest, AddSample) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options; MuxerOptions options;
options.segment_duration = 10.0; options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts"; options.segment_template = "file$Number$.ts";
@ -182,9 +182,9 @@ TEST_F(TsSegmenterTest, PassedSegmentDuration) {
// done correctly in the segmenter. // done correctly in the segmenter.
const uint32_t kInputTimescale = 1001; const uint32_t kInputTimescale = 1001;
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kInputTimescale, kDuration, kH264VideoCodec, kCodecString, kTrackId, kInputTimescale, kDuration, kH264Codec, kCodecString,
kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kExtraData, arraysize(kExtraData), kWidth, kHeight, kPixelWidth,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options; MuxerOptions options;
options.segment_duration = 10.0; options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts"; options.segment_template = "file$Number$.ts";
@ -281,9 +281,9 @@ TEST_F(TsSegmenterTest, PassedSegmentDuration) {
// Finalize right after Initialize(). The writer will not be initialized. // Finalize right after Initialize(). The writer will not be initialized.
TEST_F(TsSegmenterTest, InitializeThenFinalize) { TEST_F(TsSegmenterTest, InitializeThenFinalize) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options; MuxerOptions options;
options.segment_duration = 10.0; options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts"; options.segment_template = "file$Number$.ts";
@ -310,9 +310,9 @@ TEST_F(TsSegmenterTest, InitializeThenFinalize) {
// writer with a mock. // writer with a mock.
TEST_F(TsSegmenterTest, Finalize) { TEST_F(TsSegmenterTest, Finalize) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options; MuxerOptions options;
options.segment_duration = 10.0; options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts"; 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. // Verify that it won't finish a segment if the sample is not a key frame.
TEST_F(TsSegmenterTest, SegmentOnlyBeforeKeyFrame) { TEST_F(TsSegmenterTest, SegmentOnlyBeforeKeyFrame) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options; MuxerOptions options;
options.segment_duration = 10.0; options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts"; options.segment_template = "file$Number$.ts";
@ -445,9 +445,9 @@ TEST_F(TsSegmenterTest, SegmentOnlyBeforeKeyFrame) {
TEST_F(TsSegmenterTest, WithEncryptionNoClearLead) { TEST_F(TsSegmenterTest, WithEncryptionNoClearLead) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options; MuxerOptions options;
options.segment_duration = 10.0; options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts"; options.segment_template = "file$Number$.ts";
@ -485,9 +485,9 @@ TEST_F(TsSegmenterTest, WithEncryptionNoClearLead) {
// not null. // not null.
TEST_F(TsSegmenterTest, WithEncryptionNoClearLeadNoMuxerListener) { TEST_F(TsSegmenterTest, WithEncryptionNoClearLeadNoMuxerListener) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options; MuxerOptions options;
options.segment_duration = 10.0; options.segment_duration = 10.0;
options.segment_template = "file$Number$.ts"; 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. // Verify that encryption notification is sent to objects after clear lead.
TEST_F(TsSegmenterTest, WithEncryptionWithClearLead) { TEST_F(TsSegmenterTest, WithEncryptionWithClearLead) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
MuxerOptions options; MuxerOptions options;
options.segment_duration = 1.0; 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) { if (stream_info.stream_type() == StreamType::kStreamVideo) {
const VideoStreamInfo& video_stream_info = const VideoStreamInfo& video_stream_info =
static_cast<const VideoStreamInfo&>(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 " LOG(ERROR) << "TsWriter cannot handle video codec "
<< video_stream_info.codec() << " yet."; << video_stream_info.codec() << " yet.";
return false; return false;
@ -184,7 +184,7 @@ bool TsWriter::Initialize(const StreamInfo& stream_info) {
DCHECK_EQ(stream_type, StreamType::kStreamAudio); DCHECK_EQ(stream_type, StreamType::kStreamAudio);
const AudioStreamInfo& audio_stream_info = const AudioStreamInfo& audio_stream_info =
static_cast<const AudioStreamInfo&>(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 " LOG(ERROR) << "TsWriter cannot handle audio codec "
<< audio_stream_info.codec() << " yet."; << audio_stream_info.codec() << " yet.";
return false; return false;

View File

@ -28,8 +28,8 @@ namespace {
const int kTsPacketSize = 188; const int kTsPacketSize = 188;
// Only {Audio,Video}Codec matter for this test. Other values are bogus. // Only {Audio,Video}Codec matter for this test. Other values are bogus.
const VideoCodec kH264VideoCodec = VideoCodec::kCodecH264; const Codec kH264Codec = Codec::kCodecH264;
const AudioCodec kAacAudioCodec = AudioCodec::kCodecAAC; const Codec kAacCodec = Codec::kCodecAAC;
const int kTrackId = 0; const int kTrackId = 0;
const uint32_t kTimeScale = 90000; const uint32_t kTimeScale = 90000;
const uint64_t kDuration = 180000; const uint64_t kDuration = 180000;
@ -158,35 +158,35 @@ class TsWriterTest : public ::testing::Test {
TEST_F(TsWriterTest, InitializeVideoH264) { TEST_F(TsWriterTest, InitializeVideoH264) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
} }
TEST_F(TsWriterTest, InitializeVideoNonH264) { TEST_F(TsWriterTest, InitializeVideoNonH264) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, VideoCodec::kCodecVP9, kCodecString, kTrackId, kTimeScale, kDuration, Codec::kCodecVP9, kCodecString,
kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kExtraData, arraysize(kExtraData), kWidth, kHeight, kPixelWidth,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_FALSE(ts_writer_.Initialize(*stream_info)); EXPECT_FALSE(ts_writer_.Initialize(*stream_info));
} }
TEST_F(TsWriterTest, InitializeAudioAac) { TEST_F(TsWriterTest, InitializeAudioAac) {
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo( scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, kAacAudioCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kAacCodec, kCodecString, kExtraData,
kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, arraysize(kExtraData), kSampleBits, kNumChannels, kSamplingFrequency,
kMaxBitrate, kAverageBitrate, kExtraData, arraysize(kExtraData), kSeekPreroll, kCodecDelay, kMaxBitrate, kAverageBitrate, kLanguage,
kIsEncrypted)); kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
} }
TEST_F(TsWriterTest, InitializeAudioNonAac) { TEST_F(TsWriterTest, InitializeAudioNonAac) {
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo( scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, AudioCodec::kCodecOpus, kCodecString, kTrackId, kTimeScale, kDuration, Codec::kCodecOpus, kCodecString,
kLanguage, kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kExtraData, arraysize(kExtraData), kSampleBits, kNumChannels,
kCodecDelay, kMaxBitrate, kAverageBitrate, kExtraData, kSamplingFrequency, kSeekPreroll, kCodecDelay, kMaxBitrate,
arraysize(kExtraData), kIsEncrypted)); kAverageBitrate, kLanguage, kIsEncrypted));
EXPECT_FALSE(ts_writer_.Initialize(*stream_info)); EXPECT_FALSE(ts_writer_.Initialize(*stream_info));
} }
@ -199,9 +199,9 @@ TEST_F(TsWriterTest, ClearH264Psi) {
EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(WriteOnePmt()); EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(WriteOnePmt());
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -253,10 +253,10 @@ TEST_F(TsWriterTest, ClearAacPmt) {
EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(WriteOnePmt()); EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(WriteOnePmt());
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo( 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, kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay,
kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData, kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted));
arraysize(kAacBasicProfileExtraData), kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -281,9 +281,9 @@ TEST_F(TsWriterTest, ClearLeadH264Pmt) {
.WillOnce(WriteTwoPmts()); .WillOnce(WriteTwoPmts());
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -310,9 +310,9 @@ TEST_F(TsWriterTest, EncryptedSegmentsH264Pmt) {
EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(WriteOnePmt()); EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(WriteOnePmt());
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -341,10 +341,10 @@ TEST_F(TsWriterTest, ClearLeadAacPmt) {
.WillOnce(WriteTwoPmts()); .WillOnce(WriteTwoPmts());
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo( 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, kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay,
kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData, kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted));
arraysize(kAacBasicProfileExtraData), kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -371,10 +371,10 @@ TEST_F(TsWriterTest, EncryptedSegmentsAacPmt) {
EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(WriteOnePmt()); EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(WriteOnePmt());
scoped_refptr<AudioStreamInfo> stream_info(new AudioStreamInfo( 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, kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay,
kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData, kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted));
arraysize(kAacBasicProfileExtraData), kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass());
@ -398,9 +398,9 @@ TEST_F(TsWriterTest, EncryptedSegmentsAacPmt) {
TEST_F(TsWriterTest, AddPesPacket) { TEST_F(TsWriterTest, AddPesPacket) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_));
@ -463,9 +463,9 @@ TEST_F(TsWriterTest, AddPesPacket) {
// Verify that PES packet > 64KiB can be handled. // Verify that PES packet > 64KiB can be handled.
TEST_F(TsWriterTest, BigPesPacket) { TEST_F(TsWriterTest, BigPesPacket) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_));
@ -499,9 +499,9 @@ TEST_F(TsWriterTest, BigPesPacket) {
// PTS (implicilty) cast to bool is true. // PTS (implicilty) cast to bool is true.
TEST_F(TsWriterTest, PesPtsZeroNoDts) { TEST_F(TsWriterTest, PesPtsZeroNoDts) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_));
@ -559,9 +559,9 @@ TEST_F(TsWriterTest, PesPtsZeroNoDts) {
// adaptation_field_length should be 0. // adaptation_field_length should be 0.
TEST_F(TsWriterTest, TsPacketPayload183Bytes) { TEST_F(TsWriterTest, TsPacketPayload183Bytes) {
scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo( scoped_refptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); 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)); subsamples->push_back(SubsampleEntry(clear_bytes, cipher_bytes));
} }
VideoCodec GetVideoCodec(const StreamInfo& stream_info) { Codec GetCodec(const StreamInfo& stream_info) {
if (stream_info.stream_type() != kStreamVideo) if (stream_info.stream_type() != kStreamVideo) return kUnknownCodec;
return kUnknownVideoCodec;
const VideoStreamInfo& video_stream_info = const VideoStreamInfo& video_stream_info =
static_cast<const VideoStreamInfo&>(stream_info); static_cast<const VideoStreamInfo&>(stream_info);
return video_stream_info.codec(); return video_stream_info.codec();
@ -60,19 +59,15 @@ uint8_t GetNaluLengthSize(const StreamInfo& stream_info) {
} // namespace } // namespace
EncryptingFragmenter::EncryptingFragmenter( EncryptingFragmenter::EncryptingFragmenter(
scoped_refptr<StreamInfo> info, scoped_refptr<StreamInfo> info, TrackFragment* traf,
TrackFragment* traf, scoped_ptr<EncryptionKey> encryption_key, int64_t clear_time,
scoped_ptr<EncryptionKey> encryption_key, FourCC protection_scheme, uint8_t crypt_byte_block, uint8_t skip_byte_block,
int64_t clear_time,
FourCC protection_scheme,
uint8_t crypt_byte_block,
uint8_t skip_byte_block,
MuxerListener* listener) MuxerListener* listener)
: Fragmenter(info, traf), : Fragmenter(info, traf),
info_(info), info_(info),
encryption_key_(encryption_key.Pass()), encryption_key_(encryption_key.Pass()),
nalu_length_size_(GetNaluLengthSize(*info)), nalu_length_size_(GetNaluLengthSize(*info)),
video_codec_(GetVideoCodec(*info)), video_codec_(GetCodec(*info)),
clear_time_(clear_time), clear_time_(clear_time),
protection_scheme_(protection_scheme), protection_scheme_(protection_scheme),
crypt_byte_block_(crypt_byte_block), 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 // 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. // the size field in bytes. Can be 1, 2 or 4 bytes.
const uint8_t nalu_length_size_; const uint8_t nalu_length_size_;
const VideoCodec video_codec_; const Codec video_codec_;
int64_t clear_time_; int64_t clear_time_;
const FourCC protection_scheme_; const FourCC protection_scheme_;
const uint8_t crypt_byte_block_; 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; return (static_cast<double>(time_in_old_scale) / old_scale) * new_scale;
} }
VideoCodec FourCCToVideoCodec(FourCC fourcc) { Codec FourCCToCodec(FourCC fourcc) {
switch (fourcc) { switch (fourcc) {
case FOURCC_avc1: case FOURCC_avc1:
return kCodecH264; return kCodecH264;
@ -54,13 +54,6 @@ VideoCodec FourCCToVideoCodec(FourCC fourcc) {
return kCodecVP9; return kCodecVP9;
case FOURCC_vp10: case FOURCC_vp10:
return kCodecVP10; return kCodecVP10;
default:
return kUnknownVideoCodec;
}
}
AudioCodec FourCCToAudioCodec(FourCC fourcc) {
switch(fourcc) {
case FOURCC_Opus: case FOURCC_Opus:
return kCodecOpus; return kCodecOpus;
case FOURCC_dtsc: case FOURCC_dtsc:
@ -80,7 +73,7 @@ AudioCodec FourCCToAudioCodec(FourCC fourcc) {
case FOURCC_ec_3: case FOURCC_ec_3:
return kCodecEAC3; return kCodecEAC3;
default: default:
return kUnknownAudioCodec; return kUnknownCodec;
} }
} }
@ -343,7 +336,7 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx]; const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx];
const FourCC actual_format = entry.GetActualFormat(); const FourCC actual_format = entry.GetActualFormat();
AudioCodec codec = FourCCToAudioCodec(actual_format); Codec codec = FourCCToCodec(actual_format);
uint8_t num_channels = 0; uint8_t num_channels = 0;
uint32_t sampling_frequency = 0; uint32_t sampling_frequency = 0;
uint64_t codec_delay_ns = 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; entry.sinf.info.track_encryption.default_is_protected == 1;
DVLOG(1) << "is_audio_track_encrypted_: " << is_encrypted; DVLOG(1) << "is_audio_track_encrypted_: " << is_encrypted;
streams.push_back(new AudioStreamInfo( streams.push_back(new AudioStreamInfo(
track->header.track_id, track->header.track_id, timescale, duration, codec,
timescale,
duration,
codec,
AudioStreamInfo::GetCodecString(codec, audio_object_type), AudioStreamInfo::GetCodecString(codec, audio_object_type),
track->media.header.language.code, codec_config.data(), codec_config.size(), entry.samplesize,
entry.samplesize, num_channels, sampling_frequency, seek_preroll_ns, codec_delay_ns,
num_channels, max_bitrate, avg_bitrate, track->media.header.language.code,
sampling_frequency,
seek_preroll_ns,
codec_delay_ns,
max_bitrate,
avg_bitrate,
codec_config.data(),
codec_config.size(),
is_encrypted)); is_encrypted));
} }
@ -509,7 +492,7 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
uint8_t nalu_length_size = 0; uint8_t nalu_length_size = 0;
const FourCC actual_format = entry.GetActualFormat(); const FourCC actual_format = entry.GetActualFormat();
const VideoCodec video_codec = FourCCToVideoCodec(actual_format); const Codec video_codec = FourCCToCodec(actual_format);
switch (actual_format) { switch (actual_format) {
case FOURCC_avc1: { case FOURCC_avc1: {
AVCDecoderConfigurationRecord avc_config; AVCDecoderConfigurationRecord avc_config;
@ -580,11 +563,11 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted; DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted;
streams.push_back(new VideoStreamInfo( streams.push_back(new VideoStreamInfo(
track->header.track_id, timescale, duration, video_codec, track->header.track_id, timescale, duration, video_codec,
codec_string, track->media.header.language.code, coded_width, codec_string, entry.codec_configuration.data.data(),
coded_height, pixel_width, pixel_height, entry.codec_configuration.data.size(), coded_width, coded_height,
pixel_width, pixel_height,
0, // trick_play_rate 0, // trick_play_rate
nalu_length_size, entry.codec_configuration.data.data(), nalu_length_size, track->media.header.language.code, is_encrypted));
entry.codec_configuration.data.size(), is_encrypted));
} }
} }

View File

@ -40,7 +40,7 @@ void SetStartAndEndFromOffsetAndSize(size_t offset,
*end = *start + static_cast<uint32_t>(size) - 1; *end = *start + static_cast<uint32_t>(size) - 1;
} }
FourCC VideoCodecToFourCC(VideoCodec codec) { FourCC CodecToFourCC(Codec codec) {
switch (codec) { switch (codec) {
case kCodecH264: case kCodecH264:
return FOURCC_avc1; return FOURCC_avc1;
@ -54,13 +54,6 @@ FourCC VideoCodecToFourCC(VideoCodec codec) {
return FOURCC_vp09; return FOURCC_vp09;
case kCodecVP10: case kCodecVP10:
return FOURCC_vp10; return FOURCC_vp10;
default:
return FOURCC_NULL;
}
}
FourCC AudioCodecToFourCC(AudioCodec codec) {
switch (codec) {
case kCodecAAC: case kCodecAAC:
return FOURCC_mp4a; return FOURCC_mp4a;
case kCodecAC3: case kCodecAC3:
@ -100,7 +93,7 @@ Status MP4Muxer::Initialize() {
ftyp->compatible_brands.push_back(FOURCC_mp41); ftyp->compatible_brands.push_back(FOURCC_mp41);
if (streams().size() == 1 && if (streams().size() == 1 &&
streams()[0]->info()->stream_type() == kStreamVideo) { streams()[0]->info()->stream_type() == kStreamVideo) {
const FourCC codec_fourcc = VideoCodecToFourCC( const FourCC codec_fourcc = CodecToFourCC(
static_cast<VideoStreamInfo*>(streams()[0]->info().get())->codec()); static_cast<VideoStreamInfo*>(streams()[0]->info().get())->codec());
if (codec_fourcc != FOURCC_NULL) if (codec_fourcc != FOURCC_NULL)
ftyp->compatible_brands.push_back(codec_fourcc); 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; trak->header.height = video_info->height() * 0x10000;
VideoSampleEntry video; VideoSampleEntry video;
video.format = VideoCodecToFourCC(video_info->codec()); video.format = CodecToFourCC(video_info->codec());
video.width = video_info->width(); video.width = video_info->width();
video.height = video_info->height(); video.height = video_info->height();
video.codec_configuration.data = video_info->codec_config(); video.codec_configuration.data = video_info->codec_config();
@ -249,7 +242,7 @@ void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info,
trak->header.volume = 0x100; trak->header.volume = 0x100;
AudioSampleEntry audio; AudioSampleEntry audio;
audio.format = AudioCodecToFourCC(audio_info->codec()); audio.format = CodecToFourCC(audio_info->codec());
switch(audio_info->codec()){ switch(audio_info->codec()){
case kCodecAAC: case kCodecAAC:
audio.esds.es_descriptor.set_object_type(kISO_14496_3); // MPEG4 AAC. 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 "packager/media/formats/webm/encryptor.h"
#include <gflags/gflags.h>
#include "packager/media/base/aes_encryptor.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/fourccs.h"
#include "packager/media/base/media_sample.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 shaka {
namespace media { namespace media {
namespace webm { namespace webm {
namespace { namespace {
const size_t kAesBlockSize = 16;
Status CreateContentEncryption(mkvmuxer::Track* track, EncryptionKey* key) { Status CreateContentEncryption(mkvmuxer::Track* track, EncryptionKey* key) {
if (!track->AddContentEncoding()) { if (!track->AddContentEncoding()) {
return Status(error::INTERNAL_ERROR, return Status(error::INTERNAL_ERROR,
@ -54,9 +60,12 @@ Encryptor::~Encryptor() {}
Status Encryptor::Initialize(MuxerListener* muxer_listener, Status Encryptor::Initialize(MuxerListener* muxer_listener,
KeySource::TrackType track_type, KeySource::TrackType track_type,
KeySource* key_source) { Codec codec,
KeySource* key_source,
bool webm_subsample_encryption) {
DCHECK(key_source); 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) { Status Encryptor::AddTrackInfo(mkvmuxer::Track* track) {
@ -69,10 +78,71 @@ Status Encryptor::EncryptFrame(scoped_refptr<MediaSample> sample,
DCHECK(encryptor_); DCHECK(encryptor_);
const size_t sample_size = sample->data_size(); const size_t sample_size = sample->data_size();
// 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.");
}
}
if (encrypt_frame) { if (encrypt_frame) {
// | 1 | iv | enc_data |
const size_t iv_size = encryptor_->iv().size(); const size_t iv_size = encryptor_->iv().size();
sample->resize_data(sample_size + iv_size + 1); 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(); uint8_t* sample_data = sample->writable_data();
// Encrypt the data in-place. // Encrypt the data in-place.
@ -80,15 +150,16 @@ Status Encryptor::EncryptFrame(scoped_refptr<MediaSample> sample,
return Status(error::MUXER_FAILURE, "Failed to encrypt the frame."); 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 // First move the sample data to after the IV; then write the IV and
// byte. // signal byte.
memmove(sample_data + iv_size + 1, sample_data, sample_size); memmove(sample_data + iv_size + kWebMSignalByteSize, sample_data,
sample_data[0] = 0x01; sample_size);
sample_data[0] = kWebMEncryptedSignal;
memcpy(sample_data + 1, encryptor_->iv().data(), iv_size); memcpy(sample_data + 1, encryptor_->iv().data(), iv_size);
}
encryptor_->UpdateIv(); encryptor_->UpdateIv();
} else { } else {
// | 0 | data | // Clear sample: | signal_byte(0) | data |
sample->resize_data(sample_size + 1); sample->resize_data(sample_size + 1);
uint8_t* sample_data = sample->writable_data(); uint8_t* sample_data = sample->writable_data();
memmove(sample_data + 1, sample_data, sample_size); 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, Status Encryptor::CreateEncryptor(MuxerListener* muxer_listener,
KeySource::TrackType track_type, KeySource::TrackType track_type,
KeySource* key_source) { Codec codec,
KeySource* key_source,
bool webm_subsample_encryption) {
scoped_ptr<EncryptionKey> encryption_key(new EncryptionKey()); scoped_ptr<EncryptionKey> encryption_key(new EncryptionKey());
Status status = key_source->GetKey(track_type, encryption_key.get()); Status status = key_source->GetKey(track_type, encryption_key.get());
if (!status.ok()) if (!status.ok())
@ -109,13 +182,18 @@ Status Encryptor::CreateEncryptor(MuxerListener* muxer_listener,
if (!AesCryptor::GenerateRandomIv(FOURCC_cenc, &encryption_key->iv)) if (!AesCryptor::GenerateRandomIv(FOURCC_cenc, &encryption_key->iv))
return Status(error::INTERNAL_ERROR, "Failed to generate random iv."); return Status(error::INTERNAL_ERROR, "Failed to generate random iv.");
} }
DCHECK_EQ(kWebMIvSize, encryption_key->iv.size());
scoped_ptr<AesCtrEncryptor> encryptor(new AesCtrEncryptor()); scoped_ptr<AesCtrEncryptor> encryptor(new AesCtrEncryptor());
const bool initialized = const bool initialized =
encryptor->InitializeWithIv(encryption_key->key, encryption_key->iv); encryptor->InitializeWithIv(encryption_key->key, encryption_key->iv);
if (!initialized) if (!initialized)
return Status(error::INTERNAL_ERROR, "Failed to create the encryptor."); 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) { if (muxer_listener) {
const bool kInitialEncryptionInfo = true; const bool kInitialEncryptionInfo = true;
muxer_listener->OnEncryptionInfoReady( muxer_listener->OnEncryptionInfoReady(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,6 +5,7 @@
#ifndef MEDIA_FORMATS_WEBM_WEBM_CONSTANTS_H_ #ifndef MEDIA_FORMATS_WEBM_WEBM_CONSTANTS_H_
#define MEDIA_FORMATS_WEBM_WEBM_CONSTANTS_H_ #define MEDIA_FORMATS_WEBM_WEBM_CONSTANTS_H_
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
namespace shaka { namespace shaka {
@ -207,9 +208,13 @@ const uint8_t kWebMFlagKeyframe = 0x80;
/// Current encrypted WebM request for comments specification is here /// Current encrypted WebM request for comments specification is here
/// http://wiki.webmproject.org/encryption/webm-encryption-rfc /// http://wiki.webmproject.org/encryption/webm-encryption-rfc
const uint8_t kWebMFlagEncryptedFrame = 0x1; const size_t kWebMIvSize = 8;
const int kWebMIvSize = 8; const size_t kWebMSignalByteSize = 1;
const int 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 /// Current specification for WebVTT embedded in WebM
/// http://wiki.webmproject.org/webm-metadata/temporal-metadata/webvtt-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/logging.h"
#include "packager/base/sys_byteorder.h" #include "packager/base/sys_byteorder.h"
#include "packager/media/base/buffer_reader.h"
#include "packager/media/formats/webm/webm_constants.h" #include "packager/media/formats/webm/webm_constants.h"
namespace shaka { namespace shaka {
@ -16,48 +17,96 @@ namespace {
// CTR IV appended with a CTR block counter. |iv| is an 8 byte CTR IV. // 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 // |iv_size| is the size of |iv| in btyes. Returns a string of
// kDecryptionKeySize bytes. // kDecryptionKeySize bytes.
std::string GenerateWebMCounterBlock(const uint8_t* iv, int iv_size) { std::vector<uint8_t> GenerateWebMCounterBlock(const uint8_t* iv, int iv_size) {
std::string counter_block(reinterpret_cast<const char*>(iv), iv_size); std::vector<uint8_t> counter_block(iv, iv + iv_size);
counter_block.append(DecryptConfig::kDecryptionKeySize - iv_size, 0); counter_block.insert(counter_block.end(),
DecryptConfig::kDecryptionKeySize - iv_size, 0);
return counter_block; return counter_block;
} }
} // namespace anonymous } // namespace anonymous
// TODO(tinskip): Add unit test for this function.
bool WebMCreateDecryptConfig(const uint8_t* data, bool WebMCreateDecryptConfig(const uint8_t* data,
int data_size, int data_size,
const uint8_t* key_id, const uint8_t* key_id,
int key_id_size, int key_id_size,
scoped_ptr<DecryptConfig>* decrypt_config, scoped_ptr<DecryptConfig>* decrypt_config,
int* data_offset) { int* data_offset) {
if (data_size < kWebMSignalByteSize) { int header_size = kWebMSignalByteSize;
DVLOG(1) << "Got a block from an encrypted stream with no data."; if (data_size < header_size) {
DVLOG(1) << "Empty WebM sample.";
return false; return false;
} }
uint8_t signal_byte = data[0]; uint8_t signal_byte = data[0];
int frame_offset = sizeof(signal_byte);
// Setting the DecryptConfig object of the buffer while leaving the if (signal_byte & kWebMEncryptedSignal) {
// initialization vector empty will tell the decryptor that the frame is // Encrypted sample.
// unencrypted. header_size += kWebMIvSize;
std::string counter_block; if (data_size < header_size) {
DVLOG(1) << "Encrypted WebM sample too small to hold IV: " << data_size;
if (signal_byte & kWebMFlagEncryptedFrame) {
if (data_size < kWebMSignalByteSize + kWebMIvSize) {
DVLOG(1) << "Got an encrypted block with not enough data " << data_size;
return false; return false;
} }
counter_block = GenerateWebMCounterBlock(data + frame_offset, kWebMIvSize); std::vector<SubsampleEntry> subsamples;
frame_offset += kWebMIvSize; 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( decrypt_config->reset(new DecryptConfig(
std::vector<uint8_t>(key_id, key_id + key_id_size), std::vector<uint8_t>(key_id, key_id + key_id_size),
std::vector<uint8_t>(counter_block.begin(), counter_block.end()), GenerateWebMCounterBlock(data + kWebMSignalByteSize, kWebMIvSize),
std::vector<SubsampleEntry>())); subsamples));
*data_offset = frame_offset; } else {
// Clear sample.
decrypt_config->reset();
}
*data_offset = header_size;
return true; return true;
} }

View File

@ -53,7 +53,7 @@ scoped_refptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
const std::string& codec_id, const std::string& codec_id,
const std::vector<uint8_t>& codec_private, const std::vector<uint8_t>& codec_private,
bool is_encrypted) { bool is_encrypted) {
VideoCodec video_codec = kUnknownVideoCodec; Codec video_codec = kUnknownCodec;
if (codec_id == "V_VP8") { if (codec_id == "V_VP8") {
video_codec = kCodecVP8; video_codec = kCodecVP8;
} else if (codec_id == "V_VP9") { } else if (codec_id == "V_VP9") {
@ -110,9 +110,9 @@ scoped_refptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
sar_y /= gcd; sar_y /= gcd;
return scoped_refptr<VideoStreamInfo>(new VideoStreamInfo( return scoped_refptr<VideoStreamInfo>(new VideoStreamInfo(
track_num, kWebMTimeScale, 0, video_codec, std::string(), std::string(), track_num, kWebMTimeScale, 0, video_codec, std::string(),
width_after_crop, height_after_crop, sar_x, sar_y, 0, 0, codec_private.data(), codec_private.size(), width_after_crop,
codec_private.data(), codec_private.size(), is_encrypted)); height_after_crop, sar_x, sar_y, 0, 0, std::string(), is_encrypted));
} }
bool WebMVideoClient::OnUInt(int id, int64_t val) { 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 // There is no one metadata to determine what the language is. Parts
// of the text may be annotated as some specific language. // of the text may be annotated as some specific language.
const char kLanguage[] = ""; const char kLanguage[] = "";
streams.push_back(new TextStreamInfo( streams.push_back(new TextStreamInfo(kTrackId, kTimescale, kDuration,
kTrackId,
kTimescale,
kDuration,
"wvtt", "wvtt",
kLanguage,
base::JoinString(header_, "\n"), base::JoinString(header_, "\n"),
0, // Not necessary. 0, // Not necessary.
0)); // Not necessary. 0,
kLanguage)); // Not necessary.
init_cb_.Run(streams); init_cb_.Run(streams);
state_ = kCueIdentifierOrTimingOrComment; state_ = kCueIdentifierOrTimingOrComment;

View File

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

Binary file not shown.