// Copyright 2017 Google LLC. 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_MEDIA_HANDLER_H_ #define PACKAGER_MEDIA_BASE_MEDIA_HANDLER_H_ #include #include #include #include "packager/media/base/media_sample.h" #include "packager/media/base/stream_info.h" #include "packager/media/base/text_sample.h" #include "packager/status.h" namespace shaka { namespace media { enum class StreamDataType { kUnknown, kStreamInfo, kMediaSample, kTextSample, kSegmentInfo, kScte35Event, kCueEvent, }; std::string StreamDataTypeToString(StreamDataType type); // Scte35Event represents cuepoint markers in input streams. It will be used // to represent out of band cuepoint markers too. struct Scte35Event { std::string id; // Segmentation type id from SCTE35 segmentation descriptor. int type = 0; double start_time_in_seconds = 0; double duration_in_seconds = 0; std::string cue_data; }; enum class CueEventType { kCueIn, kCueOut, kCuePoint }; // In server-based model, Chunking Handler consolidates SCTE-35 events and // generates CueEvent before an ad is about to be inserted. struct CueEvent { CueEventType type = CueEventType::kCuePoint; double time_in_seconds; std::string cue_data; }; struct SegmentInfo { bool is_subsegment = false; bool is_chunk = false; bool is_final_chunk_in_seg = false; bool is_encrypted = false; int64_t start_timestamp = -1; int64_t duration = 0; // This is only available if key rotation is enabled. Note that we may have // a |key_rotation_encryption_config| even if the segment is not encrypted, // which is the case for clear lead. std::shared_ptr key_rotation_encryption_config; }; // TODO(kqyang): Should we use protobuf? struct StreamData { size_t stream_index = static_cast(-1); StreamDataType stream_data_type = StreamDataType::kUnknown; std::shared_ptr stream_info; std::shared_ptr media_sample; std::shared_ptr text_sample; std::shared_ptr segment_info; std::shared_ptr scte35_event; std::shared_ptr cue_event; static std::unique_ptr FromStreamInfo( size_t stream_index, std::shared_ptr stream_info) { std::unique_ptr stream_data(new StreamData); stream_data->stream_index = stream_index; stream_data->stream_data_type = StreamDataType::kStreamInfo; stream_data->stream_info = std::move(stream_info); return stream_data; } static std::unique_ptr FromMediaSample( size_t stream_index, std::shared_ptr media_sample) { std::unique_ptr stream_data(new StreamData); stream_data->stream_index = stream_index; stream_data->stream_data_type = StreamDataType::kMediaSample; stream_data->media_sample = std::move(media_sample); return stream_data; } static std::unique_ptr FromTextSample( size_t stream_index, std::shared_ptr text_sample) { std::unique_ptr stream_data(new StreamData); stream_data->stream_index = stream_index; stream_data->stream_data_type = StreamDataType::kTextSample; stream_data->text_sample = std::move(text_sample); return stream_data; } static std::unique_ptr FromSegmentInfo( size_t stream_index, std::shared_ptr segment_info) { std::unique_ptr stream_data(new StreamData); stream_data->stream_index = stream_index; stream_data->stream_data_type = StreamDataType::kSegmentInfo; stream_data->segment_info = std::move(segment_info); return stream_data; } static std::unique_ptr FromScte35Event( size_t stream_index, std::shared_ptr scte35_event) { std::unique_ptr stream_data(new StreamData); stream_data->stream_index = stream_index; stream_data->stream_data_type = StreamDataType::kScte35Event; stream_data->scte35_event = std::move(scte35_event); return stream_data; } static std::unique_ptr FromCueEvent( size_t stream_index, std::shared_ptr cue_event) { std::unique_ptr stream_data(new StreamData); stream_data->stream_index = stream_index; stream_data->stream_data_type = StreamDataType::kCueEvent; stream_data->cue_event = std::move(cue_event); return stream_data; } }; /// MediaHandler is the base media processing unit. Media handlers transform /// the input streams and propagate the outputs to downstream media handlers. /// There are three different types of media handlers: /// 1) Single input single output /// This is the most basic handler. It only supports one input and one /// output with both index as 0. /// 2) Multiple inputs multiple outputs /// The number of outputs must be equal to the number of inputs. The /// output stream at a specific index comes from the input stream at the /// same index. Different streams usually share a common resource, although /// they may be independent. One example of this is encryption handler. /// 3) Single input multiple outputs /// The input stream is split into multiple output streams. One example /// of this is the replicator media handler. /// Other types of media handlers are disallowed and not supported. class MediaHandler { public: MediaHandler() = default; virtual ~MediaHandler() = default; /// Connect downstream handler at the specified output stream index. Status SetHandler(size_t output_stream_index, std::shared_ptr handler); /// Connect downstream handler to the next available output stream index. Status AddHandler(std::shared_ptr handler) { return SetHandler(next_output_stream_index_, handler); } /// Initialize the handler and downstream handlers. Note that it should be /// called after setting up the graph before running the graph. Status Initialize(); /// Validate if the handler is connected to its upstream handler. bool IsConnected() { return num_input_streams_ > 0; } static Status Chain(const std::vector>& list); protected: /// Internal implementation of initialize. Note that it should only initialize /// the MediaHandler itself. Downstream handlers are handled in Initialize(). virtual Status InitializeInternal() = 0; /// Process the incoming stream data. Note that (1) stream_data.stream_index /// should be the input stream index; (2) The implementation needs to call /// DispatchXxx to dispatch the processed stream data to the downstream /// handlers after finishing processing if needed. virtual Status Process(std::unique_ptr stream_data) = 0; /// Event handler for flush request at the specific input stream index. virtual Status OnFlushRequest(size_t input_stream_index); /// Validate if the stream at the specified index actually exists. virtual bool ValidateOutputStreamIndex(size_t stream_index) const; /// Dispatch the stream data to downstream handlers. Note that /// stream_data.stream_index should be the output stream index. Status Dispatch(std::unique_ptr stream_data) const; /// Dispatch the stream info to downstream handlers. Status DispatchStreamInfo( size_t stream_index, std::shared_ptr stream_info) const { return Dispatch( StreamData::FromStreamInfo(stream_index, std::move(stream_info))); } /// Dispatch the media sample to downstream handlers. Status DispatchMediaSample( size_t stream_index, std::shared_ptr media_sample) const { return Dispatch( StreamData::FromMediaSample(stream_index, std::move(media_sample))); } /// Dispatch the text sample to downstream handlers. // DispatchTextSample should only be override for testing. Status DispatchTextSample( size_t stream_index, std::shared_ptr text_sample) const { return Dispatch( StreamData::FromTextSample(stream_index, std::move(text_sample))); } /// Dispatch the segment info to downstream handlers. Status DispatchSegmentInfo( size_t stream_index, std::shared_ptr segment_info) const { return Dispatch( StreamData::FromSegmentInfo(stream_index, std::move(segment_info))); } /// Dispatch the scte35 event to downstream handlers. Status DispatchScte35Event( size_t stream_index, std::shared_ptr scte35_event) const { return Dispatch( StreamData::FromScte35Event(stream_index, std::move(scte35_event))); } /// Dispatch the cue event to downstream handlers. Status DispatchCueEvent(size_t stream_index, std::shared_ptr cue_event) const { return Dispatch( StreamData::FromCueEvent(stream_index, std::move(cue_event))); } /// Flush the downstream connected at the specified output stream index. Status FlushDownstream(size_t output_stream_index); /// Flush all connected downstream handlers. Status FlushAllDownstreams(); bool initialized() { return initialized_; } size_t num_input_streams() const { return num_input_streams_; } size_t next_output_stream_index() const { return next_output_stream_index_; } const std::map, size_t>>& output_handlers() { return output_handlers_; } private: MediaHandler(const MediaHandler&) = delete; MediaHandler& operator=(const MediaHandler&) = delete; bool initialized_ = false; // Number of input streams. size_t num_input_streams_ = 0; // The next available output stream index, used by AddHandler. size_t next_output_stream_index_ = 0; // output stream index -> {output handler, output handler input stream index} // map. std::map, size_t>> output_handlers_; }; } // namespace media } // namespace shaka #endif // PACKAGER_MEDIA_BASE_MEDIA_HANDLER_H_