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