From 1706b0bc3af66810ff96a8640333d9aae7a0673e Mon Sep 17 00:00:00 2001 From: "Ivan L. Isaev" <1@crownet.ru> Date: Wed, 30 Aug 2017 03:42:33 +0700 Subject: [PATCH] multi-manifest (e.g. DASH + HLS) output support Fixes #262 --- .../media/event/combined_muxer_listener.cc | 76 +++++++++++++++++++ .../media/event/combined_muxer_listener.h | 52 +++++++++++++ packager/media/event/media_event.gyp | 2 + packager/packager.cc | 46 ++++------- 4 files changed, 144 insertions(+), 32 deletions(-) create mode 100644 packager/media/event/combined_muxer_listener.cc create mode 100644 packager/media/event/combined_muxer_listener.h diff --git a/packager/media/event/combined_muxer_listener.cc b/packager/media/event/combined_muxer_listener.cc new file mode 100644 index 0000000000..05a461fea9 --- /dev/null +++ b/packager/media/event/combined_muxer_listener.cc @@ -0,0 +1,76 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "packager/media/event/combined_muxer_listener.h" + +namespace shaka { +namespace media { + +CombinedMuxerListener::CombinedMuxerListener( + std::list>* muxer_listeners) { + DCHECK(muxer_listeners); + muxer_listeners_.swap(*muxer_listeners); +} + +CombinedMuxerListener::~CombinedMuxerListener() {} + +void CombinedMuxerListener::OnEncryptionInfoReady( + bool is_initial_encryption_info, + FourCC protection_scheme, + const std::vector& key_id, + const std::vector& iv, + const std::vector& key_system_info) { + for (auto& listener: muxer_listeners_) { + listener->OnEncryptionInfoReady(is_initial_encryption_info, + protection_scheme, + key_id, + iv, + key_system_info); + } +} + +void CombinedMuxerListener::OnEncryptionStart() { + for (auto& listener: muxer_listeners_) { + listener->OnEncryptionStart(); + } +} + +void CombinedMuxerListener::OnMediaStart( + const MuxerOptions& muxer_options, + const StreamInfo& stream_info, + uint32_t time_scale, + ContainerType container_type) { + for (auto& listener: muxer_listeners_) { + listener->OnMediaStart( + muxer_options, stream_info, time_scale, container_type); + } +} + +void CombinedMuxerListener::OnSampleDurationReady( + uint32_t sample_duration) { + for (auto& listener: muxer_listeners_) { + listener->OnSampleDurationReady(sample_duration); + } +} + +void CombinedMuxerListener::OnMediaEnd(const MediaRanges& media_ranges, + float duration_seconds) { + for (auto& listener: muxer_listeners_) { + listener->OnMediaEnd(media_ranges, duration_seconds); + } +} + +void CombinedMuxerListener::OnNewSegment(const std::string& file_name, + uint64_t start_time, + uint64_t duration, + uint64_t segment_file_size) { + for (auto& listener: muxer_listeners_) { + listener->OnNewSegment(file_name, start_time, duration, segment_file_size); + } +} + +} // namespace media +} // namespace shaka diff --git a/packager/media/event/combined_muxer_listener.h b/packager/media/event/combined_muxer_listener.h new file mode 100644 index 0000000000..46d57d78ba --- /dev/null +++ b/packager/media/event/combined_muxer_listener.h @@ -0,0 +1,52 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef PACKAGER_MEDIA_EVENT_COMBINED_MUXER_LISTENER_H_ +#define PACKAGER_MEDIA_EVENT_COMBINED_MUXER_LISTENER_H_ + +#include +#include + +#include "packager/media/event/muxer_listener.h" + +namespace shaka { +namespace media { + +class CombinedMuxerListener : public MuxerListener { + public: + explicit CombinedMuxerListener( + std::list>* muxer_listeners); + ~CombinedMuxerListener() override; + + void OnEncryptionInfoReady(bool is_initial_encryption_info, + FourCC protection_scheme, + const std::vector& key_id, + const std::vector& iv, + const std::vector& + key_system_info) override; + void OnEncryptionStart() override; + void OnMediaStart(const MuxerOptions& muxer_options, + const StreamInfo& stream_info, + uint32_t time_scale, + ContainerType container_type) override; + void OnSampleDurationReady(uint32_t sample_duration) override; + void OnMediaEnd(const MediaRanges& media_ranges, + float duration_seconds) override; + void OnNewSegment(const std::string& file_name, + uint64_t start_time, + uint64_t duration, + uint64_t segment_file_size) override; + + private: + std::list> muxer_listeners_; + + DISALLOW_COPY_AND_ASSIGN(CombinedMuxerListener); +}; + +} // namespace media +} // namespace shaka + +#endif // PACKAGER_MEDIA_EVENT_COMBINED_MUXER_LISTENER_H_ diff --git a/packager/media/event/media_event.gyp b/packager/media/event/media_event.gyp index 9c8f1da7a6..1b46e107d1 100644 --- a/packager/media/event/media_event.gyp +++ b/packager/media/event/media_event.gyp @@ -13,6 +13,8 @@ 'target_name': 'media_event', 'type': '<(component)', 'sources': [ + 'combined_muxer_listener.cc', + 'combined_muxer_listener.h', 'hls_notify_muxer_listener.cc', 'hls_notify_muxer_listener.h', 'mpd_notify_muxer_listener.cc', diff --git a/packager/packager.cc b/packager/packager.cc index f9333ffd46..646d0e0392 100644 --- a/packager/packager.cc +++ b/packager/packager.cc @@ -27,6 +27,7 @@ #include "packager/media/chunking/chunking_handler.h" #include "packager/media/crypto/encryption_handler.h" #include "packager/media/demuxer/demuxer.h" +#include "packager/media/event/combined_muxer_listener.h" #include "packager/media/event/hls_notify_muxer_listener.h" #include "packager/media/event/mpd_notify_muxer_listener.h" #include "packager/media/event/vod_media_info_dump_muxer_listener.h" @@ -153,26 +154,6 @@ bool ValidateParams(const PackagingParams& packaging_params, return false; } - if (packaging_params.output_media_info && - !packaging_params.mpd_params.mpd_output.empty()) { - LOG(ERROR) << "output_media_info and MPD output do not work together."; - return false; - } - - if (packaging_params.output_media_info && - !packaging_params.hls_params.master_playlist_output.empty()) { - LOG(ERROR) << "output_media_info and HLS output do not work together."; - return false; - } - - // Since there isn't a muxer listener that can output both MPD and HLS, - // disallow specifying both MPD and HLS flags. - if (!packaging_params.mpd_params.mpd_output.empty() && - !packaging_params.hls_params.master_playlist_output.empty()) { - LOG(ERROR) << "output both MPD and HLS are not supported."; - return false; - } - if (stream_descriptors.empty()) { LOG(ERROR) << "Stream descriptors cannot be empty."; return false; @@ -421,20 +402,17 @@ Status CreateRemuxJobs(const StreamDescriptorList& stream_descriptors, if (packaging_params.test_params.inject_fake_clock) muxer->set_clock(fake_clock); - std::unique_ptr muxer_listener; + std::list> muxer_listeners; DCHECK(!(packaging_params.output_media_info && mpd_notifier)); if (packaging_params.output_media_info) { const std::string output_media_info_file_name = stream_muxer_options.output_file_name + kMediaInfoSuffix; - std::unique_ptr - vod_media_info_dump_muxer_listener( - new VodMediaInfoDumpMuxerListener(output_media_info_file_name)); - muxer_listener = std::move(vod_media_info_dump_muxer_listener); + muxer_listeners.emplace_back( + new VodMediaInfoDumpMuxerListener(output_media_info_file_name)); } + if (mpd_notifier) { - std::unique_ptr mpd_notify_muxer_listener( - new MpdNotifyMuxerListener(mpd_notifier)); - muxer_listener = std::move(mpd_notify_muxer_listener); + muxer_listeners.emplace_back(new MpdNotifyMuxerListener(mpd_notifier)); } if (hls_notifier) { @@ -450,12 +428,16 @@ Status CreateRemuxJobs(const StreamDescriptorList& stream_descriptors, if (hls_playlist_name.empty()) hls_playlist_name = base::StringPrintf("stream_%d.m3u8", stream_number); - muxer_listener.reset(new HlsNotifyMuxerListener(hls_playlist_name, name, - group_id, hls_notifier)); + muxer_listeners.emplace_back( + new HlsNotifyMuxerListener(hls_playlist_name, name, + group_id, hls_notifier)); } - if (muxer_listener) - muxer->SetMuxerListener(std::move(muxer_listener)); + if (!muxer_listeners.empty()) { + std::unique_ptr combined_muxer_listener( + new CombinedMuxerListener(&muxer_listeners)); + muxer->SetMuxerListener(std::move(combined_muxer_listener)); + } // Create a new trick_play_handler. Note that the stream_decriptors // are sorted so that for the same input and stream_selector, the main