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 <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 CHECK_STATUS(status, str)                  \
32     {                                              \
33         media_status_t val = (status);             \
34         if (AMEDIA_OK != val) {                    \
35             ALOGE("%s with error %d", (str), val); \
36             return false;                          \
37         }                                          \
38     }
39 
40 #define CHECK_ERR(val, strA, strB, result) \
41     if ((val)) {                           \
42         (result) = false;                  \
43         ALOGE("%s %s", (strA), (strB));    \
44     }
45 
46 struct callbackObject {
47     AMediaCodecBufferInfo bufferInfo;
48     int32_t bufferIndex;
49     bool isInput;
50 
callbackObjectcallbackObject51     callbackObject(int32_t index, AMediaCodecBufferInfo* info)
52         : bufferInfo{*info}, bufferIndex{index}, isInput{false} {}
53 
callbackObjectcallbackObject54     callbackObject(int32_t index) : bufferIndex{index}, isInput{true} {}
55 
callbackObjectcallbackObject56     callbackObject() : bufferIndex{-1}, isInput{false} {}
57 };
58 
59 class CodecAsyncHandler {
60   private:
61     std::mutex mMutex;
62     std::condition_variable mCondition;
63     std::list<callbackObject> mCbInputQueue;
64     std::list<callbackObject> mCbOutputQueue;
65     AMediaFormat* mOutFormat;
66     volatile bool mSignalledOutFormatChanged;
67     volatile bool mSignalledError;
68 
69   public:
70     CodecAsyncHandler();
71     ~CodecAsyncHandler();
72     void pushToInputList(callbackObject element);
73     void pushToOutputList(callbackObject element);
74     callbackObject getInput();
75     callbackObject getOutput();
76     callbackObject getWork();
77     bool isInputQueueEmpty();
78     void clearQueues();
79     void setOutputFormat(AMediaFormat* format);
80     AMediaFormat* getOutputFormat();
81     bool hasOutputFormatChanged();
82     void setError(bool status);
83     bool getError();
84     void resetContext();
85     media_status_t setCallBack(AMediaCodec* codec, bool isCodecInAsyncMode);
86 };
87 
88 class OutputManager {
89   private:
90     std::vector<int64_t> inpPtsArray;
91     std::vector<int64_t> outPtsArray;
92     std::vector<uint8_t> memory;
93     uLong crc32value = 0U;
94 
95   public:
saveInPTS(int64_t pts)96     void saveInPTS(int64_t pts) {
97         // Add only Unique timeStamp, discarding any duplicate frame / non-display frame
98         if (0 == std::count(inpPtsArray.begin(), inpPtsArray.end(), pts)) {
99             inpPtsArray.push_back(pts);
100         }
101     }
saveOutPTS(int64_t pts)102     void saveOutPTS(int64_t pts) { outPtsArray.push_back(pts); }
103     bool isPtsStrictlyIncreasing(int64_t lastPts);
104     bool isOutPtsListIdenticalToInpPtsList(bool requireSorting);
saveToMemory(uint8_t * buf,AMediaCodecBufferInfo * info)105     void saveToMemory(uint8_t* buf, AMediaCodecBufferInfo* info) {
106         memory.insert(memory.end(), buf, buf + info->size);
107     }
updateChecksum(uint8_t * buf,AMediaCodecBufferInfo * info)108     void updateChecksum(uint8_t* buf, AMediaCodecBufferInfo* info) {
109         updateChecksum(buf, info, 0, 0, 0);
110     }
111     void updateChecksum(
112             uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height, int stride);
getChecksum()113     uLong getChecksum() { return crc32value; }
reset()114     void reset() {
115         inpPtsArray.clear();
116         outPtsArray.clear();
117         memory.clear();
118         crc32value = 0U;
119     }
120     bool equals(const OutputManager* that);
121     float getRmsError(uint8_t* refData, int length);
getOutStreamSize()122     int getOutStreamSize() { return memory.size(); }
123 };
124 
125 class CodecTestBase {
126   protected:
127     const char* mMime;
128     bool mIsAudio;
129     CodecAsyncHandler mAsyncHandle;
130     bool mIsCodecInAsyncMode;
131     bool mSawInputEOS;
132     bool mSawOutputEOS;
133     bool mSignalEOSWithLastFrame;
134     int mInputCount;
135     int mOutputCount;
136     int64_t mPrevOutputPts;
137     bool mSignalledOutFormatChanged;
138     AMediaFormat* mOutFormat;
139 
140     bool mSaveToMem;
141     OutputManager* mOutputBuff;
142     OutputManager mRefBuff;
143     OutputManager mTestBuff;
144     OutputManager mReconfBuff;
145 
146     AMediaCodec* mCodec;
147 
148     CodecTestBase(const char* mime);
149     ~CodecTestBase();
150     virtual bool configureCodec(AMediaFormat* format, bool isAsync, bool signalEOSWithLastFrame,
151                                 bool isEncoder);
152     virtual bool flushCodec();
153     bool reConfigureCodec(AMediaFormat* format, bool isAsync, bool signalEOSWithLastFrame,
154                           bool isEncoder);
155     virtual void resetContext(bool isAsync, bool signalEOSWithLastFrame);
156     virtual bool enqueueInput(size_t bufferIndex) = 0;
157     virtual bool dequeueOutput(size_t bufferIndex, AMediaCodecBufferInfo* bufferInfo) = 0;
158     bool enqueueEOS(size_t bufferIndex);
159     bool doWork(int frameLimit);
160     bool queueEOS();
161     bool waitForAllOutputs();
162     int getWidth(AMediaFormat* format);
163     int getHeight(AMediaFormat* format);
164     bool isFormatSimilar(AMediaFormat* inpFormat, AMediaFormat* outFormat);
hasSeenError()165     bool hasSeenError() { return mAsyncHandle.getError(); }
166 };
167 
168 #endif  // MEDIACTSNATIVE_NATIVE_CODEC_TEST_BASE_H
169