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 "NativeCodecEncoderSurfaceTest"
19*b7c941bbSAndroid Build Coastguard Worker #include <log/log.h>
20*b7c941bbSAndroid Build Coastguard Worker
21*b7c941bbSAndroid Build Coastguard Worker #include <android/native_window_jni.h>
22*b7c941bbSAndroid Build Coastguard Worker #include <jni.h>
23*b7c941bbSAndroid Build Coastguard Worker #include <media/NdkMediaExtractor.h>
24*b7c941bbSAndroid Build Coastguard Worker #include <media/NdkMediaMuxer.h>
25*b7c941bbSAndroid Build Coastguard Worker #include <sys/stat.h>
26*b7c941bbSAndroid Build Coastguard Worker
27*b7c941bbSAndroid Build Coastguard Worker #include "NativeCodecTestBase.h"
28*b7c941bbSAndroid Build Coastguard Worker #include "NativeMediaCommon.h"
29*b7c941bbSAndroid Build Coastguard Worker
30*b7c941bbSAndroid Build Coastguard Worker class CodecEncoderSurfaceTest {
31*b7c941bbSAndroid Build Coastguard Worker private:
32*b7c941bbSAndroid Build Coastguard Worker const char* mMediaType;
33*b7c941bbSAndroid Build Coastguard Worker ANativeWindow* mWindow;
34*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor* mExtractor;
35*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* mDecFormat;
36*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* mEncFormat;
37*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer* mMuxer;
38*b7c941bbSAndroid Build Coastguard Worker AMediaCodec* mDecoder;
39*b7c941bbSAndroid Build Coastguard Worker AMediaCodec* mEncoder;
40*b7c941bbSAndroid Build Coastguard Worker CodecAsyncHandler mAsyncHandleDecoder;
41*b7c941bbSAndroid Build Coastguard Worker CodecAsyncHandler mAsyncHandleEncoder;
42*b7c941bbSAndroid Build Coastguard Worker bool mIsCodecInAsyncMode;
43*b7c941bbSAndroid Build Coastguard Worker bool mSawDecInputEOS;
44*b7c941bbSAndroid Build Coastguard Worker bool mSawDecOutputEOS;
45*b7c941bbSAndroid Build Coastguard Worker bool mSawEncOutputEOS;
46*b7c941bbSAndroid Build Coastguard Worker bool mSignalEOSWithLastFrame;
47*b7c941bbSAndroid Build Coastguard Worker int mDecInputCount;
48*b7c941bbSAndroid Build Coastguard Worker int mDecOutputCount;
49*b7c941bbSAndroid Build Coastguard Worker int mEncOutputCount;
50*b7c941bbSAndroid Build Coastguard Worker int mMaxBFrames;
51*b7c941bbSAndroid Build Coastguard Worker int mLatency;
52*b7c941bbSAndroid Build Coastguard Worker bool mReviseLatency;
53*b7c941bbSAndroid Build Coastguard Worker int mMuxTrackID;
54*b7c941bbSAndroid Build Coastguard Worker
55*b7c941bbSAndroid Build Coastguard Worker OutputManager* mOutputBuff;
56*b7c941bbSAndroid Build Coastguard Worker OutputManager* mRefBuff;
57*b7c941bbSAndroid Build Coastguard Worker OutputManager* mTestBuff;
58*b7c941bbSAndroid Build Coastguard Worker bool mSaveToMem;
59*b7c941bbSAndroid Build Coastguard Worker
60*b7c941bbSAndroid Build Coastguard Worker std::string mErrorLogs;
61*b7c941bbSAndroid Build Coastguard Worker std::string mTestEnv;
62*b7c941bbSAndroid Build Coastguard Worker
63*b7c941bbSAndroid Build Coastguard Worker bool setUpExtractor(const char* srcFile, const char* srcMediaType, int colorFormat);
64*b7c941bbSAndroid Build Coastguard Worker void deleteExtractor();
65*b7c941bbSAndroid Build Coastguard Worker bool configureCodec(bool isAsync, bool signalEOSWithLastFrame, bool usePersistentSurface);
66*b7c941bbSAndroid Build Coastguard Worker void resetContext(bool isAsync, bool signalEOSWithLastFrame);
67*b7c941bbSAndroid Build Coastguard Worker bool enqueueDecoderInput(size_t bufferIndex);
68*b7c941bbSAndroid Build Coastguard Worker bool dequeueDecoderOutput(size_t bufferIndex, AMediaCodecBufferInfo* bufferInfo);
69*b7c941bbSAndroid Build Coastguard Worker bool dequeueEncoderOutput(size_t bufferIndex, AMediaCodecBufferInfo* info);
70*b7c941bbSAndroid Build Coastguard Worker bool tryEncoderOutput(long timeOutUs);
71*b7c941bbSAndroid Build Coastguard Worker bool waitForAllEncoderOutputs();
72*b7c941bbSAndroid Build Coastguard Worker bool queueEOS();
73*b7c941bbSAndroid Build Coastguard Worker bool enqueueDecoderEOS(size_t bufferIndex);
74*b7c941bbSAndroid Build Coastguard Worker bool doWork(int frameLimit);
hasSeenError()75*b7c941bbSAndroid Build Coastguard Worker bool hasSeenError() { return mAsyncHandleDecoder.getError() || mAsyncHandleEncoder.getError(); }
76*b7c941bbSAndroid Build Coastguard Worker
77*b7c941bbSAndroid Build Coastguard Worker public:
getErrorMsg()78*b7c941bbSAndroid Build Coastguard Worker std::string getErrorMsg() {
79*b7c941bbSAndroid Build Coastguard Worker return mTestEnv +
80*b7c941bbSAndroid Build Coastguard Worker "################### Error Details #####################\n" +
81*b7c941bbSAndroid Build Coastguard Worker mErrorLogs;
82*b7c941bbSAndroid Build Coastguard Worker }
83*b7c941bbSAndroid Build Coastguard Worker CodecEncoderSurfaceTest(const char* mediaType, const char* cfgParams, const char* separator);
84*b7c941bbSAndroid Build Coastguard Worker ~CodecEncoderSurfaceTest();
85*b7c941bbSAndroid Build Coastguard Worker
86*b7c941bbSAndroid Build Coastguard Worker bool testSimpleEncode(const char* encoder, const char* decoder, const char* srcPath,
87*b7c941bbSAndroid Build Coastguard Worker const char* srcMediaType, const char* muxOutPath, int colorFormat,
88*b7c941bbSAndroid Build Coastguard Worker bool usePersistentSurface, int frameLimit);
89*b7c941bbSAndroid Build Coastguard Worker };
90*b7c941bbSAndroid Build Coastguard Worker
CodecEncoderSurfaceTest(const char * mediaType,const char * cfgParams,const char * separator)91*b7c941bbSAndroid Build Coastguard Worker CodecEncoderSurfaceTest::CodecEncoderSurfaceTest(const char* mediaType, const char* cfgParams,
92*b7c941bbSAndroid Build Coastguard Worker const char* separator)
93*b7c941bbSAndroid Build Coastguard Worker : mMediaType{mediaType} {
94*b7c941bbSAndroid Build Coastguard Worker mWindow = nullptr;
95*b7c941bbSAndroid Build Coastguard Worker mExtractor = nullptr;
96*b7c941bbSAndroid Build Coastguard Worker mDecFormat = nullptr;
97*b7c941bbSAndroid Build Coastguard Worker mEncFormat = deSerializeMediaFormat(cfgParams, separator);
98*b7c941bbSAndroid Build Coastguard Worker mMuxer = nullptr;
99*b7c941bbSAndroid Build Coastguard Worker mDecoder = nullptr;
100*b7c941bbSAndroid Build Coastguard Worker mEncoder = nullptr;
101*b7c941bbSAndroid Build Coastguard Worker resetContext(false, false);
102*b7c941bbSAndroid Build Coastguard Worker mMaxBFrames = 0;
103*b7c941bbSAndroid Build Coastguard Worker if (mEncFormat != nullptr) {
104*b7c941bbSAndroid Build Coastguard Worker // key formalized in Android U (sdk==34).
105*b7c941bbSAndroid Build Coastguard Worker // Use internally-defined when running on earlier releases, such as happens with MTS
106*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __ANDROID_API_U__, *)) {
107*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getInt32(mEncFormat, AMEDIAFORMAT_KEY_MAX_B_FRAMES, &mMaxBFrames);
108*b7c941bbSAndroid Build Coastguard Worker } else {
109*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getInt32(mEncFormat, COMPATIBLE_AMEDIAFORMAT_KEY_MAX_B_FRAMES,
110*b7c941bbSAndroid Build Coastguard Worker &mMaxBFrames);
111*b7c941bbSAndroid Build Coastguard Worker }
112*b7c941bbSAndroid Build Coastguard Worker }
113*b7c941bbSAndroid Build Coastguard Worker mLatency = mMaxBFrames;
114*b7c941bbSAndroid Build Coastguard Worker mReviseLatency = false;
115*b7c941bbSAndroid Build Coastguard Worker mMuxTrackID = -1;
116*b7c941bbSAndroid Build Coastguard Worker mRefBuff = new OutputManager();
117*b7c941bbSAndroid Build Coastguard Worker mTestBuff = new OutputManager(mRefBuff->getSharedErrorLogs());
118*b7c941bbSAndroid Build Coastguard Worker }
119*b7c941bbSAndroid Build Coastguard Worker
~CodecEncoderSurfaceTest()120*b7c941bbSAndroid Build Coastguard Worker CodecEncoderSurfaceTest::~CodecEncoderSurfaceTest() {
121*b7c941bbSAndroid Build Coastguard Worker deleteExtractor();
122*b7c941bbSAndroid Build Coastguard Worker if (mWindow) {
123*b7c941bbSAndroid Build Coastguard Worker ANativeWindow_release(mWindow);
124*b7c941bbSAndroid Build Coastguard Worker mWindow = nullptr;
125*b7c941bbSAndroid Build Coastguard Worker }
126*b7c941bbSAndroid Build Coastguard Worker if (mEncFormat) {
127*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_delete(mEncFormat);
128*b7c941bbSAndroid Build Coastguard Worker mEncFormat = nullptr;
129*b7c941bbSAndroid Build Coastguard Worker }
130*b7c941bbSAndroid Build Coastguard Worker if (mMuxer) {
131*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(mMuxer);
132*b7c941bbSAndroid Build Coastguard Worker mMuxer = nullptr;
133*b7c941bbSAndroid Build Coastguard Worker }
134*b7c941bbSAndroid Build Coastguard Worker if (mDecoder) {
135*b7c941bbSAndroid Build Coastguard Worker AMediaCodec_delete(mDecoder);
136*b7c941bbSAndroid Build Coastguard Worker mDecoder = nullptr;
137*b7c941bbSAndroid Build Coastguard Worker }
138*b7c941bbSAndroid Build Coastguard Worker if (mEncoder) {
139*b7c941bbSAndroid Build Coastguard Worker AMediaCodec_delete(mEncoder);
140*b7c941bbSAndroid Build Coastguard Worker mEncoder = nullptr;
141*b7c941bbSAndroid Build Coastguard Worker }
142*b7c941bbSAndroid Build Coastguard Worker delete mRefBuff;
143*b7c941bbSAndroid Build Coastguard Worker delete mTestBuff;
144*b7c941bbSAndroid Build Coastguard Worker }
145*b7c941bbSAndroid Build Coastguard Worker
setUpExtractor(const char * srcFile,const char * srcMediaType,int colorFormat)146*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderSurfaceTest::setUpExtractor(const char* srcFile, const char* srcMediaType,
147*b7c941bbSAndroid Build Coastguard Worker int colorFormat) {
148*b7c941bbSAndroid Build Coastguard Worker FILE* fp = fopen(srcFile, "rbe");
149*b7c941bbSAndroid Build Coastguard Worker struct stat buf {};
150*b7c941bbSAndroid Build Coastguard Worker if (fp && !fstat(fileno(fp), &buf)) {
151*b7c941bbSAndroid Build Coastguard Worker deleteExtractor();
152*b7c941bbSAndroid Build Coastguard Worker mExtractor = AMediaExtractor_new();
153*b7c941bbSAndroid Build Coastguard Worker media_status_t res =
154*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_setDataSourceFd(mExtractor, fileno(fp), 0, buf.st_size);
155*b7c941bbSAndroid Build Coastguard Worker if (res != AMEDIA_OK) {
156*b7c941bbSAndroid Build Coastguard Worker deleteExtractor();
157*b7c941bbSAndroid Build Coastguard Worker } else {
158*b7c941bbSAndroid Build Coastguard Worker for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(mExtractor);
159*b7c941bbSAndroid Build Coastguard Worker trackID++) {
160*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* currFormat = AMediaExtractor_getTrackFormat(mExtractor, trackID);
161*b7c941bbSAndroid Build Coastguard Worker const char* mediaType = nullptr;
162*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getString(currFormat, AMEDIAFORMAT_KEY_MIME, &mediaType);
163*b7c941bbSAndroid Build Coastguard Worker if (mediaType && strcmp(mediaType, srcMediaType) == 0) {
164*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_selectTrack(mExtractor, trackID);
165*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_setInt32(currFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, colorFormat);
166*b7c941bbSAndroid Build Coastguard Worker mDecFormat = currFormat;
167*b7c941bbSAndroid Build Coastguard Worker break;
168*b7c941bbSAndroid Build Coastguard Worker }
169*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_delete(currFormat);
170*b7c941bbSAndroid Build Coastguard Worker }
171*b7c941bbSAndroid Build Coastguard Worker }
172*b7c941bbSAndroid Build Coastguard Worker }
173*b7c941bbSAndroid Build Coastguard Worker if (fp) fclose(fp);
174*b7c941bbSAndroid Build Coastguard Worker return mDecFormat != nullptr;
175*b7c941bbSAndroid Build Coastguard Worker }
176*b7c941bbSAndroid Build Coastguard Worker
deleteExtractor()177*b7c941bbSAndroid Build Coastguard Worker void CodecEncoderSurfaceTest::deleteExtractor() {
178*b7c941bbSAndroid Build Coastguard Worker if (mExtractor) {
179*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_delete(mExtractor);
180*b7c941bbSAndroid Build Coastguard Worker mExtractor = nullptr;
181*b7c941bbSAndroid Build Coastguard Worker }
182*b7c941bbSAndroid Build Coastguard Worker if (mDecFormat) {
183*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_delete(mDecFormat);
184*b7c941bbSAndroid Build Coastguard Worker mDecFormat = nullptr;
185*b7c941bbSAndroid Build Coastguard Worker }
186*b7c941bbSAndroid Build Coastguard Worker }
187*b7c941bbSAndroid Build Coastguard Worker
configureCodec(bool isAsync,bool signalEOSWithLastFrame,bool usePersistentSurface)188*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderSurfaceTest::configureCodec(bool isAsync, bool signalEOSWithLastFrame,
189*b7c941bbSAndroid Build Coastguard Worker bool usePersistentSurface) {
190*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mEncFormat,
191*b7c941bbSAndroid Build Coastguard Worker std::string{"encountered error during deserialization of media format"})
192*b7c941bbSAndroid Build Coastguard Worker resetContext(isAsync, signalEOSWithLastFrame);
193*b7c941bbSAndroid Build Coastguard Worker mTestEnv = "################### Test Environment #####################\n";
194*b7c941bbSAndroid Build Coastguard Worker {
195*b7c941bbSAndroid Build Coastguard Worker char* name = nullptr;
196*b7c941bbSAndroid Build Coastguard Worker media_status_t val = AMediaCodec_getName(mEncoder, &name);
197*b7c941bbSAndroid Build Coastguard Worker if (AMEDIA_OK != val) {
198*b7c941bbSAndroid Build Coastguard Worker mErrorLogs = StringFormat("%s with error %d \n", "AMediaCodec_getName failed", val);
199*b7c941bbSAndroid Build Coastguard Worker return false;
200*b7c941bbSAndroid Build Coastguard Worker }
201*b7c941bbSAndroid Build Coastguard Worker if (!name) {
202*b7c941bbSAndroid Build Coastguard Worker mErrorLogs = std::string{"AMediaCodec_getName returned null"};
203*b7c941bbSAndroid Build Coastguard Worker return false;
204*b7c941bbSAndroid Build Coastguard Worker }
205*b7c941bbSAndroid Build Coastguard Worker mTestEnv.append(StringFormat("Component name %s \n", name));
206*b7c941bbSAndroid Build Coastguard Worker AMediaCodec_releaseName(mEncoder, name);
207*b7c941bbSAndroid Build Coastguard Worker }
208*b7c941bbSAndroid Build Coastguard Worker {
209*b7c941bbSAndroid Build Coastguard Worker char* name = nullptr;
210*b7c941bbSAndroid Build Coastguard Worker media_status_t val = AMediaCodec_getName(mDecoder, &name);
211*b7c941bbSAndroid Build Coastguard Worker if (AMEDIA_OK != val) {
212*b7c941bbSAndroid Build Coastguard Worker mErrorLogs = StringFormat("%s with error %d \n", "AMediaCodec_getName failed", val);
213*b7c941bbSAndroid Build Coastguard Worker return false;
214*b7c941bbSAndroid Build Coastguard Worker }
215*b7c941bbSAndroid Build Coastguard Worker if (!name) {
216*b7c941bbSAndroid Build Coastguard Worker mErrorLogs = std::string{"AMediaCodec_getName returned null"};
217*b7c941bbSAndroid Build Coastguard Worker return false;
218*b7c941bbSAndroid Build Coastguard Worker }
219*b7c941bbSAndroid Build Coastguard Worker mTestEnv.append(StringFormat("Decoder Component name %s \n", name));
220*b7c941bbSAndroid Build Coastguard Worker AMediaCodec_releaseName(mDecoder, name);
221*b7c941bbSAndroid Build Coastguard Worker }
222*b7c941bbSAndroid Build Coastguard Worker mTestEnv += StringFormat("Format under test :- %s \n", AMediaFormat_toString(mEncFormat));
223*b7c941bbSAndroid Build Coastguard Worker mTestEnv += StringFormat("Format of Decoder input :- %s \n", AMediaFormat_toString(mDecFormat));
224*b7c941bbSAndroid Build Coastguard Worker mTestEnv += StringFormat("Encoder and Decoder are operating in :- %s mode \n",
225*b7c941bbSAndroid Build Coastguard Worker (isAsync ? "asynchronous" : "synchronous"));
226*b7c941bbSAndroid Build Coastguard Worker mTestEnv += StringFormat("Components received input eos :- %s \n",
227*b7c941bbSAndroid Build Coastguard Worker (signalEOSWithLastFrame ? "with full buffer" : "with empty buffer"));
228*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(mAsyncHandleEncoder.setCallBack(mEncoder, isAsync),
229*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_setAsyncNotifyCallback failed")
230*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_configure(mEncoder, mEncFormat, nullptr, nullptr,
231*b7c941bbSAndroid Build Coastguard Worker AMEDIACODEC_CONFIGURE_FLAG_ENCODE),
232*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_configure failed")
233*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* inpFormat = AMediaCodec_getInputFormat(mEncoder);
234*b7c941bbSAndroid Build Coastguard Worker mReviseLatency = AMediaFormat_getInt32(inpFormat, AMEDIAFORMAT_KEY_LATENCY, &mLatency);
235*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_delete(inpFormat);
236*b7c941bbSAndroid Build Coastguard Worker
237*b7c941bbSAndroid Build Coastguard Worker if (usePersistentSurface) {
238*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_createPersistentInputSurface(&mWindow),
239*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_createPersistentInputSurface failed")
240*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_setInputSurface(mEncoder,
241*b7c941bbSAndroid Build Coastguard Worker reinterpret_cast<ANativeWindow*>(mWindow)),
242*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_setInputSurface failed")
243*b7c941bbSAndroid Build Coastguard Worker } else {
244*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_createInputSurface(mEncoder, &mWindow),
245*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_createInputSurface failed")
246*b7c941bbSAndroid Build Coastguard Worker }
247*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(mAsyncHandleDecoder.setCallBack(mDecoder, isAsync),
248*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_setAsyncNotifyCallback failed")
249*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_configure(mDecoder, mDecFormat, mWindow, nullptr, 0),
250*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_configure failed")
251*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
252*b7c941bbSAndroid Build Coastguard Worker }
253*b7c941bbSAndroid Build Coastguard Worker
resetContext(bool isAsync,bool signalEOSWithLastFrame)254*b7c941bbSAndroid Build Coastguard Worker void CodecEncoderSurfaceTest::resetContext(bool isAsync, bool signalEOSWithLastFrame) {
255*b7c941bbSAndroid Build Coastguard Worker mAsyncHandleDecoder.resetContext();
256*b7c941bbSAndroid Build Coastguard Worker mAsyncHandleEncoder.resetContext();
257*b7c941bbSAndroid Build Coastguard Worker mIsCodecInAsyncMode = isAsync;
258*b7c941bbSAndroid Build Coastguard Worker mSawDecInputEOS = false;
259*b7c941bbSAndroid Build Coastguard Worker mSawDecOutputEOS = false;
260*b7c941bbSAndroid Build Coastguard Worker mSawEncOutputEOS = false;
261*b7c941bbSAndroid Build Coastguard Worker mSignalEOSWithLastFrame = signalEOSWithLastFrame;
262*b7c941bbSAndroid Build Coastguard Worker mDecInputCount = 0;
263*b7c941bbSAndroid Build Coastguard Worker mDecOutputCount = 0;
264*b7c941bbSAndroid Build Coastguard Worker mEncOutputCount = 0;
265*b7c941bbSAndroid Build Coastguard Worker }
266*b7c941bbSAndroid Build Coastguard Worker
enqueueDecoderEOS(size_t bufferIndex)267*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderSurfaceTest::enqueueDecoderEOS(size_t bufferIndex) {
268*b7c941bbSAndroid Build Coastguard Worker if (!hasSeenError() && !mSawDecInputEOS) {
269*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, 0, 0,
270*b7c941bbSAndroid Build Coastguard Worker AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM),
271*b7c941bbSAndroid Build Coastguard Worker "Queued Decoder End of Stream Failed")
272*b7c941bbSAndroid Build Coastguard Worker mSawDecInputEOS = true;
273*b7c941bbSAndroid Build Coastguard Worker ALOGV("Queued Decoder End of Stream");
274*b7c941bbSAndroid Build Coastguard Worker }
275*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
276*b7c941bbSAndroid Build Coastguard Worker }
277*b7c941bbSAndroid Build Coastguard Worker
enqueueDecoderInput(size_t bufferIndex)278*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderSurfaceTest::enqueueDecoderInput(size_t bufferIndex) {
279*b7c941bbSAndroid Build Coastguard Worker if (AMediaExtractor_getSampleSize(mExtractor) < 0) {
280*b7c941bbSAndroid Build Coastguard Worker return enqueueDecoderEOS(bufferIndex);
281*b7c941bbSAndroid Build Coastguard Worker } else {
282*b7c941bbSAndroid Build Coastguard Worker uint32_t flags = 0;
283*b7c941bbSAndroid Build Coastguard Worker size_t bufSize = 0;
284*b7c941bbSAndroid Build Coastguard Worker uint8_t* buf = AMediaCodec_getInputBuffer(mDecoder, bufferIndex, &bufSize);
285*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(buf, std::string{"AMediaCodec_getInputBuffer failed"})
286*b7c941bbSAndroid Build Coastguard Worker ssize_t size = AMediaExtractor_getSampleSize(mExtractor);
287*b7c941bbSAndroid Build Coastguard Worker int64_t pts = AMediaExtractor_getSampleTime(mExtractor);
288*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(size > bufSize,
289*b7c941bbSAndroid Build Coastguard Worker StringFormat("extractor sample size exceeds codec input buffer size %zu %zu",
290*b7c941bbSAndroid Build Coastguard Worker size, bufSize))
291*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(size != AMediaExtractor_readSampleData(mExtractor, buf, bufSize),
292*b7c941bbSAndroid Build Coastguard Worker std::string{"AMediaExtractor_readSampleData failed"})
293*b7c941bbSAndroid Build Coastguard Worker if (!AMediaExtractor_advance(mExtractor) && mSignalEOSWithLastFrame) {
294*b7c941bbSAndroid Build Coastguard Worker flags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
295*b7c941bbSAndroid Build Coastguard Worker mSawDecInputEOS = true;
296*b7c941bbSAndroid Build Coastguard Worker }
297*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, size, pts, flags),
298*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_queueInputBuffer failed")
299*b7c941bbSAndroid Build Coastguard Worker ALOGV("input: id: %zu size: %zu pts: %" PRId64 " flags: %d", bufferIndex, size, pts,
300*b7c941bbSAndroid Build Coastguard Worker flags);
301*b7c941bbSAndroid Build Coastguard Worker if (size > 0) {
302*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->saveInPTS(pts);
303*b7c941bbSAndroid Build Coastguard Worker mDecInputCount++;
304*b7c941bbSAndroid Build Coastguard Worker }
305*b7c941bbSAndroid Build Coastguard Worker }
306*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
307*b7c941bbSAndroid Build Coastguard Worker }
308*b7c941bbSAndroid Build Coastguard Worker
dequeueDecoderOutput(size_t bufferIndex,AMediaCodecBufferInfo * bufferInfo)309*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderSurfaceTest::dequeueDecoderOutput(size_t bufferIndex,
310*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo* bufferInfo) {
311*b7c941bbSAndroid Build Coastguard Worker if ((bufferInfo->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) != 0) {
312*b7c941bbSAndroid Build Coastguard Worker mSawDecOutputEOS = true;
313*b7c941bbSAndroid Build Coastguard Worker }
314*b7c941bbSAndroid Build Coastguard Worker if (bufferInfo->size > 0 && (bufferInfo->flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) == 0) {
315*b7c941bbSAndroid Build Coastguard Worker mDecOutputCount++;
316*b7c941bbSAndroid Build Coastguard Worker }
317*b7c941bbSAndroid Build Coastguard Worker ALOGV("output: id: %zu size: %d pts: %" PRId64 " flags: %d", bufferIndex, bufferInfo->size,
318*b7c941bbSAndroid Build Coastguard Worker bufferInfo->presentationTimeUs, bufferInfo->flags);
319*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_releaseOutputBuffer(mDecoder, bufferIndex, mWindow != nullptr),
320*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_releaseOutputBuffer failed")
321*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
322*b7c941bbSAndroid Build Coastguard Worker }
323*b7c941bbSAndroid Build Coastguard Worker
dequeueEncoderOutput(size_t bufferIndex,AMediaCodecBufferInfo * info)324*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderSurfaceTest::dequeueEncoderOutput(size_t bufferIndex,
325*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo* info) {
326*b7c941bbSAndroid Build Coastguard Worker if ((info->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) != 0) {
327*b7c941bbSAndroid Build Coastguard Worker mSawEncOutputEOS = true;
328*b7c941bbSAndroid Build Coastguard Worker }
329*b7c941bbSAndroid Build Coastguard Worker if (info->size > 0) {
330*b7c941bbSAndroid Build Coastguard Worker size_t buffSize;
331*b7c941bbSAndroid Build Coastguard Worker uint8_t* buf = AMediaCodec_getOutputBuffer(mEncoder, bufferIndex, &buffSize);
332*b7c941bbSAndroid Build Coastguard Worker // NdkMediaCodec calls ABuffer::data, which already adds offset
333*b7c941bbSAndroid Build Coastguard Worker info->offset = 0;
334*b7c941bbSAndroid Build Coastguard Worker if (mSaveToMem) {
335*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->saveToMemory(buf, info);
336*b7c941bbSAndroid Build Coastguard Worker }
337*b7c941bbSAndroid Build Coastguard Worker if (mMuxer != nullptr) {
338*b7c941bbSAndroid Build Coastguard Worker if (mMuxTrackID == -1) {
339*b7c941bbSAndroid Build Coastguard Worker mMuxTrackID = AMediaMuxer_addTrack(mMuxer, AMediaCodec_getOutputFormat(mEncoder));
340*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaMuxer_start(mMuxer), "AMediaMuxer_start failed")
341*b7c941bbSAndroid Build Coastguard Worker }
342*b7c941bbSAndroid Build Coastguard Worker if ((info->flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) == 0) {
343*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaMuxer_writeSampleData(mMuxer, mMuxTrackID, buf, info),
344*b7c941bbSAndroid Build Coastguard Worker "AMediaMuxer_writeSampleData failed")
345*b7c941bbSAndroid Build Coastguard Worker }
346*b7c941bbSAndroid Build Coastguard Worker }
347*b7c941bbSAndroid Build Coastguard Worker if ((info->flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) == 0) {
348*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->saveOutPTS(info->presentationTimeUs);
349*b7c941bbSAndroid Build Coastguard Worker mEncOutputCount++;
350*b7c941bbSAndroid Build Coastguard Worker }
351*b7c941bbSAndroid Build Coastguard Worker }
352*b7c941bbSAndroid Build Coastguard Worker ALOGV("output: id: %zu size: %d pts: %" PRId64 " flags: %d", bufferIndex, info->size,
353*b7c941bbSAndroid Build Coastguard Worker info->presentationTimeUs, info->flags);
354*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_releaseOutputBuffer(mEncoder, bufferIndex, false),
355*b7c941bbSAndroid Build Coastguard Worker "AMediaCodec_releaseOutputBuffer failed")
356*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
357*b7c941bbSAndroid Build Coastguard Worker }
358*b7c941bbSAndroid Build Coastguard Worker
tryEncoderOutput(long timeOutUs)359*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderSurfaceTest::tryEncoderOutput(long timeOutUs) {
360*b7c941bbSAndroid Build Coastguard Worker if (mIsCodecInAsyncMode) {
361*b7c941bbSAndroid Build Coastguard Worker if (!hasSeenError() && !mSawEncOutputEOS) {
362*b7c941bbSAndroid Build Coastguard Worker while (mReviseLatency) {
363*b7c941bbSAndroid Build Coastguard Worker if (!mAsyncHandleEncoder.waitOnFormatChange()) {
364*b7c941bbSAndroid Build Coastguard Worker mErrorLogs.append("taking too long to receive onOutputFormatChanged callback");
365*b7c941bbSAndroid Build Coastguard Worker return false;
366*b7c941bbSAndroid Build Coastguard Worker }
367*b7c941bbSAndroid Build Coastguard Worker int actualLatency;
368*b7c941bbSAndroid Build Coastguard Worker mReviseLatency = false;
369*b7c941bbSAndroid Build Coastguard Worker if (AMediaFormat_getInt32(mAsyncHandleEncoder.getOutputFormat(),
370*b7c941bbSAndroid Build Coastguard Worker AMEDIAFORMAT_KEY_LATENCY, &actualLatency)) {
371*b7c941bbSAndroid Build Coastguard Worker if (mLatency < actualLatency) {
372*b7c941bbSAndroid Build Coastguard Worker mLatency = actualLatency;
373*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
374*b7c941bbSAndroid Build Coastguard Worker }
375*b7c941bbSAndroid Build Coastguard Worker }
376*b7c941bbSAndroid Build Coastguard Worker }
377*b7c941bbSAndroid Build Coastguard Worker callbackObject element = mAsyncHandleEncoder.getOutput();
378*b7c941bbSAndroid Build Coastguard Worker if (element.bufferIndex >= 0) {
379*b7c941bbSAndroid Build Coastguard Worker if (!dequeueEncoderOutput(element.bufferIndex, &element.bufferInfo)) return false;
380*b7c941bbSAndroid Build Coastguard Worker }
381*b7c941bbSAndroid Build Coastguard Worker }
382*b7c941bbSAndroid Build Coastguard Worker } else {
383*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo outInfo;
384*b7c941bbSAndroid Build Coastguard Worker if (!mSawEncOutputEOS) {
385*b7c941bbSAndroid Build Coastguard Worker int bufferID = AMediaCodec_dequeueOutputBuffer(mEncoder, &outInfo, timeOutUs);
386*b7c941bbSAndroid Build Coastguard Worker if (bufferID >= 0) {
387*b7c941bbSAndroid Build Coastguard Worker if (!dequeueEncoderOutput(bufferID, &outInfo)) return false;
388*b7c941bbSAndroid Build Coastguard Worker } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
389*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* outFormat = AMediaCodec_getOutputFormat(mEncoder);
390*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getInt32(outFormat, AMEDIAFORMAT_KEY_LATENCY, &mLatency);
391*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_delete(outFormat);
392*b7c941bbSAndroid Build Coastguard Worker } else if (bufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
393*b7c941bbSAndroid Build Coastguard Worker } else if (bufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
394*b7c941bbSAndroid Build Coastguard Worker } else {
395*b7c941bbSAndroid Build Coastguard Worker mErrorLogs.append(
396*b7c941bbSAndroid Build Coastguard Worker StringFormat("unexpected return value from *_dequeueOutputBuffer: %d",
397*b7c941bbSAndroid Build Coastguard Worker bufferID));
398*b7c941bbSAndroid Build Coastguard Worker return false;
399*b7c941bbSAndroid Build Coastguard Worker }
400*b7c941bbSAndroid Build Coastguard Worker }
401*b7c941bbSAndroid Build Coastguard Worker }
402*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
403*b7c941bbSAndroid Build Coastguard Worker }
404*b7c941bbSAndroid Build Coastguard Worker
waitForAllEncoderOutputs()405*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderSurfaceTest::waitForAllEncoderOutputs() {
406*b7c941bbSAndroid Build Coastguard Worker if (mIsCodecInAsyncMode) {
407*b7c941bbSAndroid Build Coastguard Worker while (!hasSeenError() && !mSawEncOutputEOS) {
408*b7c941bbSAndroid Build Coastguard Worker if (!tryEncoderOutput(kQDeQTimeOutUs)) return false;
409*b7c941bbSAndroid Build Coastguard Worker }
410*b7c941bbSAndroid Build Coastguard Worker } else {
411*b7c941bbSAndroid Build Coastguard Worker while (!mSawEncOutputEOS) {
412*b7c941bbSAndroid Build Coastguard Worker if (!tryEncoderOutput(kQDeQTimeOutUs)) return false;
413*b7c941bbSAndroid Build Coastguard Worker }
414*b7c941bbSAndroid Build Coastguard Worker }
415*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
416*b7c941bbSAndroid Build Coastguard Worker }
417*b7c941bbSAndroid Build Coastguard Worker
queueEOS()418*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderSurfaceTest::queueEOS() {
419*b7c941bbSAndroid Build Coastguard Worker if (mIsCodecInAsyncMode) {
420*b7c941bbSAndroid Build Coastguard Worker while (!hasSeenError() && !mSawDecInputEOS) {
421*b7c941bbSAndroid Build Coastguard Worker callbackObject element = mAsyncHandleDecoder.getWork();
422*b7c941bbSAndroid Build Coastguard Worker if (element.bufferIndex >= 0) {
423*b7c941bbSAndroid Build Coastguard Worker if (element.isInput) {
424*b7c941bbSAndroid Build Coastguard Worker if (!enqueueDecoderEOS(element.bufferIndex)) return false;
425*b7c941bbSAndroid Build Coastguard Worker } else {
426*b7c941bbSAndroid Build Coastguard Worker if (!dequeueDecoderOutput(element.bufferIndex, &element.bufferInfo)) {
427*b7c941bbSAndroid Build Coastguard Worker return false;
428*b7c941bbSAndroid Build Coastguard Worker }
429*b7c941bbSAndroid Build Coastguard Worker }
430*b7c941bbSAndroid Build Coastguard Worker }
431*b7c941bbSAndroid Build Coastguard Worker }
432*b7c941bbSAndroid Build Coastguard Worker } else {
433*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo outInfo;
434*b7c941bbSAndroid Build Coastguard Worker while (!mSawDecInputEOS) {
435*b7c941bbSAndroid Build Coastguard Worker ssize_t oBufferID = AMediaCodec_dequeueOutputBuffer(mDecoder, &outInfo, kQDeQTimeOutUs);
436*b7c941bbSAndroid Build Coastguard Worker if (oBufferID >= 0) {
437*b7c941bbSAndroid Build Coastguard Worker if (!dequeueDecoderOutput(oBufferID, &outInfo)) return false;
438*b7c941bbSAndroid Build Coastguard Worker } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
439*b7c941bbSAndroid Build Coastguard Worker } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
440*b7c941bbSAndroid Build Coastguard Worker } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
441*b7c941bbSAndroid Build Coastguard Worker } else {
442*b7c941bbSAndroid Build Coastguard Worker mErrorLogs.append(
443*b7c941bbSAndroid Build Coastguard Worker StringFormat("unexpected return value from *_dequeueOutputBuffer: %d",
444*b7c941bbSAndroid Build Coastguard Worker oBufferID));
445*b7c941bbSAndroid Build Coastguard Worker return false;
446*b7c941bbSAndroid Build Coastguard Worker }
447*b7c941bbSAndroid Build Coastguard Worker ssize_t iBufferId = AMediaCodec_dequeueInputBuffer(mDecoder, kQDeQTimeOutUs);
448*b7c941bbSAndroid Build Coastguard Worker if (iBufferId >= 0) {
449*b7c941bbSAndroid Build Coastguard Worker if (!enqueueDecoderEOS(iBufferId)) return false;
450*b7c941bbSAndroid Build Coastguard Worker } else if (iBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
451*b7c941bbSAndroid Build Coastguard Worker } else {
452*b7c941bbSAndroid Build Coastguard Worker mErrorLogs.append(
453*b7c941bbSAndroid Build Coastguard Worker StringFormat("unexpected return value from *_dequeueInputBuffer: %zd",
454*b7c941bbSAndroid Build Coastguard Worker iBufferId));
455*b7c941bbSAndroid Build Coastguard Worker return false;
456*b7c941bbSAndroid Build Coastguard Worker }
457*b7c941bbSAndroid Build Coastguard Worker }
458*b7c941bbSAndroid Build Coastguard Worker }
459*b7c941bbSAndroid Build Coastguard Worker
460*b7c941bbSAndroid Build Coastguard Worker if (mIsCodecInAsyncMode) {
461*b7c941bbSAndroid Build Coastguard Worker // output processing after queuing EOS is done in waitForAllOutputs()
462*b7c941bbSAndroid Build Coastguard Worker while (!hasSeenError() && !mSawDecOutputEOS) {
463*b7c941bbSAndroid Build Coastguard Worker callbackObject element = mAsyncHandleDecoder.getOutput();
464*b7c941bbSAndroid Build Coastguard Worker if (element.bufferIndex >= 0) {
465*b7c941bbSAndroid Build Coastguard Worker if (!dequeueDecoderOutput(element.bufferIndex, &element.bufferInfo)) return false;
466*b7c941bbSAndroid Build Coastguard Worker }
467*b7c941bbSAndroid Build Coastguard Worker if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
468*b7c941bbSAndroid Build Coastguard Worker if (mDecOutputCount - mEncOutputCount > mLatency) {
469*b7c941bbSAndroid Build Coastguard Worker if (!tryEncoderOutput(-1)) return false;
470*b7c941bbSAndroid Build Coastguard Worker }
471*b7c941bbSAndroid Build Coastguard Worker }
472*b7c941bbSAndroid Build Coastguard Worker } else {
473*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo outInfo;
474*b7c941bbSAndroid Build Coastguard Worker // output processing after queuing EOS is done in waitForAllOutputs()
475*b7c941bbSAndroid Build Coastguard Worker while (!mSawDecOutputEOS) {
476*b7c941bbSAndroid Build Coastguard Worker if (!mSawDecOutputEOS) {
477*b7c941bbSAndroid Build Coastguard Worker ssize_t oBufferID =
478*b7c941bbSAndroid Build Coastguard Worker AMediaCodec_dequeueOutputBuffer(mDecoder, &outInfo, kQDeQTimeOutUs);
479*b7c941bbSAndroid Build Coastguard Worker if (oBufferID >= 0) {
480*b7c941bbSAndroid Build Coastguard Worker if (!dequeueDecoderOutput(oBufferID, &outInfo)) return false;
481*b7c941bbSAndroid Build Coastguard Worker } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
482*b7c941bbSAndroid Build Coastguard Worker } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
483*b7c941bbSAndroid Build Coastguard Worker } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
484*b7c941bbSAndroid Build Coastguard Worker } else {
485*b7c941bbSAndroid Build Coastguard Worker mErrorLogs.append(
486*b7c941bbSAndroid Build Coastguard Worker StringFormat("unexpected return value from *_dequeueOutputBuffer: %d",
487*b7c941bbSAndroid Build Coastguard Worker oBufferID));
488*b7c941bbSAndroid Build Coastguard Worker return false;
489*b7c941bbSAndroid Build Coastguard Worker }
490*b7c941bbSAndroid Build Coastguard Worker }
491*b7c941bbSAndroid Build Coastguard Worker if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
492*b7c941bbSAndroid Build Coastguard Worker if (mDecOutputCount - mEncOutputCount > mLatency) {
493*b7c941bbSAndroid Build Coastguard Worker if (!tryEncoderOutput(-1)) return false;
494*b7c941bbSAndroid Build Coastguard Worker }
495*b7c941bbSAndroid Build Coastguard Worker }
496*b7c941bbSAndroid Build Coastguard Worker }
497*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
498*b7c941bbSAndroid Build Coastguard Worker }
499*b7c941bbSAndroid Build Coastguard Worker
doWork(int frameLimit)500*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderSurfaceTest::doWork(int frameLimit) {
501*b7c941bbSAndroid Build Coastguard Worker int frameCnt = 0;
502*b7c941bbSAndroid Build Coastguard Worker if (mIsCodecInAsyncMode) {
503*b7c941bbSAndroid Build Coastguard Worker // output processing after queuing EOS is done in waitForAllOutputs()
504*b7c941bbSAndroid Build Coastguard Worker while (!hasSeenError() && !mSawDecInputEOS && frameCnt < frameLimit) {
505*b7c941bbSAndroid Build Coastguard Worker callbackObject element = mAsyncHandleDecoder.getWork();
506*b7c941bbSAndroid Build Coastguard Worker if (element.bufferIndex >= 0) {
507*b7c941bbSAndroid Build Coastguard Worker if (element.isInput) {
508*b7c941bbSAndroid Build Coastguard Worker if (!enqueueDecoderInput(element.bufferIndex)) return false;
509*b7c941bbSAndroid Build Coastguard Worker frameCnt++;
510*b7c941bbSAndroid Build Coastguard Worker } else {
511*b7c941bbSAndroid Build Coastguard Worker if (!dequeueDecoderOutput(element.bufferIndex, &element.bufferInfo)) {
512*b7c941bbSAndroid Build Coastguard Worker return false;
513*b7c941bbSAndroid Build Coastguard Worker }
514*b7c941bbSAndroid Build Coastguard Worker }
515*b7c941bbSAndroid Build Coastguard Worker }
516*b7c941bbSAndroid Build Coastguard Worker // check decoder EOS
517*b7c941bbSAndroid Build Coastguard Worker if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
518*b7c941bbSAndroid Build Coastguard Worker // encoder output
519*b7c941bbSAndroid Build Coastguard Worker if (mDecOutputCount - mEncOutputCount > mLatency) {
520*b7c941bbSAndroid Build Coastguard Worker if (!tryEncoderOutput(-1)) return false;
521*b7c941bbSAndroid Build Coastguard Worker }
522*b7c941bbSAndroid Build Coastguard Worker }
523*b7c941bbSAndroid Build Coastguard Worker } else {
524*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo outInfo;
525*b7c941bbSAndroid Build Coastguard Worker // output processing after queuing EOS is done in waitForAllOutputs()
526*b7c941bbSAndroid Build Coastguard Worker while (!mSawDecInputEOS && frameCnt < frameLimit) {
527*b7c941bbSAndroid Build Coastguard Worker ssize_t oBufferID = AMediaCodec_dequeueOutputBuffer(mDecoder, &outInfo, kQDeQTimeOutUs);
528*b7c941bbSAndroid Build Coastguard Worker if (oBufferID >= 0) {
529*b7c941bbSAndroid Build Coastguard Worker if (!dequeueDecoderOutput(oBufferID, &outInfo)) return false;
530*b7c941bbSAndroid Build Coastguard Worker } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
531*b7c941bbSAndroid Build Coastguard Worker } else if (oBufferID == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
532*b7c941bbSAndroid Build Coastguard Worker } else if (oBufferID == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
533*b7c941bbSAndroid Build Coastguard Worker } else {
534*b7c941bbSAndroid Build Coastguard Worker mErrorLogs.append(
535*b7c941bbSAndroid Build Coastguard Worker StringFormat("unexpected return value from *_dequeueOutputBuffer: %zd",
536*b7c941bbSAndroid Build Coastguard Worker oBufferID));
537*b7c941bbSAndroid Build Coastguard Worker return false;
538*b7c941bbSAndroid Build Coastguard Worker }
539*b7c941bbSAndroid Build Coastguard Worker ssize_t iBufferId = AMediaCodec_dequeueInputBuffer(mDecoder, kQDeQTimeOutUs);
540*b7c941bbSAndroid Build Coastguard Worker if (iBufferId >= 0) {
541*b7c941bbSAndroid Build Coastguard Worker if (!enqueueDecoderInput(iBufferId)) return false;
542*b7c941bbSAndroid Build Coastguard Worker frameCnt++;
543*b7c941bbSAndroid Build Coastguard Worker } else if (iBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
544*b7c941bbSAndroid Build Coastguard Worker } else {
545*b7c941bbSAndroid Build Coastguard Worker mErrorLogs.append(
546*b7c941bbSAndroid Build Coastguard Worker StringFormat("unexpected return value from *_dequeueInputBuffer: %zd",
547*b7c941bbSAndroid Build Coastguard Worker iBufferId));
548*b7c941bbSAndroid Build Coastguard Worker return false;
549*b7c941bbSAndroid Build Coastguard Worker }
550*b7c941bbSAndroid Build Coastguard Worker if (mSawDecOutputEOS) AMediaCodec_signalEndOfInputStream(mEncoder);
551*b7c941bbSAndroid Build Coastguard Worker if (mDecOutputCount - mEncOutputCount > mLatency) {
552*b7c941bbSAndroid Build Coastguard Worker if (!tryEncoderOutput(-1)) return false;
553*b7c941bbSAndroid Build Coastguard Worker }
554*b7c941bbSAndroid Build Coastguard Worker }
555*b7c941bbSAndroid Build Coastguard Worker }
556*b7c941bbSAndroid Build Coastguard Worker return !hasSeenError();
557*b7c941bbSAndroid Build Coastguard Worker }
558*b7c941bbSAndroid Build Coastguard Worker
testSimpleEncode(const char * encoder,const char * decoder,const char * srcPath,const char * srcMediaType,const char * muxOutPath,int colorFormat,bool usePersistentSurface,int frameLimit)559*b7c941bbSAndroid Build Coastguard Worker bool CodecEncoderSurfaceTest::testSimpleEncode(const char* encoder, const char* decoder,
560*b7c941bbSAndroid Build Coastguard Worker const char* srcPath, const char *srcMediaType,
561*b7c941bbSAndroid Build Coastguard Worker const char* muxOutPath, int colorFormat,
562*b7c941bbSAndroid Build Coastguard Worker bool usePersistentSurface, int frameLimit) {
563*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FALSE(setUpExtractor(srcPath, srcMediaType, colorFormat),
564*b7c941bbSAndroid Build Coastguard Worker std::string{"setUpExtractor failed"})
565*b7c941bbSAndroid Build Coastguard Worker bool muxOutput = muxOutPath != nullptr;
566*b7c941bbSAndroid Build Coastguard Worker
567*b7c941bbSAndroid Build Coastguard Worker /* TODO(b/149027258) */
568*b7c941bbSAndroid Build Coastguard Worker if (true) mSaveToMem = false;
569*b7c941bbSAndroid Build Coastguard Worker else mSaveToMem = true;
570*b7c941bbSAndroid Build Coastguard Worker auto ref = mRefBuff;
571*b7c941bbSAndroid Build Coastguard Worker auto test = mTestBuff;
572*b7c941bbSAndroid Build Coastguard Worker int loopCounter = 0;
573*b7c941bbSAndroid Build Coastguard Worker const bool boolStates[]{true, false};
574*b7c941bbSAndroid Build Coastguard Worker for (bool isAsync : boolStates) {
575*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_seekTo(mExtractor, 0, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC);
576*b7c941bbSAndroid Build Coastguard Worker mOutputBuff = loopCounter == 0 ? ref : test;
577*b7c941bbSAndroid Build Coastguard Worker mOutputBuff->reset();
578*b7c941bbSAndroid Build Coastguard Worker
579*b7c941bbSAndroid Build Coastguard Worker /* TODO(b/147348711) */
580*b7c941bbSAndroid Build Coastguard Worker /* Instead of create and delete codec at every iteration, we would like to create
581*b7c941bbSAndroid Build Coastguard Worker * once and use it for all iterations and delete before exiting */
582*b7c941bbSAndroid Build Coastguard Worker mEncoder = AMediaCodec_createCodecByName(encoder);
583*b7c941bbSAndroid Build Coastguard Worker mDecoder = AMediaCodec_createCodecByName(decoder);
584*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mDecoder, StringFormat("unable to create media codec by name %s", decoder))
585*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_NULL(mEncoder, StringFormat("unable to create media codec by name %s", encoder))
586*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = nullptr;
587*b7c941bbSAndroid Build Coastguard Worker if (muxOutput && loopCounter == 0) {
588*b7c941bbSAndroid Build Coastguard Worker OutputFormat muxerFormat = AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4;
589*b7c941bbSAndroid Build Coastguard Worker if (!strcmp(mMediaType, AMEDIA_MIMETYPE_VIDEO_VP8) ||
590*b7c941bbSAndroid Build Coastguard Worker !strcmp(mMediaType, AMEDIA_MIMETYPE_VIDEO_VP9)) {
591*b7c941bbSAndroid Build Coastguard Worker muxerFormat = AMEDIAMUXER_OUTPUT_FORMAT_WEBM;
592*b7c941bbSAndroid Build Coastguard Worker }
593*b7c941bbSAndroid Build Coastguard Worker ofp = fopen(muxOutPath, "wbe+");
594*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
595*b7c941bbSAndroid Build Coastguard Worker mMuxer = AMediaMuxer_new(fileno(ofp), muxerFormat);
596*b7c941bbSAndroid Build Coastguard Worker }
597*b7c941bbSAndroid Build Coastguard Worker }
598*b7c941bbSAndroid Build Coastguard Worker if (!configureCodec(isAsync, false, usePersistentSurface)) return false;
599*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mEncoder), "Encoder AMediaCodec_start failed")
600*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_start(mDecoder), "Decoder AMediaCodec_start failed")
601*b7c941bbSAndroid Build Coastguard Worker if (!doWork(frameLimit)) return false;
602*b7c941bbSAndroid Build Coastguard Worker if (!queueEOS()) return false;
603*b7c941bbSAndroid Build Coastguard Worker if (!waitForAllEncoderOutputs()) return false;
604*b7c941bbSAndroid Build Coastguard Worker if (muxOutput) {
605*b7c941bbSAndroid Build Coastguard Worker if (mMuxer != nullptr) {
606*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaMuxer_stop(mMuxer), "AMediaMuxer_stop failed")
607*b7c941bbSAndroid Build Coastguard Worker mMuxTrackID = -1;
608*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaMuxer_delete(mMuxer), "AMediaMuxer_delete failed")
609*b7c941bbSAndroid Build Coastguard Worker mMuxer = nullptr;
610*b7c941bbSAndroid Build Coastguard Worker }
611*b7c941bbSAndroid Build Coastguard Worker if (ofp) fclose(ofp);
612*b7c941bbSAndroid Build Coastguard Worker }
613*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_stop(mDecoder), "AMediaCodec_stop failed for Decoder")
614*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_stop(mEncoder), "AMediaCodec_stop failed for Encoder")
615*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(mAsyncHandleDecoder.getError(),
616*b7c941bbSAndroid Build Coastguard Worker std::string{"Decoder has encountered error in async mode. \n"}.append(
617*b7c941bbSAndroid Build Coastguard Worker mAsyncHandleDecoder.getErrorMsg()))
618*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(mAsyncHandleEncoder.getError(),
619*b7c941bbSAndroid Build Coastguard Worker std::string{"Encoder has encountered error in async mode. \n"}.append(
620*b7c941bbSAndroid Build Coastguard Worker mAsyncHandleEncoder.getErrorMsg()))
621*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE((0 == mDecInputCount), std::string{"Decoder has not received any input \n"})
622*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE((0 == mDecOutputCount), std::string{"Decoder has not sent any output \n"})
623*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE((0 == mEncOutputCount), std::string{"Encoder has not sent any output \n"})
624*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE((mDecInputCount != mDecOutputCount),
625*b7c941bbSAndroid Build Coastguard Worker StringFormat("Decoder output count is not equal to decoder input count\n "
626*b7c941bbSAndroid Build Coastguard Worker "Input count : %s, Output count : %s\n",
627*b7c941bbSAndroid Build Coastguard Worker mDecInputCount, mDecOutputCount))
628*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE((mMaxBFrames == 0 && !mOutputBuff->isPtsStrictlyIncreasing(INT32_MIN)),
629*b7c941bbSAndroid Build Coastguard Worker std::string{"Output timestamps are not strictly increasing \n"}.append(
630*b7c941bbSAndroid Build Coastguard Worker ref->getErrorMsg()))
631*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE((mEncOutputCount != mDecOutputCount),
632*b7c941bbSAndroid Build Coastguard Worker StringFormat("Encoder output count is not equal to decoder input "
633*b7c941bbSAndroid Build Coastguard Worker "count\n Input count : %s, Output count : %s\n",
634*b7c941bbSAndroid Build Coastguard Worker mDecInputCount, mEncOutputCount))
635*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE(!mOutputBuff->isOutPtsListIdenticalToInpPtsList(mMaxBFrames != 0),
636*b7c941bbSAndroid Build Coastguard Worker std::string{"Input pts list and Output pts list are not identical \n"}
637*b7c941bbSAndroid Build Coastguard Worker .append(ref->getErrorMsg()))
638*b7c941bbSAndroid Build Coastguard Worker // TODO:(b/149027258) Remove false once output is validated across runs
639*b7c941bbSAndroid Build Coastguard Worker if (false) {
640*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_TRUE((loopCounter != 0 && !ref->equals(test)),
641*b7c941bbSAndroid Build Coastguard Worker std::string{"Encoder output is not consistent across runs \n"}.append(
642*b7c941bbSAndroid Build Coastguard Worker test->getErrorMsg()))
643*b7c941bbSAndroid Build Coastguard Worker }
644*b7c941bbSAndroid Build Coastguard Worker loopCounter++;
645*b7c941bbSAndroid Build Coastguard Worker ANativeWindow_release(mWindow);
646*b7c941bbSAndroid Build Coastguard Worker mWindow = nullptr;
647*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_delete(mEncoder), "AMediaCodec_delete failed for encoder")
648*b7c941bbSAndroid Build Coastguard Worker mEncoder = nullptr;
649*b7c941bbSAndroid Build Coastguard Worker RETURN_IF_FAIL(AMediaCodec_delete(mDecoder), "AMediaCodec_delete failed for decoder")
650*b7c941bbSAndroid Build Coastguard Worker mDecoder = nullptr;
651*b7c941bbSAndroid Build Coastguard Worker }
652*b7c941bbSAndroid Build Coastguard Worker return true;
653*b7c941bbSAndroid Build Coastguard Worker }
654*b7c941bbSAndroid Build Coastguard Worker
nativeTestSimpleEncode(JNIEnv * env,jobject,jstring jEncoder,jstring jDecoder,jstring jMediaType,jstring jtestFile,jstring jTestFileMediaType,jstring jmuxFile,jint jColorFormat,jboolean jUsePersistentSurface,jstring jCfgParams,jstring jSeparator,jobject jRetMsg,jint jFrameLimit)655*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestSimpleEncode(JNIEnv* env, jobject, jstring jEncoder, jstring jDecoder,
656*b7c941bbSAndroid Build Coastguard Worker jstring jMediaType, jstring jtestFile,
657*b7c941bbSAndroid Build Coastguard Worker jstring jTestFileMediaType, jstring jmuxFile,
658*b7c941bbSAndroid Build Coastguard Worker jint jColorFormat, jboolean jUsePersistentSurface,
659*b7c941bbSAndroid Build Coastguard Worker jstring jCfgParams, jstring jSeparator, jobject jRetMsg,
660*b7c941bbSAndroid Build Coastguard Worker jint jFrameLimit) {
661*b7c941bbSAndroid Build Coastguard Worker const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
662*b7c941bbSAndroid Build Coastguard Worker const char* cDecoder = env->GetStringUTFChars(jDecoder, nullptr);
663*b7c941bbSAndroid Build Coastguard Worker const char* cMediaType = env->GetStringUTFChars(jMediaType, nullptr);
664*b7c941bbSAndroid Build Coastguard Worker const char* cTestFile = env->GetStringUTFChars(jtestFile, nullptr);
665*b7c941bbSAndroid Build Coastguard Worker const char* cTestFileMediaType = env->GetStringUTFChars(jTestFileMediaType, nullptr);
666*b7c941bbSAndroid Build Coastguard Worker const char* cMuxFile = jmuxFile ? env->GetStringUTFChars(jmuxFile, nullptr) : nullptr;
667*b7c941bbSAndroid Build Coastguard Worker const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
668*b7c941bbSAndroid Build Coastguard Worker const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
669*b7c941bbSAndroid Build Coastguard Worker auto codecEncoderSurfaceTest = new CodecEncoderSurfaceTest(cMediaType, cCfgParams, cSeparator);
670*b7c941bbSAndroid Build Coastguard Worker bool isPass = codecEncoderSurfaceTest->testSimpleEncode(cEncoder, cDecoder, cTestFile,
671*b7c941bbSAndroid Build Coastguard Worker cTestFileMediaType, cMuxFile,
672*b7c941bbSAndroid Build Coastguard Worker jColorFormat, jUsePersistentSurface,
673*b7c941bbSAndroid Build Coastguard Worker jFrameLimit);
674*b7c941bbSAndroid Build Coastguard Worker std::string msg = isPass ? std::string{} : codecEncoderSurfaceTest->getErrorMsg();
675*b7c941bbSAndroid Build Coastguard Worker delete codecEncoderSurfaceTest;
676*b7c941bbSAndroid Build Coastguard Worker jclass clazz = env->GetObjectClass(jRetMsg);
677*b7c941bbSAndroid Build Coastguard Worker jmethodID mId =
678*b7c941bbSAndroid Build Coastguard Worker env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
679*b7c941bbSAndroid Build Coastguard Worker env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
680*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jEncoder, cEncoder);
681*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jDecoder, cDecoder);
682*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jMediaType, cMediaType);
683*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jtestFile, cTestFile);
684*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jTestFileMediaType, cTestFileMediaType);
685*b7c941bbSAndroid Build Coastguard Worker if (cMuxFile) env->ReleaseStringUTFChars(jmuxFile, cMuxFile);
686*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
687*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jSeparator, cSeparator);
688*b7c941bbSAndroid Build Coastguard Worker
689*b7c941bbSAndroid Build Coastguard Worker return isPass;
690*b7c941bbSAndroid Build Coastguard Worker }
691*b7c941bbSAndroid Build Coastguard Worker
registerAndroidMediaV2CtsEncoderSurfaceTest(JNIEnv * env)692*b7c941bbSAndroid Build Coastguard Worker int registerAndroidMediaV2CtsEncoderSurfaceTest(JNIEnv* env) {
693*b7c941bbSAndroid Build Coastguard Worker const JNINativeMethod methodTable[] = {
694*b7c941bbSAndroid Build Coastguard Worker {"nativeTestSimpleEncode",
695*b7c941bbSAndroid Build Coastguard Worker "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
696*b7c941bbSAndroid Build Coastguard Worker "String;Ljava/lang/String;IZLjava/lang/String;Ljava/lang/String;Ljava/lang/"
697*b7c941bbSAndroid Build Coastguard Worker "StringBuilder;I)Z",
698*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestSimpleEncode},
699*b7c941bbSAndroid Build Coastguard Worker };
700*b7c941bbSAndroid Build Coastguard Worker jclass c = env->FindClass("android/mediav2/cts/CodecEncoderSurfaceTest");
701*b7c941bbSAndroid Build Coastguard Worker return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
702*b7c941bbSAndroid Build Coastguard Worker }
703*b7c941bbSAndroid Build Coastguard Worker
JNI_OnLoad(JavaVM * vm,void *)704*b7c941bbSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
705*b7c941bbSAndroid Build Coastguard Worker JNIEnv* env;
706*b7c941bbSAndroid Build Coastguard Worker if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) return JNI_ERR;
707*b7c941bbSAndroid Build Coastguard Worker if (registerAndroidMediaV2CtsEncoderSurfaceTest(env) != JNI_OK) return JNI_ERR;
708*b7c941bbSAndroid Build Coastguard Worker return JNI_VERSION_1_6;
709*b7c941bbSAndroid Build Coastguard Worker }
710