From 64c6821dc833257264667d2fb1a43d6950329ef4 Mon Sep 17 00:00:00 2001 From: Kongqun Yang Date: Mon, 23 Jan 2017 14:51:00 -0800 Subject: [PATCH] MediaHandler implementation MediaHandler is the basic processing unit in shaka-packager 2.0. Change-Id: I5f8d744e39adfff5cfebe0c50a29ead4d717cca4 --- packager/media/base/media_base.gyp | 2 + packager/media/base/media_handler.cc | 53 +++++++++ packager/media/base/media_handler.h | 169 +++++++++++++++++++++++++++ packager/media/base/status.h | 4 + 4 files changed, 228 insertions(+) create mode 100644 packager/media/base/media_handler.cc create mode 100644 packager/media/base/media_handler.h diff --git a/packager/media/base/media_base.gyp b/packager/media/base/media_base.gyp index 7853b741c9..86f5b114a8 100644 --- a/packager/media/base/media_base.gyp +++ b/packager/media/base/media_base.gyp @@ -54,6 +54,8 @@ 'key_source.h', 'limits.h', 'macros.h', + 'media_handler.cc', + 'media_handler.h', 'media_parser.h', 'media_sample.cc', 'media_sample.h', diff --git a/packager/media/base/media_handler.cc b/packager/media/base/media_handler.cc new file mode 100644 index 0000000000..2c4fecaa0d --- /dev/null +++ b/packager/media/base/media_handler.cc @@ -0,0 +1,53 @@ +// 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 + +#include "packager/media/base/media_handler.h" + +namespace shaka { +namespace media { + +Status MediaHandler::SetHandler(int output_stream_index, + std::shared_ptr handler) { + if (!ValidateOutputStreamIndex(output_stream_index)) + return Status(error::INVALID_ARGUMENT, "Invalid output stream index"); + if (output_handlers_.find(output_stream_index) != output_handlers_.end()) { + return Status(error::ALREADY_EXISTS, + "The handler at the specified index already exists."); + } + output_handlers_[output_stream_index] = + std::make_pair(handler, handler->num_input_streams_++); + next_output_stream_index_ = output_stream_index + 1; + return Status::OK; +} + +Status MediaHandler::FlushStream(int input_stream_index) { + // The default implementation treats the output stream index to be identical + // to the input stream index, which is true for most handlers. + auto handler_it = output_handlers_.find(input_stream_index); + if (handler_it == output_handlers_.end()) { + return Status(error::NOT_FOUND, + "No output handler exist at the specified index."); + } + return handler_it->second.first->FlushStream(handler_it->second.second); +} + +bool MediaHandler::ValidateOutputStreamIndex(int stream_index) const { + return stream_index >= 0 && stream_index < num_input_streams_; +} + +Status MediaHandler::Dispatch(std::unique_ptr stream_data) { + int output_stream_index = stream_data->stream_index; + auto handler_it = output_handlers_.find(output_stream_index); + if (handler_it == output_handlers_.end()) { + return Status(error::NOT_FOUND, + "No output handler exist at the specified index."); + } + stream_data->stream_index = handler_it->second.second; + return handler_it->second.first->Process(std::move(stream_data)); +} + +} // namespace media +} // namespace shaka diff --git a/packager/media/base/media_handler.h b/packager/media/base/media_handler.h new file mode 100644 index 0000000000..fc461ec857 --- /dev/null +++ b/packager/media/base/media_handler.h @@ -0,0 +1,169 @@ +// 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_MEDIA_HANDLER_H_ +#define PACKAGER_MEDIA_BASE_MEDIA_HANDLER_H_ + +#include +#include +#include + +#include "packager/media/base/status.h" + +namespace shaka { +namespace media { + +/// 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 encryptor handler. +/// 3) Single input multiple outputs +/// The input stream is splitted into multiple output streams. One example +/// of this is trick play 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(int output_stream_index, + std::shared_ptr handler); + + /// Connect downstream handler to the next availble output stream index. + Status AddHandler(std::shared_ptr handler) { + return SetHandler(next_output_stream_index_, handler); + } + + protected: + enum class StreamDataType { + kUnknown, + kPeriodInfo, + kStreamInfo, + kEncryptionConfig, + kMediaSample, + kMediaEvent, + kSegmentInfo, + }; + + // TODO(kqyang): Define these structures. + struct PeriodInfo {}; + struct StreamInfo {}; + struct EncryptionConfig {}; + struct MediaSample {}; + struct MediaEvent {}; + struct SegmentInfo {}; + + // TODO(kqyang): Should we use protobuf? + struct StreamData { + int stream_index; + StreamDataType stream_data_type; + + std::unique_ptr period_info; + std::unique_ptr stream_info; + std::unique_ptr encryption_config; + std::unique_ptr media_sample; + std::unique_ptr media_event; + std::unique_ptr segment_info; + }; + + /// 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; + + /// Flush the stream at the specified input stream index. + virtual Status FlushStream(int input_stream_index); + + /// Validate if the stream at the specified index actually exists. + virtual bool ValidateOutputStreamIndex(int 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); + + /// Dispatch the period info to downstream handlers. + Status DispatchPeriodInfo(int stream_index, + std::unique_ptr period_info) { + std::unique_ptr stream_data(new StreamData); + stream_data->stream_index = stream_index; + stream_data->period_info = std::move(period_info); + return Dispatch(std::move(stream_data)); + } + + /// Dispatch the stream info to downstream handlers. + Status DispatchStreamInfo(int stream_index, + std::unique_ptr stream_info) { + std::unique_ptr stream_data(new StreamData); + stream_data->stream_index = stream_index; + stream_data->stream_info = std::move(stream_info); + return Dispatch(std::move(stream_data)); + } + + /// Dispatch the encryption config to downstream handlers. + Status DispatchEncryptionConfig( + int stream_index, + std::unique_ptr encryption_config) { + std::unique_ptr stream_data(new StreamData); + stream_data->stream_index = stream_index; + stream_data->encryption_config = std::move(encryption_config); + return Dispatch(std::move(stream_data)); + } + + /// Dispatch the media sample to downstream handlers. + Status DispatchMediaSample(int stream_index, + std::unique_ptr media_sample) { + std::unique_ptr stream_data(new StreamData); + stream_data->stream_index = stream_index; + stream_data->media_sample = std::move(media_sample); + return Dispatch(std::move(stream_data)); + } + + /// Dispatch the media event to downstream handlers. + Status DispatchMediaEvent(int stream_index, + std::unique_ptr media_event) { + std::unique_ptr stream_data(new StreamData); + stream_data->stream_index = stream_index; + stream_data->media_event = std::move(media_event); + return Dispatch(std::move(stream_data)); + } + + /// Dispatch the segment info to downstream handlers. + Status DispatchSegmentInfo(int stream_index, + std::unique_ptr segment_info) { + std::unique_ptr stream_data(new StreamData); + stream_data->stream_index = stream_index; + stream_data->segment_info = std::move(segment_info); + return Dispatch(std::move(stream_data)); + } + + int num_input_streams() const { return num_input_streams_; } + + private: + MediaHandler(const MediaHandler&) = delete; + MediaHandler& operator=(const MediaHandler&) = delete; + + // Number of input streams. + int num_input_streams_ = 0; + // The next available output stream index, used by AddHandler. + int next_output_stream_index_ = 0; + // output stream index -> {output handler, output handler input stream index} + // map. + std::map, int>> output_handlers_; +}; + +} // namespace media +} // namespace shaka + +#endif // PACKAGER_MEDIA_BASE_MEDIA_HANDLER_H_ diff --git a/packager/media/base/status.h b/packager/media/base/status.h index bdb027c9ae..e1bfbbb133 100644 --- a/packager/media/base/status.h +++ b/packager/media/base/status.h @@ -68,6 +68,10 @@ enum Code { // Value was not found. NOT_FOUND, + + // The entity that a client attempted to create (e.g., file or directory) + // already exists. + ALREADY_EXISTS, }; } // namespace error