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
This commit is contained in:
KongQun Yang 2018-01-11 16:55:43 -08:00
parent d9871330e7
commit c9fb2b4a85
7 changed files with 117 additions and 77 deletions

View File

@ -72,10 +72,7 @@ Status ChunkingHandler::Process(std::unique_ptr<StreamData> 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();
}

View File

@ -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 <cstdint>
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_

View File

@ -154,23 +154,29 @@ void HlsNotifyMuxerListener::OnMediaEnd(const MediaRanges& media_ranges,
if (!media_ranges.subsegment_ranges.empty()) {
const std::vector<Range>& 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,12 +186,11 @@ 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(
@ -193,15 +198,20 @@ void HlsNotifyMuxerListener::OnNewSegment(const std::string& file_name,
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);
}
}
} // namespace media
} // namespace shaka

View File

@ -9,7 +9,7 @@
#include <string>
#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<SubsegmentInfo> 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<EventInfo> event_info_;
};
} // namespace media

View File

@ -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',

View File

@ -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);
}
}

View File

@ -9,12 +9,11 @@
#ifndef PACKAGER_MEDIA_EVENT_MPD_NOTIFY_MUXER_LISTENER_H_
#define PACKAGER_MEDIA_EVENT_MPD_NOTIFY_MUXER_LISTENER_H_
#include <list>
#include <memory>
#include <vector>
#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<uint8_t> default_key_id_;
std::vector<ProtectionSystemSpecificInfo> 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<SubsegmentInfo> 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<EventInfo> event_info_;
};
} // namespace media