1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "FrameReassembler.h"
18
19 #include <gtest/gtest.h>
20
21 #include <C2PlatformSupport.h>
22
23 #include <media/stagefright/foundation/ABuffer.h>
24 #include <media/stagefright/foundation/AMessage.h>
25
26 namespace android {
27
BytesPerSample(C2Config::pcm_encoding_t encoding)28 static size_t BytesPerSample(C2Config::pcm_encoding_t encoding) {
29 return encoding == PCM_8 ? 1
30 : encoding == PCM_16 ? 2
31 : encoding == PCM_FLOAT ? 4 : 0;
32 }
33
Diff(c2_cntr64_t a,c2_cntr64_t b)34 static uint64_t Diff(c2_cntr64_t a, c2_cntr64_t b) {
35 return std::abs((a - b).peek());
36 }
37
38 class FrameReassemblerTest : public ::testing::Test {
39 public:
40 static const C2MemoryUsage kUsage;
41 static constexpr uint64_t kTimestampToleranceUs = 100;
42
FrameReassemblerTest()43 FrameReassemblerTest() {
44 mInitStatus = GetCodec2BlockPool(C2BlockPool::BASIC_LINEAR, nullptr, &mPool);
45 }
46
initStatus() const47 status_t initStatus() const { return mInitStatus; }
48
testPushSameSize(size_t encoderFrameSize,size_t sampleRate,size_t channelCount,C2Config::pcm_encoding_t encoding,size_t inputFrameSizeInBytes,size_t count,size_t expectedOutputSize,bool separateEos)49 void testPushSameSize(
50 size_t encoderFrameSize,
51 size_t sampleRate,
52 size_t channelCount,
53 C2Config::pcm_encoding_t encoding,
54 size_t inputFrameSizeInBytes,
55 size_t count,
56 size_t expectedOutputSize,
57 bool separateEos) {
58 FrameReassembler frameReassembler;
59 frameReassembler.init(
60 mPool,
61 kUsage,
62 encoderFrameSize,
63 sampleRate,
64 channelCount,
65 encoding);
66
67 ASSERT_TRUE(frameReassembler) << "FrameReassembler init failed";
68
69 size_t inputIndex = 0, outputIndex = 0;
70 size_t expectCount = 0;
71 for (size_t i = 0; i < count + (separateEos ? 1 : 0); ++i) {
72 sp<MediaCodecBuffer> buffer = new MediaCodecBuffer(
73 new AMessage, new ABuffer(inputFrameSizeInBytes));
74 buffer->setRange(0, inputFrameSizeInBytes);
75 buffer->meta()->setInt64(
76 "timeUs",
77 inputIndex * 1000000 / sampleRate / channelCount / BytesPerSample(encoding));
78 if (i == count - 1) {
79 buffer->meta()->setInt32("eos", 1);
80 }
81 if (i == count && separateEos) {
82 buffer->setRange(0, 0);
83 } else {
84 for (size_t j = 0; j < inputFrameSizeInBytes; ++j, ++inputIndex) {
85 buffer->base()[j] = (inputIndex & 0xFF);
86 }
87 }
88 std::list<std::unique_ptr<C2Work>> items;
89 ASSERT_EQ(C2_OK, frameReassembler.process(buffer, &items));
90 while (!items.empty()) {
91 std::unique_ptr<C2Work> work = std::move(*items.begin());
92 items.erase(items.begin());
93 // Verify timestamp
94 uint64_t expectedTimeUs =
95 outputIndex * 1000000 / sampleRate / channelCount / BytesPerSample(encoding);
96 EXPECT_GE(
97 kTimestampToleranceUs,
98 Diff(expectedTimeUs, work->input.ordinal.timestamp))
99 << "expected timestamp: " << expectedTimeUs
100 << " actual timestamp: " << work->input.ordinal.timestamp.peeku()
101 << " output index: " << outputIndex;
102
103 // Verify buffer
104 ASSERT_EQ(1u, work->input.buffers.size());
105 std::shared_ptr<C2Buffer> buffer = work->input.buffers.front();
106 ASSERT_EQ(C2BufferData::LINEAR, buffer->data().type());
107 ASSERT_EQ(1u, buffer->data().linearBlocks().size());
108 C2ReadView view = buffer->data().linearBlocks().front().map().get();
109 ASSERT_EQ(C2_OK, view.error());
110 ASSERT_EQ(encoderFrameSize * BytesPerSample(encoding), view.capacity());
111 for (size_t j = 0; j < view.capacity(); ++j, ++outputIndex) {
112 ASSERT_TRUE(outputIndex < inputIndex
113 || inputIndex == inputFrameSizeInBytes * count)
114 << "inputIndex = " << inputIndex << " outputIndex = " << outputIndex;
115 uint8_t expected = outputIndex < inputIndex ? (outputIndex & 0xFF) : 0;
116 if (expectCount < 10) {
117 ++expectCount;
118 EXPECT_EQ(expected, view.data()[j]) << "output index = " << outputIndex;
119 }
120 }
121 }
122 }
123
124 ASSERT_EQ(inputFrameSizeInBytes * count, inputIndex);
125 size_t encoderFrameSizeInBytes =
126 encoderFrameSize * channelCount * BytesPerSample(encoding);
127 ASSERT_EQ(0, outputIndex % encoderFrameSizeInBytes)
128 << "output size must be multiple of frame size: output size = " << outputIndex
129 << " frame size = " << encoderFrameSizeInBytes;
130 ASSERT_EQ(expectedOutputSize, outputIndex)
131 << "output size must be smallest multiple of frame size, "
132 << "equal to or larger than input size. output size = " << outputIndex
133 << " input size = " << inputIndex << " frame size = " << encoderFrameSizeInBytes;
134 }
135
136 private:
137 status_t mInitStatus;
138 std::shared_ptr<C2BlockPool> mPool;
139 };
140
141 const C2MemoryUsage FrameReassemblerTest::kUsage{C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
142
143 // Push frames with exactly the same size as the encoder requested.
TEST_F(FrameReassemblerTest,PushExactFrameSize)144 TEST_F(FrameReassemblerTest, PushExactFrameSize) {
145 ASSERT_EQ(OK, initStatus());
146 for (bool separateEos : {false, true}) {
147 testPushSameSize(
148 1024 /* frame size in samples */,
149 48000 /* sample rate */,
150 1 /* channel count */,
151 PCM_8,
152 1024 /* input frame size in bytes = 1024 samples * 1 channel * 1 bytes/sample */,
153 10 /* count */,
154 10240 /* expected output size = 10 * 1024 bytes/frame */,
155 separateEos);
156 testPushSameSize(
157 1024 /* frame size in samples */,
158 48000 /* sample rate */,
159 1 /* channel count */,
160 PCM_16,
161 2048 /* input frame size in bytes = 1024 samples * 1 channel * 2 bytes/sample */,
162 10 /* count */,
163 20480 /* expected output size = 10 * 2048 bytes/frame */,
164 separateEos);
165 testPushSameSize(
166 1024 /* frame size in samples */,
167 48000 /* sample rate */,
168 1 /* channel count */,
169 PCM_FLOAT,
170 4096 /* input frame size in bytes = 1024 samples * 1 channel * 4 bytes/sample */,
171 10 /* count */,
172 40960 /* expected output size = 10 * 4096 bytes/frame */,
173 separateEos);
174 }
175 }
176
177 // Push frames with half the size that the encoder requested.
TEST_F(FrameReassemblerTest,PushHalfFrameSize)178 TEST_F(FrameReassemblerTest, PushHalfFrameSize) {
179 ASSERT_EQ(OK, initStatus());
180 for (bool separateEos : {false, true}) {
181 testPushSameSize(
182 1024 /* frame size in samples */,
183 48000 /* sample rate */,
184 1 /* channel count */,
185 PCM_8,
186 512 /* input frame size in bytes = 512 samples * 1 channel * 1 bytes/sample */,
187 10 /* count */,
188 5120 /* expected output size = 5 * 1024 bytes/frame */,
189 separateEos);
190 testPushSameSize(
191 1024 /* frame size in samples */,
192 48000 /* sample rate */,
193 1 /* channel count */,
194 PCM_16,
195 1024 /* input frame size in bytes = 512 samples * 1 channel * 2 bytes/sample */,
196 10 /* count */,
197 10240 /* expected output size = 5 * 2048 bytes/frame */,
198 separateEos);
199 testPushSameSize(
200 1024 /* frame size in samples */,
201 48000 /* sample rate */,
202 1 /* channel count */,
203 PCM_FLOAT,
204 2048 /* input frame size in bytes = 512 samples * 1 channel * 4 bytes/sample */,
205 10 /* count */,
206 20480 /* expected output size = 5 * 4096 bytes/frame */,
207 separateEos);
208 }
209 }
210
211 // Push frames with twice the size that the encoder requested.
TEST_F(FrameReassemblerTest,PushDoubleFrameSize)212 TEST_F(FrameReassemblerTest, PushDoubleFrameSize) {
213 ASSERT_EQ(OK, initStatus());
214 for (bool separateEos : {false, true}) {
215 testPushSameSize(
216 1024 /* frame size in samples */,
217 48000 /* sample rate */,
218 1 /* channel count */,
219 PCM_8,
220 2048 /* input frame size in bytes = 2048 samples * 1 channel * 1 bytes/sample */,
221 10 /* count */,
222 20480 /* expected output size = 20 * 1024 bytes/frame */,
223 separateEos);
224 testPushSameSize(
225 1024 /* frame size in samples */,
226 48000 /* sample rate */,
227 1 /* channel count */,
228 PCM_16,
229 4096 /* input frame size in bytes = 2048 samples * 1 channel * 2 bytes/sample */,
230 10 /* count */,
231 40960 /* expected output size = 20 * 2048 bytes/frame */,
232 separateEos);
233 testPushSameSize(
234 1024 /* frame size in samples */,
235 48000 /* sample rate */,
236 1 /* channel count */,
237 PCM_FLOAT,
238 8192 /* input frame size in bytes = 2048 samples * 1 channel * 4 bytes/sample */,
239 10 /* count */,
240 81920 /* expected output size = 20 * 4096 bytes/frame */,
241 separateEos);
242 }
243 }
244
245 // Push frames with a little bit larger (+5 samples) than the requested size.
TEST_F(FrameReassemblerTest,PushLittleLargerFrameSize)246 TEST_F(FrameReassemblerTest, PushLittleLargerFrameSize) {
247 ASSERT_EQ(OK, initStatus());
248 for (bool separateEos : {false, true}) {
249 testPushSameSize(
250 1024 /* frame size in samples */,
251 48000 /* sample rate */,
252 1 /* channel count */,
253 PCM_8,
254 1029 /* input frame size in bytes = 1029 samples * 1 channel * 1 bytes/sample */,
255 10 /* count */,
256 11264 /* expected output size = 11 * 1024 bytes/frame */,
257 separateEos);
258 testPushSameSize(
259 1024 /* frame size in samples */,
260 48000 /* sample rate */,
261 1 /* channel count */,
262 PCM_16,
263 2058 /* input frame size in bytes = 1029 samples * 1 channel * 2 bytes/sample */,
264 10 /* count */,
265 22528 /* expected output size = 11 * 2048 bytes/frame */,
266 separateEos);
267 testPushSameSize(
268 1024 /* frame size in samples */,
269 48000 /* sample rate */,
270 1 /* channel count */,
271 PCM_FLOAT,
272 4116 /* input frame size in bytes = 1029 samples * 1 channel * 4 bytes/sample */,
273 10 /* count */,
274 45056 /* expected output size = 11 * 4096 bytes/frame */,
275 separateEos);
276 }
277 }
278
279 // Push frames with a little bit smaller (-5 samples) than the requested size.
TEST_F(FrameReassemblerTest,PushLittleSmallerFrameSize)280 TEST_F(FrameReassemblerTest, PushLittleSmallerFrameSize) {
281 ASSERT_EQ(OK, initStatus());
282 for (bool separateEos : {false, true}) {
283 testPushSameSize(
284 1024 /* frame size in samples */,
285 48000 /* sample rate */,
286 1 /* channel count */,
287 PCM_8,
288 1019 /* input frame size in bytes = 1019 samples * 1 channel * 1 bytes/sample */,
289 10 /* count */,
290 10240 /* expected output size = 10 * 1024 bytes/frame */,
291 separateEos);
292 testPushSameSize(
293 1024 /* frame size in samples */,
294 48000 /* sample rate */,
295 1 /* channel count */,
296 PCM_16,
297 2038 /* input frame size in bytes = 1019 samples * 1 channel * 2 bytes/sample */,
298 10 /* count */,
299 20480 /* expected output size = 10 * 2048 bytes/frame */,
300 separateEos);
301 testPushSameSize(
302 1024 /* frame size in samples */,
303 48000 /* sample rate */,
304 1 /* channel count */,
305 PCM_FLOAT,
306 4076 /* input frame size in bytes = 1019 samples * 1 channel * 4 bytes/sample */,
307 10 /* count */,
308 40960 /* expected output size = 10 * 4096 bytes/frame */,
309 separateEos);
310 }
311 }
312
313 // Push single-byte frames
TEST_F(FrameReassemblerTest,PushSingleByte)314 TEST_F(FrameReassemblerTest, PushSingleByte) {
315 ASSERT_EQ(OK, initStatus());
316 for (bool separateEos : {false, true}) {
317 testPushSameSize(
318 1024 /* frame size in samples */,
319 48000 /* sample rate */,
320 1 /* channel count */,
321 PCM_8,
322 1 /* input frame size in bytes */,
323 100000 /* count */,
324 100352 /* expected output size = 98 * 1024 bytes/frame */,
325 separateEos);
326 testPushSameSize(
327 1024 /* frame size in samples */,
328 48000 /* sample rate */,
329 1 /* channel count */,
330 PCM_16,
331 1 /* input frame size in bytes */,
332 100000 /* count */,
333 100352 /* expected output size = 49 * 2048 bytes/frame */,
334 separateEos);
335 testPushSameSize(
336 1024 /* frame size in samples */,
337 48000 /* sample rate */,
338 1 /* channel count */,
339 PCM_FLOAT,
340 1 /* input frame size in bytes */,
341 100000 /* count */,
342 102400 /* expected output size = 25 * 4096 bytes/frame */,
343 separateEos);
344 }
345 }
346
347 // Push one big chunk.
TEST_F(FrameReassemblerTest,PushBigChunk)348 TEST_F(FrameReassemblerTest, PushBigChunk) {
349 ASSERT_EQ(OK, initStatus());
350 for (bool separateEos : {false, true}) {
351 testPushSameSize(
352 1024 /* frame size in samples */,
353 48000 /* sample rate */,
354 1 /* channel count */,
355 PCM_8,
356 100000 /* input frame size in bytes */,
357 1 /* count */,
358 100352 /* expected output size = 98 * 1024 bytes/frame */,
359 separateEos);
360 testPushSameSize(
361 1024 /* frame size in samples */,
362 48000 /* sample rate */,
363 1 /* channel count */,
364 PCM_16,
365 100000 /* input frame size in bytes */,
366 1 /* count */,
367 100352 /* expected output size = 49 * 2048 bytes/frame */,
368 separateEos);
369 testPushSameSize(
370 1024 /* frame size in samples */,
371 48000 /* sample rate */,
372 1 /* channel count */,
373 PCM_FLOAT,
374 100000 /* input frame size in bytes */,
375 1 /* count */,
376 102400 /* expected output size = 25 * 4096 bytes/frame */,
377 separateEos);
378 }
379 }
380
381 } // namespace android
382