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

Commit 0677f5b8 authored by Ray Essick's avatar Ray Essick Committed by Automerger Merge Worker
Browse files

Merge "SampleVideoEncoder: Add SurfaceEncoder Test" am: fae8c085

Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/1575044

Change-Id: Ida8384c412c0b7ac40f81d46f0b36cf7b134137b
parents 60d845e9 fae8c085
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@

This is a sample android application for encoding AVC/HEVC streams with B-Frames enabled. It uses MediaRecorder APIs to record B-frames enabled video from camera2 input and MediaCodec APIs to encode reference test vector using input surface.

This page describes how to get started with the Encoder App.
This page describes how to get started with the Encoder App and how to run the tests for it.


# Getting Started
@@ -33,6 +33,17 @@ adb shell am start -n "com.android.media.samplevideoencoder/com.android.media.sa

After installing the app, a TextureView showing camera preview is dispalyed on one third of the screen. It also features checkboxes to select either avc/hevc and hw/sw codecs. It also has an option to select either MediaRecorder APIs or MediaCodec, along with the 'Start' button to start/stop recording.

# Running Tests

The app also contains a test, which will test the MediaCodec APIs for encoding avc/hevc streams with B-frames enabled. This does not require us to use application UI.

## Running the tests using atest
Note that atest command will install the SampleVideoEncoder app on the device.

Command to run the tests:
```
atest SampleVideoEncoder
```

# Ouput

@@ -40,3 +51,6 @@ The muxed ouptput video is saved in the app data at:
```
/storage/emulated/0/Android/data/com.android.media.samplevideoencoder/files/
```

The total number of I-frames, P-frames and B-frames after encoding has been done using MediaCodec APIs are displayed on the screen.
The results of the tests can be obtained from the logcats of the test.
+5 −1
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ package {
    default_applicable_licenses: ["frameworks_av_license"],
}

android_app {
android_test {
    name: "SampleVideoEncoder",

    manifest: "src/main/AndroidManifest.xml",
@@ -41,6 +41,10 @@ android_app {
        "androidx.annotation_annotation",
        "androidx.appcompat_appcompat",
        "androidx-constraintlayout_constraintlayout",
        "junit",
        "androidx.test.core",
        "androidx.test.runner",
        "hamcrest-library",
    ],

    javacflags: [
+28 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 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.
-->
<configuration description="Runs SampleVideoEncoder Tests">
    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
        <option name="cleanup-apks" value="false" />
        <option name="test-file-name" value="SampleVideoEncoder.apk" />
    </target_preparer>

    <option name="test-tag" value="SampleVideoEncoder" />
    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
        <option name="package" value="com.android.media.samplevideoencoder" />
        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
        <option name="hidden-api-checks" value="false"/>
    </test>
</configuration>
+93 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.samplevideoencoder.tests;

import androidx.test.platform.app.InstrumentationRegistry;

import android.content.Context;
import android.media.MediaFormat;
import android.util.Log;

import com.android.media.samplevideoencoder.MediaCodecSurfaceEncoder;
import com.android.media.samplevideoencoder.R;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;

@RunWith(Parameterized.class)
public class SampleVideoEncoderTest {
    private static final String TAG = SampleVideoEncoderTest.class.getSimpleName();
    private final Context mContext;
    private int mMaxBFrames;
    private int mInputResId;
    private String mMime;
    private boolean mIsSoftwareEncoder;

    @Parameterized.Parameters
    public static Collection<Object[]> inputFiles() {
        return Arrays.asList(new Object[][]{
                // Parameters: MimeType, isSoftwareEncoder, maxBFrames
                {MediaFormat.MIMETYPE_VIDEO_AVC, false, 1},
                {MediaFormat.MIMETYPE_VIDEO_AVC, true, 1},
                {MediaFormat.MIMETYPE_VIDEO_HEVC, false, 1},
                {MediaFormat.MIMETYPE_VIDEO_HEVC, true, 1}});
    }

    public SampleVideoEncoderTest(String mimeType, boolean isSoftwareEncoder, int maxBFrames) {
        this.mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
        this.mInputResId = R.raw.crowd_1920x1080_25fps_4000kbps_h265;
        this.mMime = mimeType;
        this.mIsSoftwareEncoder = isSoftwareEncoder;
        this.mMaxBFrames = maxBFrames;
    }

    private String getOutputPath() {
        File dir = mContext.getExternalFilesDir(null);
        if (dir == null) {
            Log.e(TAG, "Cannot get external directory path to save output video");
            return null;
        }
        String videoPath = dir.getAbsolutePath() + "/Video-" + System.currentTimeMillis() + ".mp4";
        Log.i(TAG, "Output video is saved at: " + videoPath);
        return videoPath;
    }

    @Test
    public void testMediaSurfaceEncoder() throws IOException, InterruptedException {
        String outputFilePath = getOutputPath();
        MediaCodecSurfaceEncoder surfaceEncoder =
                new MediaCodecSurfaceEncoder(mContext, mInputResId, mMime, mIsSoftwareEncoder,
                        outputFilePath, mMaxBFrames);
        int encodingStatus = surfaceEncoder.startEncodingSurface();
        assertThat(encodingStatus, is(equalTo(0)));
        int[] frameNumArray = surfaceEncoder.getFrameTypes();
        Log.i(TAG, "Results: I-Frames: " + frameNumArray[0] + "; P-Frames: " + frameNumArray[1] +
                "\n " + "; B-Frames:" + frameNumArray[2]);
        assertNotEquals("Encoder mime: " + mMime + " isSoftware: " + mIsSoftwareEncoder +
                " failed to generate B Frames", frameNumArray[2], 0);
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -38,4 +38,8 @@
        </activity>
    </application>

    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
        android:targetPackage="com.android.media.samplevideoencoder"
        android:label="SampleVideoEncoder Test"/>

</manifest>
 No newline at end of file