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 "NativeCodecEncoderTest"
19*b7c941bbSAndroid Build Coastguard Worker #include <log/log.h>
20*b7c941bbSAndroid Build Coastguard Worker
21*b7c941bbSAndroid Build Coastguard Worker #include <jni.h>
22*b7c941bbSAndroid Build Coastguard Worker #include <sys/stat.h>
23*b7c941bbSAndroid Build Coastguard Worker
24*b7c941bbSAndroid Build Coastguard Worker #include "NativeCodecTestBase.h"
25*b7c941bbSAndroid Build Coastguard Worker #include "NativeMediaCommon.h"
26*b7c941bbSAndroid Build Coastguard Worker
27*b7c941bbSAndroid Build Coastguard Worker class CodecEncoderTest final : public CodecTestBase {
28*b7c941bbSAndroid Build Coastguard Worker private:
29*b7c941bbSAndroid Build Coastguard Worker uint8_t* mInputData;
30*b7c941bbSAndroid Build Coastguard Worker size_t mInputLength;
31*b7c941bbSAndroid Build Coastguard Worker int mInputBufferReadOffset;
32*b7c941bbSAndroid Build Coastguard Worker int mNumBytesSubmitted;
33*b7c941bbSAndroid Build Coastguard Worker int mLoopBackFrameLimit;
34*b7c941bbSAndroid Build Coastguard Worker bool mIsLoopBack;
35*b7c941bbSAndroid Build Coastguard Worker int64_t mInputOffsetPts;
36*b7c941bbSAndroid Build Coastguard Worker std::vector<AMediaFormat*> mFormats;
37*b7c941bbSAndroid Build Coastguard Worker int mNumSyncFramesReceived;
38*b7c941bbSAndroid Build Coastguard Worker std::vector<int> mSyncFramesPos;
39*b7c941bbSAndroid Build Coastguard Worker
40*b7c941bbSAndroid Build Coastguard Worker int mWidth, mHeight;
41*b7c941bbSAndroid Build Coastguard Worker int mChannels;
42*b7c941bbSAndroid Build Coastguard Worker int mSampleRate;
43*b7c941bbSAndroid Build Coastguard Worker int mColorFormat;
44*b7c941bbSAndroid Build Coastguard Worker int mMaxBFrames;
45*b7c941bbSAndroid Build Coastguard Worker int mDefFrameRate;
46*b7c941bbSAndroid Build Coastguard Worker const int kInpFrmWidth = 352;
47*b7c941bbSAndroid Build Coastguard Worker const int kInpFrmHeight = 288;
48*b7c941bbSAndroid Build Coastguard Worker
49*b7c941bbSAndroid Build Coastguard Worker void convertyuv420ptoyuv420sp();
50*b7c941bbSAndroid Build Coastguard Worker void setUpSource(const char* srcPath);
51*b7c941bbSAndroid Build Coastguard Worker void deleteSource();
52*b7c941bbSAndroid Build Coastguard Worker void deleteParams();
53*b7c941bbSAndroid Build Coastguard Worker bool configureCodec(AMediaFormat* format, bool isAsync, bool signalEOSWithLastFrame,
54*b7c941bbSAndroid Build Coastguard Worker bool isEncoder) override;
55*b7c941bbSAndroid Build Coastguard Worker void resetContext(bool isAsync, bool signalEOSWithLastFrame) override;
56*b7c941bbSAndroid Build Coastguard Worker bool enqueueInput(size_t bufferIndex) override;
57*b7c941bbSAndroid Build Coastguard Worker bool dequeueOutput(size_t bufferIndex, AMediaCodecBufferInfo* bufferInfo) override;
58*b7c941bbSAndroid Build Coastguard Worker bool doWork(int frameLimit) override;
59*b7c941bbSAndroid Build Coastguard Worker bool isTestStateValid() override;
60*b7c941bbSAndroid Build Coastguard Worker bool initFormat(AMediaFormat* format);
61*b7c941bbSAndroid Build Coastguard Worker bool encodeToMemory(const char* file, const char* encoder, int frameLimit, AMediaFormat* format,
62*b7c941bbSAndroid Build Coastguard Worker OutputManager* ref);
63*b7c941bbSAndroid Build Coastguard Worker void fillByteBuffer(uint8_t* inputBuffer);
64*b7c941bbSAndroid Build Coastguard Worker void forceSyncFrame(AMediaFormat* format);
65*b7c941bbSAndroid Build Coastguard Worker void updateBitrate(AMediaFormat* format, int bitrate);
66*b7c941bbSAndroid Build Coastguard Worker
67*b7c941bbSAndroid Build Coastguard Worker public:
68*b7c941bbSAndroid Build Coastguard Worker CodecEncoderTest(const char* mediaType, const char* cfgParams, const char* cfgReconfigParams,
69*b7c941bbSAndroid Build Coastguard Worker const char* separator);
70*b7c941bbSAndroid Build Coastguard Worker ~CodecEncoderTest();
71*b7c941bbSAndroid Build Coastguard Worker
72*b7c941bbSAndroid Build Coastguard Worker bool testSimpleEncode(const char* encoder, const char* srcPath, int frameLimit);
73*b7c941bbSAndroid Build Coastguard Worker bool testReconfigure(const char* encoder, const char* srcPath, int frameLimit);
74*b7c941bbSAndroid Build Coastguard Worker bool testSetForceSyncFrame(const char* encoder, const char* srcPath);
75*b7c941bbSAndroid Build Coastguard Worker bool testAdaptiveBitRate(const char* encoder, const char* srcPath);
76*b7c941bbSAndroid Build Coastguard Worker bool testOnlyEos(const char* encoder);
77*b7c941bbSAndroid Build Coastguard Worker };
78*b7c941bbSAndroid Build Coastguard Worker
CodecEncoderTest(const char * mediaType,const char * cfgParams,const char * cfgReconfigParams,const char * separator)79*b7c941bbSAndroid Build Coastguard Worker CodecEncoderTest::CodecEncoderTest(const char* mediaType, const char* cfgParams,
80*b7c941bbSAndroid Build Coastguard Worker const char* cfgReconfigParams, const char* separator)
81*b7c941bbSAndroid Build Coastguard Worker : CodecTestBase(mediaType) {
82*b7c941bbSAndroid Build Coastguard Worker mFormats.push_back(deSerializeMediaFormat(cfgParams, separator));
83*b7c941bbSAndroid Build Coastguard Worker if (cfgReconfigParams) {
84*b7c941bbSAndroid Build Coastguard Worker mFormats.push_back(deSerializeMediaFormat(cfgReconfigParams, separator));
85*b7c941bbSAndroid Build Coastguard Worker }
86*b7c941bbSAndroid Build Coastguard Worker if (mIsVideo && mFormats[0] != nullptr) {
87*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getInt32(mFormats[0], AMEDIAFORMAT_KEY_COLOR_FORMAT, &mColorFormat);
88*b7c941bbSAndroid Build Coastguard Worker }
89*b7c941bbSAndroid Build Coastguard Worker mInputData = nullptr;
90*b7c941bbSAndroid Build Coastguard Worker mInputLength = 0;
91*b7c941bbSAndroid Build Coastguard Worker mInputBufferReadOffset = 0;
92*b7c941bbSAndroid Build Coastguard Worker mNumBytesSubmitted = 0;
93*b7c941bbSAndroid Build Coastguard Worker mLoopBackFrameLimit = 0;
94*b7c941bbSAndroid Build Coastguard Worker mIsLoopBack = false;
95*b7c941bbSAndroid Build Coastguard Worker mInputOffsetPts = 0;
96*b7c941bbSAndroid Build Coastguard Worker }
97*b7c941bbSAndroid Build Coastguard Worker
~CodecEncoderTest()98*b7c941bbSAndroid Build Coastguard Worker CodecEncoderTest::~CodecEncoderTest() {
99*b7c941bbSAndroid Build Coastguard Worker deleteSource();
100*b7c941bbSAndroid Build Coastguard Worker deleteParams();
101*b7c941bbSAndroid Build Coastguard Worker }
102*b7c941bbSAndroid Build Coastguard Worker
convertyuv420ptoyuv420sp()103*b7c941bbSAndroid Build Coastguard Worker void CodecEncoderTest::convertyuv420ptoyuv420sp() {
104*b7c941bbSAndroid Build Coastguard Worker int ySize = kInpFrmWidth * kInpFrmHeight;
105*b7c941bbSAndroid Build Coastguard Worker int uSize = kInpFrmWidth * kInpFrmHeight / 4;
106*b7c941bbSAndroid Build Coastguard Worker int frameSize = ySize + uSize * 2;
107*b7c941bbSAndroid Build Coastguard Worker int totalFrames = mInputLength / frameSize;
108*b7c941bbSAndroid Build Coastguard Worker uint8_t* u = new uint8_t[uSize];
109*b7c941bbSAndroid Build Coastguard Worker uint8_t* v = new uint8_t[uSize];
110*b7c941bbSAndroid Build Coastguard Worker uint8_t* frameBase = mInputData;
111*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < totalFrames; i++) {
112*b7c941bbSAndroid Build Coastguard Worker uint8_t* uvBase = frameBase + ySize;
113*b7c941bbSAndroid Build Coastguard Worker memcpy(u, uvBase, uSize);
114*b7c941bbSAndroid Build Coastguard Worker memcpy(v, uvBase + uSize, uSize);
115*b7c941bbSAndroid Build Coastguard Worker for (int j = 0, idx = 0; j < uSize; j++, idx += 2) {
116*b7c941bbSAndroid Build Coastguard Worker uvBase[idx] = u[j];
117*b7c941bbSAndroid Build Coastguard Worker uvBase[idx + 1] = v[j];
118*b7c941bbSAndroid Build Coastguard Worker }
119*b7c941bbSAndroid Build Coastguard Worker frameBase += frameSize;
120*b7c941bbSAndroid Build Coastguard Worker }
121*b7c941bbSAndroid Build Coastguard Worker delete[] u;
122*b7c941bbSAndroid Build Coastguard Worker delete[] v;
123*b7c941bbSAndroid Build Coastguard Worker }
124*b7c941bbSAndroid Build Coastguard Worker
setUpSource(const char * srcPath)125*b7c941bbSAndroid Build Coastguard Worker void CodecEncoderTest::setUpSource(const char* srcPath) {
126*b7c941bbSAndroid Build Coastguard Worker FILE* fp = fopen(srcPath, "rbe");
127*b7c941bbSAndroid Build Coastguard Worker struct stat buf {};
128*b7c941bbSAndroid Build Coastguard Worker if (fp && !fstat(fileno(fp), &buf)) {
129*b7c941bbSAndroid Build Coastguard Worker deleteSource();
130*b7c941bbSAndroid Build Coastguard Worker mInputLength = buf.st_size;
131*b7c941bbSAndroid Build Coastguard Worker mInputData = new uint8_t[mInputLength];
132*b7c941bbSAndroid Build Coastguard Worker fread(mInputData, sizeof(uint8_t), mInputLength, fp);
133*b7c941bbSAndroid Build Coastguard Worker if (mColorFormat == COLOR_FormatYUV420SemiPlanar) {
134*b7c941bbSAndroid Build Coastguard Worker convertyuv420ptoyuv420sp();
135*b7c941bbSAndroid Build Coastguard Worker }
136*b7c941bbSAndroid Build Coastguard Worker } else {
137*b7c941bbSAndroid Build Coastguard Worker ALOGE("unable to open input file %s", srcPath);
138*b7c941bbSAndroid Build Coastguard Worker }
139*b7c941bbSAndroid Build Coastguard Worker if (fp) fclose(fp);
140*b7c941bbSAndroid Build Coastguard Worker }
141*b7c941bbSAndroid Build Coastguard Worker
deleteSource()142*b7c941bbSAndroid Build Coastguard Worker void CodecEncoderTest::deleteSource() {
143*b7c941bbSAndroid Build Coastguard Worker if (mInputData) {
144*b7c941bbSAndroid Build Coastguard Worker delete[] mInputData;
145*b7c941bbSAndroid Build Coastguard Worker mInputData = nullptr;
146*b7c941bbSAndroid Build Coastguard Worker }
147*b7c941bbSAndroid Build Coastguard Worker mInputLength = 0;
148*b7c941bbSAndroid Build Coastguard Worker }
149*b7c941bbSAndroid Build Coastguard Worker
deleteParams()150*b7c941bbSAndroid Build Coastguard Worker void CodecEncoderTest::deleteParams() {
151*b7c941bbSAndroid Build Coastguard Worker for (auto format : mFormats) AMediaFormat_delete(format);
152*b7c941bbSAndroid Build Coastguard Worker mFormats.clear();
153*b7c941bbSAndroid Build Coastguard Worker }
154*b7c941bbSAndroid Build Coastguard Worker
configureCodec(AMediaFormat * format,bool isAsync,bool signalEOSWithLastFrame,bool isEncoder)155*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::configureCodec(AMediaFormat* format, bool isAsync,
156*b7c941bbSAndroid Build Coastguard Worker bool signalEOSWithLastFrame, bool isEncoder) {
157*b7c941bbSAndroid Build Coastguard Worker if (!initFormat(format)) return false;
158*b7c941bbSAndroid Build Coastguard Worker return CodecTestBase::configureCodec(format, isAsync, signalEOSWithLastFrame, isEncoder);
159*b7c941bbSAndroid Build Coastguard Worker }
160*b7c941bbSAndroid Build Coastguard Worker
resetContext(bool isAsync,bool signalEOSWithLastFrame)161*b7c941bbSAndroid Build Coastguard Worker void CodecEncoderTest::resetContext(bool isAsync, bool signalEOSWithLastFrame) {
162*b7c941bbSAndroid Build Coastguard Worker CodecTestBase::resetContext(isAsync, signalEOSWithLastFrame);
163*b7c941bbSAndroid Build Coastguard Worker mInputBufferReadOffset = 0;
164*b7c941bbSAndroid Build Coastguard Worker mNumBytesSubmitted = 0;
165*b7c941bbSAndroid Build Coastguard Worker mInputOffsetPts = 0;
166*b7c941bbSAndroid Build Coastguard Worker mNumSyncFramesReceived = 0;
167*b7c941bbSAndroid Build Coastguard Worker mSyncFramesPos.clear();
168*b7c941bbSAndroid Build Coastguard Worker }
169*b7c941bbSAndroid Build Coastguard Worker
fillByteBuffer(uint8_t * inputBuffer)170*b7c941bbSAndroid Build Coastguard Worker void CodecEncoderTest::fillByteBuffer(uint8_t* inputBuffer) {
171*b7c941bbSAndroid Build Coastguard Worker int width, height, tileWidth, tileHeight;
172*b7c941bbSAndroid Build Coastguard Worker int offset = 0, frmOffset = mInputBufferReadOffset;
173*b7c941bbSAndroid Build Coastguard Worker int numOfPlanes;
174*b7c941bbSAndroid Build Coastguard Worker if (mColorFormat == COLOR_FormatYUV420SemiPlanar) {
175*b7c941bbSAndroid Build Coastguard Worker numOfPlanes = 2;
176*b7c941bbSAndroid Build Coastguard Worker } else {
177*b7c941bbSAndroid Build Coastguard Worker numOfPlanes = 3;
178*b7c941bbSAndroid Build Coastguard Worker }
179*b7c941bbSAndroid Build Coastguard Worker for (int plane = 0; plane < numOfPlanes; plane++) {
180*b7c941bbSAndroid Build Coastguard Worker if (plane == 0) {
181*b7c941bbSAndroid Build Coastguard Worker width = mWidth;
182*b7c941bbSAndroid Build Coastguard Worker height = mHeight;
183*b7c941bbSAndroid Build Coastguard Worker tileWidth = kInpFrmWidth;
184*b7c941bbSAndroid Build Coastguard Worker tileHeight = kInpFrmHeight;
185*b7c941bbSAndroid Build Coastguard Worker } else {
186*b7c941bbSAndroid Build Coastguard Worker if (mColorFormat == COLOR_FormatYUV420SemiPlanar) {
187*b7c941bbSAndroid Build Coastguard Worker width = mWidth;
188*b7c941bbSAndroid Build Coastguard Worker tileWidth = kInpFrmWidth;
189*b7c941bbSAndroid Build Coastguard Worker } else {
190*b7c941bbSAndroid Build Coastguard Worker width = mWidth / 2;
191*b7c941bbSAndroid Build Coastguard Worker tileWidth = kInpFrmWidth / 2;
192*b7c941bbSAndroid Build Coastguard Worker }
193*b7c941bbSAndroid Build Coastguard Worker height = mHeight / 2;
194*b7c941bbSAndroid Build Coastguard Worker tileHeight = kInpFrmHeight / 2;
195*b7c941bbSAndroid Build Coastguard Worker }
196*b7c941bbSAndroid Build Coastguard Worker for (int k = 0; k < height; k += tileHeight) {
197*b7c941bbSAndroid Build Coastguard Worker int rowsToCopy = std::min(height - k, tileHeight);
198*b7c941bbSAndroid Build Coastguard Worker for (int j = 0; j < rowsToCopy; j++) {
199*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < width; i += tileWidth) {
200*b7c941bbSAndroid Build Coastguard Worker int colsToCopy = std::min(width - i, tileWidth);
201*b7c941bbSAndroid Build Coastguard Worker memcpy(inputBuffer + (offset + (k + j) * width + i),
202*b7c941bbSAndroid Build Coastguard Worker mInputData + (frmOffset + j * tileWidth), colsToCopy);
203*b7c941bbSAndroid Build Coastguard Worker }
204*b7c941bbSAndroid Build Coastguard Worker }
205*b7c941bbSAndroid Build Coastguard Worker }
206*b7c941bbSAndroid Build Coastguard Worker offset += width * height;
207*b7c941bbSAndroid Build Coastguard Worker frmOffset += tileWidth * tileHeight;
208*b7c941bbSAndroid Build Coastguard Worker }
209*b7c941bbSAndroid Build Coastguard Worker }
210*b7c941bbSAndroid Build Coastguard Worker
enqueueInput(size_t bufferIndex)211*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::enqueueInput(size_t bufferIndex) {
212*b7c941bbSAndroid Build Coastguard Worker if (mInputBufferReadOffset >= mInputLength) {
213*b7c941bbSAndroid Build Coastguard Worker if (!mIsLoopBack) return enqueueEOS(bufferIndex);
214*b7c941bbSAndroid Build Coastguard Worker mInputBufferReadOffset = 0; // loop back to beginning
215*b7c941bbSAndroid Build Coastguard Worker }
216*b7c941bbSAndroid Build Coastguard Worker {
217*b7c941bbSAndroid Build Coastguard Worker int size = 0;
218*b7c941bbSAndroid Build Coastguard Worker int flags = 0;
219*b7c941bbSAndroid Build Coastguard Worker int64_t pts = mInputOffsetPts;
220*b7c941bbSAndroid Build Coastguard Worker size_t buffSize;
221*b7c941bbSAndroid Build Coastguard Worker uint8_t* inputBuffer = AMediaCodec_getInputBuffer(mCodec, bufferIndex, &buffSize);
222*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(inputBuffer, std::string{"AMediaCodec_getInputBuffer returned nullptr"})
223*b7c941bbSAndroid Build Coastguard Worker if (mIsAudio) {
224*b7c941bbSAndroid Build Coastguard Worker pts += mNumBytesSubmitted * 1000000LL / (2 * mChannels * mSampleRate);
225*b7c941bbSAndroid Build Coastguard Worker size = std::min(buffSize, mInputLength - mInputBufferReadOffset);
226*b7c941bbSAndroid Build Coastguard Worker memcpy(inputBuffer, mInputData + mInputBufferReadOffset, size);
227*b7c941bbSAndroid Build Coastguard Worker if (mSignalEOSWithLastFrame) {
228*b7c941bbSAndroid Build Coastguard Worker if (mIsLoopBack ? (mInputCount + 1 >= mLoopBackFrameLimit)
229*b7c941bbSAndroid Build Coastguard Worker : (mInputBufferReadOffset + size >= mInputLength)) {
230*b7c941bbSAndroid Build Coastguard Worker flags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
231*b7c941bbSAndroid Build Coastguard Worker mSawInputEOS = true;
232*b7c941bbSAndroid Build Coastguard Worker }
233*b7c941bbSAndroid Build Coastguard Worker }
234*b7c941bbSAndroid Build Coastguard Worker mInputBufferReadOffset += size;
235*b7c941bbSAndroid Build Coastguard Worker } else {
236*b7c941bbSAndroid Build Coastguard Worker pts += mInputCount * 1000000LL / mDefFrameRate;
237*b7c941bbSAndroid Build Coastguard Worker size = mWidth * mHeight * 3 / 2;
238*b7c941bbSAndroid Build Coastguard Worker int frmSize = kInpFrmWidth * kInpFrmHeight * 3 / 2;
239*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(mInputBufferReadOffset + frmSize > mInputLength,
240*b7c941bbSAndroid Build Coastguard Worker std::string{"received partial frame to encode"})
241*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(size > buffSize,
242*b7c941bbSAndroid Build Coastguard Worker StringFormat("frame size exceeds buffer capacity of input buffer %d %zu",
243*b7c941bbSAndroid Build Coastguard Worker size, buffSize))
244*b7c941bbSAndroid Build Coastguard Worker if (mWidth == kInpFrmWidth && mHeight == kInpFrmHeight) {
245*b7c941bbSAndroid Build Coastguard Worker memcpy(inputBuffer, mInputData + mInputBufferReadOffset, size);
246*b7c941bbSAndroid Build Coastguard Worker } else {
247*b7c941bbSAndroid Build Coastguard Worker fillByteBuffer(inputBuffer);
248*b7c941bbSAndroid Build Coastguard Worker }
249*b7c941bbSAndroid Build Coastguard Worker if (mSignalEOSWithLastFrame) {
250*b7c941bbSAndroid Build Coastguard Worker if (mIsLoopBack ? (mInputCount + 1 >= mLoopBackFrameLimit)
251*b7c941bbSAndroid Build Coastguard Worker : (mInputBufferReadOffset + frmSize >= mInputLength)) {
252*b7c941bbSAndroid Build Coastguard Worker flags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
253*b7c941bbSAndroid Build Coastguard Worker mSawInputEOS = true;
254*b7c941bbSAndroid Build Coastguard Worker }
255*b7c941bbSAndroid Build Coastguard Worker }
256*b7c941bbSAndroid Build Coastguard Worker mInputBufferReadOffset += frmSize;
257*b7c941bbSAndroid Build Coastguard Worker }
258*b7c941bbSAndroid Build Coastguard Worker mNumBytesSubmitted += size;
259*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_queueInputBuffer(mCodec, bufferIndex, 0, size, pts, flags),
260*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_queueInputBuffer failed")
261*b7c941bbSAndroid Build Coastguard Worker ALOGV("input: id: %zu size: %d pts: %" PRId64 " flags: %d", bufferIndex, size, pts,
262*b7c941bbSAndroid Build Coastguard Worker flags);
263*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->saveInPTS(pts);
264*b7c941bbSAndroid Build Coastguard Worker mInputCount++;
265*b7c941bbSAndroid Build Coastguard Worker }
266*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
267*b7c941bbSAndroid Build Coastguard Worker }
268*b7c941bbSAndroid Build Coastguard Worker
dequeueOutput(size_t bufferIndex,AMediaCodecBufferInfo * info)269*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::dequeueOutput(size_t bufferIndex, AMediaCodecBufferInfo* info) {
270*b7c941bbSAndroid Build Coastguard Worker if ((info->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) != 0) {
271*b7c941bbSAndroid Build Coastguard Worker mSawOutputEOS = true;
272*b7c941bbSAndroid Build Coastguard Worker }
273*b7c941bbSAndroid Build Coastguard Worker if (info->size > 0) {
274*b7c941bbSAndroid Build Coastguard Worker if (mSaveToMem) {
275*b7c941bbSAndroid Build Coastguard Worker size_t buffSize;
276*b7c941bbSAndroid Build Coastguard Worker uint8_t* buf = AMediaCodec_getOutputBuffer(mCodec, bufferIndex, &buffSize);
277*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(buf, std::string{"AMediaCodec_getOutputBuffer returned nullptr"})
278*b7c941bbSAndroid Build Coastguard Worker // NdkMediaCodec calls ABuffer::data, which already adds offset
279*b7c941bbSAndroid Build Coastguard Worker info->offset = 0;
280*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->saveToMemory(buf, info);
281*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->updateChecksum(buf, info);
282*b7c941bbSAndroid Build Coastguard Worker }
283*b7c941bbSAndroid Build Coastguard Worker if ((info->flags & AMEDIACODEC_BUFFER_FLAG_KEY_FRAME) != 0) {
284*b7c941bbSAndroid Build Coastguard Worker mNumSyncFramesReceived += 1;
285*b7c941bbSAndroid Build Coastguard Worker mSyncFramesPos.push_back(mOutputCount);
286*b7c941bbSAndroid Build Coastguard Worker }
287*b7c941bbSAndroid Build Coastguard Worker if ((info->flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) == 0) {
288*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->saveOutPTS(info->presentationTimeUs);
289*b7c941bbSAndroid Build Coastguard Worker mOutputCount++;
290*b7c941bbSAndroid Build Coastguard Worker }
291*b7c941bbSAndroid Build Coastguard Worker }
292*b7c941bbSAndroid Build Coastguard Worker ALOGV("output: id: %zu size: %d pts: %" PRId64 " flags: %d", bufferIndex, info->size,
293*b7c941bbSAndroid Build Coastguard Worker info->presentationTimeUs, info->flags);
294*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_releaseOutputBuffer(mCodec, bufferIndex, false),
295*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_releaseOutputBuffer failed")
296*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
297*b7c941bbSAndroid Build Coastguard Worker }
298*b7c941bbSAndroid Build Coastguard Worker
doWork(int frameLimit)299*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::doWork(int frameLimit) {
300*b7c941bbSAndroid Build Coastguard Worker mLoopBackFrameLimit = frameLimit;
301*b7c941bbSAndroid Build Coastguard Worker return CodecTestBase::doWork(frameLimit);
302*b7c941bbSAndroid Build Coastguard Worker }
303*b7c941bbSAndroid Build Coastguard Worker
isTestStateValid()304*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::isTestStateValid() {
305*b7c941bbSAndroid Build Coastguard Worker if (!CodecTestBase::isTestStateValid()) return false;
306*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE((mIsAudio || (mIsVideo && mMaxBFrames == 0)) &&
307*b7c941bbSAndroid Build Coastguard Worker !mOutputBuff->isPtsStrictlyIncreasing(mPrevOutputPts),
308*b7c941bbSAndroid Build Coastguard Worker std::string{"Output timestamps are not strictly increasing \n"}.append(
309*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->getErrorMsg()))
310*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(mIsVideo && !mOutputBuff->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0),
311*b7c941bbSAndroid Build Coastguard Worker std::string{"Input pts list and Output pts list are not identical \n"}.append(
312*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->getErrorMsg()))
313*b7c941bbSAndroid Build Coastguard Worker return true;
314*b7c941bbSAndroid Build Coastguard Worker }
315*b7c941bbSAndroid Build Coastguard Worker
316*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAFORMAT_KEY_CHANNEL_COUNT
317*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAFORMAT_KEY_COLOR_FORMAT
318*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAFORMAT_KEY_FRAME_RATE
319*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAFORMAT_KEY_HEIGHT
320*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAFORMAT_KEY_MAX_B_FRAMES
321*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAFORMAT_KEY_SAMPLE_RATE
322*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAFORMAT_KEY_WIDTH
323*b7c941bbSAndroid Build Coastguard Worker //
initFormat(AMediaFormat * format)324*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::initFormat(AMediaFormat* format) {
325*b7c941bbSAndroid Build Coastguard Worker if (mIsAudio) {
326*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate),
327*b7c941bbSAndroid Build Coastguard Worker StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_SAMPLE_RATE))
328*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mChannels),
329*b7c941bbSAndroid Build Coastguard Worker StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_CHANNEL_COUNT))
330*b7c941bbSAndroid Build Coastguard Worker } else {
331*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &mWidth),
332*b7c941bbSAndroid Build Coastguard Worker StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_WIDTH))
333*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &mHeight),
334*b7c941bbSAndroid Build Coastguard Worker StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_HEIGHT))
335*b7c941bbSAndroid Build Coastguard Worker // key formalized in Android U (sdk==34).
336*b7c941bbSAndroid Build Coastguard Worker // Use internally-defined when running on earlier releases, such as happens with MTS
337*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __ANDROID_API_U__, *)) {
338*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_MAX_B_FRAMES,
339*b7c941bbSAndroid Build Coastguard Worker &mMaxBFrames),
340*b7c941bbSAndroid Build Coastguard Worker StringFormat("format does not have key %s",
341*b7c941bbSAndroid Build Coastguard Worker AMEDIAFORMAT_KEY_MAX_B_FRAMES))
342*b7c941bbSAndroid Build Coastguard Worker } else {
343*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(AMediaFormat_getInt32(format, COMPATIBLE_AMEDIAFORMAT_KEY_MAX_B_FRAMES,
344*b7c941bbSAndroid Build Coastguard Worker &mMaxBFrames),
345*b7c941bbSAndroid Build Coastguard Worker StringFormat("format does not have key %s",
346*b7c941bbSAndroid Build Coastguard Worker COMPATIBLE_AMEDIAFORMAT_KEY_MAX_B_FRAMES))
347*b7c941bbSAndroid Build Coastguard Worker }
348*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &mDefFrameRate),
349*b7c941bbSAndroid Build Coastguard Worker StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_FRAME_RATE))
350*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, &mColorFormat),
351*b7c941bbSAndroid Build Coastguard Worker StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_COLOR_FORMAT))
352*b7c941bbSAndroid Build Coastguard Worker }
353*b7c941bbSAndroid Build Coastguard Worker return true;
354*b7c941bbSAndroid Build Coastguard Worker }
355*b7c941bbSAndroid Build Coastguard Worker
encodeToMemory(const char * file,const char * encoder,int32_t frameLimit,AMediaFormat * format,OutputManager * ref)356*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::encodeToMemory(const char* file, const char* encoder, int32_t frameLimit,
357*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* format, OutputManager* ref) {
358*b7c941bbSAndroid Build Coastguard Worker /* TODO(b/149027258) */
359*b7c941bbSAndroid Build Coastguard Worker if (true) mSaveToMem = false;
360*b7c941bbSAndroid Build Coastguard Worker else mSaveToMem = true;
361*b7c941bbSAndroid Build Coastguard Worker mOutputBuff = ref;
362*b7c941bbSAndroid Build Coastguard Worker mCodec = AMediaCodec_createCodecByName(encoder);
363*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mCodec, StringFormat("unable to create codec by name %s \n", encoder))
364*b7c941bbSAndroid Build Coastguard Worker setUpSource(file);
365*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mInputData, StringFormat("unable to open input file %s", file))
366*b7c941bbSAndroid Build Coastguard Worker if (!configureCodec(format, false, true, true)) return false;
367*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
368*b7c941bbSAndroid Build Coastguard Worker if (!doWork(frameLimit)) return false;
369*b7c941bbSAndroid Build Coastguard Worker if (!queueEOS()) return false;
370*b7c941bbSAndroid Build Coastguard Worker if (!waitForAllOutputs()) return false;
371*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed")
372*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed")
373*b7c941bbSAndroid Build Coastguard Worker mCodec = nullptr;
374*b7c941bbSAndroid Build Coastguard Worker mSaveToMem = false;
375*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
376*b7c941bbSAndroid Build Coastguard Worker }
377*b7c941bbSAndroid Build Coastguard Worker
forceSyncFrame(AMediaFormat * format)378*b7c941bbSAndroid Build Coastguard Worker void CodecEncoderTest::forceSyncFrame(AMediaFormat* format) {
379*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_setInt32(format, TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
380*b7c941bbSAndroid Build Coastguard Worker ALOGV("requesting key frame");
381*b7c941bbSAndroid Build Coastguard Worker AMediaCodec_setParameters(mCodec, format);
382*b7c941bbSAndroid Build Coastguard Worker }
383*b7c941bbSAndroid Build Coastguard Worker
updateBitrate(AMediaFormat * format,int bitrate)384*b7c941bbSAndroid Build Coastguard Worker void CodecEncoderTest::updateBitrate(AMediaFormat* format, int bitrate) {
385*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_setInt32(format, TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE, bitrate);
386*b7c941bbSAndroid Build Coastguard Worker ALOGV("requesting bitrate to be changed to %d", bitrate);
387*b7c941bbSAndroid Build Coastguard Worker AMediaCodec_setParameters(mCodec, format);
388*b7c941bbSAndroid Build Coastguard Worker }
389*b7c941bbSAndroid Build Coastguard Worker
testSimpleEncode(const char * encoder,const char * srcPath,int frameLimit)390*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::testSimpleEncode(const char* encoder, const char* srcPath, int frameLimit) {
391*b7c941bbSAndroid Build Coastguard Worker setUpSource(srcPath);
392*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mInputData, StringFormat("unable to open input file %s", srcPath))
393*b7c941bbSAndroid Build Coastguard Worker /* TODO(b/149027258) */
394*b7c941bbSAndroid Build Coastguard Worker if (true) mSaveToMem = false;
395*b7c941bbSAndroid Build Coastguard Worker else mSaveToMem = true;
396*b7c941bbSAndroid Build Coastguard Worker auto ref = mRefBuff;
397*b7c941bbSAndroid Build Coastguard Worker auto test = mTestBuff;
398*b7c941bbSAndroid Build Coastguard Worker const bool boolStates[]{true, false};
399*b7c941bbSAndroid Build Coastguard Worker for (auto format : mFormats) {
400*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(format,
401*b7c941bbSAndroid Build Coastguard Worker std::string{"encountered error during deserialization of media format"})
402*b7c941bbSAndroid Build Coastguard Worker int loopCounter = 0;
403*b7c941bbSAndroid Build Coastguard Worker for (auto eosType : boolStates) {
404*b7c941bbSAndroid Build Coastguard Worker for (auto isAsync : boolStates) {
405*b7c941bbSAndroid Build Coastguard Worker mOutputBuff = loopCounter == 0 ? ref : test;
406*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->reset();
407*b7c941bbSAndroid Build Coastguard Worker /* TODO(b/147348711) */
408*b7c941bbSAndroid Build Coastguard Worker /* Instead of create and delete codec at every iteration, we would like to create
409*b7c941bbSAndroid Build Coastguard Worker * once and use it for all iterations and delete before exiting */
410*b7c941bbSAndroid Build Coastguard Worker mCodec = AMediaCodec_createCodecByName(encoder);
411*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mCodec, StringFormat("unable to create codec %s", encoder))
412*b7c941bbSAndroid Build Coastguard Worker char* name = nullptr;
413*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_getName(mCodec, &name), "AMediaCodec_getName failed")
414*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(name, std::string{"AMediaCodec_getName returned null"})
415*b7c941bbSAndroid Build Coastguard Worker auto res = strcmp(name, encoder) != 0;
416*b7c941bbSAndroid Build Coastguard Worker AMediaCodec_releaseName(mCodec, name);
417*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(res,
418*b7c941bbSAndroid Build Coastguard Worker StringFormat("Codec name mismatch act/got: %s/%s", encoder, name))
419*b7c941bbSAndroid Build Coastguard Worker if (!configureCodec(format, isAsync, eosType, true)) return false;
420*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
421*b7c941bbSAndroid Build Coastguard Worker if (!doWork(frameLimit)) return false;
422*b7c941bbSAndroid Build Coastguard Worker if (!queueEOS()) return false;
423*b7c941bbSAndroid Build Coastguard Worker if (!waitForAllOutputs()) return false;
424*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed")
425*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed")
426*b7c941bbSAndroid Build Coastguard Worker mCodec = nullptr;
427*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE((loopCounter != 0 && !ref->equals(test)),
428*b7c941bbSAndroid Build Coastguard Worker std::string{"Encoder output is not consistent across runs \n"}
429*b7c941bbSAndroid Build Coastguard Worker .append(test->getErrorMsg()))
430*b7c941bbSAndroid Build Coastguard Worker loopCounter++;
431*b7c941bbSAndroid Build Coastguard Worker }
432*b7c941bbSAndroid Build Coastguard Worker }
433*b7c941bbSAndroid Build Coastguard Worker }
434*b7c941bbSAndroid Build Coastguard Worker return true;
435*b7c941bbSAndroid Build Coastguard Worker }
436*b7c941bbSAndroid Build Coastguard Worker
testReconfigure(const char * encoder,const char * srcPath,int frameLimit)437*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::testReconfigure(const char* encoder, const char* srcPath, int frameLimit) {
438*b7c941bbSAndroid Build Coastguard Worker setUpSource(srcPath);
439*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mInputData, StringFormat("unable to open input file %s", srcPath))
440*b7c941bbSAndroid Build Coastguard Worker auto configRef = mReconfBuff;
441*b7c941bbSAndroid Build Coastguard Worker if (mFormats.size() > 1) {
442*b7c941bbSAndroid Build Coastguard Worker auto format = mFormats[1];
443*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(format,
444*b7c941bbSAndroid Build Coastguard Worker std::string{"encountered error during deserialization of media format"})
445*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(encodeToMemory(srcPath, encoder, frameLimit, format, configRef),
446*b7c941bbSAndroid Build Coastguard Worker StringFormat("encodeToMemory failed for file: %s codec: %s \n format: %s",
447*b7c941bbSAndroid Build Coastguard Worker srcPath, encoder, AMediaFormat_toString(format)))
448*b7c941bbSAndroid Build Coastguard Worker }
449*b7c941bbSAndroid Build Coastguard Worker auto format = mFormats[0];
450*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(format, std::string{"encountered error during deserialization of media format"})
451*b7c941bbSAndroid Build Coastguard Worker auto ref = mRefBuff;
452*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(encodeToMemory(srcPath, encoder, frameLimit, format, ref),
453*b7c941bbSAndroid Build Coastguard Worker StringFormat("encodeToMemory failed for file: %s codec: %s \n format: %s",
454*b7c941bbSAndroid Build Coastguard Worker srcPath, encoder, AMediaFormat_toString(format)))
455*b7c941bbSAndroid Build Coastguard Worker
456*b7c941bbSAndroid Build Coastguard Worker auto test = mTestBuff;
457*b7c941bbSAndroid Build Coastguard Worker mOutputBuff = test;
458*b7c941bbSAndroid Build Coastguard Worker const bool boolStates[]{true, false};
459*b7c941bbSAndroid Build Coastguard Worker for (auto isAsync : boolStates) {
460*b7c941bbSAndroid Build Coastguard Worker /* TODO(b/147348711) */
461*b7c941bbSAndroid Build Coastguard Worker /* Instead of create and delete codec at every iteration, we would like to create
462*b7c941bbSAndroid Build Coastguard Worker * once and use it for all iterations and delete before exiting */
463*b7c941bbSAndroid Build Coastguard Worker mCodec = AMediaCodec_createCodecByName(encoder);
464*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mCodec, StringFormat("unable to create codec %s", encoder))
465*b7c941bbSAndroid Build Coastguard Worker if (!configureCodec(format, isAsync, true, true)) return false;
466*b7c941bbSAndroid Build Coastguard Worker /* test reconfigure in init state */
467*b7c941bbSAndroid Build Coastguard Worker if (!reConfigureCodec(format, !isAsync, false, true)) return false;
468*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
469*b7c941bbSAndroid Build Coastguard Worker
470*b7c941bbSAndroid Build Coastguard Worker /* test reconfigure in running state before queuing input */
471*b7c941bbSAndroid Build Coastguard Worker if (!reConfigureCodec(format, !isAsync, false, true)) return false;
472*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
473*b7c941bbSAndroid Build Coastguard Worker if (!doWork(23)) return false;
474*b7c941bbSAndroid Build Coastguard Worker
475*b7c941bbSAndroid Build Coastguard Worker /* test reconfigure codec in running state */
476*b7c941bbSAndroid Build Coastguard Worker if (!reConfigureCodec(format, isAsync, true, true)) return false;
477*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
478*b7c941bbSAndroid Build Coastguard Worker
479*b7c941bbSAndroid Build Coastguard Worker /* TODO(b/149027258) */
480*b7c941bbSAndroid Build Coastguard Worker if (true) mSaveToMem = false;
481*b7c941bbSAndroid Build Coastguard Worker else mSaveToMem = true;
482*b7c941bbSAndroid Build Coastguard Worker test->reset();
483*b7c941bbSAndroid Build Coastguard Worker if (!doWork(frameLimit)) return false;
484*b7c941bbSAndroid Build Coastguard Worker if (!queueEOS()) return false;
485*b7c941bbSAndroid Build Coastguard Worker if (!waitForAllOutputs()) return false;
486*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed")
487*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(!ref->equals(test),
488*b7c941bbSAndroid Build Coastguard Worker std::string{"Encoder output is not consistent across runs \n"}.append(
489*b7c941bbSAndroid Build Coastguard Worker test->getErrorMsg()))
490*b7c941bbSAndroid Build Coastguard Worker
491*b7c941bbSAndroid Build Coastguard Worker /* test reconfigure codec at eos state */
492*b7c941bbSAndroid Build Coastguard Worker if (!reConfigureCodec(format, !isAsync, false, true)) return false;
493*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
494*b7c941bbSAndroid Build Coastguard Worker test->reset();
495*b7c941bbSAndroid Build Coastguard Worker if (!doWork(frameLimit)) return false;
496*b7c941bbSAndroid Build Coastguard Worker if (!queueEOS()) return false;
497*b7c941bbSAndroid Build Coastguard Worker if (!waitForAllOutputs()) return false;
498*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed")
499*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(!ref->equals(test),
500*b7c941bbSAndroid Build Coastguard Worker std::string{"Encoder output is not consistent across runs \n"}.append(
501*b7c941bbSAndroid Build Coastguard Worker test->getErrorMsg()))
502*b7c941bbSAndroid Build Coastguard Worker
503*b7c941bbSAndroid Build Coastguard Worker /* test reconfigure codec for new format */
504*b7c941bbSAndroid Build Coastguard Worker if (mFormats.size() > 1) {
505*b7c941bbSAndroid Build Coastguard Worker if (!reConfigureCodec(mFormats[1], isAsync, false, true)) return false;
506*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
507*b7c941bbSAndroid Build Coastguard Worker test->reset();
508*b7c941bbSAndroid Build Coastguard Worker if (!doWork(frameLimit)) return false;
509*b7c941bbSAndroid Build Coastguard Worker if (!queueEOS()) return false;
510*b7c941bbSAndroid Build Coastguard Worker if (!waitForAllOutputs()) return false;
511*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed")
512*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(!configRef->equals(test),
513*b7c941bbSAndroid Build Coastguard Worker std::string{"Encoder output is not consistent across runs \n"}.append(
514*b7c941bbSAndroid Build Coastguard Worker test->getErrorMsg()))
515*b7c941bbSAndroid Build Coastguard Worker }
516*b7c941bbSAndroid Build Coastguard Worker mSaveToMem = false;
517*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed")
518*b7c941bbSAndroid Build Coastguard Worker mCodec = nullptr;
519*b7c941bbSAndroid Build Coastguard Worker }
520*b7c941bbSAndroid Build Coastguard Worker return true;
521*b7c941bbSAndroid Build Coastguard Worker }
522*b7c941bbSAndroid Build Coastguard Worker
testOnlyEos(const char * encoder)523*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::testOnlyEos(const char* encoder) {
524*b7c941bbSAndroid Build Coastguard Worker /* TODO(b/149027258) */
525*b7c941bbSAndroid Build Coastguard Worker if (true) mSaveToMem = false;
526*b7c941bbSAndroid Build Coastguard Worker else mSaveToMem = true;
527*b7c941bbSAndroid Build Coastguard Worker auto ref = mRefBuff;
528*b7c941bbSAndroid Build Coastguard Worker auto test = mTestBuff;
529*b7c941bbSAndroid Build Coastguard Worker const bool boolStates[]{true, false};
530*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* format = mFormats[0];
531*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(format, std::string{"encountered error during deserialization of media format"})
532*b7c941bbSAndroid Build Coastguard Worker int loopCounter = 0;
533*b7c941bbSAndroid Build Coastguard Worker for (auto isAsync : boolStates) {
534*b7c941bbSAndroid Build Coastguard Worker mOutputBuff = loopCounter == 0 ? ref : test;
535*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->reset();
536*b7c941bbSAndroid Build Coastguard Worker /* TODO(b/147348711) */
537*b7c941bbSAndroid Build Coastguard Worker /* Instead of create and delete codec at every iteration, we would like to create
538*b7c941bbSAndroid Build Coastguard Worker * once and use it for all iterations and delete before exiting */
539*b7c941bbSAndroid Build Coastguard Worker mCodec = AMediaCodec_createCodecByName(encoder);
540*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mCodec, StringFormat("unable to create codec by name %s", encoder))
541*b7c941bbSAndroid Build Coastguard Worker if (!configureCodec(format, isAsync, false, true)) return false;
542*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
543*b7c941bbSAndroid Build Coastguard Worker if (!queueEOS()) return false;
544*b7c941bbSAndroid Build Coastguard Worker if (!waitForAllOutputs()) return false;
545*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed")
546*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed")
547*b7c941bbSAndroid Build Coastguard Worker mCodec = nullptr;
548*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE((loopCounter != 0 && !ref->equals(test)),
549*b7c941bbSAndroid Build Coastguard Worker std::string{"Encoder output is not consistent across runs \n"}.append(
550*b7c941bbSAndroid Build Coastguard Worker test->getErrorMsg()))
551*b7c941bbSAndroid Build Coastguard Worker loopCounter++;
552*b7c941bbSAndroid Build Coastguard Worker }
553*b7c941bbSAndroid Build Coastguard Worker return true;
554*b7c941bbSAndroid Build Coastguard Worker }
555*b7c941bbSAndroid Build Coastguard Worker
testSetForceSyncFrame(const char * encoder,const char * srcPath)556*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::testSetForceSyncFrame(const char* encoder, const char* srcPath) {
557*b7c941bbSAndroid Build Coastguard Worker setUpSource(srcPath);
558*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mInputData, StringFormat("unable to open input file %s", srcPath))
559*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* format = mFormats[0];
560*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(format, std::string{"encountered error during deserialization of media format"})
561*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &mDefFrameRate),
562*b7c941bbSAndroid Build Coastguard Worker StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_FRAME_RATE))
563*b7c941bbSAndroid Build Coastguard Worker // Maximum allowed key frame interval variation from the target value.
564*b7c941bbSAndroid Build Coastguard Worker int kMaxKeyFrameIntervalVariation = 3;
565*b7c941bbSAndroid Build Coastguard Worker int kKeyFrameInterval = 2; // force key frame every 2 seconds.
566*b7c941bbSAndroid Build Coastguard Worker int kKeyFramePos = mDefFrameRate * kKeyFrameInterval;
567*b7c941bbSAndroid Build Coastguard Worker int kNumKeyFrameRequests = 7;
568*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* params = AMediaFormat_new();
569*b7c941bbSAndroid Build Coastguard Worker mFormats.push_back(params);
570*b7c941bbSAndroid Build Coastguard Worker mOutputBuff = mTestBuff;
571*b7c941bbSAndroid Build Coastguard Worker const bool boolStates[]{true, false};
572*b7c941bbSAndroid Build Coastguard Worker for (auto isAsync : boolStates) {
573*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->reset();
574*b7c941bbSAndroid Build Coastguard Worker /* TODO(b/147348711) */
575*b7c941bbSAndroid Build Coastguard Worker /* Instead of create and delete codec at every iteration, we would like to create
576*b7c941bbSAndroid Build Coastguard Worker * once and use it for all iterations and delete before exiting */
577*b7c941bbSAndroid Build Coastguard Worker mCodec = AMediaCodec_createCodecByName(encoder);
578*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mCodec, StringFormat("unable to create codec by name%s", encoder))
579*b7c941bbSAndroid Build Coastguard Worker if (!configureCodec(format, isAsync, false, true)) return false;
580*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
581*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < kNumKeyFrameRequests; i++) {
582*b7c941bbSAndroid Build Coastguard Worker if (!doWork(kKeyFramePos)) return false;
583*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(mSawInputEOS,
584*b7c941bbSAndroid Build Coastguard Worker StringFormat("Unable to encode %d frames as the input resource contains "
585*b7c941bbSAndroid Build Coastguard Worker "only %d frames \n",
586*b7c941bbSAndroid Build Coastguard Worker kKeyFramePos, mInputCount))
587*b7c941bbSAndroid Build Coastguard Worker forceSyncFrame(params);
588*b7c941bbSAndroid Build Coastguard Worker mInputBufferReadOffset = 0;
589*b7c941bbSAndroid Build Coastguard Worker }
590*b7c941bbSAndroid Build Coastguard Worker if (!queueEOS()) return false;
591*b7c941bbSAndroid Build Coastguard Worker if (!waitForAllOutputs()) return false;
592*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed")
593*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed")
594*b7c941bbSAndroid Build Coastguard Worker mCodec = nullptr;
595*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE((mNumSyncFramesReceived < kNumKeyFrameRequests),
596*b7c941bbSAndroid Build Coastguard Worker StringFormat("Received only %d key frames for %d key frame requests \n",
597*b7c941bbSAndroid Build Coastguard Worker mNumSyncFramesReceived, kNumKeyFrameRequests))
598*b7c941bbSAndroid Build Coastguard Worker ALOGD("mNumSyncFramesReceived %d", mNumSyncFramesReceived);
599*b7c941bbSAndroid Build Coastguard Worker for (int i = 0, expPos = 0, index = 0; i < kNumKeyFrameRequests; i++) {
600*b7c941bbSAndroid Build Coastguard Worker int j = index;
601*b7c941bbSAndroid Build Coastguard Worker for (; j < mSyncFramesPos.size(); j++) {
602*b7c941bbSAndroid Build Coastguard Worker // Check key frame intervals:
603*b7c941bbSAndroid Build Coastguard Worker // key frame position should not be greater than target value + 3
604*b7c941bbSAndroid Build Coastguard Worker // key frame position should not be less than target value - 3
605*b7c941bbSAndroid Build Coastguard Worker if (abs(expPos - mSyncFramesPos.at(j)) <= kMaxKeyFrameIntervalVariation) {
606*b7c941bbSAndroid Build Coastguard Worker index = j;
607*b7c941bbSAndroid Build Coastguard Worker break;
608*b7c941bbSAndroid Build Coastguard Worker }
609*b7c941bbSAndroid Build Coastguard Worker }
610*b7c941bbSAndroid Build Coastguard Worker if (j == mSyncFramesPos.size()) {
611*b7c941bbSAndroid Build Coastguard Worker ALOGW("requested key frame at frame index %d none found near by", expPos);
612*b7c941bbSAndroid Build Coastguard Worker }
613*b7c941bbSAndroid Build Coastguard Worker expPos += kKeyFramePos;
614*b7c941bbSAndroid Build Coastguard Worker }
615*b7c941bbSAndroid Build Coastguard Worker }
616*b7c941bbSAndroid Build Coastguard Worker return true;
617*b7c941bbSAndroid Build Coastguard Worker }
618*b7c941bbSAndroid Build Coastguard Worker
testAdaptiveBitRate(const char * encoder,const char * srcPath)619*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderTest::testAdaptiveBitRate(const char* encoder, const char* srcPath) {
620*b7c941bbSAndroid Build Coastguard Worker setUpSource(srcPath);
621*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mInputData, StringFormat("unable to open input file %s", srcPath))
622*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* format = mFormats[0];
623*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(format, std::string{"encountered error during deserialization of media format"})
624*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &mDefFrameRate),
625*b7c941bbSAndroid Build Coastguard Worker StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_FRAME_RATE))
626*b7c941bbSAndroid Build Coastguard Worker int kAdaptiveBitrateInterval = 3; // change bitrate every 3 seconds.
627*b7c941bbSAndroid Build Coastguard Worker int kAdaptiveBitrateDurationFrame = mDefFrameRate * kAdaptiveBitrateInterval;
628*b7c941bbSAndroid Build Coastguard Worker int kBitrateChangeRequests = 7;
629*b7c941bbSAndroid Build Coastguard Worker // TODO(b/251265293) Reduce the allowed deviation after improving the test conditions
630*b7c941bbSAndroid Build Coastguard Worker float kMaxBitrateDeviation = 60.0; // allowed bitrate deviation in %
631*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* params = AMediaFormat_new();
632*b7c941bbSAndroid Build Coastguard Worker mFormats.push_back(params);
633*b7c941bbSAndroid Build Coastguard Worker mOutputBuff = mTestBuff;
634*b7c941bbSAndroid Build Coastguard Worker mSaveToMem = true;
635*b7c941bbSAndroid Build Coastguard Worker const bool boolStates[]{true, false};
636*b7c941bbSAndroid Build Coastguard Worker for (auto isAsync : boolStates) {
637*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->reset();
638*b7c941bbSAndroid Build Coastguard Worker /* TODO(b/147348711) */
639*b7c941bbSAndroid Build Coastguard Worker /* Instead of create and delete codec at every iteration, we would like to create
640*b7c941bbSAndroid Build Coastguard Worker * once and use it for all iterations and delete before exiting */
641*b7c941bbSAndroid Build Coastguard Worker mCodec = AMediaCodec_createCodecByName(encoder);
642*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mCodec, StringFormat("unable to create codec by name %s", encoder))
643*b7c941bbSAndroid Build Coastguard Worker if (!configureCodec(format, isAsync, false, true)) return false;
644*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
645*b7c941bbSAndroid Build Coastguard Worker int expOutSize = 0;
646*b7c941bbSAndroid Build Coastguard Worker int bitrate;
647*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate),
648*b7c941bbSAndroid Build Coastguard Worker StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_BIT_RATE))
649*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < kBitrateChangeRequests; i++) {
650*b7c941bbSAndroid Build Coastguard Worker if (!doWork(kAdaptiveBitrateDurationFrame)) return false;
651*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(mSawInputEOS,
652*b7c941bbSAndroid Build Coastguard Worker StringFormat("Unable to encode %d frames as the input resource contains "
653*b7c941bbSAndroid Build Coastguard Worker "only %d frames \n",
654*b7c941bbSAndroid Build Coastguard Worker kAdaptiveBitrateDurationFrame, mInputCount))
655*b7c941bbSAndroid Build Coastguard Worker expOutSize += kAdaptiveBitrateInterval * bitrate;
656*b7c941bbSAndroid Build Coastguard Worker if ((i & 1) == 1) bitrate *= 2;
657*b7c941bbSAndroid Build Coastguard Worker else bitrate /= 2;
658*b7c941bbSAndroid Build Coastguard Worker updateBitrate(params, bitrate);
659*b7c941bbSAndroid Build Coastguard Worker mInputBufferReadOffset = 0;
660*b7c941bbSAndroid Build Coastguard Worker }
661*b7c941bbSAndroid Build Coastguard Worker if (!queueEOS()) return false;
662*b7c941bbSAndroid Build Coastguard Worker if (!waitForAllOutputs()) return false;
663*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_stop(mCodec), "AMediaCodec_stop failed")
664*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_delete(mCodec), "AMediaCodec_delete failed")
665*b7c941bbSAndroid Build Coastguard Worker mCodec = nullptr;
666*b7c941bbSAndroid Build Coastguard Worker /* TODO: validate output br with sliding window constraints Sec 5.2 cdd */
667*b7c941bbSAndroid Build Coastguard Worker int outSize = mOutputBuff->getOutStreamSize() * 8;
668*b7c941bbSAndroid Build Coastguard Worker float brDev = abs(expOutSize - outSize) * 100.0f / expOutSize;
669*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(brDev > kMaxBitrateDeviation,
670*b7c941bbSAndroid Build Coastguard Worker StringFormat("Relative Bitrate error is too large : %f %%\n", brDev))
671*b7c941bbSAndroid Build Coastguard Worker }
672*b7c941bbSAndroid Build Coastguard Worker return true;
673*b7c941bbSAndroid Build Coastguard Worker }
674*b7c941bbSAndroid Build Coastguard Worker
nativeTestSimpleEncode(JNIEnv * env,jobject,jstring jEncoder,jstring jsrcPath,jstring jMediaType,jstring jCfgParams,jstring jSeparator,jobject jRetMsg,jint jFrameLimit)675*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestSimpleEncode(JNIEnv* env, jobject, jstring jEncoder, jstring jsrcPath,
676*b7c941bbSAndroid Build Coastguard Worker jstring jMediaType, jstring jCfgParams, jstring jSeparator,
677*b7c941bbSAndroid Build Coastguard Worker jobject jRetMsg, jint jFrameLimit) {
678*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
679*b7c941bbSAndroid Build Coastguard Worker const char* cMediaType = env->GetStringUTFChars(jMediaType, nullptr);
680*b7c941bbSAndroid Build Coastguard Worker const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
681*b7c941bbSAndroid Build Coastguard Worker const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
682*b7c941bbSAndroid Build Coastguard Worker const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
683*b7c941bbSAndroid Build Coastguard Worker auto codecEncoderTest = new CodecEncoderTest(cMediaType, cCfgParams, nullptr, cSeparator);
684*b7c941bbSAndroid Build Coastguard Worker bool isPass = codecEncoderTest->testSimpleEncode(cEncoder, csrcPath, jFrameLimit);
685*b7c941bbSAndroid Build Coastguard Worker std::string msg = isPass ? std::string{} : codecEncoderTest->getErrorMsg();
686*b7c941bbSAndroid Build Coastguard Worker delete codecEncoderTest;
687*b7c941bbSAndroid Build Coastguard Worker jclass clazz = env->GetObjectClass(jRetMsg);
688*b7c941bbSAndroid Build Coastguard Worker jmethodID mId =
689*b7c941bbSAndroid Build Coastguard Worker env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
690*b7c941bbSAndroid Build Coastguard Worker env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
691*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
692*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jSeparator, cSeparator);
693*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jEncoder, cEncoder);
694*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jMediaType, cMediaType);
695*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
696*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
697*b7c941bbSAndroid Build Coastguard Worker }
698*b7c941bbSAndroid Build Coastguard Worker
nativeTestReconfigure(JNIEnv * env,jobject,jstring jEncoder,jstring jsrcPath,jstring jMediaType,jstring jCfgParams,jstring jReconfigCfgParams,jstring jSeparator,jobject jRetMsg,jint jFrameLimit)699*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestReconfigure(JNIEnv* env, jobject, jstring jEncoder, jstring jsrcPath,
700*b7c941bbSAndroid Build Coastguard Worker jstring jMediaType, jstring jCfgParams,
701*b7c941bbSAndroid Build Coastguard Worker jstring jReconfigCfgParams, jstring jSeparator,
702*b7c941bbSAndroid Build Coastguard Worker jobject jRetMsg, jint jFrameLimit) {
703*b7c941bbSAndroid Build Coastguard Worker bool isPass;
704*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
705*b7c941bbSAndroid Build Coastguard Worker const char* cMediaType = env->GetStringUTFChars(jMediaType, nullptr);
706*b7c941bbSAndroid Build Coastguard Worker const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
707*b7c941bbSAndroid Build Coastguard Worker const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
708*b7c941bbSAndroid Build Coastguard Worker const char* cReconfigCfgParams = jReconfigCfgParams != nullptr
709*b7c941bbSAndroid Build Coastguard Worker ? env->GetStringUTFChars(jReconfigCfgParams, nullptr)
710*b7c941bbSAndroid Build Coastguard Worker : nullptr;
711*b7c941bbSAndroid Build Coastguard Worker const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
712*b7c941bbSAndroid Build Coastguard Worker auto codecEncoderTest =
713*b7c941bbSAndroid Build Coastguard Worker new CodecEncoderTest(cMediaType, cCfgParams, cReconfigCfgParams, cSeparator);
714*b7c941bbSAndroid Build Coastguard Worker isPass = codecEncoderTest->testReconfigure(cEncoder, csrcPath, jFrameLimit);
715*b7c941bbSAndroid Build Coastguard Worker std::string msg = isPass ? std::string{} : codecEncoderTest->getErrorMsg();
716*b7c941bbSAndroid Build Coastguard Worker delete codecEncoderTest;
717*b7c941bbSAndroid Build Coastguard Worker jclass clazz = env->GetObjectClass(jRetMsg);
718*b7c941bbSAndroid Build Coastguard Worker jmethodID mId =
719*b7c941bbSAndroid Build Coastguard Worker env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
720*b7c941bbSAndroid Build Coastguard Worker env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
721*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
722*b7c941bbSAndroid Build Coastguard Worker if (cReconfigCfgParams != nullptr) {
723*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jReconfigCfgParams, cReconfigCfgParams);
724*b7c941bbSAndroid Build Coastguard Worker }
725*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jSeparator, cSeparator);
726*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jEncoder, cEncoder);
727*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jMediaType, cMediaType);
728*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
729*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
730*b7c941bbSAndroid Build Coastguard Worker }
731*b7c941bbSAndroid Build Coastguard Worker
nativeTestSetForceSyncFrame(JNIEnv * env,jobject,jstring jEncoder,jstring jsrcPath,jstring jMediaType,jstring jCfgParams,jstring jSeparator,jobject jRetMsg)732*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestSetForceSyncFrame(JNIEnv* env, jobject, jstring jEncoder,
733*b7c941bbSAndroid Build Coastguard Worker jstring jsrcPath, jstring jMediaType,
734*b7c941bbSAndroid Build Coastguard Worker jstring jCfgParams, jstring jSeparator,
735*b7c941bbSAndroid Build Coastguard Worker jobject jRetMsg) {
736*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
737*b7c941bbSAndroid Build Coastguard Worker const char* cMediaType = env->GetStringUTFChars(jMediaType, nullptr);
738*b7c941bbSAndroid Build Coastguard Worker const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
739*b7c941bbSAndroid Build Coastguard Worker const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
740*b7c941bbSAndroid Build Coastguard Worker const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
741*b7c941bbSAndroid Build Coastguard Worker auto codecEncoderTest = new CodecEncoderTest(cMediaType, cCfgParams, nullptr, cSeparator);
742*b7c941bbSAndroid Build Coastguard Worker bool isPass = codecEncoderTest->testSetForceSyncFrame(cEncoder, csrcPath);
743*b7c941bbSAndroid Build Coastguard Worker std::string msg = isPass ? std::string{} : codecEncoderTest->getErrorMsg();
744*b7c941bbSAndroid Build Coastguard Worker delete codecEncoderTest;
745*b7c941bbSAndroid Build Coastguard Worker jclass clazz = env->GetObjectClass(jRetMsg);
746*b7c941bbSAndroid Build Coastguard Worker jmethodID mId =
747*b7c941bbSAndroid Build Coastguard Worker env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
748*b7c941bbSAndroid Build Coastguard Worker env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
749*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
750*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jSeparator, cSeparator);
751*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jEncoder, cEncoder);
752*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jMediaType, cMediaType);
753*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
754*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
755*b7c941bbSAndroid Build Coastguard Worker }
756*b7c941bbSAndroid Build Coastguard Worker
nativeTestAdaptiveBitRate(JNIEnv * env,jobject,jstring jEncoder,jstring jsrcPath,jstring jMediaType,jstring jCfgParams,jstring jSeparator,jobject jRetMsg)757*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestAdaptiveBitRate(JNIEnv* env, jobject, jstring jEncoder, jstring jsrcPath,
758*b7c941bbSAndroid Build Coastguard Worker jstring jMediaType, jstring jCfgParams,
759*b7c941bbSAndroid Build Coastguard Worker jstring jSeparator, jobject jRetMsg) {
760*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
761*b7c941bbSAndroid Build Coastguard Worker const char* cMediaType = env->GetStringUTFChars(jMediaType, nullptr);
762*b7c941bbSAndroid Build Coastguard Worker const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
763*b7c941bbSAndroid Build Coastguard Worker const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
764*b7c941bbSAndroid Build Coastguard Worker const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
765*b7c941bbSAndroid Build Coastguard Worker auto codecEncoderTest = new CodecEncoderTest(cMediaType, cCfgParams, nullptr, cSeparator);
766*b7c941bbSAndroid Build Coastguard Worker bool isPass = codecEncoderTest->testAdaptiveBitRate(cEncoder, csrcPath);
767*b7c941bbSAndroid Build Coastguard Worker std::string msg = isPass ? std::string{} : codecEncoderTest->getErrorMsg();
768*b7c941bbSAndroid Build Coastguard Worker delete codecEncoderTest;
769*b7c941bbSAndroid Build Coastguard Worker jclass clazz = env->GetObjectClass(jRetMsg);
770*b7c941bbSAndroid Build Coastguard Worker jmethodID mId =
771*b7c941bbSAndroid Build Coastguard Worker env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
772*b7c941bbSAndroid Build Coastguard Worker env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
773*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
774*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jSeparator, cSeparator);
775*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jEncoder, cEncoder);
776*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jMediaType, cMediaType);
777*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
778*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
779*b7c941bbSAndroid Build Coastguard Worker }
780*b7c941bbSAndroid Build Coastguard Worker
nativeTestOnlyEos(JNIEnv * env,jobject,jstring jEncoder,jstring jMediaType,jstring jCfgParams,jstring jSeparator,jobject jRetMsg)781*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestOnlyEos(JNIEnv* env, jobject, jstring jEncoder, jstring jMediaType,
782*b7c941bbSAndroid Build Coastguard Worker jstring jCfgParams, jstring jSeparator, jobject jRetMsg) {
783*b7c941bbSAndroid Build Coastguard Worker const char* cMediaType = env->GetStringUTFChars(jMediaType, nullptr);
784*b7c941bbSAndroid Build Coastguard Worker const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
785*b7c941bbSAndroid Build Coastguard Worker const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
786*b7c941bbSAndroid Build Coastguard Worker const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
787*b7c941bbSAndroid Build Coastguard Worker auto codecEncoderTest = new CodecEncoderTest(cMediaType, cCfgParams, nullptr, cSeparator);
788*b7c941bbSAndroid Build Coastguard Worker bool isPass = codecEncoderTest->testOnlyEos(cEncoder);
789*b7c941bbSAndroid Build Coastguard Worker std::string msg = isPass ? std::string{} : codecEncoderTest->getErrorMsg();
790*b7c941bbSAndroid Build Coastguard Worker delete codecEncoderTest;
791*b7c941bbSAndroid Build Coastguard Worker jclass clazz = env->GetObjectClass(jRetMsg);
792*b7c941bbSAndroid Build Coastguard Worker jmethodID mId =
793*b7c941bbSAndroid Build Coastguard Worker env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
794*b7c941bbSAndroid Build Coastguard Worker env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
795*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
796*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jSeparator, cSeparator);
797*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jEncoder, cEncoder);
798*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jMediaType, cMediaType);
799*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
800*b7c941bbSAndroid Build Coastguard Worker }
801*b7c941bbSAndroid Build Coastguard Worker
registerAndroidMediaV2CtsEncoderTest(JNIEnv * env)802*b7c941bbSAndroid Build Coastguard Worker int registerAndroidMediaV2CtsEncoderTest(JNIEnv* env) {
803*b7c941bbSAndroid Build Coastguard Worker const JNINativeMethod methodTable[] = {
804*b7c941bbSAndroid Build Coastguard Worker {"nativeTestSimpleEncode",
805*b7c941bbSAndroid Build Coastguard Worker "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
806*b7c941bbSAndroid Build Coastguard Worker "String;Ljava/lang/StringBuilder;I)Z",
807*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestSimpleEncode},
808*b7c941bbSAndroid Build Coastguard Worker {"nativeTestReconfigure",
809*b7c941bbSAndroid Build Coastguard Worker "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
810*b7c941bbSAndroid Build Coastguard Worker "String;Ljava/lang/String;Ljava/lang/StringBuilder;I)Z",
811*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestReconfigure},
812*b7c941bbSAndroid Build Coastguard Worker {"nativeTestSetForceSyncFrame",
813*b7c941bbSAndroid Build Coastguard Worker "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
814*b7c941bbSAndroid Build Coastguard Worker "String;Ljava/lang/StringBuilder;)Z",
815*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestSetForceSyncFrame},
816*b7c941bbSAndroid Build Coastguard Worker {"nativeTestAdaptiveBitRate",
817*b7c941bbSAndroid Build Coastguard Worker "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
818*b7c941bbSAndroid Build Coastguard Worker "String;Ljava/lang/StringBuilder;)Z",
819*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestAdaptiveBitRate},
820*b7c941bbSAndroid Build Coastguard Worker {"nativeTestOnlyEos",
821*b7c941bbSAndroid Build Coastguard Worker "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
822*b7c941bbSAndroid Build Coastguard Worker "StringBuilder;)Z",
823*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestOnlyEos},
824*b7c941bbSAndroid Build Coastguard Worker };
825*b7c941bbSAndroid Build Coastguard Worker jclass c = env->FindClass("android/mediav2/cts/CodecEncoderTest");
826*b7c941bbSAndroid Build Coastguard Worker return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
827*b7c941bbSAndroid Build Coastguard Worker }
828*b7c941bbSAndroid Build Coastguard Worker
JNI_OnLoad(JavaVM * vm,void *)829*b7c941bbSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
830*b7c941bbSAndroid Build Coastguard Worker JNIEnv* env;
831*b7c941bbSAndroid Build Coastguard Worker if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) return JNI_ERR;
832*b7c941bbSAndroid Build Coastguard Worker if (registerAndroidMediaV2CtsEncoderTest(env) != JNI_OK) return JNI_ERR;
833*b7c941bbSAndroid Build Coastguard Worker return JNI_VERSION_1_6;
834*b7c941bbSAndroid Build Coastguard Worker }
835