7 #include "packager/media/chunking/chunking_handler.h" 11 #include "packager/base/logging.h" 12 #include "packager/media/base/media_sample.h" 13 #include "packager/status_macros.h" 18 const size_t kStreamIndex = 0;
21 ChunkingHandler::ChunkingHandler(
const ChunkingParams& chunking_params)
22 : chunking_params_(chunking_params) {
23 CHECK_NE(chunking_params.segment_duration_in_seconds, 0u);
27 if (num_input_streams() != 1 || next_output_stream_index() != 1) {
28 return Status(error::INVALID_ARGUMENT,
29 "Expects exactly one input and one output.");
35 switch (stream_data->stream_data_type) {
36 case StreamDataType::kStreamInfo:
37 return OnStreamInfo(std::move(stream_data->stream_info));
38 case StreamDataType::kCueEvent:
39 return OnCueEvent(std::move(stream_data->cue_event));
40 case StreamDataType::kSegmentInfo:
41 VLOG(3) <<
"Droppping existing segment info.";
43 case StreamDataType::kMediaSample:
44 return OnMediaSample(std::move(stream_data->media_sample));
46 VLOG(3) <<
"Stream data type " 47 <<
static_cast<int>(stream_data->stream_data_type) <<
" ignored.";
48 return Dispatch(std::move(stream_data));
53 RETURN_IF_ERROR(EndSegmentIfStarted());
54 return FlushDownstream(kStreamIndex);
57 Status ChunkingHandler::OnStreamInfo(std::shared_ptr<const StreamInfo> info) {
58 time_scale_ = info->time_scale();
60 chunking_params_.segment_duration_in_seconds * time_scale_;
61 subsegment_duration_ =
62 chunking_params_.subsegment_duration_in_seconds * time_scale_;
63 return DispatchStreamInfo(kStreamIndex, std::move(info));
66 Status ChunkingHandler::OnCueEvent(std::shared_ptr<const CueEvent> event) {
67 RETURN_IF_ERROR(EndSegmentIfStarted());
68 const double event_time_in_seconds =
event->time_in_seconds;
69 RETURN_IF_ERROR(DispatchCueEvent(kStreamIndex, std::move(event)));
72 segment_start_time_ = base::nullopt;
75 cue_offset_ = event_time_in_seconds * time_scale_;
79 Status ChunkingHandler::OnMediaSample(
80 std::shared_ptr<const MediaSample> sample) {
81 DCHECK_NE(time_scale_, 0u) <<
"kStreamInfo should arrive before kMediaSample";
83 const int64_t timestamp = sample->dts();
85 bool started_new_segment =
false;
86 const bool can_start_new_segment =
87 sample->is_key_frame() || !chunking_params_.segment_sap_aligned;
88 if (can_start_new_segment) {
89 const int64_t segment_index =
90 timestamp < cue_offset_ ? 0
91 : (timestamp - cue_offset_) / segment_duration_;
92 if (!segment_start_time_ || segment_index != current_segment_index_) {
93 current_segment_index_ = segment_index;
95 current_subsegment_index_ = 0;
97 RETURN_IF_ERROR(EndSegmentIfStarted());
98 segment_start_time_ = timestamp;
99 subsegment_start_time_ = timestamp;
100 started_new_segment =
true;
103 if (!started_new_segment && IsSubsegmentEnabled()) {
104 const bool can_start_new_subsegment =
105 sample->is_key_frame() || !chunking_params_.subsegment_sap_aligned;
106 if (can_start_new_subsegment) {
107 const int64_t subsegment_index =
108 (timestamp - segment_start_time_.value()) / subsegment_duration_;
109 if (subsegment_index != current_subsegment_index_) {
110 current_subsegment_index_ = subsegment_index;
112 RETURN_IF_ERROR(EndSubsegmentIfStarted());
113 subsegment_start_time_ = timestamp;
118 VLOG(3) <<
"Sample ts: " << timestamp <<
" " 119 <<
" duration: " << sample->duration() <<
" scale: " << time_scale_
120 << (segment_start_time_ ?
" dispatch " :
" discard ");
123 if (!segment_start_time_)
125 last_sample_end_timestamp_ = timestamp + sample->duration();
126 return DispatchMediaSample(kStreamIndex, std::move(sample));
129 Status ChunkingHandler::EndSegmentIfStarted()
const {
130 if (!segment_start_time_)
133 auto segment_info = std::make_shared<SegmentInfo>();
134 segment_info->start_timestamp = segment_start_time_.value();
135 segment_info->duration =
136 last_sample_end_timestamp_ - segment_start_time_.value();
137 return DispatchSegmentInfo(kStreamIndex, std::move(segment_info));
140 Status ChunkingHandler::EndSubsegmentIfStarted()
const {
141 if (!subsegment_start_time_)
144 auto subsegment_info = std::make_shared<SegmentInfo>();
145 subsegment_info->start_timestamp = subsegment_start_time_.value();
146 subsegment_info->duration =
147 last_sample_end_timestamp_ - subsegment_start_time_.value();
148 subsegment_info->is_subsegment =
true;
149 return DispatchSegmentInfo(kStreamIndex, std::move(subsegment_info));
All the methods that are virtual are virtual for mocking.