diff --git a/app/mpd_flags.cc b/app/mpd_flags.cc index 78ca76a715..f2693c0234 100644 --- a/app/mpd_flags.cc +++ b/app/mpd_flags.cc @@ -8,12 +8,15 @@ #include "app/mpd_flags.h" +// TODO(rkuroiwa, kqyang): Remove the 'Exclusive' statements once +// --output_media_info can work together with --mpd_output. DEFINE_bool(output_media_info, false, "Create a human readable format of MediaInfo. The output file name " "will be the name specified by output flag, suffixed with " - "'.media_info'."); -DEFINE_string(mpd_output, "", "MPD output file name."); + "'.media_info'. Exclusive with --mpd_output."); +DEFINE_string(mpd_output, "", + "MPD output file name. Exclusive with --output_media_info."); DEFINE_string(scheme_id_uri, "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", "This flag only applies if output_media_info is true. This value " diff --git a/app/packager_main.cc b/app/packager_main.cc index 283dcaecd7..d022a54fc0 100644 --- a/app/packager_main.cc +++ b/app/packager_main.cc @@ -22,6 +22,7 @@ #include "media/base/muxer_options.h" #include "media/base/muxer_util.h" #include "media/event/mpd_notify_muxer_listener.h" +#include "media/event/vod_media_info_dump_muxer_listener.h" #include "media/formats/mp4/mp4_muxer.h" #include "mpd/base/mpd_builder.h" #include "mpd/base/simple_mpd_notifier.h" @@ -54,6 +55,7 @@ using dash_packager::MpdOptions; using dash_packager::SimpleMpdNotifier; using event::MpdNotifyMuxerListener; using event::MuxerListener; +using event::VodMediaInfoDumpMuxerListener; // Demux, Mux(es) and worker thread used to remux a source file/stream. class RemuxJob : public base::SimpleThread { @@ -155,12 +157,28 @@ bool CreateRemuxJobs(const StringVector& stream_descriptors, FLAGS_crypto_period_duration); } + scoped_ptr muxer_listener; + DCHECK(!(FLAGS_output_media_info && mpd_notifier)); + if (FLAGS_output_media_info) { + const std::string output_mpd_file_name = + stream_muxer_options.output_file_name + ".media_info"; + scoped_ptr + vod_media_info_dump_muxer_listener( + new VodMediaInfoDumpMuxerListener(output_mpd_file_name)); + vod_media_info_dump_muxer_listener->SetContentProtectionSchemeIdUri( + FLAGS_scheme_id_uri); + muxer_listener = vod_media_info_dump_muxer_listener.Pass(); + } if (mpd_notifier) { scoped_ptr mpd_notify_muxer_listener( new MpdNotifyMuxerListener(mpd_notifier)); mpd_notify_muxer_listener->SetContentProtectionSchemeIdUri( FLAGS_scheme_id_uri); - muxer_listeners->push_back(mpd_notify_muxer_listener.release()); + muxer_listener = mpd_notify_muxer_listener.Pass(); + } + + if (muxer_listener) { + muxer_listeners->push_back(muxer_listener.release()); muxer->SetMuxerListener(muxer_listeners->back()); } @@ -205,14 +223,21 @@ Status RunRemuxJobs(const std::vector& remux_jobs) { } bool RunPackager(const StringVector& stream_descriptors) { - if (FLAGS_output_media_info) { - NOTIMPLEMENTED() << "ERROR: --output_media_info is not supported yet."; - return false; - } - if (!AssignFlagsFromProfile()) return false; + if (FLAGS_output_media_info && !FLAGS_mpd_output.empty()) { + NOTIMPLEMENTED() << "ERROR: --output_media_info and --mpd_output do not " + "work together."; + return false; + } + if (FLAGS_output_media_info && !FLAGS_single_segment) { + // TODO(rkuroiwa, kqyang): Support partial media info dump for live. + NOTIMPLEMENTED() << "ERROR: --output_media_info is only supported if " + "--single_segment is true."; + return false; + } + // Get basic muxer options. MuxerOptions muxer_options; if (!GetMuxerOptions(&muxer_options)) diff --git a/media/event/vod_media_info_dump_muxer_listener.cc b/media/event/vod_media_info_dump_muxer_listener.cc index 7612004358..e4c5a9380e 100644 --- a/media/event/vod_media_info_dump_muxer_listener.cc +++ b/media/event/vod_media_info_dump_muxer_listener.cc @@ -19,8 +19,9 @@ namespace event { using dash_packager::MediaInfo; -VodMediaInfoDumpMuxerListener::VodMediaInfoDumpMuxerListener(File* output_file) - : file_(output_file) {} +VodMediaInfoDumpMuxerListener::VodMediaInfoDumpMuxerListener( + const std::string& output_file_name) + : output_file_name_(output_file_name) {} VodMediaInfoDumpMuxerListener::~VodMediaInfoDumpMuxerListener() {} @@ -85,20 +86,29 @@ void VodMediaInfoDumpMuxerListener::OnNewSegment(uint64 start_time, NOTIMPLEMENTED(); } -void VodMediaInfoDumpMuxerListener::SerializeMediaInfoToFile() { +bool VodMediaInfoDumpMuxerListener::SerializeMediaInfoToFile() { std::string output_string; if (!google::protobuf::TextFormat::PrintToString(*media_info_, &output_string)) { LOG(ERROR) << "Failed to serialize MediaInfo to string."; - return; + return false; } - if (file_->Write(output_string.data(), output_string.size()) <= 0) { + media::File* file = File::Open(output_file_name_.c_str(), "w"); + if (!file) { + LOG(ERROR) << "Failed to open " << output_file_name_; + return false; + } + if (file->Write(output_string.data(), output_string.size()) <= 0) { LOG(ERROR) << "Failed to write MediaInfo to file."; - return; + file->Close(); + return false; } - - file_->Flush(); + if (!file->Close()) { + LOG(ERROR) << "Failed to close " << output_file_name_; + return false; + } + return true; } } // namespace event diff --git a/media/event/vod_media_info_dump_muxer_listener.h b/media/event/vod_media_info_dump_muxer_listener.h index 421a1caec0..1f4c3baa6e 100644 --- a/media/event/vod_media_info_dump_muxer_listener.h +++ b/media/event/vod_media_info_dump_muxer_listener.h @@ -24,24 +24,19 @@ class MediaInfo; } // namespace dash_packager namespace media { - -class File; - namespace event { class VodMediaInfoDumpMuxerListener : public MuxerListener { public: - // This object does not own |output_file|. The file has to be open and be - // ready for Write(). This will Flush() the file on write but it does not - // Close() the file. - VodMediaInfoDumpMuxerListener(File* output_file); + VodMediaInfoDumpMuxerListener(const std::string& output_file_name); virtual ~VodMediaInfoDumpMuxerListener(); - // If the stream is encrypted use this as 'schemeIdUri' attribute for - // ContentProtection element. + /// If the stream is encrypted use this as 'schemeIdUri' attribute for + /// ContentProtection element. void SetContentProtectionSchemeIdUri(const std::string& scheme_id_uri); - // MuxerListener implementation. + /// @name MuxerListener implementation overrides. + /// @{ virtual void OnMediaStart(const MuxerOptions& muxer_options, const std::vector& stream_infos, uint32 time_scale, @@ -60,11 +55,13 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener { virtual void OnNewSegment(uint64 start_time, uint64 duration, uint64 segment_file_size) OVERRIDE; - private: - // Write |media_info_| to |file_|. - void SerializeMediaInfoToFile(); + /// @} - File* file_; + private: + // Write |media_info_| to |output_file_name_|. + bool SerializeMediaInfoToFile(); + + std::string output_file_name_; std::string scheme_id_uri_; scoped_ptr media_info_; diff --git a/media/event/vod_media_info_dump_muxer_listener_unittest.cc b/media/event/vod_media_info_dump_muxer_listener_unittest.cc index 7296510904..6842f67144 100644 --- a/media/event/vod_media_info_dump_muxer_listener_unittest.cc +++ b/media/event/vod_media_info_dump_muxer_listener_unittest.cc @@ -152,16 +152,14 @@ void ExpectTextFormatMediaInfoEqual(const std::string& expect, class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test { public: - VodMediaInfoDumpMuxerListenerTest() : temp_file_(NULL) {} + VodMediaInfoDumpMuxerListenerTest() {} virtual ~VodMediaInfoDumpMuxerListenerTest() {} virtual void SetUp() OVERRIDE { ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_)); DLOG(INFO) << "Created temp file: " << temp_file_path_.value(); - temp_file_ = File::Open(temp_file_path_.value().c_str(), "w"); - ASSERT_TRUE(temp_file_); - listener_.reset(new VodMediaInfoDumpMuxerListener(temp_file_)); + listener_.reset(new VodMediaInfoDumpMuxerListener(temp_file_path_.value())); } virtual void TearDown() OVERRIDE { @@ -182,7 +180,7 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test { } void FireOnMediaEndWithParams(const OnMediaEndParameters& params) { - // On success, this writes the result to |temp_file_|. + // On success, this writes the result to |temp_file_path_|. listener_->OnMediaEnd(params.has_init_range, params.init_range_start, params.init_range_end, @@ -204,7 +202,6 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test { } protected: - File* temp_file_; base::FilePath temp_file_path_; scoped_ptr listener_; @@ -221,7 +218,6 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, UnencryptedStream_Normal) { FireOnMediaStartWithDefaultMuxerOptions(stream_infos, !kEnableEncryption); OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams(); FireOnMediaEndWithParams(media_end_param); - ASSERT_TRUE(temp_file_->Close()); const char kExpectedProtobufOutput[] = "bandwidth: 7620\n" @@ -258,7 +254,6 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) { OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams(); FireOnMediaEndWithParams(media_end_param); - ASSERT_TRUE(temp_file_->Close()); const char kExpectedProtobufOutput[] = "bandwidth: 7620\n"