diff --git a/media/extractors/tests/Android.bp b/media/extractors/tests/Android.bp new file mode 100644 index 0000000000..059c308c2e --- /dev/null +++ b/media/extractors/tests/Android.bp @@ -0,0 +1,96 @@ +/* + * 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: "ExtractorUnitTest", + gtest: true, + + srcs: ["ExtractorUnitTest.cpp"], + + static_libs: [ + "libaacextractor", + "libamrextractor", + "libmp3extractor", + "libwavextractor", + "liboggextractor", + "libflacextractor", + "libmidiextractor", + "libmkvextractor", + "libmpeg2extractor", + "libmp4extractor", + "libaudioutils", + "libdatasource", + + "libstagefright", + "libstagefright_id3", + "libstagefright_flacdec", + "libstagefright_esds", + "libstagefright_mpeg2support", + "libstagefright_mpeg2extractor", + "libstagefright_foundation", + "libstagefright_metadatautils", + + "libmedia_midiiowrapper", + "libsonivox", + "libvorbisidec", + "libwebm", + "libFLAC", + ], + + shared_libs: [ + "android.hardware.cas@1.0", + "android.hardware.cas.native@1.0", + "android.hidl.token@1.0-utils", + "android.hidl.allocator@1.0", + "libbinder", + "libbinder_ndk", + "libutils", + "liblog", + "libcutils", + "libmediandk", + "libmedia", + "libcrypto", + "libhidlmemory", + "libhidlbase", + ], + + include_dirs: [ + "frameworks/av/media/extractors/", + "frameworks/av/media/libstagefright/", + ], + + compile_multilib: "first", + + cflags: [ + "-Werror", + "-Wall", + ], + + ldflags: [ + "-Wl", + "-Bsymbolic", + // to ignore duplicate symbol: GETEXTRACTORDEF + "-z muldefs", + ], + + sanitize: { + cfi: true, + misc_undefined: [ + "unsigned-integer-overflow", + "signed-integer-overflow", + ], + }, +} diff --git a/media/extractors/tests/ExtractorUnitTest.cpp b/media/extractors/tests/ExtractorUnitTest.cpp new file mode 100644 index 0000000000..518166e05b --- /dev/null +++ b/media/extractors/tests/ExtractorUnitTest.cpp @@ -0,0 +1,528 @@ +/* + * 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 "ExtractorUnitTest" +#include + +#include +#include +#include +#include + +#include "aac/AACExtractor.h" +#include "amr/AMRExtractor.h" +#include "flac/FLACExtractor.h" +#include "midi/MidiExtractor.h" +#include "mkv/MatroskaExtractor.h" +#include "mp3/MP3Extractor.h" +#include "mp4/MPEG4Extractor.h" +#include "mp4/SampleTable.h" +#include "mpeg2/MPEG2PSExtractor.h" +#include "mpeg2/MPEG2TSExtractor.h" +#include "ogg/OggExtractor.h" +#include "wav/WAVExtractor.h" + +#include "ExtractorUnitTestEnvironment.h" + +using namespace android; + +#define OUTPUT_DUMP_FILE "/data/local/tmp/extractorOutput" + +constexpr int32_t kMaxCount = 10; +constexpr int32_t kOpusSeekPreRollUs = 80000; // 80 ms; + +static ExtractorUnitTestEnvironment *gEnv = nullptr; + +class ExtractorUnitTest : public ::testing::TestWithParam> { + public: + ExtractorUnitTest() : mInputFp(nullptr), mDataSource(nullptr), mExtractor(nullptr) {} + + ~ExtractorUnitTest() { + if (mInputFp) { + fclose(mInputFp); + mInputFp = nullptr; + } + if (mDataSource) { + mDataSource.clear(); + mDataSource = nullptr; + } + if (mExtractor) { + delete mExtractor; + mExtractor = nullptr; + } + } + + virtual void SetUp() override { + mExtractorName = unknown_comp; + mDisableTest = false; + + static const std::map mapExtractor = { + {"aac", AAC}, {"amr", AMR}, {"mp3", MP3}, {"ogg", OGG}, + {"wav", WAV}, {"mkv", MKV}, {"flac", FLAC}, {"midi", MIDI}, + {"mpeg4", MPEG4}, {"mpeg2ts", MPEG2TS}, {"mpeg2ps", MPEG2PS}}; + // Find the component type + string writerFormat = GetParam().first; + if (mapExtractor.find(writerFormat) != mapExtractor.end()) { + mExtractorName = mapExtractor.at(writerFormat); + } + if (mExtractorName == standardExtractors::unknown_comp) { + cout << "[ WARN ] Test Skipped. Invalid extractor\n"; + mDisableTest = true; + } + } + + int32_t setDataSource(string inputFileName); + + int32_t createExtractor(); + + enum standardExtractors { + AAC, + AMR, + FLAC, + MIDI, + MKV, + MP3, + MPEG4, + MPEG2PS, + MPEG2TS, + OGG, + WAV, + unknown_comp, + }; + + bool mDisableTest; + standardExtractors mExtractorName; + + FILE *mInputFp; + sp mDataSource; + MediaExtractorPluginHelper *mExtractor; +}; + +int32_t ExtractorUnitTest::setDataSource(string inputFileName) { + mInputFp = fopen(inputFileName.c_str(), "rb"); + if (!mInputFp) { + ALOGE("Unable to open input file for reading"); + return -1; + } + struct stat buf; + stat(inputFileName.c_str(), &buf); + int32_t fd = fileno(mInputFp); + mDataSource = new FileSource(dup(fd), 0, buf.st_size); + if (!mDataSource) return -1; + return 0; +} + +int32_t ExtractorUnitTest::createExtractor() { + switch (mExtractorName) { + case AAC: + mExtractor = new AACExtractor(new DataSourceHelper(mDataSource->wrap()), 0); + break; + case AMR: + mExtractor = new AMRExtractor(new DataSourceHelper(mDataSource->wrap())); + break; + case MP3: + mExtractor = new MP3Extractor(new DataSourceHelper(mDataSource->wrap()), nullptr); + break; + case OGG: + mExtractor = new OggExtractor(new DataSourceHelper(mDataSource->wrap())); + break; + case WAV: + mExtractor = new WAVExtractor(new DataSourceHelper(mDataSource->wrap())); + break; + case MKV: + mExtractor = new MatroskaExtractor(new DataSourceHelper(mDataSource->wrap())); + break; + case FLAC: + mExtractor = new FLACExtractor(new DataSourceHelper(mDataSource->wrap())); + break; + case MPEG4: + mExtractor = new MPEG4Extractor(new DataSourceHelper(mDataSource->wrap())); + break; + case MPEG2TS: + mExtractor = new MPEG2TSExtractor(new DataSourceHelper(mDataSource->wrap())); + break; + case MPEG2PS: + mExtractor = new MPEG2PSExtractor(new DataSourceHelper(mDataSource->wrap())); + break; + case MIDI: + mExtractor = new MidiExtractor(mDataSource->wrap()); + break; + default: + return -1; + } + if (!mExtractor) return -1; + return 0; +} + +void getSeekablePoints(vector &seekablePoints, MediaTrackHelper *track) { + int32_t status = 0; + if (!seekablePoints.empty()) { + seekablePoints.clear(); + } + int64_t timeStamp; + while (status != AMEDIA_ERROR_END_OF_STREAM) { + MediaBufferHelper *buffer = nullptr; + status = track->read(&buffer); + if (buffer) { + AMediaFormat *metaData = buffer->meta_data(); + int32_t isSync = 0; + AMediaFormat_getInt32(metaData, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, &isSync); + if (isSync) { + AMediaFormat_getInt64(metaData, AMEDIAFORMAT_KEY_TIME_US, &timeStamp); + seekablePoints.push_back(timeStamp); + } + buffer->release(); + } + } +} + +TEST_P(ExtractorUnitTest, CreateExtractorTest) { + if (mDisableTest) return; + + ALOGV("Checks if a valid extractor is created for a given input file"); + string inputFileName = gEnv->getRes() + GetParam().second; + + ASSERT_EQ(setDataSource(inputFileName), 0) + << "SetDataSource failed for" << GetParam().first << "extractor"; + + ASSERT_EQ(createExtractor(), 0) + << "Extractor creation failed for" << GetParam().first << "extractor"; + + // A valid extractor instace should return success for following calls + ASSERT_GT(mExtractor->countTracks(), 0); + + AMediaFormat *format = AMediaFormat_new(); + ASSERT_NE(format, nullptr) << "AMediaFormat_new returned null AMediaformat"; + + ASSERT_EQ(mExtractor->getMetaData(format), AMEDIA_OK); + AMediaFormat_delete(format); +} + +TEST_P(ExtractorUnitTest, ExtractorTest) { + if (mDisableTest) return; + + ALOGV("Validates %s Extractor for a given input file", GetParam().first.c_str()); + string inputFileName = gEnv->getRes() + GetParam().second; + + int32_t status = setDataSource(inputFileName); + ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor"; + + status = createExtractor(); + ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor"; + + int32_t numTracks = mExtractor->countTracks(); + ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip"; + + for (int32_t idx = 0; idx < numTracks; idx++) { + MediaTrackHelper *track = mExtractor->getTrack(idx); + ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx; + + CMediaTrack *cTrack = wrap(track); + ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx; + + MediaBufferGroup *bufferGroup = new MediaBufferGroup(); + status = cTrack->start(track, bufferGroup->wrap()); + ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track"; + + FILE *outFp = fopen((OUTPUT_DUMP_FILE + to_string(idx)).c_str(), "wb"); + if (!outFp) { + ALOGW("Unable to open output file for dumping extracted stream"); + } + + while (status != AMEDIA_ERROR_END_OF_STREAM) { + MediaBufferHelper *buffer = nullptr; + status = track->read(&buffer); + ALOGV("track->read Status = %d buffer %p", status, buffer); + if (buffer) { + ALOGV("buffer->data %p buffer->size() %zu buffer->range_length() %zu", + buffer->data(), buffer->size(), buffer->range_length()); + if (outFp) fwrite(buffer->data(), 1, buffer->range_length(), outFp); + buffer->release(); + } + } + if (outFp) fclose(outFp); + status = cTrack->stop(track); + ASSERT_EQ(OK, status) << "Failed to stop the track"; + delete bufferGroup; + delete track; + } +} + +TEST_P(ExtractorUnitTest, MetaDataComparisonTest) { + if (mDisableTest) return; + + ALOGV("Validates Extractor's meta data for a given input file"); + string inputFileName = gEnv->getRes() + GetParam().second; + + int32_t status = setDataSource(inputFileName); + ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor"; + + status = createExtractor(); + ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor"; + + int32_t numTracks = mExtractor->countTracks(); + ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip"; + + AMediaFormat *extractorFormat = AMediaFormat_new(); + ASSERT_NE(extractorFormat, nullptr) << "AMediaFormat_new returned null AMediaformat"; + AMediaFormat *trackFormat = AMediaFormat_new(); + ASSERT_NE(trackFormat, nullptr) << "AMediaFormat_new returned null AMediaformat"; + + for (int32_t idx = 0; idx < numTracks; idx++) { + MediaTrackHelper *track = mExtractor->getTrack(idx); + ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx; + + CMediaTrack *cTrack = wrap(track); + ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx; + + MediaBufferGroup *bufferGroup = new MediaBufferGroup(); + status = cTrack->start(track, bufferGroup->wrap()); + ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track"; + + status = mExtractor->getTrackMetaData(extractorFormat, idx, 1); + ASSERT_EQ(OK, (media_status_t)status) << "Failed to get trackMetaData"; + + status = track->getFormat(trackFormat); + ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data"; + + const char *extractorMime, *trackMime; + AMediaFormat_getString(extractorFormat, AMEDIAFORMAT_KEY_MIME, &extractorMime); + AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &trackMime); + ASSERT_TRUE(!strcmp(extractorMime, trackMime)) + << "Extractor's format doesn't match track format"; + + if (!strncmp(extractorMime, "audio/", 6)) { + int32_t exSampleRate, exChannelCount; + int32_t trackSampleRate, trackChannelCount; + ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, + &exChannelCount)); + ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, + &exSampleRate)); + ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, + &trackChannelCount)); + ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, + &trackSampleRate)); + ASSERT_EQ(exChannelCount, trackChannelCount) << "ChannelCount not as expected"; + ASSERT_EQ(exSampleRate, trackSampleRate) << "SampleRate not as expected"; + } else { + int32_t exWidth, exHeight; + int32_t trackWidth, trackHeight; + ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_WIDTH, &exWidth)); + ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_HEIGHT, &exHeight)); + ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_WIDTH, &trackWidth)); + ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_HEIGHT, &trackHeight)); + ASSERT_EQ(exWidth, trackWidth) << "Width not as expected"; + ASSERT_EQ(exHeight, trackHeight) << "Height not as expected"; + } + status = cTrack->stop(track); + ASSERT_EQ(OK, status) << "Failed to stop the track"; + delete bufferGroup; + delete track; + } + AMediaFormat_delete(trackFormat); + AMediaFormat_delete(extractorFormat); +} + +TEST_P(ExtractorUnitTest, MultipleStartStopTest) { + if (mDisableTest) return; + + ALOGV("Test %s extractor for multiple start and stop calls", GetParam().first.c_str()); + string inputFileName = gEnv->getRes() + GetParam().second; + + int32_t status = setDataSource(inputFileName); + ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor"; + + status = createExtractor(); + ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor"; + + int32_t numTracks = mExtractor->countTracks(); + ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip"; + + // start/stop the tracks multiple times + for (int32_t count = 0; count < kMaxCount; count++) { + for (int32_t idx = 0; idx < numTracks; idx++) { + MediaTrackHelper *track = mExtractor->getTrack(idx); + ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx; + + CMediaTrack *cTrack = wrap(track); + ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx; + + MediaBufferGroup *bufferGroup = new MediaBufferGroup(); + status = cTrack->start(track, bufferGroup->wrap()); + ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track"; + MediaBufferHelper *buffer = nullptr; + status = track->read(&buffer); + if (buffer) { + ALOGV("buffer->data %p buffer->size() %zu buffer->range_length() %zu", + buffer->data(), buffer->size(), buffer->range_length()); + buffer->release(); + } + status = cTrack->stop(track); + ASSERT_EQ(OK, status) << "Failed to stop the track"; + delete bufferGroup; + delete track; + } + } +} + +TEST_P(ExtractorUnitTest, SeekTest) { + // Both Flac and Wav extractor can give samples from any pts and mark the given sample as + // sync frame. So, this seek test is not applicable to FLAC and WAV extractors + if (mDisableTest || mExtractorName == FLAC || mExtractorName == WAV) return; + + ALOGV("Validates %s Extractor behaviour for different seek modes", GetParam().first.c_str()); + string inputFileName = gEnv->getRes() + GetParam().second; + + int32_t status = setDataSource(inputFileName); + ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor"; + + status = createExtractor(); + ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor"; + + int32_t numTracks = mExtractor->countTracks(); + ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip"; + + uint32_t seekFlag = mExtractor->flags(); + if (!(seekFlag & MediaExtractorPluginHelper::CAN_SEEK)) { + cout << "[ WARN ] Test Skipped. " << GetParam().first + << " Extractor doesn't support seek\n"; + return; + } + + vector seekablePoints; + for (int32_t idx = 0; idx < numTracks; idx++) { + MediaTrackHelper *track = mExtractor->getTrack(idx); + ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx; + + CMediaTrack *cTrack = wrap(track); + ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx; + + // Get all the seekable points of a given input + MediaBufferGroup *bufferGroup = new MediaBufferGroup(); + status = cTrack->start(track, bufferGroup->wrap()); + ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track"; + getSeekablePoints(seekablePoints, track); + ASSERT_GT(seekablePoints.size(), 0) + << "Failed to get seekable points for " << GetParam().first << " extractor"; + + AMediaFormat *trackFormat = AMediaFormat_new(); + ASSERT_NE(trackFormat, nullptr) << "AMediaFormat_new returned null format"; + status = track->getFormat(trackFormat); + ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data"; + + bool isOpus = false; + const char *mime; + AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &mime); + if (!strcmp(mime, "audio/opus")) isOpus = true; + AMediaFormat_delete(trackFormat); + + int32_t seekIdx = 0; + size_t seekablePointsSize = seekablePoints.size(); + for (int32_t mode = CMediaTrackReadOptions::SEEK_PREVIOUS_SYNC; + mode <= CMediaTrackReadOptions::SEEK_CLOSEST; mode++) { + for (int32_t seekCount = 0; seekCount < kMaxCount; seekCount++) { + seekIdx = rand() % seekablePointsSize + 1; + if (seekIdx >= seekablePointsSize) seekIdx = seekablePointsSize - 1; + + int64_t seekToTimeStamp = seekablePoints[seekIdx]; + if (seekablePointsSize > 1) { + int64_t prevTimeStamp = seekablePoints[seekIdx - 1]; + seekToTimeStamp = seekToTimeStamp - ((seekToTimeStamp - prevTimeStamp) >> 3); + } + + // Opus has a seekPreRollUs. TimeStamp returned by the + // extractor is calculated based on (seekPts - seekPreRollUs). + // So we add the preRoll value to the timeStamp we want to seek to. + if (isOpus) { + seekToTimeStamp += kOpusSeekPreRollUs; + } + + MediaTrackHelper::ReadOptions *options = new MediaTrackHelper::ReadOptions( + mode | CMediaTrackReadOptions::SEEK, seekToTimeStamp); + ASSERT_NE(options, nullptr) << "Cannot create read option"; + + MediaBufferHelper *buffer = nullptr; + status = track->read(&buffer, options); + if (status == AMEDIA_ERROR_END_OF_STREAM) { + delete options; + continue; + } + if (buffer) { + AMediaFormat *metaData = buffer->meta_data(); + int64_t timeStamp; + AMediaFormat_getInt64(metaData, AMEDIAFORMAT_KEY_TIME_US, &timeStamp); + buffer->release(); + + // CMediaTrackReadOptions::SEEK is 8. Using mask 0111b to get true modes + switch (mode & 0x7) { + case CMediaTrackReadOptions::SEEK_PREVIOUS_SYNC: + if (seekablePointsSize == 1) { + EXPECT_EQ(timeStamp, seekablePoints[seekIdx]); + } else { + EXPECT_EQ(timeStamp, seekablePoints[seekIdx - 1]); + } + break; + case CMediaTrackReadOptions::SEEK_NEXT_SYNC: + case CMediaTrackReadOptions::SEEK_CLOSEST_SYNC: + case CMediaTrackReadOptions::SEEK_CLOSEST: + EXPECT_EQ(timeStamp, seekablePoints[seekIdx]); + break; + default: + break; + } + } + delete options; + } + } + status = cTrack->stop(track); + ASSERT_EQ(OK, status) << "Failed to stop the track"; + delete bufferGroup; + delete track; + } + seekablePoints.clear(); +} + +// TODO: (b/145332185) +// Add MIDI inputs +INSTANTIATE_TEST_SUITE_P(ExtractorUnitTestAll, ExtractorUnitTest, + ::testing::Values(make_pair("aac", "loudsoftaac.aac"), + make_pair("amr", "testamr.amr"), + make_pair("amr", "amrwb.wav"), + make_pair("ogg", "john_cage.ogg"), + make_pair("wav", "monotestgsm.wav"), + make_pair("mpeg2ts", "segment000001.ts"), + make_pair("flac", "sinesweepflac.flac"), + make_pair("ogg", "testopus.opus"), + make_pair("mkv", "sinesweepvorbis.mkv"), + make_pair("mpeg4", "sinesweepoggmp4.mp4"), + make_pair("mp3", "sinesweepmp3lame.mp3"), + make_pair("mkv", "swirl_144x136_vp9.webm"), + make_pair("mkv", "swirl_144x136_vp8.webm"), + make_pair("mpeg2ps", "swirl_144x136_mpeg2.mpg"), + make_pair("mpeg4", "swirl_132x130_mpeg4.mp4"))); + +int main(int argc, char **argv) { + gEnv = new ExtractorUnitTestEnvironment(); + ::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/extractors/tests/ExtractorUnitTestEnvironment.h b/media/extractors/tests/ExtractorUnitTestEnvironment.h new file mode 100644 index 0000000000..fce8fc282f --- /dev/null +++ b/media/extractors/tests/ExtractorUnitTestEnvironment.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 __EXTRACTOR_UNIT_TEST_ENVIRONMENT_H__ +#define __EXTRACTOR_UNIT_TEST_ENVIRONMENT_H__ + +#include + +#include + +using namespace std; + +class ExtractorUnitTestEnvironment : public ::testing::Environment { + public: + ExtractorUnitTestEnvironment() : 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 ExtractorUnitTestEnvironment::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 // __EXTRACTOR_UNIT_TEST_ENVIRONMENT_H__ diff --git a/media/extractors/tests/README.md b/media/extractors/tests/README.md new file mode 100644 index 0000000000..6e02d3efb6 --- /dev/null +++ b/media/extractors/tests/README.md @@ -0,0 +1,34 @@ +## Media Testing ## +--- +#### Extractor : +The Extractor Test Suite validates the extractors available in the device. + +Run the following steps to build the test suite: +``` +m ExtractorUnitTest +``` + +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/ExtractorUnitTest/ExtractorUnitTest /data/local/tmp/ +``` + +To test 32-bit binary push binaries from nativetest. +``` +adb push ${OUT}/data/nativetest/ExtractorUnitTest/ExtractorUnitTest /data/local/tmp/ +``` + +The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/1Z9nCIRB6pGLvb5mPkF8BURa5Nc6cY9pY). Push these files into device for testing. +Download extractor folder and push all the files in this folder to /data/local/tmp/ on the device. +``` +adb push extractor /data/local/tmp/ +``` + +usage: ExtractorUnitTest -P \ +``` +adb shell /data/local/tmp/ExtractorUnitTest -P /data/local/tmp/extractor/ +```