xref: /aosp_15_r20/cts/tests/media/jni/NativeCodecTestBase.cpp (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1*b7c941bbSAndroid Build Coastguard Worker /*
2*b7c941bbSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*b7c941bbSAndroid Build Coastguard Worker  *
4*b7c941bbSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*b7c941bbSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*b7c941bbSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*b7c941bbSAndroid Build Coastguard Worker  *
8*b7c941bbSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*b7c941bbSAndroid Build Coastguard Worker  *
10*b7c941bbSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*b7c941bbSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*b7c941bbSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b7c941bbSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*b7c941bbSAndroid Build Coastguard Worker  * limitations under the License.
15*b7c941bbSAndroid Build Coastguard Worker  */
16*b7c941bbSAndroid Build Coastguard Worker 
17*b7c941bbSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*b7c941bbSAndroid Build Coastguard Worker #define LOG_TAG "NativeCodecTestBase"
19*b7c941bbSAndroid Build Coastguard Worker #include <log/log.h>
20*b7c941bbSAndroid Build Coastguard Worker 
21*b7c941bbSAndroid Build Coastguard Worker #include "NativeCodecTestBase.h"
22*b7c941bbSAndroid Build Coastguard Worker 
onAsyncInputAvailable(AMediaCodec * codec,void * userdata,int32_t index)23*b7c941bbSAndroid Build Coastguard Worker static void onAsyncInputAvailable(AMediaCodec* codec, void* userdata, int32_t index) {
24*b7c941bbSAndroid Build Coastguard Worker     (void)codec;
25*b7c941bbSAndroid Build Coastguard Worker     assert(index >= 0);
26*b7c941bbSAndroid Build Coastguard Worker     auto* aSyncHandle = static_cast<CodecAsyncHandler*>(userdata);
27*b7c941bbSAndroid Build Coastguard Worker     callbackObject element{index};
28*b7c941bbSAndroid Build Coastguard Worker     aSyncHandle->pushToInputList(element);
29*b7c941bbSAndroid Build Coastguard Worker }
30*b7c941bbSAndroid Build Coastguard Worker 
onAsyncOutputAvailable(AMediaCodec * codec,void * userdata,int32_t index,AMediaCodecBufferInfo * bufferInfo)31*b7c941bbSAndroid Build Coastguard Worker static void onAsyncOutputAvailable(AMediaCodec* codec, void* userdata, int32_t index,
32*b7c941bbSAndroid Build Coastguard Worker                                    AMediaCodecBufferInfo* bufferInfo) {
33*b7c941bbSAndroid Build Coastguard Worker     (void)codec;
34*b7c941bbSAndroid Build Coastguard Worker     assert(index >= 0);
35*b7c941bbSAndroid Build Coastguard Worker     auto* aSyncHandle = static_cast<CodecAsyncHandler*>(userdata);
36*b7c941bbSAndroid Build Coastguard Worker     callbackObject element{index, bufferInfo};
37*b7c941bbSAndroid Build Coastguard Worker     aSyncHandle->pushToOutputList(element);
38*b7c941bbSAndroid Build Coastguard Worker }
39*b7c941bbSAndroid Build Coastguard Worker 
onAsyncFormatChanged(AMediaCodec * codec,void * userdata,AMediaFormat * format)40*b7c941bbSAndroid Build Coastguard Worker static void onAsyncFormatChanged(AMediaCodec* codec, void* userdata, AMediaFormat* format) {
41*b7c941bbSAndroid Build Coastguard Worker     (void)codec;
42*b7c941bbSAndroid Build Coastguard Worker     auto* aSyncHandle = static_cast<CodecAsyncHandler*>(userdata);
43*b7c941bbSAndroid Build Coastguard Worker     aSyncHandle->setOutputFormat(format);
44*b7c941bbSAndroid Build Coastguard Worker     ALOGI("Output format changed: %s", AMediaFormat_toString(format));
45*b7c941bbSAndroid Build Coastguard Worker }
46*b7c941bbSAndroid Build Coastguard Worker 
onAsyncError(AMediaCodec * codec,void * userdata,media_status_t error,int32_t actionCode,const char * detail)47*b7c941bbSAndroid Build Coastguard Worker static void onAsyncError(AMediaCodec* codec, void* userdata, media_status_t error,
48*b7c941bbSAndroid Build Coastguard Worker                          int32_t actionCode, const char* detail) {
49*b7c941bbSAndroid Build Coastguard Worker     (void)codec;
50*b7c941bbSAndroid Build Coastguard Worker     auto* aSyncHandle = static_cast<CodecAsyncHandler*>(userdata);
51*b7c941bbSAndroid Build Coastguard Worker     auto msg = StringFormat("###################  Async Error Details  #####################\n "
52*b7c941bbSAndroid Build Coastguard Worker                             "received media codec error: %s , code : %d , action code: %d \n",
53*b7c941bbSAndroid Build Coastguard Worker                             detail, error, actionCode);
54*b7c941bbSAndroid Build Coastguard Worker     aSyncHandle->setError(true, msg);
55*b7c941bbSAndroid Build Coastguard Worker     ALOGE("received media codec error: %s , code : %d , action code: %d ", detail, error,
56*b7c941bbSAndroid Build Coastguard Worker           actionCode);
57*b7c941bbSAndroid Build Coastguard Worker }
58*b7c941bbSAndroid Build Coastguard Worker 
arePtsListsIdentical(const std::vector<int64_t> & refArray,const std::vector<int64_t> & testArray,const std::shared_ptr<std::string> & logs)59*b7c941bbSAndroid Build Coastguard Worker static bool arePtsListsIdentical(const std::vector<int64_t>& refArray,
60*b7c941bbSAndroid Build Coastguard Worker                                  const std::vector<int64_t>& testArray,
61*b7c941bbSAndroid Build Coastguard Worker                                  const std::shared_ptr<std::string>& logs) {
62*b7c941bbSAndroid Build Coastguard Worker     bool isEqual = true;
63*b7c941bbSAndroid Build Coastguard Worker     if (refArray.size() != testArray.size()) {
64*b7c941bbSAndroid Build Coastguard Worker         logs->append("Reference and test timestamps list sizes are not identical \n");
65*b7c941bbSAndroid Build Coastguard Worker         logs->append(StringFormat("reference pts list size is %zu \n", refArray.size()));
66*b7c941bbSAndroid Build Coastguard Worker         logs->append(StringFormat("test pts list size is %zu \n", testArray.size()));
67*b7c941bbSAndroid Build Coastguard Worker         isEqual = false;
68*b7c941bbSAndroid Build Coastguard Worker     }
69*b7c941bbSAndroid Build Coastguard Worker     for (int i = 0; i < std::min(refArray.size(), testArray.size()); i++) {
70*b7c941bbSAndroid Build Coastguard Worker         if (refArray[i] != testArray[i]) {
71*b7c941bbSAndroid Build Coastguard Worker             logs->append(StringFormat("Frame idx %d, ref pts %dus, test pts %dus \n", i,
72*b7c941bbSAndroid Build Coastguard Worker                                       refArray[i], testArray[i]));
73*b7c941bbSAndroid Build Coastguard Worker             isEqual = false;
74*b7c941bbSAndroid Build Coastguard Worker         }
75*b7c941bbSAndroid Build Coastguard Worker     }
76*b7c941bbSAndroid Build Coastguard Worker     if (refArray.size() < testArray.size()) {
77*b7c941bbSAndroid Build Coastguard Worker         for (auto i = refArray.size(); i < testArray.size(); i++) {
78*b7c941bbSAndroid Build Coastguard Worker             logs->append(
79*b7c941bbSAndroid Build Coastguard Worker                     StringFormat("Frame idx %d, ref pts EMPTY, test pts %dus \n", i, testArray[i]));
80*b7c941bbSAndroid Build Coastguard Worker         }
81*b7c941bbSAndroid Build Coastguard Worker     } else if (refArray.size() > testArray.size()) {
82*b7c941bbSAndroid Build Coastguard Worker         for (auto i = testArray.size(); i < refArray.size(); i++) {
83*b7c941bbSAndroid Build Coastguard Worker             logs->append(
84*b7c941bbSAndroid Build Coastguard Worker                     StringFormat("Frame idx %d, ref pts %dus, test pts EMPTY \n", i, refArray[i]));
85*b7c941bbSAndroid Build Coastguard Worker         }
86*b7c941bbSAndroid Build Coastguard Worker     }
87*b7c941bbSAndroid Build Coastguard Worker     if (!isEqual) {
88*b7c941bbSAndroid Build Coastguard Worker         logs->append("Are frames for which timestamps differ between reference and test. \n");
89*b7c941bbSAndroid Build Coastguard Worker     }
90*b7c941bbSAndroid Build Coastguard Worker     return isEqual;
91*b7c941bbSAndroid Build Coastguard Worker }
92*b7c941bbSAndroid Build Coastguard Worker 
CodecAsyncHandler()93*b7c941bbSAndroid Build Coastguard Worker CodecAsyncHandler::CodecAsyncHandler() {
94*b7c941bbSAndroid Build Coastguard Worker     mOutFormat = nullptr;
95*b7c941bbSAndroid Build Coastguard Worker     mSignalledOutFormatChanged = false;
96*b7c941bbSAndroid Build Coastguard Worker     mSignalledError = false;
97*b7c941bbSAndroid Build Coastguard Worker }
98*b7c941bbSAndroid Build Coastguard Worker 
~CodecAsyncHandler()99*b7c941bbSAndroid Build Coastguard Worker CodecAsyncHandler::~CodecAsyncHandler() {
100*b7c941bbSAndroid Build Coastguard Worker     if (mOutFormat) {
101*b7c941bbSAndroid Build Coastguard Worker         AMediaFormat_delete(mOutFormat);
102*b7c941bbSAndroid Build Coastguard Worker         mOutFormat = nullptr;
103*b7c941bbSAndroid Build Coastguard Worker     }
104*b7c941bbSAndroid Build Coastguard Worker }
105*b7c941bbSAndroid Build Coastguard Worker 
pushToInputList(callbackObject element)106*b7c941bbSAndroid Build Coastguard Worker void CodecAsyncHandler::pushToInputList(callbackObject element) {
107*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
108*b7c941bbSAndroid Build Coastguard Worker     mCbInputQueue.push_back(element);
109*b7c941bbSAndroid Build Coastguard Worker     mCondition.notify_all();
110*b7c941bbSAndroid Build Coastguard Worker }
111*b7c941bbSAndroid Build Coastguard Worker 
pushToOutputList(callbackObject element)112*b7c941bbSAndroid Build Coastguard Worker void CodecAsyncHandler::pushToOutputList(callbackObject element) {
113*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
114*b7c941bbSAndroid Build Coastguard Worker     mCbOutputQueue.push_back(element);
115*b7c941bbSAndroid Build Coastguard Worker     mCondition.notify_all();
116*b7c941bbSAndroid Build Coastguard Worker }
117*b7c941bbSAndroid Build Coastguard Worker 
getInput()118*b7c941bbSAndroid Build Coastguard Worker callbackObject CodecAsyncHandler::getInput() {
119*b7c941bbSAndroid Build Coastguard Worker     callbackObject element{-1};
120*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
121*b7c941bbSAndroid Build Coastguard Worker     while (!mSignalledError) {
122*b7c941bbSAndroid Build Coastguard Worker         if (mCbInputQueue.empty()) {
123*b7c941bbSAndroid Build Coastguard Worker             mCondition.wait(lock);
124*b7c941bbSAndroid Build Coastguard Worker         } else {
125*b7c941bbSAndroid Build Coastguard Worker             element = mCbInputQueue.front();
126*b7c941bbSAndroid Build Coastguard Worker             mCbInputQueue.pop_front();
127*b7c941bbSAndroid Build Coastguard Worker             break;
128*b7c941bbSAndroid Build Coastguard Worker         }
129*b7c941bbSAndroid Build Coastguard Worker     }
130*b7c941bbSAndroid Build Coastguard Worker     return element;
131*b7c941bbSAndroid Build Coastguard Worker }
132*b7c941bbSAndroid Build Coastguard Worker 
getOutput()133*b7c941bbSAndroid Build Coastguard Worker callbackObject CodecAsyncHandler::getOutput() {
134*b7c941bbSAndroid Build Coastguard Worker     callbackObject element;
135*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
136*b7c941bbSAndroid Build Coastguard Worker     while (!mSignalledError) {
137*b7c941bbSAndroid Build Coastguard Worker         if (mCbOutputQueue.empty()) {
138*b7c941bbSAndroid Build Coastguard Worker             mCondition.wait(lock);
139*b7c941bbSAndroid Build Coastguard Worker         } else {
140*b7c941bbSAndroid Build Coastguard Worker             element = mCbOutputQueue.front();
141*b7c941bbSAndroid Build Coastguard Worker             mCbOutputQueue.pop_front();
142*b7c941bbSAndroid Build Coastguard Worker             break;
143*b7c941bbSAndroid Build Coastguard Worker         }
144*b7c941bbSAndroid Build Coastguard Worker     }
145*b7c941bbSAndroid Build Coastguard Worker     return element;
146*b7c941bbSAndroid Build Coastguard Worker }
147*b7c941bbSAndroid Build Coastguard Worker 
getWork()148*b7c941bbSAndroid Build Coastguard Worker callbackObject CodecAsyncHandler::getWork() {
149*b7c941bbSAndroid Build Coastguard Worker     callbackObject element;
150*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
151*b7c941bbSAndroid Build Coastguard Worker     while (!mSignalledError) {
152*b7c941bbSAndroid Build Coastguard Worker         if (mCbInputQueue.empty() && mCbOutputQueue.empty()) {
153*b7c941bbSAndroid Build Coastguard Worker             mCondition.wait(lock);
154*b7c941bbSAndroid Build Coastguard Worker         } else {
155*b7c941bbSAndroid Build Coastguard Worker             if (!mCbOutputQueue.empty()) {
156*b7c941bbSAndroid Build Coastguard Worker                 element = mCbOutputQueue.front();
157*b7c941bbSAndroid Build Coastguard Worker                 mCbOutputQueue.pop_front();
158*b7c941bbSAndroid Build Coastguard Worker                 break;
159*b7c941bbSAndroid Build Coastguard Worker             } else {
160*b7c941bbSAndroid Build Coastguard Worker                 element = mCbInputQueue.front();
161*b7c941bbSAndroid Build Coastguard Worker                 mCbInputQueue.pop_front();
162*b7c941bbSAndroid Build Coastguard Worker                 break;
163*b7c941bbSAndroid Build Coastguard Worker             }
164*b7c941bbSAndroid Build Coastguard Worker         }
165*b7c941bbSAndroid Build Coastguard Worker     }
166*b7c941bbSAndroid Build Coastguard Worker     return element;
167*b7c941bbSAndroid Build Coastguard Worker }
168*b7c941bbSAndroid Build Coastguard Worker 
isInputQueueEmpty()169*b7c941bbSAndroid Build Coastguard Worker bool CodecAsyncHandler::isInputQueueEmpty() {
170*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
171*b7c941bbSAndroid Build Coastguard Worker     return mCbInputQueue.empty();
172*b7c941bbSAndroid Build Coastguard Worker }
173*b7c941bbSAndroid Build Coastguard Worker 
clearQueues()174*b7c941bbSAndroid Build Coastguard Worker void CodecAsyncHandler::clearQueues() {
175*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
176*b7c941bbSAndroid Build Coastguard Worker     mCbInputQueue.clear();
177*b7c941bbSAndroid Build Coastguard Worker     mCbOutputQueue.clear();
178*b7c941bbSAndroid Build Coastguard Worker }
179*b7c941bbSAndroid Build Coastguard Worker 
setOutputFormat(AMediaFormat * format)180*b7c941bbSAndroid Build Coastguard Worker void CodecAsyncHandler::setOutputFormat(AMediaFormat* format) {
181*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
182*b7c941bbSAndroid Build Coastguard Worker     assert(format != nullptr);
183*b7c941bbSAndroid Build Coastguard Worker     if (mOutFormat) {
184*b7c941bbSAndroid Build Coastguard Worker         AMediaFormat_delete(mOutFormat);
185*b7c941bbSAndroid Build Coastguard Worker         mOutFormat = nullptr;
186*b7c941bbSAndroid Build Coastguard Worker     }
187*b7c941bbSAndroid Build Coastguard Worker     mOutFormat = format;
188*b7c941bbSAndroid Build Coastguard Worker     mSignalledOutFormatChanged = true;
189*b7c941bbSAndroid Build Coastguard Worker     mCondition.notify_all();
190*b7c941bbSAndroid Build Coastguard Worker }
191*b7c941bbSAndroid Build Coastguard Worker 
waitOnFormatChange()192*b7c941bbSAndroid Build Coastguard Worker bool CodecAsyncHandler::waitOnFormatChange() {
193*b7c941bbSAndroid Build Coastguard Worker     int retry = kRetryLimit;
194*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
195*b7c941bbSAndroid Build Coastguard Worker     while (!mSignalledError) {
196*b7c941bbSAndroid Build Coastguard Worker         if (mSignalledOutFormatChanged || retry == 0) break;
197*b7c941bbSAndroid Build Coastguard Worker         if (std::cv_status::timeout ==
198*b7c941bbSAndroid Build Coastguard Worker             mCondition.wait_for(lock, std::chrono::microseconds(kQDeQTimeOutUs))) {
199*b7c941bbSAndroid Build Coastguard Worker             retry--;
200*b7c941bbSAndroid Build Coastguard Worker         }
201*b7c941bbSAndroid Build Coastguard Worker     }
202*b7c941bbSAndroid Build Coastguard Worker     return !mSignalledError && mSignalledOutFormatChanged;
203*b7c941bbSAndroid Build Coastguard Worker }
204*b7c941bbSAndroid Build Coastguard Worker 
getOutputFormat()205*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* CodecAsyncHandler::getOutputFormat() {
206*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
207*b7c941bbSAndroid Build Coastguard Worker     return mOutFormat;
208*b7c941bbSAndroid Build Coastguard Worker }
209*b7c941bbSAndroid Build Coastguard Worker 
hasOutputFormatChanged()210*b7c941bbSAndroid Build Coastguard Worker bool CodecAsyncHandler::hasOutputFormatChanged() {
211*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
212*b7c941bbSAndroid Build Coastguard Worker     return mSignalledOutFormatChanged;
213*b7c941bbSAndroid Build Coastguard Worker }
214*b7c941bbSAndroid Build Coastguard Worker 
setError(bool status,std::string & msg)215*b7c941bbSAndroid Build Coastguard Worker void CodecAsyncHandler::setError(bool status, std::string& msg) {
216*b7c941bbSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock{mMutex};
217*b7c941bbSAndroid Build Coastguard Worker     mSignalledError = status;
218*b7c941bbSAndroid Build Coastguard Worker     mErrorMsg.append(msg);
219*b7c941bbSAndroid Build Coastguard Worker     mCondition.notify_all();
220*b7c941bbSAndroid Build Coastguard Worker }
221*b7c941bbSAndroid Build Coastguard Worker 
getError() const222*b7c941bbSAndroid Build Coastguard Worker bool CodecAsyncHandler::getError() const {
223*b7c941bbSAndroid Build Coastguard Worker     return mSignalledError;
224*b7c941bbSAndroid Build Coastguard Worker }
225*b7c941bbSAndroid Build Coastguard Worker 
resetContext()226*b7c941bbSAndroid Build Coastguard Worker void CodecAsyncHandler::resetContext() {
227*b7c941bbSAndroid Build Coastguard Worker     clearQueues();
228*b7c941bbSAndroid Build Coastguard Worker     if (mOutFormat) {
229*b7c941bbSAndroid Build Coastguard Worker         AMediaFormat_delete(mOutFormat);
230*b7c941bbSAndroid Build Coastguard Worker         mOutFormat = nullptr;
231*b7c941bbSAndroid Build Coastguard Worker     }
232*b7c941bbSAndroid Build Coastguard Worker     mSignalledOutFormatChanged = false;
233*b7c941bbSAndroid Build Coastguard Worker     mSignalledError = false;
234*b7c941bbSAndroid Build Coastguard Worker     mErrorMsg.clear();
235*b7c941bbSAndroid Build Coastguard Worker }
236*b7c941bbSAndroid Build Coastguard Worker 
getErrorMsg()237*b7c941bbSAndroid Build Coastguard Worker std::string CodecAsyncHandler::getErrorMsg() {
238*b7c941bbSAndroid Build Coastguard Worker     return mErrorMsg;
239*b7c941bbSAndroid Build Coastguard Worker }
240*b7c941bbSAndroid Build Coastguard Worker 
setCallBack(AMediaCodec * codec,bool isCodecInAsyncMode)241*b7c941bbSAndroid Build Coastguard Worker media_status_t CodecAsyncHandler::setCallBack(AMediaCodec* codec, bool isCodecInAsyncMode) {
242*b7c941bbSAndroid Build Coastguard Worker     media_status_t status = AMEDIA_OK;
243*b7c941bbSAndroid Build Coastguard Worker     if (isCodecInAsyncMode) {
244*b7c941bbSAndroid Build Coastguard Worker         AMediaCodecOnAsyncNotifyCallback callBack = {onAsyncInputAvailable, onAsyncOutputAvailable,
245*b7c941bbSAndroid Build Coastguard Worker                                                      onAsyncFormatChanged, onAsyncError};
246*b7c941bbSAndroid Build Coastguard Worker         status = AMediaCodec_setAsyncNotifyCallback(codec, callBack, this);
247*b7c941bbSAndroid Build Coastguard Worker     }
248*b7c941bbSAndroid Build Coastguard Worker     return status;
249*b7c941bbSAndroid Build Coastguard Worker }
250*b7c941bbSAndroid Build Coastguard Worker 
isPtsStrictlyIncreasing(int64_t lastPts)251*b7c941bbSAndroid Build Coastguard Worker bool OutputManager::isPtsStrictlyIncreasing(int64_t lastPts) {
252*b7c941bbSAndroid Build Coastguard Worker     bool result = true;
253*b7c941bbSAndroid Build Coastguard Worker     for (auto i = 0; i < outPtsArray.size(); i++) {
254*b7c941bbSAndroid Build Coastguard Worker         if (lastPts < outPtsArray[i]) {
255*b7c941bbSAndroid Build Coastguard Worker             lastPts = outPtsArray[i];
256*b7c941bbSAndroid Build Coastguard Worker         } else {
257*b7c941bbSAndroid Build Coastguard Worker             mErrorLogs.append("Timestamp values are not strictly increasing. \n");
258*b7c941bbSAndroid Build Coastguard Worker             mErrorLogs.append("Frame indices around which timestamp values decreased :- \n");
259*b7c941bbSAndroid Build Coastguard Worker             for (auto j = std::max(0, i - 3); j < std::min((int)outPtsArray.size(), i + 3); j++) {
260*b7c941bbSAndroid Build Coastguard Worker                 if (j == 0) {
261*b7c941bbSAndroid Build Coastguard Worker                     mErrorLogs.append(
262*b7c941bbSAndroid Build Coastguard Worker                             StringFormat("pts of frame idx -1 is  %" PRId64 "\n", lastPts));
263*b7c941bbSAndroid Build Coastguard Worker                 }
264*b7c941bbSAndroid Build Coastguard Worker                 mErrorLogs.append(
265*b7c941bbSAndroid Build Coastguard Worker                         StringFormat("pts of frame idx %d is %" PRId64 "\n", j, outPtsArray[j]));
266*b7c941bbSAndroid Build Coastguard Worker             }
267*b7c941bbSAndroid Build Coastguard Worker             result = false;
268*b7c941bbSAndroid Build Coastguard Worker             break;
269*b7c941bbSAndroid Build Coastguard Worker         }
270*b7c941bbSAndroid Build Coastguard Worker     }
271*b7c941bbSAndroid Build Coastguard Worker     return result;
272*b7c941bbSAndroid Build Coastguard Worker }
273*b7c941bbSAndroid Build Coastguard Worker 
updateChecksum(uint8_t * buf,AMediaCodecBufferInfo * info,int width,int height,int stride,int bytesPerSample)274*b7c941bbSAndroid Build Coastguard Worker void OutputManager::updateChecksum(uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height,
275*b7c941bbSAndroid Build Coastguard Worker                                    int stride, int bytesPerSample) {
276*b7c941bbSAndroid Build Coastguard Worker     uint8_t flattenInfo[16];
277*b7c941bbSAndroid Build Coastguard Worker     int pos = 0;
278*b7c941bbSAndroid Build Coastguard Worker     if (width <= 0 || height <= 0 || stride <= 0) {
279*b7c941bbSAndroid Build Coastguard Worker         flattenField<int32_t>(flattenInfo, &pos, info->size);
280*b7c941bbSAndroid Build Coastguard Worker     }
281*b7c941bbSAndroid Build Coastguard Worker     flattenField<int32_t>(flattenInfo, &pos, info->flags & ~AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
282*b7c941bbSAndroid Build Coastguard Worker     flattenField<int64_t>(flattenInfo, &pos, info->presentationTimeUs);
283*b7c941bbSAndroid Build Coastguard Worker     crc32value = crc32(crc32value, flattenInfo, pos);
284*b7c941bbSAndroid Build Coastguard Worker     if (width > 0 && height > 0 && stride > 0 && bytesPerSample > 0) {
285*b7c941bbSAndroid Build Coastguard Worker         // Only checksum Y plane
286*b7c941bbSAndroid Build Coastguard Worker         std::vector<uint8_t> tmp(width * height * bytesPerSample, 0u);
287*b7c941bbSAndroid Build Coastguard Worker         size_t offset = 0;
288*b7c941bbSAndroid Build Coastguard Worker         for (int i = 0; i < height; ++i) {
289*b7c941bbSAndroid Build Coastguard Worker             memcpy(tmp.data() + (i * width * bytesPerSample), buf + offset, width * bytesPerSample);
290*b7c941bbSAndroid Build Coastguard Worker             offset += stride;
291*b7c941bbSAndroid Build Coastguard Worker         }
292*b7c941bbSAndroid Build Coastguard Worker         crc32value = crc32(crc32value, tmp.data(), width * height * bytesPerSample);
293*b7c941bbSAndroid Build Coastguard Worker     } else {
294*b7c941bbSAndroid Build Coastguard Worker         crc32value = crc32(crc32value, buf, info->size);
295*b7c941bbSAndroid Build Coastguard Worker     }
296*b7c941bbSAndroid Build Coastguard Worker }
297*b7c941bbSAndroid Build Coastguard Worker 
isOutPtsListIdenticalToInpPtsList(bool isPtsOutOfOrder)298*b7c941bbSAndroid Build Coastguard Worker bool OutputManager::isOutPtsListIdenticalToInpPtsList(bool isPtsOutOfOrder) {
299*b7c941bbSAndroid Build Coastguard Worker     std::vector<int64_t> inPtsArrayCopy(inpPtsArray);
300*b7c941bbSAndroid Build Coastguard Worker     std::sort(inPtsArrayCopy.begin(), inPtsArrayCopy.end());
301*b7c941bbSAndroid Build Coastguard Worker     if (isPtsOutOfOrder) {
302*b7c941bbSAndroid Build Coastguard Worker         std::vector<int64_t> outPtsArrayCopy(outPtsArray);
303*b7c941bbSAndroid Build Coastguard Worker         std::sort(outPtsArrayCopy.begin(), outPtsArrayCopy.end());
304*b7c941bbSAndroid Build Coastguard Worker         return arePtsListsIdentical(inPtsArrayCopy, outPtsArrayCopy, mSharedErrorLogs);
305*b7c941bbSAndroid Build Coastguard Worker     }
306*b7c941bbSAndroid Build Coastguard Worker     return arePtsListsIdentical(inPtsArrayCopy, outPtsArray, mSharedErrorLogs);
307*b7c941bbSAndroid Build Coastguard Worker }
308*b7c941bbSAndroid Build Coastguard Worker 
equals(OutputManager * that)309*b7c941bbSAndroid Build Coastguard Worker bool OutputManager::equals(OutputManager* that) {
310*b7c941bbSAndroid Build Coastguard Worker     if (this == that) return true;
311*b7c941bbSAndroid Build Coastguard Worker     if (that == nullptr) return false;
312*b7c941bbSAndroid Build Coastguard Worker     if (!equalsDequeuedOutput(that)) return false;
313*b7c941bbSAndroid Build Coastguard Worker     if (!equalsPtsList(that)) return false;
314*b7c941bbSAndroid Build Coastguard Worker     return true;
315*b7c941bbSAndroid Build Coastguard Worker }
316*b7c941bbSAndroid Build Coastguard Worker 
equalsDequeuedOutput(OutputManager * that)317*b7c941bbSAndroid Build Coastguard Worker bool OutputManager::equalsDequeuedOutput(OutputManager* that) {
318*b7c941bbSAndroid Build Coastguard Worker     if (this == that) return true;
319*b7c941bbSAndroid Build Coastguard Worker     if (that == nullptr) return false;
320*b7c941bbSAndroid Build Coastguard Worker     bool isEqual = true;
321*b7c941bbSAndroid Build Coastguard Worker     if (crc32value != that->crc32value) {
322*b7c941bbSAndroid Build Coastguard Worker         mSharedErrorLogs->append("CRC32 checksums computed for byte buffers received from "
323*b7c941bbSAndroid Build Coastguard Worker                                  "getOutputBuffer() do not match between ref and test runs. \n");
324*b7c941bbSAndroid Build Coastguard Worker         mSharedErrorLogs->append(StringFormat("Ref CRC32 checksum value is %lu \n", crc32value));
325*b7c941bbSAndroid Build Coastguard Worker         mSharedErrorLogs->append(
326*b7c941bbSAndroid Build Coastguard Worker                 StringFormat("Test CRC32 checksum value is %lu \n", that->crc32value));
327*b7c941bbSAndroid Build Coastguard Worker         isEqual = false;
328*b7c941bbSAndroid Build Coastguard Worker     }
329*b7c941bbSAndroid Build Coastguard Worker     if (memory.size() == that->memory.size()) {
330*b7c941bbSAndroid Build Coastguard Worker         if (memory != that->memory) {
331*b7c941bbSAndroid Build Coastguard Worker             int count = 0;
332*b7c941bbSAndroid Build Coastguard Worker             for (int i = 0; i < memory.size(); i++) {
333*b7c941bbSAndroid Build Coastguard Worker                 if (memory[i] != that->memory[i]) {
334*b7c941bbSAndroid Build Coastguard Worker                     count++;
335*b7c941bbSAndroid Build Coastguard Worker                     mSharedErrorLogs->append(StringFormat("At offset %d, ref buffer val is %x and "
336*b7c941bbSAndroid Build Coastguard Worker                                                           "test buffer val is %x \n",
337*b7c941bbSAndroid Build Coastguard Worker                                                           i, memory[i], that->memory[i]));
338*b7c941bbSAndroid Build Coastguard Worker                     if (count == 20) {
339*b7c941bbSAndroid Build Coastguard Worker                         mSharedErrorLogs->append("stopping after 20 mismatches, ...\n");
340*b7c941bbSAndroid Build Coastguard Worker                         break;
341*b7c941bbSAndroid Build Coastguard Worker                     }
342*b7c941bbSAndroid Build Coastguard Worker                 }
343*b7c941bbSAndroid Build Coastguard Worker             }
344*b7c941bbSAndroid Build Coastguard Worker             if (count != 0) {
345*b7c941bbSAndroid Build Coastguard Worker                 mSharedErrorLogs->append("Ref and Test outputs are not identical \n");
346*b7c941bbSAndroid Build Coastguard Worker             }
347*b7c941bbSAndroid Build Coastguard Worker             isEqual = false;
348*b7c941bbSAndroid Build Coastguard Worker         }
349*b7c941bbSAndroid Build Coastguard Worker     } else {
350*b7c941bbSAndroid Build Coastguard Worker         mSharedErrorLogs->append("ref and test output sizes are not identical \n");
351*b7c941bbSAndroid Build Coastguard Worker         mSharedErrorLogs->append(StringFormat("Ref output buffer size %d \n", memory.size()));
352*b7c941bbSAndroid Build Coastguard Worker         mSharedErrorLogs->append(
353*b7c941bbSAndroid Build Coastguard Worker                 StringFormat("Test output buffer size %d \n", that->memory.size()));
354*b7c941bbSAndroid Build Coastguard Worker         isEqual = false;
355*b7c941bbSAndroid Build Coastguard Worker     }
356*b7c941bbSAndroid Build Coastguard Worker     return isEqual;
357*b7c941bbSAndroid Build Coastguard Worker }
358*b7c941bbSAndroid Build Coastguard Worker 
equalsPtsList(OutputManager * that)359*b7c941bbSAndroid Build Coastguard Worker bool OutputManager::equalsPtsList(OutputManager* that) {
360*b7c941bbSAndroid Build Coastguard Worker     if (this == that) return true;
361*b7c941bbSAndroid Build Coastguard Worker     if (that == nullptr) return false;
362*b7c941bbSAndroid Build Coastguard Worker     return arePtsListsIdentical(outPtsArray, that->outPtsArray, mSharedErrorLogs);
363*b7c941bbSAndroid Build Coastguard Worker }
364*b7c941bbSAndroid Build Coastguard Worker 
getRmsError(uint8_t * refData,int length)365*b7c941bbSAndroid Build Coastguard Worker float OutputManager::getRmsError(uint8_t* refData, int length) {
366*b7c941bbSAndroid Build Coastguard Worker     long totalErrorSquared = 0;
367*b7c941bbSAndroid Build Coastguard Worker     if (length != memory.size()) return MAXFLOAT;
368*b7c941bbSAndroid Build Coastguard Worker     if ((length % 2) != 0) return MAXFLOAT;
369*b7c941bbSAndroid Build Coastguard Worker     auto* testData = new uint8_t[length];
370*b7c941bbSAndroid Build Coastguard Worker     std::copy(memory.begin(), memory.end(), testData);
371*b7c941bbSAndroid Build Coastguard Worker     auto* testDataReinterpret = reinterpret_cast<int16_t*>(testData);
372*b7c941bbSAndroid Build Coastguard Worker     auto* refDataReinterpret = reinterpret_cast<int16_t*>(refData);
373*b7c941bbSAndroid Build Coastguard Worker     for (int i = 0; i < length / 2; i++) {
374*b7c941bbSAndroid Build Coastguard Worker         int d = testDataReinterpret[i] - refDataReinterpret[i];
375*b7c941bbSAndroid Build Coastguard Worker         totalErrorSquared += d * d;
376*b7c941bbSAndroid Build Coastguard Worker     }
377*b7c941bbSAndroid Build Coastguard Worker     delete[] testData;
378*b7c941bbSAndroid Build Coastguard Worker     long avgErrorSquared = (totalErrorSquared / (length / 2));
379*b7c941bbSAndroid Build Coastguard Worker     return (float)sqrt(avgErrorSquared);
380*b7c941bbSAndroid Build Coastguard Worker }
381*b7c941bbSAndroid Build Coastguard Worker 
CodecTestBase(const char * mediaType)382*b7c941bbSAndroid Build Coastguard Worker CodecTestBase::CodecTestBase(const char* mediaType) {
383*b7c941bbSAndroid Build Coastguard Worker     mMediaType = mediaType;
384*b7c941bbSAndroid Build Coastguard Worker     mIsAudio = strncmp(mediaType, "audio/", strlen("audio/")) == 0;
385*b7c941bbSAndroid Build Coastguard Worker     mIsVideo = strncmp(mediaType, "video/", strlen("video/")) == 0;
386*b7c941bbSAndroid Build Coastguard Worker     mIsCodecInAsyncMode = false;
387*b7c941bbSAndroid Build Coastguard Worker     mSawInputEOS = false;
388*b7c941bbSAndroid Build Coastguard Worker     mSawOutputEOS = false;
389*b7c941bbSAndroid Build Coastguard Worker     mSignalEOSWithLastFrame = false;
390*b7c941bbSAndroid Build Coastguard Worker     mInputCount = 0;
391*b7c941bbSAndroid Build Coastguard Worker     mOutputCount = 0;
392*b7c941bbSAndroid Build Coastguard Worker     mPrevOutputPts = INT32_MIN;
393*b7c941bbSAndroid Build Coastguard Worker     mSignalledOutFormatChanged = false;
394*b7c941bbSAndroid Build Coastguard Worker     mOutFormat = nullptr;
395*b7c941bbSAndroid Build Coastguard Worker     mSaveToMem = false;
396*b7c941bbSAndroid Build Coastguard Worker     mOutputBuff = nullptr;
397*b7c941bbSAndroid Build Coastguard Worker     mCodec = nullptr;
398*b7c941bbSAndroid Build Coastguard Worker     mBytesPerSample = mIsAudio ? 2 : 1;
399*b7c941bbSAndroid Build Coastguard Worker     mRefBuff = new OutputManager();
400*b7c941bbSAndroid Build Coastguard Worker     mTestBuff = new OutputManager(mRefBuff->getSharedErrorLogs());
401*b7c941bbSAndroid Build Coastguard Worker     mReconfBuff = new OutputManager(mRefBuff->getSharedErrorLogs());
402*b7c941bbSAndroid Build Coastguard Worker }
403*b7c941bbSAndroid Build Coastguard Worker 
~CodecTestBase()404*b7c941bbSAndroid Build Coastguard Worker CodecTestBase::~CodecTestBase() {
405*b7c941bbSAndroid Build Coastguard Worker     if (mOutFormat) {
406*b7c941bbSAndroid Build Coastguard Worker         AMediaFormat_delete(mOutFormat);
407*b7c941bbSAndroid Build Coastguard Worker         mOutFormat = nullptr;
408*b7c941bbSAndroid Build Coastguard Worker     }
409*b7c941bbSAndroid Build Coastguard Worker     if (mCodec) {
410*b7c941bbSAndroid Build Coastguard Worker         AMediaCodec_delete(mCodec);
411*b7c941bbSAndroid Build Coastguard Worker         mCodec = nullptr;
412*b7c941bbSAndroid Build Coastguard Worker     }
413*b7c941bbSAndroid Build Coastguard Worker     delete mRefBuff;
414*b7c941bbSAndroid Build Coastguard Worker     delete mTestBuff;
415*b7c941bbSAndroid Build Coastguard Worker     delete mReconfBuff;
416*b7c941bbSAndroid Build Coastguard Worker }
417*b7c941bbSAndroid Build Coastguard Worker 
configureCodec(AMediaFormat * format,bool isAsync,bool signalEOSWithLastFrame,bool isEncoder)418*b7c941bbSAndroid Build Coastguard Worker bool CodecTestBase::configureCodec(AMediaFormat* format, bool isAsync, bool signalEOSWithLastFrame,
419*b7c941bbSAndroid Build Coastguard Worker                                    bool isEncoder) {
420*b7c941bbSAndroid Build Coastguard Worker     resetContext(isAsync, signalEOSWithLastFrame);
421*b7c941bbSAndroid Build Coastguard Worker     mTestEnv = "###################      Test Environment       #####################\n";
422*b7c941bbSAndroid Build Coastguard Worker     {
423*b7c941bbSAndroid Build Coastguard Worker         char* name = nullptr;
424*b7c941bbSAndroid Build Coastguard Worker         media_status_t val = AMediaCodec_getName(mCodec, &name);
425*b7c941bbSAndroid Build Coastguard Worker         if (AMEDIA_OK != val) {
426*b7c941bbSAndroid Build Coastguard Worker             mErrorLogs = StringFormat("%s with error %d \n", "AMediaCodec_getName failed", val);
427*b7c941bbSAndroid Build Coastguard Worker             return false;
428*b7c941bbSAndroid Build Coastguard Worker         }
429*b7c941bbSAndroid Build Coastguard Worker         if (!name) {
430*b7c941bbSAndroid Build Coastguard Worker             mErrorLogs = std::string{"AMediaCodec_getName returned null"};
431*b7c941bbSAndroid Build Coastguard Worker             return false;
432*b7c941bbSAndroid Build Coastguard Worker         }
433*b7c941bbSAndroid Build Coastguard Worker         mTestEnv.append(StringFormat("Component name %s \n", name));
434*b7c941bbSAndroid Build Coastguard Worker         AMediaCodec_releaseName(mCodec, name);
435*b7c941bbSAndroid Build Coastguard Worker     }
436*b7c941bbSAndroid Build Coastguard Worker     mTestEnv.append(StringFormat("Format under test :- %s \n", AMediaFormat_toString(format)));
437*b7c941bbSAndroid Build Coastguard Worker     mTestEnv.append(StringFormat("Component operating in :- %s mode \n",
438*b7c941bbSAndroid Build Coastguard Worker                                  (isAsync ? "asynchronous" : "synchronous")));
439*b7c941bbSAndroid Build Coastguard Worker     mTestEnv.append(
440*b7c941bbSAndroid Build Coastguard Worker             StringFormat("Component received input eos :- %s \n",
441*b7c941bbSAndroid Build Coastguard Worker                          (signalEOSWithLastFrame ? "with full buffer" : "with empty buffer")));
442*b7c941bbSAndroid Build Coastguard Worker     RETURN_IF_FAIL(mAsyncHandle.setCallBack(mCodec, isAsync),
443*b7c941bbSAndroid Build Coastguard Worker                    "AMediaCodec_setAsyncNotifyCallback failed")
444*b7c941bbSAndroid Build Coastguard Worker     RETURN_IF_FAIL(AMediaCodec_configure(mCodec, format, nullptr, nullptr,
445*b7c941bbSAndroid Build Coastguard Worker                                          isEncoder ? AMEDIACODEC_CONFIGURE_FLAG_ENCODE : 0),
446*b7c941bbSAndroid Build Coastguard Worker                    "AMediaCodec_configure failed")
447*b7c941bbSAndroid Build Coastguard Worker     return true;
448*b7c941bbSAndroid Build Coastguard Worker }
449*b7c941bbSAndroid Build Coastguard Worker 
flushCodec()450*b7c941bbSAndroid Build Coastguard Worker bool CodecTestBase::flushCodec() {
451*b7c941bbSAndroid Build Coastguard Worker     RETURN_IF_FAIL(AMediaCodec_flush(mCodec), "AMediaCodec_flush failed")
452*b7c941bbSAndroid Build Coastguard Worker     // TODO(b/147576107): is it ok to clearQueues right away or wait for some signal
453*b7c941bbSAndroid Build Coastguard Worker     mAsyncHandle.clearQueues();
454*b7c941bbSAndroid Build Coastguard Worker     mSawInputEOS = false;
455*b7c941bbSAndroid Build Coastguard Worker     mSawOutputEOS = false;
456*b7c941bbSAndroid Build Coastguard Worker     mInputCount = 0;
457*b7c941bbSAndroid Build Coastguard Worker     mOutputCount = 0;
458*b7c941bbSAndroid Build Coastguard Worker     mPrevOutputPts = INT32_MIN;
459*b7c941bbSAndroid Build Coastguard Worker     return true;
460*b7c941bbSAndroid Build Coastguard Worker }
461*b7c941bbSAndroid Build Coastguard Worker 
reConfigureCodec(AMediaFormat * format,bool isAsync,bool signalEOSWithLastFrame,bool isEncoder)462*b7c941bbSAndroid Build Coastguard Worker bool CodecTestBase::reConfigureCodec(AMediaFormat* format, bool isAsync,
463*b7c941bbSAndroid Build Coastguard Worker                                      bool signalEOSWithLastFrame, bool isEncoder) {
464*b7c941bbSAndroid Build Coastguard Worker     RETURN_IF_FAIL(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed")
465*b7c941bbSAndroid Build Coastguard Worker     return configureCodec(format, isAsync, signalEOSWithLastFrame, isEncoder);
466*b7c941bbSAndroid Build Coastguard Worker }
467*b7c941bbSAndroid Build Coastguard Worker 
resetContext(bool isAsync,bool signalEOSWithLastFrame)468*b7c941bbSAndroid Build Coastguard Worker void CodecTestBase::resetContext(bool isAsync, bool signalEOSWithLastFrame) {
469*b7c941bbSAndroid Build Coastguard Worker     mAsyncHandle.resetContext();
470*b7c941bbSAndroid Build Coastguard Worker     mIsCodecInAsyncMode = isAsync;
471*b7c941bbSAndroid Build Coastguard Worker     mSawInputEOS = false;
472*b7c941bbSAndroid Build Coastguard Worker     mSawOutputEOS = false;
473*b7c941bbSAndroid Build Coastguard Worker     mSignalEOSWithLastFrame = signalEOSWithLastFrame;
474*b7c941bbSAndroid Build Coastguard Worker     mInputCount = 0;
475*b7c941bbSAndroid Build Coastguard Worker     mOutputCount = 0;
476*b7c941bbSAndroid Build Coastguard Worker     mPrevOutputPts = INT32_MIN;
477*b7c941bbSAndroid Build Coastguard Worker     mSignalledOutFormatChanged = false;
478*b7c941bbSAndroid Build Coastguard Worker     if (mOutFormat) {
479*b7c941bbSAndroid Build Coastguard Worker         AMediaFormat_delete(mOutFormat);
480*b7c941bbSAndroid Build Coastguard Worker         mOutFormat = nullptr;
481*b7c941bbSAndroid Build Coastguard Worker     }
482*b7c941bbSAndroid Build Coastguard Worker }
483*b7c941bbSAndroid Build Coastguard Worker 
isTestStateValid()484*b7c941bbSAndroid Build Coastguard Worker bool CodecTestBase::isTestStateValid() {
485*b7c941bbSAndroid Build Coastguard Worker     RETURN_IF_TRUE(hasSeenError(),
486*b7c941bbSAndroid Build Coastguard Worker                    std::string{"Encountered error in async mode. \n"}.append(
487*b7c941bbSAndroid Build Coastguard Worker                            mAsyncHandle.getErrorMsg()))
488*b7c941bbSAndroid Build Coastguard Worker     RETURN_IF_TRUE(mInputCount > 0 && mOutputCount <= 0,
489*b7c941bbSAndroid Build Coastguard Worker                    StringFormat("fed %d input frames, received no output frames \n", mInputCount))
490*b7c941bbSAndroid Build Coastguard Worker     /*if (mInputCount == 0 && mInputCount != mOutputCount) {
491*b7c941bbSAndroid Build Coastguard Worker         (void)mOutputBuff->isOutPtsListIdenticalToInpPtsList(true);
492*b7c941bbSAndroid Build Coastguard Worker         RETURN_IF_TRUE(true,
493*b7c941bbSAndroid Build Coastguard Worker                        StringFormat("The number of output frames received is not same as number of "
494*b7c941bbSAndroid Build Coastguard Worker                                     "input frames queued. Output count is %d, Input count is %d \n",
495*b7c941bbSAndroid Build Coastguard Worker                                     mOutputCount, mInputCount)
496*b7c941bbSAndroid Build Coastguard Worker                                .append(mOutputBuff->getErrorMsg()))
497*b7c941bbSAndroid Build Coastguard Worker     }*/
498*b7c941bbSAndroid Build Coastguard Worker     return true;
499*b7c941bbSAndroid Build Coastguard Worker }
500*b7c941bbSAndroid Build Coastguard Worker 
enqueueEOS(size_t bufferIndex)501*b7c941bbSAndroid Build Coastguard Worker bool CodecTestBase::enqueueEOS(size_t bufferIndex) {
502*b7c941bbSAndroid Build Coastguard Worker     if (!hasSeenError() && !mSawInputEOS) {
503*b7c941bbSAndroid Build Coastguard Worker         RETURN_IF_FAIL(AMediaCodec_queueInputBuffer(mCodec, bufferIndex, 0, 0, 0,
504*b7c941bbSAndroid Build Coastguard Worker                                                     AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM),
505*b7c941bbSAndroid Build Coastguard Worker                        "AMediaCodec_queueInputBuffer failed")
506*b7c941bbSAndroid Build Coastguard Worker         mSawInputEOS = true;
507*b7c941bbSAndroid Build Coastguard Worker         ALOGV("Queued End of Stream");
508*b7c941bbSAndroid Build Coastguard Worker     }
509*b7c941bbSAndroid Build Coastguard Worker     return !hasSeenError();
510*b7c941bbSAndroid Build Coastguard Worker }
511*b7c941bbSAndroid Build Coastguard Worker 
doWork(int frameLimit)512*b7c941bbSAndroid Build Coastguard Worker bool CodecTestBase::doWork(int frameLimit) {
513*b7c941bbSAndroid Build Coastguard Worker     bool isOk = true;
514*b7c941bbSAndroid Build Coastguard Worker     int frameCnt = 0;
515*b7c941bbSAndroid Build Coastguard Worker     if (mIsCodecInAsyncMode) {
516*b7c941bbSAndroid Build Coastguard Worker         // output processing after queuing EOS is done in waitForAllOutputs()
517*b7c941bbSAndroid Build Coastguard Worker         while (!hasSeenError() && isOk && !mSawInputEOS && frameCnt < frameLimit) {
518*b7c941bbSAndroid Build Coastguard Worker             callbackObject element = mAsyncHandle.getWork();
519*b7c941bbSAndroid Build Coastguard Worker             if (element.bufferIndex >= 0) {
520*b7c941bbSAndroid Build Coastguard Worker                 if (element.isInput) {
521*b7c941bbSAndroid Build Coastguard Worker                     isOk = enqueueInput(element.bufferIndex);
522*b7c941bbSAndroid Build Coastguard Worker                     frameCnt++;
523*b7c941bbSAndroid Build Coastguard Worker                 } else {
524*b7c941bbSAndroid Build Coastguard Worker                     isOk = dequeueOutput(element.bufferIndex, &element.bufferInfo);
525*b7c941bbSAndroid Build Coastguard Worker                 }
526*b7c941bbSAndroid Build Coastguard Worker             }
527*b7c941bbSAndroid Build Coastguard Worker         }
528*b7c941bbSAndroid Build Coastguard Worker     } else {
529*b7c941bbSAndroid Build Coastguard Worker         AMediaCodecBufferInfo outInfo;
530*b7c941bbSAndroid Build Coastguard Worker         // output processing after queuing EOS is done in waitForAllOutputs()
531*b7c941bbSAndroid Build Coastguard Worker         while (isOk && !mSawInputEOS && frameCnt < frameLimit) {
532*b7c941bbSAndroid Build Coastguard Worker             ssize_t oBufferID = AMediaCodec_dequeueOutputBuffer(mCodec, &outInfo, kQDeQTimeOutUs);
533*b7c941bbSAndroid Build Coastguard Worker             if (oBufferID >= 0) {
534*b7c941bbSAndroid Build Coastguard Worker                 isOk = dequeueOutput(oBufferID, &outInfo);
535*b7c941bbSAndroid Build Coastguard Worker             } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
536*b7c941bbSAndroid Build Coastguard Worker                 if (mOutFormat) {
537*b7c941bbSAndroid Build Coastguard Worker                     AMediaFormat_delete(mOutFormat);
538*b7c941bbSAndroid Build Coastguard Worker                     mOutFormat = nullptr;
539*b7c941bbSAndroid Build Coastguard Worker                 }
540*b7c941bbSAndroid Build Coastguard Worker                 mOutFormat = AMediaCodec_getOutputFormat(mCodec);
541*b7c941bbSAndroid Build Coastguard Worker                 mSignalledOutFormatChanged = true;
542*b7c941bbSAndroid Build Coastguard Worker             } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
543*b7c941bbSAndroid Build Coastguard Worker             } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
544*b7c941bbSAndroid Build Coastguard Worker             } else {
545*b7c941bbSAndroid Build Coastguard Worker                 auto msg = StringFormat("unexpected return value from "
546*b7c941bbSAndroid Build Coastguard Worker                                         "AMediaCodec_dequeueOutputBuffer: %zd \n",
547*b7c941bbSAndroid Build Coastguard Worker                                         oBufferID);
548*b7c941bbSAndroid Build Coastguard Worker                 mErrorLogs.append(msg);
549*b7c941bbSAndroid Build Coastguard Worker                 ALOGE("%s", msg.c_str());
550*b7c941bbSAndroid Build Coastguard Worker                 return false;
551*b7c941bbSAndroid Build Coastguard Worker             }
552*b7c941bbSAndroid Build Coastguard Worker             ssize_t iBufferId = AMediaCodec_dequeueInputBuffer(mCodec, kQDeQTimeOutUs);
553*b7c941bbSAndroid Build Coastguard Worker             if (iBufferId >= 0) {
554*b7c941bbSAndroid Build Coastguard Worker                 isOk = enqueueInput(iBufferId);
555*b7c941bbSAndroid Build Coastguard Worker                 frameCnt++;
556*b7c941bbSAndroid Build Coastguard Worker             } else if (iBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
557*b7c941bbSAndroid Build Coastguard Worker             } else {
558*b7c941bbSAndroid Build Coastguard Worker                 auto msg = StringFormat("unexpected return value from "
559*b7c941bbSAndroid Build Coastguard Worker                                         "AMediaCodec_dequeueInputBuffer: %zd \n",
560*b7c941bbSAndroid Build Coastguard Worker                                         iBufferId);
561*b7c941bbSAndroid Build Coastguard Worker                 mErrorLogs.append(msg);
562*b7c941bbSAndroid Build Coastguard Worker                 ALOGE("%s", msg.c_str());
563*b7c941bbSAndroid Build Coastguard Worker                 return false;
564*b7c941bbSAndroid Build Coastguard Worker             }
565*b7c941bbSAndroid Build Coastguard Worker         }
566*b7c941bbSAndroid Build Coastguard Worker     }
567*b7c941bbSAndroid Build Coastguard Worker     return !hasSeenError() && isOk;
568*b7c941bbSAndroid Build Coastguard Worker }
569*b7c941bbSAndroid Build Coastguard Worker 
queueEOS()570*b7c941bbSAndroid Build Coastguard Worker bool CodecTestBase::queueEOS() {
571*b7c941bbSAndroid Build Coastguard Worker     bool isOk = true;
572*b7c941bbSAndroid Build Coastguard Worker     if (mIsCodecInAsyncMode) {
573*b7c941bbSAndroid Build Coastguard Worker         while (!hasSeenError() && isOk && !mSawInputEOS) {
574*b7c941bbSAndroid Build Coastguard Worker             callbackObject element = mAsyncHandle.getWork();
575*b7c941bbSAndroid Build Coastguard Worker             if (element.bufferIndex >= 0) {
576*b7c941bbSAndroid Build Coastguard Worker                 if (element.isInput) {
577*b7c941bbSAndroid Build Coastguard Worker                     isOk = enqueueEOS(element.bufferIndex);
578*b7c941bbSAndroid Build Coastguard Worker                 } else {
579*b7c941bbSAndroid Build Coastguard Worker                     isOk = dequeueOutput(element.bufferIndex, &element.bufferInfo);
580*b7c941bbSAndroid Build Coastguard Worker                 }
581*b7c941bbSAndroid Build Coastguard Worker             }
582*b7c941bbSAndroid Build Coastguard Worker         }
583*b7c941bbSAndroid Build Coastguard Worker     } else {
584*b7c941bbSAndroid Build Coastguard Worker         AMediaCodecBufferInfo outInfo;
585*b7c941bbSAndroid Build Coastguard Worker         while (isOk && !mSawInputEOS) {
586*b7c941bbSAndroid Build Coastguard Worker             ssize_t oBufferID = AMediaCodec_dequeueOutputBuffer(mCodec, &outInfo, kQDeQTimeOutUs);
587*b7c941bbSAndroid Build Coastguard Worker             if (oBufferID >= 0) {
588*b7c941bbSAndroid Build Coastguard Worker                 isOk = dequeueOutput(oBufferID, &outInfo);
589*b7c941bbSAndroid Build Coastguard Worker             } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
590*b7c941bbSAndroid Build Coastguard Worker                 if (mOutFormat) {
591*b7c941bbSAndroid Build Coastguard Worker                     AMediaFormat_delete(mOutFormat);
592*b7c941bbSAndroid Build Coastguard Worker                     mOutFormat = nullptr;
593*b7c941bbSAndroid Build Coastguard Worker                 }
594*b7c941bbSAndroid Build Coastguard Worker                 mOutFormat = AMediaCodec_getOutputFormat(mCodec);
595*b7c941bbSAndroid Build Coastguard Worker                 mSignalledOutFormatChanged = true;
596*b7c941bbSAndroid Build Coastguard Worker             } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
597*b7c941bbSAndroid Build Coastguard Worker             } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
598*b7c941bbSAndroid Build Coastguard Worker             } else {
599*b7c941bbSAndroid Build Coastguard Worker                 auto msg = StringFormat("unexpected return value from "
600*b7c941bbSAndroid Build Coastguard Worker                                         "AMediaCodec_dequeueOutputBuffer: %zd \n",
601*b7c941bbSAndroid Build Coastguard Worker                                         oBufferID);
602*b7c941bbSAndroid Build Coastguard Worker                 mErrorLogs.append(msg);
603*b7c941bbSAndroid Build Coastguard Worker                 ALOGE("%s", msg.c_str());
604*b7c941bbSAndroid Build Coastguard Worker                 return false;
605*b7c941bbSAndroid Build Coastguard Worker             }
606*b7c941bbSAndroid Build Coastguard Worker             ssize_t iBufferId = AMediaCodec_dequeueInputBuffer(mCodec, kQDeQTimeOutUs);
607*b7c941bbSAndroid Build Coastguard Worker             if (iBufferId >= 0) {
608*b7c941bbSAndroid Build Coastguard Worker                 isOk = enqueueEOS(iBufferId);
609*b7c941bbSAndroid Build Coastguard Worker             } else if (iBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
610*b7c941bbSAndroid Build Coastguard Worker             } else {
611*b7c941bbSAndroid Build Coastguard Worker                 auto msg = StringFormat("unexpected return value from "
612*b7c941bbSAndroid Build Coastguard Worker                                         "AMediaCodec_dequeueInputBuffer: %zd \n",
613*b7c941bbSAndroid Build Coastguard Worker                                         iBufferId);
614*b7c941bbSAndroid Build Coastguard Worker                 mErrorLogs.append(msg);
615*b7c941bbSAndroid Build Coastguard Worker                 ALOGE("%s", msg.c_str());
616*b7c941bbSAndroid Build Coastguard Worker                 return false;
617*b7c941bbSAndroid Build Coastguard Worker             }
618*b7c941bbSAndroid Build Coastguard Worker         }
619*b7c941bbSAndroid Build Coastguard Worker     }
620*b7c941bbSAndroid Build Coastguard Worker     return !hasSeenError() && isOk;
621*b7c941bbSAndroid Build Coastguard Worker }
622*b7c941bbSAndroid Build Coastguard Worker 
waitForAllOutputs()623*b7c941bbSAndroid Build Coastguard Worker bool CodecTestBase::waitForAllOutputs() {
624*b7c941bbSAndroid Build Coastguard Worker     bool isOk = true;
625*b7c941bbSAndroid Build Coastguard Worker     if (mIsCodecInAsyncMode) {
626*b7c941bbSAndroid Build Coastguard Worker         while (!hasSeenError() && isOk && !mSawOutputEOS) {
627*b7c941bbSAndroid Build Coastguard Worker             callbackObject element = mAsyncHandle.getOutput();
628*b7c941bbSAndroid Build Coastguard Worker             if (element.bufferIndex >= 0) {
629*b7c941bbSAndroid Build Coastguard Worker                 isOk = dequeueOutput(element.bufferIndex, &element.bufferInfo);
630*b7c941bbSAndroid Build Coastguard Worker             }
631*b7c941bbSAndroid Build Coastguard Worker         }
632*b7c941bbSAndroid Build Coastguard Worker     } else {
633*b7c941bbSAndroid Build Coastguard Worker         AMediaCodecBufferInfo outInfo;
634*b7c941bbSAndroid Build Coastguard Worker         while (!mSawOutputEOS) {
635*b7c941bbSAndroid Build Coastguard Worker             int bufferID = AMediaCodec_dequeueOutputBuffer(mCodec, &outInfo, kQDeQTimeOutUs);
636*b7c941bbSAndroid Build Coastguard Worker             if (bufferID >= 0) {
637*b7c941bbSAndroid Build Coastguard Worker                 isOk = dequeueOutput(bufferID, &outInfo);
638*b7c941bbSAndroid Build Coastguard Worker             } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
639*b7c941bbSAndroid Build Coastguard Worker                 if (mOutFormat) {
640*b7c941bbSAndroid Build Coastguard Worker                     AMediaFormat_delete(mOutFormat);
641*b7c941bbSAndroid Build Coastguard Worker                     mOutFormat = nullptr;
642*b7c941bbSAndroid Build Coastguard Worker                 }
643*b7c941bbSAndroid Build Coastguard Worker                 mOutFormat = AMediaCodec_getOutputFormat(mCodec);
644*b7c941bbSAndroid Build Coastguard Worker                 mSignalledOutFormatChanged = true;
645*b7c941bbSAndroid Build Coastguard Worker             } else if (bufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
646*b7c941bbSAndroid Build Coastguard Worker             } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
647*b7c941bbSAndroid Build Coastguard Worker             } else {
648*b7c941bbSAndroid Build Coastguard Worker                 auto msg = StringFormat("unexpected return value from "
649*b7c941bbSAndroid Build Coastguard Worker                                         "AMediaCodec_dequeueOutputBuffer: %d \n",
650*b7c941bbSAndroid Build Coastguard Worker                                         bufferID);
651*b7c941bbSAndroid Build Coastguard Worker                 mErrorLogs.append(msg);
652*b7c941bbSAndroid Build Coastguard Worker                 ALOGE("%s", msg.c_str());
653*b7c941bbSAndroid Build Coastguard Worker                 return false;
654*b7c941bbSAndroid Build Coastguard Worker             }
655*b7c941bbSAndroid Build Coastguard Worker         }
656*b7c941bbSAndroid Build Coastguard Worker     }
657*b7c941bbSAndroid Build Coastguard Worker     return isOk && isTestStateValid();
658*b7c941bbSAndroid Build Coastguard Worker }
659*b7c941bbSAndroid Build Coastguard Worker 
getWidth(AMediaFormat * format)660*b7c941bbSAndroid Build Coastguard Worker int CodecTestBase::getWidth(AMediaFormat* format) {
661*b7c941bbSAndroid Build Coastguard Worker     int width = -1;
662*b7c941bbSAndroid Build Coastguard Worker     int cropLeft, cropRight, cropTop, cropBottom;
663*b7c941bbSAndroid Build Coastguard Worker     AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width);
664*b7c941bbSAndroid Build Coastguard Worker     if (AMediaFormat_getRect(format, "crop", &cropLeft, &cropTop, &cropRight, &cropBottom) ||
665*b7c941bbSAndroid Build Coastguard Worker         (AMediaFormat_getInt32(format, "crop-left", &cropLeft) &&
666*b7c941bbSAndroid Build Coastguard Worker          AMediaFormat_getInt32(format, "crop-right", &cropRight))) {
667*b7c941bbSAndroid Build Coastguard Worker         width = cropRight + 1 - cropLeft;
668*b7c941bbSAndroid Build Coastguard Worker     }
669*b7c941bbSAndroid Build Coastguard Worker     return width;
670*b7c941bbSAndroid Build Coastguard Worker }
671*b7c941bbSAndroid Build Coastguard Worker 
getHeight(AMediaFormat * format)672*b7c941bbSAndroid Build Coastguard Worker int CodecTestBase::getHeight(AMediaFormat* format) {
673*b7c941bbSAndroid Build Coastguard Worker     int height = -1;
674*b7c941bbSAndroid Build Coastguard Worker     int cropLeft, cropRight, cropTop, cropBottom;
675*b7c941bbSAndroid Build Coastguard Worker     AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height);
676*b7c941bbSAndroid Build Coastguard Worker     if (AMediaFormat_getRect(format, "crop", &cropLeft, &cropTop, &cropRight, &cropBottom) ||
677*b7c941bbSAndroid Build Coastguard Worker         (AMediaFormat_getInt32(format, "crop-top", &cropTop) &&
678*b7c941bbSAndroid Build Coastguard Worker          AMediaFormat_getInt32(format, "crop-bottom", &cropBottom))) {
679*b7c941bbSAndroid Build Coastguard Worker         height = cropBottom + 1 - cropTop;
680*b7c941bbSAndroid Build Coastguard Worker     }
681*b7c941bbSAndroid Build Coastguard Worker     return height;
682*b7c941bbSAndroid Build Coastguard Worker }
683*b7c941bbSAndroid Build Coastguard Worker 
isFormatSimilar(AMediaFormat * inpFormat,AMediaFormat * outFormat)684*b7c941bbSAndroid Build Coastguard Worker bool CodecTestBase::isFormatSimilar(AMediaFormat* inpFormat, AMediaFormat* outFormat) {
685*b7c941bbSAndroid Build Coastguard Worker     const char *refMediaType = nullptr, *testMediaType = nullptr;
686*b7c941bbSAndroid Build Coastguard Worker     bool hasRefMediaType = AMediaFormat_getString(inpFormat, AMEDIAFORMAT_KEY_MIME, &refMediaType);
687*b7c941bbSAndroid Build Coastguard Worker     bool hasTestMediaType =
688*b7c941bbSAndroid Build Coastguard Worker             AMediaFormat_getString(outFormat, AMEDIAFORMAT_KEY_MIME, &testMediaType);
689*b7c941bbSAndroid Build Coastguard Worker 
690*b7c941bbSAndroid Build Coastguard Worker     if (!hasRefMediaType || !hasTestMediaType) return false;
691*b7c941bbSAndroid Build Coastguard Worker     if (!strncmp(refMediaType, "audio/", strlen("audio/"))) {
692*b7c941bbSAndroid Build Coastguard Worker         int32_t refSampleRate = -1;
693*b7c941bbSAndroid Build Coastguard Worker         int32_t testSampleRate = -2;
694*b7c941bbSAndroid Build Coastguard Worker         int32_t refNumChannels = -1;
695*b7c941bbSAndroid Build Coastguard Worker         int32_t testNumChannels = -2;
696*b7c941bbSAndroid Build Coastguard Worker         AMediaFormat_getInt32(inpFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &refSampleRate);
697*b7c941bbSAndroid Build Coastguard Worker         AMediaFormat_getInt32(outFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &testSampleRate);
698*b7c941bbSAndroid Build Coastguard Worker         AMediaFormat_getInt32(inpFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &refNumChannels);
699*b7c941bbSAndroid Build Coastguard Worker         AMediaFormat_getInt32(outFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &testNumChannels);
700*b7c941bbSAndroid Build Coastguard Worker         return refNumChannels == testNumChannels && refSampleRate == testSampleRate &&
701*b7c941bbSAndroid Build Coastguard Worker                 (strncmp(testMediaType, "audio/", strlen("audio/")) == 0);
702*b7c941bbSAndroid Build Coastguard Worker     } else if (!strncmp(refMediaType, "video/", strlen("video/"))) {
703*b7c941bbSAndroid Build Coastguard Worker         int32_t refWidth = getWidth(inpFormat);
704*b7c941bbSAndroid Build Coastguard Worker         int32_t testWidth = getWidth(outFormat);
705*b7c941bbSAndroid Build Coastguard Worker         int32_t refHeight = getHeight(inpFormat);
706*b7c941bbSAndroid Build Coastguard Worker         int32_t testHeight = getHeight(outFormat);
707*b7c941bbSAndroid Build Coastguard Worker         return refWidth != -1 && refHeight != -1 && refWidth == testWidth &&
708*b7c941bbSAndroid Build Coastguard Worker                 refHeight == testHeight &&
709*b7c941bbSAndroid Build Coastguard Worker                 (strncmp(testMediaType, "video/", strlen("video/")) == 0);
710*b7c941bbSAndroid Build Coastguard Worker     }
711*b7c941bbSAndroid Build Coastguard Worker     return true;
712*b7c941bbSAndroid Build Coastguard Worker }
713