2017-01-23 22:51:00 +00:00
|
|
|
// 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 <map>
|
|
|
|
#include <memory>
|
|
|
|
#include <utility>
|
|
|
|
|
2017-02-02 18:28:29 +00:00
|
|
|
#include "packager/media/base/media_sample.h"
|
2017-01-23 22:51:00 +00:00
|
|
|
#include "packager/media/base/status.h"
|
2017-02-02 18:28:29 +00:00
|
|
|
#include "packager/media/base/stream_info.h"
|
2017-01-23 22:51:00 +00:00
|
|
|
|
|
|
|
namespace shaka {
|
|
|
|
namespace media {
|
|
|
|
|
2017-02-02 18:28:29 +00:00
|
|
|
enum class StreamDataType {
|
|
|
|
kUnknown,
|
|
|
|
kPeriodInfo,
|
|
|
|
kStreamInfo,
|
|
|
|
kEncryptionConfig,
|
|
|
|
kMediaSample,
|
|
|
|
kMediaEvent,
|
|
|
|
kSegmentInfo,
|
|
|
|
};
|
|
|
|
|
|
|
|
// TODO(kqyang): Define these structures.
|
|
|
|
struct PeriodInfo {};
|
|
|
|
struct EncryptionConfig {};
|
|
|
|
struct MediaEvent {};
|
|
|
|
struct SegmentInfo {
|
|
|
|
bool is_subsegment = false;
|
|
|
|
bool is_encrypted = false;
|
Implement ChunkingHandler
This handler is a multi-in multi-out handler. If more than one input is
provided, there should be one and only one video stream; also, all inputs
should come from the same thread and are synchronized.
There can be multiple chunking handler running in different threads or even
different processes, we use the "consistent chunking algorithm" to make sure
the chunks in different streams are aligned without explicit communcating
with each other - which is not efficient and often difficult.
Consistent Chunking Algorithm:
1. Find the consistent chunkable boundary
Let the timestamps for video frames be (t1, t2, t3, ...). Then a
consistent chunkable boundary is simply the first chunkable boundary after
(tk / N) != (tk-1 / N), where '/' denotes integer division, and N is the
intended chunk duration.
2. Chunk only at the consistent chunkable boundary
This algorithm will make sure the chunks from different video streams are
aligned if they have aligned GoPs. However, this algorithm will only work
for video streams. To be able to chunk non video streams at similar
positions as video streams, ChunkingHandler is designed to accept one video
input and multiple non video inputs, the non video inputs are chunked when
the video input is chunked. If the inputs are synchronized - which is true
if the inputs come from the same demuxer, the video and non video chunks
are aligned.
Change-Id: Id3bad51ab14f311efdb8713b6cd36d36cf9e4639
2017-02-07 18:58:47 +00:00
|
|
|
int64_t start_timestamp = -1;
|
|
|
|
int64_t duration = 0;
|
2017-02-02 18:28:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// TODO(kqyang): Should we use protobuf?
|
|
|
|
struct StreamData {
|
Implement ChunkingHandler
This handler is a multi-in multi-out handler. If more than one input is
provided, there should be one and only one video stream; also, all inputs
should come from the same thread and are synchronized.
There can be multiple chunking handler running in different threads or even
different processes, we use the "consistent chunking algorithm" to make sure
the chunks in different streams are aligned without explicit communcating
with each other - which is not efficient and often difficult.
Consistent Chunking Algorithm:
1. Find the consistent chunkable boundary
Let the timestamps for video frames be (t1, t2, t3, ...). Then a
consistent chunkable boundary is simply the first chunkable boundary after
(tk / N) != (tk-1 / N), where '/' denotes integer division, and N is the
intended chunk duration.
2. Chunk only at the consistent chunkable boundary
This algorithm will make sure the chunks from different video streams are
aligned if they have aligned GoPs. However, this algorithm will only work
for video streams. To be able to chunk non video streams at similar
positions as video streams, ChunkingHandler is designed to accept one video
input and multiple non video inputs, the non video inputs are chunked when
the video input is chunked. If the inputs are synchronized - which is true
if the inputs come from the same demuxer, the video and non video chunks
are aligned.
Change-Id: Id3bad51ab14f311efdb8713b6cd36d36cf9e4639
2017-02-07 18:58:47 +00:00
|
|
|
int stream_index = -1;
|
|
|
|
StreamDataType stream_data_type = StreamDataType::kUnknown;
|
2017-02-02 18:28:29 +00:00
|
|
|
|
2017-02-10 23:39:58 +00:00
|
|
|
std::shared_ptr<PeriodInfo> period_info;
|
|
|
|
std::shared_ptr<StreamInfo> stream_info;
|
|
|
|
std::shared_ptr<EncryptionConfig> encryption_config;
|
|
|
|
std::shared_ptr<MediaSample> media_sample;
|
|
|
|
std::shared_ptr<MediaEvent> media_event;
|
|
|
|
std::shared_ptr<SegmentInfo> segment_info;
|
2017-02-02 18:28:29 +00:00
|
|
|
};
|
|
|
|
|
2017-01-23 22:51:00 +00:00
|
|
|
/// 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<MediaHandler> handler);
|
|
|
|
|
|
|
|
/// Connect downstream handler to the next availble output stream index.
|
|
|
|
Status AddHandler(std::shared_ptr<MediaHandler> handler) {
|
|
|
|
return SetHandler(next_output_stream_index_, handler);
|
|
|
|
}
|
|
|
|
|
2017-02-02 18:28:29 +00:00
|
|
|
/// Initialize the handler and downstream handlers. Note that it should be
|
|
|
|
/// called after setting up the graph before running the graph.
|
|
|
|
Status Initialize();
|
|
|
|
|
2017-01-23 22:51:00 +00:00
|
|
|
protected:
|
2017-02-02 18:28:29 +00:00
|
|
|
/// Internal implementation of initialize. Note that it should only initialize
|
|
|
|
/// the MediaHandler itself. Downstream handlers are handled in Initialize().
|
|
|
|
virtual Status InitializeInternal() = 0;
|
2017-01-23 22:51:00 +00:00
|
|
|
|
|
|
|
/// 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<StreamData> 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;
|
|
|
|
|
2017-02-02 18:28:29 +00:00
|
|
|
bool initialized() { return initialized_; }
|
|
|
|
int num_input_streams() { return num_input_streams_; }
|
|
|
|
|
2017-01-23 22:51:00 +00:00
|
|
|
/// Dispatch the stream data to downstream handlers. Note that
|
|
|
|
/// stream_data.stream_index should be the output stream index.
|
|
|
|
Status Dispatch(std::unique_ptr<StreamData> stream_data);
|
|
|
|
|
|
|
|
/// Dispatch the period info to downstream handlers.
|
|
|
|
Status DispatchPeriodInfo(int stream_index,
|
2017-02-10 23:39:58 +00:00
|
|
|
std::shared_ptr<PeriodInfo> period_info) {
|
2017-01-23 22:51:00 +00:00
|
|
|
std::unique_ptr<StreamData> stream_data(new StreamData);
|
|
|
|
stream_data->stream_index = stream_index;
|
Implement ChunkingHandler
This handler is a multi-in multi-out handler. If more than one input is
provided, there should be one and only one video stream; also, all inputs
should come from the same thread and are synchronized.
There can be multiple chunking handler running in different threads or even
different processes, we use the "consistent chunking algorithm" to make sure
the chunks in different streams are aligned without explicit communcating
with each other - which is not efficient and often difficult.
Consistent Chunking Algorithm:
1. Find the consistent chunkable boundary
Let the timestamps for video frames be (t1, t2, t3, ...). Then a
consistent chunkable boundary is simply the first chunkable boundary after
(tk / N) != (tk-1 / N), where '/' denotes integer division, and N is the
intended chunk duration.
2. Chunk only at the consistent chunkable boundary
This algorithm will make sure the chunks from different video streams are
aligned if they have aligned GoPs. However, this algorithm will only work
for video streams. To be able to chunk non video streams at similar
positions as video streams, ChunkingHandler is designed to accept one video
input and multiple non video inputs, the non video inputs are chunked when
the video input is chunked. If the inputs are synchronized - which is true
if the inputs come from the same demuxer, the video and non video chunks
are aligned.
Change-Id: Id3bad51ab14f311efdb8713b6cd36d36cf9e4639
2017-02-07 18:58:47 +00:00
|
|
|
stream_data->stream_data_type = StreamDataType::kPeriodInfo;
|
2017-01-23 22:51:00 +00:00
|
|
|
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,
|
2017-02-10 23:39:58 +00:00
|
|
|
std::shared_ptr<StreamInfo> stream_info) {
|
2017-01-23 22:51:00 +00:00
|
|
|
std::unique_ptr<StreamData> stream_data(new StreamData);
|
|
|
|
stream_data->stream_index = stream_index;
|
Implement ChunkingHandler
This handler is a multi-in multi-out handler. If more than one input is
provided, there should be one and only one video stream; also, all inputs
should come from the same thread and are synchronized.
There can be multiple chunking handler running in different threads or even
different processes, we use the "consistent chunking algorithm" to make sure
the chunks in different streams are aligned without explicit communcating
with each other - which is not efficient and often difficult.
Consistent Chunking Algorithm:
1. Find the consistent chunkable boundary
Let the timestamps for video frames be (t1, t2, t3, ...). Then a
consistent chunkable boundary is simply the first chunkable boundary after
(tk / N) != (tk-1 / N), where '/' denotes integer division, and N is the
intended chunk duration.
2. Chunk only at the consistent chunkable boundary
This algorithm will make sure the chunks from different video streams are
aligned if they have aligned GoPs. However, this algorithm will only work
for video streams. To be able to chunk non video streams at similar
positions as video streams, ChunkingHandler is designed to accept one video
input and multiple non video inputs, the non video inputs are chunked when
the video input is chunked. If the inputs are synchronized - which is true
if the inputs come from the same demuxer, the video and non video chunks
are aligned.
Change-Id: Id3bad51ab14f311efdb8713b6cd36d36cf9e4639
2017-02-07 18:58:47 +00:00
|
|
|
stream_data->stream_data_type = StreamDataType::kStreamInfo;
|
2017-01-23 22:51:00 +00:00
|
|
|
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<EncryptionConfig> encryption_config) {
|
|
|
|
std::unique_ptr<StreamData> stream_data(new StreamData);
|
|
|
|
stream_data->stream_index = stream_index;
|
Implement ChunkingHandler
This handler is a multi-in multi-out handler. If more than one input is
provided, there should be one and only one video stream; also, all inputs
should come from the same thread and are synchronized.
There can be multiple chunking handler running in different threads or even
different processes, we use the "consistent chunking algorithm" to make sure
the chunks in different streams are aligned without explicit communcating
with each other - which is not efficient and often difficult.
Consistent Chunking Algorithm:
1. Find the consistent chunkable boundary
Let the timestamps for video frames be (t1, t2, t3, ...). Then a
consistent chunkable boundary is simply the first chunkable boundary after
(tk / N) != (tk-1 / N), where '/' denotes integer division, and N is the
intended chunk duration.
2. Chunk only at the consistent chunkable boundary
This algorithm will make sure the chunks from different video streams are
aligned if they have aligned GoPs. However, this algorithm will only work
for video streams. To be able to chunk non video streams at similar
positions as video streams, ChunkingHandler is designed to accept one video
input and multiple non video inputs, the non video inputs are chunked when
the video input is chunked. If the inputs are synchronized - which is true
if the inputs come from the same demuxer, the video and non video chunks
are aligned.
Change-Id: Id3bad51ab14f311efdb8713b6cd36d36cf9e4639
2017-02-07 18:58:47 +00:00
|
|
|
stream_data->stream_data_type = StreamDataType::kEncryptionConfig;
|
2017-01-23 22:51:00 +00:00
|
|
|
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,
|
2017-02-10 23:39:58 +00:00
|
|
|
std::shared_ptr<MediaSample> media_sample) {
|
2017-01-23 22:51:00 +00:00
|
|
|
std::unique_ptr<StreamData> stream_data(new StreamData);
|
|
|
|
stream_data->stream_index = stream_index;
|
Implement ChunkingHandler
This handler is a multi-in multi-out handler. If more than one input is
provided, there should be one and only one video stream; also, all inputs
should come from the same thread and are synchronized.
There can be multiple chunking handler running in different threads or even
different processes, we use the "consistent chunking algorithm" to make sure
the chunks in different streams are aligned without explicit communcating
with each other - which is not efficient and often difficult.
Consistent Chunking Algorithm:
1. Find the consistent chunkable boundary
Let the timestamps for video frames be (t1, t2, t3, ...). Then a
consistent chunkable boundary is simply the first chunkable boundary after
(tk / N) != (tk-1 / N), where '/' denotes integer division, and N is the
intended chunk duration.
2. Chunk only at the consistent chunkable boundary
This algorithm will make sure the chunks from different video streams are
aligned if they have aligned GoPs. However, this algorithm will only work
for video streams. To be able to chunk non video streams at similar
positions as video streams, ChunkingHandler is designed to accept one video
input and multiple non video inputs, the non video inputs are chunked when
the video input is chunked. If the inputs are synchronized - which is true
if the inputs come from the same demuxer, the video and non video chunks
are aligned.
Change-Id: Id3bad51ab14f311efdb8713b6cd36d36cf9e4639
2017-02-07 18:58:47 +00:00
|
|
|
stream_data->stream_data_type = StreamDataType::kMediaSample;
|
2017-01-23 22:51:00 +00:00
|
|
|
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,
|
2017-02-10 23:39:58 +00:00
|
|
|
std::shared_ptr<MediaEvent> media_event) {
|
2017-01-23 22:51:00 +00:00
|
|
|
std::unique_ptr<StreamData> stream_data(new StreamData);
|
|
|
|
stream_data->stream_index = stream_index;
|
Implement ChunkingHandler
This handler is a multi-in multi-out handler. If more than one input is
provided, there should be one and only one video stream; also, all inputs
should come from the same thread and are synchronized.
There can be multiple chunking handler running in different threads or even
different processes, we use the "consistent chunking algorithm" to make sure
the chunks in different streams are aligned without explicit communcating
with each other - which is not efficient and often difficult.
Consistent Chunking Algorithm:
1. Find the consistent chunkable boundary
Let the timestamps for video frames be (t1, t2, t3, ...). Then a
consistent chunkable boundary is simply the first chunkable boundary after
(tk / N) != (tk-1 / N), where '/' denotes integer division, and N is the
intended chunk duration.
2. Chunk only at the consistent chunkable boundary
This algorithm will make sure the chunks from different video streams are
aligned if they have aligned GoPs. However, this algorithm will only work
for video streams. To be able to chunk non video streams at similar
positions as video streams, ChunkingHandler is designed to accept one video
input and multiple non video inputs, the non video inputs are chunked when
the video input is chunked. If the inputs are synchronized - which is true
if the inputs come from the same demuxer, the video and non video chunks
are aligned.
Change-Id: Id3bad51ab14f311efdb8713b6cd36d36cf9e4639
2017-02-07 18:58:47 +00:00
|
|
|
stream_data->stream_data_type = StreamDataType::kMediaEvent;
|
2017-01-23 22:51:00 +00:00
|
|
|
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,
|
2017-02-10 23:39:58 +00:00
|
|
|
std::shared_ptr<SegmentInfo> segment_info) {
|
2017-01-23 22:51:00 +00:00
|
|
|
std::unique_ptr<StreamData> stream_data(new StreamData);
|
|
|
|
stream_data->stream_index = stream_index;
|
Implement ChunkingHandler
This handler is a multi-in multi-out handler. If more than one input is
provided, there should be one and only one video stream; also, all inputs
should come from the same thread and are synchronized.
There can be multiple chunking handler running in different threads or even
different processes, we use the "consistent chunking algorithm" to make sure
the chunks in different streams are aligned without explicit communcating
with each other - which is not efficient and often difficult.
Consistent Chunking Algorithm:
1. Find the consistent chunkable boundary
Let the timestamps for video frames be (t1, t2, t3, ...). Then a
consistent chunkable boundary is simply the first chunkable boundary after
(tk / N) != (tk-1 / N), where '/' denotes integer division, and N is the
intended chunk duration.
2. Chunk only at the consistent chunkable boundary
This algorithm will make sure the chunks from different video streams are
aligned if they have aligned GoPs. However, this algorithm will only work
for video streams. To be able to chunk non video streams at similar
positions as video streams, ChunkingHandler is designed to accept one video
input and multiple non video inputs, the non video inputs are chunked when
the video input is chunked. If the inputs are synchronized - which is true
if the inputs come from the same demuxer, the video and non video chunks
are aligned.
Change-Id: Id3bad51ab14f311efdb8713b6cd36d36cf9e4639
2017-02-07 18:58:47 +00:00
|
|
|
stream_data->stream_data_type = StreamDataType::kSegmentInfo;
|
2017-01-23 22:51:00 +00:00
|
|
|
stream_data->segment_info = std::move(segment_info);
|
|
|
|
return Dispatch(std::move(stream_data));
|
|
|
|
}
|
|
|
|
|
|
|
|
int num_input_streams() const { return num_input_streams_; }
|
2017-02-02 18:28:29 +00:00
|
|
|
int next_output_stream_index() const { return next_output_stream_index_; }
|
2017-01-23 22:51:00 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
MediaHandler(const MediaHandler&) = delete;
|
|
|
|
MediaHandler& operator=(const MediaHandler&) = delete;
|
|
|
|
|
2017-02-02 18:28:29 +00:00
|
|
|
bool initialized_ = false;
|
2017-01-23 22:51:00 +00:00
|
|
|
// 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, std::pair<std::shared_ptr<MediaHandler>, int>> output_handlers_;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace media
|
|
|
|
} // namespace shaka
|
|
|
|
|
|
|
|
#endif // PACKAGER_MEDIA_BASE_MEDIA_HANDLER_H_
|