summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhuoyao Zhang <zhuoyao@google.com>2017-04-13 19:24:28 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2017-04-13 19:24:29 +0000
commit9eeda9561f18b253571519b20700b7d0d68b6370 (patch)
tree5a859966a575171b753485445c4e67334e299ac5
parent61d3d5ee851453a6a4b4470e7c18eab1c8cc733e (diff)
parent527cf971592a0e06f30b7056374beb1a5257d2f7 (diff)
downloadandroid_hardware_interfaces-9eeda9561f18b253571519b20700b7d0d68b6370.tar.gz
android_hardware_interfaces-9eeda9561f18b253571519b20700b7d0d68b6370.tar.bz2
android_hardware_interfaces-9eeda9561f18b253571519b20700b7d0d68b6370.zip
Merge "media.omx VTS test baseline" into oc-dev
-rwxr-xr-x[-rw-r--r--]media/Android.bp3
-rw-r--r--media/omx/1.0/vts/functional/audio/Android.bp79
-rw-r--r--media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp687
-rw-r--r--media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp263
-rw-r--r--media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp316
-rw-r--r--media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.h78
-rw-r--r--media/omx/1.0/vts/functional/common/media_hidl_test_common.h206
-rw-r--r--media/omx/1.0/vts/functional/component/Android.bp45
-rw-r--r--media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp1213
-rw-r--r--media/omx/1.0/vts/functional/master/Android.bp38
-rw-r--r--media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp120
11 files changed, 3048 insertions, 0 deletions
diff --git a/media/Android.bp b/media/Android.bp
index f2abc678a..34ecf17e1 100644..100755
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -2,4 +2,7 @@
subdirs = [
"1.0",
"omx/1.0",
+ "omx/1.0/vts/functional/master",
+ "omx/1.0/vts/functional/component",
+ "omx/1.0/vts/functional/audio",
]
diff --git a/media/omx/1.0/vts/functional/audio/Android.bp b/media/omx/1.0/vts/functional/audio/Android.bp
new file mode 100644
index 000000000..d6c73ced7
--- /dev/null
+++ b/media/omx/1.0/vts/functional/audio/Android.bp
@@ -0,0 +1,79 @@
+//
+// Copyright (C) 2017 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: "VtsHalMediaOmxV1_0TargetAudioEncTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalMediaOmxV1_0TargetAudioEncTest.cpp",
+ "media_audio_hidl_test_common.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidlmemory",
+ "libhidltransport",
+ "libhwbinder",
+ "libnativehelper",
+ "libutils",
+ "libstagefright_foundation",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "android.hardware.media.omx@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+ include_dirs: [
+ "frameworks/native/include/media/openmax/",
+ "hardware/interfaces/media/omx/1.0/vts/functional/common",
+ ],
+}
+
+cc_test {
+ name: "VtsHalMediaOmxV1_0TargetAudioDecTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalMediaOmxV1_0TargetAudioDecTest.cpp",
+ "media_audio_hidl_test_common.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidlmemory",
+ "libhidltransport",
+ "libhwbinder",
+ "libnativehelper",
+ "libutils",
+ "libstagefright_foundation",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "android.hardware.media.omx@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+ include_dirs: [
+ "frameworks/native/include/media/openmax/",
+ "hardware/interfaces/media/omx/1.0/vts/functional/common",
+ ],
+}
+
+
diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp
new file mode 100644
index 000000000..7c2175351
--- /dev/null
+++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp
@@ -0,0 +1,687 @@
+/*
+ * Copyright (C) 2017 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_TAG "media_omx_hidl_audio_dec_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMapper.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hidl::memory::V1_0::IMapper;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <getopt.h>
+#include <media_audio_hidl_test_common.h>
+#include <media_hidl_test_common.h>
+#include <fstream>
+
+// A class for test environment setup
+class ComponentTestEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ ComponentTestEnvironment() : instance("default") {}
+
+ void setInstance(const char* _instance) { instance = _instance; }
+
+ void setComponent(const char* _component) { component = _component; }
+
+ void setRole(const char* _role) { role = _role; }
+
+ void setQuirks(int _quirks) { quirks = _quirks; }
+
+ const hidl_string getInstance() const { return instance; }
+
+ const hidl_string getComponent() const { return component; }
+
+ const hidl_string getRole() const { return role; }
+
+ int getQuirks() const { return quirks; }
+
+ int initFromOptions(int argc, char** argv) {
+ static struct option options[] = {
+ {"instance", required_argument, 0, 'I'},
+ {"component", required_argument, 0, 'C'},
+ {"role", required_argument, 0, 'R'},
+ {"quirks", required_argument, 0, 'Q'},
+ {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "I:C:Q:R:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'I':
+ setInstance(optarg);
+ break;
+ case 'C':
+ setComponent(optarg);
+ break;
+ case 'Q':
+ setQuirks(atoi(optarg));
+ break;
+ case 'R':
+ setRole(optarg);
+ break;
+ case '?':
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-I, --instance: HAL instance to test\n"
+ "-C, --component: OMX component to test\n"
+ "-R, --Role: OMX component Role\n"
+ "-Q, --quirks: Component quirks\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+ }
+
+ private:
+ hidl_string instance;
+ hidl_string component;
+ hidl_string role;
+ // to be removed when IOmxNode::setQuirks is removed
+ int quirks;
+};
+
+static ComponentTestEnvironment* gEnv = nullptr;
+
+class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ android::hardware::media::omx::V1_0::Status status;
+ omx = ::testing::VtsHalHidlTargetTestBase::getService<IOmx>(
+ gEnv->getInstance());
+ ASSERT_NE(omx, nullptr);
+ observer = new CodecObserver();
+ ASSERT_NE(observer, nullptr);
+ ASSERT_EQ(strncmp(gEnv->getComponent().c_str(), "OMX.", 4), 0)
+ << "Invalid Component Name";
+ EXPECT_TRUE(omx->allocateNode(
+ gEnv->getComponent(), observer,
+ [&](android::hardware::media::omx::V1_0::Status _s,
+ sp<IOmxNode> const& _nl) {
+ status = _s;
+ this->omxNode = _nl;
+ })
+ .isOk());
+ ASSERT_NE(omxNode, nullptr);
+ ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
+ struct StringToName {
+ const char* Name;
+ standardComp CompName;
+ };
+ const StringToName kStringToName[] = {
+ {"mp3", mp3}, {"amrnb", amrnb}, {"amrwb", amrwb},
+ {"aac", aac}, {"vorbis", vorbis}, {"opus", opus},
+ {"pcm", pcm}, {"flac", flac},
+ };
+ const size_t kNumStringToName =
+ sizeof(kStringToName) / sizeof(kStringToName[0]);
+ const char* pch;
+ char substring[OMX_MAX_STRINGNAME_SIZE];
+ strcpy(substring, gEnv->getRole().c_str());
+ pch = strchr(substring, '.');
+ ASSERT_NE(pch, nullptr);
+ compName = unknown_comp;
+ for (size_t i = 0; i < kNumStringToName; ++i) {
+ if (!strcasecmp(pch + 1, kStringToName[i].Name)) {
+ compName = kStringToName[i].CompName;
+ break;
+ }
+ }
+ ASSERT_NE(compName, unknown_comp);
+ struct CompToCoding {
+ standardComp CompName;
+ OMX_AUDIO_CODINGTYPE eEncoding;
+ };
+ static const CompToCoding kCompToCoding[] = {
+ {mp3, OMX_AUDIO_CodingMP3},
+ {amrnb, OMX_AUDIO_CodingAMR},
+ {amrwb, OMX_AUDIO_CodingAMR},
+ {aac, OMX_AUDIO_CodingAAC},
+ {vorbis, OMX_AUDIO_CodingVORBIS},
+ {pcm, OMX_AUDIO_CodingPCM},
+ {opus, (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS},
+ {flac, OMX_AUDIO_CodingFLAC},
+ };
+ static const size_t kNumCompToCoding =
+ sizeof(kCompToCoding) / sizeof(kCompToCoding[0]);
+ size_t i;
+ for (i = 0; i < kNumCompToCoding; ++i) {
+ if (kCompToCoding[i].CompName == compName) {
+ eEncoding = kCompToCoding[i].eEncoding;
+ break;
+ }
+ }
+ ASSERT_NE(i, kNumCompToCoding);
+ }
+
+ virtual void TearDown() override {
+ if (omxNode != nullptr) {
+ EXPECT_TRUE((omxNode->freeNode()).isOk());
+ omxNode = nullptr;
+ }
+ }
+
+ enum standardComp {
+ mp3,
+ amrnb,
+ amrwb,
+ aac,
+ vorbis,
+ opus,
+ pcm,
+ flac,
+ unknown_comp,
+ };
+
+ sp<IOmx> omx;
+ sp<CodecObserver> observer;
+ sp<IOmxNode> omxNode;
+ standardComp compName;
+ OMX_AUDIO_CODINGTYPE eEncoding;
+};
+
+void setDefaultPortParam(
+ sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding,
+ int32_t nChannels = 2, int32_t nSampleRate = 44100,
+ OMX_NUMERICALDATATYPE eNumData = OMX_NumericalDataSigned,
+ int32_t nBitPerSample = 16) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_PARAM_PORTDEFINITIONTYPE portDef;
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
+ &portDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+
+ portDef.format.audio.bFlagErrorConcealment = OMX_TRUE;
+ portDef.format.audio.eEncoding = eEncoding;
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
+ &portDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+
+ switch ((int)eEncoding) {
+ case OMX_AUDIO_CodingPCM:
+ setupPCMPort(omxNode, portIndex, nChannels, eNumData, nBitPerSample,
+ nSampleRate);
+ break;
+ default:
+ ASSERT_TRUE(false);
+ break;
+ }
+}
+
+void getInputChannelInfo(sp<IOmxNode> omxNode, OMX_U32 kPortIndexInput,
+ OMX_AUDIO_CODINGTYPE eEncoding, int32_t* nChannels,
+ int32_t* nSampleRate) {
+ *nChannels = 0;
+ *nSampleRate = 0;
+ android::hardware::media::omx::V1_0::Status status;
+
+ switch ((int)eEncoding) {
+ case OMX_AUDIO_CodingPCM: {
+ OMX_AUDIO_PARAM_PCMMODETYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioPcm,
+ kPortIndexInput, &param);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSamplingRate;
+ break;
+ }
+ case OMX_AUDIO_CodingMP3: {
+ OMX_AUDIO_PARAM_MP3TYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioMp3,
+ kPortIndexInput, &param);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSampleRate;
+ break;
+ }
+ case OMX_AUDIO_CodingFLAC: {
+ OMX_AUDIO_PARAM_FLACTYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioFlac,
+ kPortIndexInput, &param);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSampleRate;
+ break;
+ }
+ case OMX_AUDIO_CodingAndroidOPUS: {
+ OMX_AUDIO_PARAM_ANDROID_OPUSTYPE param;
+ status = getPortParam(omxNode,
+ (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus,
+ kPortIndexInput, &param);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSampleRate;
+ break;
+ }
+ case OMX_AUDIO_CodingVORBIS: {
+ OMX_AUDIO_PARAM_VORBISTYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioVorbis,
+ kPortIndexInput, &param);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSampleRate;
+ break;
+ }
+ case OMX_AUDIO_CodingAMR: {
+ OMX_AUDIO_PARAM_AMRTYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioAmr,
+ kPortIndexInput, &param);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = 8000;
+ break;
+ }
+ case OMX_AUDIO_CodingAAC: {
+ OMX_AUDIO_PARAM_AACPROFILETYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioAac,
+ kPortIndexInput, &param);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSampleRate;
+ break;
+ }
+ default:
+ ASSERT_TRUE(false);
+ break;
+ }
+}
+
+void GetURLForComponent(AudioDecHidlTest::standardComp comp, const char** mURL,
+ const char** info) {
+ struct CompToURL {
+ AudioDecHidlTest::standardComp comp;
+ const char* mURL;
+ const char* info;
+ };
+ static const CompToURL kCompToURL[] = {
+ {AudioDecHidlTest::standardComp::mp3,
+ "/sdcard/raw/MP3_48KHz_128kbps_s_1_17_CBR.audio.mp3",
+ "/sdcard/raw/MP3_48KHz_128kbps_s_1_17_CBR.audio.info"},
+ {AudioDecHidlTest::standardComp::aac,
+ "/sdcard/raw/H264_500_AAC_128.audio.aac",
+ "/sdcard/raw/H264_500_AAC_128.audio.info"},
+ {AudioDecHidlTest::standardComp::amrnb,
+ "/sdcard/raw/H264_320_AMRNB_6.audio.amr",
+ "/sdcard/raw/H264_320_AMRNB_6.audio.info"},
+ {AudioDecHidlTest::standardComp::amrwb, "", ""},
+ {AudioDecHidlTest::standardComp::vorbis, "", ""},
+ {AudioDecHidlTest::standardComp::opus, "", ""},
+ {AudioDecHidlTest::standardComp::flac, "", ""},
+ };
+
+ for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
+ if (kCompToURL[i].comp == comp) {
+ *mURL = kCompToURL[i].mURL;
+ *info = kCompToURL[i].info;
+ return;
+ }
+ }
+}
+
+void flushAllPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
+ android::Vector<BufferInfo>* iBuffer,
+ android::Vector<BufferInfo>* oBuffer,
+ OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput) {
+ android::hardware::media::omx::V1_0::Status status;
+ Message msg;
+ // Flush
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
+ kPortIndexInput);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush);
+ ASSERT_EQ(msg.data.eventData.data2, kPortIndexInput);
+ // test if client got all its buffers back
+ for (size_t i = 0; i < iBuffer->size(); ++i) {
+ EXPECT_EQ((*iBuffer)[i].owner, client);
+ }
+
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
+ kPortIndexOutput);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush);
+ ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
+ // test if client got all its buffers back
+ for (size_t i = 0; i < oBuffer->size(); ++i) {
+ EXPECT_EQ((*oBuffer)[i].owner, client);
+ }
+}
+
+void decodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
+ android::Vector<BufferInfo>* iBuffer,
+ android::Vector<BufferInfo>* oBuffer,
+ OMX_AUDIO_CODINGTYPE eEncoding, OMX_U32 kPortIndexInput,
+ OMX_U32 kPortIndexOutput, uint32_t nFrames,
+ std::ifstream& eleStream, std::ifstream& eleInfo) {
+ android::hardware::media::omx::V1_0::Status status;
+ Message msg;
+
+ // dispatch output buffers
+ for (size_t i = 0; i < oBuffer->size(); i++) {
+ dispatchOutputBuffer(omxNode, oBuffer, i);
+ }
+ // dispatch input buffers
+ int bytesCount = 0;
+ for (size_t i = 0; i < iBuffer->size(); i++) {
+ char* ipBuffer = static_cast<char*>(
+ static_cast<void*>((*iBuffer)[i].mMemory->getPointer()));
+ if (!(eleInfo >> bytesCount)) break;
+ eleStream.read(ipBuffer, bytesCount);
+ ASSERT_EQ(eleStream.gcount(), bytesCount);
+ dispatchInputBuffer(omxNode, iBuffer, i, bytesCount, 0, 0);
+ }
+
+ while (nFrames != 0) {
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
+ if (status == android::hardware::media::omx::V1_0::Status::OK &&
+ msg.type == Message::Type::EVENT &&
+ msg.data.eventData.event == OMX_EventPortSettingsChanged) {
+ ASSERT_EQ(msg.data.eventData.data1, kPortIndexOutput);
+
+ status = omxNode->sendCommand(
+ toRawCommandType(OMX_CommandPortDisable), kPortIndexOutput);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer,
+ oBuffer);
+ if (status ==
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT) {
+ for (size_t i = 0; i < oBuffer->size(); ++i) {
+ // test if client got all its buffers back
+ EXPECT_EQ((*oBuffer)[i].owner, client);
+ // free the buffers
+ status =
+ omxNode->freeBuffer(kPortIndexOutput, (*oBuffer)[i].id);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+ }
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ iBuffer, oBuffer);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortDisable);
+ ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
+
+ // Port Reconfigurations
+ int32_t nChannels;
+ int32_t nSampleRate;
+ getInputChannelInfo(omxNode, kPortIndexInput, eEncoding,
+ &nChannels, &nSampleRate);
+ setDefaultPortParam(omxNode, kPortIndexOutput,
+ OMX_AUDIO_CodingPCM, nChannels,
+ nSampleRate);
+
+ // If you can disable a port, then you should be able to enable
+ // it as well
+ status = omxNode->sendCommand(
+ toRawCommandType(OMX_CommandPortEnable), kPortIndexOutput);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+
+ // do not enable the port until all the buffers are supplied
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ iBuffer, oBuffer);
+ ASSERT_EQ(
+ status,
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ iBuffer, oBuffer);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
+ ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
+
+ // dispatch output buffers
+ for (size_t i = 0; i < oBuffer->size(); i++) {
+ dispatchOutputBuffer(omxNode, oBuffer, i);
+ }
+ } else {
+ ASSERT_TRUE(false);
+ }
+ continue;
+ }
+ size_t index = 0;
+ if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) {
+ char* ipBuffer = static_cast<char*>(
+ static_cast<void*>((*iBuffer)[index].mMemory->getPointer()));
+ if (!(eleInfo >> bytesCount)) break;
+ eleStream.read(ipBuffer, bytesCount);
+ ASSERT_EQ(eleStream.gcount(), bytesCount);
+ dispatchInputBuffer(omxNode, iBuffer, index, bytesCount, 0, 0);
+ }
+ if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
+ dispatchOutputBuffer(omxNode, oBuffer, index);
+ }
+ nFrames--;
+ }
+}
+
+// Set Component Role
+TEST_F(AudioDecHidlTest, SetRole) {
+ android::hardware::media::omx::V1_0::Status status;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+// Enumerate Port Format
+TEST_F(AudioDecHidlTest, EnumeratePortFormat) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+ status = setAudioPortFormat(omxNode, kPortIndexInput, eEncoding);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = setAudioPortFormat(omxNode, kPortIndexOutput, OMX_AUDIO_CodingPCM);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+// Decode Test
+TEST_F(AudioDecHidlTest, DecodeTest) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+ const char *mURL = nullptr, *info = nullptr;
+ GetURLForComponent(compName, &mURL, &info);
+ EXPECT_NE(mURL, nullptr);
+ EXPECT_NE(info, nullptr);
+
+ std::ifstream eleStream, eleInfo;
+ eleStream.open(mURL, std::ifstream::binary);
+ ASSERT_EQ(eleStream.is_open(), true);
+ eleInfo.open(info);
+ ASSERT_EQ(eleInfo.is_open(), true);
+
+ if (eEncoding == OMX_AUDIO_CodingPCM)
+ setDefaultPortParam(omxNode, kPortIndexInput, eEncoding);
+ int32_t nChannels;
+ int32_t nSampleRate;
+ getInputChannelInfo(omxNode, kPortIndexInput, eEncoding, &nChannels,
+ &nSampleRate);
+ setDefaultPortParam(omxNode, kPortIndexOutput, OMX_AUDIO_CodingPCM,
+ nChannels, nSampleRate);
+
+ Message msg;
+ android::Vector<BufferInfo> iBuffer, oBuffer;
+
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ allocatePortBuffers(omxNode, &iBuffer, kPortIndexInput);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+ allocatePortBuffers(omxNode, &oBuffer, kPortIndexOutput);
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
+
+ // Port Reconfiguration
+ decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, eEncoding,
+ kPortIndexInput, kPortIndexOutput, (1 << 12), eleStream,
+ eleInfo);
+
+ // flush
+ flushAllPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
+ kPortIndexOutput);
+
+ // set state to Idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // set state to Loaded
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateLoaded);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // dont change state until all buffers are freed
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ for (size_t i = 0; i < iBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexInput, iBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ // dont change state until all buffers are freed
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexOutput, oBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateLoaded);
+
+ eleInfo.close();
+ eleStream.close();
+}
+
+int main(int argc, char** argv) {
+ gEnv = new ComponentTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ }
+ return status;
+}
diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp
new file mode 100644
index 000000000..6a88b1a7b
--- /dev/null
+++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2017 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_TAG "media_omx_hidl_audio_enc_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMapper.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hidl::memory::V1_0::IMapper;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <getopt.h>
+#include <media_audio_hidl_test_common.h>
+#include <media_hidl_test_common.h>
+#include <fstream>
+
+// A class for test environment setup
+class ComponentTestEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ ComponentTestEnvironment() : instance("default") {}
+
+ void setInstance(const char* _instance) { instance = _instance; }
+
+ void setComponent(const char* _component) { component = _component; }
+
+ void setRole(const char* _role) { role = _role; }
+
+ void setQuirks(int _quirks) { quirks = _quirks; }
+
+ const hidl_string getInstance() const { return instance; }
+
+ const hidl_string getComponent() const { return component; }
+
+ const hidl_string getRole() const { return role; }
+
+ int getQuirks() const { return quirks; }
+
+ int initFromOptions(int argc, char** argv) {
+ static struct option options[] = {
+ {"instance", required_argument, 0, 'I'},
+ {"component", required_argument, 0, 'C'},
+ {"role", required_argument, 0, 'R'},
+ {"quirks", required_argument, 0, 'Q'},
+ {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "I:C:Q:R:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'I':
+ setInstance(optarg);
+ break;
+ case 'C':
+ setComponent(optarg);
+ break;
+ case 'Q':
+ setQuirks(atoi(optarg));
+ break;
+ case 'R':
+ setRole(optarg);
+ break;
+ case '?':
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-I, --instance: HAL instance to test\n"
+ "-C, --component: OMX component to test\n"
+ "-R, --Role: OMX component Role\n"
+ "-Q, --quirks: Component quirks\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+ }
+
+ private:
+ hidl_string instance;
+ hidl_string component;
+ hidl_string role;
+ // to be removed when IOmxNode::setQuirks is removed
+ int quirks;
+};
+
+static ComponentTestEnvironment* gEnv = nullptr;
+
+class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ android::hardware::media::omx::V1_0::Status status;
+ omx = ::testing::VtsHalHidlTargetTestBase::getService<IOmx>(
+ gEnv->getInstance());
+ ASSERT_NE(omx, nullptr);
+ observer = new CodecObserver();
+ ASSERT_NE(observer, nullptr);
+ ASSERT_EQ(strncmp(gEnv->getComponent().c_str(), "OMX.", 4), 0)
+ << "Invalid Component Name";
+ EXPECT_TRUE(omx->allocateNode(
+ gEnv->getComponent(), observer,
+ [&](android::hardware::media::omx::V1_0::Status _s,
+ sp<IOmxNode> const& _nl) {
+ status = _s;
+ this->omxNode = _nl;
+ })
+ .isOk());
+ ASSERT_NE(omxNode, nullptr);
+ ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
+ struct StringToName {
+ const char* Name;
+ standardComp CompName;
+ };
+ const StringToName kStringToName[] = {
+ {"mp3", mp3}, {"amrnb", amrnb}, {"amrwb", amrwb},
+ {"aac", aac}, {"vorbis", vorbis}, {"opus", opus},
+ {"pcm", pcm}, {"flac", flac},
+ };
+ const size_t kNumStringToName =
+ sizeof(kStringToName) / sizeof(kStringToName[0]);
+ const char* pch;
+ char substring[OMX_MAX_STRINGNAME_SIZE];
+ strcpy(substring, gEnv->getRole().c_str());
+ pch = strchr(substring, '.');
+ ASSERT_NE(pch, nullptr);
+ compName = unknown_comp;
+ for (size_t i = 0; i < kNumStringToName; ++i) {
+ if (!strcasecmp(pch + 1, kStringToName[i].Name)) {
+ compName = kStringToName[i].CompName;
+ break;
+ }
+ }
+ ASSERT_NE(compName, unknown_comp);
+ struct CompToCoding {
+ standardComp CompName;
+ OMX_AUDIO_CODINGTYPE eEncoding;
+ };
+ static const CompToCoding kCompToCoding[] = {
+ {mp3, OMX_AUDIO_CodingMP3},
+ {amrnb, OMX_AUDIO_CodingAMR},
+ {amrwb, OMX_AUDIO_CodingAMR},
+ {aac, OMX_AUDIO_CodingAAC},
+ {vorbis, OMX_AUDIO_CodingVORBIS},
+ {pcm, OMX_AUDIO_CodingPCM},
+ {opus, (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS},
+ {flac, OMX_AUDIO_CodingFLAC},
+ };
+ static const size_t kNumCompToCoding =
+ sizeof(kCompToCoding) / sizeof(kCompToCoding[0]);
+ size_t i;
+ for (i = 0; i < kNumCompToCoding; ++i) {
+ if (kCompToCoding[i].CompName == compName) {
+ eEncoding = kCompToCoding[i].eEncoding;
+ break;
+ }
+ }
+ ASSERT_NE(i, kNumCompToCoding);
+ }
+
+ virtual void TearDown() override {
+ if (omxNode != nullptr) {
+ EXPECT_TRUE((omxNode->freeNode()).isOk());
+ omxNode = nullptr;
+ }
+ }
+
+ enum standardComp {
+ mp3,
+ amrnb,
+ amrwb,
+ aac,
+ vorbis,
+ opus,
+ pcm,
+ flac,
+ unknown_comp,
+ };
+
+ sp<IOmx> omx;
+ sp<CodecObserver> observer;
+ sp<IOmxNode> omxNode;
+ standardComp compName;
+ OMX_AUDIO_CODINGTYPE eEncoding;
+};
+
+// Set Component Role
+TEST_F(AudioEncHidlTest, SetRole) {
+ android::hardware::media::omx::V1_0::Status status;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+// Enumerate Port Format
+TEST_F(AudioEncHidlTest, EnumeratePortFormat) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+ status = setAudioPortFormat(omxNode, kPortIndexInput, OMX_AUDIO_CodingPCM);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = setAudioPortFormat(omxNode, kPortIndexOutput, eEncoding);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+int main(int argc, char** argv) {
+ gEnv = new ComponentTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ }
+ return status;
+}
diff --git a/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp
new file mode 100644
index 000000000..e01e9aaba
--- /dev/null
+++ b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2017 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_TAG "media_omx_hidl_audio_test_common"
+#include <android-base/logging.h>
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMapper.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hidl::memory::V1_0::IMapper;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <hidlmemory/mapping.h>
+#include <media_audio_hidl_test_common.h>
+#include <media_hidl_test_common.h>
+#include <memory>
+
+void allocatePortBuffers(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ OMX_U32 portIndex) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_PARAM_PORTDEFINITIONTYPE portDef;
+
+ buffArray->clear();
+
+ sp<IAllocator> allocator = IAllocator::getService("ashmem");
+ EXPECT_NE(allocator, nullptr);
+
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
+ &portDef);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ for (size_t i = 0; i < portDef.nBufferCountActual; i++) {
+ BufferInfo buffer;
+ buffer.owner = client;
+ buffer.omxBuffer.type = CodecBuffer::Type::SHARED_MEM;
+ buffer.omxBuffer.attr.preset.rangeOffset = 0;
+ buffer.omxBuffer.attr.preset.rangeLength = 0;
+ bool success;
+ allocator->allocate(
+ portDef.nBufferSize,
+ [&success, &buffer](bool _s,
+ ::android::hardware::hidl_memory const& mem) {
+ success = _s;
+ buffer.omxBuffer.sharedMemory = mem;
+ });
+ ASSERT_EQ(success, true);
+ buffer.mMemory = mapMemory(buffer.omxBuffer.sharedMemory);
+ ASSERT_NE(buffer.mMemory, nullptr);
+ omxNode->useBuffer(
+ portIndex, buffer.omxBuffer,
+ [&status, &buffer](android::hardware::media::omx::V1_0::Status _s,
+ uint32_t id) {
+ status = _s;
+ buffer.id = id;
+ });
+ buffArray->push(buffer);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ }
+}
+
+size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray) {
+ for (size_t i = 0; i < buffArray->size(); i++) {
+ if ((*buffArray)[i].owner == client) return i;
+ }
+ return buffArray->size();
+}
+
+void dispatchInputBuffer(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ size_t bufferIndex, int bytesCount, uint32_t flags,
+ uint64_t timestamp) {
+ android::hardware::media::omx::V1_0::Status status;
+ CodecBuffer t;
+ t.sharedMemory = android::hardware::hidl_memory();
+ t.nativeHandle = android::hardware::hidl_handle();
+ t.type = CodecBuffer::Type::PRESET;
+ t.attr.preset.rangeOffset = 0;
+ t.attr.preset.rangeLength = bytesCount;
+ native_handle_t* fenceNh = native_handle_create(0, 0);
+ ASSERT_NE(fenceNh, nullptr);
+ status = omxNode->emptyBuffer((*buffArray)[bufferIndex].id, t, flags,
+ timestamp, fenceNh);
+ native_handle_close(fenceNh);
+ native_handle_delete(fenceNh);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ buffArray->editItemAt(bufferIndex).owner = component;
+}
+
+void dispatchOutputBuffer(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ size_t bufferIndex) {
+ android::hardware::media::omx::V1_0::Status status;
+ CodecBuffer t;
+ t.sharedMemory = android::hardware::hidl_memory();
+ t.nativeHandle = android::hardware::hidl_handle();
+ t.type = CodecBuffer::Type::PRESET;
+ t.attr.preset.rangeOffset = 0;
+ t.attr.preset.rangeLength = 0;
+ native_handle_t* fenceNh = native_handle_create(0, 0);
+ ASSERT_NE(fenceNh, nullptr);
+ status = omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh);
+ native_handle_close(fenceNh);
+ native_handle_delete(fenceNh);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ buffArray->editItemAt(bufferIndex).owner = component;
+}
+
+Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
+ sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE encoding) {
+ OMX_U32 index = 0;
+ OMX_AUDIO_PARAM_PORTFORMATTYPE portFormat;
+ std::vector<OMX_AUDIO_CODINGTYPE> eEncoding;
+ android::hardware::media::omx::V1_0::Status status;
+
+ while (1) {
+ portFormat.nIndex = index;
+ status = getPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
+ &portFormat);
+ if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
+ eEncoding.push_back(portFormat.eEncoding);
+ index++;
+ if (index == 512) {
+ EXPECT_LE(index, 512U)
+ << "Expecting OMX_ErrorNoMore but not received";
+ break;
+ }
+ }
+ if (!index) return status;
+ for (index = 0; index < eEncoding.size(); index++) {
+ if (eEncoding[index] == encoding) {
+ portFormat.eEncoding = eEncoding[index];
+ break;
+ }
+ }
+ if (index == eEncoding.size()) {
+ ALOGI("setting default Port format");
+ portFormat.eEncoding = eEncoding[0];
+ }
+ // In setParam call nIndex shall be ignored as per omx-il specification.
+ // see how this holds up by corrupting nIndex
+ portFormat.nIndex = RANDOM_INDEX;
+ status = setPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
+ &portFormat);
+ return status;
+}
+
+Return<android::hardware::media::omx::V1_0::Status> setRole(
+ sp<IOmxNode> omxNode, const char* role) {
+ OMX_PARAM_COMPONENTROLETYPE params;
+ strcpy((char*)params.cRole, role);
+ return setParam(omxNode, OMX_IndexParamStandardComponentRole, &params);
+}
+
+void setupPCMPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ OMX_NUMERICALDATATYPE eNumData, int32_t nBitPerSample,
+ int32_t nSamplingRate) {
+ OMX_AUDIO_PARAM_PCMMODETYPE param;
+ android::hardware::media::omx::V1_0::Status status;
+ status = getPortParam(omxNode, OMX_IndexParamAudioPcm, portIndex, &param);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.eNumData = eNumData;
+ param.eEndian = OMX_EndianBig;
+ param.bInterleaved = OMX_TRUE;
+ param.nBitPerSample = nBitPerSample;
+ param.nSamplingRate = nSamplingRate;
+ param.ePCMMode = OMX_AUDIO_PCMModeLinear;
+ switch (nChannels) {
+ case 1:
+ param.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+ break;
+ case 2:
+ param.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+ param.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+ break;
+ default:
+ EXPECT_TRUE(false);
+ }
+ status = setPortParam(omxNode, OMX_IndexParamAudioPcm, portIndex, &param);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupMP3Port(sp<IOmxNode> omxNode, OMX_U32 portIndex,
+ OMX_AUDIO_MP3STREAMFORMATTYPE eFormat, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, bool isEncoder) {
+ if (isEncoder == false) return;
+ OMX_AUDIO_PARAM_MP3TYPE param;
+ android::hardware::media::omx::V1_0::Status status;
+ status = getPortParam(omxNode, OMX_IndexParamAudioMp3, portIndex, &param);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.nBitRate = nBitRate;
+ param.nSampleRate = nSampleRate;
+ param.nAudioBandWidth = 0;
+ param.eChannelMode = (nChannels == 1) ? OMX_AUDIO_ChannelModeMono
+ : OMX_AUDIO_ChannelModeStereo;
+ param.eFormat = eFormat;
+ status = setPortParam(omxNode, OMX_IndexParamAudioMp3, portIndex, &param);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupFLACPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nSampleRate, int32_t nCompressionLevel,
+ bool isEncoder) {
+ if (isEncoder == false) return;
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_AUDIO_PARAM_FLACTYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioFlac, portIndex, &param);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.nSampleRate = nSampleRate;
+ param.nCompressionLevel = nCompressionLevel;
+ status = setPortParam(omxNode, OMX_IndexParamAudioFlac, portIndex, &param);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupOPUSPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, bool isEncoder) {
+ if (isEncoder == false) return;
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_AUDIO_PARAM_ANDROID_OPUSTYPE param;
+ status =
+ getPortParam(omxNode, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus,
+ portIndex, &param);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.nBitRate = nBitRate;
+ param.nSampleRate = nSampleRate;
+ status =
+ setPortParam(omxNode, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus,
+ portIndex, &param);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupAMRPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nBitRate,
+ OMX_AUDIO_AMRBANDMODETYPE eAMRBandMode, bool isEncoder) {
+ if (isEncoder == false) return;
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_AUDIO_PARAM_AMRTYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioAmr, portIndex, &param);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = 1;
+ param.nBitRate = nBitRate;
+ param.eAMRBandMode = eAMRBandMode;
+ status = setPortParam(omxNode, OMX_IndexParamAudioAmr, portIndex, &param);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupVORBISPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, int32_t nQuality,
+ bool isEncoder) {
+ if (isEncoder == false) return;
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_AUDIO_PARAM_VORBISTYPE param;
+ status =
+ getPortParam(omxNode, OMX_IndexParamAudioVorbis, portIndex, &param);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.nBitRate = nBitRate;
+ param.nSampleRate = nSampleRate;
+ param.nQuality = nQuality;
+ status =
+ setPortParam(omxNode, OMX_IndexParamAudioVorbis, portIndex, &param);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupAACPort(sp<IOmxNode> omxNode, OMX_U32 portIndex,
+ OMX_AUDIO_AACPROFILETYPE eAACProfile,
+ OMX_AUDIO_AACSTREAMFORMATTYPE eAACStreamFormat,
+ int32_t nChannels, int32_t nBitRate, int32_t nSampleRate,
+ bool isEncoder) {
+ if (isEncoder == false) return;
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_AUDIO_PARAM_AACPROFILETYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioAac, portIndex, &param);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.nSampleRate = nSampleRate;
+ param.nBitRate = nBitRate;
+ param.eAACProfile = eAACProfile;
+ param.eAACStreamFormat = eAACStreamFormat;
+ param.eChannelMode = (nChannels == 1) ? OMX_AUDIO_ChannelModeMono
+ : OMX_AUDIO_ChannelModeStereo;
+ status = setPortParam(omxNode, OMX_IndexParamAudioAac, portIndex, &param);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
diff --git a/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.h b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.h
new file mode 100644
index 000000000..bdf5d52d4
--- /dev/null
+++ b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016, 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 MEDIA_AUDIO_HIDL_TEST_COMMON_H
+#define MEDIA_AUDIO_HIDL_TEST_COMMON_H
+
+#include <media_hidl_test_common.h>
+/*
+ * Random Index used for monkey testing while get/set parameters
+ */
+#define RANDOM_INDEX 1729
+
+/*
+ * Common audio utils
+ */
+void allocatePortBuffers(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ OMX_U32 portIndex);
+
+size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray);
+
+void dispatchInputBuffer(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ size_t bufferIndex, int bytesCount, uint32_t flags,
+ uint64_t timestamp);
+
+void dispatchOutputBuffer(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ size_t bufferIndex);
+
+Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
+ sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE encoding);
+
+Return<android::hardware::media::omx::V1_0::Status> setRole(
+ sp<IOmxNode> omxNode, const char* role);
+
+void setupPCMPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ OMX_NUMERICALDATATYPE eNumData, int32_t nBitPerSample,
+ int32_t nSamplingRate);
+
+void setupMP3Port(sp<IOmxNode> omxNode, OMX_U32 portIndex,
+ OMX_AUDIO_MP3STREAMFORMATTYPE eFormat, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, bool isEncoder);
+
+void setupFLACPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nSampleRate, int32_t nCompressionLevel,
+ bool isEncoder);
+
+void setupOPUSPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, bool isEncoder);
+
+void setupAMRPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nBitRate,
+ OMX_AUDIO_AMRBANDMODETYPE eAMRBandMode, bool isEncoder);
+
+void setupVORBISPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, int32_t nQuality,
+ bool isEncoder);
+
+void setupAACPort(sp<IOmxNode> omxNode, OMX_U32 portIndex,
+ OMX_AUDIO_AACPROFILETYPE eAACProfile,
+ OMX_AUDIO_AACSTREAMFORMATTYPE eAACStreamFormat,
+ int32_t nChannels, int32_t nBitRate, int32_t nSampleRate,
+ bool isEncoder);
+
+#endif // MEDIA_AUDIO_HIDL_TEST_COMMON_H
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
new file mode 100644
index 000000000..942146396
--- /dev/null
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2016, 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 MEDIA_HIDL_TEST_COMMON_H
+#define MEDIA_HIDL_TEST_COMMON_H
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <utils/Condition.h>
+#include <utils/List.h>
+#include <utils/Mutex.h>
+
+#include <media/openmax/OMX_Index.h>
+#include <media/openmax/OMX_Core.h>
+#include <media/openmax/OMX_Component.h>
+#include <media/openmax/OMX_IndexExt.h>
+#include <media/openmax/OMX_AudioExt.h>
+
+/*
+ * TODO: Borrowed from Conversion.h. This is not the ideal way to do it.
+ * Loose these definitions once you include Conversion.h
+ */
+inline uint32_t toRawIndexType(OMX_INDEXTYPE l) {
+ return static_cast<uint32_t>(l);
+}
+
+inline android::hardware::media::omx::V1_0::Status toStatus(
+ android::status_t l) {
+ return static_cast<android::hardware::media::omx::V1_0::Status>(l);
+}
+
+inline hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) {
+ hidl_vec<uint8_t> t;
+ t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false);
+ return t;
+}
+
+inline uint32_t toRawCommandType(OMX_COMMANDTYPE l) {
+ return static_cast<uint32_t>(l);
+}
+
+/*
+ * Handle Callback functions EmptythisBuffer(), FillthisBuffer(),
+ * EventHandler()
+ */
+#define DEFAULT_TIMEOUT 40000
+
+enum bufferOwner {
+ client,
+ component,
+ unknown,
+};
+
+struct BufferInfo {
+ uint32_t id;
+ bufferOwner owner;
+ android::hardware::media::omx::V1_0::CodecBuffer omxBuffer;
+ ::android::sp<IMemory> mMemory;
+};
+
+struct CodecObserver : public IOmxObserver {
+ public:
+ Return<void> onMessages(const hidl_vec<Message>& messages) override {
+ android::Mutex::Autolock autoLock(msgLock);
+ for (hidl_vec<Message>::const_iterator it = messages.begin();
+ it != messages.end(); ++it) {
+ msgQueue.push_back(*it);
+ }
+ msgCondition.signal();
+ return Void();
+ }
+ android::hardware::media::omx::V1_0::Status dequeueMessage(
+ Message* msg, int64_t timeoutUs,
+ android::Vector<BufferInfo>* iBuffers = nullptr,
+ android::Vector<BufferInfo>* oBuffers = nullptr) {
+ int64_t finishBy = android::ALooper::GetNowUs() + timeoutUs;
+ for (;;) {
+ android::Mutex::Autolock autoLock(msgLock);
+ android::List<Message>::iterator it = msgQueue.begin();
+ while (it != msgQueue.end()) {
+ if (it->type ==
+ android::hardware::media::omx::V1_0::Message::Type::EVENT) {
+ *msg = *it;
+ msgQueue.erase(it);
+ return ::android::hardware::media::omx::V1_0::Status::OK;
+ } else if (it->type == android::hardware::media::omx::V1_0::
+ Message::Type::FILL_BUFFER_DONE) {
+ if (oBuffers) {
+ size_t i;
+ for (i = 0; i < oBuffers->size(); ++i) {
+ if ((*oBuffers)[i].id ==
+ it->data.bufferData.buffer) {
+ oBuffers->editItemAt(i).owner = client;
+ msgQueue.erase(it);
+ break;
+ }
+ }
+ EXPECT_LE(i, oBuffers->size());
+ }
+ } else if (it->type == android::hardware::media::omx::V1_0::
+ Message::Type::EMPTY_BUFFER_DONE) {
+ if (iBuffers) {
+ size_t i;
+ for (i = 0; i < iBuffers->size(); ++i) {
+ if ((*iBuffers)[i].id ==
+ it->data.bufferData.buffer) {
+ iBuffers->editItemAt(i).owner = client;
+ msgQueue.erase(it);
+ break;
+ }
+ }
+ EXPECT_LE(i, iBuffers->size());
+ }
+ }
+ ++it;
+ }
+ android::status_t err =
+ (timeoutUs < 0)
+ ? msgCondition.wait(msgLock)
+ : msgCondition.waitRelative(
+ msgLock,
+ (finishBy - android::ALooper::GetNowUs()) * 1000);
+ if (err == android::TIMED_OUT) return toStatus(err);
+ }
+ }
+
+ android::List<Message> msgQueue;
+ android::Mutex msgLock;
+ android::Condition msgCondition;
+};
+
+/*
+ * Useful Wrapper utilities
+ */
+template <class T>
+void InitOMXParams(T* params) {
+ params->nSize = sizeof(T);
+ params->nVersion.s.nVersionMajor = 1;
+ params->nVersion.s.nVersionMinor = 0;
+ params->nVersion.s.nRevision = 0;
+ params->nVersion.s.nStep = 0;
+}
+
+template <class T>
+Return<android::hardware::media::omx::V1_0::Status> getParam(
+ sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, T* params) {
+ android::hardware::media::omx::V1_0::Status status;
+ InitOMXParams(params);
+ omxNode->getParameter(
+ toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)),
+ [&status, &params](android::hardware::media::omx::V1_0::Status _s,
+ hidl_vec<uint8_t> const& outParams) {
+ status = _s;
+ std::copy(outParams.data(), outParams.data() + outParams.size(),
+ static_cast<uint8_t*>(static_cast<void*>(params)));
+ });
+ return status;
+}
+
+template <class T>
+Return<android::hardware::media::omx::V1_0::Status> setParam(
+ sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, T* params) {
+ InitOMXParams(params);
+ return omxNode->setParameter(toRawIndexType(omxIdx),
+ inHidlBytes(params, sizeof(*params)));
+}
+
+template <class T>
+Return<android::hardware::media::omx::V1_0::Status> getPortParam(
+ sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) {
+ android::hardware::media::omx::V1_0::Status status;
+ InitOMXParams(params);
+ params->nPortIndex = nPortIndex;
+ omxNode->getParameter(
+ toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)),
+ [&status, &params](android::hardware::media::omx::V1_0::Status _s,
+ hidl_vec<uint8_t> const& outParams) {
+ status = _s;
+ std::copy(outParams.data(), outParams.data() + outParams.size(),
+ static_cast<uint8_t*>(static_cast<void*>(params)));
+ });
+ return status;
+}
+
+template <class T>
+Return<android::hardware::media::omx::V1_0::Status> setPortParam(
+ sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) {
+ InitOMXParams(params);
+ params->nPortIndex = nPortIndex;
+ return omxNode->setParameter(toRawIndexType(omxIdx),
+ inHidlBytes(params, sizeof(*params)));
+}
+
+#endif // MEDIA_HIDL_TEST_COMMON_H
diff --git a/media/omx/1.0/vts/functional/component/Android.bp b/media/omx/1.0/vts/functional/component/Android.bp
new file mode 100644
index 000000000..02fe18283
--- /dev/null
+++ b/media/omx/1.0/vts/functional/component/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2017 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: "VtsHalMediaOmxV1_0TargetComponentTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalMediaOmxV1_0TargetComponentTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libnativehelper",
+ "libutils",
+ "libstagefright_foundation",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "android.hardware.media.omx@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+ include_dirs: [
+ "frameworks/native/include/media/openmax/",
+ "hardware/interfaces/media/omx/1.0/vts/functional/common",
+ ],
+}
+
diff --git a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
new file mode 100644
index 000000000..fdffd661d
--- /dev/null
+++ b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
@@ -0,0 +1,1213 @@
+/*
+ * Copyright (C) 2017 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_TAG "media_omx_hidl_component_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMapper.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hidl::memory::V1_0::IMapper;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <getopt.h>
+#include <media_hidl_test_common.h>
+
+// A class for test environment setup
+class ComponentTestEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ ComponentTestEnvironment() : instance("default") {}
+
+ void setInstance(const char* _instance) { instance = _instance; }
+
+ void setComponent(const char* _component) { component = _component; }
+
+ void setRole(const char* _role) { role = _role; }
+
+ void setQuirks(int _quirks) { quirks = _quirks; }
+
+ const hidl_string getInstance() const { return instance; }
+
+ const hidl_string getComponent() const { return component; }
+
+ const hidl_string getRole() const { return role; }
+
+ int getQuirks() const { return quirks; }
+
+ int initFromOptions(int argc, char** argv) {
+ static struct option options[] = {
+ {"instance", required_argument, 0, 'I'},
+ {"component", required_argument, 0, 'C'},
+ {"role", required_argument, 0, 'R'},
+ {"quirks", required_argument, 0, 'Q'},
+ {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "I:C:Q:R:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'I':
+ setInstance(optarg);
+ break;
+ case 'C':
+ setComponent(optarg);
+ break;
+ case 'Q':
+ setQuirks(atoi(optarg));
+ break;
+ case 'R':
+ setRole(optarg);
+ break;
+ case '?':
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-I, --instance: HAL instance to test\n"
+ "-C, --component: OMX component to test\n"
+ "-R, --Role: OMX component Role\n"
+ "-Q, --quirks: Component quirks\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+ }
+
+ private:
+ hidl_string instance;
+ hidl_string component;
+ hidl_string role;
+ // to be removed when IOmxNode::setQuirks is removed
+ int quirks;
+};
+
+static ComponentTestEnvironment* gEnv = nullptr;
+
+class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ android::hardware::media::omx::V1_0::Status status;
+ omx = ::testing::VtsHalHidlTargetTestBase::getService<IOmx>(
+ gEnv->getInstance());
+ ASSERT_NE(omx, nullptr);
+ observer = new CodecObserver();
+ ASSERT_NE(observer, nullptr);
+ ASSERT_EQ(strncmp(gEnv->getComponent().c_str(), "OMX.", 4), 0)
+ << "Invalid Component Name";
+ EXPECT_TRUE(omx->allocateNode(
+ gEnv->getComponent(), observer,
+ [&](android::hardware::media::omx::V1_0::Status _s,
+ sp<IOmxNode> const& _nl) {
+ status = _s;
+ this->omxNode = _nl;
+ })
+ .isOk());
+ ASSERT_NE(omxNode, nullptr);
+ ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
+ struct StringToClass {
+ const char* Class;
+ standardCompClass CompClass;
+ };
+ const StringToClass kStringToClass[] = {
+ {"audio_decoder", audio_decoder},
+ {"audio_encoder", audio_encoder},
+ {"video_decoder", video_decoder},
+ {"video_encoder", video_encoder},
+ };
+ const size_t kNumStringToClass =
+ sizeof(kStringToClass) / sizeof(kStringToClass[0]);
+ const char* pch;
+ char substring[OMX_MAX_STRINGNAME_SIZE];
+ strcpy(substring, gEnv->getRole().c_str());
+ pch = strchr(substring, '.');
+ ASSERT_NE(pch, nullptr) << "Invalid Component Role";
+ substring[pch - substring] = '\0';
+ compClass = unknown_class;
+ for (size_t i = 0; i < kNumStringToClass; ++i) {
+ if (!strcasecmp(substring, kStringToClass[i].Class)) {
+ compClass = kStringToClass[i].CompClass;
+ break;
+ }
+ }
+ ASSERT_NE(compClass, unknown_class) << "Invalid Component Class";
+
+ allocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(
+ "ashmem");
+ ASSERT_NE(allocator, nullptr);
+ }
+
+ virtual void TearDown() override {
+ if (omxNode != nullptr) {
+ EXPECT_TRUE((omxNode->freeNode()).isOk());
+ omxNode = nullptr;
+ }
+ }
+
+ enum standardCompClass {
+ audio_decoder,
+ audio_encoder,
+ video_decoder,
+ video_encoder,
+ unknown_class,
+ };
+
+ sp<IOmx> omx;
+ sp<CodecObserver> observer;
+ sp<IOmxNode> omxNode;
+ sp<IAllocator> allocator;
+ standardCompClass compClass;
+};
+
+#define RANDOM_INDEX 1729
+
+void allocatePortBuffers(sp<IOmxNode> omxNode, sp<IAllocator> allocator,
+ android::Vector<BufferInfo>* buffArray,
+ OMX_U32 portIndex) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_PARAM_PORTDEFINITIONTYPE portDef;
+
+ buffArray->clear();
+
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
+ &portDef);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ for (size_t i = 0; i < portDef.nBufferCountActual; i++) {
+ BufferInfo buffer;
+ buffer.owner = client;
+ buffer.omxBuffer.type = CodecBuffer::Type::SHARED_MEM;
+ buffer.omxBuffer.attr.preset.rangeOffset = 0;
+ buffer.omxBuffer.attr.preset.rangeLength = 0;
+ bool success;
+ allocator->allocate(
+ portDef.nBufferSize,
+ [&success, &buffer](bool _s,
+ ::android::hardware::hidl_memory const& mem) {
+ success = _s;
+ buffer.omxBuffer.sharedMemory = mem;
+ });
+ ASSERT_EQ(success, true);
+
+ omxNode->useBuffer(
+ portIndex, buffer.omxBuffer,
+ [&status, &buffer](android::hardware::media::omx::V1_0::Status _s,
+ uint32_t id) {
+ status = _s;
+ buffer.id = id;
+ });
+ buffArray->push(buffer);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ }
+}
+
+Return<android::hardware::media::omx::V1_0::Status> setVideoPortFormat(
+ sp<IOmxNode> omxNode, OMX_U32 portIndex,
+ OMX_VIDEO_CODINGTYPE compressionFormat, OMX_COLOR_FORMATTYPE colorFormat,
+ OMX_U32 frameRate) {
+ OMX_U32 index = 0;
+ OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
+ std::vector<OMX_COLOR_FORMATTYPE> eColorFormat;
+ std::vector<OMX_VIDEO_CODINGTYPE> eCompressionFormat;
+ android::hardware::media::omx::V1_0::Status status;
+
+ while (1) {
+ portFormat.nIndex = index;
+ status = getPortParam(omxNode, OMX_IndexParamVideoPortFormat, portIndex,
+ &portFormat);
+ if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
+ if (compressionFormat == OMX_VIDEO_CodingUnused)
+ eColorFormat.push_back(portFormat.eColorFormat);
+ else
+ eCompressionFormat.push_back(portFormat.eCompressionFormat);
+ index++;
+ if (index == 512) {
+ EXPECT_LE(index, 512U)
+ << "Expecting OMX_ErrorNoMore but not received";
+ break;
+ }
+ }
+ if (!index) return status;
+ if (compressionFormat == OMX_VIDEO_CodingUnused) {
+ for (index = 0; index < eColorFormat.size(); index++) {
+ if (eColorFormat[index] == colorFormat) {
+ portFormat.eColorFormat = eColorFormat[index];
+ break;
+ }
+ }
+ if (index == eColorFormat.size()) {
+ ALOGI("setting default color format");
+ portFormat.eColorFormat = eColorFormat[0];
+ }
+ portFormat.eCompressionFormat = OMX_VIDEO_CodingUnused;
+ } else {
+ for (index = 0; index < eCompressionFormat.size(); index++) {
+ if (eCompressionFormat[index] == compressionFormat) {
+ portFormat.eCompressionFormat = eCompressionFormat[index];
+ break;
+ }
+ }
+ if (index == eCompressionFormat.size()) {
+ ALOGI("setting default compression format");
+ portFormat.eCompressionFormat = eCompressionFormat[0];
+ }
+ portFormat.eColorFormat = OMX_COLOR_FormatUnused;
+ }
+ // In setParam call nIndex shall be ignored as per omx-il specification.
+ // see how this holds up by corrupting nIndex
+ portFormat.nIndex = RANDOM_INDEX;
+ portFormat.xFramerate = frameRate;
+ status = setPortParam(omxNode, OMX_IndexParamVideoPortFormat, portIndex,
+ &portFormat);
+ return status;
+}
+
+Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
+ sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE encoding) {
+ OMX_U32 index = 0;
+ OMX_AUDIO_PARAM_PORTFORMATTYPE portFormat;
+ std::vector<OMX_AUDIO_CODINGTYPE> eEncoding;
+ android::hardware::media::omx::V1_0::Status status;
+
+ while (1) {
+ portFormat.nIndex = index;
+ status = getPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
+ &portFormat);
+ if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
+ eEncoding.push_back(portFormat.eEncoding);
+ index++;
+ if (index == 512) {
+ EXPECT_LE(index, 512U)
+ << "Expecting OMX_ErrorNoMore but not received";
+ break;
+ }
+ }
+ if (!index) return status;
+ for (index = 0; index < eEncoding.size(); index++) {
+ if (eEncoding[index] == encoding) {
+ portFormat.eEncoding = eEncoding[index];
+ break;
+ }
+ }
+ if (index == eEncoding.size()) {
+ ALOGI("setting default Port format");
+ portFormat.eEncoding = eEncoding[0];
+ }
+ // In setParam call nIndex shall be ignored as per omx-il specification.
+ // see how this holds up by corrupting nIndex
+ portFormat.nIndex = RANDOM_INDEX;
+ status = setPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
+ &portFormat);
+ return status;
+}
+
+Return<android::hardware::media::omx::V1_0::Status> setRole(
+ sp<IOmxNode> omxNode, const char* role) {
+ OMX_PARAM_COMPONENTROLETYPE params;
+ strcpy((char*)params.cRole, role);
+ return setParam(omxNode, OMX_IndexParamStandardComponentRole, &params);
+}
+
+// Set Component Role
+TEST_F(ComponentHidlTest, SetRole) {
+ android::hardware::media::omx::V1_0::Status status;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+// Get Number of Ports and their Indices for all Domains
+// (Audio/Video/Image/Other)
+TEST_F(ComponentHidlTest, GetPortIndices) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_PORT_PARAM_TYPE params;
+
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+
+ // All standard OMX components shall support following OMX Index types
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = getParam(omxNode, OMX_IndexParamImageInit, &params);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = getParam(omxNode, OMX_IndexParamOtherInit, &params);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+// Enumerate Port Format
+TEST_F(ComponentHidlTest, EnumeratePortFormat) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+
+ OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420Planar;
+ OMX_U32 frameRate = 24 << 16;
+
+ if (compClass == audio_encoder) {
+ status =
+ setAudioPortFormat(omxNode, kPortIndexInput, OMX_AUDIO_CodingPCM);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = setAudioPortFormat(omxNode, kPortIndexOutput,
+ OMX_AUDIO_CodingAutoDetect);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ } else if (compClass == audio_decoder) {
+ status = setAudioPortFormat(omxNode, kPortIndexInput,
+ OMX_AUDIO_CodingAutoDetect);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ setAudioPortFormat(omxNode, kPortIndexOutput, OMX_AUDIO_CodingPCM);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ } else if (compClass == video_encoder) {
+ status =
+ setVideoPortFormat(omxNode, kPortIndexInput, OMX_VIDEO_CodingUnused,
+ colorFormat, frameRate);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = setVideoPortFormat(omxNode, kPortIndexOutput,
+ OMX_VIDEO_CodingAutoDetect,
+ OMX_COLOR_FormatUnused, 0U);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ } else {
+ status = setVideoPortFormat(omxNode, kPortIndexInput,
+ OMX_VIDEO_CodingAutoDetect,
+ OMX_COLOR_FormatUnused, 0U);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ setVideoPortFormat(omxNode, kPortIndexOutput,
+ OMX_VIDEO_CodingUnused, colorFormat, frameRate);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ }
+}
+
+// r/w default i/o port parameters
+TEST_F(ComponentHidlTest, SetDefaultPortParams) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+
+ OMX_PARAM_PORTDEFINITIONTYPE iPortDef;
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexInput, &iPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+
+ if (status == android::hardware::media::omx::V1_0::Status::OK) {
+ EXPECT_EQ(iPortDef.eDir, OMX_DirInput);
+ EXPECT_EQ(iPortDef.bEnabled, OMX_TRUE);
+ EXPECT_EQ(iPortDef.bPopulated, 0);
+ EXPECT_GE(iPortDef.nBufferCountMin, 1U);
+ EXPECT_GE(iPortDef.nBufferCountActual, iPortDef.nBufferCountMin);
+ if (compClass == audio_encoder || compClass == audio_decoder) {
+ EXPECT_EQ(iPortDef.eDomain, OMX_PortDomainAudio);
+ if (compClass == audio_decoder) {
+ iPortDef.format.audio.bFlagErrorConcealment = OMX_TRUE;
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexInput, &iPortDef);
+ }
+ EXPECT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ } else if (compClass == video_encoder || compClass == video_decoder) {
+ EXPECT_EQ(iPortDef.eDomain, OMX_PortDomainVideo);
+ }
+ OMX_PARAM_PORTDEFINITIONTYPE dummy = iPortDef;
+ iPortDef.nBufferCountActual = iPortDef.nBufferCountMin - 1;
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexInput, &iPortDef);
+ EXPECT_NE(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ // Edit Read-Only fields.
+ iPortDef.eDir = OMX_DirOutput; // Read Only field
+ iPortDef.nBufferCountActual = dummy.nBufferCountActual << 1;
+ iPortDef.nBufferCountMin = dummy.nBufferCountMin
+ << 1; // Read Only field
+ iPortDef.nBufferSize = dummy.nBufferSize << 1; // Read Only field
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexInput, &iPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexInput, &iPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ EXPECT_EQ(iPortDef.nBufferCountActual, dummy.nBufferCountActual << 1);
+ if ((iPortDef.eDir != OMX_DirInput) ||
+ (iPortDef.nBufferCountMin != dummy.nBufferCountMin) ||
+ (iPortDef.nBufferSize != dummy.nBufferSize)) {
+ ALOGI(
+ "Warning, Component does not seem to preserve Read-Only "
+ "fields");
+ printf(
+ "Warning, Component does not seem to preserve Read-Only fields "
+ "\n");
+ }
+ }
+
+ OMX_PARAM_PORTDEFINITIONTYPE oPortDef;
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexOutput, &oPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ EXPECT_EQ(oPortDef.eDir, OMX_DirOutput);
+ EXPECT_EQ(oPortDef.bEnabled, OMX_TRUE);
+ EXPECT_EQ(oPortDef.bPopulated, 0);
+ EXPECT_GE(oPortDef.nBufferCountMin, 1U);
+ EXPECT_GE(oPortDef.nBufferCountActual, oPortDef.nBufferCountMin);
+ if (compClass == audio_encoder || compClass == audio_decoder) {
+ EXPECT_EQ(oPortDef.eDomain, OMX_PortDomainAudio);
+ if (compClass == audio_encoder) {
+ oPortDef.format.audio.bFlagErrorConcealment = OMX_TRUE;
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexOutput, &oPortDef);
+ }
+ EXPECT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ } else if (compClass == video_encoder || compClass == video_decoder) {
+ EXPECT_EQ(oPortDef.eDomain, OMX_PortDomainVideo);
+ }
+ OMX_PARAM_PORTDEFINITIONTYPE dummy = oPortDef;
+ oPortDef.nBufferCountActual = oPortDef.nBufferCountMin - 1;
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexOutput, &oPortDef);
+ EXPECT_NE(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ // Edit Read-Only fields.
+ oPortDef.eDir = OMX_DirInput; // Read Only field
+ oPortDef.nBufferCountActual = dummy.nBufferCountActual << 1;
+ oPortDef.nBufferCountMin = dummy.nBufferCountMin
+ << 1; // Read Only field
+ oPortDef.nBufferSize = dummy.nBufferSize << 1; // Read Only field
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexOutput, &oPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexOutput, &oPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ EXPECT_EQ(oPortDef.nBufferCountActual, dummy.nBufferCountActual << 1);
+ if ((oPortDef.eDir != OMX_DirOutput) ||
+ (oPortDef.nBufferCountMin != dummy.nBufferCountMin) ||
+ (oPortDef.nBufferSize != dummy.nBufferSize)) {
+ ALOGI(
+ "Warning, Component does not seem to preserve Read-Only "
+ "fields");
+ printf(
+ "Warning, Component does not seem to preserve Read-Only fields "
+ "\n");
+ }
+ }
+}
+
+// Test State Transitions & Flush
+TEST_F(ComponentHidlTest, StateTransitions_Flush) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ Message msg;
+
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+
+ android::Vector<BufferInfo> iBuffer, oBuffer;
+
+ // set state to idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // Dont switch states until the ports got their buffers
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ // allocate buffers on input port
+ allocatePortBuffers(omxNode, allocator, &iBuffer, kPortIndexInput);
+
+ // Dont switch states until the ports got their buffers
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ // allocate buffers on output port
+ allocatePortBuffers(omxNode, allocator, &oBuffer, kPortIndexOutput);
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // set state to executing
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
+
+ CodecBuffer t;
+ t.sharedMemory = android::hardware::hidl_memory();
+ t.nativeHandle = android::hardware::hidl_handle();
+ t.type = CodecBuffer::Type::PRESET;
+ t.attr.preset.rangeOffset = 0;
+ t.attr.preset.rangeLength = 0;
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ native_handle_t* fenceNh = native_handle_create(0, 0);
+ status = omxNode->fillBuffer(oBuffer[i].id, t, fenceNh);
+ native_handle_close(fenceNh);
+ native_handle_delete(fenceNh);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ oBuffer.editItemAt(i).owner = component;
+ }
+
+ // set state to Idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // test if client got all its buffers back
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ EXPECT_EQ(oBuffer[i].owner, client);
+ }
+
+ // set state to executing
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
+
+ for (size_t i = 0; i < oBuffer.size(); i += 2) {
+ native_handle_t* fenceNh = native_handle_create(0, 0);
+ status = omxNode->fillBuffer(oBuffer[i].id, t, fenceNh);
+ native_handle_close(fenceNh);
+ native_handle_delete(fenceNh);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ oBuffer.editItemAt(i).owner = component;
+ }
+
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
+ kPortIndexOutput);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush);
+ ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
+
+ // test if client got all its buffers back
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ EXPECT_EQ(oBuffer[i].owner, client);
+ }
+
+ // set state to Idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // set state to Loaded
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateLoaded);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // dont change state until all buffers are freed
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ for (size_t i = 0; i < iBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexInput, iBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ // dont change state until all buffers are freed
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexOutput, oBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateLoaded);
+}
+
+// Test State Transitions
+TEST_F(ComponentHidlTest, StateTransitions_M) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ Message msg;
+
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+
+ android::Vector<BufferInfo> iBuffer, oBuffer;
+
+ // set state to loaded ; receive error OMX_ErrorSameState
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateLoaded);
+ EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // set state to executing ; receive error OMX_ErrorIncorrectStateTransition
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // set state to idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // allocate buffers on i/o port
+ allocatePortBuffers(omxNode, allocator, &iBuffer, kPortIndexInput);
+ allocatePortBuffers(omxNode, allocator, &oBuffer, kPortIndexOutput);
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // set state to idle ; receive error OMX_ErrorSameState
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // set state to executing
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
+
+ // set state to executing ; receive error OMX_ErrorSameState
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // set state to Loaded ; receive error OMX_ErrorIncorrectStateTransition
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateLoaded);
+ EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // set state to Idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // set state to Loaded
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateLoaded);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ for (size_t i = 0; i < iBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexInput, iBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexOutput, oBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateLoaded);
+}
+
+// Enable and Disable Input and Output ports when the component is in Loaded
+// State
+TEST_F(ComponentHidlTest, PortEnableDisable_Loaded) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_U32 portBase = 0;
+ Message msg;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ portBase = params.nStartPortNumber;
+ }
+
+ for (size_t i = portBase; i < portBase + 2; i++) {
+ status =
+ omxNode->sendCommand(toRawCommandType(OMX_CommandPortDisable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ if (msg.data.eventData.event == OMX_EventCmdComplete) {
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortDisable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+ // If you can disable a port, then you should be able to enable it
+ // as well
+ status = omxNode->sendCommand(
+ toRawCommandType(OMX_CommandPortEnable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+ } else if (msg.data.eventData.event == OMX_EventError) {
+ ALOGI("Port %d Disabling failed with error %d", (int)i,
+ (int)msg.data.eventData.event);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ }
+}
+
+// Enable and Disable Input and Output ports when the component is in Idle State
+TEST_F(ComponentHidlTest, PortEnableDisable_Idle) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ OMX_U32 portBase = 0;
+ Message msg;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ portBase = params.nStartPortNumber;
+ }
+ kPortIndexInput = portBase;
+ kPortIndexOutput = portBase + 1;
+
+ // Component State :: Idle
+ android::Vector<BufferInfo> pBuffer[2];
+ // set state to idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // allocate buffers on input port
+ allocatePortBuffers(omxNode, allocator, &pBuffer[0], kPortIndexInput);
+ allocatePortBuffers(omxNode, allocator, &pBuffer[1], kPortIndexOutput);
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0],
+ &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ for (size_t i = portBase; i < portBase + 2; i++) {
+ status =
+ omxNode->sendCommand(toRawCommandType(OMX_CommandPortDisable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0],
+ &pBuffer[1]);
+ if (status == android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ if (msg.data.eventData.event == OMX_EventCmdComplete) {
+ // do not disable the port until all the buffers are freed
+ ASSERT_TRUE(false);
+ } else if (msg.data.eventData.event == OMX_EventError) {
+ ALOGI("Port %d Disabling failed with error %d", (int)i,
+ (int)msg.data.eventData.event);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ } else if (status ==
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT) {
+ for (size_t j = 0; j < pBuffer[i - portBase].size(); ++j) {
+ status = omxNode->freeBuffer(i, pBuffer[i - portBase][j].id);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortDisable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+
+ // If you can disable a port, then you should be able to enable it
+ // as well
+ status = omxNode->sendCommand(
+ toRawCommandType(OMX_CommandPortEnable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // do not enable the port until all the buffers are supplied
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ allocatePortBuffers(omxNode, allocator, &pBuffer[i - portBase], i);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ }
+}
+
+// Enable and Disable Input and Output ports when the component is in execute
+TEST_F(ComponentHidlTest, PortEnableDisable_Execute) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ OMX_U32 portBase = 0;
+ Message msg;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ portBase = params.nStartPortNumber;
+ }
+ kPortIndexInput = portBase;
+ kPortIndexOutput = portBase + 1;
+
+ // Component State :: Idle
+ android::Vector<BufferInfo> pBuffer[2];
+ // set state to idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // allocate buffers on input port
+ allocatePortBuffers(omxNode, allocator, &pBuffer[0], kPortIndexInput);
+ allocatePortBuffers(omxNode, allocator, &pBuffer[1], kPortIndexOutput);
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0],
+ &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // Component State :: Execute
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0],
+ &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
+
+ CodecBuffer t;
+ t.sharedMemory = android::hardware::hidl_memory();
+ t.nativeHandle = android::hardware::hidl_handle();
+ t.type = CodecBuffer::Type::PRESET;
+ t.attr.preset.rangeOffset = 0;
+ t.attr.preset.rangeLength = 0;
+ for (size_t i = 0; i < pBuffer[1].size(); ++i) {
+ native_handle_t* fenceNh = native_handle_create(0, 0);
+ status = omxNode->fillBuffer(pBuffer[1][i].id, t, fenceNh);
+ native_handle_close(fenceNh);
+ native_handle_delete(fenceNh);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ pBuffer[1].editItemAt(i).owner = component;
+ }
+
+ for (size_t i = portBase; i < portBase + 2; i++) {
+ status =
+ omxNode->sendCommand(toRawCommandType(OMX_CommandPortDisable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0],
+ &pBuffer[1]);
+ if (status == android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ if (msg.data.eventData.event == OMX_EventCmdComplete) {
+ // do not disable the port until all the buffers are freed
+ ASSERT_TRUE(false);
+ } else if (msg.data.eventData.event == OMX_EventError) {
+ ALOGI("Port %d Disabling failed with error %d", (int)i,
+ (int)msg.data.eventData.event);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ } else if (status ==
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT) {
+ for (size_t j = 0; j < pBuffer[i - portBase].size(); ++j) {
+ // test if client got all its buffers back
+ EXPECT_EQ(pBuffer[i - portBase][j].owner, client);
+ // free the buffers
+ status = omxNode->freeBuffer(i, pBuffer[i - portBase][j].id);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortDisable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+
+ // If you can disable a port, then you should be able to enable it
+ // as well
+ status = omxNode->sendCommand(
+ toRawCommandType(OMX_CommandPortEnable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // do not enable the port until all the buffers are supplied
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ allocatePortBuffers(omxNode, allocator, &pBuffer[i - portBase], i);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ }
+}
+
+// Enable and Disable Input and Output ports, (in loaded state)
+TEST_F(ComponentHidlTest, PortEnableDisable_M) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_U32 portBase = 0;
+ Message msg;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ portBase = params.nStartPortNumber;
+ }
+
+ // disable invalid port, expecting OMX_ErrorBadPortIndex
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandPortDisable),
+ RANDOM_INDEX);
+ ASSERT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // enable invalid port, expecting OMX_ErrorBadPortIndex
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandPortEnable),
+ RANDOM_INDEX);
+ ASSERT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // disable all ports
+ status =
+ omxNode->sendCommand(toRawCommandType(OMX_CommandPortDisable), OMX_ALL);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ for (size_t i = 0; i < 2; i++) {
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ if (msg.data.eventData.event == OMX_EventCmdComplete) {
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortDisable);
+ if (msg.data.eventData.data2 != portBase ||
+ msg.data.eventData.data2 != portBase + 1)
+ EXPECT_TRUE(false);
+ } else if (msg.data.eventData.event == OMX_EventError) {
+ ALOGI("Port %d Disabling failed with error %d", (int)i,
+ (int)msg.data.eventData.event);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ }
+
+ // enable all ports
+ status =
+ omxNode->sendCommand(toRawCommandType(OMX_CommandPortEnable), OMX_ALL);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ for (size_t i = 0; i < 2; i++) {
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ if (msg.data.eventData.event == OMX_EventCmdComplete) {
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
+ if (msg.data.eventData.data2 != portBase ||
+ msg.data.eventData.data2 != portBase + 1)
+ EXPECT_TRUE(false);
+ } else if (msg.data.eventData.event == OMX_EventError) {
+ ALOGI("Port %d Enabling failed with error %d", (int)i,
+ (int)msg.data.eventData.event);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ }
+}
+
+int main(int argc, char** argv) {
+ gEnv = new ComponentTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ }
+ return status;
+}
diff --git a/media/omx/1.0/vts/functional/master/Android.bp b/media/omx/1.0/vts/functional/master/Android.bp
new file mode 100644
index 000000000..6edbf4a6f
--- /dev/null
+++ b/media/omx/1.0/vts/functional/master/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2017 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: "VtsHalMediaOmxV1_0TargetMasterTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalMediaOmxV1_0TargetMasterTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.media.omx@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
+
diff --git a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
new file mode 100644
index 000000000..65b999e88
--- /dev/null
+++ b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 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_TAG "media_omx_hidl_master_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <getopt.h>
+#include <log/log.h>
+#include <VtsHalHidlTargetTestBase.h>
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+// A class for test environment setup
+class ComponentTestEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ ComponentTestEnvironment() : instance("default") {}
+
+ void setInstance(const char* _instance) { instance = _instance; }
+
+ const hidl_string getInstance() const { return instance; }
+
+ int initFromOptions(int argc, char** argv) {
+ static struct option options[] = {
+ {"instance", required_argument, 0, 'I'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "I:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'I':
+ setInstance(optarg);
+ break;
+ case '?':
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-I, --instance: HAL instance to test\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+ }
+
+ private:
+ hidl_string instance;
+};
+
+static ComponentTestEnvironment* gEnv = nullptr;
+
+class MasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ omx = ::testing::VtsHalHidlTargetTestBase::getService<IOmx>(
+ gEnv->getInstance());
+ ASSERT_NE(omx, nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ sp<IOmx> omx;
+};
+
+// enumerate list of components and roles
+TEST_F(MasterHidlTest, ListNodes) {
+ android::hardware::media::omx::V1_0::Status status;
+ hidl_vec<IOmx::ComponentInfo> nodeList;
+ EXPECT_TRUE(
+ omx->listNodes([&status, &nodeList](
+ android::hardware::media::omx::V1_0::Status _s,
+ hidl_vec<IOmx::ComponentInfo> const& _nl) {
+ status = _s;
+ nodeList = _nl;
+ })
+ .isOk());
+}
+
+int main(int argc, char** argv) {
+ gEnv = new ComponentTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ }
+ return status;
+}