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