Merge "Benchmark: Add SDK Extractor" am: 200b3291b4 am: 995d433aa4 am: 37d27065a0

am: bd2e267483

Change-Id: I89ce2e7aec4cc24c7f5791cef704b529ad7be574
gugelfrei
Ray Essick 5 years ago committed by android-build-merger
commit 5350f16479

@ -17,4 +17,5 @@
subdirs = [
"src",
"tests",
]
"MediaBenchmarkTest",
]

@ -0,0 +1,46 @@
/*
* 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.
*/
android_test {
name: "MediaBenchmarkTest",
// Include all the test code
srcs: ["src/androidTest/**/*.java"],
sdk_version: "system_current",
resource_dirs: ["res"],
libs: [
"android.test.runner",
"android.test.base",
],
static_libs: [
"libMediaBenchmark",
"junit",
"androidx.test.runner",
],
}
android_library {
name: "libMediaBenchmark",
// Include all the libraries
srcs: ["src/main/**/*.java"],
sdk_version: "system_current",
}

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
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"
tools:remove="android:appComponentFactory">
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.media.benchmark"
android:label="Benchmark Media Test"/>
</manifest>

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 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 Media Benchmark Tests">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="MediaBenchmarkTest.apk" />
</target_preparer>
<option name="test-tag" value="MediaBenchmarkTest" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.media.benchmark" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>

@ -0,0 +1,64 @@
/*
* 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.
*/
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
}
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
defaultConfig {
applicationId "com.android.media.benchmark"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
sourceSets {
main {
java.srcDirs 'src/main/java'
res.srcDirs 'res'
manifest.srcFile 'AndroidManifest.xml'
}
androidTest {
java.srcDirs 'src/androidTest/java'
res.srcDirs 'res'
manifest.srcFile 'AndroidManifest.xml'
}
}
}
repositories {
google()
jcenter()
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
}

@ -0,0 +1,3 @@
<resources>
<string name="input_file_path">/data/local/tmp/MediaBenchmark/res/</string>
</resources>

@ -0,0 +1,92 @@
/*
* 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 com.android.media.benchmark.R;
import com.android.media.benchmark.library.Extractor;
import android.content.Context;
import android.util.Log;
import androidx.test.platform.app.InstrumentationRegistry;
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.IOException;
import java.util.Arrays;
import java.util.Collection;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@RunWith(Parameterized.class)
public class ExtractorTest {
private static Context mContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
private static final String TAG = "ExtractorTest";
private String mInputFileName;
private int mTrackId;
@Parameterized.Parameters
public static Collection<Object[]> inputFiles() {
return Arrays.asList(new Object[][]{/* Parameters: filename, trackId*/
{"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", 0},
{"crowd_1920x1080_25fps_6700kbps_h264.ts", 0},
{"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", 0},
{"crowd_1920x1080_25fps_4000kbps_av1.webm", 0},
{"crowd_1920x1080_25fps_4000kbps_h265.mkv", 0},
{"crowd_1920x1080_25fps_4000kbps_vp8.webm", 0},
{"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", 0},
{"bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 0},
{"bbb_44100hz_2ch_600kbps_flac_5mins.flac", 0},
{"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", 0},
{"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", 0},
{"bbb_44100hz_2ch_80kbps_vorbis_5mins.mp4", 0},
{"bbb_48000hz_2ch_100kbps_opus_5mins.webm", 0}});
}
public ExtractorTest(String filename, int track) {
this.mInputFileName = filename;
this.mTrackId = track;
}
@Test
public void sampleExtractTest() throws IOException {
int status = -1;
File inputFile = new File(mInputFilePath + mInputFileName);
if (inputFile.exists()) {
FileInputStream fileInput = new FileInputStream(inputFile);
FileDescriptor fileDescriptor = fileInput.getFD();
Extractor extractor = new Extractor();
extractor.setUpExtractor(fileDescriptor);
status = extractor.extractSample(mTrackId);
extractor.deinitExtractor();
extractor.dumpStatistics(mInputFileName);
fileInput.close();
} else {
Log.e(TAG, "Cannot find " + mInputFileName + " in directory " + mInputFilePath);
}
assertThat(status, is(equalTo(0)));
}
}

@ -0,0 +1,175 @@
/*
* 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.MediaExtractor;
import android.media.MediaFormat;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.IOException;
import java.nio.ByteBuffer;
public class Extractor {
private static final String TAG = "Extractor";
private static final int kMaxBufSize = 1024 * 1024 * 16;
private MediaExtractor mExtractor;
private ByteBuffer mFrameBuffer;
private MediaCodec.BufferInfo mBufferInfo;
private Stats mStats;
private long mDurationUs;
public Extractor() {
mFrameBuffer = ByteBuffer.allocate(kMaxBufSize);
mBufferInfo = new MediaCodec.BufferInfo();
mStats = new Stats();
}
/**
* Creates a Media Extractor and sets data source(FileDescriptor)to use
*
* @param fileDescriptor FileDescriptor for the file which is to be extracted
* @return TrackCount of the sample
* @throws IOException If FileDescriptor is null
*/
public int setUpExtractor(FileDescriptor fileDescriptor) throws IOException {
long sTime = mStats.getCurTime();
mExtractor = new MediaExtractor();
mExtractor.setDataSource(fileDescriptor);
long eTime = mStats.getCurTime();
long timeTaken = mStats.getTimeDiff(sTime, eTime);
mStats.setInitTime(timeTaken);
return mExtractor.getTrackCount();
}
/**
* Returns the track format of the specified index
*
* @param trackID Index of the track
* @return Format of the track
*/
public MediaFormat getFormat(int trackID) { return mExtractor.getTrackFormat(trackID); }
/**
* Returns the extracted buffer for the input clip
*/
public ByteBuffer getFrameBuffer() { return this.mFrameBuffer; }
/**
* Returns the information of buffer related to sample
*/
public MediaCodec.BufferInfo getBufferInfo() { return this.mBufferInfo; }
/**
* Returns the duration of the sample
*/
public long getClipDuration() { return this.mDurationUs; }
/**
* Retrieve the current sample and store it in the byte buffer
* Also, sets the information related to extracted sample and store it in buffer info
*
* @return Sample size of the extracted sample
*/
public int getFrameSample() {
int sampleSize = mExtractor.readSampleData(mFrameBuffer, 0);
if (sampleSize < 0) {
mBufferInfo.flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
mBufferInfo.size = 0;
} else {
mBufferInfo.size = sampleSize;
mBufferInfo.offset = 0;
mBufferInfo.flags = mExtractor.getSampleFlags();
mBufferInfo.presentationTimeUs = mExtractor.getSampleTime();
mExtractor.advance();
}
return sampleSize;
}
/**
* Setup the track format and get the duration of the sample
* Track is selected here for extraction
*
* @param trackId Track index to be selected
* @return 0 for valid track, otherwise -1
*/
public int selectExtractorTrack(int trackId) {
MediaFormat trackFormat = mExtractor.getTrackFormat(trackId);
mDurationUs = trackFormat.getLong(MediaFormat.KEY_DURATION);
if (mDurationUs < 0) {
Log.e(TAG, "Invalid Clip");
return -1;
}
mExtractor.selectTrack(trackId);
return 0;
}
/**
* Unselect the track
*
* @param trackId Track Index to be unselected
*/
public void unselectExtractorTrack(int trackId) { mExtractor.unselectTrack(trackId); }
/**
* Free up the resources
*/
public void deinitExtractor() {
long sTime = mStats.getCurTime();
mExtractor.release();
long eTime = mStats.getCurTime();
long timeTaken = mStats.getTimeDiff(sTime, eTime);
mStats.setDeInitTime(timeTaken);
}
/**
* Performs extract operation
*
* @param currentTrack Track index to be extracted
* @return Status as 0 if extraction is successful, -1 otherwise
*/
public int extractSample(int currentTrack) {
int status;
status = selectExtractorTrack(currentTrack);
if (status == -1) {
Log.e(TAG, "Failed to select track");
return -1;
}
mStats.setStartTime();
while (true) {
int readSampleSize = getFrameSample();
if (readSampleSize <= 0) {
break;
}
mStats.addOutputTime();
mStats.addFrameSize(readSampleSize);
}
unselectExtractorTrack(currentTrack);
return 0;
}
/**
* Write the benchmark logs for the given input file
*
* @param inputReference Name of the input file
*/
public void dumpStatistics(String inputReference) {
String operation = "extract";
mStats.dumpStatistics(operation, inputReference, mDurationUs);
}
}

@ -0,0 +1,138 @@
/*
* 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.util.Log;
import java.util.ArrayList;
/**
* Measures Performance.
*/
public class Stats {
private static final String TAG = "Stats";
private long mInitTimeNs;
private long mDeInitTimeNs;
private long mStartTimeNs;
private ArrayList<Integer> mFrameSizes;
private ArrayList<Long> mInputTimer;
private ArrayList<Long> mOutputTimer;
public Stats() {
mFrameSizes = new ArrayList<>();
mInputTimer = new ArrayList<>();
mOutputTimer = new ArrayList<>();
mInitTimeNs = 0;
mDeInitTimeNs = 0;
}
public long getCurTime() { return System.nanoTime(); }
public void setInitTime(long initTime) { mInitTimeNs = initTime; }
public void setDeInitTime(long deInitTime) { mDeInitTimeNs = deInitTime; }
public void setStartTime() { mStartTimeNs = System.nanoTime(); }
public void addFrameSize(int size) { mFrameSizes.add(size); }
public void addInputTime() { mInputTimer.add(System.nanoTime()); }
public void addOutputTime() { mOutputTimer.add(System.nanoTime()); }
public void reset() {
if (mFrameSizes.size() != 0) {
mFrameSizes.clear();
}
if (mInputTimer.size() != 0) {
mInputTimer.clear();
}
if (mOutputTimer.size() != 0) {
mOutputTimer.clear();
}
}
public long getInitTime() { return mInitTimeNs; }
public long getDeInitTime() { return mDeInitTimeNs; }
public long getTimeDiff(long sTime, long eTime) { return (eTime - sTime); }
private long getTotalTime() {
if (mOutputTimer.size() == 0) {
return -1;
}
long lastTime = mOutputTimer.get(mOutputTimer.size() - 1);
return lastTime - mStartTimeNs;
}
private long getTotalSize() {
long totalSize = 0;
for (long size : mFrameSizes) {
totalSize += size;
}
return totalSize;
}
/**
* Dumps the stats of the operation for a given input media.
* <p>
* \param operation describes the operation performed on the input media
* (i.e. extract/mux/decode/encode)
* \param inputReference input media
* \param durationUs is a duration of the input media in microseconds.
*/
public void dumpStatistics(String operation, String inputReference, long durationUs) {
if (mOutputTimer.size() == 0) {
Log.e(TAG, "No output produced");
return;
}
long totalTimeTakenNs = getTotalTime();
long timeTakenPerSec = (totalTimeTakenNs * 1000000) / durationUs;
long timeToFirstFrameNs = mOutputTimer.get(0) - mStartTimeNs;
long size = getTotalSize();
// get min and max output intervals.
long intervalNs;
long minTimeTakenNs = Long.MAX_VALUE;
long maxTimeTakenNs = 0;
long prevIntervalNs = mStartTimeNs;
for (int idx = 0; idx < mOutputTimer.size() - 1; idx++) {
intervalNs = mOutputTimer.get(idx) - prevIntervalNs;
prevIntervalNs = mOutputTimer.get(idx);
if (minTimeTakenNs > intervalNs) {
minTimeTakenNs = intervalNs;
} else if (maxTimeTakenNs < intervalNs) {
maxTimeTakenNs = intervalNs;
}
}
// Print the Stats
Log.i(TAG, "Input Reference : " + inputReference);
Log.i(TAG, "Setup Time in nano sec : " + mInitTimeNs);
Log.i(TAG, "Average Time in nano sec : " + totalTimeTakenNs / mOutputTimer.size());
Log.i(TAG, "Time to first frame in nano sec : " + timeToFirstFrameNs);
Log.i(TAG, "Time taken (in nano sec) to " + operation + " 1 sec of content : " +
timeTakenPerSec);
Log.i(TAG, "Total bytes " + operation + "ed : " + size);
Log.i(TAG, "Number of bytes " + operation + "ed per second : " +
(size * 1000000000) / totalTimeTakenNs);
Log.i(TAG, "Minimum Time in nano sec : " + minTimeTakenNs);
Log.i(TAG, "Maximum Time in nano sec : " + maxTimeTakenNs);
Log.i(TAG, "Destroy Time in nano sec : " + mDeInitTimeNs);
}
}

@ -1,9 +1,16 @@
# Benchmark tests
Benchmark app analyses the time taken by MediaCodec, MediaExtractor and MediaMuxer for given set of inputs. It is used to benchmark these modules on android devices.
Benchmark results are emitted to logcat.
This page describes steps to run the NDK and SDK layer test.
Run the following steps to build the test suite:
```
mmm frameworks/av/media/tests/benchmark/
```
To run the test suite for measuring performance of the native layer, follow the following steps:
# NDK
The binaries will be created in the following path : ${OUT}/data/nativetest64/
@ -13,20 +20,25 @@ Eg. adb push $(OUT)/data/nativetest64/extractorTest/extractorTest /data/local/tm
To run the binary, follow the commands mentioned below under each module.
The resource files for the tests are taken from [here](https://drive.google.com/open?id=1ghMr17BBJ7n0pqbm7oREiTN_MNemJUqy)
The resource file for the tests is taken from [here](https://drive.google.com/open?id=1ghMr17BBJ7n0pqbm7oREiTN_MNemJUqy)
Download the MediaBenchmark.zip file, unzip and push it to /data/local/tmp/ on the device.
```
unzip MediaBenchmark.zip
adb push MediaBenchmark /data/local/tmp
```
## Extractor
The test extracts elementary stream and benchmarks the extractors available in NDK.
Push the resource files to /sdcard/res on the device.
You can use a different location, but you have to modify the rest of the instructions to replace /sdcard/res with wherever you chose to put the files.
The resource files are assumed to be at /data/local/tmp/MediaBenchmark/res/. You can use a different location, but you have to modify the rest of the instructions to replace /data/local/tmp/MediaBenchmark/res/ with wherever you chose to put the files.
The path to these files on the device is required to be given for the test.
```
adb shell /data/local/tmp/extractorTest -P /sdcard/res/
adb shell /data/local/tmp/extractorTest -P /data/local/tmp/MediaBenchmark/res/
```
## Decoder
@ -36,7 +48,7 @@ The test decodes input stream and benchmarks the decoders available in NDK.
Setup steps are same as extractor.
```
adb shell /data/local/tmp/decoderTest -P /sdcard/res/
adb shell /data/local/tmp/decoderTest -P /data/local/tmp/MediaBenchmark/res/
```
## Muxer
@ -46,7 +58,7 @@ The test muxes elementary stream and benchmarks the muxers available in NDK.
Setup steps are same as extractor.
```
adb shell /data/local/tmp/muxerTest -P /sdcard/res/
adb shell /data/local/tmp/muxerTest -P /data/local/tmp/MediaBenchmark/res/
```
## Encoder
@ -56,5 +68,31 @@ The test encodes input stream and benchmarks the encoders available in NDK.
Setup steps are same as extractor.
```
adb shell /data/local/tmp/encoderTest -P /sdcard/res/
adb shell /data/local/tmp/encoderTest -P /data/local/tmp/MediaBenchmark/res/
```
# SDK
To run the test suite for measuring performance of the SDK APIs, follow the following steps:
The apk will be created at the following path:
${OUT}/testcases/MediaBenchmarkApp/arm64/
To get the resorce files for the test follow instructions given in [NDK](#NDK)
For installing the apk, run the command:
```
adb install -f -r ${OUT}/testcases/MediaBenchmarkApp/arm64/MediaBenchmarkApp.apk
```
For running all the tests, run the command:
```
adb shell am instrument -w -r -e package com.android.media.benchmark.tests com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
```
## Extractor
The test extracts elementary stream and benchmarks the extractors available in SDK.
```
adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.ExtractorTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
```

Loading…
Cancel
Save