• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.mediav2.common.cts;
18 
19 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
20 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
21 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
22 import static android.mediav2.common.cts.MuxerUtils.getMuxerFormatForMediaType;
23 import static android.mediav2.common.cts.MuxerUtils.getTempFilePath;
24 
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertNotNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assert.fail;
29 
30 import android.annotation.NonNull;
31 import android.graphics.ImageFormat;
32 import android.media.AudioFormat;
33 import android.media.Image;
34 import android.media.MediaCodec;
35 import android.media.MediaCodecInfo;
36 import android.media.MediaFormat;
37 import android.media.MediaMuxer;
38 import android.os.PersistableBundle;
39 import android.util.Log;
40 
41 import com.android.compatibility.common.util.Preconditions;
42 
43 import org.junit.After;
44 import org.junit.Before;
45 
46 import java.io.File;
47 import java.io.FileInputStream;
48 import java.io.IOException;
49 import java.nio.ByteBuffer;
50 import java.util.ArrayList;
51 
52 /**
53  * Wrapper class for trying and testing encoder components.
54  */
55 public class CodecEncoderTestBase extends CodecTestBase {
56     private static final String LOG_TAG = CodecEncoderTestBase.class.getSimpleName();
57 
58     protected final EncoderConfigParams[] mEncCfgParams;
59 
60     protected EncoderConfigParams mActiveEncCfg;
61     protected RawResource mActiveRawRes;
62     protected boolean mIsLoopBack;
63     protected int mLoopBackFrameLimit;
64 
65     protected byte[] mInputData;
66     protected int mInputBufferReadOffset;
67     protected int mNumBytesSubmitted;
68     protected long mInputOffsetPts;
69 
70     protected ArrayList<MediaCodec.BufferInfo> mInfoList = new ArrayList<>();
71 
72     protected boolean mMuxOutput;
73     protected String mMuxedOutputFile;
74     protected MediaMuxer mMuxer;
75     protected int mTrackID = -1;
76 
CodecEncoderTestBase(String encoder, String mediaType, EncoderConfigParams[] encCfgParams, String allTestParams)77     public CodecEncoderTestBase(String encoder, String mediaType,
78             EncoderConfigParams[] encCfgParams, String allTestParams) {
79         super(encoder, mediaType, allTestParams);
80         mEncCfgParams = encCfgParams;
81     }
82 
83     public static final float ACCEPTABLE_WIRELESS_TX_QUALITY = 20.0f;  // psnr in dB
84     public static final float ACCEPTABLE_AV_SYNC_ERROR = 22.0f; // duration in ms
85 
86     /**
87      * Selects encoder input color format in byte buffer mode. As of now ndk tests support only
88      * 420p, 420sp. COLOR_FormatYUV420Flexible although can represent any form of yuv, it doesn't
89      * work in ndk due to lack of AMediaCodec_GetInputImage()
90      */
findByteBufferColorFormat(String encoder, String mediaType)91     public static int findByteBufferColorFormat(String encoder, String mediaType)
92             throws IOException {
93         MediaCodecInfo.CodecCapabilities cap = null;
94         for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) {
95             if (encoder.equals(codecInfo.getName())) {
96                 cap = codecInfo.getCapabilitiesForType(mediaType);
97                 break;
98             }
99         }
100         assertNotNull("did not receive capabilities for encoder: " + encoder + ", media type: "
101                         + mediaType + "\n", cap);
102         int colorFormat = -1;
103         for (int c : cap.colorFormats) {
104             if (c == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar
105                     || c == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar) {
106                 Log.v(LOG_TAG, "selecting color format: " + c);
107                 colorFormat = c;
108                 break;
109             }
110         }
111         return colorFormat;
112     }
113 
validateEncodedPSNR(String inpMediaType, String inpFile, String outMediaType, String outFile, boolean allowInpResize, boolean allowInpLoopBack, double perFramePsnrThreshold)114     public static void validateEncodedPSNR(String inpMediaType, String inpFile,
115             String outMediaType, String outFile, boolean allowInpResize, boolean allowInpLoopBack,
116             double perFramePsnrThreshold) throws IOException, InterruptedException {
117         CompareStreams cs = new CompareStreams(inpMediaType, inpFile, outMediaType, outFile,
118                 allowInpResize, allowInpLoopBack);
119         validateEncodedPSNR(cs.getFramesPSNR(), perFramePsnrThreshold);
120         cs.cleanUp();
121     }
122 
validateEncodedPSNR(RawResource inp, String outMediaType, String outFile, boolean allowInpResize, boolean allowInpLoopBack, double perFramePsnrThreshold)123     public static void validateEncodedPSNR(RawResource inp, String outMediaType, String outFile,
124             boolean allowInpResize, boolean allowInpLoopBack, double perFramePsnrThreshold)
125             throws IOException, InterruptedException {
126         CompareStreams cs = new CompareStreams(inp, outMediaType, outFile, allowInpResize,
127                 allowInpLoopBack);
128         validateEncodedPSNR(cs.getFramesPSNR(), perFramePsnrThreshold);
129         cs.cleanUp();
130     }
131 
validateEncodedPSNR(@onNull ArrayList<double[]> framesPSNR, double perFramePsnrThreshold)132     public static void validateEncodedPSNR(@NonNull ArrayList<double[]> framesPSNR,
133             double perFramePsnrThreshold) {
134         StringBuilder msg = new StringBuilder();
135         boolean isOk = true;
136         for (int j = 0; j < framesPSNR.size(); j++) {
137             double[] framePSNR = framesPSNR.get(j);
138             // https://www.itu.int/dms_pub/itu-t/opb/tut/T-TUT-ASC-2020-HSTP1-PDF-E.pdf
139             // weighted psnr (6 * psnrY + psnrU + psnrV) / 8;
140             // stronger weighting of luma PSNR is to compensate for the fact that most of the
141             // bits are used to describe luma information
142             double weightPSNR = (6 * framePSNR[0] + framePSNR[1] + framePSNR[2]) / 8;
143             if (weightPSNR < perFramePsnrThreshold) {
144                 msg.append(String.format(
145                         "Frame %d - PSNR Y: %f, PSNR U: %f, PSNR V: %f, Weighted PSNR: %f < "
146                                 + "Threshold %f \n",
147                         j, framePSNR[0], framePSNR[1], framePSNR[2], weightPSNR,
148                         perFramePsnrThreshold));
149                 isOk = false;
150             }
151         }
152         assertTrue("Encountered frames with PSNR less than configured threshold "
153                 + perFramePsnrThreshold + "dB \n" + msg, isOk);
154     }
155 
bitRateModeToString(int mode)156     public static String bitRateModeToString(int mode) {
157         switch (mode) {
158             case MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR:
159                 return "cbr";
160             case MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR:
161                 return "vbr";
162             case MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ:
163                 return "cq";
164             case MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR_FD:
165                 return "cbrwithfd";
166             default:
167                 return "unknown";
168         }
169     }
170 
rangeToString(int range)171     public static String rangeToString(int range) {
172         switch (range) {
173             case UNSPECIFIED:
174                 return "unspecified";
175             case MediaFormat.COLOR_RANGE_FULL:
176                 return "full";
177             case MediaFormat.COLOR_RANGE_LIMITED:
178                 return "limited";
179             default:
180                 return "unknown";
181         }
182     }
183 
colorStandardToString(int standard)184     public static String colorStandardToString(int standard) {
185         switch (standard) {
186             case UNSPECIFIED:
187                 return "unspecified";
188             case MediaFormat.COLOR_STANDARD_BT709:
189                 return "bt709";
190             case MediaFormat.COLOR_STANDARD_BT601_PAL:
191                 return "bt601pal";
192             case MediaFormat.COLOR_STANDARD_BT601_NTSC:
193                 return "bt601ntsc";
194             case MediaFormat.COLOR_STANDARD_BT2020:
195                 return "bt2020";
196             default:
197                 return "unknown";
198         }
199     }
200 
colorTransferToString(int transfer)201     public static String colorTransferToString(int transfer) {
202         switch (transfer) {
203             case UNSPECIFIED:
204                 return "unspecified";
205             case MediaFormat.COLOR_TRANSFER_LINEAR:
206                 return "linear";
207             case MediaFormat.COLOR_TRANSFER_SDR_VIDEO:
208                 return "sdr";
209             case MediaFormat.COLOR_TRANSFER_HLG:
210                 return "hlg";
211             case MediaFormat.COLOR_TRANSFER_ST2084:
212                 return "st2084";
213             default:
214                 return "unknown";
215         }
216     }
217 
colorFormatToString(int colorFormat, int bitDepth)218     public static String colorFormatToString(int colorFormat, int bitDepth) {
219         switch (colorFormat) {
220             case COLOR_FormatYUV420Flexible:
221                 return "yuv420flexible";
222             case COLOR_FormatYUVP010:
223                 return "yuvp010";
224             case COLOR_FormatSurface:
225                 if (bitDepth == 8) {
226                     return "surfacergb888";
227                 } else if (bitDepth == 10) {
228                     return "surfaceabgr2101010";
229                 } else {
230                     return "unknown";
231                 }
232             default:
233                 return "unknown";
234         }
235     }
236 
audioEncodingToString(int enc)237     public static String audioEncodingToString(int enc) {
238         switch (enc) {
239             case AudioFormat.ENCODING_INVALID:
240                 return "invalid";
241             case AudioFormat.ENCODING_PCM_16BIT:
242                 return "pcm16";
243             case AudioFormat.ENCODING_PCM_FLOAT:
244                 return "pcmfloat";
245             default:
246                 return "unknown";
247         }
248     }
249 
250     @Before
setUpCodecEncoderTestBase()251     public void setUpCodecEncoderTestBase() {
252         assertTrue("Testing a mediaType that is neither audio nor video is not supported \n"
253                 + mTestConfig, mIsAudio || mIsVideo);
254     }
255 
deleteMuxedFile()256     public void deleteMuxedFile() {
257         if (mMuxedOutputFile != null) {
258             File file = new File(mMuxedOutputFile);
259             if (file.exists()) {
260                 assertTrue("unable to delete file " + mMuxedOutputFile, file.delete());
261             }
262             mMuxedOutputFile = null;
263         }
264     }
265 
266     @After
tearDown()267     public void tearDown() {
268         if (mMuxer != null) {
269             mMuxer.release();
270             mMuxer = null;
271         }
272         deleteMuxedFile();
273     }
274 
275     @Override
resetContext(boolean isAsync, boolean signalEOSWithLastFrame)276     protected void resetContext(boolean isAsync, boolean signalEOSWithLastFrame) {
277         super.resetContext(isAsync, signalEOSWithLastFrame);
278         mInputBufferReadOffset = 0;
279         mNumBytesSubmitted = 0;
280         mInputOffsetPts = 0;
281         mInfoList.clear();
282     }
283 
setUpSource(String inpPath)284     protected void setUpSource(String inpPath) throws IOException {
285         Preconditions.assertTestFileExists(inpPath);
286         try (FileInputStream fInp = new FileInputStream(inpPath)) {
287             int size = (int) new File(inpPath).length();
288             mInputData = new byte[size];
289             fInp.read(mInputData, 0, size);
290         }
291     }
292 
fillImage(Image image)293     protected void fillImage(Image image) {
294         int format = image.getFormat();
295         assertTrue("unexpected image format \n" + mTestConfig + mTestEnv,
296                 format == ImageFormat.YUV_420_888 || format == ImageFormat.YCBCR_P010);
297         int bytesPerSample = (ImageFormat.getBitsPerPixel(format) * 2) / (8 * 3);  // YUV420
298         assertEquals("Invalid bytes per sample \n" + mTestConfig + mTestEnv, bytesPerSample,
299                 mActiveRawRes.mBytesPerSample);
300 
301         int imageWidth = image.getWidth();
302         int imageHeight = image.getHeight();
303         Image.Plane[] planes = image.getPlanes();
304         int offset = mInputBufferReadOffset;
305         for (int i = 0; i < planes.length; ++i) {
306             ByteBuffer buf = planes[i].getBuffer();
307             int width = imageWidth;
308             int height = imageHeight;
309             int tileWidth = mActiveRawRes.mWidth;
310             int tileHeight = mActiveRawRes.mHeight;
311             int rowStride = planes[i].getRowStride();
312             int pixelStride = planes[i].getPixelStride();
313             if (i != 0) {
314                 width = imageWidth / 2;
315                 height = imageHeight / 2;
316                 tileWidth = mActiveRawRes.mWidth / 2;
317                 tileHeight = mActiveRawRes.mHeight / 2;
318             }
319             if (pixelStride == bytesPerSample) {
320                 if (width == rowStride && width == tileWidth && height == tileHeight) {
321                     buf.put(mInputData, offset, width * height * bytesPerSample);
322                 } else {
323                     for (int z = 0; z < height; z += tileHeight) {
324                         int rowsToCopy = Math.min(height - z, tileHeight);
325                         for (int y = 0; y < rowsToCopy; y++) {
326                             for (int x = 0; x < width; x += tileWidth) {
327                                 int colsToCopy = Math.min(width - x, tileWidth);
328                                 buf.position((z + y) * rowStride + x * bytesPerSample);
329                                 buf.put(mInputData, offset + y * tileWidth * bytesPerSample,
330                                         colsToCopy * bytesPerSample);
331                             }
332                         }
333                     }
334                 }
335             } else {
336                 // do it pixel-by-pixel
337                 for (int z = 0; z < height; z += tileHeight) {
338                     int rowsToCopy = Math.min(height - z, tileHeight);
339                     for (int y = 0; y < rowsToCopy; y++) {
340                         int lineOffset = (z + y) * rowStride;
341                         for (int x = 0; x < width; x += tileWidth) {
342                             int colsToCopy = Math.min(width - x, tileWidth);
343                             for (int w = 0; w < colsToCopy; w++) {
344                                 for (int bytePos = 0; bytePos < bytesPerSample; bytePos++) {
345                                     buf.position(lineOffset + (x + w) * pixelStride + bytePos);
346                                     buf.put(mInputData[offset + y * tileWidth * bytesPerSample
347                                             + w * bytesPerSample + bytePos]);
348                                 }
349                             }
350                         }
351                     }
352                 }
353             }
354             offset += tileWidth * tileHeight * bytesPerSample;
355         }
356     }
357 
fillByteBuffer(ByteBuffer inputBuffer)358     void fillByteBuffer(ByteBuffer inputBuffer) {
359         int offset = 0, frmOffset = mInputBufferReadOffset;
360         for (int plane = 0; plane < 3; plane++) {
361             int width = mActiveEncCfg.mWidth;
362             int height = mActiveEncCfg.mHeight;
363             int tileWidth = mActiveRawRes.mWidth;
364             int tileHeight = mActiveRawRes.mHeight;
365             if (plane != 0) {
366                 width = mActiveEncCfg.mWidth / 2;
367                 height = mActiveEncCfg.mHeight / 2;
368                 tileWidth = mActiveRawRes.mWidth / 2;
369                 tileHeight = mActiveRawRes.mHeight / 2;
370             }
371             for (int k = 0; k < height; k += tileHeight) {
372                 int rowsToCopy = Math.min(height - k, tileHeight);
373                 for (int j = 0; j < rowsToCopy; j++) {
374                     for (int i = 0; i < width; i += tileWidth) {
375                         int colsToCopy = Math.min(width - i, tileWidth);
376                         inputBuffer.position(
377                                 offset + (k + j) * width * mActiveRawRes.mBytesPerSample
378                                         + i * mActiveRawRes.mBytesPerSample);
379                         inputBuffer.put(mInputData,
380                                 frmOffset + j * tileWidth * mActiveRawRes.mBytesPerSample,
381                                 colsToCopy * mActiveRawRes.mBytesPerSample);
382                     }
383                 }
384             }
385             offset += width * height * mActiveRawRes.mBytesPerSample;
386             frmOffset += tileWidth * tileHeight * mActiveRawRes.mBytesPerSample;
387         }
388     }
389 
enqueueInput(int bufferIndex)390     protected void enqueueInput(int bufferIndex) {
391         if (mIsLoopBack && mInputBufferReadOffset >= mInputData.length) {
392             mInputBufferReadOffset = 0;
393         }
394         ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
395         if (mInputBufferReadOffset >= mInputData.length) {
396             enqueueEOS(bufferIndex);
397         } else {
398             int size;
399             int flags = 0;
400             long pts = mInputOffsetPts;
401             if (mIsAudio) {
402                 pts += mNumBytesSubmitted * 1000000L / ((long) mActiveRawRes.mBytesPerSample
403                         * mActiveEncCfg.mChannelCount * mActiveEncCfg.mSampleRate);
404                 size = Math.min(inputBuffer.capacity(), mInputData.length - mInputBufferReadOffset);
405                 assertEquals(0, size % ((long) mActiveRawRes.mBytesPerSample
406                         * mActiveEncCfg.mChannelCount));
407                 inputBuffer.put(mInputData, mInputBufferReadOffset, size);
408                 if (mSignalEOSWithLastFrame) {
409                     if (mIsLoopBack ? (mInputCount + 1 >= mLoopBackFrameLimit) :
410                             (mInputBufferReadOffset + size >= mInputData.length)) {
411                         flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
412                         mSawInputEOS = true;
413                     }
414                 }
415                 mInputBufferReadOffset += size;
416             } else {
417                 pts += mInputCount * 1000000L / mActiveEncCfg.mFrameRate;
418                 size = mActiveRawRes.mBytesPerSample * mActiveEncCfg.mWidth * mActiveEncCfg.mHeight
419                         * 3 / 2;
420                 int frmSize = mActiveRawRes.mBytesPerSample * mActiveRawRes.mWidth
421                         * mActiveRawRes.mHeight * 3 / 2;
422                 if (mInputBufferReadOffset + frmSize > mInputData.length) {
423                     fail("received partial frame to encode \n" + mTestConfig + mTestEnv);
424                 } else {
425                     Image img = mCodec.getInputImage(bufferIndex);
426                     assertNotNull("getInputImage() expected to return non-null for video \n"
427                             + mTestConfig + mTestEnv, img);
428                     fillImage(img);
429                 }
430                 if (mSignalEOSWithLastFrame) {
431                     if (mIsLoopBack ? (mInputCount + 1 >= mLoopBackFrameLimit) :
432                             (mInputBufferReadOffset + frmSize >= mInputData.length)) {
433                         flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
434                         mSawInputEOS = true;
435                     }
436                 }
437                 mInputBufferReadOffset += frmSize;
438             }
439             mNumBytesSubmitted += size;
440             if (ENABLE_LOGS) {
441                 Log.v(LOG_TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts
442                         + " flags: " + flags);
443             }
444             mCodec.queueInputBuffer(bufferIndex, 0, size, pts, flags);
445             mOutputBuff.saveInPTS(pts);
446             mInputCount++;
447         }
448     }
449 
dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info)450     protected void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
451         if (ENABLE_LOGS) {
452             Log.v(LOG_TAG, "output: id: " + bufferIndex + " flags: " + info.flags + " size: "
453                     + info.size + " timestamp: " + info.presentationTimeUs);
454         }
455         if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
456             mSawOutputEOS = true;
457         }
458         if (info.size > 0) {
459             ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
460             if (mSaveToMem) {
461                 MediaCodec.BufferInfo copy = new MediaCodec.BufferInfo();
462                 copy.set(mOutputBuff.getOutStreamSize(), info.size, info.presentationTimeUs,
463                         info.flags);
464                 mInfoList.add(copy);
465 
466                 mOutputBuff.checksum(buf, info);
467                 mOutputBuff.saveToMemory(buf, info);
468             }
469             if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
470                 mOutputBuff.saveOutPTS(info.presentationTimeUs);
471                 mOutputCount++;
472             }
473             if (mMuxer != null) {
474                 if (mTrackID == -1) {
475                     mTrackID = mMuxer.addTrack(mCodec.getOutputFormat());
476                     mMuxer.start();
477                 }
478                 if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
479                     mMuxer.writeSampleData(mTrackID, buf, info);
480                 }
481             }
482         }
483         mCodec.releaseOutputBuffer(bufferIndex, false);
484     }
485 
486     @Override
doWork(int frameLimit)487     protected void doWork(int frameLimit) throws IOException, InterruptedException {
488         mLoopBackFrameLimit = frameLimit;
489         if (mMuxOutput) {
490             int muxerFormat = getMuxerFormatForMediaType(mMediaType);
491             mMuxedOutputFile = getTempFilePath((mActiveEncCfg.mInputBitDepth == 10) ? "10bit" : "");
492             mMuxer = new MediaMuxer(mMuxedOutputFile, muxerFormat);
493         }
494         super.doWork(frameLimit);
495     }
496 
497     @Override
waitForAllOutputs()498     protected void waitForAllOutputs() throws InterruptedException {
499         super.waitForAllOutputs();
500         if (mMuxOutput) {
501             if (mTrackID != -1) {
502                 mMuxer.stop();
503                 mTrackID = -1;
504             }
505             if (mMuxer != null) {
506                 mMuxer.release();
507                 mMuxer = null;
508             }
509         }
510     }
511 
512     @Override
validateMetrics(String codec, MediaFormat format)513     protected PersistableBundle validateMetrics(String codec, MediaFormat format) {
514         PersistableBundle metrics = super.validateMetrics(codec, format);
515         assertEquals("error! metrics#MetricsConstants.MIME_TYPE is not as expected \n" + mTestConfig
516                 + mTestEnv, metrics.getString(MediaCodec.MetricsConstants.MIME_TYPE), mMediaType);
517         assertEquals("error! metrics#MetricsConstants.ENCODER is not as expected \n" + mTestConfig
518                 + mTestEnv, 1, metrics.getInt(MediaCodec.MetricsConstants.ENCODER));
519         return metrics;
520     }
521 
encodeToMemory(String encoder, EncoderConfigParams cfg, RawResource res, OutputManager outputBuff, int frameLimit, boolean saveToMem, boolean muxOutput, boolean isAsync, boolean eosType)522     public void encodeToMemory(String encoder, EncoderConfigParams cfg, RawResource res,
523             OutputManager outputBuff, int frameLimit, boolean saveToMem, boolean muxOutput,
524             boolean isAsync, boolean eosType)
525             throws IOException, InterruptedException {
526         mSaveToMem = saveToMem;
527         mMuxOutput = muxOutput;
528         mOutputBuff = outputBuff;
529         mInfoList.clear();
530         mActiveEncCfg = cfg;
531         mActiveRawRes = res;
532         mCodec = MediaCodec.createByCodecName(encoder);
533         setUpSource(mActiveRawRes.mFileName);
534         configureCodec(mActiveEncCfg.getFormat(), isAsync, eosType, true);
535         mCodec.start();
536         doWork(frameLimit);
537         queueEOS();
538         waitForAllOutputs();
539         mCodec.stop();
540         mCodec.release();
541         mActiveRawRes = null;
542         mActiveEncCfg = null;
543         mSaveToMem = false;
544         mMuxOutput = false;
545     }
546 
547     /**
548      * Encodes the given raw resource using the specified encoder configuration and manages
549      * the output.
550      */
encodeToMemory(String encoder, EncoderConfigParams cfg, RawResource res, OutputManager outputBuff, int frameLimit, boolean saveToMem, boolean muxOutput)551     public void encodeToMemory(String encoder, EncoderConfigParams cfg, RawResource res,
552             OutputManager outputBuff, int frameLimit, boolean saveToMem, boolean muxOutput)
553             throws IOException, InterruptedException {
554         encodeToMemory(encoder, cfg, res, outputBuff, frameLimit, saveToMem, muxOutput, true, true);
555     }
556 
encodeToMemory(String encoder, EncoderConfigParams cfg, RawResource res, int frameLimit, boolean saveToMem, boolean muxOutput)557     public void encodeToMemory(String encoder, EncoderConfigParams cfg, RawResource res,
558             int frameLimit, boolean saveToMem, boolean muxOutput)
559             throws IOException, InterruptedException {
560         encodeToMemory(encoder, cfg, res, new OutputManager(), frameLimit, saveToMem, muxOutput);
561     }
562 
setLoopBack(boolean loopBack)563     public void setLoopBack(boolean loopBack) {
564         mIsLoopBack = loopBack;
565     }
566 
getMuxedOutputFilePath()567     public String getMuxedOutputFilePath() {
568         return mMuxedOutputFile;
569     }
570 
571     @Override
validateTestState()572     protected void validateTestState() {
573         super.validateTestState();
574         if ((mIsAudio || (mIsVideo && mActiveEncCfg.mMaxBFrames == 0))
575                 && !mOutputBuff.isPtsStrictlyIncreasing(mPrevOutputPts)) {
576             fail("Output timestamps are not strictly increasing \n" + mTestConfig + mTestEnv
577                     + mOutputBuff.getErrMsg());
578         }
579         if (mIsVideo) {
580             if (!mOutputBuff.isOutPtsListIdenticalToInpPtsList((mActiveEncCfg.mMaxBFrames != 0))) {
581                 fail("Input pts list and Output pts list are not identical \n" + mTestConfig
582                         + mTestEnv + mOutputBuff.getErrMsg());
583             }
584         }
585     }
586 }
587