diff --git a/packager/media/chunking/chunking_handler.cc b/packager/media/chunking/chunking_handler.cc index 12639d48ab..11daa7d9c7 100644 --- a/packager/media/chunking/chunking_handler.cc +++ b/packager/media/chunking/chunking_handler.cc @@ -72,10 +72,7 @@ Status ChunkingHandler::Process(std::unique_ptr stream_data) { break; } case StreamDataType::kScte35Event: { - DCHECK_NE(main_stream_index_, kInvalidStreamIndex) - << "kStreamInfo should arrive before kScte35Event"; - const auto stream_index = stream_data->stream_index; - if (stream_index != main_stream_index_) { + if (stream_data->stream_index != main_stream_index_) { VLOG(3) << "Dropping scte35 event from non main stream."; return Status::OK; } @@ -189,7 +186,7 @@ Status ChunkingHandler::ProcessMainMediaSample(const MediaSample* sample) { // Use PTS instead of DTS for cue event timestamp. cue_event->timestamp = sample->pts(); cue_event->cue_data = scte35_events_.top()->scte35_event->cue_data; - VLOG(1) << "Chunked at " << timestamp << " for Ad Cue."; + LOG(INFO) << "Chunked at " << timestamp << " for Ad Cue."; scte35_events_.pop(); } diff --git a/packager/media/event/event_info.h b/packager/media/event/event_info.h new file mode 100644 index 0000000000..e3104478e7 --- /dev/null +++ b/packager/media/event/event_info.h @@ -0,0 +1,42 @@ +// Copyright 2018 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 +// +// Defines EventInfo structure used internally by muxer listeners for VOD. + +#ifndef PACKAGER_MEDIA_EVENT_EVENT_INFO_H_ +#define PACKAGER_MEDIA_EVENT_EVENT_INFO_H_ + +#include + +namespace shaka { +namespace media { + +// This stores data passed into OnNewSegment() for VOD. +struct SegmentEventInfo { + uint64_t start_time; + // The below two fields are only useful for Segment. + uint64_t duration; + uint64_t segment_file_size; +}; + +// This stores data passed into OnCueEvent() for VOD. +struct CueEventInfo { + uint64_t timestamp; +}; + +// This stores data for lazy event callback for VOD. +struct EventInfo { + bool is_cue_event; + union { + SegmentEventInfo segment_info; + CueEventInfo cue_event_info; + }; +}; + +} // namespace media +} // namespace shaka + +#endif // PACKAGER_MEDIA_EVENT_EVENT_INFO_H_ diff --git a/packager/media/event/hls_notify_muxer_listener.cc b/packager/media/event/hls_notify_muxer_listener.cc index 18f372ccd1..826d3897ce 100644 --- a/packager/media/event/hls_notify_muxer_listener.cc +++ b/packager/media/event/hls_notify_muxer_listener.cc @@ -154,23 +154,29 @@ void HlsNotifyMuxerListener::OnMediaEnd(const MediaRanges& media_ranges, if (!media_ranges.subsegment_ranges.empty()) { const std::vector& subsegment_ranges = media_ranges.subsegment_ranges; - size_t num_subsegments = subsegment_ranges.size(); - if (subsegments_.size() != num_subsegments) { + const size_t num_subsegments = subsegment_ranges.size(); + size_t subsegment_index = 0; + for (const auto& event_info : event_info_) { + if (event_info.is_cue_event) { + hls_notifier_->NotifyCueEvent(stream_id_, + event_info.cue_event_info.timestamp); + } else { + if (subsegment_index < num_subsegments) { + const Range& range = subsegment_ranges[subsegment_index]; + hls_notifier_->NotifyNewSegment( + stream_id_, media_info_.media_file_name(), + event_info.segment_info.start_time, + event_info.segment_info.duration, range.start, + range.end + 1 - range.start); + } + ++subsegment_index; + } + } + if (subsegment_index != num_subsegments) { LOG(WARNING) << "Number of subsegment ranges (" << num_subsegments << ") does not match the number of subsegments notified to " "OnNewSegment() (" - << subsegments_.size() << ")."; - num_subsegments = std::min(subsegments_.size(), num_subsegments); - } - for (size_t i = 0; i < num_subsegments; ++i) { - const Range& range = subsegment_ranges[i]; - const SubsegmentInfo& subsegment_info = subsegments_[i]; - if (subsegment_info.cue_break) { - hls_notifier_->NotifyCueEvent(stream_id_, subsegment_info.start_time); - } - hls_notifier_->NotifyNewSegment( - stream_id_, media_info_.media_file_name(), subsegment_info.start_time, - subsegment_info.duration, range.start, range.end + 1 - range.start); + << event_info_.size() << ")."; } } } @@ -180,27 +186,31 @@ void HlsNotifyMuxerListener::OnNewSegment(const std::string& file_name, uint64_t duration, uint64_t segment_file_size) { if (!media_info_.has_segment_template()) { - SubsegmentInfo subsegment = {start_time, duration, segment_file_size, - next_subsegment_contains_cue_break_}; - subsegments_.push_back(subsegment); - next_subsegment_contains_cue_break_ = false; - return; + EventInfo event_info; + event_info.is_cue_event = false; + event_info.segment_info = {start_time, duration, segment_file_size}; + event_info_.push_back(event_info); + } else { + // For multisegment, it always starts from the beginning of the file. + const size_t kStartingByteOffset = 0u; + const bool result = hls_notifier_->NotifyNewSegment( + stream_id_, file_name, start_time, duration, kStartingByteOffset, + segment_file_size); + LOG_IF(WARNING, !result) << "Failed to add new segment."; } - // For multisegment, it always starts from the beginning of the file. - const size_t kStartingByteOffset = 0u; - const bool result = hls_notifier_->NotifyNewSegment( - stream_id_, file_name, start_time, duration, kStartingByteOffset, - segment_file_size); - LOG_IF(WARNING, !result) << "Failed to add new segment."; } void HlsNotifyMuxerListener::OnCueEvent(uint64_t timestamp, const std::string& cue_data) { + // Not using |cue_data| at this moment. if (!media_info_.has_segment_template()) { - next_subsegment_contains_cue_break_ = true; - return; + EventInfo event_info; + event_info.is_cue_event = true; + event_info.cue_event_info = {timestamp}; + event_info_.push_back(event_info); + } else { + hls_notifier_->NotifyCueEvent(stream_id_, timestamp); } - hls_notifier_->NotifyCueEvent(stream_id_, timestamp); } } // namespace media diff --git a/packager/media/event/hls_notify_muxer_listener.h b/packager/media/event/hls_notify_muxer_listener.h index 08cc00c89e..2d6722faad 100644 --- a/packager/media/event/hls_notify_muxer_listener.h +++ b/packager/media/event/hls_notify_muxer_listener.h @@ -9,7 +9,7 @@ #include -#include "packager/base/macros.h" +#include "packager/media/event/event_info.h" #include "packager/media/event/muxer_listener.h" #include "packager/mpd/base/media_info.pb.h" @@ -62,13 +62,8 @@ class HlsNotifyMuxerListener : public MuxerListener { /// @} private: - // This stores data passed into OnNewSegment() for VOD. - struct SubsegmentInfo { - uint64_t start_time; - uint64_t duration; - uint64_t segment_file_size; - bool cue_break; - }; + HlsNotifyMuxerListener(const HlsNotifyMuxerListener&) = delete; + HlsNotifyMuxerListener& operator=(const HlsNotifyMuxerListener&) = delete; const std::string playlist_name_; const std::string ext_x_media_name_; @@ -87,11 +82,10 @@ class HlsNotifyMuxerListener : public MuxerListener { // MediaInfo passed to Notifier::OnNewStream(). Mainly for single segment // playlists. MediaInfo media_info_; - std::vector subsegments_; - // Whether the next subsegment contains AdCue break. - bool next_subsegment_contains_cue_break_ = false; - - DISALLOW_COPY_AND_ASSIGN(HlsNotifyMuxerListener); + // Even information for delayed function calls (NotifyNewSegment and + // NotifyCueEvent) after NotifyNewStream is called in OnMediaEnd. Only needed + // for on-demand as the functions are called immediately in live mode. + std::vector event_info_; }; } // namespace media diff --git a/packager/media/event/media_event.gyp b/packager/media/event/media_event.gyp index dded50a218..13086b0cc5 100644 --- a/packager/media/event/media_event.gyp +++ b/packager/media/event/media_event.gyp @@ -15,6 +15,7 @@ 'sources': [ 'combined_muxer_listener.cc', 'combined_muxer_listener.h', + 'event_info.h', 'hls_notify_muxer_listener.cc', 'hls_notify_muxer_listener.h', 'mpd_notify_muxer_listener.cc', diff --git a/packager/media/event/mpd_notify_muxer_listener.cc b/packager/media/event/mpd_notify_muxer_listener.cc index 5cafd85066..2466302054 100644 --- a/packager/media/event/mpd_notify_muxer_listener.cc +++ b/packager/media/event/mpd_notify_muxer_listener.cc @@ -112,7 +112,7 @@ void MpdNotifyMuxerListener::OnSampleDurationReady( void MpdNotifyMuxerListener::OnMediaEnd(const MediaRanges& media_ranges, float duration_seconds) { if (mpd_notifier_->dash_profile() == DashProfile::kLive) { - DCHECK(subsegments_.empty()); + DCHECK(event_info_.empty()); // TODO(kqyang): Set mpd duration to |duration_seconds|, which is more // accurate than the duration coded in the original media header. if (mpd_notifier_->mpd_type() == MpdType::kStatic) @@ -132,15 +132,17 @@ void MpdNotifyMuxerListener::OnMediaEnd(const MediaRanges& media_ranges, mpd_notifier_->NotifyNewContainer(*media_info_, &id); // TODO(rkuroiwa): Use media_ranges.subsegment_ranges instead of caching the // subsegments. - for (const SubsegmentInfo& subsegment : subsegments_) { - if (subsegment.cue_break) { - mpd_notifier_->NotifyCueEvent(id, subsegment.start_time); + for (const auto& event_info : event_info_) { + if (event_info.is_cue_event) { + mpd_notifier_->NotifyCueEvent(id, event_info.cue_event_info.timestamp); + } else { + mpd_notifier_->NotifyNewSegment( + id, event_info.segment_info.start_time, + event_info.segment_info.duration, + event_info.segment_info.segment_file_size); } - mpd_notifier_->NotifyNewSegment(id, subsegment.start_time, - subsegment.duration, - subsegment.segment_file_size); } - subsegments_.clear(); + event_info_.clear(); mpd_notifier_->Flush(); } @@ -155,10 +157,10 @@ void MpdNotifyMuxerListener::OnNewSegment(const std::string& file_name, if (mpd_notifier_->mpd_type() == MpdType::kDynamic) mpd_notifier_->Flush(); } else { - SubsegmentInfo subsegment = {start_time, duration, segment_file_size, - next_subsegment_contains_cue_break_}; - next_subsegment_contains_cue_break_ = false; - subsegments_.push_back(subsegment); + EventInfo event_info; + event_info.is_cue_event = false; + event_info.segment_info = {start_time, duration, segment_file_size}; + event_info_.push_back(event_info); } } @@ -168,7 +170,10 @@ void MpdNotifyMuxerListener::OnCueEvent(uint64_t timestamp, if (mpd_notifier_->dash_profile() == DashProfile::kLive) { mpd_notifier_->NotifyCueEvent(notification_id_, timestamp); } else { - next_subsegment_contains_cue_break_ = true; + EventInfo event_info; + event_info.is_cue_event = true; + event_info.cue_event_info = {timestamp}; + event_info_.push_back(event_info); } } diff --git a/packager/media/event/mpd_notify_muxer_listener.h b/packager/media/event/mpd_notify_muxer_listener.h index c5b50341c7..195dcd6534 100644 --- a/packager/media/event/mpd_notify_muxer_listener.h +++ b/packager/media/event/mpd_notify_muxer_listener.h @@ -9,12 +9,11 @@ #ifndef PACKAGER_MEDIA_EVENT_MPD_NOTIFY_MUXER_LISTENER_H_ #define PACKAGER_MEDIA_EVENT_MPD_NOTIFY_MUXER_LISTENER_H_ -#include #include #include -#include "packager/base/macros.h" #include "packager/media/base/muxer_options.h" +#include "packager/media/event/event_info.h" #include "packager/media/event/muxer_listener.h" namespace shaka { @@ -55,13 +54,8 @@ class MpdNotifyMuxerListener : public MuxerListener { /// @} private: - // This stores data passed into OnNewSegment() for VOD. - struct SubsegmentInfo { - uint64_t start_time; - uint64_t duration; - uint64_t segment_file_size; - bool cue_break; - }; + MpdNotifyMuxerListener(const MpdNotifyMuxerListener&) = delete; + MpdNotifyMuxerListener& operator=(const MpdNotifyMuxerListener&) = delete; MpdNotifier* const mpd_notifier_ = nullptr; uint32_t notification_id_ = 0; @@ -73,15 +67,12 @@ class MpdNotifyMuxerListener : public MuxerListener { std::vector default_key_id_; std::vector key_system_info_; - // Saves all the subsegment information for VOD. This should be used to call - // MpdNotifier::NotifyNewSegment() after NotifyNewSegment() is called - // (in OnMediaEnd). This is not used for live because NotifyNewSegment() is - // called immediately in OnNewSegment(). - std::list subsegments_; - // Whether the next subsegment contains AdCue break. - bool next_subsegment_contains_cue_break_ = false; - - DISALLOW_COPY_AND_ASSIGN(MpdNotifyMuxerListener); + // Saves all the Subsegment and CueEvent information for VOD. This should be + // used to call NotifyNewSegment() and NotifyCueEvent after + // NotifyNewContainer() is called (in OnMediaEnd). This is not used for live + // because NotifyNewSegment() is called immediately in OnNewSegment(), and + // NotifyCueEvent is called immediately in OnCueEvent. + std::vector event_info_; }; } // namespace media