diff --git a/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecTestEnvironment.h b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecTestEnvironment.h new file mode 100644 index 0000000000..0344ac5d6f --- /dev/null +++ b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecTestEnvironment.h @@ -0,0 +1,72 @@ +/* + * 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 __AMRNBDEC_TEST_ENVIRONMENT_H__ +#define __AMRNBDEC_TEST_ENVIRONMENT_H__ + +#include + +#include + +using namespace std; + +class AmrnbDecTestEnvironment : public ::testing::Environment { + public: + AmrnbDecTestEnvironment() : 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 AmrnbDecTestEnvironment::initFromOptions(int argc, char **argv) { + static struct option options[] = {{"res", 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 \n\n" + "test options are:\n\n" + "-P, --path: Resource files directory location\n", + argv[optind ?: 1], argv[0]); + return 2; + } + return 0; +} + +#endif // __AMRNBDEC_TEST_ENVIRONMENT_H__ diff --git a/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp new file mode 100644 index 0000000000..af620741e9 --- /dev/null +++ b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp @@ -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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "AmrnbDecoderTest" +#define OUTPUT_FILE "/data/local/tmp/amrnbDecode.out" + +#include + +#include +#include + +#include "gsmamr_dec.h" + +#include "AmrnbDecTestEnvironment.h" + +// Constants for AMR-NB +constexpr int32_t kInputBufferSize = 64; +constexpr int32_t kSamplesPerFrame = L_FRAME; +constexpr int32_t kBitsPerSample = 16; +constexpr int32_t kSampleRate = 8000; +constexpr int32_t kChannels = 1; +constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8; +const int32_t kFrameSizes[] = {12, 13, 15, 17, 19, 20, 26, 31, -1, -1, -1, -1, -1, -1, -1, -1}; + +constexpr int32_t kNumFrameReset = 150; + +static AmrnbDecTestEnvironment *gEnv = nullptr; + +class AmrnbDecoderTest : public ::testing::TestWithParam { + public: + AmrnbDecoderTest() : mFpInput(nullptr) {} + + ~AmrnbDecoderTest() { + if (mFpInput) { + fclose(mFpInput); + mFpInput = nullptr; + } + } + + FILE *mFpInput; + SNDFILE *openOutputFile(SF_INFO *sfInfo); + int32_t DecodeFrames(void *amrHandle, SNDFILE *outFileHandle, int32_t frameCount = INT32_MAX); +}; + +SNDFILE *AmrnbDecoderTest::openOutputFile(SF_INFO *sfInfo) { + memset(sfInfo, 0, sizeof(SF_INFO)); + sfInfo->channels = kChannels; + sfInfo->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; + sfInfo->samplerate = kSampleRate; + SNDFILE *outFileHandle = sf_open(OUTPUT_FILE, SFM_WRITE, sfInfo); + return outFileHandle; +} + +int32_t AmrnbDecoderTest::DecodeFrames(void *amrHandle, SNDFILE *outFileHandle, + int32_t frameCount) { + uint8_t inputBuf[kInputBufferSize]; + int16_t outputBuf[kOutputBufferSize]; + + while (frameCount > 0) { + uint8_t mode; + int32_t bytesRead = fread(&mode, 1, 1, mFpInput); + if (bytesRead != 1) break; + + // Find frame type + Frame_Type_3GPP frameType = (Frame_Type_3GPP)((mode >> 3) & 0x0f); + int32_t frameSize = kFrameSizes[frameType]; + if (frameSize < 0) { + ALOGE("Illegal frame type"); + return -1; + } + bytesRead = fread(inputBuf, 1, frameSize, mFpInput); + if (bytesRead != frameSize) break; + + int32_t bytesDecoded = AMRDecode(amrHandle, frameType, inputBuf, outputBuf, MIME_IETF); + if (bytesDecoded == -1) { + ALOGE("Failed to decode the input file"); + return -1; + } + + sf_writef_short(outFileHandle, outputBuf, kSamplesPerFrame); + frameCount--; + } + return 0; +} + +TEST_F(AmrnbDecoderTest, CreateAmrnbDecoderTest) { + void *amrHandle; + int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder"); + ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder"; + GSMDecodeFrameExit(&amrHandle); + ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder"; +} + +TEST_P(AmrnbDecoderTest, DecodeTest) { + string inputFile = gEnv->getRes() + GetParam(); + mFpInput = fopen(inputFile.c_str(), "rb"); + ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile; + + // Open the output file. + SF_INFO sfInfo; + SNDFILE *outFileHandle = openOutputFile(&sfInfo); + ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output"; + + void *amrHandle; + int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder"); + ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder"; + + // Decode + int32_t decoderErr = DecodeFrames(amrHandle, outFileHandle); + ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error"; + + sf_close(outFileHandle); + GSMDecodeFrameExit(&amrHandle); + ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder"; +} + +TEST_P(AmrnbDecoderTest, ResetDecodeTest) { + string inputFile = gEnv->getRes() + GetParam(); + mFpInput = fopen(inputFile.c_str(), "rb"); + ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile; + + // Open the output file. + SF_INFO sfInfo; + SNDFILE *outFileHandle = openOutputFile(&sfInfo); + ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output"; + + void *amrHandle; + int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder"); + ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder"; + + // Decode kNumFrameReset first + int32_t decoderErr = DecodeFrames(amrHandle, outFileHandle, kNumFrameReset); + ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error"; + + status = Speech_Decode_Frame_reset(amrHandle); + ASSERT_EQ(status, 0) << "Error resting AMR-NB decoder"; + + // Start decoding again + decoderErr = DecodeFrames(amrHandle, outFileHandle); + ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error"; + + sf_close(outFileHandle); + GSMDecodeFrameExit(&amrHandle); + ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder"; +} + +INSTANTIATE_TEST_SUITE_P(AmrnbDecoderTestAll, AmrnbDecoderTest, + ::testing::Values(("bbb_8000hz_1ch_8kbps_amrnb_30sec.amrnb"), + ("sine_amrnb_1ch_12kbps_8000hz.amrnb"))); + +int main(int argc, char **argv) { + gEnv = new AmrnbDecTestEnvironment(); + ::testing::AddGlobalTestEnvironment(gEnv); + ::testing::InitGoogleTest(&argc, argv); + int status = gEnv->initFromOptions(argc, argv); + if (status == 0) { + status = RUN_ALL_TESTS(); + ALOGV("Test result = %d\n", status); + } + return status; +} diff --git a/media/libstagefright/codecs/amrnb/dec/test/Android.bp b/media/libstagefright/codecs/amrnb/dec/test/Android.bp new file mode 100644 index 0000000000..7a95cfa6fb --- /dev/null +++ b/media/libstagefright/codecs/amrnb/dec/test/Android.bp @@ -0,0 +1,48 @@ +/* + * 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: "AmrnbDecoderTest", + gtest: true, + + srcs: [ + "AmrnbDecoderTest.cpp", + ], + + static_libs: [ + "libstagefright_amrnb_common", + "libstagefright_amrnbdec", + "libaudioutils", + "libsndfile", + ], + + shared_libs: [ + "liblog", + ], + + cflags: [ + "-Werror", + "-Wall", + ], + + sanitize: { + cfi: true, + misc_undefined: [ + "unsigned-integer-overflow", + "signed-integer-overflow", + ], + }, +} diff --git a/media/libstagefright/codecs/amrnb/dec/test/README.md b/media/libstagefright/codecs/amrnb/dec/test/README.md new file mode 100644 index 0000000000..62e13aef8c --- /dev/null +++ b/media/libstagefright/codecs/amrnb/dec/test/README.md @@ -0,0 +1,34 @@ +## Media Testing ## +--- +#### AMR-NB Decoder : +The Amr-Nb Decoder Test Suite validates the amrnb decoder available in libstagefright. + +Run the following steps to build the test suite: +``` +m AmrnbDecoderTest +``` + +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/AmrnbDecoderTest/AmrnbDecoderTest /data/local/tmp/ +``` + +To test 32-bit binary push binaries from nativetest. +``` +adb push ${OUT}/data/nativetest/AmrnbDecoderTest/AmrnbDecoderTest /data/local/tmp/ +``` + +The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b). Push these files into device for testing. +Download amr-nb folder and push all the files in this folder to /data/local/tmp/ on the device. +``` +adb push amr-nb/. /data/local/tmp/ +``` + +usage: AmrnbDecoderTest -P \ +``` +adb shell /data/local/tmp/AmrnbDecoderTest -P /data/local/tmp/ +```