// Copyright 2017 Google Inc. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd #ifndef PACKAGER_MEDIA_BASE_TRICK_PLAY_HANDLER_H_ #define PACKAGER_MEDIA_BASE_TRICK_PLAY_HANDLER_H_ #include "packager/media/base/media_handler.h" namespace shaka { namespace media { struct TrickPlayOptions { /// Trick play rates. Note that there can be multiple trick play rates, /// e.g., 2, 4 and 8. That means, one input video stream will generate 3 /// output trick play streams and original stream. Three trick play streams /// are: /// [key_frame_0, key_frame_2, key_frame_4, ...] /// [key_frame_0, key_frame_4, key_frame_8,...] /// [key_frame_0, key_frame_8, key_frame_16, ...]. std::vector trick_play_rates; }; /// TrickPlayHandler is a single-input-multiple-output media handler. It creates /// trick play streams from the input. // The stream data in trick play stream is not a simple duplicate. Some // information need to be updated, including trick_play_rate in // VideoStreamInfo, the duration in MediaSample (which makes sure there is no // gap between the media sample dts). Since the duration information can be // determined after getting the next media sample, a queue is used to cache the // input stream data before the next key frame. class TrickPlayHandler : public MediaHandler { public: explicit TrickPlayHandler(const TrickPlayOptions& trick_play_options); ~TrickPlayHandler() override; protected: /// @name MediaHandler implementation overrides. /// @{ Status InitializeInternal() override; Status Process(std::unique_ptr stream_data) override; bool ValidateOutputStreamIndex(size_t stream_index) const override; Status OnFlushRequest(size_t input_stream_index) override; /// @} private: friend class TrickPlayHandlerTest; // Process the cached stream data for one trick play stream. // The cached data is dispatched to the |output_stream_index|. // The |current_dts| is for updating the duration of key frames, // so that there is no gap between consecutive key frames. When // |current_dts| = -1, the original duration of the key frame is used. Status ProcessCachedStreamData( int output_stream_index, std::deque>* cached_stream_data); // Process a single stream data. Depending on the stream data type, some // information needs to be updated. // Decoding timestamp for current key media sample. It is used for calculating // the duration of previous key media sample, to make sure there is no gap // between two key media samples. Status ProcessOneStreamData(int output_stream_index, const std::shared_ptr& stream_data); const TrickPlayOptions trick_play_options_; TrickPlayHandler(const TrickPlayHandler&) = delete; TrickPlayHandler& operator=(const TrickPlayHandler&) = delete; /// Num of key frames received. uint32_t total_key_frames_ = 0; // End timestamp of the previous processed media_sample, which is |dts| + // |duration|. The duration of key frame in trick play stream is updated based // on this timestamp. int64_t prev_sample_end_timestamp_ = 0; // The data in output streams should be in the same order as in the input // stream. Cache the stream data before next key frame so that we can // determine the duration for the current key frame. Since one key frame may // be dispatched to different trick play stream, each trick play stream need // its own queue to handle the synchronization. // TODO(hmchen): Use one queue and multiple iterators, instead of multiple // queues. std::vector>> cached_stream_data_; }; } // namespace media } // namespace shaka #endif // PACKAGER_MEDIA_BASE_TRICK_PLAY_HANDLER_H_