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