Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f25d4b2 authored by Arun Johnson's avatar Arun Johnson
Browse files

Updates to Media benchmark library

 - Add FrameReleaseQueue to MediaBenchmark
 - Encode use case with surfaces/bytebuffers
 - added more utilites functions to CodecUtils

Bug: 242731464
Change-Id: I921337a17e8f4dcaf541bcc8d9323640ceeb9ed1
parent 35ea409b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -69,6 +69,6 @@ android_library {
java_defaults {
    name: "MediaBenchmark-defaults",

    min_sdk_version: "28",
    min_sdk_version: "29",
    target_sdk_version: "30",
}
+1 −3
Original line number Diff line number Diff line
@@ -20,8 +20,6 @@
    package="com.android.media.benchmark">
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />

    <application
        tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon"
+2 −2
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ android {
    compileSdkVersion 30
    defaultConfig {
        applicationId "com.android.media.benchmark"
        minSdkVersion 28
        minSdkVersion 29
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
+43 −2
Original line number Diff line number Diff line
@@ -2,13 +2,12 @@ package com.android.media.benchmark.library;

import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.os.Build;

import java.util.ArrayList;

public class CodecUtils {
    private CodecUtils() {}

    /**
     * Queries the MediaCodecList and returns codec names of supported codecs.
     *
@@ -36,4 +35,46 @@ public class CodecUtils {
        }
        return supportedCodecs;
    }
    /**
     * Returns a decoder that supports the given MediaFormat along with the "features".
     *
     * @param format  MediaFormat that the codec should support
     * @param isSoftware Specifies if this is a software / hardware decoder
     * @param isEncoder Specifies if the request is for encoders or not.
     * @param features is the feature that should be supported.
     * @return name of the codec.
     */
    public static String getMediaCodec(MediaFormat format, boolean isSoftware,
                                  String[] features, boolean isEncoder) {
        MediaCodecList mcl = new MediaCodecList(MediaCodecList.ALL_CODECS);
        MediaCodecInfo[] codecInfos = mcl.getCodecInfos();
        String mime = format.getString(MediaFormat.KEY_MIME);
        for (MediaCodecInfo codecInfo : codecInfos) {
            if (codecInfo.isEncoder() != isEncoder) continue;
            if (isSoftware != codecInfo.isSoftwareOnly()) continue;
            String[] types = codecInfo.getSupportedTypes();
            for (String type : types) {
                if (type.equalsIgnoreCase(mime)) {
                    boolean isOk = true;
                    MediaCodecInfo.CodecCapabilities codecCapabilities =
                        codecInfo.getCapabilitiesForType(type);
                    if (!codecCapabilities.isFormatSupported(format)) {
                        isOk = false;
                    }
                    if (features != null) {
                        for (String feature : features) {
                            if (!codecCapabilities.isFeatureSupported(feature)) {
                                isOk = false;
                                break;
                            }
                        }
                    }
                    if (isOk) {
                        return codecInfo.getName();
                    }
                }
            }
        }
        return null;
    }
}
+70 −9
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.media.benchmark.library;

import android.view.Surface;

import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaFormat;
@@ -28,13 +30,17 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;

public class Decoder {
import com.android.media.benchmark.library.IBufferXfer;

public class Decoder implements IBufferXfer.IReceiveBuffer {
    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 Surface mSurface = null;
    private boolean mRender = false;
    private ArrayList<BufferInfo> mInputBufferInfo;
    private Stats mStats;

@@ -47,9 +53,29 @@ public class Decoder {

    private ArrayList<ByteBuffer> mInputBuffer;
    private FileOutputStream mOutputStream;
    private FrameReleaseQueue mFrameReleaseQueue = null;
    private IBufferXfer.ISendBuffer mIBufferSend = null;

    /* success for decoder */
    public static final int DECODE_SUCCESS = 0;
    /* some error happened during decoding */
    public static final int DECODE_DECODER_ERROR = -1;
    /* error while creating a decoder */
    public static final int DECODE_CREATE_ERROR = -2;
    public Decoder() { mStats = new Stats(); }
    public Stats getStats() { return mStats; };
    @Override
    public boolean receiveBuffer(IBufferXfer.BufferXferInfo info) {
        MediaCodec codec = (MediaCodec)info.obj;
        codec.releaseOutputBuffer(info.idx, mRender);
        return true;
    }
    @Override
    public boolean connect(IBufferXfer.ISendBuffer receiver) {
        Log.d(TAG,"Setting interface of the sender");
        mIBufferSend = receiver;
        return true;
    }
    /**
     * Setup of decoder
     *
@@ -59,6 +85,17 @@ public class Decoder {
        mSignalledError = false;
        mOutputStream = outputStream;
    }
    public void setupDecoder(Surface surface, boolean render,
            boolean useFrameReleaseQueue, int frameRate) {
        mSignalledError = false;
        mOutputStream = null;
        mSurface = surface;
        mRender = render;
        if (useFrameReleaseQueue) {
            Log.i(TAG, "Using FrameReleaseQueue with frameRate " + frameRate);
            mFrameReleaseQueue = new FrameReleaseQueue(mRender, frameRate);
        }
    }

    private MediaCodec createCodec(String codecName, MediaFormat format) throws IOException {
        String mime = format.getString(MediaFormat.KEY_MIME);
@@ -95,7 +132,8 @@ public class Decoder {
     * @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
     * @return DECODE_SUCCESS if decode was successful, DECODE_DECODER_ERROR for fail,
     *         DECODE_CREATE_ERROR for decoder not created
     * @throws IOException if the codec cannot be created.
     */
    public int decode(@NonNull ArrayList<ByteBuffer> inputBuffer,
@@ -112,7 +150,10 @@ public class Decoder {
        long sTime = mStats.getCurTime();
        mCodec = createCodec(codecName, format);
        if (mCodec == null) {
            return -2;
            return DECODE_CREATE_ERROR;
        }
        if (mFrameReleaseQueue != null) {
            mFrameReleaseQueue.setMediaCodec(mCodec);
        }
        if (asyncMode) {
            mCodec.setCallback(new MediaCodec.Callback() {
@@ -158,7 +199,7 @@ public class Decoder {
        if (DEBUG) {
            Log.d(TAG, "Media Format : " + format.toString());
        }
        mCodec.configure(format, null, null, isEncoder);
        mCodec.configure(format, mSurface, null, isEncoder);
        mCodec.start();
        Log.i(TAG, "Codec started ");
        long eTime = mStats.getCurTime();
@@ -168,7 +209,7 @@ public class Decoder {
            try {
                synchronized (mLock) { mLock.wait(); }
                if (mSignalledError) {
                    return -1;
                    return DECODE_DECODER_ERROR;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
@@ -201,7 +242,7 @@ public class Decoder {
                        Log.e(TAG,
                                "MediaCodec.dequeueOutputBuffer"
                                        + " returned invalid index " + outputBufferId);
                        return -1;
                        return DECODE_DECODER_ERROR;
                    }
                } else {
                    mStats.addOutputTime();
@@ -212,9 +253,13 @@ public class Decoder {
                }
            }
        }
        if (mFrameReleaseQueue != null) {
            Log.i(TAG, "Ending FrameReleaseQueue");
            mFrameReleaseQueue.stopFrameRelease();
        }
        mInputBuffer.clear();
        mInputBufferInfo.clear();
        return 0;
        return DECODE_SUCCESS;
    }

    /**
@@ -290,7 +335,9 @@ public class Decoder {
        if (DEBUG) {
            Log.d(TAG,
                    "In OutputBufferAvailable ,"
                            + " output frame number = " + mNumOutputFrame);
                            + " output frame number = " + mNumOutputFrame
                            + " timestamp = " + outputBufferInfo.presentationTimeUs
                            + " size = " + outputBufferInfo.size);
        }
        if (mOutputStream != null) {
            try {
@@ -303,7 +350,21 @@ public class Decoder {
                Log.d(TAG, "Error Dumping File: Exception " + e.toString());
            }
        }
        mediaCodec.releaseOutputBuffer(outputBufferId, false);
        if (mFrameReleaseQueue != null) {
            mFrameReleaseQueue.pushFrame(mNumOutputFrame, outputBufferId,
                                            outputBufferInfo.presentationTimeUs);
        } else if (mIBufferSend != null) {
            IBufferXfer.BufferXferInfo info = new IBufferXfer.BufferXferInfo();
            info.buf = mediaCodec.getOutputBuffer(outputBufferId);
            info.idx = outputBufferId;
            info.obj = mediaCodec;
            info.bytesRead = outputBufferInfo.size;
            info.presentationTimeUs = outputBufferInfo.presentationTimeUs;
            info.flag = outputBufferInfo.flags;
            mIBufferSend.sendBuffer(this, info);
        } else {
            mediaCodec.releaseOutputBuffer(outputBufferId, mRender);
        }
        mSawOutputEOS = (outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
        if (mSawOutputEOS) {
            Log.i(TAG, "Saw output EOS");
Loading