1 /*
2 * Copyright (C) 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "NativeCodecTestBase"
19 #include <log/log.h>
20
21 #include "NativeCodecTestBase.h"
22
onAsyncInputAvailable(AMediaCodec * codec,void * userdata,int32_t index)23 static void onAsyncInputAvailable(AMediaCodec* codec, void* userdata, int32_t index) {
24 (void)codec;
25 assert(index >= 0);
26 auto* aSyncHandle = static_cast<CodecAsyncHandler*>(userdata);
27 callbackObject element{index};
28 aSyncHandle->pushToInputList(element);
29 }
30
onAsyncOutputAvailable(AMediaCodec * codec,void * userdata,int32_t index,AMediaCodecBufferInfo * bufferInfo)31 static void onAsyncOutputAvailable(AMediaCodec* codec, void* userdata, int32_t index,
32 AMediaCodecBufferInfo* bufferInfo) {
33 (void)codec;
34 assert(index >= 0);
35 auto* aSyncHandle = static_cast<CodecAsyncHandler*>(userdata);
36 callbackObject element{index, bufferInfo};
37 aSyncHandle->pushToOutputList(element);
38 }
39
onAsyncFormatChanged(AMediaCodec * codec,void * userdata,AMediaFormat * format)40 static void onAsyncFormatChanged(AMediaCodec* codec, void* userdata, AMediaFormat* format) {
41 (void)codec;
42 auto* aSyncHandle = static_cast<CodecAsyncHandler*>(userdata);
43 aSyncHandle->setOutputFormat(format);
44 ALOGI("Output format changed: %s", AMediaFormat_toString(format));
45 }
46
onAsyncError(AMediaCodec * codec,void * userdata,media_status_t error,int32_t actionCode,const char * detail)47 static void onAsyncError(AMediaCodec* codec, void* userdata, media_status_t error,
48 int32_t actionCode, const char* detail) {
49 (void)codec;
50 auto* aSyncHandle = static_cast<CodecAsyncHandler*>(userdata);
51 aSyncHandle->setError(true);
52 ALOGE("received media codec error: %s , code : %d , action code: %d ", detail, error,
53 actionCode);
54 }
55
CodecAsyncHandler()56 CodecAsyncHandler::CodecAsyncHandler() {
57 mOutFormat = nullptr;
58 mSignalledOutFormatChanged = false;
59 mSignalledError = false;
60 }
61
~CodecAsyncHandler()62 CodecAsyncHandler::~CodecAsyncHandler() {
63 if (mOutFormat) {
64 AMediaFormat_delete(mOutFormat);
65 mOutFormat = nullptr;
66 }
67 }
68
pushToInputList(callbackObject element)69 void CodecAsyncHandler::pushToInputList(callbackObject element) {
70 std::unique_lock<std::mutex> lock{mMutex};
71 mCbInputQueue.push_back(element);
72 mCondition.notify_all();
73 }
74
pushToOutputList(callbackObject element)75 void CodecAsyncHandler::pushToOutputList(callbackObject element) {
76 std::unique_lock<std::mutex> lock{mMutex};
77 mCbOutputQueue.push_back(element);
78 mCondition.notify_all();
79 }
80
getInput()81 callbackObject CodecAsyncHandler::getInput() {
82 callbackObject element{-1};
83 std::unique_lock<std::mutex> lock{mMutex};
84 while (!mSignalledError) {
85 if (mCbInputQueue.empty()) {
86 mCondition.wait(lock);
87 } else {
88 element = mCbInputQueue.front();
89 mCbInputQueue.pop_front();
90 break;
91 }
92 }
93 return element;
94 }
95
getOutput()96 callbackObject CodecAsyncHandler::getOutput() {
97 callbackObject element;
98 std::unique_lock<std::mutex> lock{mMutex};
99 while (!mSignalledError) {
100 if (mCbOutputQueue.empty()) {
101 mCondition.wait(lock);
102 } else {
103 element = mCbOutputQueue.front();
104 mCbOutputQueue.pop_front();
105 break;
106 }
107 }
108 return element;
109 }
110
getWork()111 callbackObject CodecAsyncHandler::getWork() {
112 callbackObject element;
113 std::unique_lock<std::mutex> lock{mMutex};
114 while (!mSignalledError) {
115 if (mCbInputQueue.empty() && mCbOutputQueue.empty()) {
116 mCondition.wait(lock);
117 } else {
118 if (!mCbOutputQueue.empty()) {
119 element = mCbOutputQueue.front();
120 mCbOutputQueue.pop_front();
121 break;
122 } else {
123 element = mCbInputQueue.front();
124 mCbInputQueue.pop_front();
125 break;
126 }
127 }
128 }
129 return element;
130 }
131
isInputQueueEmpty()132 bool CodecAsyncHandler::isInputQueueEmpty() {
133 std::unique_lock<std::mutex> lock{mMutex};
134 return mCbInputQueue.empty();
135 }
136
clearQueues()137 void CodecAsyncHandler::clearQueues() {
138 std::unique_lock<std::mutex> lock{mMutex};
139 mCbInputQueue.clear();
140 mCbOutputQueue.clear();
141 }
142
setOutputFormat(AMediaFormat * format)143 void CodecAsyncHandler::setOutputFormat(AMediaFormat* format) {
144 std::unique_lock<std::mutex> lock{mMutex};
145 assert(format != nullptr);
146 if (mOutFormat) {
147 AMediaFormat_delete(mOutFormat);
148 mOutFormat = nullptr;
149 }
150 mOutFormat = format;
151 mSignalledOutFormatChanged = true;
152 }
153
getOutputFormat()154 AMediaFormat* CodecAsyncHandler::getOutputFormat() {
155 std::unique_lock<std::mutex> lock{mMutex};
156 return mOutFormat;
157 }
158
hasOutputFormatChanged()159 bool CodecAsyncHandler::hasOutputFormatChanged() {
160 std::unique_lock<std::mutex> lock{mMutex};
161 return mSignalledOutFormatChanged;
162 }
163
setError(bool status)164 void CodecAsyncHandler::setError(bool status) {
165 std::unique_lock<std::mutex> lock{mMutex};
166 mSignalledError = status;
167 mCondition.notify_all();
168 }
169
getError()170 bool CodecAsyncHandler::getError() {
171 return mSignalledError;
172 }
173
resetContext()174 void CodecAsyncHandler::resetContext() {
175 clearQueues();
176 if (mOutFormat) {
177 AMediaFormat_delete(mOutFormat);
178 mOutFormat = nullptr;
179 }
180 mSignalledOutFormatChanged = false;
181 mSignalledError = false;
182 }
183
setCallBack(AMediaCodec * codec,bool isCodecInAsyncMode)184 media_status_t CodecAsyncHandler::setCallBack(AMediaCodec* codec, bool isCodecInAsyncMode) {
185 media_status_t status = AMEDIA_OK;
186 if (isCodecInAsyncMode) {
187 AMediaCodecOnAsyncNotifyCallback callBack = {onAsyncInputAvailable, onAsyncOutputAvailable,
188 onAsyncFormatChanged, onAsyncError};
189 status = AMediaCodec_setAsyncNotifyCallback(codec, callBack, this);
190 }
191 return status;
192 }
193
isPtsStrictlyIncreasing(int64_t lastPts)194 bool OutputManager::isPtsStrictlyIncreasing(int64_t lastPts) {
195 bool result = true;
196 for (auto it1 = outPtsArray.cbegin(); it1 < outPtsArray.cend(); it1++) {
197 if (lastPts < *it1) {
198 lastPts = *it1;
199 } else {
200 ALOGE("Timestamp ordering check failed: last timestamp: %" PRId64
201 " / current timestamp: %" PRId64 "",
202 lastPts, *it1);
203 result = false;
204 break;
205 }
206 }
207 return result;
208 }
209
updateChecksum(uint8_t * buf,AMediaCodecBufferInfo * info,int width,int height,int stride)210 void OutputManager::updateChecksum(
211 uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height, int stride) {
212 uint8_t flattenInfo[16];
213 int pos = 0;
214 if (width <= 0 || height <= 0 || stride <= 0) {
215 flattenField<int32_t>(flattenInfo, &pos, info->size);
216 }
217 flattenField<int32_t>(flattenInfo, &pos,
218 info->flags & ~AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
219 flattenField<int64_t>(flattenInfo, &pos, info->presentationTimeUs);
220 crc32value = crc32(crc32value, flattenInfo, pos);
221 if (width > 0 && height > 0 && stride > 0) {
222 // Only checksum Y plane
223 std::vector<uint8_t> tmp(width * height, 0u);
224 size_t offset = 0;
225 for (int i = 0; i < height; ++i) {
226 memcpy(tmp.data() + (i * width), buf + offset, width);
227 offset += stride;
228 }
229 crc32value = crc32(crc32value, tmp.data(), width * height);
230 } else {
231 crc32value = crc32(crc32value, buf, info->size);
232 }
233 }
234
isOutPtsListIdenticalToInpPtsList(bool requireSorting)235 bool OutputManager::isOutPtsListIdenticalToInpPtsList(bool requireSorting) {
236 bool isEqual = true;
237 std::sort(inpPtsArray.begin(), inpPtsArray.end());
238 if (requireSorting) {
239 std::sort(outPtsArray.begin(), outPtsArray.end());
240 }
241 if (outPtsArray != inpPtsArray) {
242 if (outPtsArray.size() != inpPtsArray.size()) {
243 ALOGE("input and output presentation timestamp list sizes are not identical sizes "
244 "exp/rec %zu/%zu", inpPtsArray.size(), outPtsArray.size());
245 isEqual = false;
246 } else {
247 int count = 0;
248 for (auto it1 = outPtsArray.cbegin(), it2 = inpPtsArray.cbegin();
249 it1 < outPtsArray.cend(); it1++, it2++) {
250 if (*it1 != *it2) {
251 ALOGE("input output pts mismatch, exp/rec %" PRId64 "/%" PRId64 "",
252 *it2, *it1);
253 count++;
254 }
255 if (count == 20) {
256 ALOGE("stopping after 20 mismatches ... ");
257 break;
258 }
259 }
260 if (count != 0) isEqual = false;
261 }
262 }
263 return isEqual;
264 }
265
equals(const OutputManager * that)266 bool OutputManager::equals(const OutputManager* that) {
267 if (this == that) return true;
268 if (outPtsArray != that->outPtsArray) {
269 if (outPtsArray.size() != that->outPtsArray.size()) {
270 ALOGE("ref and test outputs presentation timestamp arrays are of unequal sizes "
271 "%zu, %zu", outPtsArray.size(), that->outPtsArray.size());
272 return false;
273 } else {
274 int count = 0;
275 for (auto it1 = outPtsArray.cbegin(), it2 = that->outPtsArray.cbegin();
276 it1 < outPtsArray.cend(); it1++, it2++) {
277 if (*it1 != *it2) {
278 ALOGE("presentation timestamp exp/rec %" PRId64 "/%" PRId64 "", *it1, *it2);
279 count++;
280 }
281 if (count == 20) {
282 ALOGE("stopping after 20 mismatches ... ");
283 break;
284 }
285 }
286 if (count != 0) return false;
287 }
288 }
289 if (crc32value != that->crc32value) {
290 ALOGE("ref and test outputs checksum do not match %lu, %lu", crc32value, that->crc32value);
291 if (memory.size() != that->memory.size()) {
292 ALOGE("ref and test outputs decoded buffer are of unequal sizes %zu, %zu",
293 memory.size(), that->memory.size());
294 } else {
295 int count = 0;
296 for (auto it1 = memory.cbegin(), it2 = that->memory.cbegin(); it1 < memory.cend();
297 it1++, it2++) {
298 if (*it1 != *it2) {
299 ALOGE("decoded sample exp/rec %d/%d", *it1, *it2);
300 count++;
301 }
302 if (count == 20) {
303 ALOGE("stopping after 20 mismatches ... ");
304 break;
305 }
306 }
307 }
308 return false;
309 }
310 return true;
311 }
312
getRmsError(uint8_t * refData,int length)313 float OutputManager::getRmsError(uint8_t* refData, int length) {
314 long totalErrorSquared = 0;
315 if (length != memory.size()) return MAXFLOAT;
316 if ((length % 2) != 0) return MAXFLOAT;
317 auto* testData = new uint8_t[length];
318 std::copy(memory.begin(), memory.end(), testData);
319 auto* testDataReinterpret = reinterpret_cast<int16_t*>(testData);
320 auto* refDataReinterpret = reinterpret_cast<int16_t*>(refData);
321 for (int i = 0; i < length / 2; i++) {
322 int d = testDataReinterpret[i] - refDataReinterpret[i];
323 totalErrorSquared += d * d;
324 }
325 delete[] testData;
326 long avgErrorSquared = (totalErrorSquared / (length / 2));
327 return (float)sqrt(avgErrorSquared);
328 }
329
CodecTestBase(const char * mime)330 CodecTestBase::CodecTestBase(const char* mime) {
331 mMime = mime;
332 mIsAudio = strncmp(mime, "audio/", strlen("audio/")) == 0;
333 mIsCodecInAsyncMode = false;
334 mSawInputEOS = false;
335 mSawOutputEOS = false;
336 mSignalEOSWithLastFrame = false;
337 mInputCount = 0;
338 mOutputCount = 0;
339 mPrevOutputPts = INT32_MIN;
340 mSignalledOutFormatChanged = false;
341 mOutFormat = nullptr;
342 mSaveToMem = false;
343 mOutputBuff = nullptr;
344 mCodec = nullptr;
345 }
346
~CodecTestBase()347 CodecTestBase::~CodecTestBase() {
348 if (mOutFormat) {
349 AMediaFormat_delete(mOutFormat);
350 mOutFormat = nullptr;
351 }
352 if (mCodec) {
353 AMediaCodec_delete(mCodec);
354 mCodec = nullptr;
355 }
356 }
357
configureCodec(AMediaFormat * format,bool isAsync,bool signalEOSWithLastFrame,bool isEncoder)358 bool CodecTestBase::configureCodec(AMediaFormat* format, bool isAsync, bool signalEOSWithLastFrame,
359 bool isEncoder) {
360 resetContext(isAsync, signalEOSWithLastFrame);
361 CHECK_STATUS(mAsyncHandle.setCallBack(mCodec, isAsync),
362 "AMediaCodec_setAsyncNotifyCallback failed");
363 CHECK_STATUS(AMediaCodec_configure(mCodec, format, nullptr, nullptr,
364 isEncoder ? AMEDIACODEC_CONFIGURE_FLAG_ENCODE : 0),
365 "AMediaCodec_configure failed");
366 return true;
367 }
368
flushCodec()369 bool CodecTestBase::flushCodec() {
370 CHECK_STATUS(AMediaCodec_flush(mCodec), "AMediaCodec_flush failed");
371 // TODO(b/147576107): is it ok to clearQueues right away or wait for some signal
372 mAsyncHandle.clearQueues();
373 mSawInputEOS = false;
374 mSawOutputEOS = false;
375 mInputCount = 0;
376 mOutputCount = 0;
377 mPrevOutputPts = INT32_MIN;
378 return true;
379 }
380
reConfigureCodec(AMediaFormat * format,bool isAsync,bool signalEOSWithLastFrame,bool isEncoder)381 bool CodecTestBase::reConfigureCodec(AMediaFormat* format, bool isAsync,
382 bool signalEOSWithLastFrame, bool isEncoder) {
383 CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
384 return configureCodec(format, isAsync, signalEOSWithLastFrame, isEncoder);
385 }
386
resetContext(bool isAsync,bool signalEOSWithLastFrame)387 void CodecTestBase::resetContext(bool isAsync, bool signalEOSWithLastFrame) {
388 mAsyncHandle.resetContext();
389 mIsCodecInAsyncMode = isAsync;
390 mSawInputEOS = false;
391 mSawOutputEOS = false;
392 mSignalEOSWithLastFrame = signalEOSWithLastFrame;
393 mInputCount = 0;
394 mOutputCount = 0;
395 mPrevOutputPts = INT32_MIN;
396 mSignalledOutFormatChanged = false;
397 if (mOutFormat) {
398 AMediaFormat_delete(mOutFormat);
399 mOutFormat = nullptr;
400 }
401 }
402
enqueueEOS(size_t bufferIndex)403 bool CodecTestBase::enqueueEOS(size_t bufferIndex) {
404 if (!hasSeenError() && !mSawInputEOS) {
405 CHECK_STATUS(AMediaCodec_queueInputBuffer(mCodec, bufferIndex, 0, 0, 0,
406 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM),
407 "AMediaCodec_queueInputBuffer failed");
408 mSawInputEOS = true;
409 ALOGV("Queued End of Stream");
410 }
411 return !hasSeenError();
412 }
413
doWork(int frameLimit)414 bool CodecTestBase::doWork(int frameLimit) {
415 bool isOk = true;
416 int frameCnt = 0;
417 if (mIsCodecInAsyncMode) {
418 // output processing after queuing EOS is done in waitForAllOutputs()
419 while (!hasSeenError() && isOk && !mSawInputEOS && frameCnt < frameLimit) {
420 callbackObject element = mAsyncHandle.getWork();
421 if (element.bufferIndex >= 0) {
422 if (element.isInput) {
423 isOk = enqueueInput(element.bufferIndex);
424 frameCnt++;
425 } else {
426 isOk = dequeueOutput(element.bufferIndex, &element.bufferInfo);
427 }
428 }
429 }
430 } else {
431 AMediaCodecBufferInfo outInfo;
432 // output processing after queuing EOS is done in waitForAllOutputs()
433 while (isOk && !mSawInputEOS && frameCnt < frameLimit) {
434 ssize_t oBufferID = AMediaCodec_dequeueOutputBuffer(mCodec, &outInfo, kQDeQTimeOutUs);
435 if (oBufferID >= 0) {
436 isOk = dequeueOutput(oBufferID, &outInfo);
437 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
438 if (mOutFormat) {
439 AMediaFormat_delete(mOutFormat);
440 mOutFormat = nullptr;
441 }
442 mOutFormat = AMediaCodec_getOutputFormat(mCodec);
443 mSignalledOutFormatChanged = true;
444 } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
445 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
446 } else {
447 ALOGE("unexpected return value from *_dequeueOutputBuffer: %zd", oBufferID);
448 return false;
449 }
450 ssize_t iBufferId = AMediaCodec_dequeueInputBuffer(mCodec, kQDeQTimeOutUs);
451 if (iBufferId >= 0) {
452 isOk = enqueueInput(iBufferId);
453 frameCnt++;
454 } else if (iBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
455 } else {
456 ALOGE("unexpected return value from *_dequeueInputBuffer: %zd", iBufferId);
457 return false;
458 }
459 }
460 }
461 return !hasSeenError() && isOk;
462 }
463
queueEOS()464 bool CodecTestBase::queueEOS() {
465 bool isOk = true;
466 if (mIsCodecInAsyncMode) {
467 while (!hasSeenError() && isOk && !mSawInputEOS) {
468 callbackObject element = mAsyncHandle.getWork();
469 if (element.bufferIndex >= 0) {
470 if (element.isInput) {
471 isOk = enqueueEOS(element.bufferIndex);
472 } else {
473 isOk = dequeueOutput(element.bufferIndex, &element.bufferInfo);
474 }
475 }
476 }
477 } else {
478 AMediaCodecBufferInfo outInfo;
479 while (isOk && !mSawInputEOS) {
480 ssize_t oBufferID = AMediaCodec_dequeueOutputBuffer(mCodec, &outInfo, kQDeQTimeOutUs);
481 if (oBufferID >= 0) {
482 isOk = dequeueOutput(oBufferID, &outInfo);
483 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
484 if (mOutFormat) {
485 AMediaFormat_delete(mOutFormat);
486 mOutFormat = nullptr;
487 }
488 mOutFormat = AMediaCodec_getOutputFormat(mCodec);
489 mSignalledOutFormatChanged = true;
490 } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
491 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
492 } else {
493 ALOGE("unexpected return value from *_dequeueOutputBuffer: %zd", oBufferID);
494 return false;
495 }
496 ssize_t iBufferId = AMediaCodec_dequeueInputBuffer(mCodec, kQDeQTimeOutUs);
497 if (iBufferId >= 0) {
498 isOk = enqueueEOS(iBufferId);
499 } else if (iBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
500 } else {
501 ALOGE("unexpected return value from *_dequeueInputBuffer: %zd", iBufferId);
502 return false;
503 }
504 }
505 }
506 return !hasSeenError() && isOk;
507 }
508
waitForAllOutputs()509 bool CodecTestBase::waitForAllOutputs() {
510 bool isOk = true;
511 if (mIsCodecInAsyncMode) {
512 while (!hasSeenError() && isOk && !mSawOutputEOS) {
513 callbackObject element = mAsyncHandle.getOutput();
514 if (element.bufferIndex >= 0) {
515 isOk = dequeueOutput(element.bufferIndex, &element.bufferInfo);
516 }
517 }
518 } else {
519 AMediaCodecBufferInfo outInfo;
520 while (!mSawOutputEOS) {
521 int bufferID = AMediaCodec_dequeueOutputBuffer(mCodec, &outInfo, kQDeQTimeOutUs);
522 if (bufferID >= 0) {
523 isOk = dequeueOutput(bufferID, &outInfo);
524 } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
525 if (mOutFormat) {
526 AMediaFormat_delete(mOutFormat);
527 mOutFormat = nullptr;
528 }
529 mOutFormat = AMediaCodec_getOutputFormat(mCodec);
530 mSignalledOutFormatChanged = true;
531 } else if (bufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
532 } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
533 } else {
534 ALOGE("unexpected return value from *_dequeueOutputBuffer: %d", bufferID);
535 return false;
536 }
537 }
538 }
539 return !hasSeenError() && isOk;
540 }
541
getWidth(AMediaFormat * format)542 int CodecTestBase::getWidth(AMediaFormat* format) {
543 int width = -1;
544 int cropLeft, cropRight, cropTop, cropBottom;
545 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width);
546 if (AMediaFormat_getRect(format, "crop", &cropLeft, &cropTop, &cropRight, &cropBottom) ||
547 (AMediaFormat_getInt32(format, "crop-left", &cropLeft) &&
548 AMediaFormat_getInt32(format, "crop-right", &cropRight))) {
549 width = cropRight + 1 - cropLeft;
550 }
551 return width;
552 }
553
getHeight(AMediaFormat * format)554 int CodecTestBase::getHeight(AMediaFormat* format) {
555 int height = -1;
556 int cropLeft, cropRight, cropTop, cropBottom;
557 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height);
558 if (AMediaFormat_getRect(format, "crop", &cropLeft, &cropTop, &cropRight, &cropBottom) ||
559 (AMediaFormat_getInt32(format, "crop-top", &cropTop) &&
560 AMediaFormat_getInt32(format, "crop-bottom", &cropBottom))) {
561 height = cropBottom + 1 - cropTop;
562 }
563 return height;
564 }
565
isFormatSimilar(AMediaFormat * inpFormat,AMediaFormat * outFormat)566 bool CodecTestBase::isFormatSimilar(AMediaFormat* inpFormat, AMediaFormat* outFormat) {
567 const char *refMime = nullptr, *testMime = nullptr;
568 bool hasRefMime = AMediaFormat_getString(inpFormat, AMEDIAFORMAT_KEY_MIME, &refMime);
569 bool hasTestMime = AMediaFormat_getString(outFormat, AMEDIAFORMAT_KEY_MIME, &testMime);
570
571 if (!hasRefMime || !hasTestMime) return false;
572 if (!strncmp(refMime, "audio/", strlen("audio/"))) {
573 int32_t refSampleRate = -1;
574 int32_t testSampleRate = -2;
575 int32_t refNumChannels = -1;
576 int32_t testNumChannels = -2;
577 AMediaFormat_getInt32(inpFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &refSampleRate);
578 AMediaFormat_getInt32(outFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &testSampleRate);
579 AMediaFormat_getInt32(inpFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &refNumChannels);
580 AMediaFormat_getInt32(outFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &testNumChannels);
581 return refNumChannels == testNumChannels && refSampleRate == testSampleRate &&
582 (strncmp(testMime, "audio/", strlen("audio/")) == 0);
583 } else if (!strncmp(refMime, "video/", strlen("video/"))) {
584 int32_t refWidth = getWidth(inpFormat);
585 int32_t testWidth = getWidth(outFormat);
586 int32_t refHeight = getHeight(inpFormat);
587 int32_t testHeight = getHeight(outFormat);
588 return refWidth != -1 && refHeight != -1 && refWidth == testWidth &&
589 refHeight == testHeight && (strncmp(testMime, "video/", strlen("video/")) == 0);
590 }
591 return true;
592 }
593