diff --git a/app/packager_main.cc b/app/packager_main.cc index b13603f9a8..14b8575379 100644 --- a/app/packager_main.cc +++ b/app/packager_main.cc @@ -15,7 +15,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "media/base/demuxer.h" -#include "media/base/fixed_encryptor_source.h" #include "media/base/media_stream.h" #include "media/base/muxer_options.h" #include "media/base/request_signer.h" @@ -76,27 +75,11 @@ scoped_ptr CreateEncryptorSource() { } } - WidevineEncryptorSource::TrackType track_type = - WidevineEncryptorSource::GetTrackTypeFromString(FLAGS_track_type); - if (track_type == WidevineEncryptorSource::TRACK_TYPE_UNKNOWN) { - LOG(ERROR) << "Unknown track_type specified."; - return scoped_ptr(); - } - encryptor_source.reset(new WidevineEncryptorSource( - FLAGS_server_url, FLAGS_content_id, track_type, signer.Pass())); + FLAGS_server_url, FLAGS_content_id, signer.Pass())); } else if (FLAGS_enable_fixed_key_encryption) { - encryptor_source.reset( - new FixedEncryptorSource(FLAGS_key_id, FLAGS_key, FLAGS_pssh)); - } - - if (encryptor_source) { - Status status = encryptor_source->Initialize(); - if (!status.ok()) { - LOG(ERROR) << "Encryptor source failed to initialize: " - << status.ToString(); - return scoped_ptr(); - } + encryptor_source = EncryptorSource::CreateFromHexStrings( + FLAGS_key_id, FLAGS_key, FLAGS_pssh, ""); } return encryptor_source.Pass(); } @@ -229,7 +212,15 @@ bool RunPackager(const std::string& input) { if (!encryptor_source) return false; } - muxer->SetEncryptorSource(encryptor_source.get(), FLAGS_clear_lead); + EncryptorSource::TrackType track_type = + EncryptorSource::GetTrackTypeFromString(FLAGS_track_type); + if (track_type != EncryptorSource::TRACK_TYPE_SD && + track_type != EncryptorSource::TRACK_TYPE_HD) { + LOG(ERROR) << "FLAGS_track_type should be either 'SD' or 'HD'"; + return false; + } + muxer->SetEncryptorSource( + encryptor_source.get(), track_type, FLAGS_clear_lead); // Start remuxing process. status = demuxer.Run(); diff --git a/app/widevine_encryption_flags.h b/app/widevine_encryption_flags.h index 3f0b561e97..8590b680f1 100644 --- a/app/widevine_encryption_flags.h +++ b/app/widevine_encryption_flags.h @@ -20,7 +20,7 @@ DEFINE_bool(enable_widevine_encryption, "--aes_signing_iv) or RSA signing key (--rsa_signing_key_path)."); DEFINE_string(server_url, "", "License server url."); DEFINE_string(content_id, "", "Content Id."); -DEFINE_string(track_type, "SD", "Track type: HD, SD or AUDIO."); +DEFINE_string(track_type, "SD", "Track type: SD or HD."); DEFINE_string(signer, "", "The name of the signer."); DEFINE_string(aes_signing_key, "", diff --git a/media/base/muxer.cc b/media/base/muxer.cc index d7cc3aa4f8..7825345635 100644 --- a/media/base/muxer.cc +++ b/media/base/muxer.cc @@ -16,6 +16,7 @@ Muxer::Muxer(const MuxerOptions& options) : options_(options), encryptor_source_(NULL), initialized_(false), + track_type_(EncryptorSource::TRACK_TYPE_SD), clear_lead_in_seconds_(0), muxer_listener_(NULL), clock_(NULL) {} @@ -23,8 +24,10 @@ Muxer::Muxer(const MuxerOptions& options) Muxer::~Muxer() {} void Muxer::SetEncryptorSource(EncryptorSource* encryptor_source, + EncryptorSource::TrackType track_type, double clear_lead_in_seconds) { encryptor_source_ = encryptor_source; + track_type_ = track_type; clear_lead_in_seconds_ = clear_lead_in_seconds; } diff --git a/media/base/muxer.h b/media/base/muxer.h index 3d52bb80ad..5d3a55970b 100644 --- a/media/base/muxer.h +++ b/media/base/muxer.h @@ -13,6 +13,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "media/base/encryptor_source.h" #include "media/base/muxer_options.h" #include "media/base/status.h" @@ -41,8 +42,11 @@ class Muxer { /// Set encryptor source. /// @param encryptor_source points to the encryptor source to be injected. /// Should not be NULL. + /// @param track_type should be either SD or HD. It affects whether SD key or + /// HD key is used to encrypt the video content. /// @param clear_lead_in_seconds specifies clear lead duration in seconds. void SetEncryptorSource(EncryptorSource* encryptor_source, + EncryptorSource::TrackType track_type, double clear_lead_in_seconds); /// Add video/audio stream. @@ -70,6 +74,7 @@ class Muxer { protected: const MuxerOptions& options() const { return options_; } EncryptorSource* encryptor_source() { return encryptor_source_; } + EncryptorSource::TrackType track_type() const { return track_type_; } double clear_lead_in_seconds() const { return clear_lead_in_seconds_; } event::MuxerListener* muxer_listener() { return muxer_listener_; } base::Clock* clock() { return clock_; } @@ -95,6 +100,7 @@ class Muxer { std::vector streams_; EncryptorSource* encryptor_source_; bool initialized_; + EncryptorSource::TrackType track_type_; double clear_lead_in_seconds_; event::MuxerListener* muxer_listener_; diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc index 706ff1eeb9..800d87b2f0 100644 --- a/media/formats/mp4/box_definitions.cc +++ b/media/formats/mp4/box_definitions.cc @@ -90,6 +90,12 @@ ProtectionSystemSpecificHeader::~ProtectionSystemSpecificHeader() {} FourCC ProtectionSystemSpecificHeader::BoxType() const { return FOURCC_PSSH; } bool ProtectionSystemSpecificHeader::ReadWrite(BoxBuffer* buffer) { + if (!buffer->Reading() && !raw_box.empty()) { + // Write the raw box directly. + buffer->writer()->AppendVector(raw_box); + return true; + } + uint32 size = data.size(); RCHECK(FullBox::ReadWrite(buffer) && buffer->ReadWriteVector(&system_id, 16) && @@ -108,7 +114,10 @@ bool ProtectionSystemSpecificHeader::ReadWrite(BoxBuffer* buffer) { } uint32 ProtectionSystemSpecificHeader::ComputeSize() { - atom_size = kFullBoxSize + system_id.size() + sizeof(uint32) + data.size(); + if (!raw_box.empty()) + atom_size = raw_box.size(); + else + atom_size = kFullBoxSize + system_id.size() + sizeof(uint32) + data.size(); return atom_size; } diff --git a/media/formats/mp4/box_definitions_unittest.cc b/media/formats/mp4/box_definitions_unittest.cc index ac3de91a3a..7d30b2c8c8 100644 --- a/media/formats/mp4/box_definitions_unittest.cc +++ b/media/formats/mp4/box_definitions_unittest.cc @@ -733,7 +733,7 @@ class BoxDefinitionsTestGeneral : public testing::Test { typedef testing::Types< FileType, SegmentType, - // ProtectionSystemSpecificHeader, // Not fully parsed. + ProtectionSystemSpecificHeader, SampleAuxiliaryInformationOffset, SampleAuxiliaryInformationSize, OriginalFormat, @@ -854,8 +854,17 @@ TEST_F(BoxDefinitionsTest, ProtectionSystemSpecificHeader) { ProtectionSystemSpecificHeader pssh_readback; ASSERT_TRUE(ReadBack(&pssh_readback)); - // PSSH does not parse data. - ASSERT_EQ(pssh.system_id, pssh_readback.system_id); + ASSERT_EQ(pssh, pssh_readback); + + pssh_readback.raw_box[15] += 1; + pssh_readback.Write(this->buffer_.get()); + + ProtectionSystemSpecificHeader pssh_readback2; + ASSERT_TRUE(ReadBack(&pssh_readback2)); + + // If raw_box is set, raw_box will be written instead. + ASSERT_FALSE(pssh_readback == pssh_readback2); + ASSERT_EQ(pssh_readback.raw_box, pssh_readback2.raw_box); } TEST_F(BoxDefinitionsTest, CompactSampleSize_FieldSize16) { diff --git a/media/formats/mp4/mp4_muxer.cc b/media/formats/mp4/mp4_muxer.cc index 3aa23d83c3..ba9ad7c498 100644 --- a/media/formats/mp4/mp4_muxer.cc +++ b/media/formats/mp4/mp4_muxer.cc @@ -23,9 +23,6 @@ #include "media/formats/mp4/single_segment_segmenter.h" namespace { -// The version of cenc implemented here. CENC 4. -const int kCencSchemeVersion = 0x00010000; - // Sets the range start and end value from offset and size. // |start| and |end| are for byte-range-spec specified in RFC2616. void SetStartAndEndFromOffsetAndSize(size_t offset, @@ -93,11 +90,6 @@ Status MP4Muxer::Initialize() { } } - if (IsEncryptionRequired()) { - moov->pssh.resize(1); - GeneratePssh(&moov->pssh[0]); - } - if (options().single_segment) { segmenter_.reset( new SingleSegmentSegmenter(options(), ftyp.Pass(), moov.Pass())); @@ -107,7 +99,7 @@ Status MP4Muxer::Initialize() { } Status segmenter_initialized = segmenter_->Initialize( - encryptor_source(), clear_lead_in_seconds(), streams()); + streams(), encryptor_source(), track_type(), clear_lead_in_seconds()); if (!segmenter_initialized.ok()) return segmenter_initialized; @@ -169,17 +161,6 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info, trak->media.information.sample_table.description; sample_description.type = kVideo; sample_description.video_entries.push_back(video); - - if (IsEncryptionRequired()) { - DCHECK(encryptor_source()); - // Add a second entry for clear content if needed. - if (clear_lead_in_seconds() > 0) - sample_description.video_entries.push_back(video); - - VideoSampleEntry& encrypted_video = sample_description.video_entries[0]; - GenerateSinf(&encrypted_video.sinf, encrypted_video.format); - encrypted_video.format = FOURCC_ENCV; - } } void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info, @@ -209,33 +190,6 @@ void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info, trak->media.information.sample_table.description; sample_description.type = kAudio; sample_description.audio_entries.push_back(audio); - - if (IsEncryptionRequired()) { - DCHECK(encryptor_source()); - // Add a second entry for clear content if needed. - if (clear_lead_in_seconds() > 0) - sample_description.audio_entries.push_back(audio); - - AudioSampleEntry& encrypted_audio = sample_description.audio_entries[0]; - GenerateSinf(&encrypted_audio.sinf, encrypted_audio.format); - encrypted_audio.format = FOURCC_ENCA; - } -} - -void MP4Muxer::GeneratePssh(ProtectionSystemSpecificHeader* pssh) { - DCHECK(encryptor_source()); - pssh->system_id = encryptor_source()->key_system_id(); - pssh->data = encryptor_source()->pssh(); -} - -void MP4Muxer::GenerateSinf(ProtectionSchemeInfo* sinf, FourCC old_type) { - DCHECK(encryptor_source()); - sinf->format.format = old_type; - sinf->type.type = FOURCC_CENC; - sinf->type.version = kCencSchemeVersion; - sinf->info.track_encryption.is_encrypted = true; - sinf->info.track_encryption.default_iv_size = encryptor_source()->iv_size(); - sinf->info.track_encryption.default_kid = encryptor_source()->key_id(); } void MP4Muxer::GetStreamInfo(std::vector* stream_infos) { @@ -320,7 +274,7 @@ void MP4Muxer::FireOnMediaEndEvent() { index_range_end, duration_seconds, file_size, - IsEncryptionRequired()); + encryptor_source()); } uint64 MP4Muxer::IsoTimeNow() { diff --git a/media/formats/mp4/mp4_muxer.h b/media/formats/mp4/mp4_muxer.h index 840e122ecf..9c01c82539 100644 --- a/media/formats/mp4/mp4_muxer.h +++ b/media/formats/mp4/mp4_muxer.h @@ -50,15 +50,6 @@ class MP4Muxer : public Muxer { Track* trak, uint32 track_id); - // Generate Pssh atom. - void GeneratePssh(ProtectionSystemSpecificHeader* pssh); - - // Generates a sinf atom with CENC encryption parameters. - void GenerateSinf(ProtectionSchemeInfo* sinf, FourCC old_type); - - // Should we enable encrytion? - bool IsEncryptionRequired() { return (encryptor_source() != NULL); } - // Helper functions for events. void GetStreamInfo(std::vector* stream_infos); diff --git a/media/formats/mp4/multi_segment_segmenter.cc b/media/formats/mp4/multi_segment_segmenter.cc index 27c75c6b22..7547fa5a02 100644 --- a/media/formats/mp4/multi_segment_segmenter.cc +++ b/media/formats/mp4/multi_segment_segmenter.cc @@ -30,34 +30,6 @@ MultiSegmentSegmenter::MultiSegmentSegmenter(const MuxerOptions& options, MultiSegmentSegmenter::~MultiSegmentSegmenter() {} -Status MultiSegmentSegmenter::Initialize( - EncryptorSource* encryptor_source, - double clear_lead_in_seconds, - const std::vector& streams) { - Status status = - Segmenter::Initialize(encryptor_source, clear_lead_in_seconds, streams); - if (!status.ok()) - return status; - - DCHECK(ftyp()); - DCHECK(moov()); - // Generate the output file with init segment. - File* file = File::Open(options().output_file_name.c_str(), "w"); - if (file == NULL) { - return Status(error::FILE_FAILURE, - "Cannot open file for write " + options().output_file_name); - } - scoped_ptr buffer(new BufferWriter); - ftyp()->Write(buffer.get()); - moov()->Write(buffer.get()); - status = buffer->WriteToFile(file); - if (!file->Close()) { - LOG(WARNING) << "Failed to close the file properly: " - << options().output_file_name; - } - return status; -} - bool MultiSegmentSegmenter::GetInitRange(size_t* offset, size_t* size) { DLOG(INFO) << "MultiSegmentSegmenter outputs init segment: " << options().output_file_name; @@ -69,11 +41,31 @@ bool MultiSegmentSegmenter::GetIndexRange(size_t* offset, size_t* size) { return false; } -Status MultiSegmentSegmenter::FinalizeSegment() { - Status status = Segmenter::FinalizeSegment(); - if (!status.ok()) - return status; +Status MultiSegmentSegmenter::DoInitialize() { + DCHECK(ftyp()); + DCHECK(moov()); + // Generate the output file with init segment. + File* file = File::Open(options().output_file_name.c_str(), "w"); + if (file == NULL) { + return Status(error::FILE_FAILURE, + "Cannot open file for write " + options().output_file_name); + } + scoped_ptr buffer(new BufferWriter); + ftyp()->Write(buffer.get()); + moov()->Write(buffer.get()); + Status status = buffer->WriteToFile(file); + if (!file->Close()) { + LOG(WARNING) << "Failed to close the file properly: " + << options().output_file_name; + } + return status; +} +Status MultiSegmentSegmenter::DoFinalize() { + return Status::OK; +} + +Status MultiSegmentSegmenter::DoFinalizeSegment() { DCHECK(sidx()); // earliest_presentation_time is the earliest presentation time of any // access unit in the reference stream in the first subsegment. diff --git a/media/formats/mp4/multi_segment_segmenter.h b/media/formats/mp4/multi_segment_segmenter.h index 36fd4a994a..adb581a435 100644 --- a/media/formats/mp4/multi_segment_segmenter.h +++ b/media/formats/mp4/multi_segment_segmenter.h @@ -36,18 +36,16 @@ class MultiSegmentSegmenter : public Segmenter { /// @name Segmenter implementation overrides. /// @{ - virtual Status Initialize(EncryptorSource* encryptor_source, - double clear_lead_in_seconds, - const std::vector& streams) OVERRIDE; - virtual bool GetInitRange(size_t* offset, size_t* size) OVERRIDE; virtual bool GetIndexRange(size_t* offset, size_t* size) OVERRIDE; /// @} - protected: - virtual Status FinalizeSegment() OVERRIDE; - private: + // Segmenter implementation overrides. + virtual Status DoInitialize() OVERRIDE; + virtual Status DoFinalize() OVERRIDE; + virtual Status DoFinalizeSegment() OVERRIDE; + // Write segment to file. Status WriteSegment(); diff --git a/media/formats/mp4/segmenter.cc b/media/formats/mp4/segmenter.cc index ae56efdbf8..63a648568f 100644 --- a/media/formats/mp4/segmenter.cc +++ b/media/formats/mp4/segmenter.cc @@ -9,6 +9,7 @@ #include #include "base/stl_util.h" +#include "media/base/aes_encryptor.h" #include "media/base/buffer_writer.h" #include "media/base/encryptor_source.h" #include "media/base/media_sample.h" @@ -18,14 +19,79 @@ #include "media/formats/mp4/box_definitions.h" #include "media/formats/mp4/fragmenter.h" +namespace media { +namespace mp4 { + namespace { + +// Generate 64bit IV by default. +const size_t kDefaultIvSize = 8u; + +// The version of cenc implemented here. CENC 4. +const int kCencSchemeVersion = 0x00010000; + uint64 Rescale(uint64 time_in_old_scale, uint32 old_scale, uint32 new_scale) { return static_cast(time_in_old_scale) / old_scale * new_scale; } -} // namespace -namespace media { -namespace mp4 { +scoped_ptr CreateEncryptor( + const EncryptionKey& encryption_key) { + scoped_ptr encryptor(new AesCtrEncryptor()); + const bool initialized = + encryption_key.iv.empty() + ? encryptor->InitializeWithRandomIv(encryption_key.key, + kDefaultIvSize) + : encryptor->InitializeWithIv(encryption_key.key, encryption_key.iv); + if (!initialized) { + LOG(ERROR) << "Failed to the initialize encryptor."; + return scoped_ptr(); + } + return encryptor.Pass(); +} + +void GenerateSinf(const EncryptionKey& encryption_key, + FourCC old_type, + ProtectionSchemeInfo* sinf) { + sinf->format.format = old_type; + sinf->type.type = FOURCC_CENC; + sinf->type.version = kCencSchemeVersion; + sinf->info.track_encryption.is_encrypted = true; + sinf->info.track_encryption.default_iv_size = + encryption_key.iv.empty() ? kDefaultIvSize : encryption_key.iv.size(); + sinf->info.track_encryption.default_kid = encryption_key.key_id; +} + +void GenerateEncryptedSampleEntry(const EncryptionKey& encryption_key, + double clear_lead_in_seconds, + SampleDescription* description) { + DCHECK(description); + if (description->type == kVideo) { + DCHECK_EQ(1u, description->video_entries.size()); + + // Add a second entry for clear content if needed. + if (clear_lead_in_seconds > 0) + description->video_entries.push_back(description->video_entries[0]); + + // Convert the first entry to an encrypted entry. + VideoSampleEntry& entry = description->video_entries[0]; + GenerateSinf(encryption_key, entry.format, &entry.sinf); + entry.format = FOURCC_ENCV; + } else { + DCHECK_EQ(kAudio, description->type); + DCHECK_EQ(1u, description->audio_entries.size()); + + // Add a second entry for clear content if needed. + if (clear_lead_in_seconds > 0) + description->audio_entries.push_back(description->audio_entries[0]); + + // Convert the first entry to an encrypted entry. + AudioSampleEntry& entry = description->audio_entries[0]; + GenerateSinf(encryption_key, entry.format, &entry.sinf); + entry.format = FOURCC_ENCA; + } +} + +} // namespace Segmenter::Segmenter(const MuxerOptions& options, scoped_ptr ftyp, @@ -41,9 +107,10 @@ Segmenter::Segmenter(const MuxerOptions& options, Segmenter::~Segmenter() { STLDeleteElements(&fragmenters_); } -Status Segmenter::Initialize(EncryptorSource* encryptor_source, - double clear_lead_in_seconds, - const std::vector& streams) { +Status Segmenter::Initialize(const std::vector& streams, + EncryptorSource* encryptor_source, + EncryptorSource::TrackType track_type, + double clear_lead_in_seconds) { DCHECK_LT(0u, streams.size()); moof_->header.sequence_number = 0; @@ -64,7 +131,30 @@ Status Segmenter::Initialize(EncryptorSource* encryptor_source, } scoped_ptr encryptor; if (encryptor_source) { - encryptor = encryptor_source->CreateEncryptor(); + SampleDescription& description = + moov_->tracks[i].media.information.sample_table.description; + + DCHECK(track_type == EncryptorSource::TRACK_TYPE_SD || + track_type == EncryptorSource::TRACK_TYPE_HD); + + EncryptionKey encryption_key; + Status status = encryptor_source->GetKey( + description.type == kAudio ? EncryptorSource::TRACK_TYPE_AUDIO + : track_type, + &encryption_key); + if (!status.ok()) + return status; + + GenerateEncryptedSampleEntry( + encryption_key, clear_lead_in_seconds, &description); + + // We need one and only one pssh box. + if (moov_->pssh.empty()) { + moov_->pssh.resize(1); + moov_->pssh[0].raw_box = encryption_key.pssh; + } + + encryptor = CreateEncryptor(encryption_key); if (!encryptor) return Status(error::MUXER_FAILURE, "Failed to create the encryptor."); } @@ -84,7 +174,7 @@ Status Segmenter::Initialize(EncryptorSource* encryptor_source, // Use the reference stream's time scale as movie time scale. moov_->header.timescale = sidx_->timescale; InitializeFragments(); - return Status::OK; + return DoInitialize(); } Status Segmenter::Finalize() { @@ -110,7 +200,7 @@ Status Segmenter::Finalize() { moov_->header.duration = track->header.duration; } - return Status::OK; + return DoFinalize(); } Status Segmenter::AddSample(const MediaStream* stream, @@ -191,7 +281,7 @@ void Segmenter::InitializeSegment() { Status Segmenter::FinalizeSegment() { segment_initialized_ = false; - return Status::OK; + return DoFinalizeSegment(); } uint32 Segmenter::GetReferenceStreamId() { diff --git a/media/formats/mp4/segmenter.h b/media/formats/mp4/segmenter.h index db4625e749..ffd1ac9341 100644 --- a/media/formats/mp4/segmenter.h +++ b/media/formats/mp4/segmenter.h @@ -12,6 +12,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "media/base/encryptor_source.h" #include "media/base/status.h" namespace media { @@ -47,17 +48,30 @@ class Segmenter { /// Initialize the segmenter. /// Calling other public methods of this class without this method returning - /// Status::OK, results in an undefined behavior. - /// @param encryptor_source can be NULL. - /// @return Status::OK on success. - virtual Status Initialize(EncryptorSource* encryptor_source, - double clear_lead_in_seconds, - const std::vector& streams); + /// Status::OK results in an undefined behavior. + /// @param encryptor_source points to the key source which contains + /// the encryption keys. It can be NULL to indicate that no encryption + /// is required. + /// @param track_type indicates whether SD key or HD key should be used to + /// encrypt the video content. + /// @param clear_time specifies clear lead duration in seconds. + /// @return OK on success, an error status otherwise. + Status Initialize(const std::vector& streams, + EncryptorSource* encryptor_source, + EncryptorSource::TrackType track_type, + double clear_lead_in_seconds); - virtual Status Finalize(); + /// Finalize the segmenter. + /// @return OK on success, an error status otherwise. + Status Finalize(); - virtual Status AddSample(const MediaStream* stream, - scoped_refptr sample); + /// Add sample to the indicated stream. + /// @param stream points to the stream to which the sample belongs. It cannot + /// be NULL. + /// @param sample points to the sample to be added. + /// @return OK on success, an error status otherwise. + Status AddSample(const MediaStream* stream, + scoped_refptr sample); /// @return true if there is an initialization range, while setting @a offset /// and @a size; or false if initialization range does not apply. @@ -73,11 +87,6 @@ class Segmenter { double GetDuration() const; protected: - void InitializeSegment(); - virtual Status FinalizeSegment(); - - uint32 GetReferenceStreamId(); - const MuxerOptions& options() const { return options_; } FileType* ftyp() { return ftyp_.get(); } Movie* moov() { return moov_.get(); } @@ -85,6 +94,14 @@ class Segmenter { SegmentIndex* sidx() { return sidx_.get(); } private: + virtual Status DoInitialize() = 0; + virtual Status DoFinalize() = 0; + virtual Status DoFinalizeSegment() = 0; + + void InitializeSegment(); + Status FinalizeSegment(); + uint32 GetReferenceStreamId(); + void InitializeFragments(); Status FinalizeFragment(Fragmenter* fragment); diff --git a/media/formats/mp4/single_segment_segmenter.cc b/media/formats/mp4/single_segment_segmenter.cc index 5480fc76b9..816775c2a0 100644 --- a/media/formats/mp4/single_segment_segmenter.cc +++ b/media/formats/mp4/single_segment_segmenter.cc @@ -21,27 +21,30 @@ SingleSegmentSegmenter::SingleSegmentSegmenter(const MuxerOptions& options, : Segmenter(options, ftyp.Pass(), moov.Pass()) {} SingleSegmentSegmenter::~SingleSegmentSegmenter() {} -Status SingleSegmentSegmenter::Initialize( - EncryptorSource* encryptor_source, - double clear_lead_in_seconds, - const std::vector& streams) { - Status status = - Segmenter::Initialize(encryptor_source, clear_lead_in_seconds, streams); - if (!status.ok()) - return status; - temp_file_.reset(File::Open(options().temp_file_name.c_str(), "w")); - if (temp_file_ == NULL) { - return Status(error::FILE_FAILURE, - "Cannot open file to write " + options().temp_file_name); - } - return Status::OK; +bool SingleSegmentSegmenter::GetInitRange(size_t* offset, size_t* size) { + // In Finalize, ftyp and moov gets written first so offset must be 0. + *offset = 0; + *size = ftyp()->ComputeSize() + moov()->ComputeSize(); + return true; } -Status SingleSegmentSegmenter::Finalize() { - Status status = Segmenter::Finalize(); - if (!status.ok()) - return status; +bool SingleSegmentSegmenter::GetIndexRange(size_t* offset, size_t* size) { + // Index range is right after init range so the offset must be the size of + // ftyp and moov. + *offset = ftyp()->ComputeSize() + moov()->ComputeSize(); + *size = vod_sidx_->ComputeSize(); + return true; +} +Status SingleSegmentSegmenter::DoInitialize() { + temp_file_.reset(File::Open(options().temp_file_name.c_str(), "w")); + return temp_file_ + ? Status::OK + : Status(error::FILE_FAILURE, + "Cannot open file to write " + options().temp_file_name); +} + +Status SingleSegmentSegmenter::DoFinalize() { DCHECK(temp_file_); DCHECK(ftyp()); DCHECK(moov()); @@ -65,7 +68,7 @@ Status SingleSegmentSegmenter::Finalize() { ftyp()->Write(buffer.get()); moov()->Write(buffer.get()); vod_sidx_->Write(buffer.get()); - status = buffer->WriteToFile(file.get()); + Status status = buffer->WriteToFile(file.get()); if (!status.ok()) return status; @@ -94,26 +97,7 @@ Status SingleSegmentSegmenter::Finalize() { return Status::OK; } -bool SingleSegmentSegmenter::GetInitRange(size_t* offset, size_t* size) { - // In Finalize, ftyp and moov gets written first so offset must be 0. - *offset = 0; - *size = ftyp()->ComputeSize() + moov()->ComputeSize(); - return true; -} - -bool SingleSegmentSegmenter::GetIndexRange(size_t* offset, size_t* size) { - // Index range is right after init range so the offset must be the size of - // ftyp and moov. - *offset = ftyp()->ComputeSize() + moov()->ComputeSize(); - *size = vod_sidx_->ComputeSize(); - return true; -} - -Status SingleSegmentSegmenter::FinalizeSegment() { - Status status = Segmenter::FinalizeSegment(); - if (!status.ok()) - return status; - +Status SingleSegmentSegmenter::DoFinalizeSegment() { DCHECK(sidx()); DCHECK(fragment_buffer()); // sidx() contains pre-generated segment references with one reference per diff --git a/media/formats/mp4/single_segment_segmenter.h b/media/formats/mp4/single_segment_segmenter.h index 51153f2399..2c7f655c4b 100644 --- a/media/formats/mp4/single_segment_segmenter.h +++ b/media/formats/mp4/single_segment_segmenter.h @@ -33,19 +33,16 @@ class SingleSegmentSegmenter : public Segmenter { /// @name Segmenter implementation overrides. /// @{ - virtual Status Initialize(EncryptorSource* encryptor_source, - double clear_lead_in_seconds, - const std::vector& streams) OVERRIDE; - virtual Status Finalize() OVERRIDE; - virtual bool GetInitRange(size_t* offset, size_t* size) OVERRIDE; virtual bool GetIndexRange(size_t* offset, size_t* size) OVERRIDE; /// @} - protected: - virtual Status FinalizeSegment() OVERRIDE; - private: + // Segmenter implementation overrides. + virtual Status DoInitialize() OVERRIDE; + virtual Status DoFinalize() OVERRIDE; + virtual Status DoFinalizeSegment() OVERRIDE; + scoped_ptr vod_sidx_; scoped_ptr temp_file_; diff --git a/media/test/packager_test.cc b/media/test/packager_test.cc index 3859c9419a..dc5bf9daa7 100644 --- a/media/test/packager_test.cc +++ b/media/test/packager_test.cc @@ -9,7 +9,7 @@ #include "base/strings/stringprintf.h" #include "base/time/clock.h" #include "media/base/demuxer.h" -#include "media/base/fixed_encryptor_source.h" +#include "media/base/encryptor_source.h" #include "media/base/media_stream.h" #include "media/base/muxer.h" #include "media/base/status_test_util.h" @@ -148,8 +148,9 @@ void PackagerTestBasic::Remux(const std::string& input, Demuxer demuxer(GetFullPath(input), decryptor_source_); ASSERT_OK(demuxer.Initialize()); - FixedEncryptorSource encryptor_source(kKeyIdHex, kKeyHex, kPsshHex); - ASSERT_OK(encryptor_source.Initialize()); + scoped_ptr encryptor_source( + EncryptorSource::CreateFromHexStrings(kKeyIdHex, kKeyHex, kPsshHex, "")); + DCHECK(encryptor_source); scoped_ptr muxer_video; if (!video_output.empty()) { @@ -159,8 +160,11 @@ void PackagerTestBasic::Remux(const std::string& input, muxer_video->AddStream(FindFirstVideoStream(demuxer.streams())); - if (enable_encryption) - muxer_video->SetEncryptorSource(&encryptor_source, kClearLeadInSeconds); + if (enable_encryption) { + muxer_video->SetEncryptorSource(encryptor_source.get(), + EncryptorSource::TRACK_TYPE_SD, + kClearLeadInSeconds); + } } scoped_ptr muxer_audio; @@ -171,8 +175,11 @@ void PackagerTestBasic::Remux(const std::string& input, muxer_audio->AddStream(FindFirstAudioStream(demuxer.streams())); - if (enable_encryption) - muxer_video->SetEncryptorSource(&encryptor_source, kClearLeadInSeconds); + if (enable_encryption) { + muxer_audio->SetEncryptorSource(encryptor_source.get(), + EncryptorSource::TRACK_TYPE_SD, + kClearLeadInSeconds); + } } // Start remuxing process.