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