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