Shaka Packager SDK
Loading...
Searching...
No Matches
media_handler_test_base.cc
1// Copyright 2017 Google LLC. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd
6
7#include <packager/media/base/media_handler_test_base.h>
8
9#include <cctype>
10#include <cstddef>
11#include <cstdint>
12#include <memory>
13#include <string>
14#include <utility>
15#include <vector>
16
17#include <absl/log/check.h>
18#include <gmock/gmock.h>
19#include <gtest/gtest.h>
20
21#include <packager/macros/compiler.h>
22#include <packager/media/base/audio_stream_info.h>
23#include <packager/media/base/media_handler.h>
24#include <packager/media/base/media_sample.h>
25#include <packager/media/base/stream_info.h>
26#include <packager/media/base/text_sample.h>
27#include <packager/media/base/text_stream_info.h>
28#include <packager/media/base/video_stream_info.h>
29#include <packager/status.h>
30#include <packager/status/status_test_util.h>
31
32namespace {
33
34const int kTrackId = 1;
35const int64_t kDuration = 10000;
36const char kCodecString[] = "codec string";
37const uint8_t kSampleBits = 1;
38const uint8_t kNumChannels = 2;
39const uint32_t kSamplingFrequency = 48000;
40const uint64_t kSeekPrerollNs = 12345;
41const uint64_t kCodecDelayNs = 56789;
42const uint32_t kMaxBitrate = 13579;
43const uint32_t kAvgBitrate = 13000;
44const char kLanguage[] = "eng";
45const uint32_t kWidth = 10u;
46const uint32_t kHeight = 20u;
47const uint32_t kPixelWidth = 2u;
48const uint32_t kPixelHeight = 3u;
49const uint8_t kColorPrimaries = 0;
50const uint8_t kMatrixCoefficients = 0;
51const uint8_t kTransferCharacteristics = 0;
52
53const int16_t kTrickPlayFactor = 0;
54const uint8_t kNaluLengthSize = 1u;
55const bool kEncrypted = true;
56
57// Use H264 code config.
58const uint8_t kCodecConfig[]{
59 // clang-format off
60 // Header
61 0x01, 0x64, 0x00, 0x1e, 0xff,
62 // SPS count (ignore top three bits)
63 0xe1,
64 // SPS
65 0x00, 0x19, // Size
66 0x67, 0x64, 0x00, 0x1e, 0xac, 0xd9, 0x40, 0xa0, 0x2f, 0xf9, 0x70, 0x11,
67 0x00, 0x00, 0x03, 0x03, 0xe9, 0x00, 0x00, 0xea, 0x60, 0x0f, 0x16, 0x2d,
68 0x96,
69 // PPS count
70 0x01,
71 // PPS
72 0x00, 0x06, // Size
73 0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0,
74 // clang-format on
75};
76
77// Mock data, we don't really care about what is inside.
78const uint8_t kData[]{
79 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
80};
81
82} // namespace
83
84namespace shaka {
85namespace media {
86
87std::string BoolToString(bool value) {
88 return value ? "true" : "false";
89}
90
91bool TryMatchStreamDataType(const StreamDataType& actual,
92 const StreamDataType& expected,
93 ::testing::MatchResultListener* listener) {
94 if (actual != expected) {
95 std::string expected_as_string = StreamDataTypeToString(expected);
96 std::string actual_as_string = StreamDataTypeToString(actual);
97
98 *listener << "which is " << actual_as_string << " (expected "
99 << expected_as_string << ")";
100 return false;
101 }
102
103 return true;
104}
105
106bool TryMatchStreamType(const StreamType& actual,
107 const StreamType& expected,
108 ::testing::MatchResultListener* listener) {
109 if (actual != expected) {
110 std::string expected_as_string = StreamTypeToString(expected);
111 std::string actual_as_string = StreamTypeToString(actual);
112
113 *listener << "which is " << actual_as_string << " (expected "
114 << expected_as_string << ")";
115 return false;
116 }
117
118 return true;
119}
120
121std::string ToPrettyString(const std::string& str) {
122 std::string out;
123
124 // Opening quotation.
125 out.push_back('"');
126
127 for (char c : str) {
128 if (isspace(c)) {
129 // Make all white space characters spaces to avoid print issues in
130 // the terminal.
131 out.push_back(' ');
132 } else if (isalnum(c)) {
133 // If the character is alpha-numeric, then print it as is. Just using
134 // these characters, it should be enough to understand the string.
135 out.push_back(c);
136 } else {
137 // Replace all other characters with '.'. This is to avoid print issues
138 // (e.g. \n) or readability issues (e.g. ").
139 out.push_back('.');
140 }
141 }
142
143 // Closing quotation.
144 out.push_back('"');
145
146 return out;
147}
148
149bool FakeInputMediaHandler::ValidateOutputStreamIndex(size_t index) const {
150 UNUSED(index);
151 return true;
152}
153
154Status FakeInputMediaHandler::InitializeInternal() {
155 return Status::OK;
156}
157
158Status FakeInputMediaHandler::Process(std::unique_ptr<StreamData> stream_data) {
159 UNUSED(stream_data);
160 return Status(error::INTERNAL_ERROR,
161 "FakeInputMediaHandler should never be a downstream handler.");
162}
163
164Status MockOutputMediaHandler::InitializeInternal() {
165 return Status::OK;
166}
167
168Status MockOutputMediaHandler::Process(
169 std::unique_ptr<StreamData> stream_data) {
170 OnProcess(stream_data.get());
171 return Status::OK;
172}
173
174Status MockOutputMediaHandler::OnFlushRequest(size_t index) {
175 OnFlush(index);
176 return Status::OK;
177}
178
179Status CachingMediaHandler::InitializeInternal() {
180 return Status::OK;
181}
182
183Status CachingMediaHandler::Process(std::unique_ptr<StreamData> stream_data) {
184 stream_data_vector_.push_back(std::move(stream_data));
185 return Status::OK;
186}
187
188Status CachingMediaHandler::OnFlushRequest(size_t input_stream_index) {
189 UNUSED(input_stream_index);
190 return Status::OK;
191}
192
193bool CachingMediaHandler::ValidateOutputStreamIndex(size_t stream_index) const {
194 UNUSED(stream_index);
195 return true;
196}
197
198bool MediaHandlerTestBase::IsVideoCodec(Codec codec) const {
199 return codec >= kCodecVideo && codec < kCodecVideoMaxPlusOne;
200}
201
202std::unique_ptr<StreamInfo> MediaHandlerTestBase::GetVideoStreamInfo(
203 int32_t time_scale) const {
204 return GetVideoStreamInfo(time_scale, kCodecVP9, kWidth, kHeight);
205}
206
207std::unique_ptr<StreamInfo> MediaHandlerTestBase::GetVideoStreamInfo(
208 int32_t time_scale,
209 uint32_t width,
210 uint32_t height) const {
211 return GetVideoStreamInfo(time_scale, kCodecVP9, width, height);
212}
213
214std::unique_ptr<StreamInfo> MediaHandlerTestBase::GetVideoStreamInfo(
215 int32_t time_scale,
216 Codec codec) const {
217 return GetVideoStreamInfo(time_scale, codec, kWidth, kHeight);
218}
219
220std::unique_ptr<StreamInfo> MediaHandlerTestBase::GetVideoStreamInfo(
221 int32_t time_scale,
222 Codec codec,
223 uint32_t width,
224 uint32_t height) const {
225 return std::unique_ptr<VideoStreamInfo>(new VideoStreamInfo(
226 kTrackId, time_scale, kDuration, codec, H26xStreamFormat::kUnSpecified,
227 kCodecString, kCodecConfig, sizeof(kCodecConfig), width, height,
228 kPixelWidth, kPixelHeight, kColorPrimaries, kMatrixCoefficients,
229 kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
230 !kEncrypted));
231}
232
233std::unique_ptr<StreamInfo> MediaHandlerTestBase::GetAudioStreamInfo(
234 int32_t time_scale) const {
235 return GetAudioStreamInfo(time_scale, kCodecAAC);
236}
237
238std::unique_ptr<StreamInfo> MediaHandlerTestBase::GetAudioStreamInfo(
239 int32_t time_scale,
240 Codec codec) const {
241 return std::unique_ptr<AudioStreamInfo>(new AudioStreamInfo(
242 kTrackId, time_scale, kDuration, codec, kCodecString, kCodecConfig,
243 sizeof(kCodecConfig), kSampleBits, kNumChannels, kSamplingFrequency,
244 kSeekPrerollNs, kCodecDelayNs, kMaxBitrate, kAvgBitrate, kLanguage,
245 !kEncrypted));
246}
247
248std::shared_ptr<MediaSample> MediaHandlerTestBase::GetMediaSample(
249 int64_t timestamp,
250 int64_t duration,
251 bool is_keyframe) const {
252 return GetMediaSample(timestamp, duration, is_keyframe, kData, sizeof(kData));
253}
254
255std::shared_ptr<MediaSample> MediaHandlerTestBase::GetMediaSample(
256 int64_t timestamp,
257 int64_t duration,
258 bool is_keyframe,
259 const uint8_t* data,
260 size_t data_length) const {
261 std::shared_ptr<MediaSample> sample =
262 MediaSample::CopyFrom(data, data_length, nullptr, 0, is_keyframe);
263 sample->set_dts(timestamp);
264 sample->set_pts(timestamp);
265 sample->set_duration(duration);
266
267 return sample;
268}
269
270std::unique_ptr<SegmentInfo> MediaHandlerTestBase::GetSegmentInfo(
271 int64_t start_timestamp,
272 int64_t duration,
273 bool is_subsegment,
274 int64_t segment_number) const {
275 std::unique_ptr<SegmentInfo> info(new SegmentInfo);
276 info->start_timestamp = start_timestamp;
277 info->duration = duration;
278 info->is_subsegment = is_subsegment;
279 info->segment_number = segment_number;
280
281 return info;
282}
283
284std::unique_ptr<StreamInfo> MediaHandlerTestBase::GetTextStreamInfo(
285 int32_t timescale) const {
286 // None of this information is actually used by the text out handler.
287 // The stream info is just needed to signal the start of the stream.
288 return std::unique_ptr<StreamInfo>(
289 new TextStreamInfo(0, timescale, 0, kUnknownCodec, "", "", 0, 0, ""));
290}
291
292std::unique_ptr<TextSample> MediaHandlerTestBase::GetTextSample(
293 const std::string& id,
294 int64_t start,
295 int64_t end,
296 const std::string& payload) const {
297 return std::unique_ptr<TextSample>{
298 new TextSample(id, start, end, {}, TextFragment{{}, payload})};
299}
300
301std::unique_ptr<CueEvent> MediaHandlerTestBase::GetCueEvent(
302 double time_in_seconds) const {
303 std::unique_ptr<CueEvent> event(new CueEvent);
304 event->time_in_seconds = time_in_seconds;
305
306 return event;
307}
308
309Status MediaHandlerTestBase::SetUpAndInitializeGraph(
310 std::shared_ptr<MediaHandler> handler,
311 size_t input_count,
312 size_t output_count) {
313 DCHECK(handler);
314 DCHECK_EQ(nullptr, handler_);
315 DCHECK(inputs_.empty());
316 DCHECK(outputs_.empty());
317
318 handler_ = std::move(handler);
319
320 Status status;
321
322 // Add and connect all the requested inputs.
323 for (size_t i = 0; i < input_count; i++) {
324 inputs_.emplace_back(new FakeInputMediaHandler);
325 }
326
327 for (auto& input : inputs_) {
328 status.Update(input->AddHandler(handler_));
329 }
330
331 if (!status.ok()) {
332 return status;
333 }
334
335 // Add and connect all the requested outputs.
336 for (size_t i = 0; i < output_count; i++) {
337 outputs_.emplace_back(new testing::NiceMock<MockOutputMediaHandler>);
338 }
339
340 for (auto& output : outputs_) {
341 status.Update(handler_->AddHandler(output));
342 }
343
344 if (!status.ok()) {
345 return status;
346 }
347
348 // Initialize the graph.
349 for (auto& input : inputs_) {
350 status.Update(input->Initialize());
351 }
352
353 // In the case that there are no inputs, the start of the graph
354 // is at |handler_| so it needs to be initialized or else the graph
355 // won't be initialized.
356 if (inputs_.empty()) {
357 status.Update(handler_->Initialize());
358 }
359
360 return status;
361}
362
363FakeInputMediaHandler* MediaHandlerTestBase::Input(size_t index) {
364 DCHECK_LT(index, inputs_.size());
365 return inputs_[index].get();
366}
367
368MockOutputMediaHandler* MediaHandlerTestBase::Output(size_t index) {
369 DCHECK_LT(index, outputs_.size());
370 return outputs_[index].get();
371}
372
373MediaHandlerGraphTestBase::MediaHandlerGraphTestBase()
374 : next_handler_(new CachingMediaHandler),
375 some_handler_(new CachingMediaHandler) {}
376
377void MediaHandlerGraphTestBase::SetUpGraph(
378 size_t num_inputs,
379 size_t num_outputs,
380 std::shared_ptr<MediaHandler> handler) {
381 // Input handler is not really used anywhere else except to validate number of
382 // allowed inputs for the handler to be tested.
383 auto input_handler = std::make_shared<CachingMediaHandler>();
384 for (size_t i = 0; i < num_inputs; ++i)
385 ASSERT_OK(input_handler->SetHandler(i, handler));
386 // All outputs are routed to |next_handler_|.
387 for (size_t i = 0; i < num_outputs; ++i)
388 ASSERT_OK(handler->SetHandler(i, next_handler_));
389}
390
391const std::vector<std::unique_ptr<StreamData>>&
392MediaHandlerGraphTestBase::GetOutputStreamDataVector() const {
393 return next_handler_->Cache();
394}
395
396void MediaHandlerGraphTestBase::ClearOutputStreamDataVector() {
397 next_handler_->Clear();
398}
399
400} // namespace media
401} // namespace shaka
static std::shared_ptr< MediaSample > CopyFrom(const uint8_t *data, size_t size, bool is_key_frame)
All the methods that are virtual are virtual for mocking.