Merge "MediaTesting: Add FLAC Decoder Test" am: 09644d9b27 am: dbf34ddad2 am: 2d486a399f

Change-Id: Ibadc8d6128f7ee90f37e888cc0f2d82f491fd048
gugelfrei
Automerger Merge Worker 4 years ago
commit 961f172f9e

@ -0,0 +1,50 @@
/*
* 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: "FlacDecoderTest",
gtest: true,
srcs: [
"FlacDecoderTest.cpp",
],
shared_libs: [
"liblog",
],
static_libs: [
"libstagefright_flacdec",
"libFLAC",
],
header_libs: [
"libstagefright_foundation_headers",
],
cflags: [
"-Werror",
"-Wall",
],
sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
"signed-integer-overflow",
],
cfi: true,
},
}

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 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="Test module config for flac decoder unit tests">
<option name="test-suite-tag" value="FlacDecoderTest" />
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push" value="FlacDecoderTest->/data/local/tmp/FlacDecoderTest/" />
<option name="push-file"
key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/flac/dec/test/FlacDecoder.zip?unzip=true"
value="/data/local/tmp/FlacDecoderTestRes/" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="FlacDecoderTest" />
<option name="native-test-flag" value="-P /data/local/tmp/FlacDecoderTestRes/" />
</test>
</configuration>

@ -0,0 +1,270 @@
/*
* 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 "FlacDecoderTest"
#include <utils/Log.h>
#include <fstream>
#include "FLACDecoder.h"
#include "FlacDecoderTestEnvironment.h"
#define OUTPUT_FILE_NAME "/data/local/tmp/FlacDecoderOutput.raw"
#define CODEC_CONFIG_FLAG 32
constexpr uint32_t kMaxCount = 10;
constexpr int32_t kMaxBlockSize = 4096;
using namespace android;
struct FrameInfo {
int32_t bytesCount;
uint32_t flags;
int64_t timestamp;
};
static FlacDecoderTestEnvironment *gEnv = nullptr;
class FLACDecoderTest : public ::testing::TestWithParam<tuple<string, string, bool>> {
public:
FLACDecoderTest() : mFLACDecoder(nullptr), mHasStreamInfo(false), mInputBufferCount(0) {}
~FLACDecoderTest() {
if (mEleStream.is_open()) mEleStream.close();
if (mFLACDecoder) delete mFLACDecoder;
mFLACDecoder = nullptr;
}
virtual void SetUp() override {
mFLACDecoder = FLACDecoder::Create();
ASSERT_NE(mFLACDecoder, nullptr) << "initDecoder: failed to create FLACDecoder";
}
int32_t processFlacDecoder(vector<FrameInfo> Info, int32_t offset, int32_t range,
bool outputFloat, ofstream &ostrm);
FLACDecoder *mFLACDecoder;
FLAC__StreamMetadata_StreamInfo mStreamInfo;
bool mHasStreamInfo;
int32_t mInputBufferCount;
ifstream mEleStream;
};
void getInfo(string infoFileName, vector<FrameInfo> &Info) {
ifstream eleInfo;
eleInfo.open(infoFileName);
ASSERT_EQ(eleInfo.is_open(), true);
int32_t bytesCount = 0;
uint32_t flags = 0;
uint32_t timestamp = 0;
while (1) {
if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags;
eleInfo >> timestamp;
Info.push_back({bytesCount, flags, timestamp});
}
if (eleInfo.is_open()) eleInfo.close();
}
int32_t FLACDecoderTest::processFlacDecoder(vector<FrameInfo> Info, int32_t offset, int32_t range,
bool outputFloat, ofstream &ostrm) {
memset(&mStreamInfo, 0, sizeof(mStreamInfo));
int32_t frameID = offset;
if (range + offset > Info.size() || range < 0 || offset > Info.size() - 1 || offset < 0) {
ALOGE("Invalid offset or range or both passed for decoding");
ALOGE("offset = %d \t range = %d \t Info.size() = %zu", offset, range, Info.size());
return -1;
}
while (1) {
if (frameID == Info.size() || frameID == (offset + range)) break;
int64_t flags = (Info)[frameID].flags;
int32_t size = (Info)[frameID].bytesCount;
if (size < 0) {
ALOGE("Size for the memory allocation is negative");
return -1;
}
char *data = (char *)malloc(size);
if (!data) {
ALOGE("Insufficient memory to read frame");
return -1;
}
mEleStream.read(data, size);
if (mEleStream.gcount() != size) {
if (data) {
free(data);
data = nullptr;
}
ALOGE("Invalid size read, requested: %d and read: %zu", size, mEleStream.gcount());
return -1;
}
if (flags == CODEC_CONFIG_FLAG && mInputBufferCount == 0) {
status_t decoderErr = mFLACDecoder->parseMetadata((uint8_t *)data, size);
if (decoderErr == WOULD_BLOCK) {
ALOGV("process: parseMetadata is Blocking, Continue %d", decoderErr);
} else if (decoderErr == OK) {
mStreamInfo = mFLACDecoder->getStreamInfo();
if (mStreamInfo.sample_rate && mStreamInfo.max_blocksize && mStreamInfo.channels) {
mHasStreamInfo = true;
}
ALOGV("decoder configuration : %d Hz, %d channels, %d samples,"
" %d block size",
mStreamInfo.sample_rate, mStreamInfo.channels,
(int32_t)mStreamInfo.total_samples, mStreamInfo.max_blocksize);
} else {
ALOGE("FLACDecoder parseMetaData returns error %d", decoderErr);
if (data) {
free(data);
data = nullptr;
}
return decoderErr;
}
} else {
const size_t sampleSize = outputFloat ? sizeof(float) : sizeof(int16_t);
size_t outSize = mHasStreamInfo
? mStreamInfo.max_blocksize * mStreamInfo.channels * sampleSize
: kMaxBlockSize * FLACDecoder::kMaxChannels * sampleSize;
void *out_buf = malloc(outSize);
if (!out_buf) {
if (data) {
free(data);
data = nullptr;
}
ALOGE("Output buffer allocation failed");
return -1;
}
status_t decoderErr = mFLACDecoder->decodeOneFrame((uint8_t *)data, size, out_buf,
&outSize, outputFloat);
if (decoderErr != OK) {
ALOGE("decodeOneFrame returns error %d", decoderErr);
if (data) {
free(data);
data = nullptr;
}
if (out_buf) {
free(out_buf);
out_buf = nullptr;
}
return decoderErr;
}
ostrm.write(reinterpret_cast<char *>(out_buf), outSize);
free(out_buf);
out_buf = nullptr;
}
mInputBufferCount++;
frameID++;
free(data);
data = nullptr;
}
ALOGV("frameID=%d", frameID);
return 0;
}
TEST_F(FLACDecoderTest, CreateDeleteTest) {
if (mFLACDecoder) delete mFLACDecoder;
mFLACDecoder = nullptr;
for (int32_t i = 0; i < kMaxCount; i++) {
mFLACDecoder = FLACDecoder::Create();
ASSERT_NE(mFLACDecoder, nullptr) << "FLACDecoder Creation Failed";
if (mFLACDecoder) delete mFLACDecoder;
mFLACDecoder = nullptr;
}
}
TEST_P(FLACDecoderTest, FlushTest) {
tuple<string /* InputFileName */, string /* InfoFileName */, bool /* outputfloat */> params =
GetParam();
string inputFileName = gEnv->getRes() + get<0>(params);
string infoFileName = gEnv->getRes() + get<1>(params);
bool outputFloat = get<2>(params);
vector<FrameInfo> Info;
getInfo(infoFileName, Info);
mEleStream.open(inputFileName, ifstream::binary);
ASSERT_EQ(mEleStream.is_open(), true);
ofstream ostrm;
ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
ASSERT_EQ(ostrm.is_open(), true);
int32_t status = processFlacDecoder(Info, 0, Info.size() / 3, outputFloat, ostrm);
ASSERT_EQ(status, 0) << "Test Failed. Decode returned error = " << status << endl;
mFLACDecoder->flush();
mHasStreamInfo = false;
status = processFlacDecoder(Info, (Info.size() / 3), Info.size() - (Info.size() / 3),
outputFloat, ostrm);
ostrm.close();
Info.clear();
ASSERT_EQ(status, 0) << "Test Failed. Decode returned error = " << status << endl;
}
TEST_P(FLACDecoderTest, DecodeTest) {
tuple<string /* InputFileName */, string /* InfoFileName */, bool /* outputfloat */> params =
GetParam();
string inputFileName = gEnv->getRes() + get<0>(params);
string infoFileName = gEnv->getRes() + get<1>(params);
bool outputFloat = get<2>(params);
vector<FrameInfo> Info;
getInfo(infoFileName, Info);
mEleStream.open(inputFileName, ifstream::binary);
ASSERT_EQ(mEleStream.is_open(), true);
ofstream ostrm;
ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
ASSERT_EQ(ostrm.is_open(), true);
int32_t status = processFlacDecoder(Info, 0, Info.size(), outputFloat, ostrm);
ostrm.close();
Info.clear();
ASSERT_EQ(status, 0) << "Test Failed. Decode returned error = " << status << endl;
}
// TODO: Add remaining tests
INSTANTIATE_TEST_SUITE_P(
FLACDecoderTestAll, FLACDecoderTest,
::testing::Values(make_tuple("bbb_flac_stereo_680kbps_48000hz.flac",
"bbb_flac_stereo_680kbps_48000hz.info", true),
make_tuple("bbb_flac_stereo_680kbps_48000hz.flac",
"bbb_flac_stereo_680kbps_48000hz.info", false),
make_tuple("bbb_flac_stereo_600kbps_44100hz.flac",
"bbb_flac_stereo_600kbps_44100hz.info", true),
make_tuple("bbb_flac_stereo_600kbps_44100hz.flac",
"bbb_flac_stereo_600kbps_44100hz.info", false)));
int main(int argc, char **argv) {
gEnv = new FlacDecoderTestEnvironment();
::testing::AddGlobalTestEnvironment(gEnv);
::testing::InitGoogleTest(&argc, argv);
int status = gEnv->initFromOptions(argc, argv);
if (status == 0) {
status = RUN_ALL_TESTS();
ALOGV("Flac Decoder Test Result = %d\n", status);
}
return status;
}

@ -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 __FLAC_DECODER_TEST_ENVIRONMENT_H__
#define __FLAC_DECODER_TEST_ENVIRONMENT_H__
#include <gtest/gtest.h>
#include <getopt.h>
using namespace std;
class FlacDecoderTestEnvironment : public ::testing::Environment {
public:
FlacDecoderTestEnvironment() : res("/data/local/tmp/") {}
// Parses the command line arguments
int initFromOptions(int argc, char **argv);
void setRes(const char *_res) { res = _res; }
const string getRes() const { return res; }
private:
string res;
};
int FlacDecoderTestEnvironment::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 // __FLAC_DECODER_TEST_ENVIRONMENT_H__

@ -0,0 +1,40 @@
## Media Testing ##
---
#### FlacDecoder :
The FlacDecoder Test Suite validates the FlacDecoder available in libstagefright.
Run the following steps to build the test suite:
```
m FlacDecoderTest
```
The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
To test 64-bit binary push binaries from nativetest64.
```
adb push ${OUT}/data/nativetest64/FlacDecoderTest/FlacDecoderTest /data/local/tmp/
```
To test 32-bit binary push binaries from nativetest.
```
adb push ${OUT}/data/nativetest/FlacDecoderTest/FlacDecoderTest /data/local/tmp/
```
The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/flac/dec/test/FlacDecoder.zip).
Download, unzip and push these files into device for testing.
```
adb push FlacDecoder /data/local/tmp/
```
usage: FlacDecoderTest -P \<path_to_folder\>
```
adb shell /data/local/tmp/FlacDecoderTest -P /data/local/tmp/FlacDecoder/
```
Alternatively, the test can also be run using atest command.
```
atest FlacDecoderTest -- --enable-module-dynamic-download=true
```
Loading…
Cancel
Save