From c9fb2b4a852b5d52534eb2ab39d2a844909607c5 Mon Sep 17 00:00:00 2001 From: KongQun Yang Date: Thu, 11 Jan 2018 16:55:43 -0800 Subject: [PATCH] Use start_time from CueEvent in NotifyCueEvent Instead of using next segment start time, as CueEvent time may not align with segment start time exactly. Also remove the incorrect DCHECK in ChunkingHandler when processing kScte35Event. Change-Id: I4987740c99c8d0d25c9b99bddc5e557e45d308e0 --- packager/media/chunking/chunking_handler.cc | 7 +- packager/media/event/event_info.h | 42 ++++++++++++ .../media/event/hls_notify_muxer_listener.cc | 66 +++++++++++-------- .../media/event/hls_notify_muxer_listener.h | 20 ++---- packager/media/event/media_event.gyp | 1 + .../media/event/mpd_notify_muxer_listener.cc | 31 +++++---- .../media/event/mpd_notify_muxer_listener.h | 27 +++----- 7 files changed, 117 insertions(+), 77 deletions(-) create mode 100644 packager/media/event/event_info.h 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