7#include <packager/media/trick_play/trick_play_handler.h>
15#include <absl/log/check.h>
17#include <packager/media/base/media_handler.h>
18#include <packager/media/base/media_sample.h>
19#include <packager/media/base/stream_info.h>
20#include <packager/media/base/video_stream_info.h>
21#include <packager/status.h>
26const size_t kStreamIndexIn = 0;
27const size_t kStreamIndexOut = 0;
30TrickPlayHandler::TrickPlayHandler(uint32_t factor) : factor_(factor) {
32 <<
"Trick Play Handles must have a factor of 1 or higher.";
35Status TrickPlayHandler::InitializeInternal() {
39Status TrickPlayHandler::Process(std::unique_ptr<StreamData> stream_data) {
41 DCHECK_EQ(stream_data->stream_index, kStreamIndexIn);
43 switch (stream_data->stream_data_type) {
44 case StreamDataType::kStreamInfo:
45 return OnStreamInfo(*stream_data->stream_info);
47 case StreamDataType::kSegmentInfo:
48 return OnSegmentInfo(std::move(stream_data->segment_info));
50 case StreamDataType::kMediaSample:
51 return OnMediaSample(*stream_data->media_sample);
53 case StreamDataType::kCueEvent:
55 delayed_messages_.push_back(std::move(stream_data));
59 return Status(error::TRICK_PLAY_ERROR,
60 "Trick play only supports stream info, segment info, and "
61 "media sample messages.");
65Status TrickPlayHandler::OnFlushRequest(
size_t input_stream_index) {
66 DCHECK_EQ(input_stream_index, 0u);
71 while (s.ok() && delayed_messages_.size()) {
72 s.Update(Dispatch(std::move(delayed_messages_.front())));
73 delayed_messages_.pop_front();
76 return s.ok() ? MediaHandler::FlushAllDownstreams() : s;
79Status TrickPlayHandler::OnStreamInfo(
const StreamInfo& info) {
80 if (info.stream_type() != kStreamVideo) {
81 return Status(error::TRICK_PLAY_ERROR,
82 "Trick play does not support non-video stream");
87 video_info_ = std::make_shared<VideoStreamInfo>(
88 static_cast<const VideoStreamInfo&
>(info));
90 if (video_info_->trick_play_factor() > 0) {
91 return Status(error::TRICK_PLAY_ERROR,
92 "This stream is already a trick play stream.");
95 video_info_->set_trick_play_factor(factor_);
96 video_info_->set_playback_rate(0);
101 delayed_messages_.push_back(
102 StreamData::FromStreamInfo(kStreamIndexOut, video_info_));
107Status TrickPlayHandler::OnSegmentInfo(
108 std::shared_ptr<const SegmentInfo> info) {
109 if (delayed_messages_.empty()) {
110 return Status(error::TRICK_PLAY_ERROR,
111 "Cannot handle segments with no preceding samples.");
115 if (info->is_subsegment) {
119 const StreamDataType previous_type =
120 delayed_messages_.back()->stream_data_type;
122 switch (previous_type) {
123 case StreamDataType::kSegmentInfo:
127 previous_segment_->duration += info->duration;
130 case StreamDataType::kMediaSample:
135 previous_segment_ = std::make_shared<SegmentInfo>(*info);
136 delayed_messages_.push_back(
137 StreamData::FromSegmentInfo(kStreamIndexOut, previous_segment_));
141 return Status(error::TRICK_PLAY_ERROR,
142 "Unexpected sample in trick play deferred queue : type=" +
143 std::to_string(
static_cast<int>(previous_type)));
147Status TrickPlayHandler::OnMediaSample(
const MediaSample& sample) {
150 if (sample.is_key_frame()) {
153 if ((total_key_frames_ - 1) % factor_ == 0) {
154 return OnTrickFrame(sample);
160 DCHECK(previous_trick_frame_);
161 previous_trick_frame_->set_duration(previous_trick_frame_->duration() +
167Status TrickPlayHandler::OnTrickFrame(
const MediaSample& sample) {
168 total_trick_frames_++;
171 previous_trick_frame_ = sample.Clone();
174 delayed_messages_.push_back(
175 StreamData::FromMediaSample(kStreamIndexOut, previous_trick_frame_));
180 if (total_trick_frames_ < 2) {
185 if (total_trick_frames_ == 2) {
192 video_info_->set_playback_rate(total_frames_ - 1);
198 while (s.ok() && delayed_messages_.size() > 1) {
199 s.Update(Dispatch(std::move(delayed_messages_.front())));
200 delayed_messages_.pop_front();
All the methods that are virtual are virtual for mocking.