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,int bytesPerSample)210 void OutputManager::updateChecksum(uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height,
211 int stride, int bytesPerSample) {
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 && bytesPerSample > 0) {
222 // Only checksum Y plane
223 std::vector<uint8_t> tmp(width * height * bytesPerSample, 0u);
224 size_t offset = 0;
225 for (int i = 0; i < height; ++i) {
226 memcpy(tmp.data() + (i * width * bytesPerSample), buf + offset, width * bytesPerSample);
227 offset += stride;
228 }
229 crc32value = crc32(crc32value, tmp.data(), width * height * bytesPerSample);
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 mBytesPerSample = mIsAudio ? 2 : 1;
346 }
347
~CodecTestBase()348 CodecTestBase::~CodecTestBase() {
349 if (mOutFormat) {
350 AMediaFormat_delete(mOutFormat);
351 mOutFormat = nullptr;
352 }
353 if (mCodec) {
354 AMediaCodec_delete(mCodec);
355 mCodec = nullptr;
356 }
357 }
358
configureCodec(AMediaFormat * format,bool isAsync,bool signalEOSWithLastFrame,bool isEncoder)359 bool CodecTestBase::configureCodec(AMediaFormat* format, bool isAsync, bool signalEOSWithLastFrame,
360 bool isEncoder) {
361 resetContext(isAsync, signalEOSWithLastFrame);
362 CHECK_STATUS(mAsyncHandle.setCallBack(mCodec, isAsync),
363 "AMediaCodec_setAsyncNotifyCallback failed");
364 CHECK_STATUS(AMediaCodec_configure(mCodec, format, nullptr, nullptr,
365 isEncoder ? AMEDIACODEC_CONFIGURE_FLAG_ENCODE : 0),
366 "AMediaCodec_configure failed");
367 return true;
368 }
369
flushCodec()370 bool CodecTestBase::flushCodec() {
371 CHECK_STATUS(AMediaCodec_flush(mCodec), "AMediaCodec_flush failed");
372 // TODO(b/147576107): is it ok to clearQueues right away or wait for some signal
373 mAsyncHandle.clearQueues();
374 mSawInputEOS = false;
375 mSawOutputEOS = false;
376 mInputCount = 0;
377 mOutputCount = 0;
378 mPrevOutputPts = INT32_MIN;
379 return true;
380 }
381
reConfigureCodec(AMediaFormat * format,bool isAsync,bool signalEOSWithLastFrame,bool isEncoder)382 bool CodecTestBase::reConfigureCodec(AMediaFormat* format, bool isAsync,
383 bool signalEOSWithLastFrame, bool isEncoder) {
384 CHECK_STATUS(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed");
385 return configureCodec(format, isAsync, signalEOSWithLastFrame, isEncoder);
386 }
387
resetContext(bool isAsync,bool signalEOSWithLastFrame)388 void CodecTestBase::resetContext(bool isAsync, bool signalEOSWithLastFrame) {
389 mAsyncHandle.resetContext();
390 mIsCodecInAsyncMode = isAsync;
391 mSawInputEOS = false;
392 mSawOutputEOS = false;
393 mSignalEOSWithLastFrame = signalEOSWithLastFrame;
394 mInputCount = 0;
395 mOutputCount = 0;
396 mPrevOutputPts = INT32_MIN;
397 mSignalledOutFormatChanged = false;
398 if (mOutFormat) {
399 AMediaFormat_delete(mOutFormat);
400 mOutFormat = nullptr;
401 }
402 }
403
enqueueEOS(size_t bufferIndex)404 bool CodecTestBase::enqueueEOS(size_t bufferIndex) {
405 if (!hasSeenError() && !mSawInputEOS) {
406 CHECK_STATUS(AMediaCodec_queueInputBuffer(mCodec, bufferIndex, 0, 0, 0,
407 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM),
408 "AMediaCodec_queueInputBuffer failed");
409 mSawInputEOS = true;
410 ALOGV("Queued End of Stream");
411 }
412 return !hasSeenError();
413 }
414
doWork(int frameLimit)415 bool CodecTestBase::doWork(int frameLimit) {
416 bool isOk = true;
417 int frameCnt = 0;
418 if (mIsCodecInAsyncMode) {
419 // output processing after queuing EOS is done in waitForAllOutputs()
420 while (!hasSeenError() && isOk && !mSawInputEOS && frameCnt < frameLimit) {
421 callbackObject element = mAsyncHandle.getWork();
422 if (element.bufferIndex >= 0) {
423 if (element.isInput) {
424 isOk = enqueueInput(element.bufferIndex);
425 frameCnt++;
426 } else {
427 isOk = dequeueOutput(element.bufferIndex, &element.bufferInfo);
428 }
429 }
430 }
431 } else {
432 AMediaCodecBufferInfo outInfo;
433 // output processing after queuing EOS is done in waitForAllOutputs()
434 while (isOk && !mSawInputEOS && frameCnt < frameLimit) {
435 ssize_t oBufferID = AMediaCodec_dequeueOutputBuffer(mCodec, &outInfo, kQDeQTimeOutUs);
436 if (oBufferID >= 0) {
437 isOk = dequeueOutput(oBufferID, &outInfo);
438 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
439 if (mOutFormat) {
440 AMediaFormat_delete(mOutFormat);
441 mOutFormat = nullptr;
442 }
443 mOutFormat = AMediaCodec_getOutputFormat(mCodec);
444 mSignalledOutFormatChanged = true;
445 } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
446 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
447 } else {
448 ALOGE("unexpected return value from *_dequeueOutputBuffer: %zd", oBufferID);
449 return false;
450 }
451 ssize_t iBufferId = AMediaCodec_dequeueInputBuffer(mCodec, kQDeQTimeOutUs);
452 if (iBufferId >= 0) {
453 isOk = enqueueInput(iBufferId);
454 frameCnt++;
455 } else if (iBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
456 } else {
457 ALOGE("unexpected return value from *_dequeueInputBuffer: %zd", iBufferId);
458 return false;
459 }
460 }
461 }
462 return !hasSeenError() && isOk;
463 }
464
queueEOS()465 bool CodecTestBase::queueEOS() {
466 bool isOk = true;
467 if (mIsCodecInAsyncMode) {
468 while (!hasSeenError() && isOk && !mSawInputEOS) {
469 callbackObject element = mAsyncHandle.getWork();
470 if (element.bufferIndex >= 0) {
471 if (element.isInput) {
472 isOk = enqueueEOS(element.bufferIndex);
473 } else {
474 isOk = dequeueOutput(element.bufferIndex, &element.bufferInfo);
475 }
476 }
477 }
478 } else {
479 AMediaCodecBufferInfo outInfo;
480 while (isOk && !mSawInputEOS) {
481 ssize_t oBufferID = AMediaCodec_dequeueOutputBuffer(mCodec, &outInfo, kQDeQTimeOutUs);
482 if (oBufferID >= 0) {
483 isOk = dequeueOutput(oBufferID, &outInfo);
484 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
485 if (mOutFormat) {
486 AMediaFormat_delete(mOutFormat);
487 mOutFormat = nullptr;
488 }
489 mOutFormat = AMediaCodec_getOutputFormat(mCodec);
490 mSignalledOutFormatChanged = true;
491 } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
492 } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
493 } else {
494 ALOGE("unexpected return value from *_dequeueOutputBuffer: %zd", oBufferID);
495 return false;
496 }
497 ssize_t iBufferId = AMediaCodec_dequeueInputBuffer(mCodec, kQDeQTimeOutUs);
498 if (iBufferId >= 0) {
499 isOk = enqueueEOS(iBufferId);
500 } else if (iBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
501 } else {
502 ALOGE("unexpected return value from *_dequeueInputBuffer: %zd", iBufferId);
503 return false;
504 }
505 }
506 }
507 return !hasSeenError() && isOk;
508 }
509
waitForAllOutputs()510 bool CodecTestBase::waitForAllOutputs() {
511 bool isOk = true;
512 if (mIsCodecInAsyncMode) {
513 while (!hasSeenError() && isOk && !mSawOutputEOS) {
514 callbackObject element = mAsyncHandle.getOutput();
515 if (element.bufferIndex >= 0) {
516 isOk = dequeueOutput(element.bufferIndex, &element.bufferInfo);
517 }
518 }
519 } else {
520 AMediaCodecBufferInfo outInfo;
521 while (!mSawOutputEOS) {
522 int bufferID = AMediaCodec_dequeueOutputBuffer(mCodec, &outInfo, kQDeQTimeOutUs);
523 if (bufferID >= 0) {
524 isOk = dequeueOutput(bufferID, &outInfo);
525 } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
526 if (mOutFormat) {
527 AMediaFormat_delete(mOutFormat);
528 mOutFormat = nullptr;
529 }
530 mOutFormat = AMediaCodec_getOutputFormat(mCodec);
531 mSignalledOutFormatChanged = true;
532 } else if (bufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
533 } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
534 } else {
535 ALOGE("unexpected return value from *_dequeueOutputBuffer: %d", bufferID);
536 return false;
537 }
538 }
539 }
540 return !hasSeenError() && isOk;
541 }
542
getWidth(AMediaFormat * format)543 int CodecTestBase::getWidth(AMediaFormat* format) {
544 int width = -1;
545 int cropLeft, cropRight, cropTop, cropBottom;
546 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width);
547 if (AMediaFormat_getRect(format, "crop", &cropLeft, &cropTop, &cropRight, &cropBottom) ||
548 (AMediaFormat_getInt32(format, "crop-left", &cropLeft) &&
549 AMediaFormat_getInt32(format, "crop-right", &cropRight))) {
550 width = cropRight + 1 - cropLeft;
551 }
552 return width;
553 }
554
getHeight(AMediaFormat * format)555 int CodecTestBase::getHeight(AMediaFormat* format) {
556 int height = -1;
557 int cropLeft, cropRight, cropTop, cropBottom;
558 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height);
559 if (AMediaFormat_getRect(format, "crop", &cropLeft, &cropTop, &cropRight, &cropBottom) ||
560 (AMediaFormat_getInt32(format, "crop-top", &cropTop) &&
561 AMediaFormat_getInt32(format, "crop-bottom", &cropBottom))) {
562 height = cropBottom + 1 - cropTop;
563 }
564 return height;
565 }
566
isFormatSimilar(AMediaFormat * inpFormat,AMediaFormat * outFormat)567 bool CodecTestBase::isFormatSimilar(AMediaFormat* inpFormat, AMediaFormat* outFormat) {
568 const char *refMime = nullptr, *testMime = nullptr;
569 bool hasRefMime = AMediaFormat_getString(inpFormat, AMEDIAFORMAT_KEY_MIME, &refMime);
570 bool hasTestMime = AMediaFormat_getString(outFormat, AMEDIAFORMAT_KEY_MIME, &testMime);
571
572 if (!hasRefMime || !hasTestMime) return false;
573 if (!strncmp(refMime, "audio/", strlen("audio/"))) {
574 int32_t refSampleRate = -1;
575 int32_t testSampleRate = -2;
576 int32_t refNumChannels = -1;
577 int32_t testNumChannels = -2;
578 AMediaFormat_getInt32(inpFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &refSampleRate);
579 AMediaFormat_getInt32(outFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &testSampleRate);
580 AMediaFormat_getInt32(inpFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &refNumChannels);
581 AMediaFormat_getInt32(outFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &testNumChannels);
582 return refNumChannels == testNumChannels && refSampleRate == testSampleRate &&
583 (strncmp(testMime, "audio/", strlen("audio/")) == 0);
584 } else if (!strncmp(refMime, "video/", strlen("video/"))) {
585 int32_t refWidth = getWidth(inpFormat);
586 int32_t testWidth = getWidth(outFormat);
587 int32_t refHeight = getHeight(inpFormat);
588 int32_t testHeight = getHeight(outFormat);
589 return refWidth != -1 && refHeight != -1 && refWidth == testWidth &&
590 refHeight == testHeight && (strncmp(testMime, "video/", strlen("video/")) == 0);
591 }
592 return true;
593 }
594