7 #include <packager/media/trick_play/trick_play_handler.h>
9 #include <absl/log/check.h>
10 #include <absl/log/log.h>
12 #include <packager/media/base/video_stream_info.h>
13 #include <packager/status.h>
18 const size_t kStreamIndexIn = 0;
19 const size_t kStreamIndexOut = 0;
22 TrickPlayHandler::TrickPlayHandler(uint32_t factor) : factor_(factor) {
24 <<
"Trick Play Handles must have a factor of 1 or higher.";
27 Status TrickPlayHandler::InitializeInternal() {
31 Status TrickPlayHandler::Process(std::unique_ptr<StreamData> stream_data) {
33 DCHECK_EQ(stream_data->stream_index, kStreamIndexIn);
35 switch (stream_data->stream_data_type) {
36 case StreamDataType::kStreamInfo:
37 return OnStreamInfo(*stream_data->stream_info);
39 case StreamDataType::kSegmentInfo:
40 return OnSegmentInfo(std::move(stream_data->segment_info));
42 case StreamDataType::kMediaSample:
43 return OnMediaSample(*stream_data->media_sample);
45 case StreamDataType::kCueEvent:
47 delayed_messages_.push_back(std::move(stream_data));
51 return Status(error::TRICK_PLAY_ERROR,
52 "Trick play only supports stream info, segment info, and "
53 "media sample messages.");
57 Status TrickPlayHandler::OnFlushRequest(
size_t input_stream_index) {
58 DCHECK_EQ(input_stream_index, 0u);
63 while (s.ok() && delayed_messages_.size()) {
64 s.Update(Dispatch(std::move(delayed_messages_.front())));
65 delayed_messages_.pop_front();
68 return s.ok() ? MediaHandler::FlushAllDownstreams() : s;
71 Status TrickPlayHandler::OnStreamInfo(
const StreamInfo& info) {
72 if (info.stream_type() != kStreamVideo) {
73 return Status(error::TRICK_PLAY_ERROR,
74 "Trick play does not support non-video stream");
79 video_info_ = std::make_shared<VideoStreamInfo>(
80 static_cast<const VideoStreamInfo&
>(info));
82 if (video_info_->trick_play_factor() > 0) {
83 return Status(error::TRICK_PLAY_ERROR,
84 "This stream is already a trick play stream.");
87 video_info_->set_trick_play_factor(factor_);
88 video_info_->set_playback_rate(0);
93 delayed_messages_.push_back(
94 StreamData::FromStreamInfo(kStreamIndexOut, video_info_));
99 Status TrickPlayHandler::OnSegmentInfo(
100 std::shared_ptr<const SegmentInfo> info) {
101 if (delayed_messages_.empty()) {
102 return Status(error::TRICK_PLAY_ERROR,
103 "Cannot handle segments with no preceding samples.");
107 if (info->is_subsegment) {
111 const StreamDataType previous_type =
112 delayed_messages_.back()->stream_data_type;
114 switch (previous_type) {
115 case StreamDataType::kSegmentInfo:
119 previous_segment_->duration += info->duration;
122 case StreamDataType::kMediaSample:
127 previous_segment_ = std::make_shared<SegmentInfo>(*info);
128 delayed_messages_.push_back(
129 StreamData::FromSegmentInfo(kStreamIndexOut, previous_segment_));
133 return Status(error::TRICK_PLAY_ERROR,
134 "Unexpected sample in trick play deferred queue : type=" +
135 std::to_string(
static_cast<int>(previous_type)));
139 Status TrickPlayHandler::OnMediaSample(
const MediaSample& sample) {
142 if (sample.is_key_frame()) {
145 if ((total_key_frames_ - 1) % factor_ == 0) {
146 return OnTrickFrame(sample);
152 DCHECK(previous_trick_frame_);
153 previous_trick_frame_->set_duration(previous_trick_frame_->duration() +
159 Status TrickPlayHandler::OnTrickFrame(
const MediaSample& sample) {
160 total_trick_frames_++;
163 previous_trick_frame_ = sample.Clone();
166 delayed_messages_.push_back(
167 StreamData::FromMediaSample(kStreamIndexOut, previous_trick_frame_));
172 if (total_trick_frames_ < 2) {
177 if (total_trick_frames_ == 2) {
184 video_info_->set_playback_rate(total_frames_ - 1);
190 while (s.ok() && delayed_messages_.size() > 1) {
191 s.Update(Dispatch(std::move(delayed_messages_.front())));
192 delayed_messages_.pop_front();
All the methods that are virtual are virtual for mocking.