Benchmark: add Extractor

Test: extractorTest  --gtest_repeat=10 -P /sdcard/res/

Bug: 140051680

Change-Id: Ia877298920823337ec791081b40e5c42718a1b65
gugelfrei
Snehal N Bhamare 5 years ago
parent 1b4180698c
commit dc204de26d

@ -0,0 +1,13 @@
BasedOnStyle: Google
Standard: Cpp11
AccessModifierOffset: -2
AllowShortFunctionsOnASingleLine: Inline
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
IncludeBlocks: Preserve
IndentWidth: 4
ContinuationIndentWidth: 8
PointerAlignment: Right
TabWidth: 4
UseTab: Never

@ -0,0 +1,20 @@
/*
* 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.
*/
subdirs = [
"src",
"tests",
]

@ -0,0 +1,30 @@
# Benchmark tests
Run the following steps to build the test suite:
```
mmm frameworks/av/media/tests/benchmark/
```
The binaries will be created in the following path : ${OUT}/data/nativetest64/
adb push $(OUT)/data/nativetest64/* /data/local/tmp/
Eg. adb push $(OUT)/data/nativetest64/extractorTest/extractorTest /data/local/tmp/
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)
## 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 path to these files on the device is required to be given for the test.
```
adb shell /data/local/tmp/extractorTest -P /sdcard/res/
```

@ -20,6 +20,7 @@
#include <utils/Log.h>
#include <media/NdkMediaCodec.h>
#include <media/NdkMediaError.h>
constexpr uint32_t kQueueDequeueTimeoutUs = 1000;
constexpr uint32_t kMaxCSDStrlen = 16;

@ -0,0 +1,29 @@
/*
* 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.
*/
cc_library_static {
name: "libbenchmark_extractor",
defaults: [
"libbenchmark_common-defaults",
"libbenchmark_soft_sanitize_all-defaults",
],
srcs: ["Extractor.cpp"],
export_include_dirs: ["."],
ldflags: ["-Wl,-Bsymbolic"]
}

@ -0,0 +1,133 @@
/*
* 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "extractor"
#include <iostream>
#include "Extractor.h"
int32_t Extractor::initExtractor(int32_t fd, size_t fileSize) {
mTimer = new Timer();
mFrameBuf = (uint8_t *)calloc(kMaxBufferSize, sizeof(uint8_t));
if (!mFrameBuf) return -1;
int64_t sTime = mTimer->getCurTime();
mExtractor = AMediaExtractor_new();
if (!mExtractor) return AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
media_status_t status = AMediaExtractor_setDataSourceFd(mExtractor, fd, 0, fileSize);
if (status != AMEDIA_OK) return status;
int64_t eTime = mTimer->getCurTime();
int64_t timeTaken = mTimer->getTimeDiff(sTime, eTime);
mTimer->setInitTime(timeTaken);
return AMediaExtractor_getTrackCount(mExtractor);
}
void *Extractor::getCSDSample(AMediaCodecBufferInfo &frameInfo, int32_t csdIndex) {
char csdName[kMaxCSDStrlen];
void *csdBuffer = nullptr;
frameInfo.presentationTimeUs = 0;
frameInfo.flags = AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG;
snprintf(csdName, sizeof(csdName), "csd-%d", csdIndex);
size_t size;
bool csdFound = AMediaFormat_getBuffer(mFormat, csdName, &csdBuffer, &size);
if (!csdFound) return nullptr;
frameInfo.size = (int32_t)size;
return csdBuffer;
}
int32_t Extractor::getFrameSample(AMediaCodecBufferInfo &frameInfo) {
int32_t size = AMediaExtractor_readSampleData(mExtractor, mFrameBuf, kMaxBufferSize);
if (size < 0) return -1;
frameInfo.flags = AMediaExtractor_getSampleFlags(mExtractor);
frameInfo.size = size;
frameInfo.presentationTimeUs = AMediaExtractor_getSampleTime(mExtractor);
AMediaExtractor_advance(mExtractor);
return 0;
}
int32_t Extractor::setupTrackFormat(int32_t trackId) {
AMediaExtractor_selectTrack(mExtractor, trackId);
mFormat = AMediaExtractor_getTrackFormat(mExtractor, trackId);
if (!mFormat) return AMEDIA_ERROR_INVALID_OBJECT;
bool durationFound = AMediaFormat_getInt64(mFormat, AMEDIAFORMAT_KEY_DURATION, &mDurationUs);
if (!durationFound) return AMEDIA_ERROR_INVALID_OBJECT;
return AMEDIA_OK;
}
int32_t Extractor::extract(int32_t trackId) {
int32_t status = setupTrackFormat(trackId);
if (status != AMEDIA_OK) return status;
int32_t idx = 0;
AMediaCodecBufferInfo frameInfo;
while (1) {
memset(&frameInfo, 0, sizeof(AMediaCodecBufferInfo));
void *csdBuffer = getCSDSample(frameInfo, idx);
if (!csdBuffer || !frameInfo.size) break;
idx++;
}
mTimer->setStartTime();
while (1) {
int32_t status = getFrameSample(frameInfo);
if (status || !frameInfo.size) break;
mTimer->addOutputTime();
}
if (mFormat) {
AMediaFormat_delete(mFormat);
mFormat = nullptr;
}
AMediaExtractor_unselectTrack(mExtractor, trackId);
return AMEDIA_OK;
}
void Extractor::dumpStatistics(string inputReference) {
string operation = "extract";
mTimer->dumpStatistics(operation, inputReference, mDurationUs);
}
void Extractor::deInitExtractor() {
if (mFrameBuf) {
free(mFrameBuf);
mFrameBuf = nullptr;
}
int64_t sTime = mTimer->getCurTime();
if (mExtractor) {
// TODO: (b/140128505) Multiple calls result in DoS.
// Uncomment call to AMediaExtractor_delete() once this is resolved
// AMediaExtractor_delete(mExtractor);
mExtractor = nullptr;
}
int64_t eTime = mTimer->getCurTime();
int64_t deInitTime = mTimer->getTimeDiff(sTime, eTime);
mTimer->setDeInitTime(deInitTime);
}

@ -0,0 +1,66 @@
/*
* 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.
*/
#ifndef __EXTRACTOR_H__
#define __EXTRACTOR_H__
#include <media/NdkMediaExtractor.h>
#include "BenchmarkCommon.h"
#include "Timer.h"
class Extractor {
public:
Extractor()
: mFormat(nullptr),
mExtractor(nullptr),
mTimer(nullptr),
mFrameBuf{nullptr},
mDurationUs{0} {}
~Extractor() {
if (mTimer) delete mTimer;
}
int32_t initExtractor(int32_t fd, size_t fileSize);
int32_t setupTrackFormat(int32_t trackId);
void *getCSDSample(AMediaCodecBufferInfo &frameInfo, int32_t csdIndex);
int32_t getFrameSample(AMediaCodecBufferInfo &frameInfo);
int32_t extract(int32_t trackId);
void dumpStatistics(std::string inputReference);
void deInitExtractor();
AMediaFormat *getFormat() { return mFormat; }
uint8_t *getFrameBuf() { return mFrameBuf; }
int64_t getClipDuration() { return mDurationUs; }
private:
AMediaFormat *mFormat;
AMediaExtractor *mExtractor;
Timer *mTimer;
uint8_t *mFrameBuf;
int64_t mDurationUs;
};
#endif // __EXTRACTOR_H__

@ -0,0 +1,28 @@
/*
* 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.
*/
cc_test {
name: "extractorTest",
gtest: true,
defaults: [
"libbenchmark_common-defaults",
"libbenchmark_soft_sanitize_all-defaults",
],
srcs: ["ExtractorTest.cpp"],
static_libs: ["libbenchmark_extractor"]
}

@ -0,0 +1,73 @@
/*
* 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.
*/
#ifndef __BENCHMARK_TEST_ENVIRONMENT_H__
#define __BENCHMARK_TEST_ENVIRONMENT_H__
#include <gtest/gtest.h>
#include <getopt.h>
using namespace std;
class BenchmarkTestEnvironment : public ::testing::Environment {
public:
BenchmarkTestEnvironment() : res("/sdcard/media/") {}
// Parses the command line argument
int initFromOptions(int argc, char **argv);
void setRes(const char *_res) { res = _res; }
const string getRes() const { return res; }
private:
string res;
};
int BenchmarkTestEnvironment::initFromOptions(int argc, char **argv) {
static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
while (true) {
int index = 0;
int c = getopt_long(argc, argv, "P:", options, &index);
if (c == -1) {
break;
}
switch (c) {
case 'P': {
setRes(optarg);
break;
}
default:
break;
}
}
if (optind < argc) {
fprintf(stderr,
"unrecognized option: %s\n\n"
"usage: %s <gtest options> <test options>\n\n"
"test options are:\n\n"
"-P, --path: Resource files directory location\n",
argv[optind ?: 1], argv[0]);
return 2;
}
return 0;
}
#endif // __BENCHMARK_TEST_ENVIRONMENT_H__

@ -0,0 +1,94 @@
/*
* 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "extractorTest"
#include <gtest/gtest.h>
#include "Extractor.h"
#include "BenchmarkTestEnvironment.h"
static BenchmarkTestEnvironment *gEnv = nullptr;
class ExtractorTest : public ::testing::TestWithParam<pair<string, int32_t>> {};
TEST_P(ExtractorTest, Extract) {
Extractor *extractObj = new Extractor();
string inputFile = gEnv->getRes() + GetParam().first;
FILE *inputFp = fopen(inputFile.c_str(), "rb");
if (!inputFp) {
cout << "[ WARN ] Test Skipped. Unable to open input file for reading \n";
return;
}
// Read file properties
size_t fileSize = 0;
fseek(inputFp, 0, SEEK_END);
fileSize = ftell(inputFp);
fseek(inputFp, 0, SEEK_SET);
int32_t fd = fileno(inputFp);
int32_t trackCount = extractObj->initExtractor(fd, fileSize);
if (trackCount <= 0) {
cout << "[ WARN ] Test Skipped. initExtractor failed\n";
return;
}
int32_t trackID = GetParam().second;
int32_t status = extractObj->extract(trackID);
if (status != AMEDIA_OK) {
cout << "[ WARN ] Test Skipped. Extraction failed \n";
return;
}
extractObj->deInitExtractor();
extractObj->dumpStatistics(GetParam().first);
fclose(inputFp);
delete extractObj;
}
INSTANTIATE_TEST_SUITE_P(ExtractorTestAll, ExtractorTest,
::testing::Values(make_pair("crowd_1920x1080_25fps_4000kbps_vp9.webm", 0),
make_pair("crowd_1920x1080_25fps_6000kbps_h263.3gp", 0),
make_pair("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", 0),
make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", 0),
make_pair("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", 0),
make_pair("crowd_1920x1080_25fps_4000kbps_av1.webm", 0),
make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", 0),
make_pair("crowd_1920x1080_25fps_4000kbps_vp8.webm", 0),
make_pair("bbb_44100hz_2ch_128kbps_aac_5mins.mp4", 0),
make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 0),
make_pair("bbb_44100hz_2ch_600kbps_flac_5mins.flac", 0),
make_pair("bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", 0),
make_pair("bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", 0),
make_pair("bbb_44100hz_2ch_80kbps_vorbis_5mins.mp4", 0),
make_pair("bbb_48000hz_2ch_100kbps_opus_5mins.webm", 0)));
int main(int argc, char **argv) {
gEnv = new BenchmarkTestEnvironment();
::testing::AddGlobalTestEnvironment(gEnv);
::testing::InitGoogleTest(&argc, argv);
int status = gEnv->initFromOptions(argc, argv);
if (status == 0) {
status = RUN_ALL_TESTS();
ALOGD(" Extractor Test result = %d\n", status);
}
return status;
}
Loading…
Cancel
Save