7 #include "packager/media/trick_play/trick_play_handler.h"
9 #include "packager/base/logging.h"
10 #include "packager/media/base/video_stream_info.h"
15 const size_t kStreamIndexIn = 0;
16 const size_t kStreamIndexOut = 0;
19 TrickPlayHandler::TrickPlayHandler(uint32_t factor) : factor_(factor) {
21 <<
"Trick Play Handles must have a factor of 1 or higher.";
24 Status TrickPlayHandler::InitializeInternal() {
28 Status TrickPlayHandler::Process(std::unique_ptr<StreamData> stream_data) {
30 DCHECK_EQ(stream_data->stream_index, kStreamIndexIn);
32 switch (stream_data->stream_data_type) {
33 case StreamDataType::kStreamInfo:
34 return OnStreamInfo(*stream_data->stream_info);
36 case StreamDataType::kSegmentInfo:
37 return OnSegmentInfo(std::move(stream_data->segment_info));
39 case StreamDataType::kMediaSample:
40 return OnMediaSample(*stream_data->media_sample);
42 case StreamDataType::kCueEvent:
44 delayed_messages_.push_back(std::move(stream_data));
48 return Status(error::TRICK_PLAY_ERROR,
49 "Trick play only supports stream info, segment info, and "
50 "media sample messages.");
54 Status TrickPlayHandler::OnFlushRequest(
size_t input_stream_index) {
55 DCHECK_EQ(input_stream_index, 0u);
60 while (s.ok() && delayed_messages_.size()) {
61 s.Update(Dispatch(std::move(delayed_messages_.front())));
62 delayed_messages_.pop_front();
65 return s.ok() ? MediaHandler::FlushAllDownstreams() : s;
68 Status TrickPlayHandler::OnStreamInfo(
const StreamInfo& info) {
69 if (info.stream_type() != kStreamVideo) {
70 return Status(error::TRICK_PLAY_ERROR,
71 "Trick play does not support non-video stream");
76 video_info_ = std::make_shared<VideoStreamInfo>(
77 static_cast<const VideoStreamInfo&
>(info));
79 if (video_info_->trick_play_factor() > 0) {
80 return Status(error::TRICK_PLAY_ERROR,
81 "This stream is already a trick play stream.");
84 video_info_->set_trick_play_factor(factor_);
85 video_info_->set_playback_rate(0);
90 delayed_messages_.push_back(
91 StreamData::FromStreamInfo(kStreamIndexOut, video_info_));
96 Status TrickPlayHandler::OnSegmentInfo(
97 std::shared_ptr<const SegmentInfo> info) {
98 if (delayed_messages_.empty()) {
99 return Status(error::TRICK_PLAY_ERROR,
100 "Cannot handle segments with no preceding samples.");
104 if (info->is_subsegment) {
108 const StreamDataType previous_type =
109 delayed_messages_.back()->stream_data_type;
111 switch (previous_type) {
112 case StreamDataType::kSegmentInfo:
116 previous_segment_->duration += info->duration;
119 case StreamDataType::kMediaSample:
124 previous_segment_ = std::make_shared<SegmentInfo>(*info);
125 delayed_messages_.push_back(
126 StreamData::FromSegmentInfo(kStreamIndexOut, previous_segment_));
130 return Status(error::TRICK_PLAY_ERROR,
131 "Unexpected sample in trick play deferred queue : type=" +
132 std::to_string(
static_cast<int>(previous_type)));
136 Status TrickPlayHandler::OnMediaSample(
const MediaSample& sample) {
139 if (sample.is_key_frame()) {
142 if ((total_key_frames_ - 1) % factor_ == 0) {
143 return OnTrickFrame(sample);
149 DCHECK(previous_trick_frame_);
150 previous_trick_frame_->set_duration(previous_trick_frame_->duration() +
156 Status TrickPlayHandler::OnTrickFrame(
const MediaSample& sample) {
157 total_trick_frames_++;
160 previous_trick_frame_ = sample.Clone();
163 delayed_messages_.push_back(
164 StreamData::FromMediaSample(kStreamIndexOut, previous_trick_frame_));
169 if (total_trick_frames_ < 2) {
174 if (total_trick_frames_ == 2) {
181 video_info_->set_playback_rate(total_frames_ - 1);
187 while (s.ok() && delayed_messages_.size() > 1) {
188 s.Update(Dispatch(std::move(delayed_messages_.front())));
189 delayed_messages_.pop_front();
All the methods that are virtual are virtual for mocking.