Merge "Benchmark: Add SDK Decoder" am: 03379fb2cc
am: 42e055cd58
Change-Id: I562238f5857feb073cd32c723369e8cbfe53d4b6
gugelfrei
commit
172e15dd36
@ -1,3 +1,4 @@
|
||||
<resources>
|
||||
<string name="input_file_path">/data/local/tmp/MediaBenchmark/res/</string>
|
||||
</resources>
|
||||
<string name="output_file_path">/data/local/tmp/MediaBenchmark/output/</string>
|
||||
</resources>
|
||||
|
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.media.benchmark.tests;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaFormat;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.media.benchmark.R;
|
||||
import com.android.media.benchmark.library.CodecUtils;
|
||||
import com.android.media.benchmark.library.Decoder;
|
||||
import com.android.media.benchmark.library.Extractor;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class DecoderTest {
|
||||
private static final Context mContext =
|
||||
InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
|
||||
private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
|
||||
private static final String TAG = "DecoderTest";
|
||||
private static final long PER_TEST_TIMEOUT_MS = 60000;
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean WRITE_OUTPUT = false;
|
||||
private String mInputFile;
|
||||
private boolean mAsyncMode;
|
||||
|
||||
public DecoderTest(String inputFile, boolean asyncMode) {
|
||||
this.mInputFile = inputFile;
|
||||
this.mAsyncMode = asyncMode;
|
||||
}
|
||||
|
||||
@Parameterized.Parameters
|
||||
public static Collection<Object[]> input() {
|
||||
return Arrays.asList(new Object[][]{
|
||||
//Audio Sync Test
|
||||
{"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", false},
|
||||
{"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", false},
|
||||
{"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", false},
|
||||
{"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", false},
|
||||
{"bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", false},
|
||||
{"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", false},
|
||||
{"bbb_48000hz_2ch_100kbps_opus_30sec.webm", false},
|
||||
// Audio Async Test
|
||||
{"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", true},
|
||||
{"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", true},
|
||||
{"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", true},
|
||||
{"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", true},
|
||||
{"bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", true},
|
||||
{"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", true},
|
||||
{"bbb_48000hz_2ch_100kbps_opus_30sec.webm", true},
|
||||
// Video Sync Test
|
||||
{"crowd_1920x1080_25fps_4000kbps_vp9.webm", false},
|
||||
{"crowd_1920x1080_25fps_4000kbps_vp8.webm", false},
|
||||
{"crowd_1920x1080_25fps_4000kbps_av1.webm", false},
|
||||
{"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", false},
|
||||
{"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", false},
|
||||
{"crowd_352x288_25fps_6000kbps_h263.3gp", false},
|
||||
{"crowd_1920x1080_25fps_6700kbps_h264.ts", false},
|
||||
{"crowd_1920x1080_25fps_4000kbps_h265.mkv", false},
|
||||
// Video Async Test
|
||||
{"crowd_1920x1080_25fps_4000kbps_vp9.webm", true},
|
||||
{"crowd_1920x1080_25fps_4000kbps_vp8.webm", true},
|
||||
{"crowd_1920x1080_25fps_4000kbps_av1.webm", true},
|
||||
{"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", true},
|
||||
{"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", true},
|
||||
{"crowd_352x288_25fps_6000kbps_h263.3gp", true},
|
||||
{"crowd_1920x1080_25fps_6700kbps_h264.ts", true},
|
||||
{"crowd_1920x1080_25fps_4000kbps_h265.mkv", true}});
|
||||
}
|
||||
|
||||
@Test(timeout = PER_TEST_TIMEOUT_MS)
|
||||
public void testDecoder() throws IOException {
|
||||
File inputFile = new File(mInputFilePath + mInputFile);
|
||||
if (inputFile.exists()) {
|
||||
FileInputStream fileInput = new FileInputStream(inputFile);
|
||||
FileDescriptor fileDescriptor = fileInput.getFD();
|
||||
Extractor extractor = new Extractor();
|
||||
int trackCount = extractor.setUpExtractor(fileDescriptor);
|
||||
ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
|
||||
ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
|
||||
if (trackCount <= 0) {
|
||||
Log.e(TAG, "Extraction failed. No tracks for file: " + mInputFile);
|
||||
return;
|
||||
}
|
||||
for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
|
||||
extractor.selectExtractorTrack(currentTrack);
|
||||
MediaFormat format = extractor.getFormat(currentTrack);
|
||||
String mime = format.getString(MediaFormat.KEY_MIME);
|
||||
ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
|
||||
if (mediaCodecs.size() <= 0) {
|
||||
Log.e(TAG,
|
||||
"No suitable codecs found for file: " + mInputFile
|
||||
+ " track : " + currentTrack + " mime: " + mime);
|
||||
continue;
|
||||
}
|
||||
// Get samples from extractor
|
||||
int sampleSize;
|
||||
do {
|
||||
sampleSize = extractor.getFrameSample();
|
||||
MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
|
||||
MediaCodec.BufferInfo info = extractor.getBufferInfo();
|
||||
ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
|
||||
dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
|
||||
bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
|
||||
inputBuffer.add(dataBuffer);
|
||||
frameInfo.add(bufInfo);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG,
|
||||
"Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = "
|
||||
+ bufInfo.presentationTimeUs + " size = " + bufInfo.size);
|
||||
}
|
||||
} while (sampleSize > 0);
|
||||
for (String codecName : mediaCodecs) {
|
||||
FileOutputStream decodeOutputStream = null;
|
||||
if (WRITE_OUTPUT) {
|
||||
if (!Paths.get(mOutputFilePath).toFile().exists()) {
|
||||
Files.createDirectories(Paths.get(mOutputFilePath));
|
||||
}
|
||||
File outFile = new File(mOutputFilePath + "decoder.out");
|
||||
if (outFile.exists()) {
|
||||
if (!outFile.delete()) {
|
||||
Log.e(TAG, " Unable to delete existing file" + outFile.toString());
|
||||
}
|
||||
}
|
||||
if (outFile.createNewFile()) {
|
||||
decodeOutputStream = new FileOutputStream(outFile);
|
||||
} else {
|
||||
Log.e(TAG, "Unable to create file: " + outFile.toString());
|
||||
}
|
||||
}
|
||||
Decoder decoder = new Decoder();
|
||||
decoder.setupDecoder(decodeOutputStream);
|
||||
int status =
|
||||
decoder.decode(inputBuffer, frameInfo, mAsyncMode, format, codecName);
|
||||
decoder.deInitCodec();
|
||||
if (status == 0) {
|
||||
decoder.dumpStatistics(
|
||||
mInputFile + " " + codecName, extractor.getClipDuration());
|
||||
Log.i(TAG,
|
||||
"Decoding Successful for file: " + mInputFile
|
||||
+ " with codec: " + codecName);
|
||||
} else {
|
||||
Log.e(TAG,
|
||||
"Decoder returned error " + status + " for file: " + mInputFile
|
||||
+ " with codec: " + codecName);
|
||||
}
|
||||
decoder.resetDecoder();
|
||||
if (decodeOutputStream != null) {
|
||||
decodeOutputStream.close();
|
||||
}
|
||||
}
|
||||
extractor.unselectExtractorTrack(currentTrack);
|
||||
inputBuffer.clear();
|
||||
frameInfo.clear();
|
||||
}
|
||||
extractor.deinitExtractor();
|
||||
fileInput.close();
|
||||
} else {
|
||||
Log.w(TAG,
|
||||
"Warning: Test Skipped. Cannot find " + mInputFile + " in directory "
|
||||
+ mInputFilePath);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.android.media.benchmark.library;
|
||||
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaCodecList;
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CodecUtils {
|
||||
private CodecUtils() {}
|
||||
|
||||
/**
|
||||
* Queries the MediaCodecList and returns codec names of supported codecs.
|
||||
*
|
||||
* @param mimeType Mime type of input
|
||||
* @param isEncoder Specifies encoder or decoder
|
||||
* @return ArrayList of codec names
|
||||
*/
|
||||
public static ArrayList<String> selectCodecs(String mimeType, boolean isEncoder) {
|
||||
MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
||||
MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
|
||||
ArrayList<String> supportedCodecs = new ArrayList<>();
|
||||
for (MediaCodecInfo codecInfo : codecInfos) {
|
||||
if (isEncoder != codecInfo.isEncoder()) {
|
||||
continue;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) {
|
||||
continue;
|
||||
}
|
||||
String[] types = codecInfo.getSupportedTypes();
|
||||
for (String type : types) {
|
||||
if (type.equalsIgnoreCase(mimeType)) {
|
||||
supportedCodecs.add(codecInfo.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return supportedCodecs;
|
||||
}
|
||||
}
|
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.media.benchmark.library;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import android.media.MediaFormat;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Decoder {
|
||||
private static final String TAG = "Decoder";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final int kQueueDequeueTimeoutUs = 1000;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private MediaCodec mCodec;
|
||||
private ArrayList<BufferInfo> mInputBufferInfo;
|
||||
private Stats mStats;
|
||||
|
||||
private boolean mSawInputEOS;
|
||||
private boolean mSawOutputEOS;
|
||||
private boolean mSignalledError;
|
||||
|
||||
private int mNumOutputFrame;
|
||||
private int mIndex;
|
||||
|
||||
private ArrayList<ByteBuffer> mInputBuffer;
|
||||
private FileOutputStream mOutputStream;
|
||||
|
||||
public Decoder() { mStats = new Stats(); }
|
||||
|
||||
/**
|
||||
* Setup of decoder
|
||||
*
|
||||
* @param outputStream Will dump the output in this stream if not null.
|
||||
*/
|
||||
public void setupDecoder(FileOutputStream outputStream) {
|
||||
mSignalledError = false;
|
||||
mOutputStream = outputStream;
|
||||
}
|
||||
|
||||
private MediaCodec createCodec(String codecName, MediaFormat format) throws IOException {
|
||||
String mime = format.getString(MediaFormat.KEY_MIME);
|
||||
try {
|
||||
MediaCodec codec;
|
||||
if (codecName.isEmpty()) {
|
||||
Log.i(TAG, "File mime type: " + mime);
|
||||
if (mime != null) {
|
||||
codec = MediaCodec.createDecoderByType(mime);
|
||||
Log.i(TAG, "Decoder created for mime type " + mime);
|
||||
return codec;
|
||||
} else {
|
||||
Log.e(TAG, "Mime type is null, please specify a mime type to create decoder");
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
codec = MediaCodec.createByCodecName(codecName);
|
||||
Log.i(TAG, "Decoder created with codec name: " + codecName + " mime: " + mime);
|
||||
return codec;
|
||||
}
|
||||
} catch (IllegalArgumentException ex) {
|
||||
ex.printStackTrace();
|
||||
Log.e(TAG, "Failed to create decoder for " + codecName + " mime:" + mime);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the given input buffer,
|
||||
* provided valid list of buffer info and format are passed as inputs.
|
||||
*
|
||||
* @param inputBuffer Decode the provided list of ByteBuffers
|
||||
* @param inputBufferInfo List of buffer info corresponding to provided input buffers
|
||||
* @param asyncMode Will run on async implementation if true
|
||||
* @param format For creating the decoder if codec name is empty and configuring it
|
||||
* @param codecName Will create the decoder with codecName
|
||||
* @return 0 if decode was successful , -1 for fail, -2 for decoder not created
|
||||
* @throws IOException if the codec cannot be created.
|
||||
*/
|
||||
public int decode(@NonNull ArrayList<ByteBuffer> inputBuffer,
|
||||
@NonNull ArrayList<BufferInfo> inputBufferInfo, final boolean asyncMode,
|
||||
@NonNull MediaFormat format, String codecName) throws IOException {
|
||||
mInputBuffer = new ArrayList<>(inputBuffer.size());
|
||||
mInputBuffer.addAll(inputBuffer);
|
||||
mInputBufferInfo = new ArrayList<>(inputBufferInfo.size());
|
||||
mInputBufferInfo.addAll(inputBufferInfo);
|
||||
mSawInputEOS = false;
|
||||
mSawOutputEOS = false;
|
||||
mNumOutputFrame = 0;
|
||||
mIndex = 0;
|
||||
long sTime = mStats.getCurTime();
|
||||
mCodec = createCodec(codecName, format);
|
||||
if (mCodec == null) {
|
||||
return -2;
|
||||
}
|
||||
if (asyncMode) {
|
||||
mCodec.setCallback(new MediaCodec.Callback() {
|
||||
@Override
|
||||
public void onInputBufferAvailable(
|
||||
@NonNull MediaCodec mediaCodec, int inputBufferId) {
|
||||
try {
|
||||
mStats.addInputTime();
|
||||
onInputAvailable(inputBufferId, mediaCodec);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
|
||||
int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
|
||||
mStats.addOutputTime();
|
||||
onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
|
||||
if (mSawOutputEOS) {
|
||||
Log.i(TAG, "Saw output EOS");
|
||||
synchronized (mLock) { mLock.notify(); }
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOutputFormatChanged(
|
||||
@NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
|
||||
Log.i(TAG, "Output format changed. Format: " + format.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(
|
||||
@NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
|
||||
mSignalledError = true;
|
||||
Log.e(TAG, "Codec Error: " + e.toString());
|
||||
e.printStackTrace();
|
||||
synchronized (mLock) { mLock.notify(); }
|
||||
}
|
||||
});
|
||||
}
|
||||
int isEncoder = 0;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Media Format : " + format.toString());
|
||||
}
|
||||
mCodec.configure(format, null, null, isEncoder);
|
||||
mCodec.start();
|
||||
Log.i(TAG, "Codec started ");
|
||||
long eTime = mStats.getCurTime();
|
||||
mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
|
||||
mStats.setStartTime();
|
||||
if (asyncMode) {
|
||||
try {
|
||||
synchronized (mLock) { mLock.wait(); }
|
||||
if (mSignalledError) {
|
||||
return -1;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
while (!mSawOutputEOS && !mSignalledError) {
|
||||
/* Queue input data */
|
||||
if (!mSawInputEOS) {
|
||||
int inputBufferId = mCodec.dequeueInputBuffer(kQueueDequeueTimeoutUs);
|
||||
if (inputBufferId < 0 && inputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
|
||||
Log.e(TAG,
|
||||
"MediaCodec.dequeueInputBuffer "
|
||||
+ " returned invalid index : " + inputBufferId);
|
||||
return -1;
|
||||
}
|
||||
mStats.addInputTime();
|
||||
onInputAvailable(inputBufferId, mCodec);
|
||||
}
|
||||
/* Dequeue output data */
|
||||
BufferInfo outputBufferInfo = new BufferInfo();
|
||||
int outputBufferId =
|
||||
mCodec.dequeueOutputBuffer(outputBufferInfo, kQueueDequeueTimeoutUs);
|
||||
if (outputBufferId < 0) {
|
||||
if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
||||
MediaFormat outFormat = mCodec.getOutputFormat();
|
||||
Log.i(TAG, "Output format changed. Format: " + outFormat.toString());
|
||||
} else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
|
||||
Log.i(TAG, "Ignoring deprecated flag: INFO_OUTPUT_BUFFERS_CHANGED");
|
||||
} else if (outputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
|
||||
Log.e(TAG,
|
||||
"MediaCodec.dequeueOutputBuffer"
|
||||
+ " returned invalid index " + outputBufferId);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
mStats.addOutputTime();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Dequeue O/P buffer with BufferID " + outputBufferId);
|
||||
}
|
||||
onOutputAvailable(mCodec, outputBufferId, outputBufferInfo);
|
||||
}
|
||||
if (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
|
||||
Log.i(TAG, "Saw output EOS");
|
||||
}
|
||||
}
|
||||
}
|
||||
mInputBuffer.clear();
|
||||
mInputBufferInfo.clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the codec and releases codec resources.
|
||||
*/
|
||||
public void deInitCodec() {
|
||||
long sTime = mStats.getCurTime();
|
||||
if (mCodec != null) {
|
||||
mCodec.stop();
|
||||
mCodec.release();
|
||||
mCodec = null;
|
||||
}
|
||||
long eTime = mStats.getCurTime();
|
||||
mStats.setDeInitTime(mStats.getTimeDiff(sTime, eTime));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints out the statistics in the information log
|
||||
*
|
||||
* @param inputReference The operation being performed, in this case decode
|
||||
* @param durationUs Duration of the clip in microseconds
|
||||
*/
|
||||
public void dumpStatistics(String inputReference, long durationUs) {
|
||||
String operation = "decode";
|
||||
mStats.dumpStatistics(operation, inputReference, durationUs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the stats
|
||||
*/
|
||||
public void resetDecoder() { mStats.reset(); }
|
||||
|
||||
private void onInputAvailable(int inputBufferId, MediaCodec mediaCodec) {
|
||||
if ((inputBufferId >= 0) && !mSawInputEOS) {
|
||||
ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
|
||||
BufferInfo bufInfo = mInputBufferInfo.get(mIndex);
|
||||
inputCodecBuffer.put(mInputBuffer.get(mIndex).array());
|
||||
mIndex++;
|
||||
if (bufInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
|
||||
mSawInputEOS = true;
|
||||
Log.i(TAG, "Saw input EOS");
|
||||
}
|
||||
mStats.addFrameSize(bufInfo.size);
|
||||
mediaCodec.queueInputBuffer(inputBufferId, bufInfo.offset, bufInfo.size,
|
||||
bufInfo.presentationTimeUs, bufInfo.flags);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG,
|
||||
"Codec Input: "
|
||||
+ "flag = " + bufInfo.flags + " timestamp = "
|
||||
+ bufInfo.presentationTimeUs + " size = " + bufInfo.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onOutputAvailable(
|
||||
MediaCodec mediaCodec, int outputBufferId, BufferInfo outputBufferInfo) {
|
||||
if (mSawOutputEOS || outputBufferId < 0) {
|
||||
return;
|
||||
}
|
||||
mNumOutputFrame++;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG,
|
||||
"In OutputBufferAvailable ,"
|
||||
+ " output frame number = " + mNumOutputFrame);
|
||||
}
|
||||
if (mOutputStream != null) {
|
||||
try {
|
||||
ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferId);
|
||||
byte[] bytesOutput = new byte[outputBuffer.remaining()];
|
||||
outputBuffer.get(bytesOutput);
|
||||
mOutputStream.write(bytesOutput);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Log.d(TAG, "Error Dumping File: Exception " + e.toString());
|
||||
}
|
||||
}
|
||||
mediaCodec.releaseOutputBuffer(outputBufferId, false);
|
||||
mSawOutputEOS = (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
}
|
||||
}
|
Loading…
Reference in new issue