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"
16 const size_t kMainStreamIndex = 0;
19 TrickPlayHandler::TrickPlayHandler() {}
21 TrickPlayHandler::~TrickPlayHandler() {}
23 void TrickPlayHandler::SetHandlerForMainStream(
24 std::shared_ptr<MediaHandler> handler) {
25 SetHandler(kMainStreamIndex, std::move(handler));
28 void TrickPlayHandler::SetHandlerForTrickPlay(
29 uint32_t trick_play_factor,
30 std::shared_ptr<MediaHandler> handler) {
31 trick_play_factors_.push_back(trick_play_factor);
33 SetHandler(trick_play_factors_.size(), std::move(handler));
37 if (!HasMainStream()) {
38 return Status(error::TRICK_PLAY_ERROR,
39 "Trick play does not have main stream");
41 if (trick_play_factors_.empty()) {
42 return Status(error::TRICK_PLAY_ERROR,
43 "Trick play factors are not specified.");
45 size_t num_trick_play_factors = trick_play_factors_.size();
46 cached_stream_data_.resize(num_trick_play_factors);
47 playback_rates_.resize(num_trick_play_factors, 0);
53 std::unique_ptr<StreamData> input_stream_data) {
56 DCHECK_EQ(input_stream_data->stream_index, 0u);
57 std::unique_ptr<StreamData> output_stream_data(
new StreamData());
58 *output_stream_data = *input_stream_data;
64 std::shared_ptr<StreamData> stream_data(std::move(input_stream_data));
65 if (stream_data->stream_data_type == StreamDataType::kStreamInfo) {
66 if (stream_data->stream_info->stream_type() != kStreamVideo) {
67 status.
SetError(error::TRICK_PLAY_ERROR,
68 "Trick play does not support non-video stream");
73 if (video_stream_info.trick_play_factor() > 0) {
74 status.
SetError(error::TRICK_PLAY_ERROR,
75 "This stream is alreay a trick play stream.");
80 if (stream_data->stream_data_type == StreamDataType::kSegmentInfo) {
81 for (
auto& cached_data : cached_stream_data_) {
85 if (!cached_data.empty() &&
86 cached_data.back()->stream_data_type == StreamDataType::kMediaSample)
87 cached_data.push_back(stream_data);
92 if (stream_data->stream_data_type != StreamDataType::kMediaSample) {
96 for (
size_t i = 0; i < cached_stream_data_.size(); ++i)
97 cached_stream_data_[i].push_back(stream_data);
101 if (stream_data->media_sample->is_key_frame()) {
104 DCHECK_EQ(trick_play_factors_.size(), cached_stream_data_.size());
105 for (
size_t i = 0; i < cached_stream_data_.size(); ++i) {
106 uint32_t factor = trick_play_factors_[i];
107 if (total_key_frames_ % factor == 0) {
110 if (!cached_stream_data_[i].empty() && total_key_frames_ > 0) {
113 if (playback_rates_[i] == 0)
114 playback_rates_[i] = total_frames_;
117 ProcessCachedStreamData(i + 1, &cached_stream_data_[i]);
121 cached_stream_data_[i].push_back(stream_data);
129 prev_sample_end_timestamp_ =
130 stream_data->media_sample->dts() + stream_data->media_sample->duration();
138 return stream_index <= trick_play_factors_.size();
142 DCHECK_EQ(input_stream_index, 0u)
143 <<
"Trick Play Handler should only have single input.";
144 for (
size_t i = 0; i < cached_stream_data_.size(); ++i) {
145 LOG_IF(WARNING, playback_rates_[i] == 0)
146 <<
"Max playout rate for trick play factor " << trick_play_factors_[i]
147 <<
" is not determined. "
148 <<
"Specify it as total number of frames: " << total_frames_ <<
".";
149 playback_rates_[i] = total_frames_;
150 ProcessCachedStreamData(i + 1, &cached_stream_data_[i]);
155 bool TrickPlayHandler::HasMainStream() {
156 const auto& handlers = output_handlers();
157 const auto& main_stream_handler = handlers.find(kMainStreamIndex);
158 if (main_stream_handler == handlers.end()) {
161 return main_stream_handler->second.first !=
nullptr;
164 Status TrickPlayHandler::ProcessCachedStreamData(
165 size_t output_stream_index,
166 std::deque<std::shared_ptr<StreamData>>* cached_stream_data) {
167 while (!cached_stream_data->empty()) {
169 ProcessOneStreamData(output_stream_index, cached_stream_data->front());
173 cached_stream_data->pop_front();
178 Status TrickPlayHandler::ProcessOneStreamData(
179 size_t output_stream_index,
180 const std::shared_ptr<StreamData>& stream_data) {
181 size_t trick_play_index = output_stream_index - 1;
182 uint32_t trick_play_factor = trick_play_factors_[trick_play_index];
184 switch (stream_data->stream_data_type) {
186 case StreamDataType::kStreamInfo: {
187 const VideoStreamInfo& video_stream_info =
188 static_cast<const VideoStreamInfo&
>(*stream_data->stream_info);
189 std::shared_ptr<VideoStreamInfo> trick_play_video_stream_info(
190 new VideoStreamInfo(video_stream_info));
191 trick_play_video_stream_info->set_trick_play_factor(trick_play_factor);
192 DCHECK_GT(playback_rates_[trick_play_index], 0u);
193 trick_play_video_stream_info->set_playback_rate(
194 playback_rates_[trick_play_index]);
199 case StreamDataType::kMediaSample: {
200 if (stream_data->media_sample->is_key_frame()) {
201 std::shared_ptr<MediaSample> trick_play_media_sample =
203 trick_play_media_sample->set_duration(prev_sample_end_timestamp_ -
204 stream_data->media_sample->dts());
211 std::unique_ptr<StreamData> new_stream_data(
new StreamData(*stream_data));
212 new_stream_data->stream_index = output_stream_index;
213 status =
Dispatch(std::move(new_stream_data));