MediaTesting: Add mp3Decoder Test
Test: Mp3DecoderTest -P /data/local/tmp/
Bug: 144750946
Change-Id: I1822cd91ec54d79537d1a0f4fe6cbb819bd3e5a1
diff --git a/media/libstagefright/codecs/mp3dec/test/Android.bp b/media/libstagefright/codecs/mp3dec/test/Android.bp
new file mode 100644
index 0000000..0ff8b12
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/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: "Mp3DecoderTest",
+ gtest: true,
+
+ srcs: [
+ "mp3reader.cpp",
+ "Mp3DecoderTest.cpp",
+ ],
+
+ static_libs: [
+ "libstagefright_mp3dec",
+ "libsndfile",
+ "libaudioutils",
+ ],
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
new file mode 100644
index 0000000..99553ec
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
@@ -0,0 +1,200 @@
+/*
+ * 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 "Mp3DecoderTest"
+
+#include <utils/Log.h>
+
+#include <audio_utils/sndfile.h>
+#include <stdio.h>
+
+#include "mp3reader.h"
+#include "pvmp3decoder_api.h"
+
+#include "Mp3DecoderTestEnvironment.h"
+
+#define OUTPUT_FILE "/data/local/tmp/mp3Decode.out"
+
+constexpr int32_t kInputBufferSize = 1024 * 10;
+constexpr int32_t kOutputBufferSize = 4608 * 2;
+constexpr int32_t kMaxCount = 10;
+constexpr int32_t kNumFrameReset = 150;
+
+static Mp3DecoderTestEnvironment *gEnv = nullptr;
+
+class Mp3DecoderTest : public ::testing::TestWithParam<string> {
+ public:
+ Mp3DecoderTest() : mConfig(nullptr) {}
+
+ ~Mp3DecoderTest() {
+ if (mConfig) {
+ delete mConfig;
+ mConfig = nullptr;
+ }
+ }
+
+ virtual void SetUp() override {
+ mConfig = new tPVMP3DecoderExternal{};
+ ASSERT_NE(mConfig, nullptr) << "Failed to initialize config. No Memory available";
+ mConfig->equalizerType = flat;
+ mConfig->crcEnabled = false;
+ }
+
+ tPVMP3DecoderExternal *mConfig;
+ Mp3Reader mMp3Reader;
+
+ ERROR_CODE DecodeFrames(void *decoderbuf, SNDFILE *outFileHandle, SF_INFO sfInfo,
+ int32_t frameCount = INT32_MAX);
+ SNDFILE *openOutputFile(SF_INFO *sfInfo);
+};
+
+ERROR_CODE Mp3DecoderTest::DecodeFrames(void *decoderBuf, SNDFILE *outFileHandle, SF_INFO sfInfo,
+ int32_t frameCount) {
+ uint8_t inputBuf[kInputBufferSize];
+ int16_t outputBuf[kOutputBufferSize];
+ uint32_t bytesRead;
+ ERROR_CODE decoderErr;
+ while (frameCount > 0) {
+ bool success = mMp3Reader.getFrame(inputBuf, &bytesRead);
+ if (!success) {
+ break;
+ }
+ mConfig->inputBufferCurrentLength = bytesRead;
+ mConfig->inputBufferMaxLength = 0;
+ mConfig->inputBufferUsedLength = 0;
+ mConfig->pInputBuffer = inputBuf;
+ mConfig->pOutputBuffer = outputBuf;
+ mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
+ decoderErr = pvmp3_framedecoder(mConfig, decoderBuf);
+ if (decoderErr != NO_DECODING_ERROR) break;
+ sf_writef_short(outFileHandle, outputBuf, mConfig->outputFrameSize / sfInfo.channels);
+ frameCount--;
+ }
+ return decoderErr;
+}
+
+SNDFILE *Mp3DecoderTest::openOutputFile(SF_INFO *sfInfo) {
+ memset(sfInfo, 0, sizeof(SF_INFO));
+ sfInfo->channels = mMp3Reader.getNumChannels();
+ sfInfo->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ sfInfo->samplerate = mMp3Reader.getSampleRate();
+ SNDFILE *outFileHandle = sf_open(OUTPUT_FILE, SFM_WRITE, sfInfo);
+ return outFileHandle;
+}
+
+TEST_F(Mp3DecoderTest, MultiCreateMp3DecoderTest) {
+ size_t memRequirements = pvmp3_decoderMemRequirements();
+ ASSERT_NE(memRequirements, 0) << "Failed to get the memory requirement size";
+ void *decoderBuf = malloc(memRequirements);
+ ASSERT_NE(decoderBuf, nullptr)
+ << "Failed to allocate decoder memory of size " << memRequirements;
+ for (int count = 0; count < kMaxCount; count++) {
+ pvmp3_InitDecoder(mConfig, decoderBuf);
+ ALOGV("Decoder created successfully");
+ }
+ if (decoderBuf) {
+ free(decoderBuf);
+ decoderBuf = nullptr;
+ }
+}
+
+TEST_P(Mp3DecoderTest, DecodeTest) {
+ size_t memRequirements = pvmp3_decoderMemRequirements();
+ ASSERT_NE(memRequirements, 0) << "Failed to get the memory requirement size";
+ void *decoderBuf = malloc(memRequirements);
+ ASSERT_NE(decoderBuf, nullptr)
+ << "Failed to allocate decoder memory of size " << memRequirements;
+
+ pvmp3_InitDecoder(mConfig, decoderBuf);
+ ALOGV("Decoder created successfully");
+ string inputFile = gEnv->getRes() + GetParam();
+ bool status = mMp3Reader.init(inputFile.c_str());
+ ASSERT_TRUE(status) << "Unable to initialize the mp3Reader";
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+ ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+ ERROR_CODE decoderErr = DecodeFrames(decoderBuf, outFileHandle, sfInfo);
+ ASSERT_EQ(decoderErr, NO_DECODING_ERROR) << "Failed to decode the frames";
+ ASSERT_EQ(sfInfo.channels, mConfig->num_channels) << "Number of channels does not match";
+ ASSERT_EQ(sfInfo.samplerate, mConfig->samplingRate) << "Sample rate does not match";
+
+ mMp3Reader.close();
+ sf_close(outFileHandle);
+ if (decoderBuf) {
+ free(decoderBuf);
+ decoderBuf = nullptr;
+ }
+}
+
+TEST_P(Mp3DecoderTest, ResetDecoderTest) {
+ size_t memRequirements = pvmp3_decoderMemRequirements();
+ ASSERT_NE(memRequirements, 0) << "Failed to get the memory requirement size";
+ void *decoderBuf = malloc(memRequirements);
+ ASSERT_NE(decoderBuf, nullptr)
+ << "Failed to allocate decoder memory of size " << memRequirements;
+
+ pvmp3_InitDecoder(mConfig, decoderBuf);
+ ALOGV("Decoder created successfully.");
+ string inputFile = gEnv->getRes() + GetParam();
+ bool status = mMp3Reader.init(inputFile.c_str());
+ ASSERT_TRUE(status) << "Unable to initialize the mp3Reader";
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+ ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+ ERROR_CODE decoderErr;
+ decoderErr = DecodeFrames(decoderBuf, outFileHandle, sfInfo, kNumFrameReset);
+ ASSERT_EQ(decoderErr, NO_DECODING_ERROR) << "Failed to decode the frames";
+ ASSERT_EQ(sfInfo.channels, mConfig->num_channels) << "Number of channels does not match";
+ ASSERT_EQ(sfInfo.samplerate, mConfig->samplingRate) << "Sample rate does not match";
+
+ pvmp3_resetDecoder(decoderBuf);
+ // Decode the same file.
+ decoderErr = DecodeFrames(decoderBuf, outFileHandle, sfInfo);
+ ASSERT_EQ(decoderErr, NO_DECODING_ERROR) << "Failed to decode the frames";
+ ASSERT_EQ(sfInfo.channels, mConfig->num_channels) << "Number of channels does not match";
+ ASSERT_EQ(sfInfo.samplerate, mConfig->samplingRate) << "Sample rate does not match";
+
+ mMp3Reader.close();
+ sf_close(outFileHandle);
+ if (decoderBuf) {
+ free(decoderBuf);
+ decoderBuf = nullptr;
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(Mp3DecoderTestAll, Mp3DecoderTest,
+ ::testing::Values(("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3"),
+ ("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3"),
+ ("bbb_mp3_stereo_192kbps_48000hz.mp3")));
+
+int main(int argc, char **argv) {
+ gEnv = new Mp3DecoderTestEnvironment();
+ ::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/mp3dec/test/Mp3DecoderTestEnvironment.h b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTestEnvironment.h
new file mode 100644
index 0000000..a54b34c
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTestEnvironment.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 __MP3DECODER_TEST_ENVIRONMENT_H__
+#define __MP3DECODER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class Mp3DecoderTestEnvironment : public ::testing::Environment {
+ public:
+ Mp3DecoderTestEnvironment() : 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 Mp3DecoderTestEnvironment::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 <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 // __MP3DECODER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/mp3dec/test/README.md b/media/libstagefright/codecs/mp3dec/test/README.md
new file mode 100644
index 0000000..019239e
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/README.md
@@ -0,0 +1,34 @@
+## Media Testing ##
+---
+#### Mp3Decoder :
+The Mp3Decoder Test Suite validates the mp3decoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m Mp3DecoderTest
+```
+
+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/Mp3DecoderTest/Mp3DecoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/Mp3DecoderTest/Mp3DecoderTest /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 mp3 folder and push all the files in this folder to /data/local/tmp/ on the device.
+```
+adb push mp3/. /data/local/tmp/
+```
+
+usage: Mp3DecoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/Mp3DecoderTest -P /data/local/tmp/
+```