2023-05-01 21:57:40 +00:00
|
|
|
// Copyright 2022 Google LLC. All rights reserved.
|
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
|
|
|
//
|
|
|
|
// 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
|
|
|
|
|
2018-01-03 00:10:33 +00:00
|
|
|
#ifndef PACKAGER_MEDIA_BASE_MEDIA_HANDLER_TEST_BASE_H_
|
|
|
|
#define PACKAGER_MEDIA_BASE_MEDIA_HANDLER_TEST_BASE_H_
|
|
|
|
|
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
|
|
|
#include <gmock/gmock.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
2023-10-09 23:21:41 +00:00
|
|
|
#include <absl/strings/escaping.h>
|
|
|
|
#include <absl/strings/numbers.h>
|
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
|
|
|
#include "packager/media/base/media_handler.h"
|
2018-06-19 16:53:50 +00:00
|
|
|
#include "packager/media/base/video_stream_info.h"
|
2023-05-01 21:57:40 +00:00
|
|
|
#include "packager/utils/bytes_to_string_view.h"
|
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
|
|
|
|
|
|
|
namespace shaka {
|
|
|
|
namespace media {
|
|
|
|
|
2018-01-03 00:10:33 +00:00
|
|
|
std::string BoolToString(bool value);
|
2018-05-25 17:41:02 +00:00
|
|
|
std::string ToPrettyString(const std::string& str);
|
|
|
|
|
|
|
|
bool TryMatchStreamDataType(const StreamDataType& actual,
|
|
|
|
const StreamDataType& expected,
|
|
|
|
::testing::MatchResultListener* listener);
|
|
|
|
|
2018-06-19 16:53:50 +00:00
|
|
|
bool TryMatchStreamType(const StreamType& actual,
|
|
|
|
const StreamType& expected,
|
|
|
|
::testing::MatchResultListener* listener);
|
|
|
|
|
2018-05-25 17:41:02 +00:00
|
|
|
template <typename T, typename M>
|
|
|
|
bool TryMatch(const T& value,
|
|
|
|
const M& matcher,
|
|
|
|
::testing::MatchResultListener* listener,
|
|
|
|
const char* value_name) {
|
|
|
|
if (!ExplainMatchResult(matcher, value, listener)) {
|
|
|
|
// Need a space at the start of the string in the case that
|
|
|
|
// it gets combined with another string.
|
|
|
|
*listener << " Mismatch on " << value_name;
|
2018-01-03 00:10:33 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-05-25 17:41:02 +00:00
|
|
|
return true;
|
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
|
|
|
}
|
|
|
|
|
2020-06-01 22:26:31 +00:00
|
|
|
MATCHER_P(IsPsshInfoWithSystemId,
|
|
|
|
system_id,
|
|
|
|
std::string(negation ? "doesn't " : "") + " have system ID " +
|
|
|
|
testing::PrintToString(system_id)) {
|
|
|
|
*result_listener << "which is (" << testing::PrintToString(arg.system_id)
|
|
|
|
<< ")";
|
|
|
|
return arg.system_id == system_id;
|
|
|
|
}
|
|
|
|
|
2018-02-08 02:28:51 +00:00
|
|
|
MATCHER_P4(IsStreamInfo, stream_index, time_scale, encrypted, language, "") {
|
2018-05-25 17:41:02 +00:00
|
|
|
if (!TryMatchStreamDataType(arg->stream_data_type,
|
|
|
|
StreamDataType::kStreamInfo, result_listener)) {
|
2018-02-08 02:28:51 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-05-25 17:41:02 +00:00
|
|
|
const std::string is_encrypted_string =
|
|
|
|
BoolToString(arg->stream_info->is_encrypted());
|
|
|
|
|
|
|
|
*result_listener << "which is (" << arg->stream_index << ", "
|
|
|
|
<< arg->stream_info->time_scale() << ", "
|
|
|
|
<< is_encrypted_string << ", "
|
2018-02-08 02:28:51 +00:00
|
|
|
<< arg->stream_info->language() << ")";
|
2018-05-25 17:41:02 +00:00
|
|
|
|
|
|
|
return TryMatch(arg->stream_index, stream_index, result_listener,
|
|
|
|
"stream_index") &&
|
|
|
|
TryMatch(arg->stream_info->time_scale(), time_scale, result_listener,
|
|
|
|
"time_scale") &&
|
|
|
|
TryMatch(arg->stream_info->is_encrypted(), encrypted, result_listener,
|
|
|
|
"is_encrypted") &&
|
|
|
|
TryMatch(arg->stream_info->language(), language, result_listener,
|
|
|
|
"language");
|
2018-02-08 02:28:51 +00:00
|
|
|
}
|
|
|
|
|
2018-06-19 16:53:50 +00:00
|
|
|
MATCHER_P3(IsVideoStream, stream_index, trick_play_factor, playback_rate, "") {
|
|
|
|
if (!TryMatchStreamDataType(arg->stream_data_type,
|
|
|
|
StreamDataType::kStreamInfo, result_listener)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!TryMatchStreamType(arg->stream_info->stream_type(), kStreamVideo,
|
|
|
|
result_listener)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const VideoStreamInfo* info =
|
|
|
|
static_cast<const VideoStreamInfo*>(arg->stream_info.get());
|
|
|
|
|
|
|
|
*result_listener << "which is (" << arg->stream_index << ", "
|
|
|
|
<< info->trick_play_factor() << ", " << info->playback_rate()
|
|
|
|
<< ")";
|
|
|
|
|
|
|
|
return TryMatch(arg->stream_index, stream_index, result_listener,
|
|
|
|
"stream_index") &&
|
|
|
|
TryMatch(info->trick_play_factor(), trick_play_factor, result_listener,
|
|
|
|
"trick_play_factor") &&
|
|
|
|
TryMatch(info->playback_rate(), playback_rate, result_listener,
|
|
|
|
"playback_rate");
|
|
|
|
}
|
|
|
|
|
2017-03-11 02:48:04 +00:00
|
|
|
MATCHER_P5(IsSegmentInfo,
|
|
|
|
stream_index,
|
|
|
|
start_timestamp,
|
|
|
|
duration,
|
|
|
|
subsegment,
|
|
|
|
encrypted,
|
|
|
|
"") {
|
2018-05-25 17:41:02 +00:00
|
|
|
if (!TryMatchStreamDataType(arg->stream_data_type,
|
|
|
|
StreamDataType::kSegmentInfo, result_listener)) {
|
2018-01-03 00:10:33 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-05-25 17:41:02 +00:00
|
|
|
const std::string is_subsegment_string =
|
|
|
|
BoolToString(arg->segment_info->is_subsegment);
|
|
|
|
const std::string is_encrypted_string =
|
|
|
|
BoolToString(arg->segment_info->is_encrypted);
|
|
|
|
|
|
|
|
*result_listener << "which is (" << arg->stream_index << ", "
|
|
|
|
<< arg->segment_info->start_timestamp << ", "
|
|
|
|
<< arg->segment_info->duration << ", "
|
|
|
|
<< is_subsegment_string << ", " << is_encrypted_string
|
|
|
|
<< ")";
|
|
|
|
|
|
|
|
return TryMatch(arg->stream_index, stream_index, result_listener,
|
|
|
|
"stream_index") &&
|
|
|
|
TryMatch(arg->segment_info->start_timestamp, start_timestamp,
|
|
|
|
result_listener, "start_timestamp") &&
|
|
|
|
TryMatch(arg->segment_info->duration, duration, result_listener,
|
|
|
|
"duration") &&
|
|
|
|
TryMatch(arg->segment_info->is_subsegment, subsegment, result_listener,
|
|
|
|
"is_subsegment") &&
|
|
|
|
TryMatch(arg->segment_info->is_encrypted, encrypted, result_listener,
|
|
|
|
"is_encrypted");
|
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
|
|
|
}
|
|
|
|
|
2017-03-11 02:48:04 +00:00
|
|
|
MATCHER_P6(MatchEncryptionConfig,
|
|
|
|
protection_scheme,
|
|
|
|
crypt_byte_block,
|
|
|
|
skip_byte_block,
|
|
|
|
per_sample_iv_size,
|
|
|
|
constant_iv,
|
|
|
|
key_id,
|
|
|
|
"") {
|
2023-07-14 15:19:01 +00:00
|
|
|
const std::string constant_iv_hex = absl::BytesToHexString(
|
|
|
|
std::string(std::begin(arg.constant_iv), std::end(arg.constant_iv)));
|
|
|
|
const std::string key_id_hex = absl::BytesToHexString(
|
|
|
|
std::string(std::begin(arg.key_id), std::end(arg.key_id)));
|
2018-05-25 17:41:02 +00:00
|
|
|
const std::string protection_scheme_as_string =
|
|
|
|
FourCCToString(arg.protection_scheme);
|
|
|
|
// Convert to integers so that they will print as a number and not a uint8_t
|
|
|
|
// (char).
|
|
|
|
const int crypt_byte_as_int = static_cast<int>(arg.crypt_byte_block);
|
|
|
|
const int skip_byte_as_int = static_cast<int>(arg.skip_byte_block);
|
|
|
|
|
|
|
|
*result_listener << "which is (" << protection_scheme_as_string << ", "
|
|
|
|
<< crypt_byte_as_int << ", " << skip_byte_as_int << ", "
|
|
|
|
<< arg.per_sample_iv_size << ", " << constant_iv_hex << ", "
|
|
|
|
<< key_id_hex << ")";
|
|
|
|
|
|
|
|
return TryMatch(arg.protection_scheme, protection_scheme, result_listener,
|
|
|
|
"protection_scheme") &&
|
|
|
|
TryMatch(arg.crypt_byte_block, crypt_byte_block, result_listener,
|
|
|
|
"crypt_byte_block") &&
|
|
|
|
TryMatch(arg.skip_byte_block, skip_byte_block, result_listener,
|
|
|
|
"skip_byte_block") &&
|
|
|
|
TryMatch(arg.per_sample_iv_size, per_sample_iv_size, result_listener,
|
|
|
|
"per_sample_iv_size") &&
|
|
|
|
TryMatch(arg.constant_iv, constant_iv, result_listener,
|
|
|
|
"constant_iv") &&
|
|
|
|
TryMatch(arg.key_id, key_id, result_listener, "key_id");
|
2017-03-11 02:48:04 +00:00
|
|
|
}
|
|
|
|
|
2018-06-14 23:39:59 +00:00
|
|
|
MATCHER_P5(IsMediaSample,
|
|
|
|
stream_index,
|
|
|
|
timestamp,
|
|
|
|
duration,
|
|
|
|
encrypted,
|
|
|
|
keyframe,
|
|
|
|
"") {
|
2018-05-25 17:41:02 +00:00
|
|
|
if (!TryMatchStreamDataType(arg->stream_data_type,
|
|
|
|
StreamDataType::kMediaSample, result_listener)) {
|
2018-01-03 00:10:33 +00:00
|
|
|
return false;
|
|
|
|
}
|
2018-05-25 17:41:02 +00:00
|
|
|
|
|
|
|
const std::string is_encrypted_string =
|
|
|
|
BoolToString(arg->media_sample->is_encrypted());
|
2018-06-14 23:39:59 +00:00
|
|
|
const std::string is_key_frame_string =
|
|
|
|
BoolToString(arg->media_sample->is_key_frame());
|
2018-05-25 17:41:02 +00:00
|
|
|
|
|
|
|
*result_listener << "which is (" << arg->stream_index << ", "
|
|
|
|
<< arg->media_sample->dts() << ", "
|
|
|
|
<< arg->media_sample->duration() << ", "
|
2018-06-14 23:39:59 +00:00
|
|
|
<< is_encrypted_string << ", " << is_key_frame_string << ")";
|
2018-05-25 17:41:02 +00:00
|
|
|
|
|
|
|
return TryMatch(arg->stream_index, stream_index, result_listener,
|
|
|
|
"stream_index") &&
|
|
|
|
TryMatch(arg->media_sample->dts(), timestamp, result_listener,
|
|
|
|
"dts") &&
|
|
|
|
TryMatch(arg->media_sample->duration(), duration, result_listener,
|
|
|
|
"duration") &&
|
|
|
|
TryMatch(arg->media_sample->is_encrypted(), encrypted, result_listener,
|
2018-06-14 23:39:59 +00:00
|
|
|
"is_encrypted") &&
|
|
|
|
TryMatch(arg->media_sample->is_key_frame(), keyframe, result_listener,
|
|
|
|
"is_key_frame");
|
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
|
|
|
}
|
|
|
|
|
2020-08-24 22:23:15 +00:00
|
|
|
MATCHER_P4(IsTextSample, stream_index, id, start_time, end_time, "") {
|
2018-05-25 17:41:02 +00:00
|
|
|
if (!TryMatchStreamDataType(arg->stream_data_type,
|
|
|
|
StreamDataType::kTextSample, result_listener)) {
|
2018-01-03 00:10:33 +00:00
|
|
|
return false;
|
|
|
|
}
|
2018-05-25 17:41:02 +00:00
|
|
|
|
|
|
|
*result_listener << "which is (" << arg->stream_index << ", "
|
|
|
|
<< ToPrettyString(arg->text_sample->id()) << ", "
|
|
|
|
<< arg->text_sample->start_time() << ", "
|
2020-08-24 22:23:15 +00:00
|
|
|
<< arg->text_sample->EndTime() << ")";
|
2018-05-25 17:41:02 +00:00
|
|
|
|
|
|
|
return TryMatch(arg->stream_index, stream_index, result_listener,
|
|
|
|
"stream_index") &&
|
|
|
|
TryMatch(arg->text_sample->id(), id, result_listener, "id") &&
|
|
|
|
TryMatch(arg->text_sample->start_time(), start_time, result_listener,
|
|
|
|
"start_time") &&
|
|
|
|
TryMatch(arg->text_sample->EndTime(), end_time, result_listener,
|
2020-08-24 22:23:15 +00:00
|
|
|
"EndTime");
|
2017-09-18 15:47:00 +00:00
|
|
|
}
|
|
|
|
|
2018-03-15 23:01:47 +00:00
|
|
|
MATCHER_P2(IsCueEvent, stream_index, time_in_seconds, "") {
|
2018-05-25 17:41:02 +00:00
|
|
|
if (!TryMatchStreamDataType(arg->stream_data_type, StreamDataType::kCueEvent,
|
|
|
|
result_listener)) {
|
2018-01-03 00:10:33 +00:00
|
|
|
return false;
|
|
|
|
}
|
2018-05-25 17:41:02 +00:00
|
|
|
|
|
|
|
*result_listener << "which is (" << arg->stream_index << ", "
|
2018-03-15 23:01:47 +00:00
|
|
|
<< arg->cue_event->time_in_seconds << ")";
|
2018-05-25 17:41:02 +00:00
|
|
|
|
|
|
|
return TryMatch(arg->stream_index, stream_index, result_listener,
|
|
|
|
"stream_index") &&
|
|
|
|
TryMatch(arg->cue_event->time_in_seconds, time_in_seconds,
|
|
|
|
result_listener, "time_in_seconds");
|
2018-01-03 00:10:33 +00:00
|
|
|
}
|
|
|
|
|
2017-09-14 16:23:29 +00:00
|
|
|
class FakeInputMediaHandler : public MediaHandler {
|
|
|
|
public:
|
|
|
|
using MediaHandler::Dispatch;
|
|
|
|
using MediaHandler::FlushAllDownstreams;
|
|
|
|
using MediaHandler::FlushDownstream;
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool ValidateOutputStreamIndex(size_t index) const override;
|
|
|
|
Status InitializeInternal() override;
|
|
|
|
Status Process(std::unique_ptr<StreamData> stream_data) override;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MockOutputMediaHandler : public MediaHandler {
|
|
|
|
public:
|
|
|
|
MOCK_METHOD1(OnProcess, void(const StreamData*));
|
|
|
|
MOCK_METHOD1(OnFlush, void(size_t index));
|
|
|
|
|
|
|
|
private:
|
|
|
|
Status InitializeInternal() override;
|
|
|
|
Status Process(std::unique_ptr<StreamData> stream_data) override;
|
|
|
|
Status OnFlushRequest(size_t index) override;
|
|
|
|
};
|
|
|
|
|
2018-06-20 23:13:15 +00:00
|
|
|
class CachingMediaHandler : public MediaHandler {
|
2017-03-21 23:14:46 +00:00
|
|
|
public:
|
2018-06-20 23:13:15 +00:00
|
|
|
const std::vector<std::unique_ptr<StreamData>>& Cache() const {
|
2017-03-21 23:14:46 +00:00
|
|
|
return stream_data_vector_;
|
|
|
|
}
|
|
|
|
|
2018-06-20 23:13:15 +00:00
|
|
|
// TODO(vaage) : Remove the use of clear in our tests as it can make flow
|
|
|
|
// of the test harder to understand.
|
|
|
|
void Clear() { stream_data_vector_.clear(); }
|
|
|
|
|
|
|
|
private:
|
2017-03-21 23:14:46 +00:00
|
|
|
Status InitializeInternal() override;
|
|
|
|
Status Process(std::unique_ptr<StreamData> stream_data) override;
|
|
|
|
Status OnFlushRequest(size_t input_stream_index) override;
|
|
|
|
bool ValidateOutputStreamIndex(size_t stream_index) const override;
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<StreamData>> stream_data_vector_;
|
|
|
|
};
|
|
|
|
|
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
|
|
|
class MediaHandlerTestBase : public ::testing::Test {
|
|
|
|
public:
|
2017-09-14 16:23:29 +00:00
|
|
|
MediaHandlerTestBase() = default;
|
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
|
|
|
|
2017-09-14 16:23:29 +00:00
|
|
|
protected:
|
2017-09-12 17:24:24 +00:00
|
|
|
bool IsVideoCodec(Codec codec) const;
|
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
|
|
|
|
2021-08-04 18:56:44 +00:00
|
|
|
std::unique_ptr<StreamInfo> GetVideoStreamInfo(int32_t time_scale) const;
|
2017-09-14 16:23:29 +00:00
|
|
|
|
2021-08-04 18:56:44 +00:00
|
|
|
std::unique_ptr<StreamInfo> GetVideoStreamInfo(int32_t time_scale,
|
2017-09-14 16:23:29 +00:00
|
|
|
uint32_t width,
|
2022-11-04 22:46:41 +00:00
|
|
|
uint32_t height) const;
|
2017-09-12 17:24:24 +00:00
|
|
|
|
2021-08-04 18:56:44 +00:00
|
|
|
std::unique_ptr<StreamInfo> GetVideoStreamInfo(int32_t time_scale,
|
2017-09-14 16:23:29 +00:00
|
|
|
Codec codec) const;
|
2017-09-12 17:24:24 +00:00
|
|
|
|
2021-08-04 18:56:44 +00:00
|
|
|
std::unique_ptr<StreamInfo> GetVideoStreamInfo(int32_t time_scale,
|
2017-09-14 16:23:29 +00:00
|
|
|
Codec codec,
|
|
|
|
uint32_t width,
|
2022-11-04 22:46:41 +00:00
|
|
|
uint32_t height) const;
|
2017-09-12 17:24:24 +00:00
|
|
|
|
2021-08-04 18:56:44 +00:00
|
|
|
std::unique_ptr<StreamInfo> GetAudioStreamInfo(int32_t time_scale) const;
|
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
|
|
|
|
2021-08-04 18:56:44 +00:00
|
|
|
std::unique_ptr<StreamInfo> GetAudioStreamInfo(int32_t time_scale,
|
2017-09-14 16:23:29 +00:00
|
|
|
Codec codec) const;
|
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
|
|
|
|
2017-09-18 23:31:00 +00:00
|
|
|
std::shared_ptr<MediaSample> GetMediaSample(int64_t timestamp,
|
2017-09-14 16:23:29 +00:00
|
|
|
int64_t duration,
|
|
|
|
bool is_keyframe) const;
|
2017-09-12 17:24:24 +00:00
|
|
|
|
2017-09-18 23:31:00 +00:00
|
|
|
std::shared_ptr<MediaSample> GetMediaSample(int64_t timestamp,
|
2017-09-14 16:23:29 +00:00
|
|
|
int64_t duration,
|
|
|
|
bool is_keyframe,
|
|
|
|
const uint8_t* data,
|
|
|
|
size_t data_length) const;
|
2017-09-12 17:24:24 +00:00
|
|
|
|
2017-09-14 16:23:29 +00:00
|
|
|
std::unique_ptr<SegmentInfo> GetSegmentInfo(int64_t start_timestamp,
|
|
|
|
int64_t duration,
|
|
|
|
bool is_subsegment) const;
|
2017-09-12 17:24:24 +00:00
|
|
|
|
2021-08-04 18:56:44 +00:00
|
|
|
std::unique_ptr<StreamInfo> GetTextStreamInfo(int32_t timescale) const;
|
2017-09-18 15:47:00 +00:00
|
|
|
|
|
|
|
std::unique_ptr<TextSample> GetTextSample(const std::string& id,
|
2018-03-26 18:04:09 +00:00
|
|
|
int64_t start,
|
|
|
|
int64_t end,
|
2017-09-18 15:47:00 +00:00
|
|
|
const std::string& payload) const;
|
|
|
|
|
2018-03-26 18:04:09 +00:00
|
|
|
std::unique_ptr<CueEvent> GetCueEvent(double time_in_seconds) const;
|
|
|
|
|
2017-09-26 16:00:33 +00:00
|
|
|
// Connect and initialize all handlers.
|
|
|
|
Status SetUpAndInitializeGraph(std::shared_ptr<MediaHandler> handler,
|
|
|
|
size_t input_count,
|
|
|
|
size_t output_count);
|
|
|
|
|
|
|
|
// Get the input handler at |index|. The values of |index| will match the
|
|
|
|
// call to |AddInput|.
|
|
|
|
FakeInputMediaHandler* Input(size_t index);
|
|
|
|
|
|
|
|
// Get the output handler at |index|. The values of |index| will match the
|
|
|
|
// call to |AddOutput|.
|
|
|
|
MockOutputMediaHandler* Output(size_t index);
|
|
|
|
|
2017-09-14 16:23:29 +00:00
|
|
|
private:
|
|
|
|
MediaHandlerTestBase(const MediaHandlerTestBase&) = delete;
|
|
|
|
MediaHandlerTestBase& operator=(const MediaHandlerTestBase&) = delete;
|
2017-09-26 16:00:33 +00:00
|
|
|
|
|
|
|
std::shared_ptr<MediaHandler> handler_;
|
|
|
|
|
|
|
|
std::vector<std::shared_ptr<FakeInputMediaHandler>> inputs_;
|
|
|
|
std::vector<std::shared_ptr<MockOutputMediaHandler>> outputs_;
|
2017-09-14 16:23:29 +00:00
|
|
|
};
|
2017-03-11 02:48:04 +00:00
|
|
|
|
2017-09-14 16:23:29 +00:00
|
|
|
class MediaHandlerGraphTestBase : public MediaHandlerTestBase {
|
|
|
|
public:
|
|
|
|
MediaHandlerGraphTestBase();
|
|
|
|
|
|
|
|
protected:
|
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
|
|
|
/// Setup a graph using |handler| with |num_inputs| and |num_outputs|.
|
2017-03-28 06:04:29 +00:00
|
|
|
void SetUpGraph(size_t num_inputs,
|
|
|
|
size_t num_outputs,
|
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
|
|
|
std::shared_ptr<MediaHandler> handler);
|
|
|
|
|
2017-03-11 02:48:04 +00:00
|
|
|
/// @return the output stream data vector from handler.
|
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
|
|
|
const std::vector<std::unique_ptr<StreamData>>& GetOutputStreamDataVector()
|
|
|
|
const;
|
|
|
|
|
|
|
|
/// Clear the output stream data vector.
|
|
|
|
void ClearOutputStreamDataVector();
|
|
|
|
|
|
|
|
/// @return some random handler that can be used for testing.
|
|
|
|
std::shared_ptr<MediaHandler> some_handler() { return some_handler_; }
|
|
|
|
|
2017-03-21 23:14:46 +00:00
|
|
|
/// @return some a downstream handler that can be used for connecting.
|
2018-06-20 23:13:15 +00:00
|
|
|
std::shared_ptr<CachingMediaHandler> next_handler() { return next_handler_; }
|
2017-03-21 23:14:46 +00:00
|
|
|
|
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
|
|
|
private:
|
2018-06-20 23:26:35 +00:00
|
|
|
MediaHandlerGraphTestBase(const MediaHandlerGraphTestBase&) = delete;
|
|
|
|
MediaHandlerGraphTestBase& operator=(const MediaHandlerGraphTestBase&) =
|
|
|
|
delete;
|
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
|
|
|
|
|
|
|
// Downstream handler used in testing graph.
|
2018-06-20 23:13:15 +00:00
|
|
|
std::shared_ptr<CachingMediaHandler> next_handler_;
|
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
|
|
|
// Some random handler which can be used for testing.
|
|
|
|
std::shared_ptr<MediaHandler> some_handler_;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace media
|
|
|
|
} // namespace shaka
|
2018-01-03 00:10:33 +00:00
|
|
|
|
|
|
|
#endif // PACKAGER_MEDIA_BASE_MEDIA_HANDLER_TEST_BASE_H_
|