1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef MEDIACTSNATIVE_NATIVE_CODEC_TEST_BASE_H 18 #define MEDIACTSNATIVE_NATIVE_CODEC_TEST_BASE_H 19 20 #include <media/NdkMediaCodec.h> 21 #include <zlib.h> 22 23 #include <cmath> 24 #include <cstdint> 25 #include <list> 26 #include <mutex> 27 #include <vector> 28 29 #include "NativeMediaCommon.h" 30 31 #define RETURN_IF_FAIL(status, str) \ 32 { \ 33 media_status_t val = (status); \ 34 if (AMEDIA_OK != val) { \ 35 std::string msg = StringFormat("%s with error %d \n", str, val); \ 36 ALOGE("%s", msg.c_str()); \ 37 mErrorLogs.append((msg)); \ 38 return false; \ 39 } \ 40 } 41 42 #define RETURN_IF_TRUE(cond, msg) \ 43 if ((cond)) { \ 44 ALOGE("%s", (msg).c_str()); \ 45 mErrorLogs.append((msg)).append("\n"); \ 46 return false; \ 47 } 48 49 #define RETURN_IF_FALSE(cond, msg) \ 50 if (!(cond)) { \ 51 ALOGE("%s", (msg).c_str()); \ 52 mErrorLogs.append((msg)).append("\n"); \ 53 return false; \ 54 } 55 56 #define RETURN_IF_NULL(var, msg) \ 57 if ((var) == nullptr) { \ 58 ALOGE("%s", (msg).c_str()); \ 59 mErrorLogs.append((msg)).append("\n"); \ 60 return false; \ 61 } 62 63 struct callbackObject { 64 AMediaCodecBufferInfo bufferInfo; 65 int32_t bufferIndex; 66 bool isInput; 67 callbackObjectcallbackObject68 callbackObject(int32_t index, AMediaCodecBufferInfo* info) 69 : bufferInfo{*info}, bufferIndex{index}, isInput{false} {} 70 callbackObjectcallbackObject71 callbackObject(int32_t index) : bufferIndex{index}, isInput{true} {} 72 callbackObjectcallbackObject73 callbackObject() : bufferIndex{-1}, isInput{false} {} 74 }; 75 76 class CodecAsyncHandler { 77 private: 78 std::mutex mMutex; 79 std::condition_variable mCondition; 80 std::list<callbackObject> mCbInputQueue; 81 std::list<callbackObject> mCbOutputQueue; 82 AMediaFormat* mOutFormat; 83 volatile bool mSignalledOutFormatChanged; 84 volatile bool mSignalledError; 85 std::string mErrorMsg; 86 87 public: 88 CodecAsyncHandler(); 89 ~CodecAsyncHandler(); 90 void pushToInputList(callbackObject element); 91 void pushToOutputList(callbackObject element); 92 callbackObject getInput(); 93 callbackObject getOutput(); 94 callbackObject getWork(); 95 bool isInputQueueEmpty(); 96 void clearQueues(); 97 void setOutputFormat(AMediaFormat* format); 98 AMediaFormat* getOutputFormat(); 99 bool hasOutputFormatChanged(); 100 bool waitOnFormatChange(); 101 void setError(bool status, std::string& msg); 102 bool getError() const; 103 void resetContext(); 104 std::string getErrorMsg(); 105 media_status_t setCallBack(AMediaCodec* codec, bool isCodecInAsyncMode); 106 }; 107 108 class OutputManager { 109 private: 110 std::vector<int64_t> inpPtsArray; 111 std::vector<int64_t> outPtsArray; 112 std::vector<uint8_t> memory; 113 uLong crc32value = 0U; 114 std::string mErrorLogs; 115 std::shared_ptr<std::string> mSharedErrorLogs; 116 117 public: 118 OutputManager(std::shared_ptr<std::string> log = std::make_shared<std::string>()) mSharedErrorLogs(log)119 : mSharedErrorLogs(log) {} 120 saveInPTS(int64_t pts)121 void saveInPTS(int64_t pts) { 122 // Add only Unique timeStamp, discarding any duplicate frame / non-display frame 123 if (0 == std::count(inpPtsArray.begin(), inpPtsArray.end(), pts)) { 124 inpPtsArray.push_back(pts); 125 } 126 } saveOutPTS(int64_t pts)127 void saveOutPTS(int64_t pts) { outPtsArray.push_back(pts); } 128 bool isPtsStrictlyIncreasing(int64_t lastPts); 129 bool isOutPtsListIdenticalToInpPtsList(bool requireSorting); saveToMemory(uint8_t * buf,AMediaCodecBufferInfo * info)130 void saveToMemory(uint8_t* buf, AMediaCodecBufferInfo* info) { 131 memory.insert(memory.end(), buf, buf + info->size); 132 } updateChecksum(uint8_t * buf,AMediaCodecBufferInfo * info)133 void updateChecksum(uint8_t* buf, AMediaCodecBufferInfo* info) { 134 updateChecksum(buf, info, 0, 0, 0, 0); 135 } 136 137 void updateChecksum(uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height, 138 int stride, int bytesPerSample); getChecksum()139 uLong getChecksum() { return crc32value; } reset()140 void reset() { 141 inpPtsArray.clear(); 142 outPtsArray.clear(); 143 memory.clear(); 144 crc32value = 0U; 145 mErrorLogs.clear(); 146 mSharedErrorLogs->clear(); 147 } 148 bool equalsPtsList(OutputManager* that); 149 bool equalsDequeuedOutput(OutputManager* that); 150 bool equals(OutputManager* that); 151 float getRmsError(uint8_t* refData, int length); getErrorMsg()152 std::string getErrorMsg() { return mErrorLogs + *mSharedErrorLogs; } getOutStreamSize()153 int getOutStreamSize() { return memory.size(); } getSharedErrorLogs()154 std::shared_ptr<std::string> getSharedErrorLogs() { return mSharedErrorLogs; } 155 }; 156 157 class CodecTestBase { 158 protected: 159 const char* mMediaType; 160 bool mIsAudio; 161 bool mIsVideo; 162 CodecAsyncHandler mAsyncHandle; 163 bool mIsCodecInAsyncMode; 164 bool mSawInputEOS; 165 bool mSawOutputEOS; 166 bool mSignalEOSWithLastFrame; 167 int mInputCount; 168 int mOutputCount; 169 int64_t mPrevOutputPts; 170 bool mSignalledOutFormatChanged; 171 AMediaFormat* mOutFormat; 172 int mBytesPerSample; 173 174 bool mSaveToMem; 175 OutputManager* mOutputBuff; 176 OutputManager* mRefBuff; 177 OutputManager* mTestBuff; 178 OutputManager* mReconfBuff; 179 180 AMediaCodec* mCodec; 181 std::string mTestEnv; 182 std::string mErrorLogs; 183 184 CodecTestBase(const char* mediaType); 185 ~CodecTestBase(); 186 virtual bool configureCodec(AMediaFormat* format, bool isAsync, bool signalEOSWithLastFrame, 187 bool isEncoder); 188 virtual bool flushCodec(); 189 bool reConfigureCodec(AMediaFormat* format, bool isAsync, bool signalEOSWithLastFrame, 190 bool isEncoder); 191 virtual void resetContext(bool isAsync, bool signalEOSWithLastFrame); 192 virtual bool enqueueInput(size_t bufferIndex) = 0; 193 virtual bool dequeueOutput(size_t bufferIndex, AMediaCodecBufferInfo* bufferInfo) = 0; 194 virtual bool isTestStateValid(); 195 bool enqueueEOS(size_t bufferIndex); 196 virtual bool doWork(int frameLimit); 197 bool queueEOS(); 198 bool waitForAllOutputs(); 199 static int getWidth(AMediaFormat* format); 200 static int getHeight(AMediaFormat* format); 201 static bool isFormatSimilar(AMediaFormat* inpFormat, AMediaFormat* outFormat); hasSeenError()202 bool hasSeenError() { return mAsyncHandle.getError(); } 203 public: getErrorMsg()204 std::string getErrorMsg() { 205 return mTestEnv + 206 "################### Error Details #####################\n" + 207 mErrorLogs; 208 } 209 }; 210 211 #endif // MEDIACTSNATIVE_NATIVE_CODEC_TEST_BASE_H 212