diff --git a/packager/app/muxer_flags.cc b/packager/app/muxer_flags.cc index ba8db86500..2df3aab66b 100644 --- a/packager/app/muxer_flags.cc +++ b/packager/app/muxer_flags.cc @@ -50,4 +50,5 @@ DEFINE_string(temp_dir, "", "Specify a directory in which to store temporary (intermediate) " " files. Used only if single_segment=true."); - +DEFINE_bool(webm_subsample_encryption, true, + "Enable WebM subsample encryption."); diff --git a/packager/app/muxer_flags.h b/packager/app/muxer_flags.h index b9e682e709..c1e450aa89 100644 --- a/packager/app/muxer_flags.h +++ b/packager/app/muxer_flags.h @@ -20,5 +20,6 @@ DECLARE_double(fragment_duration); DECLARE_bool(fragment_sap_aligned); DECLARE_int32(num_subsegments_per_sidx); DECLARE_string(temp_dir); +DECLARE_bool(webm_subsample_encryption); #endif // APP_MUXER_FLAGS_H_ diff --git a/packager/app/packager_util.cc b/packager/app/packager_util.cc index ba46189b95..46e02be0be 100644 --- a/packager/app/packager_util.cc +++ b/packager/app/packager_util.cc @@ -154,7 +154,7 @@ bool GetMuxerOptions(MuxerOptions* muxer_options) { muxer_options->segment_sap_aligned = FLAGS_segment_sap_aligned; muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned; muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx; - + muxer_options->webm_subsample_encryption = FLAGS_webm_subsample_encryption; if (FLAGS_mp4_use_decoding_timestamp_in_timeline) { LOG(WARNING) << "Flag --mp4_use_decoding_timestamp_in_timeline is set. " "Note that it is a temporary hack to workaround Chromium " diff --git a/packager/app/test/packager_test.py b/packager/app/test/packager_test.py index 2c73889fa3..6bed8b64c0 100755 --- a/packager/app/test/packager_test.py +++ b/packager/app/test/packager_test.py @@ -195,6 +195,16 @@ class PackagerAppTest(unittest.TestCase): self._VerifyDecryption(self.output[0], 'bear-640x360-a-golden.mp4') self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4') + def testPackageWithWebmSubsampleEncryption(self): + self.packager.Package( + self._GetStreams(['video'], + output_format='webm', + test_files=['bear-640x360-vp9-altref.webm']), + self._GetFlags(encryption=True)) + self._DiffGold(self.output[0], 'bear-640x360-vp9-altref-enc-golden.webm') + self._VerifyDecryption(self.output[0], + 'bear-640x360-vp9-altref-dec-golden.webm') + def testPackageAvcTsWithEncryption(self): # Currently we only support live packaging for ts. self.packager.Package( diff --git a/packager/app/test/testdata/bear-640x360-vp9-altref-dec-golden.webm b/packager/app/test/testdata/bear-640x360-vp9-altref-dec-golden.webm new file mode 100644 index 0000000000..29aae257b3 Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-vp9-altref-dec-golden.webm differ diff --git a/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm b/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm new file mode 100644 index 0000000000..63cc98e9e4 Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm differ diff --git a/packager/media/base/audio_stream_info.cc b/packager/media/base/audio_stream_info.cc index fbf96092c8..ccf5fddaa8 100644 --- a/packager/media/base/audio_stream_info.cc +++ b/packager/media/base/audio_stream_info.cc @@ -17,8 +17,8 @@ namespace shaka { namespace media { namespace { -std::string AudioCodecToString(AudioCodec audio_codec) { - switch (audio_codec) { +std::string AudioCodecToString(Codec codec) { + switch (codec) { case kCodecAAC: return "AAC"; case kCodecAC3: @@ -42,38 +42,22 @@ std::string AudioCodecToString(AudioCodec audio_codec) { case kCodecVorbis: return "Vorbis"; default: - NOTIMPLEMENTED() << "Unknown Audio Codec: " << audio_codec; - return "UnknownAudioCodec"; + NOTIMPLEMENTED() << "Unknown Audio Codec: " << codec; + return "UnknownCodec"; } } } // namespace -AudioStreamInfo::AudioStreamInfo(int track_id, - uint32_t time_scale, - uint64_t duration, - AudioCodec codec, - const std::string& codec_string, - const std::string& language, - uint8_t sample_bits, - uint8_t num_channels, - uint32_t sampling_frequency, - uint64_t seek_preroll_ns, - uint64_t codec_delay_ns, - uint32_t max_bitrate, - uint32_t avg_bitrate, - const uint8_t* codec_config, - size_t codec_config_size, - bool is_encrypted) - : StreamInfo(kStreamAudio, - track_id, - time_scale, - duration, - codec_string, - language, - codec_config, - codec_config_size, +AudioStreamInfo::AudioStreamInfo( + int track_id, uint32_t time_scale, uint64_t duration, Codec codec, + const std::string& codec_string, const uint8_t* codec_config, + size_t codec_config_size, uint8_t sample_bits, uint8_t num_channels, + uint32_t sampling_frequency, uint64_t seek_preroll_ns, + uint64_t codec_delay_ns, uint32_t max_bitrate, uint32_t avg_bitrate, + const std::string& language, bool is_encrypted) + : StreamInfo(kStreamAudio, track_id, time_scale, duration, codec, + codec_string, codec_config, codec_config_size, language, is_encrypted), - codec_(codec), sample_bits_(sample_bits), num_channels_(num_channels), sampling_frequency_(sampling_frequency), @@ -85,10 +69,9 @@ AudioStreamInfo::AudioStreamInfo(int track_id, AudioStreamInfo::~AudioStreamInfo() {} bool AudioStreamInfo::IsValidConfig() const { - return codec_ != kUnknownAudioCodec && num_channels_ != 0 && + return codec() != kUnknownCodec && num_channels_ != 0 && num_channels_ <= limits::kMaxChannels && sample_bits_ > 0 && - sample_bits_ <= limits::kMaxBitsPerSample && - sampling_frequency_ > 0 && + sample_bits_ <= limits::kMaxBitsPerSample && sampling_frequency_ > 0 && sampling_frequency_ <= limits::kMaxSampleRate; } @@ -96,7 +79,7 @@ std::string AudioStreamInfo::ToString() const { std::string str = base::StringPrintf( "%s codec: %s\n sample_bits: %d\n num_channels: %d\n " "sampling_frequency: %d\n language: %s\n", - StreamInfo::ToString().c_str(), AudioCodecToString(codec_).c_str(), + StreamInfo::ToString().c_str(), AudioCodecToString(codec()).c_str(), sample_bits_, num_channels_, sampling_frequency_, language().c_str()); if (seek_preroll_ns_ != 0) { base::StringAppendF(&str, " seek_preroll_ns: %" PRIu64 "\n", @@ -109,7 +92,7 @@ std::string AudioStreamInfo::ToString() const { return str; } -std::string AudioStreamInfo::GetCodecString(AudioCodec codec, +std::string AudioStreamInfo::GetCodecString(Codec codec, uint8_t audio_object_type) { switch (codec) { case kCodecVorbis: diff --git a/packager/media/base/audio_stream_info.h b/packager/media/base/audio_stream_info.h index e6bb0870a0..a68c4e1364 100644 --- a/packager/media/base/audio_stream_info.h +++ b/packager/media/base/audio_stream_info.h @@ -14,42 +14,17 @@ namespace shaka { namespace media { -enum AudioCodec { - kUnknownAudioCodec = 0, - kCodecAAC, - kCodecAC3, - kCodecDTSC, - kCodecDTSE, - kCodecDTSH, - kCodecDTSL, - kCodecDTSM, - kCodecDTSP, - kCodecEAC3, - kCodecOpus, - kCodecVorbis, - - kNumAudioCodec -}; - /// Holds audio stream information. class AudioStreamInfo : public StreamInfo { public: /// Construct an initialized audio stream info object. - AudioStreamInfo(int track_id, - uint32_t time_scale, - uint64_t duration, - AudioCodec codec, - const std::string& codec_string, - const std::string& language, - uint8_t sample_bits, - uint8_t num_channels, - uint32_t sampling_frequency, - uint64_t seek_preroll_ns, - uint64_t codec_delay_ns, - uint32_t max_bitrate, - uint32_t avg_bitrate, - const uint8_t* codec_config, - size_t codec_config_size, + AudioStreamInfo(int track_id, uint32_t time_scale, uint64_t duration, + Codec codec, const std::string& codec_string, + const uint8_t* codec_config, size_t codec_config_size, + uint8_t sample_bits, uint8_t num_channels, + uint32_t sampling_frequency, uint64_t seek_preroll_ns, + uint64_t codec_delay_ns, uint32_t max_bitrate, + uint32_t avg_bitrate, const std::string& language, bool is_encrypted); /// @name StreamInfo implementation overrides. @@ -58,7 +33,6 @@ class AudioStreamInfo : public StreamInfo { std::string ToString() const override; /// @} - AudioCodec codec() const { return codec_; } uint8_t sample_bits() const { return sample_bits_; } uint8_t sample_bytes() const { return sample_bits_ / 8; } uint8_t num_channels() const { return num_channels_; } @@ -71,20 +45,17 @@ class AudioStreamInfo : public StreamInfo { uint32_t max_bitrate() const { return max_bitrate_; } uint32_t avg_bitrate() const { return avg_bitrate_; } - void set_codec(AudioCodec codec) { codec_ = codec; } void set_sampling_frequency(const uint32_t sampling_frequency) { sampling_frequency_ = sampling_frequency; } /// @param audio_object_type is only used by AAC Codec, ignored otherwise. /// @return The codec string. - static std::string GetCodecString(AudioCodec codec, - uint8_t audio_object_type); + static std::string GetCodecString(Codec codec, uint8_t audio_object_type); private: ~AudioStreamInfo() override; - AudioCodec codec_; uint8_t sample_bits_; uint8_t num_channels_; uint32_t sampling_frequency_; diff --git a/packager/media/base/muxer_options.cc b/packager/media/base/muxer_options.cc index c17f955cad..0e3bc82efb 100644 --- a/packager/media/base/muxer_options.cc +++ b/packager/media/base/muxer_options.cc @@ -17,7 +17,8 @@ MuxerOptions::MuxerOptions() fragment_sap_aligned(false), num_subsegments_per_sidx(0), mp4_use_decoding_timestamp_in_timeline(false), - bandwidth(0) {} + bandwidth(0), + webm_subsample_encryption(true) {} MuxerOptions::~MuxerOptions() {} } // namespace media diff --git a/packager/media/base/muxer_options.h b/packager/media/base/muxer_options.h index 04bada69c7..5160df24b7 100644 --- a/packager/media/base/muxer_options.h +++ b/packager/media/base/muxer_options.h @@ -73,6 +73,9 @@ struct MuxerOptions { /// User-specified bit rate for the media stream. If zero, the muxer will /// attempt to estimate. uint32_t bandwidth; + + // Enable/disable subsample encryption for WebM containers. + bool webm_subsample_encryption; }; } // namespace media diff --git a/packager/media/base/stream_info.cc b/packager/media/base/stream_info.cc index f883b99973..b856514a0f 100644 --- a/packager/media/base/stream_info.cc +++ b/packager/media/base/stream_info.cc @@ -14,19 +14,16 @@ namespace shaka { namespace media { -StreamInfo::StreamInfo(StreamType stream_type, - int track_id, - uint32_t time_scale, - uint64_t duration, +StreamInfo::StreamInfo(StreamType stream_type, int track_id, + uint32_t time_scale, uint64_t duration, Codec codec, const std::string& codec_string, - const std::string& language, - const uint8_t* codec_config, - size_t codec_config_size, - bool is_encrypted) + const uint8_t* codec_config, size_t codec_config_size, + const std::string& language, bool is_encrypted) : stream_type_(stream_type), track_id_(track_id), time_scale_(time_scale), duration_(duration), + codec_(codec), codec_string_(codec_string), language_(language), is_encrypted_(is_encrypted) { diff --git a/packager/media/base/stream_info.h b/packager/media/base/stream_info.h index 2ff325ddcb..7384d87bc1 100644 --- a/packager/media/base/stream_info.h +++ b/packager/media/base/stream_info.h @@ -22,18 +22,40 @@ enum StreamType { kStreamText, }; +enum Codec { + kUnknownCodec = 0, + kCodecH264, + kCodecHEV1, + kCodecHVC1, + kCodecVC1, + kCodecMPEG2, + kCodecMPEG4, + kCodecTheora, + kCodecVP8, + kCodecVP9, + kCodecVP10, + kCodecAAC, + kCodecAC3, + kCodecDTSC, + kCodecDTSE, + kCodecDTSH, + kCodecDTSL, + kCodecDTSM, + kCodecDTSP, + kCodecEAC3, + kCodecOpus, + kCodecVorbis, + kCodecText, + kNumCodec +}; + /// Abstract class holds stream information. class StreamInfo : public base::RefCountedThreadSafe { public: - StreamInfo(StreamType stream_type, - int track_id, - uint32_t time_scale, - uint64_t duration, - const std::string& codec_string, - const std::string& language, - const uint8_t* codec_config, - size_t codec_config_size, - bool is_encrypted); + StreamInfo(StreamType stream_type, int track_id, uint32_t time_scale, + uint64_t duration, Codec codec, const std::string& codec_string, + const uint8_t* codec_config, size_t codec_config_size, + const std::string& language, bool is_encrypted); /// @return true if this object has appropriate configuration values, false /// otherwise. @@ -46,21 +68,18 @@ class StreamInfo : public base::RefCountedThreadSafe { uint32_t track_id() const { return track_id_; } uint32_t time_scale() const { return time_scale_; } uint64_t duration() const { return duration_; } + Codec codec() const { return codec_; } const std::string& codec_string() const { return codec_string_; } + const std::vector& codec_config() const { return codec_config_; } const std::string& language() const { return language_; } - bool is_encrypted() const { return is_encrypted_; } - const std::vector& codec_config() const { return codec_config_; } - void set_duration(int duration) { duration_ = duration; } - + void set_codec(Codec codec) { codec_ = codec; } void set_codec_config(const std::vector& data) { codec_config_ = data; } - void set_codec_string(const std::string& codec_string) { codec_string_ = codec_string; } - void set_language(const std::string& language) { language_ = language; } protected: @@ -75,6 +94,7 @@ class StreamInfo : public base::RefCountedThreadSafe { uint32_t time_scale_; // Duration base on time_scale. uint64_t duration_; + Codec codec_; std::string codec_string_; std::string language_; // Whether the stream is potentially encrypted. diff --git a/packager/media/base/text_stream_info.cc b/packager/media/base/text_stream_info.cc index faa38ef7f7..c7fbc94f59 100644 --- a/packager/media/base/text_stream_info.cc +++ b/packager/media/base/text_stream_info.cc @@ -9,23 +9,15 @@ namespace shaka { namespace media { -TextStreamInfo::TextStreamInfo(int track_id, - uint32_t time_scale, +TextStreamInfo::TextStreamInfo(int track_id, uint32_t time_scale, uint64_t duration, const std::string& codec_string, - const std::string& language, - const std::string& codec_config, - uint16_t width, - uint16_t height) - : StreamInfo(kStreamText, - track_id, - time_scale, - duration, + const std::string& codec_config, uint16_t width, + uint16_t height, const std::string& language) + : StreamInfo(kStreamText, track_id, time_scale, duration, kCodecText, codec_string, - language, reinterpret_cast(codec_config.data()), - codec_config.size(), - false), + codec_config.size(), language, false), width_(width), height_(height) {} diff --git a/packager/media/base/text_stream_info.h b/packager/media/base/text_stream_info.h index 461533779d..294dfd3089 100644 --- a/packager/media/base/text_stream_info.h +++ b/packager/media/base/text_stream_info.h @@ -21,20 +21,16 @@ class TextStreamInfo : public StreamInfo { /// @param time_scale is the time scale of this stream. /// @param duration is the duration of this stream. /// @param codec_string is the codec. - /// @param language is the language of this stream. This may be empty. /// @param codec_config is configuration for this text stream. This could be /// the metadata that applies to all the samples of this stream. This /// may be empty. /// @param width of the text. This may be 0. /// @param height of the text. This may be 0. - TextStreamInfo(int track_id, - uint32_t time_scale, - uint64_t duration, + /// @param language is the language of this stream. This may be empty. + TextStreamInfo(int track_id, uint32_t time_scale, uint64_t duration, const std::string& codec_string, - const std::string& language, - const std::string& codec_config, - uint16_t width, - uint16_t height); + const std::string& codec_config, uint16_t width, + uint16_t height, const std::string& language); bool IsValidConfig() const override; diff --git a/packager/media/base/video_stream_info.cc b/packager/media/base/video_stream_info.cc index d1fc13e3b4..1947713ee6 100644 --- a/packager/media/base/video_stream_info.cc +++ b/packager/media/base/video_stream_info.cc @@ -17,8 +17,8 @@ namespace shaka { namespace media { namespace { -std::string VideoCodecToString(VideoCodec video_codec) { - switch (video_codec) { +std::string VideoCodecToString(Codec codec) { + switch (codec) { case kCodecH264: return "H264"; case kCodecHEV1: @@ -40,52 +40,35 @@ std::string VideoCodecToString(VideoCodec video_codec) { case kCodecVP10: return "VP10"; default: - NOTIMPLEMENTED() << "Unknown Video Codec: " << video_codec; - return "UnknownVideoCodec"; + NOTIMPLEMENTED() << "Unknown Video Codec: " << codec; + return "UnknownCodec"; } } } // namespace -VideoStreamInfo::VideoStreamInfo(int track_id, - uint32_t time_scale, - uint64_t duration, - VideoCodec codec, - const std::string& codec_string, - const std::string& language, - uint16_t width, - uint16_t height, - uint32_t pixel_width, - uint32_t pixel_height, - int16_t trick_play_rate, - uint8_t nalu_length_size, - const uint8_t* codec_config, - size_t codec_config_size, - bool is_encrypted) - : StreamInfo(kStreamVideo, - track_id, - time_scale, - duration, - codec_string, - language, - codec_config, - codec_config_size, +VideoStreamInfo::VideoStreamInfo( + int track_id, uint32_t time_scale, uint64_t duration, Codec codec, + const std::string& codec_string, const uint8_t* codec_config, + size_t codec_config_size, uint16_t width, uint16_t height, + uint32_t pixel_width, uint32_t pixel_height, int16_t trick_play_rate, + uint8_t nalu_length_size, const std::string& language, bool is_encrypted) + : StreamInfo(kStreamVideo, track_id, time_scale, duration, codec, + codec_string, codec_config, codec_config_size, language, is_encrypted), - codec_(codec), width_(width), height_(height), pixel_width_(pixel_width), pixel_height_(pixel_height), trick_play_rate_(trick_play_rate), - nalu_length_size_(nalu_length_size) { -} + nalu_length_size_(nalu_length_size) {} VideoStreamInfo::~VideoStreamInfo() {} bool VideoStreamInfo::IsValidConfig() const { - return codec_ != kUnknownVideoCodec && - width_ > 0 && width_ <= limits::kMaxDimension && - height_ > 0 && height_ <= limits::kMaxDimension && + return codec() != kUnknownCodec && width_ > 0 && + width_ <= limits::kMaxDimension && height_ > 0 && + height_ <= limits::kMaxDimension && (nalu_length_size_ <= 2 || nalu_length_size_ == 4); } @@ -93,7 +76,7 @@ std::string VideoStreamInfo::ToString() const { return base::StringPrintf( "%s codec: %s\n width: %d\n height: %d\n pixel_aspect_ratio: %d:%d\n " "trick_play_rate: %d\n nalu_length_size: %d\n", - StreamInfo::ToString().c_str(), VideoCodecToString(codec_).c_str(), + StreamInfo::ToString().c_str(), VideoCodecToString(codec()).c_str(), width_, height_, pixel_width_, pixel_height_, trick_play_rate_, nalu_length_size_); } diff --git a/packager/media/base/video_stream_info.h b/packager/media/base/video_stream_info.h index 1c2978a0f9..163b982e12 100644 --- a/packager/media/base/video_stream_info.h +++ b/packager/media/base/video_stream_info.h @@ -12,41 +12,18 @@ namespace shaka { namespace media { -enum VideoCodec { - kUnknownVideoCodec = 0, - kCodecH264, - kCodecHEV1, - kCodecHVC1, - kCodecVC1, - kCodecMPEG2, - kCodecMPEG4, - kCodecTheora, - kCodecVP8, - kCodecVP9, - kCodecVP10, - kNumVideoCodec -}; - /// Holds video stream information. class VideoStreamInfo : public StreamInfo { public: /// Construct an initialized video stream info object. /// @param pixel_width is the width of the pixel. 0 if unknown. /// @param pixel_height is the height of the pixels. 0 if unknown. - VideoStreamInfo(int track_id, - uint32_t time_scale, - uint64_t duration, - VideoCodec codec, - const std::string& codec_string, - const std::string& language, - uint16_t width, - uint16_t height, - uint32_t pixel_width, - uint32_t pixel_height, - int16_t trick_play_rate, - uint8_t nalu_length_size, - const uint8_t* codec_config, - size_t codec_config_size, + VideoStreamInfo(int track_id, uint32_t time_scale, uint64_t duration, + Codec codec, const std::string& codec_string, + const uint8_t* codec_config, size_t codec_config_size, + uint16_t width, uint16_t height, uint32_t pixel_width, + uint32_t pixel_height, int16_t trick_play_rate, + uint8_t nalu_length_size, const std::string& language, bool is_encrypted); /// @name StreamInfo implementation overrides. @@ -55,7 +32,6 @@ class VideoStreamInfo : public StreamInfo { std::string ToString() const override; /// @} - VideoCodec codec() const { return codec_; } uint16_t width() const { return width_; } uint16_t height() const { return height_; } /// Returns the pixel width. @@ -67,7 +43,6 @@ class VideoStreamInfo : public StreamInfo { uint8_t nalu_length_size() const { return nalu_length_size_; } int16_t trick_play_rate() const { return trick_play_rate_; } - void set_codec(VideoCodec codec) { codec_ = codec; } void set_width(uint32_t width) { width_ = width; } void set_height(uint32_t height) { height_ = height; } void set_pixel_width(uint32_t pixel_width) { pixel_width_ = pixel_width; } @@ -76,7 +51,6 @@ class VideoStreamInfo : public StreamInfo { private: ~VideoStreamInfo() override; - VideoCodec codec_; uint16_t width_; uint16_t height_; diff --git a/packager/media/codecs/hevc_decoder_configuration_record.cc b/packager/media/codecs/hevc_decoder_configuration_record.cc index 5c101d3591..43ba8e0bc2 100644 --- a/packager/media/codecs/hevc_decoder_configuration_record.cc +++ b/packager/media/codecs/hevc_decoder_configuration_record.cc @@ -59,7 +59,7 @@ std::string ReverseBitsAndHexEncode(uint32_t x) { return TrimLeadingZeros(base::HexEncode(bytes, arraysize(bytes))); } -std::string CodecAsString(VideoCodec codec) { +std::string CodecAsString(Codec codec) { switch (codec) { case kCodecHEV1: return "hev1"; @@ -132,8 +132,7 @@ bool HEVCDecoderConfigurationRecord::ParseInternal() { return true; } -std::string HEVCDecoderConfigurationRecord::GetCodecString( - VideoCodec codec) const { +std::string HEVCDecoderConfigurationRecord::GetCodecString(Codec codec) const { // ISO/IEC 14496-15:2014 Annex E. std::vector fields; fields.push_back(CodecAsString(codec)); diff --git a/packager/media/codecs/hevc_decoder_configuration_record.h b/packager/media/codecs/hevc_decoder_configuration_record.h index dcaa1eaef1..6f3c3e64ce 100644 --- a/packager/media/codecs/hevc_decoder_configuration_record.h +++ b/packager/media/codecs/hevc_decoder_configuration_record.h @@ -25,7 +25,7 @@ class HEVCDecoderConfigurationRecord : public DecoderConfigurationRecord { ~HEVCDecoderConfigurationRecord() override; /// @return The codec string. - std::string GetCodecString(VideoCodec codec) const; + std::string GetCodecString(Codec codec) const; private: bool ParseInternal() override; diff --git a/packager/media/codecs/vp_codec_configuration_record.cc b/packager/media/codecs/vp_codec_configuration_record.cc index 71d616f825..6afd43e61f 100644 --- a/packager/media/codecs/vp_codec_configuration_record.cc +++ b/packager/media/codecs/vp_codec_configuration_record.cc @@ -24,7 +24,7 @@ enum VP9CodecFeatures { kFeatureChromaSubsampling = 4, }; -std::string VPCodecAsString(VideoCodec codec) { +std::string VPCodecAsString(Codec codec) { switch (codec) { case kCodecVP8: return "vp08"; @@ -205,7 +205,7 @@ void VPCodecConfigurationRecord::WriteWebM(std::vector* data) const { writer.SwapBuffer(data); } -std::string VPCodecConfigurationRecord::GetCodecString(VideoCodec codec) const { +std::string VPCodecConfigurationRecord::GetCodecString(Codec codec) const { const std::string fields[] = { base::IntToString(profile_), base::IntToString(level_), diff --git a/packager/media/codecs/vp_codec_configuration_record.h b/packager/media/codecs/vp_codec_configuration_record.h index b298bdd9d1..8b07b48d1b 100644 --- a/packager/media/codecs/vp_codec_configuration_record.h +++ b/packager/media/codecs/vp_codec_configuration_record.h @@ -68,7 +68,7 @@ class VPCodecConfigurationRecord { void WriteWebM(std::vector* data) const; /// @return The codec string. - std::string GetCodecString(VideoCodec codec) const; + std::string GetCodecString(Codec codec) const; // Merges the values from the given configuration. If there are values in // both |*this| and |other|, the values in |other| take precedence. diff --git a/packager/media/event/muxer_listener_test_helper.cc b/packager/media/event/muxer_listener_test_helper.cc index 59ab969152..11c7ef23f4 100644 --- a/packager/media/event/muxer_listener_test_helper.cc +++ b/packager/media/event/muxer_listener_test_helper.cc @@ -16,29 +16,19 @@ VideoStreamInfoParameters::~VideoStreamInfoParameters() {} scoped_refptr CreateVideoStreamInfo( const VideoStreamInfoParameters& param) { - return scoped_refptr( - new VideoStreamInfo(param.track_id, - param.time_scale, - param.duration, - param.codec, - param.codec_string, - param.language, - param.width, - param.height, - param.pixel_width, - param.pixel_height, - 0, // trick_play_rate - param.nalu_length_size, - param.codec_config.data(), - param.codec_config.size(), - param.is_encrypted)); + return scoped_refptr(new VideoStreamInfo( + param.track_id, param.time_scale, param.duration, param.codec, + param.codec_string, param.codec_config.data(), param.codec_config.size(), + param.width, param.height, param.pixel_width, param.pixel_height, + 0, // trick_play_rate + param.nalu_length_size, param.language, param.is_encrypted)); } VideoStreamInfoParameters GetDefaultVideoStreamInfoParams() { const int kTrackId = 0; const uint32_t kTimeScale = 10; const uint64_t kVideoStreamDuration = 200; - const VideoCodec kH264Codec = kCodecH264; + const Codec kH264Codec = kCodecH264; const char* kCodecString = "avc1.010101"; const char* kLanuageUndefined = "und"; const uint16_t kWidth = 720; diff --git a/packager/media/event/muxer_listener_test_helper.h b/packager/media/event/muxer_listener_test_helper.h index f17af435c7..f196f803db 100644 --- a/packager/media/event/muxer_listener_test_helper.h +++ b/packager/media/event/muxer_listener_test_helper.h @@ -60,7 +60,7 @@ struct VideoStreamInfoParameters { int track_id; uint32_t time_scale; uint64_t duration; - VideoCodec codec; + Codec codec; std::string codec_string; std::string language; uint16_t width; diff --git a/packager/media/formats/mp2t/es_parser_adts.cc b/packager/media/formats/mp2t/es_parser_adts.cc index 0234d9f650..015bdfbf24 100644 --- a/packager/media/formats/mp2t/es_parser_adts.cc +++ b/packager/media/formats/mp2t/es_parser_adts.cc @@ -221,25 +221,13 @@ bool EsParserAdts::UpdateAudioConfiguration(const uint8_t* adts_frame, ? std::min(2 * samples_per_second, 48000) : samples_per_second; - last_audio_decoder_config_ = scoped_refptr( - new AudioStreamInfo( - pid(), - kMpeg2Timescale, - kInfiniteDuration, - kCodecAAC, - AudioStreamInfo::GetCodecString(kCodecAAC, - adts_header.GetObjectType()), - std::string(), - kAacSampleSizeBits, - adts_header.GetNumChannels(), - extended_samples_per_second, - 0 /* seek preroll */, - 0 /* codec delay */, - 0 /* max bitrate */, - 0 /* avg bitrate */, - audio_specific_config.data(), - audio_specific_config.size(), - false)); + last_audio_decoder_config_ = scoped_refptr(new AudioStreamInfo( + pid(), kMpeg2Timescale, kInfiniteDuration, kCodecAAC, + AudioStreamInfo::GetCodecString(kCodecAAC, adts_header.GetObjectType()), + audio_specific_config.data(), audio_specific_config.size(), + kAacSampleSizeBits, adts_header.GetNumChannels(), + extended_samples_per_second, 0 /* seek preroll */, 0 /* codec delay */, + 0 /* max bitrate */, 0 /* avg bitrate */, std::string(), false)); DVLOG(1) << "Sampling frequency: " << samples_per_second; DVLOG(1) << "Extended sampling frequency: " << extended_samples_per_second; diff --git a/packager/media/formats/mp2t/es_parser_h264.cc b/packager/media/formats/mp2t/es_parser_h264.cc index 2a5d946563..e5d4eeeb82 100644 --- a/packager/media/formats/mp2t/es_parser_h264.cc +++ b/packager/media/formats/mp2t/es_parser_h264.cc @@ -148,9 +148,10 @@ bool EsParserH264::UpdateVideoDecoderConfig(int pps_id) { AVCDecoderConfigurationRecord::GetCodecString(decoder_config_record[1], decoder_config_record[2], decoder_config_record[3]), - std::string(), coded_width, coded_height, pixel_width, pixel_height, 0, - H264ByteToUnitStreamConverter::kUnitStreamNaluLengthSize, - decoder_config_record.data(), decoder_config_record.size(), false)); + decoder_config_record.data(), decoder_config_record.size(), coded_width, + coded_height, pixel_width, pixel_height, 0, + H264ByteToUnitStreamConverter::kUnitStreamNaluLengthSize, std::string(), + false)); DVLOG(1) << "Profile IDC: " << sps->profile_idc; DVLOG(1) << "Level IDC: " << sps->level_idc; DVLOG(1) << "log2_max_frame_num_minus4: " << sps->log2_max_frame_num_minus4; diff --git a/packager/media/formats/mp2t/es_parser_h265.cc b/packager/media/formats/mp2t/es_parser_h265.cc index 3b67c7f575..ead8d96c9c 100644 --- a/packager/media/formats/mp2t/es_parser_h265.cc +++ b/packager/media/formats/mp2t/es_parser_h265.cc @@ -148,23 +148,12 @@ bool EsParserH265::UpdateVideoDecoderConfig(int pps_id) { return false; } - last_video_decoder_config_ = scoped_refptr( - new VideoStreamInfo( - pid(), - kMpeg2Timescale, - kInfiniteDuration, - kCodecHVC1, - decoder_config.GetCodecString(kCodecHVC1), - std::string(), - coded_width, - coded_height, - pixel_width, - pixel_height, - 0, - H26xByteToUnitStreamConverter::kUnitStreamNaluLengthSize, - decoder_config_record.data(), - decoder_config_record.size(), - false)); + last_video_decoder_config_ = scoped_refptr(new VideoStreamInfo( + pid(), kMpeg2Timescale, kInfiniteDuration, kCodecHVC1, + decoder_config.GetCodecString(kCodecHVC1), decoder_config_record.data(), + decoder_config_record.size(), coded_width, coded_height, pixel_width, + pixel_height, 0, H26xByteToUnitStreamConverter::kUnitStreamNaluLengthSize, + std::string(), false)); // Video config notification. new_stream_info_cb_.Run(last_video_decoder_config_); diff --git a/packager/media/formats/mp2t/pes_packet_generator.cc b/packager/media/formats/mp2t/pes_packet_generator.cc index 9cb9361bd3..1a952dc36d 100644 --- a/packager/media/formats/mp2t/pes_packet_generator.cc +++ b/packager/media/formats/mp2t/pes_packet_generator.cc @@ -97,7 +97,7 @@ bool PesPacketGenerator::Initialize(const StreamInfo& stream_info) { if (stream_type_ == kStreamVideo) { const VideoStreamInfo& video_stream_info = static_cast(stream_info); - if (video_stream_info.codec() != VideoCodec::kCodecH264) { + if (video_stream_info.codec() != Codec::kCodecH264) { NOTIMPLEMENTED() << "Video codec " << video_stream_info.codec() << " is not supported."; return false; @@ -110,7 +110,7 @@ bool PesPacketGenerator::Initialize(const StreamInfo& stream_info) { } else if (stream_type_ == kStreamAudio) { const AudioStreamInfo& audio_stream_info = static_cast(stream_info); - if (audio_stream_info.codec() != AudioCodec::kCodecAAC) { + if (audio_stream_info.codec() != Codec::kCodecAAC) { NOTIMPLEMENTED() << "Audio codec " << audio_stream_info.codec() << " is not supported yet."; return false; diff --git a/packager/media/formats/mp2t/pes_packet_generator_unittest.cc b/packager/media/formats/mp2t/pes_packet_generator_unittest.cc index 4ff15c0e81..f4e2fe3846 100644 --- a/packager/media/formats/mp2t/pes_packet_generator_unittest.cc +++ b/packager/media/formats/mp2t/pes_packet_generator_unittest.cc @@ -34,10 +34,10 @@ const uint8_t kAnyData[] = { const bool kIsKeyFrame = true; -// Only {Audio,Video}Codec and extra data matter for this test. Other values are +// Only Codec and extra data matter for this test. Other values are // bogus. -const VideoCodec kH264VideoCodec = VideoCodec::kCodecH264; -const AudioCodec kAacAudioCodec = AudioCodec::kCodecAAC; +const Codec kH264Codec = Codec::kCodecH264; +const Codec kAacCodec = Codec::kCodecAAC; // TODO(rkuroiwa): It might make sense to inject factory functions to create // NalUnitToByteStreamConverter and AACAudioSpecificConfig so that these @@ -102,20 +102,19 @@ class MockAACAudioSpecificConfig : public AACAudioSpecificConfig { MOCK_CONST_METHOD1(ConvertToADTS, bool(std::vector* buffer)); }; -scoped_refptr CreateVideoStreamInfo(VideoCodec codec) { +scoped_refptr CreateVideoStreamInfo(Codec codec) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, codec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kVideoExtraData, arraysize(kVideoExtraData), - kIsEncrypted)); + kTrackId, kTimeScale, kDuration, codec, kCodecString, kVideoExtraData, + arraysize(kVideoExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); return stream_info; } -scoped_refptr CreateAudioStreamInfo(AudioCodec codec) { +scoped_refptr CreateAudioStreamInfo(Codec codec) { scoped_refptr stream_info(new AudioStreamInfo( - kTrackId, kTimeScale, kDuration, codec, kCodecString, kLanguage, - kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, - kMaxBitrate, kAverageBitrate, kAudioExtraData, arraysize(kAudioExtraData), + kTrackId, kTimeScale, kDuration, codec, kCodecString, kAudioExtraData, + arraysize(kAudioExtraData), kSampleBits, kNumChannels, kSamplingFrequency, + kSeekPreroll, kCodecDelay, kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted)); return stream_info; } @@ -140,7 +139,7 @@ class PesPacketGeneratorTest : public ::testing::Test { const uint8_t* expected_output, size_t expected_output_size) { scoped_refptr stream_info( - CreateVideoStreamInfo(kH264VideoCodec)); + CreateVideoStreamInfo(kH264Codec)); EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); @@ -189,7 +188,7 @@ class PesPacketGeneratorTest : public ::testing::Test { const uint8_t* expected_output, size_t expected_output_size) { scoped_refptr stream_info( - CreateAudioStreamInfo(kAacAudioCodec)); + CreateAudioStreamInfo(kAacCodec)); EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); @@ -224,26 +223,24 @@ class PesPacketGeneratorTest : public ::testing::Test { }; TEST_F(PesPacketGeneratorTest, InitializeVideo) { - scoped_refptr stream_info( - CreateVideoStreamInfo(kH264VideoCodec)); + scoped_refptr stream_info(CreateVideoStreamInfo(kH264Codec)); EXPECT_TRUE(generator_.Initialize(*stream_info)); } TEST_F(PesPacketGeneratorTest, InitializeVideoNonH264) { scoped_refptr stream_info( - CreateVideoStreamInfo(VideoCodec::kCodecVP9)); + CreateVideoStreamInfo(Codec::kCodecVP9)); EXPECT_FALSE(generator_.Initialize(*stream_info)); } TEST_F(PesPacketGeneratorTest, InitializeAudio) { - scoped_refptr stream_info( - CreateAudioStreamInfo(kAacAudioCodec)); + scoped_refptr stream_info(CreateAudioStreamInfo(kAacCodec)); EXPECT_TRUE(generator_.Initialize(*stream_info)); } TEST_F(PesPacketGeneratorTest, InitializeAudioNonAac) { scoped_refptr stream_info( - CreateAudioStreamInfo(AudioCodec::kCodecOpus)); + CreateAudioStreamInfo(Codec::kCodecOpus)); EXPECT_FALSE(generator_.Initialize(*stream_info)); } @@ -251,13 +248,12 @@ TEST_F(PesPacketGeneratorTest, InitializeAudioNonAac) { TEST_F(PesPacketGeneratorTest, InitializeTextInfo) { scoped_refptr stream_info( new TextStreamInfo(kTrackId, kTimeScale, kDuration, kCodecString, - kLanguage, std::string(), kWidth, kHeight)); + std::string(), kWidth, kHeight, kLanguage)); EXPECT_FALSE(generator_.Initialize(*stream_info)); } TEST_F(PesPacketGeneratorTest, AddVideoSample) { - scoped_refptr stream_info( - CreateVideoStreamInfo(kH264VideoCodec)); + scoped_refptr stream_info(CreateVideoStreamInfo(kH264Codec)); EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); @@ -293,8 +289,7 @@ TEST_F(PesPacketGeneratorTest, AddVideoSample) { } TEST_F(PesPacketGeneratorTest, AddVideoSampleFailedToConvert) { - scoped_refptr stream_info( - CreateVideoStreamInfo(kH264VideoCodec)); + scoped_refptr stream_info(CreateVideoStreamInfo(kH264Codec)); EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); @@ -316,8 +311,7 @@ TEST_F(PesPacketGeneratorTest, AddVideoSampleFailedToConvert) { } TEST_F(PesPacketGeneratorTest, AddAudioSample) { - scoped_refptr stream_info( - CreateAudioStreamInfo(kAacAudioCodec)); + scoped_refptr stream_info(CreateAudioStreamInfo(kAacCodec)); EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); @@ -345,8 +339,7 @@ TEST_F(PesPacketGeneratorTest, AddAudioSample) { } TEST_F(PesPacketGeneratorTest, AddAudioSampleFailedToConvert) { - scoped_refptr stream_info( - CreateAudioStreamInfo(kAacAudioCodec)); + scoped_refptr stream_info(CreateAudioStreamInfo(kAacCodec)); EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); @@ -368,10 +361,9 @@ TEST_F(PesPacketGeneratorTest, AddAudioSampleFailedToConvert) { TEST_F(PesPacketGeneratorTest, TimeStampScaling) { const uint32_t kTestTimescale = 1000; scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTestTimescale, kDuration, kH264VideoCodec, kCodecString, - kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kVideoExtraData, arraysize(kVideoExtraData), - kIsEncrypted)); + kTrackId, kTestTimescale, kDuration, kH264Codec, kCodecString, + kVideoExtraData, arraysize(kVideoExtraData), kWidth, kHeight, kPixelWidth, + kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); EXPECT_TRUE(generator_.Initialize(*stream_info)); EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets()); diff --git a/packager/media/formats/mp2t/ts_segmenter_unittest.cc b/packager/media/formats/mp2t/ts_segmenter_unittest.cc index 9595190d28..11bbb5a346 100644 --- a/packager/media/formats/mp2t/ts_segmenter_unittest.cc +++ b/packager/media/formats/mp2t/ts_segmenter_unittest.cc @@ -29,7 +29,7 @@ namespace { // All data here is bogus. They are used to create VideoStreamInfo but the // actual values don't matter at all. const bool kIsKeyFrame = true; -const VideoCodec kH264VideoCodec = VideoCodec::kCodecH264; +const Codec kH264Codec = Codec::kCodecH264; const uint8_t kExtraData[] = { 0x00, }; @@ -107,9 +107,9 @@ class TsSegmenterTest : public ::testing::Test { TEST_F(TsSegmenterTest, Initialize) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); MuxerOptions options; options.segment_template = "file$Number$.ts"; TsSegmenter segmenter(options, nullptr); @@ -127,9 +127,9 @@ TEST_F(TsSegmenterTest, Initialize) { TEST_F(TsSegmenterTest, AddSample) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); MuxerOptions options; options.segment_duration = 10.0; options.segment_template = "file$Number$.ts"; @@ -182,9 +182,9 @@ TEST_F(TsSegmenterTest, PassedSegmentDuration) { // done correctly in the segmenter. const uint32_t kInputTimescale = 1001; scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kInputTimescale, kDuration, kH264VideoCodec, kCodecString, - kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kInputTimescale, kDuration, kH264Codec, kCodecString, + kExtraData, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, + kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); MuxerOptions options; options.segment_duration = 10.0; options.segment_template = "file$Number$.ts"; @@ -281,9 +281,9 @@ TEST_F(TsSegmenterTest, PassedSegmentDuration) { // Finalize right after Initialize(). The writer will not be initialized. TEST_F(TsSegmenterTest, InitializeThenFinalize) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); MuxerOptions options; options.segment_duration = 10.0; options.segment_template = "file$Number$.ts"; @@ -310,9 +310,9 @@ TEST_F(TsSegmenterTest, InitializeThenFinalize) { // writer with a mock. TEST_F(TsSegmenterTest, Finalize) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); MuxerOptions options; options.segment_duration = 10.0; options.segment_template = "file$Number$.ts"; @@ -339,9 +339,9 @@ TEST_F(TsSegmenterTest, Finalize) { // Verify that it won't finish a segment if the sample is not a key frame. TEST_F(TsSegmenterTest, SegmentOnlyBeforeKeyFrame) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); MuxerOptions options; options.segment_duration = 10.0; options.segment_template = "file$Number$.ts"; @@ -445,9 +445,9 @@ TEST_F(TsSegmenterTest, SegmentOnlyBeforeKeyFrame) { TEST_F(TsSegmenterTest, WithEncryptionNoClearLead) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); MuxerOptions options; options.segment_duration = 10.0; options.segment_template = "file$Number$.ts"; @@ -485,9 +485,9 @@ TEST_F(TsSegmenterTest, WithEncryptionNoClearLead) { // not null. TEST_F(TsSegmenterTest, WithEncryptionNoClearLeadNoMuxerListener) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); MuxerOptions options; options.segment_duration = 10.0; options.segment_template = "file$Number$.ts"; @@ -522,9 +522,9 @@ TEST_F(TsSegmenterTest, WithEncryptionNoClearLeadNoMuxerListener) { // Verify that encryption notification is sent to objects after clear lead. TEST_F(TsSegmenterTest, WithEncryptionWithClearLead) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, - kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); MuxerOptions options; options.segment_duration = 1.0; diff --git a/packager/media/formats/mp2t/ts_writer.cc b/packager/media/formats/mp2t/ts_writer.cc index 250c7014a1..9e5fb76d31 100644 --- a/packager/media/formats/mp2t/ts_writer.cc +++ b/packager/media/formats/mp2t/ts_writer.cc @@ -174,7 +174,7 @@ bool TsWriter::Initialize(const StreamInfo& stream_info) { if (stream_info.stream_type() == StreamType::kStreamVideo) { const VideoStreamInfo& video_stream_info = static_cast(stream_info); - if (video_stream_info.codec() != VideoCodec::kCodecH264) { + if (video_stream_info.codec() != Codec::kCodecH264) { LOG(ERROR) << "TsWriter cannot handle video codec " << video_stream_info.codec() << " yet."; return false; @@ -184,7 +184,7 @@ bool TsWriter::Initialize(const StreamInfo& stream_info) { DCHECK_EQ(stream_type, StreamType::kStreamAudio); const AudioStreamInfo& audio_stream_info = static_cast(stream_info); - if (audio_stream_info.codec() != AudioCodec::kCodecAAC) { + if (audio_stream_info.codec() != Codec::kCodecAAC) { LOG(ERROR) << "TsWriter cannot handle audio codec " << audio_stream_info.codec() << " yet."; return false; diff --git a/packager/media/formats/mp2t/ts_writer_unittest.cc b/packager/media/formats/mp2t/ts_writer_unittest.cc index 231993fb3a..78c189a81b 100644 --- a/packager/media/formats/mp2t/ts_writer_unittest.cc +++ b/packager/media/formats/mp2t/ts_writer_unittest.cc @@ -28,8 +28,8 @@ namespace { const int kTsPacketSize = 188; // Only {Audio,Video}Codec matter for this test. Other values are bogus. -const VideoCodec kH264VideoCodec = VideoCodec::kCodecH264; -const AudioCodec kAacAudioCodec = AudioCodec::kCodecAAC; +const Codec kH264Codec = Codec::kCodecH264; +const Codec kAacCodec = Codec::kCodecAAC; const int kTrackId = 0; const uint32_t kTimeScale = 90000; const uint64_t kDuration = 180000; @@ -158,35 +158,35 @@ class TsWriterTest : public ::testing::Test { TEST_F(TsWriterTest, InitializeVideoH264) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); } TEST_F(TsWriterTest, InitializeVideoNonH264) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, VideoCodec::kCodecVP9, kCodecString, - kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, Codec::kCodecVP9, kCodecString, + kExtraData, arraysize(kExtraData), kWidth, kHeight, kPixelWidth, + kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); EXPECT_FALSE(ts_writer_.Initialize(*stream_info)); } TEST_F(TsWriterTest, InitializeAudioAac) { scoped_refptr stream_info(new AudioStreamInfo( - kTrackId, kTimeScale, kDuration, kAacAudioCodec, kCodecString, kLanguage, - kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, - kMaxBitrate, kAverageBitrate, kExtraData, arraysize(kExtraData), + kTrackId, kTimeScale, kDuration, kAacCodec, kCodecString, kExtraData, + arraysize(kExtraData), kSampleBits, kNumChannels, kSamplingFrequency, + kSeekPreroll, kCodecDelay, kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); } TEST_F(TsWriterTest, InitializeAudioNonAac) { scoped_refptr stream_info(new AudioStreamInfo( - kTrackId, kTimeScale, kDuration, AudioCodec::kCodecOpus, kCodecString, - kLanguage, kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, - kCodecDelay, kMaxBitrate, kAverageBitrate, kExtraData, - arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, Codec::kCodecOpus, kCodecString, + kExtraData, arraysize(kExtraData), kSampleBits, kNumChannels, + kSamplingFrequency, kSeekPreroll, kCodecDelay, kMaxBitrate, + kAverageBitrate, kLanguage, kIsEncrypted)); EXPECT_FALSE(ts_writer_.Initialize(*stream_info)); } @@ -199,9 +199,9 @@ TEST_F(TsWriterTest, ClearH264Psi) { EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(WriteOnePmt()); scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); @@ -253,10 +253,10 @@ TEST_F(TsWriterTest, ClearAacPmt) { EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(WriteOnePmt()); scoped_refptr stream_info(new AudioStreamInfo( - kTrackId, kTimeScale, kDuration, kAacAudioCodec, kCodecString, kLanguage, + kTrackId, kTimeScale, kDuration, kAacCodec, kCodecString, + kAacBasicProfileExtraData, arraysize(kAacBasicProfileExtraData), kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, - kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData, - arraysize(kAacBasicProfileExtraData), kIsEncrypted)); + kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); @@ -281,9 +281,9 @@ TEST_F(TsWriterTest, ClearLeadH264Pmt) { .WillOnce(WriteTwoPmts()); scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); @@ -310,9 +310,9 @@ TEST_F(TsWriterTest, EncryptedSegmentsH264Pmt) { EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(WriteOnePmt()); scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); @@ -341,10 +341,10 @@ TEST_F(TsWriterTest, ClearLeadAacPmt) { .WillOnce(WriteTwoPmts()); scoped_refptr stream_info(new AudioStreamInfo( - kTrackId, kTimeScale, kDuration, kAacAudioCodec, kCodecString, kLanguage, + kTrackId, kTimeScale, kDuration, kAacCodec, kCodecString, + kAacBasicProfileExtraData, arraysize(kAacBasicProfileExtraData), kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, - kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData, - arraysize(kAacBasicProfileExtraData), kIsEncrypted)); + kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); @@ -371,10 +371,10 @@ TEST_F(TsWriterTest, EncryptedSegmentsAacPmt) { EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(WriteOnePmt()); scoped_refptr stream_info(new AudioStreamInfo( - kTrackId, kTimeScale, kDuration, kAacAudioCodec, kCodecString, kLanguage, + kTrackId, kTimeScale, kDuration, kAacCodec, kCodecString, + kAacBasicProfileExtraData, arraysize(kAacBasicProfileExtraData), kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, - kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData, - arraysize(kAacBasicProfileExtraData), kIsEncrypted)); + kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); @@ -398,9 +398,9 @@ TEST_F(TsWriterTest, EncryptedSegmentsAacPmt) { TEST_F(TsWriterTest, AddPesPacket) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); @@ -463,9 +463,9 @@ TEST_F(TsWriterTest, AddPesPacket) { // Verify that PES packet > 64KiB can be handled. TEST_F(TsWriterTest, BigPesPacket) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); @@ -499,9 +499,9 @@ TEST_F(TsWriterTest, BigPesPacket) { // PTS (implicilty) cast to bool is true. TEST_F(TsWriterTest, PesPtsZeroNoDts) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); @@ -559,9 +559,9 @@ TEST_F(TsWriterTest, PesPtsZeroNoDts) { // adaptation_field_length should be 0. TEST_F(TsWriterTest, TsPacketPayload183Bytes) { scoped_refptr stream_info(new VideoStreamInfo( - kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, - kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); + kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData, + arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight, + kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted)); EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); diff --git a/packager/media/formats/mp4/encrypting_fragmenter.cc b/packager/media/formats/mp4/encrypting_fragmenter.cc index 6767f19c8b..f0d58ae74d 100644 --- a/packager/media/formats/mp4/encrypting_fragmenter.cc +++ b/packager/media/formats/mp4/encrypting_fragmenter.cc @@ -41,9 +41,8 @@ void AddSubsamples(uint64_t clear_bytes, subsamples->push_back(SubsampleEntry(clear_bytes, cipher_bytes)); } -VideoCodec GetVideoCodec(const StreamInfo& stream_info) { - if (stream_info.stream_type() != kStreamVideo) - return kUnknownVideoCodec; +Codec GetCodec(const StreamInfo& stream_info) { + if (stream_info.stream_type() != kStreamVideo) return kUnknownCodec; const VideoStreamInfo& video_stream_info = static_cast(stream_info); return video_stream_info.codec(); @@ -60,19 +59,15 @@ uint8_t GetNaluLengthSize(const StreamInfo& stream_info) { } // namespace EncryptingFragmenter::EncryptingFragmenter( - scoped_refptr info, - TrackFragment* traf, - scoped_ptr encryption_key, - int64_t clear_time, - FourCC protection_scheme, - uint8_t crypt_byte_block, - uint8_t skip_byte_block, + scoped_refptr info, TrackFragment* traf, + scoped_ptr encryption_key, int64_t clear_time, + FourCC protection_scheme, uint8_t crypt_byte_block, uint8_t skip_byte_block, MuxerListener* listener) : Fragmenter(info, traf), info_(info), encryption_key_(encryption_key.Pass()), nalu_length_size_(GetNaluLengthSize(*info)), - video_codec_(GetVideoCodec(*info)), + video_codec_(GetCodec(*info)), clear_time_(clear_time), protection_scheme_(protection_scheme), crypt_byte_block_(crypt_byte_block), diff --git a/packager/media/formats/mp4/encrypting_fragmenter.h b/packager/media/formats/mp4/encrypting_fragmenter.h index bd666779f3..0c93a75786 100644 --- a/packager/media/formats/mp4/encrypting_fragmenter.h +++ b/packager/media/formats/mp4/encrypting_fragmenter.h @@ -92,7 +92,7 @@ class EncryptingFragmenter : public Fragmenter { // and type of NAL units remain unencrypted. This function returns the size of // the size field in bytes. Can be 1, 2 or 4 bytes. const uint8_t nalu_length_size_; - const VideoCodec video_codec_; + const Codec video_codec_; int64_t clear_time_; const FourCC protection_scheme_; const uint8_t crypt_byte_block_; diff --git a/packager/media/formats/mp4/mp4_media_parser.cc b/packager/media/formats/mp4/mp4_media_parser.cc index a6c58b3500..b86979e876 100644 --- a/packager/media/formats/mp4/mp4_media_parser.cc +++ b/packager/media/formats/mp4/mp4_media_parser.cc @@ -40,7 +40,7 @@ uint64_t Rescale(uint64_t time_in_old_scale, return (static_cast(time_in_old_scale) / old_scale) * new_scale; } -VideoCodec FourCCToVideoCodec(FourCC fourcc) { +Codec FourCCToCodec(FourCC fourcc) { switch (fourcc) { case FOURCC_avc1: return kCodecH264; @@ -54,13 +54,6 @@ VideoCodec FourCCToVideoCodec(FourCC fourcc) { return kCodecVP9; case FOURCC_vp10: return kCodecVP10; - default: - return kUnknownVideoCodec; - } -} - -AudioCodec FourCCToAudioCodec(FourCC fourcc) { - switch(fourcc) { case FOURCC_Opus: return kCodecOpus; case FOURCC_dtsc: @@ -80,7 +73,7 @@ AudioCodec FourCCToAudioCodec(FourCC fourcc) { case FOURCC_ec_3: return kCodecEAC3; default: - return kUnknownAudioCodec; + return kUnknownCodec; } } @@ -343,7 +336,7 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) { const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx]; const FourCC actual_format = entry.GetActualFormat(); - AudioCodec codec = FourCCToAudioCodec(actual_format); + Codec codec = FourCCToCodec(actual_format); uint8_t num_channels = 0; uint32_t sampling_frequency = 0; uint64_t codec_delay_ns = 0; @@ -473,21 +466,11 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) { entry.sinf.info.track_encryption.default_is_protected == 1; DVLOG(1) << "is_audio_track_encrypted_: " << is_encrypted; streams.push_back(new AudioStreamInfo( - track->header.track_id, - timescale, - duration, - codec, + track->header.track_id, timescale, duration, codec, AudioStreamInfo::GetCodecString(codec, audio_object_type), - track->media.header.language.code, - entry.samplesize, - num_channels, - sampling_frequency, - seek_preroll_ns, - codec_delay_ns, - max_bitrate, - avg_bitrate, - codec_config.data(), - codec_config.size(), + codec_config.data(), codec_config.size(), entry.samplesize, + num_channels, sampling_frequency, seek_preroll_ns, codec_delay_ns, + max_bitrate, avg_bitrate, track->media.header.language.code, is_encrypted)); } @@ -509,7 +492,7 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) { uint8_t nalu_length_size = 0; const FourCC actual_format = entry.GetActualFormat(); - const VideoCodec video_codec = FourCCToVideoCodec(actual_format); + const Codec video_codec = FourCCToCodec(actual_format); switch (actual_format) { case FOURCC_avc1: { AVCDecoderConfigurationRecord avc_config; @@ -580,11 +563,11 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) { DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted; streams.push_back(new VideoStreamInfo( track->header.track_id, timescale, duration, video_codec, - codec_string, track->media.header.language.code, coded_width, - coded_height, pixel_width, pixel_height, + codec_string, entry.codec_configuration.data.data(), + entry.codec_configuration.data.size(), coded_width, coded_height, + pixel_width, pixel_height, 0, // trick_play_rate - nalu_length_size, entry.codec_configuration.data.data(), - entry.codec_configuration.data.size(), is_encrypted)); + nalu_length_size, track->media.header.language.code, is_encrypted)); } } diff --git a/packager/media/formats/mp4/mp4_muxer.cc b/packager/media/formats/mp4/mp4_muxer.cc index 3de6640c23..277c10ae44 100644 --- a/packager/media/formats/mp4/mp4_muxer.cc +++ b/packager/media/formats/mp4/mp4_muxer.cc @@ -40,7 +40,7 @@ void SetStartAndEndFromOffsetAndSize(size_t offset, *end = *start + static_cast(size) - 1; } -FourCC VideoCodecToFourCC(VideoCodec codec) { +FourCC CodecToFourCC(Codec codec) { switch (codec) { case kCodecH264: return FOURCC_avc1; @@ -54,13 +54,6 @@ FourCC VideoCodecToFourCC(VideoCodec codec) { return FOURCC_vp09; case kCodecVP10: return FOURCC_vp10; - default: - return FOURCC_NULL; - } -} - -FourCC AudioCodecToFourCC(AudioCodec codec) { - switch (codec) { case kCodecAAC: return FOURCC_mp4a; case kCodecAC3: @@ -100,7 +93,7 @@ Status MP4Muxer::Initialize() { ftyp->compatible_brands.push_back(FOURCC_mp41); if (streams().size() == 1 && streams()[0]->info()->stream_type() == kStreamVideo) { - const FourCC codec_fourcc = VideoCodecToFourCC( + const FourCC codec_fourcc = CodecToFourCC( static_cast(streams()[0]->info().get())->codec()); if (codec_fourcc != FOURCC_NULL) ftyp->compatible_brands.push_back(codec_fourcc); @@ -226,7 +219,7 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info, trak->header.height = video_info->height() * 0x10000; VideoSampleEntry video; - video.format = VideoCodecToFourCC(video_info->codec()); + video.format = CodecToFourCC(video_info->codec()); video.width = video_info->width(); video.height = video_info->height(); video.codec_configuration.data = video_info->codec_config(); @@ -249,7 +242,7 @@ void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info, trak->header.volume = 0x100; AudioSampleEntry audio; - audio.format = AudioCodecToFourCC(audio_info->codec()); + audio.format = CodecToFourCC(audio_info->codec()); switch(audio_info->codec()){ case kCodecAAC: audio.esds.es_descriptor.set_object_type(kISO_14496_3); // MPEG4 AAC. diff --git a/packager/media/formats/webm/encryptor.cc b/packager/media/formats/webm/encryptor.cc index a23cf563cf..9808cbc19c 100644 --- a/packager/media/formats/webm/encryptor.cc +++ b/packager/media/formats/webm/encryptor.cc @@ -6,15 +6,21 @@ #include "packager/media/formats/webm/encryptor.h" +#include #include "packager/media/base/aes_encryptor.h" +#include "packager/media/base/buffer_writer.h" #include "packager/media/base/fourccs.h" #include "packager/media/base/media_sample.h" +#include "packager/media/codecs/vp9_parser.h" +#include "packager/media/formats/webm/webm_constants.h" namespace shaka { namespace media { namespace webm { namespace { +const size_t kAesBlockSize = 16; + Status CreateContentEncryption(mkvmuxer::Track* track, EncryptionKey* key) { if (!track->AddContentEncoding()) { return Status(error::INTERNAL_ERROR, @@ -54,9 +60,12 @@ Encryptor::~Encryptor() {} Status Encryptor::Initialize(MuxerListener* muxer_listener, KeySource::TrackType track_type, - KeySource* key_source) { + Codec codec, + KeySource* key_source, + bool webm_subsample_encryption) { DCHECK(key_source); - return CreateEncryptor(muxer_listener, track_type, key_source); + return CreateEncryptor(muxer_listener, track_type, codec, key_source, + webm_subsample_encryption); } Status Encryptor::AddTrackInfo(mkvmuxer::Track* track) { @@ -69,26 +78,88 @@ Status Encryptor::EncryptFrame(scoped_refptr sample, DCHECK(encryptor_); const size_t sample_size = sample->data_size(); - if (encrypt_frame) { - // | 1 | iv | enc_data | - const size_t iv_size = encryptor_->iv().size(); - sample->resize_data(sample_size + iv_size + 1); - uint8_t* sample_data = sample->writable_data(); - - // Encrypt the data in-place. - if (!encryptor_->Crypt(sample_data, sample_size, sample_data)) { - return Status(error::MUXER_FAILURE, "Failed to encrypt the frame."); + // We need to parse the frame (which also updates the vpx parser) even if the + // frame is not encrypted as the next (encrypted) frame may be dependent on + // this clear frame. + std::vector vpx_frames; + if (vpx_parser_) { + if (!vpx_parser_->Parse(sample->data(), sample_size, &vpx_frames)) { + return Status(error::MUXER_FAILURE, "Failed to parse VPx frame."); } + } - // First move the sample data to after the IV; then write the IV and signal - // byte. - memmove(sample_data + iv_size + 1, sample_data, sample_size); - sample_data[0] = 0x01; - memcpy(sample_data + 1, encryptor_->iv().data(), iv_size); + if (encrypt_frame) { + const size_t iv_size = encryptor_->iv().size(); + if (iv_size != kWebMIvSize) { + return Status(error::MUXER_FAILURE, + "Incorrect size WebM encryption IV."); + } + if (vpx_frames.size()) { + // Use partitioned subsample encryption: | signal_byte(3) | iv + // | num_partitions | partition_offset * n | enc_data | + if (vpx_frames.size() > kWebMMaxSubsamples) { + return Status(error::MUXER_FAILURE, + "Maximum number of VPx encryption partitions exceeded."); + } + uint8_t num_partitions = + vpx_frames.size() == 1 ? 1 : vpx_frames.size() * 2; + size_t header_size = kWebMSignalByteSize + iv_size + + kWebMNumPartitionsSize + + (kWebMPartitionOffsetSize * num_partitions); + sample->resize_data(header_size + sample_size); + uint8_t* sample_data = sample->writable_data(); + memmove(sample_data + header_size, sample_data, sample_size); + sample_data[0] = kWebMEncryptedSignal | kWebMPartitionedSignal; + memcpy(sample_data + kWebMSignalByteSize, encryptor_->iv().data(), + iv_size); + sample_data[kWebMSignalByteSize + kWebMIvSize] = num_partitions; + uint32 partition_offset = 0; + BufferWriter offsets_buffer(kWebMPartitionOffsetSize * num_partitions); + for (const auto& vpx_frame : vpx_frames) { + uint32_t encrypted_size = + vpx_frame.frame_size - vpx_frame.uncompressed_header_size; + encrypted_size -= encrypted_size % kAesBlockSize; + uint32_t clear_size = vpx_frame.frame_size - encrypted_size; + partition_offset += clear_size; + offsets_buffer.AppendInt(partition_offset); + if (encrypted_size > 0) { + uint8_t* encrypted_ptr = sample_data + header_size + partition_offset; + if (!encryptor_->Crypt(encrypted_ptr, encrypted_size, encrypted_ptr)) { + return Status(error::MUXER_FAILURE, "Failed to encrypt the frame."); + } + partition_offset += encrypted_size; + } + if (num_partitions > 1) { + offsets_buffer.AppendInt(partition_offset); + } + } + DCHECK_EQ(num_partitions * kWebMPartitionOffsetSize, + offsets_buffer.Size()); + memcpy(sample_data + kWebMSignalByteSize + kWebMIvSize + + kWebMNumPartitionsSize, + offsets_buffer.Buffer(), offsets_buffer.Size()); + } else { + // Use whole-frame encryption: | signal_byte(1) | iv | enc_data | + + sample->resize_data(sample_size + iv_size + kWebMSignalByteSize); + uint8_t* sample_data = sample->writable_data(); + + // Encrypt the data in-place. + if (!encryptor_->Crypt(sample_data, sample_size, sample_data)) { + return Status(error::MUXER_FAILURE, "Failed to encrypt the frame."); + } + + // First move the sample data to after the IV; then write the IV and + // signal byte. + memmove(sample_data + iv_size + kWebMSignalByteSize, sample_data, + sample_size); + sample_data[0] = kWebMEncryptedSignal; + memcpy(sample_data + 1, encryptor_->iv().data(), iv_size); + } encryptor_->UpdateIv(); } else { - // | 0 | data | + // Clear sample: | signal_byte(0) | data | sample->resize_data(sample_size + 1); uint8_t* sample_data = sample->writable_data(); memmove(sample_data + 1, sample_data, sample_size); @@ -100,7 +171,9 @@ Status Encryptor::EncryptFrame(scoped_refptr sample, Status Encryptor::CreateEncryptor(MuxerListener* muxer_listener, KeySource::TrackType track_type, - KeySource* key_source) { + Codec codec, + KeySource* key_source, + bool webm_subsample_encryption) { scoped_ptr encryption_key(new EncryptionKey()); Status status = key_source->GetKey(track_type, encryption_key.get()); if (!status.ok()) @@ -109,13 +182,18 @@ Status Encryptor::CreateEncryptor(MuxerListener* muxer_listener, if (!AesCryptor::GenerateRandomIv(FOURCC_cenc, &encryption_key->iv)) return Status(error::INTERNAL_ERROR, "Failed to generate random iv."); } - + DCHECK_EQ(kWebMIvSize, encryption_key->iv.size()); scoped_ptr encryptor(new AesCtrEncryptor()); const bool initialized = encryptor->InitializeWithIv(encryption_key->key, encryption_key->iv); if (!initialized) return Status(error::INTERNAL_ERROR, "Failed to create the encryptor."); + if (webm_subsample_encryption && codec == kCodecVP9) { + // Allocate VP9 parser to do subsample encryption of VP9. + vpx_parser_.reset(new VP9Parser); + } + if (muxer_listener) { const bool kInitialEncryptionInfo = true; muxer_listener->OnEncryptionInfoReady( diff --git a/packager/media/formats/webm/encryptor.h b/packager/media/formats/webm/encryptor.h index 051045f5b1..0cdfe7fb0e 100644 --- a/packager/media/formats/webm/encryptor.h +++ b/packager/media/formats/webm/encryptor.h @@ -11,6 +11,8 @@ #include "packager/base/memory/scoped_ptr.h" #include "packager/media/base/key_source.h" #include "packager/media/base/status.h" +#include "packager/media/base/stream_info.h" +#include "packager/media/codecs/vpx_parser.h" #include "packager/media/event/muxer_listener.h" #include "packager/third_party/libwebm/src/mkvmuxer.hpp" @@ -33,7 +35,9 @@ class Encryptor { /// @return OK on success, an error status otherwise. Status Initialize(MuxerListener* muxer_listener, KeySource::TrackType track_type, - KeySource* key_source); + Codec codec, + KeySource* key_source, + bool webm_subsample_encryption); /// Adds the encryption info to the given track. Initialize must be called /// first. @@ -50,11 +54,14 @@ class Encryptor { // Create the encryptor for the internal encryption key. Status CreateEncryptor(MuxerListener* muxer_listener, KeySource::TrackType track_type, - KeySource* key_source); + Codec codec, + KeySource* key_source, + bool webm_subsample_encryption); private: scoped_ptr key_; scoped_ptr encryptor_; + scoped_ptr vpx_parser_; }; } // namespace webm diff --git a/packager/media/formats/webm/segmenter.cc b/packager/media/formats/webm/segmenter.cc index 4b4ca15530..0d590850b8 100644 --- a/packager/media/formats/webm/segmenter.cc +++ b/packager/media/formats/webm/segmenter.cc @@ -79,7 +79,8 @@ Status Segmenter::Initialize(scoped_ptr writer, Status status; if (encryption_key_source) { - status = InitializeEncryptor(encryption_key_source, max_sd_pixels); + status = InitializeEncryptor(encryption_key_source, + max_sd_pixels); if (!status.ok()) return status; } @@ -362,7 +363,8 @@ Status Segmenter::InitializeEncryptor(KeySource* key_source, GetTrackTypeForEncryption(*info_, max_sd_pixels); if (track_type == KeySource::TrackType::TRACK_TYPE_UNKNOWN) return Status::OK; - return encryptor_->Initialize(muxer_listener_, track_type, key_source); + return encryptor_->Initialize(muxer_listener_, track_type, info_->codec(), + key_source, options_.webm_subsample_encryption); } Status Segmenter::WriteFrame(bool write_duration) { diff --git a/packager/media/formats/webm/segmenter_test_base.cc b/packager/media/formats/webm/segmenter_test_base.cc index 4ef10dbc45..726f0042de 100644 --- a/packager/media/formats/webm/segmenter_test_base.cc +++ b/packager/media/formats/webm/segmenter_test_base.cc @@ -25,7 +25,7 @@ const uint8_t kTestMediaSampleSideData[] = { const int kTrackId = 1; const uint32_t kTimeScale = 1000; const uint64_t kDuration = 8000; -const VideoCodec kVideoCodec = kCodecVP8; +const Codec kCodec = kCodecVP8; const std::string kCodecString = "vp8"; const std::string kLanguage = "en"; const uint16_t kWidth = 100; @@ -92,10 +92,10 @@ MuxerOptions SegmentTestBase::CreateMuxerOptions() const { } VideoStreamInfo* SegmentTestBase::CreateVideoStreamInfo() const { - return new VideoStreamInfo(kTrackId, kTimeScale, kDuration, kVideoCodec, - kCodecString, kLanguage, kWidth, kHeight, + return new VideoStreamInfo(kTrackId, kTimeScale, kDuration, kCodec, + kCodecString, NULL, 0, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, - kNaluLengthSize, NULL, 0, false); + kNaluLengthSize, kLanguage, false); } std::string SegmentTestBase::OutputFileName() const { @@ -200,4 +200,3 @@ bool SegmentTestBase::ClusterParser::OnString(int id, const std::string& str) { } // namespace media } // namespace shaka - diff --git a/packager/media/formats/webm/webm.gyp b/packager/media/formats/webm/webm.gyp index 3a1d7d3623..7557405d27 100644 --- a/packager/media/formats/webm/webm.gyp +++ b/packager/media/formats/webm/webm.gyp @@ -56,6 +56,7 @@ ], 'dependencies': [ '../../../third_party/boringssl/boringssl.gyp:boringssl', + '../../../third_party/gflags/gflags.gyp:gflags', '../../../third_party/libwebm/libwebm.gyp:mkvmuxer', '../../base/media_base.gyp:media_base', '../../codecs/codecs.gyp:codecs' diff --git a/packager/media/formats/webm/webm_audio_client.cc b/packager/media/formats/webm/webm_audio_client.cc index 7a962268b0..bce44299f8 100644 --- a/packager/media/formats/webm/webm_audio_client.cc +++ b/packager/media/formats/webm/webm_audio_client.cc @@ -36,7 +36,7 @@ scoped_refptr WebMAudioClient::GetAudioStreamInfo( int64_t codec_delay, const std::string& language, bool is_encrypted) { - AudioCodec audio_codec = kUnknownAudioCodec; + Codec audio_codec = kUnknownCodec; if (codec_id == "A_VORBIS") { audio_codec = kCodecVorbis; } else if (codec_id == "A_OPUS") { @@ -70,10 +70,10 @@ scoped_refptr WebMAudioClient::GetAudioStreamInfo( const uint8_t kSampleSizeInBits = 16u; return scoped_refptr(new AudioStreamInfo( track_num, kWebMTimeScale, 0, audio_codec, - AudioStreamInfo::GetCodecString(audio_codec, 0), language, - kSampleSizeInBits, channels_, sampling_frequency, + AudioStreamInfo::GetCodecString(audio_codec, 0), codec_config, + codec_config_size, kSampleSizeInBits, channels_, sampling_frequency, seek_preroll < 0 ? 0 : seek_preroll, codec_delay < 0 ? 0 : codec_delay, 0, - 0, codec_config, codec_config_size, is_encrypted)); + 0, language, is_encrypted)); } bool WebMAudioClient::OnUInt(int id, int64_t val) { diff --git a/packager/media/formats/webm/webm_cluster_parser.cc b/packager/media/formats/webm/webm_cluster_parser.cc index 2c78166a1a..c2268e378f 100644 --- a/packager/media/formats/webm/webm_cluster_parser.cc +++ b/packager/media/formats/webm/webm_cluster_parser.cc @@ -27,10 +27,7 @@ const int64_t kMicrosecondsPerMillisecond = 1000; // block is a keyframe. // |data| contains the bytes in the block. // |size| indicates the number of bytes in |data|. -bool IsKeyframe(bool is_video, - VideoCodec codec, - const uint8_t* data, - int size) { +bool IsKeyframe(bool is_video, Codec codec, const uint8_t* data, int size) { // For now, assume that all blocks are keyframes for datatypes other than // video. This is a valid assumption for Vorbis, WebVTT, & Opus. if (!is_video) @@ -370,7 +367,7 @@ bool WebMClusterParser::OnBlock(bool is_simple_block, ? (flags & 0x80) != 0 : IsKeyframe(stream_type == kStreamVideo, video_stream_info_ ? video_stream_info_->codec() - : kUnknownVideoCodec, + : kUnknownCodec, data, size); // Every encrypted Block has a signal byte and IV prepended to it. Current @@ -390,8 +387,7 @@ bool WebMClusterParser::OnBlock(bool is_simple_block, buffer = MediaSample::CopyFrom(data + data_offset, size - data_offset, additional, additional_size, is_keyframe); - // An empty iv indicates that this sample is not encrypted. - if (decrypt_config && !decrypt_config->iv().empty()) { + if (decrypt_config) { if (!decryptor_source_) { LOG(ERROR) << "Encrypted media sample encountered, but decryption is " "not enabled"; diff --git a/packager/media/formats/webm/webm_cluster_parser_unittest.cc b/packager/media/formats/webm/webm_cluster_parser_unittest.cc index e0b674e4ec..e1a2af2c1d 100644 --- a/packager/media/formats/webm/webm_cluster_parser_unittest.cc +++ b/packager/media/formats/webm/webm_cluster_parser_unittest.cc @@ -84,6 +84,7 @@ const uint8_t kNumChannels = 2u; const uint32_t kSamplingFrequency = 48000u; const uint64_t kSeekPreroll = 0u; const uint64_t kCodecDelay = 0u; +const uint8_t* kExtraData = nullptr; const size_t kExtraDataSize = 0u; const bool kEncrypted = true; const uint16_t kWidth = 320u; @@ -316,37 +317,16 @@ bool VerifyTextBuffers(const BlockInfo* block_info_ptr, class WebMClusterParserTest : public testing::Test { public: WebMClusterParserTest() - : audio_stream_info_(new AudioStreamInfo(kAudioTrackNum, - kTimeScale, - kDuration, - kUnknownAudioCodec, - kCodecString, - kLanguage, - kBitsPerSample, - kNumChannels, - kSamplingFrequency, - kSeekPreroll, - kCodecDelay, - 0, - 0, - NULL, - kExtraDataSize, - !kEncrypted)), - video_stream_info_(new VideoStreamInfo(kVideoTrackNum, - kTimeScale, - kDuration, - kCodecVP8, - kCodecString, - kLanguage, - kWidth, - kHeight, - kPixelWidth, - kPixelHeight, - kTrickPlayRate, - kNaluLengthSize, - NULL, - kExtraDataSize, - !kEncrypted)), + : audio_stream_info_(new AudioStreamInfo( + kAudioTrackNum, kTimeScale, kDuration, kUnknownCodec, kCodecString, + kExtraData, kExtraDataSize, kBitsPerSample, kNumChannels, + kSamplingFrequency, kSeekPreroll, kCodecDelay, 0, 0, kLanguage, + !kEncrypted)), + video_stream_info_(new VideoStreamInfo( + kVideoTrackNum, kTimeScale, kDuration, kCodecVP8, kCodecString, + kExtraData, kExtraDataSize, kWidth, kHeight, kPixelWidth, + kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, + !kEncrypted)), parser_(CreateDefaultParser()) {} protected: @@ -390,15 +370,12 @@ class WebMClusterParserTest : public testing::Test { // Helper that hard-codes some non-varying constructor parameters. WebMClusterParser* CreateParserHelper( - int64_t audio_default_duration, - int64_t video_default_duration, + int64_t audio_default_duration, int64_t video_default_duration, const WebMTracksParser::TextTracks& text_tracks, const std::set& ignored_tracks, const std::string& audio_encryption_key_id, - const std::string& video_encryption_key_id, - const AudioCodec audio_codec, - const VideoCodec video_codec, - const MediaParser::InitCB& init_cb) { + const std::string& video_encryption_key_id, const Codec audio_codec, + const Codec video_codec, const MediaParser::InitCB& init_cb) { audio_stream_info_->set_codec(audio_codec); video_stream_info_->set_codec(video_codec); return new WebMClusterParser( @@ -414,8 +391,7 @@ class WebMClusterParserTest : public testing::Test { WebMClusterParser* CreateDefaultParser() { return CreateParserHelper(kNoTimestamp, kNoTimestamp, TextTracks(), std::set(), std::string(), std::string(), - kUnknownAudioCodec, kCodecVP8, - MediaParser::InitCB()); + kUnknownCodec, kCodecVP8, MediaParser::InitCB()); } // Create a parser for test with custom audio and video default durations, and @@ -426,23 +402,22 @@ class WebMClusterParserTest : public testing::Test { const WebMTracksParser::TextTracks& text_tracks = TextTracks()) { return CreateParserHelper(audio_default_duration, video_default_duration, text_tracks, std::set(), std::string(), - std::string(), kUnknownAudioCodec, kCodecVP8, + std::string(), kUnknownCodec, kCodecVP8, MediaParser::InitCB()); } // Create a parser for test with custom ignored tracks. WebMClusterParser* CreateParserWithIgnoredTracks( std::set& ignored_tracks) { - return CreateParserHelper( - kNoTimestamp, kNoTimestamp, TextTracks(), ignored_tracks, std::string(), - std::string(), kUnknownAudioCodec, kCodecVP8, MediaParser::InitCB()); + return CreateParserHelper(kNoTimestamp, kNoTimestamp, TextTracks(), + ignored_tracks, std::string(), std::string(), + kUnknownCodec, kCodecVP8, MediaParser::InitCB()); } // Create a parser for test with custom encryption key ids and audio codec. - WebMClusterParser* CreateParserWithKeyIdsAndAudioCodec( + WebMClusterParser* CreateParserWithKeyIdsAndCodec( const std::string& audio_encryption_key_id, - const std::string& video_encryption_key_id, - const AudioCodec audio_codec) { + const std::string& video_encryption_key_id, const Codec audio_codec) { return CreateParserHelper(kNoTimestamp, kNoTimestamp, TextTracks(), std::set(), audio_encryption_key_id, video_encryption_key_id, audio_codec, kCodecVP8, @@ -451,10 +426,10 @@ class WebMClusterParserTest : public testing::Test { // Create a parser for test with custom video codec, also check for init // events. - WebMClusterParser* CreateParserWithVideoCodec(const VideoCodec video_codec) { + WebMClusterParser* CreateParserWithCodec(const Codec video_codec) { return CreateParserHelper( kNoTimestamp, kNoTimestamp, TextTracks(), std::set(), - std::string(), std::string(), kUnknownAudioCodec, video_codec, + std::string(), std::string(), kUnknownCodec, video_codec, base::Bind(&WebMClusterParserTest::InitEvent, base::Unretained(this))); } @@ -807,7 +782,7 @@ TEST_F(WebMClusterParserTest, ParseMultipleTextTracks) { TEST_F(WebMClusterParserTest, ParseVP8) { scoped_ptr cluster(CreateCluster(kVP8Frame, arraysize(kVP8Frame))); - parser_.reset(CreateParserWithVideoCodec(kCodecVP8)); + parser_.reset(CreateParserWithCodec(kCodecVP8)); EXPECT_EQ(cluster->size(), parser_->Parse(cluster->data(), cluster->size())); @@ -820,7 +795,7 @@ TEST_F(WebMClusterParserTest, ParseVP8) { TEST_F(WebMClusterParserTest, ParseVP9) { scoped_ptr cluster(CreateCluster(kVP9Frame, arraysize(kVP9Frame))); - parser_.reset(CreateParserWithVideoCodec(kCodecVP9)); + parser_.reset(CreateParserWithCodec(kCodecVP9)); EXPECT_EQ(cluster->size(), parser_->Parse(cluster->data(), cluster->size())); @@ -844,8 +819,8 @@ TEST_F(WebMClusterParserTest, ParseEncryptedBlock) { scoped_ptr cluster( CreateCluster(kEncryptedFrame, arraysize(kEncryptedFrame))); - parser_.reset(CreateParserWithKeyIdsAndAudioCodec(std::string(), video_key_id, - kUnknownAudioCodec)); + parser_.reset(CreateParserWithKeyIdsAndCodec(std::string(), video_key_id, + kUnknownCodec)); int result = parser_->Parse(cluster->data(), cluster->size()); EXPECT_EQ(cluster->size(), result); @@ -865,8 +840,8 @@ TEST_F(WebMClusterParserTest, ParseEncryptedBlockGetKeyFailed) { scoped_ptr cluster( CreateCluster(kEncryptedFrame, arraysize(kEncryptedFrame))); - parser_.reset(CreateParserWithKeyIdsAndAudioCodec( - std::string(), "video_key_id", kUnknownAudioCodec)); + parser_.reset(CreateParserWithKeyIdsAndCodec(std::string(), "video_key_id", + kUnknownCodec)); int result = parser_->Parse(cluster->data(), cluster->size()); EXPECT_EQ(-1, result); @@ -876,8 +851,8 @@ TEST_F(WebMClusterParserTest, ParseBadEncryptedBlock) { scoped_ptr cluster( CreateCluster(kEncryptedFrame, arraysize(kEncryptedFrame) - 2)); - parser_.reset(CreateParserWithKeyIdsAndAudioCodec( - std::string(), "video_key_id", kUnknownAudioCodec)); + parser_.reset(CreateParserWithKeyIdsAndCodec(std::string(), "video_key_id", + kUnknownCodec)); int result = parser_->Parse(cluster->data(), cluster->size()); EXPECT_EQ(-1, result); } @@ -886,8 +861,8 @@ TEST_F(WebMClusterParserTest, ParseClearFrameInEncryptedTrack) { scoped_ptr cluster(CreateCluster( kClearFrameInEncryptedTrack, arraysize(kClearFrameInEncryptedTrack))); - parser_.reset(CreateParserWithKeyIdsAndAudioCodec( - std::string(), "video_key_id", kUnknownAudioCodec)); + parser_.reset(CreateParserWithKeyIdsAndCodec(std::string(), "video_key_id", + kUnknownCodec)); int result = parser_->Parse(cluster->data(), cluster->size()); EXPECT_EQ(cluster->size(), result); diff --git a/packager/media/formats/webm/webm_constants.h b/packager/media/formats/webm/webm_constants.h index 86a3af1cbd..214aeb00f5 100644 --- a/packager/media/formats/webm/webm_constants.h +++ b/packager/media/formats/webm/webm_constants.h @@ -5,6 +5,7 @@ #ifndef MEDIA_FORMATS_WEBM_WEBM_CONSTANTS_H_ #define MEDIA_FORMATS_WEBM_WEBM_CONSTANTS_H_ +#include #include namespace shaka { @@ -207,9 +208,13 @@ const uint8_t kWebMFlagKeyframe = 0x80; /// Current encrypted WebM request for comments specification is here /// http://wiki.webmproject.org/encryption/webm-encryption-rfc -const uint8_t kWebMFlagEncryptedFrame = 0x1; -const int kWebMIvSize = 8; -const int kWebMSignalByteSize = 1; +const size_t kWebMIvSize = 8; +const size_t kWebMSignalByteSize = 1; +const uint8_t kWebMEncryptedSignal = 0x01; +const uint8_t kWebMPartitionedSignal = 0x02; +const size_t kWebMNumPartitionsSize = 1; +const size_t kWebMPartitionOffsetSize = sizeof(uint32_t); +const uint8_t kWebMMaxSubsamples = 127; /// Current specification for WebVTT embedded in WebM /// http://wiki.webmproject.org/webm-metadata/temporal-metadata/webvtt-in-webm diff --git a/packager/media/formats/webm/webm_crypto_helpers.cc b/packager/media/formats/webm/webm_crypto_helpers.cc index 6c977baaa6..f858bc415f 100644 --- a/packager/media/formats/webm/webm_crypto_helpers.cc +++ b/packager/media/formats/webm/webm_crypto_helpers.cc @@ -6,6 +6,7 @@ #include "packager/base/logging.h" #include "packager/base/sys_byteorder.h" +#include "packager/media/base/buffer_reader.h" #include "packager/media/formats/webm/webm_constants.h" namespace shaka { @@ -16,48 +17,96 @@ namespace { // CTR IV appended with a CTR block counter. |iv| is an 8 byte CTR IV. // |iv_size| is the size of |iv| in btyes. Returns a string of // kDecryptionKeySize bytes. -std::string GenerateWebMCounterBlock(const uint8_t* iv, int iv_size) { - std::string counter_block(reinterpret_cast(iv), iv_size); - counter_block.append(DecryptConfig::kDecryptionKeySize - iv_size, 0); +std::vector GenerateWebMCounterBlock(const uint8_t* iv, int iv_size) { + std::vector counter_block(iv, iv + iv_size); + counter_block.insert(counter_block.end(), + DecryptConfig::kDecryptionKeySize - iv_size, 0); return counter_block; } } // namespace anonymous +// TODO(tinskip): Add unit test for this function. bool WebMCreateDecryptConfig(const uint8_t* data, int data_size, const uint8_t* key_id, int key_id_size, scoped_ptr* decrypt_config, int* data_offset) { - if (data_size < kWebMSignalByteSize) { - DVLOG(1) << "Got a block from an encrypted stream with no data."; + int header_size = kWebMSignalByteSize; + if (data_size < header_size) { + DVLOG(1) << "Empty WebM sample."; return false; } - uint8_t signal_byte = data[0]; - int frame_offset = sizeof(signal_byte); - // Setting the DecryptConfig object of the buffer while leaving the - // initialization vector empty will tell the decryptor that the frame is - // unencrypted. - std::string counter_block; - - if (signal_byte & kWebMFlagEncryptedFrame) { - if (data_size < kWebMSignalByteSize + kWebMIvSize) { - DVLOG(1) << "Got an encrypted block with not enough data " << data_size; + if (signal_byte & kWebMEncryptedSignal) { + // Encrypted sample. + header_size += kWebMIvSize; + if (data_size < header_size) { + DVLOG(1) << "Encrypted WebM sample too small to hold IV: " << data_size; return false; } - counter_block = GenerateWebMCounterBlock(data + frame_offset, kWebMIvSize); - frame_offset += kWebMIvSize; + std::vector subsamples; + if (signal_byte & kWebMPartitionedSignal) { + // Encrypted sample with subsamples / partitioning. + header_size += kWebMNumPartitionsSize; + if (data_size < header_size) { + DVLOG(1) + << "Encrypted WebM sample too small to hold number of partitions: " + << data_size; + return false; + } + uint8_t num_partitions = data[kWebMSignalByteSize + kWebMIvSize]; + BufferReader offsets_buffer(data + header_size, data_size - header_size); + header_size += num_partitions * kWebMPartitionOffsetSize; + uint32_t subsample_offset = 0; + bool encrypted_subsample = false; + uint16_t clear_size = 0; + uint32_t encrypted_size = 0; + for (uint8_t partition_idx = 0; partition_idx < num_partitions; + ++partition_idx) { + uint32_t partition_offset; + if (!offsets_buffer.Read4(&partition_offset)) { + DVLOG(1) + << "Encrypted WebM sample too small to hold partition offsets: " + << data_size; + return false; + } + if (partition_offset < subsample_offset) { + DVLOG(1) << "Partition offsets out of order."; + return false; + } + if (encrypted_subsample) { + encrypted_size = partition_offset - subsample_offset; + subsamples.push_back(SubsampleEntry(clear_size, encrypted_size)); + } else { + clear_size = partition_offset - subsample_offset; + if (partition_idx == (num_partitions - 1)) { + encrypted_size = data_size - header_size - subsample_offset - clear_size; + subsamples.push_back(SubsampleEntry(clear_size, encrypted_size)); + } + } + subsample_offset = partition_offset; + encrypted_subsample = !encrypted_subsample; + } + if (!(num_partitions % 2)) { + // Even number of partitions. Add one last all-clear subsample. + clear_size = data_size - header_size - subsample_offset; + encrypted_size = 0; + subsamples.push_back(SubsampleEntry(clear_size, encrypted_size)); + } + } + decrypt_config->reset(new DecryptConfig( + std::vector(key_id, key_id + key_id_size), + GenerateWebMCounterBlock(data + kWebMSignalByteSize, kWebMIvSize), + subsamples)); + } else { + // Clear sample. + decrypt_config->reset(); } - decrypt_config->reset(new DecryptConfig( - std::vector(key_id, key_id + key_id_size), - std::vector(counter_block.begin(), counter_block.end()), - std::vector())); - *data_offset = frame_offset; - + *data_offset = header_size; return true; } diff --git a/packager/media/formats/webm/webm_video_client.cc b/packager/media/formats/webm/webm_video_client.cc index e77d9c4286..8a22ce5b9e 100644 --- a/packager/media/formats/webm/webm_video_client.cc +++ b/packager/media/formats/webm/webm_video_client.cc @@ -53,7 +53,7 @@ scoped_refptr WebMVideoClient::GetVideoStreamInfo( const std::string& codec_id, const std::vector& codec_private, bool is_encrypted) { - VideoCodec video_codec = kUnknownVideoCodec; + Codec video_codec = kUnknownCodec; if (codec_id == "V_VP8") { video_codec = kCodecVP8; } else if (codec_id == "V_VP9") { @@ -110,9 +110,9 @@ scoped_refptr WebMVideoClient::GetVideoStreamInfo( sar_y /= gcd; return scoped_refptr(new VideoStreamInfo( - track_num, kWebMTimeScale, 0, video_codec, std::string(), std::string(), - width_after_crop, height_after_crop, sar_x, sar_y, 0, 0, - codec_private.data(), codec_private.size(), is_encrypted)); + track_num, kWebMTimeScale, 0, video_codec, std::string(), + codec_private.data(), codec_private.size(), width_after_crop, + height_after_crop, sar_x, sar_y, 0, 0, std::string(), is_encrypted)); } bool WebMVideoClient::OnUInt(int id, int64_t val) { diff --git a/packager/media/formats/webvtt/webvtt_media_parser.cc b/packager/media/formats/webvtt/webvtt_media_parser.cc index e7bb364933..dad0688177 100644 --- a/packager/media/formats/webvtt/webvtt_media_parser.cc +++ b/packager/media/formats/webvtt/webvtt_media_parser.cc @@ -294,15 +294,12 @@ bool WebVttMediaParser::Parse(const uint8_t* buf, int size) { // There is no one metadata to determine what the language is. Parts // of the text may be annotated as some specific language. const char kLanguage[] = ""; - streams.push_back(new TextStreamInfo( - kTrackId, - kTimescale, - kDuration, - "wvtt", - kLanguage, - base::JoinString(header_, "\n"), - 0, // Not necessary. - 0)); // Not necessary. + streams.push_back(new TextStreamInfo(kTrackId, kTimescale, kDuration, + "wvtt", + base::JoinString(header_, "\n"), + 0, // Not necessary. + 0, + kLanguage)); // Not necessary. init_cb_.Run(streams); state_ = kCueIdentifierOrTimingOrComment; diff --git a/packager/media/formats/wvm/wvm_media_parser.cc b/packager/media/formats/wvm/wvm_media_parser.cc index a543e3ff43..4f23ad4765 100644 --- a/packager/media/formats/wvm/wvm_media_parser.cc +++ b/packager/media/formats/wvm/wvm_media_parser.cc @@ -739,31 +739,33 @@ bool WvmMediaParser::ParseIndexEntry() { index_size = read_ptr - index_data_.data(); if (has_video) { - VideoCodec video_codec = kCodecH264; + Codec video_codec = kCodecH264; stream_infos_.push_back(new VideoStreamInfo( stream_id_count_, time_scale, track_duration, video_codec, - std::string(), std::string(), video_width, video_height, pixel_width, - pixel_height, trick_play_rate, nalu_length_size, - video_codec_config.data(), video_codec_config.size(), true)); + std::string(), video_codec_config.data(), video_codec_config.size(), + video_width, video_height, pixel_width, pixel_height, trick_play_rate, + nalu_length_size, std::string(), true)); program_demux_stream_map_[base::UintToString(index_program_id_) + ":" + - base::UintToString(video_pes_stream_id ? - video_pes_stream_id : - kDefaultVideoStreamId)] = + base::UintToString( + video_pes_stream_id + ? video_pes_stream_id + : kDefaultVideoStreamId)] = stream_id_count_++; } if (has_audio) { - const AudioCodec audio_codec = kCodecAAC; + const Codec audio_codec = kCodecAAC; // TODO(beil): Pass in max and average bitrate in wvm container. stream_infos_.push_back(new AudioStreamInfo( stream_id_count_, time_scale, track_duration, audio_codec, - std::string(), std::string(), kAacSampleSizeBits, num_channels, - sampling_frequency, 0 /* seek preroll */, 0 /* codec delay */, - 0 /* max bitrate */, 0 /* avg bitrate */, audio_codec_config.data(), - audio_codec_config.size(), true)); + std::string(), audio_codec_config.data(), audio_codec_config.size(), + kAacSampleSizeBits, num_channels, sampling_frequency, + 0 /* seek preroll */, 0 /* codec delay */, 0 /* max bitrate */, + 0 /* avg bitrate */, std::string(), true)); program_demux_stream_map_[base::UintToString(index_program_id_) + ":" + - base::UintToString(audio_pes_stream_id ? - audio_pes_stream_id : - kDefaultAudioStreamId)] = + base::UintToString( + audio_pes_stream_id + ? audio_pes_stream_id + : kDefaultAudioStreamId)] = stream_id_count_++; } } diff --git a/packager/media/test/data/bear-640x360-vp9-altref.webm b/packager/media/test/data/bear-640x360-vp9-altref.webm new file mode 100644 index 0000000000..4c2efd7ead Binary files /dev/null and b/packager/media/test/data/bear-640x360-vp9-altref.webm differ