diff --git a/media/base/muxer.cc b/media/base/muxer.cc index ca069f7d5b..86466c1ddf 100644 --- a/media/base/muxer.cc +++ b/media/base/muxer.cc @@ -10,11 +10,17 @@ namespace media { -Muxer::Muxer(const MuxerOptions& options, EncryptorSource* encrytor_source) - : options_(options), encryptor_source_(encrytor_source) {} +Muxer::Muxer(const MuxerOptions& options) + : options_(options), encryptor_source_(NULL), clear_lead_in_seconds_(0) {} Muxer::~Muxer() {} +void Muxer::SetEncryptorSource(EncryptorSource* encryptor_source, + double clear_lead_in_seconds) { + encryptor_source_ = encryptor_source; + clear_lead_in_seconds_ = clear_lead_in_seconds; +} + Status Muxer::AddStream(MediaStream* stream) { stream->Connect(this); streams_.push_back(stream); diff --git a/media/base/muxer.h b/media/base/muxer.h index 704686af38..a73905f75c 100644 --- a/media/base/muxer.h +++ b/media/base/muxer.h @@ -22,9 +22,14 @@ class MediaStream; class Muxer { public: - Muxer(const MuxerOptions& options, EncryptorSource* encryptor_source); + explicit Muxer(const MuxerOptions& options); virtual ~Muxer(); + // Set encryptor source. Caller retains ownership of |encryptor_source|. + // Should be called before calling Initialize(). + void SetEncryptorSource(EncryptorSource* encryptor_source, + double clear_lead_in_seconds); + // Initialize the muxer. Must be called after connecting all the streams. virtual Status Initialize() = 0; @@ -46,11 +51,13 @@ class Muxer { protected: const MuxerOptions& options() const { return options_; } EncryptorSource* encryptor_source() { return encryptor_source_; } + double clear_lead_in_seconds() const { return clear_lead_in_seconds_; } private: MuxerOptions options_; std::vector streams_; - EncryptorSource* const encryptor_source_; + EncryptorSource* encryptor_source_; + double clear_lead_in_seconds_; DISALLOW_COPY_AND_ASSIGN(Muxer); }; diff --git a/media/mp4/mp4_fragmenter.cc b/media/mp4/mp4_fragmenter.cc index 0941e07bbf..283162663a 100644 --- a/media/mp4/mp4_fragmenter.cc +++ b/media/mp4/mp4_fragmenter.cc @@ -7,7 +7,6 @@ #include "media/base/aes_encryptor.h" #include "media/base/buffer_reader.h" #include "media/base/buffer_writer.h" -#include "media/base/encryptor_source.h" #include "media/base/media_sample.h" #include "media/mp4/box_definitions.h" #include "media/mp4/cenc.h" @@ -40,10 +39,10 @@ namespace media { namespace mp4 { MP4Fragmenter::MP4Fragmenter(TrackFragment* traf, - EncryptorSource* encryptor_source, + scoped_ptr encryptor, int64 clear_time, uint8 nalu_length_size) - : encryptor_source_(encryptor_source), + : encryptor_(encryptor.Pass()), nalu_length_size_(nalu_length_size), traf_(traf), fragment_finalized_(false), @@ -106,16 +105,15 @@ void MP4Fragmenter::InitializeFragment() { if (ShouldEncryptFragment()) { if (!IsSubsampleEncryptionRequired()) { - DCHECK(encryptor_source_ != NULL); - traf_->auxiliary_size.default_sample_info_size = - encryptor_source_->encryptor()->iv().size(); + DCHECK(encryptor_); + traf_->auxiliary_size.default_sample_info_size = encryptor_->iv().size(); } } } void MP4Fragmenter::FinalizeFragment() { if (ShouldEncryptFragment()) { - DCHECK(encryptor_source_ != NULL); + DCHECK(encryptor_); // The offset will be adjusted in Segmenter when we know moof size. traf_->auxiliary_offset.offsets.push_back(0); @@ -129,7 +127,7 @@ void MP4Fragmenter::FinalizeFragment() { saiz.default_sample_info_size = 0; } } - } else if (encryptor_source_ && clear_time_ > 0) { + } else if (encryptor_ && clear_time_ > 0) { // This fragment should be in clear. // We generate at most two sample description entries, encrypted entry and // clear entry. The 1-based clear entry index is always 2. @@ -182,13 +180,14 @@ void MP4Fragmenter::GenerateSegmentReference(SegmentReference* reference) { } void MP4Fragmenter::EncryptBytes(uint8* data, uint32 size) { - CHECK(encryptor_source_->encryptor()->Encrypt(data, size, data)); + DCHECK(encryptor_); + CHECK(encryptor_->Encrypt(data, size, data)); } Status MP4Fragmenter::EncryptSample(scoped_refptr sample) { - DCHECK(encryptor_source_ != NULL && encryptor_source_->encryptor() != NULL); + DCHECK(encryptor_); - FrameCENCInfo cenc_info(encryptor_source_->encryptor()->iv()); + FrameCENCInfo cenc_info(encryptor_->iv()); uint8* data = sample->writable_data(); if (!IsSubsampleEncryptionRequired()) { EncryptBytes(data, sample->data_size()); @@ -217,7 +216,7 @@ Status MP4Fragmenter::EncryptSample(scoped_refptr sample) { } cenc_info.Write(aux_data_.get()); - encryptor_source_->encryptor()->UpdateIv(); + encryptor_->UpdateIv(); return Status::OK; } diff --git a/media/mp4/mp4_fragmenter.h b/media/mp4/mp4_fragmenter.h index 725beff573..b0039375fb 100644 --- a/media/mp4/mp4_fragmenter.h +++ b/media/mp4/mp4_fragmenter.h @@ -17,8 +17,8 @@ namespace media { +class AesCtrEncryptor; class BufferWriter; -class EncryptorSource; class MediaSample; namespace mp4 { @@ -28,12 +28,12 @@ class TrackFragment; class MP4Fragmenter { public: - // Caller retains the ownership of |traf| and |encryptor_source|. - // |clear_time| specifies clear time in the current track timescale. - // |nalu_length_size| specifies NAL unit length size, for subsample - // encryption. + // Caller retains the ownership of |traf| and transfers ownership of + // |encryptor|. |clear_time| specifies clear time in the current track + // timescale. |nalu_length_size| specifies NAL unit length size, for + // subsample encryption. MP4Fragmenter(TrackFragment* traf, - EncryptorSource* encryptor_source, + scoped_ptr encryptor, int64 clear_time, uint8 nalu_length_size); ~MP4Fragmenter(); @@ -64,7 +64,7 @@ class MP4Fragmenter { // Should we enable encrytion for the current fragment? bool ShouldEncryptFragment() { - return (encryptor_source_ != NULL && clear_time_ <= 0); + return (encryptor_ != NULL && clear_time_ <= 0); } // Should we enable subsample encryption? @@ -73,7 +73,7 @@ class MP4Fragmenter { // Check if the current fragment starts with SAP. bool StartsWithSAP(); - EncryptorSource* encryptor_source_; + scoped_ptr encryptor_; // If this stream contains AVC, subsample encryption specifies that the size // and type of NAL units remain unencrypted. This field specifies the size of // the size field. Can be 1, 2 or 4 bytes. diff --git a/media/mp4/mp4_general_segmenter.cc b/media/mp4/mp4_general_segmenter.cc index e9dfccc921..b0cf40a369 100644 --- a/media/mp4/mp4_general_segmenter.cc +++ b/media/mp4/mp4_general_segmenter.cc @@ -30,8 +30,10 @@ MP4GeneralSegmenter::~MP4GeneralSegmenter() {} Status MP4GeneralSegmenter::Initialize( EncryptorSource* encryptor_source, + double clear_lead_in_seconds, const std::vector& streams) { - Status status = MP4Segmenter::Initialize(encryptor_source, streams); + Status status = MP4Segmenter::Initialize( + encryptor_source, clear_lead_in_seconds, streams); if (!status.ok()) return status; diff --git a/media/mp4/mp4_general_segmenter.h b/media/mp4/mp4_general_segmenter.h index ce237ab609..35753bb36e 100644 --- a/media/mp4/mp4_general_segmenter.h +++ b/media/mp4/mp4_general_segmenter.h @@ -36,6 +36,7 @@ class MP4GeneralSegmenter : public MP4Segmenter { // MP4Segmenter implementations. virtual Status Initialize(EncryptorSource* encryptor_source, + double clear_lead_in_seconds, const std::vector& streams) OVERRIDE; protected: diff --git a/media/mp4/mp4_muxer.cc b/media/mp4/mp4_muxer.cc index 310862aebe..f7c762cafd 100644 --- a/media/mp4/mp4_muxer.cc +++ b/media/mp4/mp4_muxer.cc @@ -33,9 +33,7 @@ uint64 IsoTimeNow() { namespace media { namespace mp4 { -MP4Muxer::MP4Muxer(const MuxerOptions& options, - EncryptorSource* encryptor_source) - : Muxer(options, encryptor_source) {} +MP4Muxer::MP4Muxer(const MuxerOptions& options) : Muxer(options) {} MP4Muxer::~MP4Muxer() {} Status MP4Muxer::Initialize() { @@ -98,7 +96,8 @@ Status MP4Muxer::Initialize() { segmenter_.reset( new MP4GeneralSegmenter(options(), ftyp.Pass(), moov.Pass())); } - return segmenter_->Initialize(encryptor_source(), streams()); + return segmenter_->Initialize( + encryptor_source(), clear_lead_in_seconds(), streams()); } Status MP4Muxer::Finalize() { @@ -152,7 +151,7 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info, if (IsEncryptionRequired()) { DCHECK(encryptor_source() != NULL); // Add a second entry for clear content if needed. - if (encryptor_source()->clear_milliseconds() > 0) + if (clear_lead_in_seconds() > 0) sample_description.video_entries.push_back(video); VideoSampleEntry& encrypted_video = sample_description.video_entries[0]; @@ -192,7 +191,7 @@ void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info, if (IsEncryptionRequired()) { DCHECK(encryptor_source() != NULL); // Add a second entry for clear content if needed. - if (encryptor_source()->clear_milliseconds() > 0) + if (clear_lead_in_seconds() > 0) sample_description.audio_entries.push_back(audio); AudioSampleEntry& encrypted_audio = sample_description.audio_entries[0]; @@ -209,13 +208,11 @@ void MP4Muxer::GeneratePssh(ProtectionSystemSpecificHeader* pssh) { void MP4Muxer::GenerateSinf(ProtectionSchemeInfo* sinf, FourCC old_type) { DCHECK(encryptor_source() != NULL); - DCHECK(encryptor_source()->encryptor() != NULL); 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()->encryptor()->iv().size(); + sinf->info.track_encryption.default_iv_size = encryptor_source()->iv_size(); sinf->info.track_encryption.default_kid = encryptor_source()->key_id(); } diff --git a/media/mp4/mp4_muxer.h b/media/mp4/mp4_muxer.h index 94440c3391..044ce81068 100644 --- a/media/mp4/mp4_muxer.h +++ b/media/mp4/mp4_muxer.h @@ -26,7 +26,7 @@ struct Track; class MP4Muxer : public Muxer { public: - MP4Muxer(const MuxerOptions& options, EncryptorSource* encryptor_source); + explicit MP4Muxer(const MuxerOptions& options); virtual ~MP4Muxer(); // Muxer implementations. diff --git a/media/mp4/mp4_segmenter.cc b/media/mp4/mp4_segmenter.cc index 0b91208ee4..a4a0b055e8 100644 --- a/media/mp4/mp4_segmenter.cc +++ b/media/mp4/mp4_segmenter.cc @@ -40,6 +40,7 @@ MP4Segmenter::MP4Segmenter(const MuxerOptions& options, MP4Segmenter::~MP4Segmenter() { STLDeleteElements(&fragmenters_); } Status MP4Segmenter::Initialize(EncryptorSource* encryptor_source, + double clear_lead_in_seconds, const std::vector& streams) { DCHECK_LT(0, streams.size()); moof_->header.sequence_number = 0; @@ -59,13 +60,17 @@ Status MP4Segmenter::Initialize(EncryptorSource* encryptor_source, if (sidx_->reference_id == 0) sidx_->reference_id = i + 1; } - int64 clear_time = 0; + scoped_ptr encryptor; if (encryptor_source) { - clear_time = encryptor_source->clear_milliseconds() / 1000.0 * - streams[i]->info()->time_scale(); + encryptor = encryptor_source->CreateEncryptor(); + if (!encryptor) + return Status(error::MUXER_FAILURE, "Failed to create the encryptor."); } fragmenters_[i] = new MP4Fragmenter( - &moof_->tracks[i], encryptor_source, clear_time, nalu_length_size); + &moof_->tracks[i], + encryptor.Pass(), + clear_lead_in_seconds * streams[i]->info()->time_scale(), + nalu_length_size); } // Choose the first stream if there is no VIDEO. diff --git a/media/mp4/mp4_segmenter.h b/media/mp4/mp4_segmenter.h index 0c77acbf3f..23036434ad 100644 --- a/media/mp4/mp4_segmenter.h +++ b/media/mp4/mp4_segmenter.h @@ -48,6 +48,7 @@ class MP4Segmenter { // Initialize the segmenter. Caller retains the ownership of // |encryptor_source|. |encryptor_source| can be NULL. virtual Status Initialize(EncryptorSource* encryptor_source, + double clear_lead_in_seconds, const std::vector& streams); virtual Status Finalize(); diff --git a/media/mp4/mp4_vod_segmenter.cc b/media/mp4/mp4_vod_segmenter.cc index 7e4f9af2fc..2bc8e2f2dd 100644 --- a/media/mp4/mp4_vod_segmenter.cc +++ b/media/mp4/mp4_vod_segmenter.cc @@ -20,8 +20,10 @@ MP4VODSegmenter::MP4VODSegmenter(const MuxerOptions& options, MP4VODSegmenter::~MP4VODSegmenter() {} Status MP4VODSegmenter::Initialize(EncryptorSource* encryptor_source, + double clear_lead_in_seconds, const std::vector& streams) { - Status status = MP4Segmenter::Initialize(encryptor_source, streams); + Status status = MP4Segmenter::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")); diff --git a/media/mp4/mp4_vod_segmenter.h b/media/mp4/mp4_vod_segmenter.h index 0ec7936bb1..cb3b6ea05d 100644 --- a/media/mp4/mp4_vod_segmenter.h +++ b/media/mp4/mp4_vod_segmenter.h @@ -33,6 +33,7 @@ class MP4VODSegmenter : public MP4Segmenter { // MP4Segmenter implementations. virtual Status Initialize(EncryptorSource* encryptor_source, + double clear_lead_in_seconds, const std::vector& streams) OVERRIDE; virtual Status Finalize() OVERRIDE; diff --git a/media/test/packager_test.cc b/media/test/packager_test.cc index da7ad896f5..3d3c007fc8 100644 --- a/media/test/packager_test.cc +++ b/media/test/packager_test.cc @@ -2,26 +2,35 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/file_util.h" #include "base/strings/string_number_conversions.h" #include "media/base/demuxer.h" #include "media/base/fixed_encryptor_source.h" -#include "media/base/media_sample.h" #include "media/base/media_stream.h" #include "media/base/muxer.h" -#include "media/base/muxer_options.h" #include "media/base/status_test_util.h" #include "media/base/stream_info.h" #include "media/mp4/mp4_muxer.h" #include "media/test/test_data_util.h" #include "testing/gtest/include/gtest/gtest.h" -using ::testing::Combine; -using ::testing::Values; using ::testing::ValuesIn; namespace { const char* kMediaFiles[] = {"bear-1280x720.mp4", "bear-1280x720-av_frag.mp4"}; +// Muxer options. +const double kSegmentDurationInSeconds = 1.0; +const double kFragmentDurationInSecodns = 0.1; +const bool kSegmentSapAligned = true; +const bool kFragmentSapAligned = true; +const int kNumSubsegmentsPerSidx = 2; +const char kOutputFileName[] = "output_file"; +const char kOutputFileName2[] = "output_file2"; +const char kSegmentTemplate[] = "template$Number$.m4s"; +const char kSegmentTemplateOutputFile[] = "template1.m4s"; +const char kTempFileName[] = "temp_file"; + // Encryption constants. const char kKeyIdHex[] = "e5007e6e9dcd5ac095202ed3758382cd"; const char kKeyHex[] = "6fc96fe628a265b13aeddec0bc421f4d"; @@ -29,112 +38,108 @@ const char kPsshHex[] = "08011210e5007e6e9dcd5ac095202ed3" "758382cd1a0d7769646576696e655f746573742211544553545f" "434f4e54454e545f49445f312a025344"; -const uint32 kClearMilliseconds = 1500; +const double kClearLeadInSeconds = 1.5; } // namespace namespace media { -class TestingMuxer : public Muxer { +class PackagerTest : public ::testing::TestWithParam { public: - TestingMuxer(const MuxerOptions& options, EncryptorSource* encryptor_source) - : Muxer(options, encryptor_source) {} + virtual void SetUp() OVERRIDE { + // Create a test directory for testing, will be deleted after test. + ASSERT_TRUE( + file_util::CreateNewTempDirectory("packager_", &test_directory_)); - virtual Status Initialize() OVERRIDE { - DVLOG(1) << "Initialize is called."; - return Status::OK; + options_.segment_duration = kSegmentDurationInSeconds; + options_.fragment_duration = kFragmentDurationInSecodns; + options_.segment_sap_aligned = kSegmentSapAligned; + options_.fragment_sap_aligned = kFragmentSapAligned; + options_.num_subsegments_per_sidx = kNumSubsegmentsPerSidx; + + options_.output_file_name = + test_directory_.AppendASCII(kOutputFileName).value(); + options_.segment_template = + test_directory_.AppendASCII(kSegmentTemplate).value(); + options_.temp_file_name = + test_directory_.AppendASCII(kTempFileName).value(); } - virtual Status AddSample(const MediaStream* stream, - scoped_refptr sample) OVERRIDE { - DVLOG(1) << "Add Sample: " << sample->ToString(); - DVLOG(2) << "To Stream: " << stream->ToString(); - return Status::OK; + virtual void TearDown() OVERRIDE { base::DeleteFile(test_directory_, true); } + + void Remux(const std::string& input_file, Muxer* muxer) { + DCHECK(muxer); + + Demuxer demuxer(input_file, NULL); + ASSERT_OK(demuxer.Initialize()); + ASSERT_LE(1, demuxer.streams().size()); + + VLOG(1) << "Num Streams: " << demuxer.streams().size(); + for (size_t i = 0; i < demuxer.streams().size(); ++i) { + VLOG(1) << "Streams " << i << ": " << demuxer.streams()[i]->ToString(); + } + + ASSERT_OK(muxer->AddStream(demuxer.streams()[0])); + ASSERT_OK(muxer->Initialize()); + + // Starts remuxing process. + ASSERT_OK(demuxer.Run()); + ASSERT_OK(muxer->Finalize()); } - virtual Status Finalize() OVERRIDE { - DVLOG(1) << "Finalize is called."; - return Status::OK; - } - - private: - DISALLOW_COPY_AND_ASSIGN(TestingMuxer); + protected: + base::FilePath test_directory_; + MuxerOptions options_; }; -typedef Muxer* CreateMuxerFunc(const std::string& input_file_name, - EncryptorSource* encryptor_source); +TEST_P(PackagerTest, MP4MuxerSingleSegmentUnencrypted) { + options_.single_segment = true; -Muxer* CreateTestingMuxer(const std::string& input_file_name, - EncryptorSource* encryptor_source) { - MuxerOptions options; - return new TestingMuxer(options, NULL); + const std::string input_media_file = GetTestDataFilePath(GetParam()).value(); + scoped_ptr muxer(new mp4::MP4Muxer(options_)); + ASSERT_NO_FATAL_FAILURE(Remux(input_media_file, muxer.get())); + + // Take the muxer output and feed into muxer again. The new muxer output + // should contain the same contents as the previous muxer output. + const std::string new_input_media_file = options_.output_file_name; + options_.output_file_name = + test_directory_.AppendASCII(kOutputFileName2).value(); + muxer.reset(new mp4::MP4Muxer(options_)); + ASSERT_NO_FATAL_FAILURE(Remux(new_input_media_file, muxer.get())); + + EXPECT_TRUE(base::ContentsEqual(base::FilePath(new_input_media_file), + base::FilePath(options_.output_file_name))); } -Muxer* CreateNormalMP4Muxer(const std::string& input_file_name, - EncryptorSource* encryptor_source) { - MuxerOptions options; - options.single_segment = true; - options.segment_duration = 0.005; - options.fragment_duration = 0.002; - options.segment_sap_aligned = true; - options.fragment_sap_aligned = true; - options.num_subsegments_per_sidx = 1; - options.output_file_name = "/tmp/clear_" + input_file_name; - options.segment_template = "/tmp/template$Number$.m4s"; - options.temp_file_name = "/tmp/tmp.mp4"; - return new mp4::MP4Muxer(options, NULL); -} +TEST_P(PackagerTest, MP4MuxerSingleSegmentEncrypted) { + options_.single_segment = true; -Muxer* CreateEncryptionMP4Muxer(const std::string& input_file_name, - EncryptorSource* encryptor_source) { - MuxerOptions options; - options.single_segment = true; - options.segment_duration = 0.005; - options.fragment_duration = 0.002; - options.segment_sap_aligned = true; - options.fragment_sap_aligned = true; - options.num_subsegments_per_sidx = 1; - options.output_file_name = "/tmp/enc_" + input_file_name; - options.segment_template = "/tmp/template$Number$.m4s"; - options.temp_file_name = "/tmp/tmp.mp4"; - return new mp4::MP4Muxer(options, encryptor_source); -} + FixedEncryptorSource encryptor_source(kKeyIdHex, kKeyHex, kPsshHex); + ASSERT_OK(encryptor_source.Initialize()); -class PackagerTest : public ::testing::TestWithParam< - ::std::tr1::tuple > {}; + const std::string input_media_file = GetTestDataFilePath(GetParam()).value(); + scoped_ptr muxer(new mp4::MP4Muxer(options_)); + muxer->SetEncryptorSource(&encryptor_source, kClearLeadInSeconds); + ASSERT_NO_FATAL_FAILURE(Remux(input_media_file, muxer.get())); -TEST_P(PackagerTest, Remux) { - std::string file_name = ::std::tr1::get<0>(GetParam()); - CreateMuxerFunc* CreateMuxer = ::std::tr1::get<1>(GetParam()); - - Demuxer demuxer(GetTestDataFilePath(file_name).value(), NULL); + // Expect the output to be encrypted. + Demuxer demuxer(options_.output_file_name, NULL); ASSERT_OK(demuxer.Initialize()); - - LOG(INFO) << "Num Streams: " << demuxer.streams().size(); - for (int i = 0; i < demuxer.streams().size(); ++i) { - LOG(INFO) << "Streams " << i << " " << demuxer.streams()[i]->ToString(); - } - - FixedEncryptorSource encryptor_source( - kKeyIdHex, kKeyHex, kPsshHex, kClearMilliseconds); - EXPECT_OK(encryptor_source.Initialize()); - - scoped_ptr muxer(CreateMuxer(file_name, &encryptor_source)); - - ASSERT_OK(muxer->AddStream(demuxer.streams()[0])); - ASSERT_OK(muxer->Initialize()); - - // Starts remuxing process. - ASSERT_OK(demuxer.Run()); - - ASSERT_OK(muxer->Finalize()); + ASSERT_EQ(1, demuxer.streams().size()); + EXPECT_TRUE(demuxer.streams()[0]->info()->is_encrypted()); } -INSTANTIATE_TEST_CASE_P(PackagerE2ETest, - PackagerTest, - Combine(ValuesIn(kMediaFiles), - Values(&CreateTestingMuxer, - &CreateNormalMP4Muxer, - &CreateEncryptionMP4Muxer))); +TEST_P(PackagerTest, MP4MuxerMultipleSegmentsUnencrypted) { + options_.single_segment = false; + + const std::string input_media_file = GetTestDataFilePath(GetParam()).value(); + scoped_ptr muxer(new mp4::MP4Muxer(options_)); + ASSERT_NO_FATAL_FAILURE(Remux(input_media_file, muxer.get())); + + EXPECT_TRUE(base::PathExists( + test_directory_.AppendASCII(kSegmentTemplateOutputFile))); +} + +INSTANTIATE_TEST_CASE_P(PackagerE2ETest, PackagerTest, ValuesIn(kMediaFiles)); } // namespace media