• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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