From 1da607c513c74612127cd18e83dcca53afb2f38f Mon Sep 17 00:00:00 2001 From: Ram Mohan M Date: Thu, 11 May 2017 18:52:47 +0530 Subject: [PATCH] Omx vts test. Bug:32023356 Test: make vts. secure buffer allocation for secure components As of now, we see a crash in encoder test application on secure components This is due to nullptr access. setting property media.mediadrmservice.enable to 1 causes a different crash sigabrt(). In decoder securebufferallocation call passes but we havent done anything with it. This commit needs more work. Change-Id: I19127e39ad7daf66ac5277406e3857ec45c99e0a add debug code This can come in handy to view the decoded/encoded content or for computation of psnr Change-Id: I80e60349c76c02e5098df667223a0227f59b8324 video encoder test with anw input buffer In this commit, anw buffers are provided as input for encoding as opposed to byte buffers. In process IOmxNode, IGraphicBufferSource api calls are tested Change-Id: I7ec4af0746fe59221de42e56b344852d8fadc4f2 add support for additional color formats Change-Id: Ia88ef9c95882958a68fee5cc68e146c3502a1b48 add eos and timestamp deviation test to video encoder Change-Id: I9ebeaa53a986ec3f8a2ef55306877aec808d2add add metamode support for video decoders Change-Id: I7d6d6991cdc0ed36241d0e99c7a23675664acb10 add a timeout while processing input buffers do not wait on input buffers processing to complete for an indefinite amount of time. wait for a predefined duration and leave Change-Id: Icceaf0737a52e62f47bc052367e7ddbdc1868a46 move duplicate code to a library move routines common across audio, video, component folders to a static library Change-Id: I55bf21e47571490e989b52b82c48c6e9a4b23745 add end of stream test for audio encoder add eos test for audio encoder and some more code cleanup Change-Id: I9d670ed53f6bba5802f919ec915e67bb0fa83518 Ensure all the buffers allocated are cycled use all buffers provided by the component (even if it is greater than the number of buffers needed by the bitstream) Change-Id: I83b454b999203fb94bc4cc50c91bd99f788131b3 move duplicate code to a library - II Change-Id: I375603feb9da303adc6a2d75ef59e43a11c3bd6d Change-Id: I83b454b999203fb94bc4cc50c91bd99f788131b3 --- media/Android.bp | 1 + media/omx/1.0/vts/functional/audio/Android.bp | 6 +- .../audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp | 95 ++- .../audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp | 110 ++- .../audio/media_audio_hidl_test_common.cpp | 272 +------ .../audio/media_audio_hidl_test_common.h | 39 +- media/omx/1.0/vts/functional/common/Android.bp | 33 + .../functional/common/media_hidl_test_common.cpp | 435 +++++++++++ .../vts/functional/common/media_hidl_test_common.h | 85 ++- media/omx/1.0/vts/functional/component/Android.bp | 4 +- .../VtsHalMediaOmxV1_0TargetComponentTest.cpp | 263 +------ media/omx/1.0/vts/functional/video/Android.bp | 12 +- .../video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp | 315 ++++++-- .../video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp | 806 ++++++++++++++++++++- .../video/media_video_hidl_test_common.cpp | 278 +------ .../video/media_video_hidl_test_common.h | 35 - 16 files changed, 1722 insertions(+), 1067 deletions(-) create mode 100755 media/omx/1.0/vts/functional/common/Android.bp create mode 100755 media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp diff --git a/media/Android.bp b/media/Android.bp index f25a609b..53e82bd7 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -3,6 +3,7 @@ subdirs = [ "1.0", "omx/1.0", "omx/1.0/vts/functional/audio", + "omx/1.0/vts/functional/common", "omx/1.0/vts/functional/component", "omx/1.0/vts/functional/master", "omx/1.0/vts/functional/video", diff --git a/media/omx/1.0/vts/functional/audio/Android.bp b/media/omx/1.0/vts/functional/audio/Android.bp index d6c73ced..66fd20be 100644 --- a/media/omx/1.0/vts/functional/audio/Android.bp +++ b/media/omx/1.0/vts/functional/audio/Android.bp @@ -34,7 +34,8 @@ cc_test { "android.hidl.memory@1.0", "android.hardware.media.omx@1.0", ], - static_libs: ["VtsHalHidlTargetTestBase"], + static_libs: ["VtsHalHidlTargetTestBase", + "VtsHalMediaOmxV1_0CommonUtil"], cflags: [ "-O0", "-g", @@ -65,7 +66,8 @@ cc_test { "android.hidl.memory@1.0", "android.hardware.media.omx@1.0", ], - static_libs: ["VtsHalHidlTargetTestBase"], + static_libs: ["VtsHalHidlTargetTestBase", + "VtsHalMediaOmxV1_0CommonUtil"], cflags: [ "-O0", "-g", diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp index 1cc18174..5ba195e5 100644 --- a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp +++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp @@ -30,6 +30,7 @@ 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::hardware::media::omx::V1_0::PortMode; using ::android::hidl::allocator::V1_0::IAllocator; using ::android::hidl::memory::V1_0::IMemory; using ::android::hidl::memory::V1_0::IMapper; @@ -136,7 +137,9 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { gEnv->getInstance()); ASSERT_NE(omx, nullptr); observer = - new CodecObserver([this](Message msg) { handleMessage(msg); }); + new CodecObserver([this](Message msg, const BufferInfo* buffer) { + handleMessage(msg, buffer); + }); ASSERT_NE(observer, nullptr); if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0) disableTest = true; @@ -218,7 +221,8 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { // callback function to process messages received by onMessages() from IL // client. - void handleMessage(Message msg) { + void handleMessage(Message msg, const BufferInfo* buffer) { + (void)buffer; if (msg.type == Message::Type::FILL_BUFFER_DONE) { if (msg.data.extendedBufferData.flags & OMX_BUFFERFLAG_EOS) { eosFlag = true; @@ -254,13 +258,26 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { } } } +#define WRITE_OUTPUT 0 +#if WRITE_OUTPUT + static int count = 0; + FILE* ofp = nullptr; + if (count) + ofp = fopen("out.bin", "ab"); + else + ofp = fopen("out.bin", "wb"); + if (ofp != nullptr) { + fwrite(static_cast(buffer->mMemory->getPointer()), + sizeof(char), + msg.data.extendedBufferData.rangeLength, ofp); + fclose(ofp); + count++; + } +#endif } } } - void testEOS(android::Vector* iBuffer, - android::Vector* oBuffer, bool signalEOS = false); - enum standardComp { mp3, amrnb, @@ -294,44 +311,6 @@ class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { } }; -// end of stream test for audio decoder components -void AudioDecHidlTest::testEOS(android::Vector* iBuffer, - android::Vector* oBuffer, - bool signalEOS) { - android::hardware::media::omx::V1_0::Status status; - size_t i = 0; - if (signalEOS) { - if ((i = getEmptyBufferID(iBuffer)) < iBuffer->size()) { - // signal an empty buffer with flag set to EOS - dispatchInputBuffer(omxNode, iBuffer, i, 0, OMX_BUFFERFLAG_EOS, 0); - } else { - ASSERT_TRUE(false); - } - } - // Dispatch all client owned output buffers to recover remaining frames - while (1) { - if ((i = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, i); - } else { - break; - } - } - while (1) { - Message msg; - status = - observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); - EXPECT_EQ(status, - android::hardware::media::omx::V1_0::Status::TIMED_OUT); - for (; i < iBuffer->size(); i++) { - if ((*iBuffer)[i].owner != client) break; - } - if (i == iBuffer->size()) break; - } - // test for flag - EXPECT_EQ(eosFlag, true); - eosFlag = false; -} - // Set Default port param. void setDefaultPortParam( sp omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding, @@ -580,8 +559,9 @@ void waitOnInputConsumption(sp omxNode, sp observer, OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput) { android::hardware::media::omx::V1_0::Status status; Message msg; + int timeOut = TIMEOUT_COUNTER; - while (1) { + while (timeOut--) { size_t i = 0; status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); @@ -603,6 +583,7 @@ void waitOnInputConsumption(sp omxNode, sp observer, if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { dispatchOutputBuffer(omxNode, oBuffer, index); } + timeOut--; } } @@ -642,6 +623,8 @@ void decodeNFrames(sp omxNode, sp observer, frameID++; } + int timeOut = TIMEOUT_COUNTER; + bool stall = false; while (1) { status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); @@ -672,9 +655,21 @@ void decodeNFrames(sp omxNode, sp observer, (*Info)[frameID].bytesCount, flags, (*Info)[frameID].timestamp); frameID++; - } + stall = false; + } else + stall = true; if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { dispatchOutputBuffer(omxNode, oBuffer, index); + stall = false; + } else + stall = true; + if (stall) + timeOut--; + else + timeOut = TIMEOUT_COUNTER; + if (timeOut == 0) { + EXPECT_TRUE(false) << "Wait on Input/Output is found indefinite"; + break; } } } @@ -778,7 +773,7 @@ TEST_F(AudioDecHidlTest, DecodeTest) { eleStream.close(); waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, kPortIndexInput, kPortIndexOutput); - testEOS(&iBuffer, &oBuffer); + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag); EXPECT_EQ(timestampUslist.empty(), true); // set state to idle changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); @@ -825,7 +820,7 @@ TEST_F(AudioDecHidlTest, EOSTest_M) { changeStateIdletoExecute(omxNode, observer); // request EOS at the start - testEOS(&iBuffer, &oBuffer, true); + testEOS(omxNode, observer, &iBuffer, &oBuffer, true, eosFlag); flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput); EXPECT_GE(framesReceived, 0U); @@ -908,7 +903,7 @@ TEST_F(AudioDecHidlTest, ThumbnailTest) { eleStream.close(); waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, kPortIndexInput, kPortIndexOutput); - testEOS(&iBuffer, &oBuffer); + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag); flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput); EXPECT_GE(framesReceived, 1U); @@ -924,7 +919,7 @@ TEST_F(AudioDecHidlTest, ThumbnailTest) { eleStream.close(); waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, kPortIndexInput, kPortIndexOutput); - testEOS(&iBuffer, &oBuffer, true); + testEOS(omxNode, observer, &iBuffer, &oBuffer, true, eosFlag); flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput); EXPECT_GE(framesReceived, 1U); @@ -1004,7 +999,7 @@ TEST_F(AudioDecHidlTest, SimpleEOSTest) { eleStream.close(); waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, eEncoding, kPortIndexInput, kPortIndexOutput); - testEOS(&iBuffer, &oBuffer); + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag); flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput); framesReceived = 0; diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp index 7d5f9685..ecd9ef98 100644 --- a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp +++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp @@ -30,6 +30,7 @@ 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::hardware::media::omx::V1_0::PortMode; using ::android::hidl::allocator::V1_0::IAllocator; using ::android::hidl::memory::V1_0::IMemory; using ::android::hidl::memory::V1_0::IMapper; @@ -135,7 +136,10 @@ class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { omx = ::testing::VtsHalHidlTargetTestBase::getService( gEnv->getInstance()); ASSERT_NE(omx, nullptr); - observer = new CodecObserver([](Message msg) { (void)msg; }); + observer = + new CodecObserver([this](Message msg, const BufferInfo* buffer) { + handleMessage(msg, buffer); + }); ASSERT_NE(observer, nullptr); if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0) disableTest = true; @@ -191,6 +195,7 @@ class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { } } if (i == kNumCompToCoding) disableTest = true; + eosFlag = false; if (disableTest) std::cerr << "[ ] Warning ! Test Disabled\n"; } @@ -201,6 +206,36 @@ class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { } } + // callback function to process messages received by onMessages() from IL + // client. + void handleMessage(Message msg, const BufferInfo* buffer) { + (void)buffer; + + if (msg.type == Message::Type::FILL_BUFFER_DONE) { + if (msg.data.extendedBufferData.flags & OMX_BUFFERFLAG_EOS) { + eosFlag = true; + } + if (msg.data.extendedBufferData.rangeLength != 0) { +#define WRITE_OUTPUT 0 +#if WRITE_OUTPUT + static int count = 0; + FILE* ofp = nullptr; + if (count) + ofp = fopen("out.bin", "ab"); + else + ofp = fopen("out.bin", "wb"); + if (ofp != nullptr) { + fwrite(static_cast(buffer->mMemory->getPointer()), + sizeof(char), + msg.data.extendedBufferData.rangeLength, ofp); + fclose(ofp); + count++; + } +#endif + } + } + } + enum standardComp { amrnb, amrwb, @@ -215,6 +250,7 @@ class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { standardComp compName; OMX_AUDIO_CODINGTYPE eEncoding; bool disableTest; + bool eosFlag; protected: static void description(const std::string& description) { @@ -289,12 +325,44 @@ void GetURLForComponent(AudioEncHidlTest::standardComp comp, char* mURL) { } } +// blocking call to ensures application to Wait till all the inputs are consumed +void waitOnInputConsumption(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer) { + android::hardware::media::omx::V1_0::Status status; + Message msg; + int timeOut = TIMEOUT_COUNTER; + + while (timeOut--) { + size_t i = 0; + status = + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); + EXPECT_EQ(status, + android::hardware::media::omx::V1_0::Status::TIMED_OUT); + // status == TIMED_OUT, it could be due to process time being large + // than DEFAULT_TIMEOUT or component needs output buffers to start + // processing. + for (; i < iBuffer->size(); i++) { + if ((*iBuffer)[i].owner != client) break; + } + if (i == iBuffer->size()) break; + + // Dispatch an output buffer assuming outQueue.empty() is true + size_t index; + if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { + dispatchOutputBuffer(omxNode, oBuffer, index); + } + timeOut--; + } +} + // Encode N Frames void encodeNFrames(sp omxNode, sp observer, android::Vector* iBuffer, android::Vector* oBuffer, uint32_t nFrames, int32_t samplesPerFrame, int32_t nChannels, - int32_t nSampleRate, std::ifstream& eleStream) { + int32_t nSampleRate, std::ifstream& eleStream, + bool signalEOS = true) { android::hardware::media::omx::V1_0::Status status; Message msg; @@ -307,6 +375,7 @@ void encodeNFrames(sp omxNode, sp observer, int32_t timestampIncr = (int)(((float)samplesPerFrame / nSampleRate) * 1000000); uint64_t timestamp = 0; + uint32_t flags = 0; for (size_t i = 0; i < iBuffer->size() && nFrames != 0; i++) { char* ipBuffer = static_cast( static_cast((*iBuffer)[i].mMemory->getPointer())); @@ -314,11 +383,14 @@ void encodeNFrames(sp omxNode, sp observer, static_cast((*iBuffer)[i].mMemory->getSize())); eleStream.read(ipBuffer, bytesCount); if (eleStream.gcount() != bytesCount) break; - dispatchInputBuffer(omxNode, iBuffer, i, bytesCount, 0, timestamp); + if (signalEOS && (nFrames == 1)) flags = OMX_BUFFERFLAG_EOS; + dispatchInputBuffer(omxNode, iBuffer, i, bytesCount, flags, timestamp); timestamp += timestampIncr; nFrames--; } + int timeOut = TIMEOUT_COUNTER; + bool stall = false; while (1) { status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); @@ -337,14 +409,27 @@ void encodeNFrames(sp omxNode, sp observer, static_cast((*iBuffer)[index].mMemory->getSize())); eleStream.read(ipBuffer, bytesCount); if (eleStream.gcount() != bytesCount) break; - dispatchInputBuffer(omxNode, iBuffer, index, bytesCount, 0, + if (signalEOS && (nFrames == 1)) flags = OMX_BUFFERFLAG_EOS; + dispatchInputBuffer(omxNode, iBuffer, index, bytesCount, flags, timestamp); timestamp += timestampIncr; nFrames--; - } + stall = false; + } else + stall = true; // Dispatch output buffer if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { dispatchOutputBuffer(omxNode, oBuffer, index); + stall = false; + } else + stall = true; + if (stall) + timeOut--; + else + timeOut = TIMEOUT_COUNTER; + if (timeOut == 0) { + EXPECT_TRUE(false) << "Wait on Input/Output is found indefinite"; + break; } } } @@ -380,8 +465,8 @@ TEST_F(AudioEncHidlTest, EnumeratePortFormat) { } // test raw stream encode -TEST_F(AudioEncHidlTest, EncodeTest) { - description("Tests Encode"); +TEST_F(AudioEncHidlTest, SimpleEncodeTest) { + description("Tests Basic encoding and EOS"); if (disableTest) return; android::hardware::media::omx::V1_0::Status status; uint32_t kPortIndexInput = 0, kPortIndexOutput = 1; @@ -399,8 +484,6 @@ TEST_F(AudioEncHidlTest, EncodeTest) { GetURLForComponent(compName, mURL); std::ifstream eleStream; - eleStream.open(mURL, std::ifstream::binary); - ASSERT_EQ(eleStream.is_open(), true); // Configure input port int32_t nChannels = 2; @@ -449,16 +532,19 @@ TEST_F(AudioEncHidlTest, EncodeTest) { // set state to executing changeStateIdletoExecute(omxNode, observer); - encodeNFrames(omxNode, observer, &iBuffer, &oBuffer, 1024, samplesPerFrame, + eleStream.open(mURL, std::ifstream::binary); + ASSERT_EQ(eleStream.is_open(), true); + encodeNFrames(omxNode, observer, &iBuffer, &oBuffer, 128, samplesPerFrame, nChannels, nSampleRate, eleStream); + eleStream.close(); + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer); + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag); // set state to idle changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); // set state to executing changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput); - - eleStream.close(); } int main(int argc, char** argv) { 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 index f09d21d6..abd044d7 100644 --- 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 @@ -30,6 +30,7 @@ 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::hardware::media::omx::V1_0::PortMode; using ::android::hidl::allocator::V1_0::IAllocator; using ::android::hidl::memory::V1_0::IMemory; using ::android::hidl::memory::V1_0::IMapper; @@ -45,277 +46,6 @@ using ::android::sp; #include #include -// allocate buffers needed on a component port -void allocatePortBuffers(sp omxNode, - android::Vector* buffArray, - OMX_U32 portIndex) { - android::hardware::media::omx::V1_0::Status status; - OMX_PARAM_PORTDEFINITIONTYPE portDef; - - buffArray->clear(); - - sp allocator = IAllocator::getService("ashmem"); - EXPECT_NE(allocator.get(), 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 = false; - allocator->allocate( - portDef.nBufferSize, - [&success, &buffer](bool _s, - ::android::hardware::hidl_memory const& mem) { - success = _s; - buffer.omxBuffer.sharedMemory = mem; - }); - ASSERT_EQ(success, true); - ASSERT_EQ(buffer.omxBuffer.sharedMemory.size(), portDef.nBufferSize); - 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); - } -} - -// State Transition : Loaded -> Idle -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateLoadedtoIdle(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, - OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // 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 are populated - 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, iBuffer, kPortIndexInput); - - // Dont switch states until the ports are populated - 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, oBuffer, kPortIndexOutput); - - // As the ports are populated, check if the state transition is complete - 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); - - return; -} - -// State Transition : Idle -> Loaded -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateIdletoLoaded(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, - OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // 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); - - return; -} - -// State Transition : Idle -> Execute -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateIdletoExecute(sp omxNode, - sp observer) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // set state to 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); - 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); - - return; -} - -// State Transition : Execute -> Idle -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateExecutetoIdle(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // 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); - } - for (size_t i = 0; i < iBuffer->size(); ++i) { - EXPECT_EQ((*iBuffer)[i].owner, client); - } -} - -// get empty buffer index -size_t getEmptyBufferID(android::Vector* buffArray) { - for (size_t i = 0; i < buffArray->size(); i++) { - if ((*buffArray)[i].owner == client) return i; - } - return buffArray->size(); -} - -// dispatch buffer to output port -void dispatchOutputBuffer(sp omxNode, - android::Vector* 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; -} - -// dispatch buffer to input port -void dispatchInputBuffer(sp omxNode, - android::Vector* 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; -} - -// Flush input and output ports -void flushPorts(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput, int64_t timeoutUs) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // Flush input port - status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), - kPortIndexInput); - ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); - status = observer->dequeueMessage(&msg, timeoutUs, 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); - } - - // Flush output port - status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), - kPortIndexOutput); - ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); - status = observer->dequeueMessage(&msg, timeoutUs, 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); - } -} - Return setAudioPortFormat( sp omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding) { OMX_U32 index = 0; 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 index d420ab57..a7624367 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright 2016, The Android Open Source Project + * 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. @@ -18,6 +18,7 @@ #define MEDIA_AUDIO_HIDL_TEST_COMMON_H #include + /* * Random Index used for monkey testing while get/set parameters */ @@ -26,42 +27,6 @@ /* * Common audio utils */ -void allocatePortBuffers(sp omxNode, - android::Vector* buffArray, - OMX_U32 portIndex); - -void changeStateLoadedtoIdle(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, - OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput); - -void changeStateIdletoLoaded(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, - OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput); - -void changeStateIdletoExecute(sp omxNode, sp observer); - -void changeStateExecutetoIdle(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer); - -size_t getEmptyBufferID(android::Vector* buffArray); - -void dispatchOutputBuffer(sp omxNode, - android::Vector* buffArray, - size_t bufferIndex); - -void dispatchInputBuffer(sp omxNode, - android::Vector* buffArray, - size_t bufferIndex, int bytesCount, uint32_t flags, - uint64_t timestamp); - -void flushPorts(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput, int64_t timeoutUs = DEFAULT_TIMEOUT); - Return setAudioPortFormat( sp omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding); diff --git a/media/omx/1.0/vts/functional/common/Android.bp b/media/omx/1.0/vts/functional/common/Android.bp new file mode 100755 index 00000000..93251fe8 --- /dev/null +++ b/media/omx/1.0/vts/functional/common/Android.bp @@ -0,0 +1,33 @@ +// +// 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_library_static { + name: "VtsHalMediaOmxV1_0CommonUtil", + defaults: ["hidl_defaults"], + srcs: ["media_hidl_test_common.cpp"], + shared_libs: [ + "liblog", + "libhidlmemory", + "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/", + ], +} diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp new file mode 100755 index 00000000..30344a1e --- /dev/null +++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp @@ -0,0 +1,435 @@ +/* + * 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_video_test_common" + +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +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::hardware::media::omx::V1_0::PortMode; +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 +#include +#include +#include +#include + +// allocate buffers needed on a component port +void allocatePortBuffers(sp omxNode, + android::Vector* buffArray, + OMX_U32 portIndex, PortMode portMode) { + 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); + + if (portMode == PortMode::PRESET_SECURE_BUFFER) { + for (size_t i = 0; i < portDef.nBufferCountActual; i++) { + BufferInfo buffer; + buffer.owner = client; + buffer.omxBuffer.type = CodecBuffer::Type::NATIVE_HANDLE; + omxNode->allocateSecureBuffer( + portIndex, portDef.nBufferSize, + [&status, &buffer]( + android::hardware::media::omx::V1_0::Status _s, uint32_t id, + ::android::hardware::hidl_handle const& nativeHandle) { + status = _s; + buffer.id = id; + buffer.omxBuffer.nativeHandle = nativeHandle; + }); + buffArray->push(buffer); + ASSERT_EQ(status, + ::android::hardware::media::omx::V1_0::Status::OK); + } + } else if (portMode == PortMode::PRESET_BYTE_BUFFER || + portMode == PortMode::DYNAMIC_ANW_BUFFER) { + sp allocator = IAllocator::getService("ashmem"); + EXPECT_NE(allocator.get(), nullptr); + + 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 = false; + if (portMode != PortMode::PRESET_BYTE_BUFFER) { + portDef.nBufferSize = sizeof(android::VideoNativeMetadata); + } + allocator->allocate( + portDef.nBufferSize, + [&success, &buffer]( + bool _s, ::android::hardware::hidl_memory const& mem) { + success = _s; + buffer.omxBuffer.sharedMemory = mem; + }); + ASSERT_EQ(success, true); + ASSERT_EQ(buffer.omxBuffer.sharedMemory.size(), + portDef.nBufferSize); + buffer.mMemory = mapMemory(buffer.omxBuffer.sharedMemory); + ASSERT_NE(buffer.mMemory, nullptr); + if (portMode == PortMode::DYNAMIC_ANW_BUFFER) { + android::VideoNativeMetadata* metaData = + static_cast( + static_cast(buffer.mMemory->getPointer())); + metaData->nFenceFd = -1; + buffer.slot = -1; + } + 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); + } + } +} + +// State Transition : Loaded -> Idle +// Note: This function does not make any background checks for this transition. +// The callee holds the reponsibility to ensure the legality of the transition. +void changeStateLoadedtoIdle(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer, + OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, + PortMode* portMode) { + android::hardware::media::omx::V1_0::Status status; + Message msg; + PortMode defaultPortMode[2], *pm; + + defaultPortMode[0] = PortMode::PRESET_BYTE_BUFFER; + defaultPortMode[1] = PortMode::PRESET_BYTE_BUFFER; + pm = portMode ? portMode : defaultPortMode; + + // 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 are populated + 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, iBuffer, kPortIndexInput, pm[0]); + + // Dont switch states until the ports are populated + 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, oBuffer, kPortIndexOutput, pm[1]); + + // As the ports are populated, check if the state transition is complete + 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); + + return; +} + +// State Transition : Idle -> Loaded +// Note: This function does not make any background checks for this transition. +// The callee holds the reponsibility to ensure the legality of the transition. +void changeStateIdletoLoaded(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer, + OMX_U32 kPortIndexInput, + OMX_U32 kPortIndexOutput) { + android::hardware::media::omx::V1_0::Status status; + Message msg; + + // 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); + + return; +} + +// State Transition : Idle -> Execute +// Note: This function does not make any background checks for this transition. +// The callee holds the reponsibility to ensure the legality of the transition. +void changeStateIdletoExecute(sp omxNode, + sp observer) { + android::hardware::media::omx::V1_0::Status status; + Message msg; + + // set state to 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); + 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); + + return; +} + +// State Transition : Execute -> Idle +// Note: This function does not make any background checks for this transition. +// The callee holds the reponsibility to ensure the legality of the transition. +void changeStateExecutetoIdle(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer) { + android::hardware::media::omx::V1_0::Status status; + Message msg; + + // 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); + } + for (size_t i = 0; i < iBuffer->size(); ++i) { + EXPECT_EQ((*iBuffer)[i].owner, client); + } +} + +// get empty buffer index +size_t getEmptyBufferID(android::Vector* buffArray) { + android::Vector::iterator it = buffArray->begin(); + while (it != buffArray->end()) { + if (it->owner == client) { + // This block of code ensures that all buffers allocated at init + // time are utilized + BufferInfo backup = *it; + buffArray->erase(it); + buffArray->push_back(backup); + return buffArray->size() - 1; + } + it++; + } + return buffArray->size(); +} + +// dispatch buffer to output port +void dispatchOutputBuffer(sp omxNode, + android::Vector* buffArray, + size_t bufferIndex, PortMode portMode) { + if (portMode == PortMode::DYNAMIC_ANW_BUFFER) { + android::hardware::media::omx::V1_0::Status status; + CodecBuffer t = (*buffArray)[bufferIndex].omxBuffer; + t.type = CodecBuffer::Type::ANW_BUFFER; + 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; + } else { + 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; + } +} + +// dispatch buffer to input port +void dispatchInputBuffer(sp omxNode, + android::Vector* 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; +} + +// Flush input and output ports +void flushPorts(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer, OMX_U32 kPortIndexInput, + OMX_U32 kPortIndexOutput, int64_t timeoutUs) { + android::hardware::media::omx::V1_0::Status status; + Message msg; + + // Flush input port + status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), + kPortIndexInput); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); + status = observer->dequeueMessage(&msg, timeoutUs, 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); + } + + // Flush output port + status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), + kPortIndexOutput); + ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); + status = observer->dequeueMessage(&msg, timeoutUs, 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); + } +} + +// dispatch an empty input buffer with eos flag set if requested. +// This call assumes that all input buffers are processed completely. +// feed output buffers till we receive a buffer with eos flag set +void testEOS(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer, bool signalEOS, + bool& eosFlag, PortMode* portMode) { + android::hardware::media::omx::V1_0::Status status; + PortMode defaultPortMode[2], *pm; + + defaultPortMode[0] = PortMode::PRESET_BYTE_BUFFER; + defaultPortMode[1] = PortMode::PRESET_BYTE_BUFFER; + pm = portMode ? portMode : defaultPortMode; + + size_t i = 0; + if (signalEOS) { + if ((i = getEmptyBufferID(iBuffer)) < iBuffer->size()) { + // signal an empty buffer with flag set to EOS + dispatchInputBuffer(omxNode, iBuffer, i, 0, OMX_BUFFERFLAG_EOS, 0); + } else { + ASSERT_TRUE(false); + } + } + + int timeOut = TIMEOUT_COUNTER; + while (timeOut--) { + // Dispatch all client owned output buffers to recover remaining frames + while (1) { + if ((i = getEmptyBufferID(oBuffer)) < oBuffer->size()) { + dispatchOutputBuffer(omxNode, oBuffer, i, pm[1]); + // if dispatch is successful, perhaps there is a latency + // in the component. Dont be in a haste to leave. reset timeout + // counter + timeOut = TIMEOUT_COUNTER; + } else { + break; + } + } + + Message msg; + status = + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); + EXPECT_EQ(status, + android::hardware::media::omx::V1_0::Status::TIMED_OUT); + if (eosFlag == true) break; + } + // test for flag + EXPECT_EQ(eosFlag, true); + eosFlag = false; +} 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 index 52d8ae20..a4025325 100644 --- 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 @@ -33,9 +33,19 @@ #include #include +#define DEFAULT_TIMEOUT 40000 +#define TIMEOUT_COUNTER (10000000 / DEFAULT_TIMEOUT) + +enum bufferOwner { + client, + component, + unknown, +}; + /* - * TODO: Borrowed from Conversion.h. This is not the ideal way to do it. - * Loose these definitions once you include Conversion.h + * TODO: below definitions are 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(l); @@ -57,22 +67,14 @@ inline uint32_t toRawCommandType(OMX_COMMANDTYPE l) { } /* - * Handle Callback functions EmptythisBuffer(), FillthisBuffer(), - * EventHandler() + * struct definitions */ -#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 mMemory; + int32_t slot; }; struct FrameData { @@ -81,9 +83,14 @@ struct FrameData { uint32_t timestamp; }; +/* + * Handle Callback functions EmptythisBuffer(), FillthisBuffer(), + * EventHandler() + */ struct CodecObserver : public IOmxObserver { public: - CodecObserver(std::function fn) : callBack(fn) {} + CodecObserver(std::function fn) + : callBack(fn) {} Return onMessages(const hidl_vec& messages) override { android::Mutex::Autolock autoLock(msgLock); for (hidl_vec::const_iterator it = messages.begin(); @@ -114,7 +121,7 @@ struct CodecObserver : public IOmxObserver { for (i = 0; i < oBuffers->size(); ++i) { if ((*oBuffers)[i].id == it->data.bufferData.buffer) { - if (callBack) callBack(*it); + if (callBack) callBack(*it, &(*oBuffers)[i]); oBuffers->editItemAt(i).owner = client; msgQueue.erase(it); break; @@ -129,6 +136,7 @@ struct CodecObserver : public IOmxObserver { for (i = 0; i < iBuffers->size(); ++i) { if ((*iBuffers)[i].id == it->data.bufferData.buffer) { + if (callBack) callBack(*it, &(*iBuffers)[i]); iBuffers->editItemAt(i).owner = client; msgQueue.erase(it); break; @@ -154,7 +162,7 @@ struct CodecObserver : public IOmxObserver { android::List msgQueue; android::Mutex msgLock; android::Condition msgCondition; - std::function callBack; + std::function callBack; }; /* @@ -245,4 +253,51 @@ Return setPortConfig( inHidlBytes(params, sizeof(*params))); } +/* + * common functions declarations + */ +void allocatePortBuffers(sp omxNode, + android::Vector* buffArray, + OMX_U32 portIndex, + PortMode portMode = PortMode::PRESET_BYTE_BUFFER); + +void changeStateLoadedtoIdle(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer, + OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, + PortMode* portMode = nullptr); + +void changeStateIdletoLoaded(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer, + OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput); + +void changeStateIdletoExecute(sp omxNode, sp observer); + +void changeStateExecutetoIdle(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer); + +size_t getEmptyBufferID(android::Vector* buffArray); + +void dispatchOutputBuffer(sp omxNode, + android::Vector* buffArray, + size_t bufferIndex, + PortMode portMode = PortMode::PRESET_BYTE_BUFFER); + +void dispatchInputBuffer(sp omxNode, + android::Vector* buffArray, + size_t bufferIndex, int bytesCount, uint32_t flags, + uint64_t timestamp); + +void flushPorts(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer, OMX_U32 kPortIndexInput, + OMX_U32 kPortIndexOutput, int64_t timeoutUs = DEFAULT_TIMEOUT); + +void testEOS(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer, bool signalEOS, + bool& eosFlag, PortMode* portMode = nullptr); + #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 index 02fe1828..fd3210fb 100644 --- a/media/omx/1.0/vts/functional/component/Android.bp +++ b/media/omx/1.0/vts/functional/component/Android.bp @@ -23,6 +23,7 @@ cc_test { "liblog", "libcutils", "libhidlbase", + "libhidlmemory", "libhidltransport", "libhwbinder", "libnativehelper", @@ -32,7 +33,8 @@ cc_test { "android.hidl.memory@1.0", "android.hardware.media.omx@1.0", ], - static_libs: ["VtsHalHidlTargetTestBase"], + static_libs: ["VtsHalHidlTargetTestBase", + "VtsHalMediaOmxV1_0CommonUtil"], cflags: [ "-O0", "-g", diff --git a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp index 17c49ca4..39e8864f 100644 --- a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp +++ b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp @@ -30,6 +30,7 @@ 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::hardware::media::omx::V1_0::PortMode; using ::android::hidl::allocator::V1_0::IAllocator; using ::android::hidl::memory::V1_0::IMemory; using ::android::hidl::memory::V1_0::IMapper; @@ -196,268 +197,6 @@ class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase { // Random Index used for monkey testing while get/set parameters #define RANDOM_INDEX 1729 -// allocate buffers needed on a component port -void allocatePortBuffers(sp omxNode, - android::Vector* buffArray, - OMX_U32 portIndex) { - android::hardware::media::omx::V1_0::Status status; - OMX_PARAM_PORTDEFINITIONTYPE portDef; - - buffArray->clear(); - - sp allocator = IAllocator::getService("ashmem"); - EXPECT_NE(allocator.get(), 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 = false; - allocator->allocate( - portDef.nBufferSize, - [&success, &buffer](bool _s, - ::android::hardware::hidl_memory const& mem) { - success = _s; - buffer.omxBuffer.sharedMemory = mem; - }); - ASSERT_EQ(success, true); - ASSERT_EQ(buffer.omxBuffer.sharedMemory.size(), portDef.nBufferSize); - - 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); - } -} - -// State Transition : Loaded -> Idle -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateLoadedtoIdle(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, - OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // 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 are populated - 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, iBuffer, kPortIndexInput); - - // Dont switch states until the ports are populated - 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, oBuffer, kPortIndexOutput); - - // As the ports are populated, check if the state transition is complete - 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); - - return; -} - -// State Transition : Idle -> Loaded -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateIdletoLoaded(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, - OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // 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); - - return; -} - -// State Transition : Idle -> Execute -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateIdletoExecute(sp omxNode, - sp observer) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // set state to 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); - 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); - - return; -} - -// State Transition : Execute -> Idle -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateExecutetoIdle(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // 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); - } - for (size_t i = 0; i < iBuffer->size(); ++i) { - EXPECT_EQ((*iBuffer)[i].owner, client); - } -} - -// dispatch buffer to output port -void dispatchOutputBuffer(sp omxNode, - android::Vector* 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; -} - -// dispatch buffer to input port -void dispatchInputBuffer(sp omxNode, - android::Vector* 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; -} - -// Flush input and output ports -void flushPorts(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // Flush input port - 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); - } - - // Flush output port - 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); - } -} - // get/set video component port format Return setVideoPortFormat( sp omxNode, OMX_U32 portIndex, diff --git a/media/omx/1.0/vts/functional/video/Android.bp b/media/omx/1.0/vts/functional/video/Android.bp index a8c8d992..4e94f3b3 100644 --- a/media/omx/1.0/vts/functional/video/Android.bp +++ b/media/omx/1.0/vts/functional/video/Android.bp @@ -33,8 +33,12 @@ cc_test { "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "android.hardware.media.omx@1.0", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.common@1.0", ], - static_libs: ["VtsHalHidlTargetTestBase"], + static_libs: ["VtsHalHidlTargetTestBase", + "VtsHalMediaOmxV1_0CommonUtil"], cflags: [ "-O0", "-g", @@ -59,13 +63,17 @@ cc_test { "libhidltransport", "libhwbinder", "libnativehelper", + "libnativewindow", "libutils", "libstagefright_foundation", "android.hidl.allocator@1.0", "android.hidl.memory@1.0", "android.hardware.media.omx@1.0", + "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.mapper@2.0", ], - static_libs: ["VtsHalHidlTargetTestBase"], + static_libs: ["VtsHalHidlTargetTestBase", + "VtsHalMediaOmxV1_0CommonUtil"], cflags: [ "-O0", "-g", diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp index 35c2b0ca..8caf697c 100644 --- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp +++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp @@ -17,6 +17,9 @@ #define LOG_TAG "media_omx_hidl_video_dec_test" #include +#include +#include +#include #include #include #include @@ -25,11 +28,14 @@ #include #include +using ::android::hardware::graphics::common::V1_0::BufferUsage; +using ::android::hardware::graphics::common::V1_0::PixelFormat; 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::hardware::media::omx::V1_0::PortMode; using ::android::hidl::allocator::V1_0::IAllocator; using ::android::hidl::memory::V1_0::IMemory; using ::android::hidl::memory::V1_0::IMapper; @@ -136,7 +142,9 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { gEnv->getInstance()); ASSERT_NE(omx, nullptr); observer = - new CodecObserver([this](Message msg) { handleMessage(msg); }); + new CodecObserver([this](Message msg, const BufferInfo* buffer) { + handleMessage(msg, buffer); + }); ASSERT_NE(observer, nullptr); if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0) disableTest = true; @@ -193,10 +201,19 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { } } if (i == kNumCompToCompression) disableTest = true; + portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER; eosFlag = false; framesReceived = 0; timestampUs = 0; timestampDevTest = false; + isSecure = false; + size_t suffixLen = strlen(".secure"); + if (strlen(gEnv->getComponent().c_str()) >= suffixLen) { + } + isSecure = !strcmp(gEnv->getComponent().c_str() + + strlen(gEnv->getComponent().c_str()) - suffixLen, + ".secure"); + if (isSecure) disableTest = true; if (disableTest) std::cerr << "[ ] Warning ! Test Disabled\n"; } @@ -209,7 +226,8 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { // callback function to process messages received by onMessages() from IL // client. - void handleMessage(Message msg) { + void handleMessage(Message msg, const BufferInfo* buffer) { + (void)buffer; if (msg.type == Message::Type::FILL_BUFFER_DONE) { if (msg.data.extendedBufferData.flags & OMX_BUFFERFLAG_EOS) { eosFlag = true; @@ -245,13 +263,27 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { } } } +#define WRITE_OUTPUT 0 +#if WRITE_OUTPUT + static int count = 0; + FILE* ofp = nullptr; + if (count) + ofp = fopen("out.bin", "ab"); + else + ofp = fopen("out.bin", "wb"); + if (ofp != nullptr && + portMode[1] == PortMode::PRESET_BYTE_BUFFER) { + fwrite(static_cast(buffer->mMemory->getPointer()), + sizeof(char), + msg.data.extendedBufferData.rangeLength, ofp); + fclose(ofp); + count++; + } +#endif } } } - void testEOS(android::Vector* iBuffer, - android::Vector* oBuffer, bool signalEOS = false); - enum standardComp { h263, avc, @@ -269,11 +301,13 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { standardComp compName; OMX_VIDEO_CODINGTYPE eCompressionFormat; bool disableTest; + PortMode portMode[2]; bool eosFlag; uint32_t framesReceived; uint64_t timestampUs; ::android::List timestampUslist; bool timestampDevTest; + bool isSecure; protected: static void description(const std::string& description) { @@ -281,44 +315,6 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { } }; -// end of stream test for video decoder components -void VideoDecHidlTest::testEOS(android::Vector* iBuffer, - android::Vector* oBuffer, - bool signalEOS) { - android::hardware::media::omx::V1_0::Status status; - size_t i = 0; - if (signalEOS) { - if ((i = getEmptyBufferID(iBuffer)) < iBuffer->size()) { - // signal an empty buffer with flag set to EOS - dispatchInputBuffer(omxNode, iBuffer, i, 0, OMX_BUFFERFLAG_EOS, 0); - } else { - ASSERT_TRUE(false); - } - } - // Dispatch all client owned output buffers to recover remaining frames - while (1) { - if ((i = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, i); - } else { - break; - } - } - while (1) { - Message msg; - status = - observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); - EXPECT_EQ(status, - android::hardware::media::omx::V1_0::Status::TIMED_OUT); - for (; i < iBuffer->size(); i++) { - if ((*iBuffer)[i].owner != client) break; - } - if (i == iBuffer->size()) break; - } - // test for flag - EXPECT_EQ(eosFlag, true); - eosFlag = false; -} - // Set Default port param. void setDefaultPortParam(sp omxNode, OMX_U32 portIndex, OMX_VIDEO_CODINGTYPE eCompressionFormat, @@ -399,12 +395,85 @@ void GetURLForComponent(VideoDecHidlTest::standardComp comp, char* mURL, } } +void allocateGraphicBuffers(sp omxNode, OMX_U32 portIndex, + android::Vector* buffArray, + uint32_t nFrameWidth, uint32_t nFrameHeight, + int32_t* nStride, uint32_t count) { + android::hardware::media::omx::V1_0::Status status; + sp allocator = + android::hardware::graphics::allocator::V2_0::IAllocator::getService(); + ASSERT_NE(nullptr, allocator.get()); + + sp mapper = + android::hardware::graphics::mapper::V2_0::IMapper::getService(); + ASSERT_NE(mapper.get(), nullptr); + + android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo + descriptorInfo; + uint32_t usage; + + descriptorInfo.width = nFrameWidth; + descriptorInfo.height = nFrameHeight; + descriptorInfo.layerCount = 1; + descriptorInfo.format = PixelFormat::RGBA_8888; + descriptorInfo.usage = static_cast(BufferUsage::CPU_READ_OFTEN); + omxNode->getGraphicBufferUsage( + portIndex, + [&status, &usage](android::hardware::media::omx::V1_0::Status _s, + uint32_t _n1) { + status = _s; + usage = _n1; + }); + if (status == android::hardware::media::omx::V1_0::Status::OK) { + descriptorInfo.usage |= usage; + } + + ::android::hardware::hidl_vec descriptor; + android::hardware::graphics::mapper::V2_0::Error error; + mapper->createDescriptor( + descriptorInfo, [&error, &descriptor]( + android::hardware::graphics::mapper::V2_0::Error _s, + ::android::hardware::hidl_vec _n1) { + error = _s; + descriptor = _n1; + }); + EXPECT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE); + + EXPECT_EQ(buffArray->size(), count); + allocator->allocate( + descriptor, count, + [&](android::hardware::graphics::mapper::V2_0::Error _s, uint32_t _n1, + const ::android::hardware::hidl_vec< + ::android::hardware::hidl_handle>& _n2) { + ASSERT_EQ(android::hardware::graphics::mapper::V2_0::Error::NONE, + _s); + *nStride = _n1; + ASSERT_EQ(count, _n2.size()); + for (uint32_t i = 0; i < count; i++) { + buffArray->editItemAt(i).omxBuffer.nativeHandle = _n2[i]; + buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.width = + nFrameWidth; + buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.height = + nFrameHeight; + buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.stride = _n1; + buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.format = + descriptorInfo.format; + buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.usage = + descriptorInfo.usage; + buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.layerCount = + descriptorInfo.layerCount; + buffArray->editItemAt(i).omxBuffer.attr.anwBuffer.id = + (*buffArray)[i].id; + } + }); +} + // port settings reconfiguration during runtime. reconfigures frame dimensions void portReconfiguration(sp omxNode, sp observer, android::Vector* iBuffer, android::Vector* oBuffer, OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, - Message msg) { + Message msg, PortMode oPortMode) { android::hardware::media::omx::V1_0::Status status; if (msg.data.eventData.event == OMX_EventPortSettingsChanged) { @@ -461,7 +530,8 @@ void portReconfiguration(sp omxNode, sp observer, status, android::hardware::media::omx::V1_0::Status::TIMED_OUT); - allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput); + allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput, + oPortMode); status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); ASSERT_EQ(status, @@ -472,7 +542,7 @@ void portReconfiguration(sp omxNode, sp observer, // dispatch output buffers for (size_t i = 0; i < oBuffer->size(); i++) { - dispatchOutputBuffer(omxNode, oBuffer, i); + dispatchOutputBuffer(omxNode, oBuffer, i, oPortMode); } } else { ASSERT_TRUE(false); @@ -499,18 +569,21 @@ void portReconfiguration(sp omxNode, sp observer, void waitOnInputConsumption(sp omxNode, sp observer, android::Vector* iBuffer, android::Vector* oBuffer, - OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput) { + OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, + PortMode oPortMode) { android::hardware::media::omx::V1_0::Status status; Message msg; + int timeOut = TIMEOUT_COUNTER; - while (1) { + while (timeOut--) { size_t i = 0; status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); if (status == android::hardware::media::omx::V1_0::Status::OK) { EXPECT_EQ(msg.type, Message::Type::EVENT); portReconfiguration(omxNode, observer, iBuffer, oBuffer, - kPortIndexInput, kPortIndexOutput, msg); + kPortIndexInput, kPortIndexOutput, msg, + oPortMode); } // status == TIMED_OUT, it could be due to process time being large // than DEFAULT_TIMEOUT or component needs output buffers to start @@ -523,8 +596,9 @@ void waitOnInputConsumption(sp omxNode, sp observer, // Dispatch an output buffer assuming outQueue.empty() is true size_t index; if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, index); + dispatchOutputBuffer(omxNode, oBuffer, index, oPortMode); } + timeOut--; } } @@ -534,13 +608,14 @@ void decodeNFrames(sp omxNode, sp observer, android::Vector* oBuffer, OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, std::ifstream& eleStream, android::Vector* Info, - int offset, int range, bool signalEOS = true) { + int offset, int range, PortMode oPortMode, + bool signalEOS = true) { 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); + dispatchOutputBuffer(omxNode, oBuffer, i, oPortMode); } // dispatch input buffers uint32_t flags = 0; @@ -563,6 +638,8 @@ void decodeNFrames(sp omxNode, sp observer, frameID++; } + int timeOut = TIMEOUT_COUNTER; + bool stall = false; while (1) { status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); @@ -571,7 +648,8 @@ void decodeNFrames(sp omxNode, sp observer, if (status == android::hardware::media::omx::V1_0::Status::OK && msg.type == Message::Type::EVENT) { portReconfiguration(omxNode, observer, iBuffer, oBuffer, - kPortIndexInput, kPortIndexOutput, msg); + kPortIndexInput, kPortIndexOutput, msg, + oPortMode); } if (frameID == (int)Info->size() || frameID == (offset + range)) break; @@ -593,9 +671,21 @@ void decodeNFrames(sp omxNode, sp observer, (*Info)[frameID].bytesCount, flags, (*Info)[frameID].timestamp); frameID++; - } + stall = false; + } else + stall = true; if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { - dispatchOutputBuffer(omxNode, oBuffer, index); + dispatchOutputBuffer(omxNode, oBuffer, index, oPortMode); + stall = false; + } else + stall = true; + if (stall) + timeOut--; + else + timeOut = TIMEOUT_COUNTER; + if (timeOut == 0) { + EXPECT_TRUE(false) << "Wait on Input/Output is found indefinite"; + break; } } } @@ -675,6 +765,28 @@ TEST_F(VideoDecHidlTest, DecodeTest) { } eleInfo.close(); + // set port mode + if (isSecure) { + portMode[0] = PortMode::PRESET_SECURE_BUFFER; + portMode[1] = PortMode::DYNAMIC_ANW_BUFFER; + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + } else { + portMode[0] = PortMode::PRESET_BYTE_BUFFER; + portMode[1] = PortMode::DYNAMIC_ANW_BUFFER; + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + if (status != ::android::hardware::media::omx::V1_0::Status::OK) { + portMode[1] = PortMode::PRESET_BYTE_BUFFER; + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, + ::android::hardware::media::omx::V1_0::Status::OK); + } + } + // set Port Params uint32_t nFrameWidth, nFrameHeight, xFramerate; OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatYUV420Planar; @@ -682,23 +794,38 @@ TEST_F(VideoDecHidlTest, DecodeTest) { &xFramerate); setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); + omxNode->prepareForAdaptivePlayback(kPortIndexOutput, false, 1920, 1080); android::Vector iBuffer, oBuffer; // set state to idle changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + kPortIndexInput, kPortIndexOutput, portMode); // set state to executing changeStateIdletoExecute(omxNode, observer); + + if (portMode[1] != PortMode::PRESET_BYTE_BUFFER) { + OMX_PARAM_PORTDEFINITIONTYPE portDef; + + status = getPortParam(omxNode, OMX_IndexParamPortDefinition, + kPortIndexOutput, &portDef); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + allocateGraphicBuffers( + omxNode, kPortIndexOutput, &oBuffer, + portDef.format.video.nFrameWidth, portDef.format.video.nFrameHeight, + &portDef.format.video.nStride, portDef.nBufferCountActual); + } + // Port Reconfiguration eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, eleStream, &Info, 0, (int)Info.size()); + kPortIndexOutput, eleStream, &Info, 0, (int)Info.size(), + portMode[1]); eleStream.close(); waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); - testEOS(&iBuffer, &oBuffer); + kPortIndexInput, kPortIndexOutput, portMode[1]); + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, portMode); EXPECT_EQ(timestampUslist.empty(), true); // set state to idle changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); @@ -730,18 +857,25 @@ TEST_F(VideoDecHidlTest, EOSTest_M) { &xFramerate); setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); - omxNode->prepareForAdaptivePlayback(kPortIndexOutput, false, 1920, 1080); + + // set port mode + PortMode portMode[2]; + portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER; + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); android::Vector iBuffer, oBuffer; // set state to idle changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + kPortIndexInput, kPortIndexOutput, portMode); // set state to executing changeStateIdletoExecute(omxNode, observer); // request EOS at the start - testEOS(&iBuffer, &oBuffer, true); + testEOS(omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode); flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput); EXPECT_GE(framesReceived, 0U); @@ -798,13 +932,20 @@ TEST_F(VideoDecHidlTest, ThumbnailTest) { &xFramerate); setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); - omxNode->prepareForAdaptivePlayback(kPortIndexOutput, false, 1920, 1080); + + // set port mode + PortMode portMode[2]; + portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER; + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); android::Vector iBuffer, oBuffer; // set state to idle changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + kPortIndexInput, kPortIndexOutput, portMode); // set state to executing changeStateIdletoExecute(omxNode, observer); @@ -814,11 +955,11 @@ TEST_F(VideoDecHidlTest, ThumbnailTest) { eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, eleStream, &Info, 0, i + 1); + kPortIndexOutput, eleStream, &Info, 0, i + 1, portMode[1]); eleStream.close(); waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); - testEOS(&iBuffer, &oBuffer); + kPortIndexInput, kPortIndexOutput, portMode[1]); + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, portMode); flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput); EXPECT_GE(framesReceived, 1U); @@ -828,11 +969,12 @@ TEST_F(VideoDecHidlTest, ThumbnailTest) { eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, eleStream, &Info, 0, i + 1, false); + kPortIndexOutput, eleStream, &Info, 0, i + 1, portMode[1], + false); eleStream.close(); waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); - testEOS(&iBuffer, &oBuffer, true); + kPortIndexInput, kPortIndexOutput, portMode[1]); + testEOS(omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode); flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput); EXPECT_GE(framesReceived, 1U); @@ -889,13 +1031,20 @@ TEST_F(VideoDecHidlTest, SimpleEOSTest) { &xFramerate); setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); - omxNode->prepareForAdaptivePlayback(kPortIndexOutput, false, 1920, 1080); + + // set port mode + PortMode portMode[2]; + portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER; + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); android::Vector iBuffer, oBuffer; // set state to idle changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + kPortIndexInput, kPortIndexOutput, portMode); // set state to executing changeStateIdletoExecute(omxNode, observer); @@ -903,11 +1052,12 @@ TEST_F(VideoDecHidlTest, SimpleEOSTest) { eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, eleStream, &Info, 0, (int)Info.size()); + kPortIndexOutput, eleStream, &Info, 0, (int)Info.size(), + portMode[1]); eleStream.close(); waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); - testEOS(&iBuffer, &oBuffer); + kPortIndexInput, kPortIndexOutput, portMode[1]); + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, portMode); flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput); framesReceived = 0; @@ -964,11 +1114,19 @@ TEST_F(VideoDecHidlTest, FlushTest) { setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused, eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate); + // set port mode + PortMode portMode[2]; + portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER; + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + android::Vector iBuffer, oBuffer; // set state to idle changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + kPortIndexInput, kPortIndexOutput, portMode); // set state to executing changeStateIdletoExecute(omxNode, observer); @@ -979,7 +1137,8 @@ TEST_F(VideoDecHidlTest, FlushTest) { eleStream.open(mURL, std::ifstream::binary); ASSERT_EQ(eleStream.is_open(), true); decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, - kPortIndexOutput, eleStream, &Info, 0, nFrames, false); + kPortIndexOutput, eleStream, &Info, 0, nFrames, portMode[1], + false); // Note: Assumes 200 ms is enough to end any decode call that started flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput, 200000); @@ -1001,7 +1160,7 @@ TEST_F(VideoDecHidlTest, FlushTest) { if (keyFrame) { decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput, eleStream, &Info, index, - Info.size() - index, false); + Info.size() - index, portMode[1], false); } // Note: Assumes 200 ms is enough to end any decode call that started flushPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp index 72ab9373..6bc95cab 100644 --- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp +++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp @@ -21,6 +21,11 @@ #include +#include +#include +#include +#include +#include #include #include #include @@ -29,11 +34,17 @@ #include #include +using ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer; +using ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener; +using ::android::hardware::graphics::common::V1_0::BufferUsage; +using ::android::hardware::graphics::common::V1_0::PixelFormat; +using ::android::hardware::media::omx::V1_0::IGraphicBufferSource; 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::hardware::media::omx::V1_0::PortMode; using ::android::hidl::allocator::V1_0::IAllocator; using ::android::hidl::memory::V1_0::IMemory; using ::android::hidl::memory::V1_0::IMapper; @@ -48,6 +59,7 @@ using ::android::sp; #include #include #include +#include #include // A class for test environment setup @@ -140,7 +152,10 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { omx = ::testing::VtsHalHidlTargetTestBase::getService( gEnv->getInstance()); ASSERT_NE(omx, nullptr); - observer = new CodecObserver([](Message msg) { (void)msg; }); + observer = + new CodecObserver([this](Message msg, const BufferInfo* buffer) { + handleMessage(msg, buffer); + }); ASSERT_NE(observer, nullptr); if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0) disableTest = true; @@ -196,6 +211,19 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { } } if (i == kNumCompToCompression) disableTest = true; + eosFlag = false; + prependSPSPPS = false; + timestampDevTest = false; + producer = nullptr; + source = nullptr; + isSecure = false; + size_t suffixLen = strlen(".secure"); + if (strlen(gEnv->getComponent().c_str()) >= suffixLen) { + } + isSecure = !strcmp(gEnv->getComponent().c_str() + + strlen(gEnv->getComponent().c_str()) - suffixLen, + ".secure"); + if (isSecure) disableTest = true; if (disableTest) std::cerr << "[ ] Warning ! Test Disabled\n"; } @@ -206,6 +234,63 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { } } + // callback function to process messages received by onMessages() from IL + // client. + void handleMessage(Message msg, const BufferInfo* buffer) { + (void)buffer; + + if (msg.type == Message::Type::FILL_BUFFER_DONE) { + if (msg.data.extendedBufferData.flags & OMX_BUFFERFLAG_EOS) { + eosFlag = true; + } + if (msg.data.extendedBufferData.rangeLength != 0) { + // Test if current timestamp is among the list of queued + // timestamps + if (timestampDevTest && (prependSPSPPS || + (msg.data.extendedBufferData.flags & + OMX_BUFFERFLAG_CODECCONFIG) == 0)) { + bool tsHit = false; + android::List::iterator it = + timestampUslist.begin(); + while (it != timestampUslist.end()) { + if (*it == msg.data.extendedBufferData.timestampUs) { + timestampUslist.erase(it); + tsHit = true; + break; + } + it++; + } + if (tsHit == false) { + if (timestampUslist.empty() == false) { + EXPECT_EQ(tsHit, true) + << "TimeStamp not recognized"; + } else { + std::cerr + << "[ ] Warning ! Received non-zero " + "output / TimeStamp not recognized \n"; + } + } + } +#define WRITE_OUTPUT 0 +#if WRITE_OUTPUT + static int count = 0; + FILE* ofp = nullptr; + if (count) + ofp = fopen("out.bin", "ab"); + else + ofp = fopen("out.bin", "wb"); + if (ofp != nullptr) { + fwrite(static_cast(buffer->mMemory->getPointer()), + sizeof(char), + msg.data.extendedBufferData.rangeLength, ofp); + fclose(ofp); + count++; + } +#endif + } + } + } + enum standardComp { h263, avc, @@ -222,6 +307,13 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { standardComp compName; OMX_VIDEO_CODINGTYPE eCompressionFormat; bool disableTest; + bool eosFlag; + bool prependSPSPPS; + ::android::List timestampUslist; + bool timestampDevTest; + bool isSecure; + sp producer; + sp source; protected: static void description(const std::string& description) { @@ -229,6 +321,30 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { } }; +// CodecProducerListener class +struct CodecProducerListener : public IProducerListener { + public: + CodecProducerListener(int a, int b) + : freeBuffers(a), minUnDequeuedCount(b) {} + virtual ::android::hardware::Return onBufferReleased() override { + android::Mutex::Autolock autoLock(bufferLock); + freeBuffers += 1; + return Void(); + } + virtual ::android::hardware::Return needsReleaseNotify() override { + return true; + } + void reduceCount() { + android::Mutex::Autolock autoLock(bufferLock); + freeBuffers -= 1; + EXPECT_GE(freeBuffers, minUnDequeuedCount); + } + + size_t freeBuffers; + size_t minUnDequeuedCount; + android::Mutex bufferLock; +}; + // request VOP refresh void requestIDR(sp omxNode, OMX_U32 portIndex) { android::hardware::media::omx::V1_0::Status status; @@ -375,13 +491,313 @@ void GetURLForComponent(char* URL) { strcat(URL, "bbb_352x288_420p_30fps_32frames.yuv"); } +// blocking call to ensures application to Wait till all the inputs are consumed +void waitOnInputConsumption(sp omxNode, sp observer, + android::Vector* iBuffer, + android::Vector* oBuffer, + bool inputDataIsMeta = false, + sp listener = nullptr) { + android::hardware::media::omx::V1_0::Status status; + Message msg; + int timeOut = TIMEOUT_COUNTER; + + while (timeOut--) { + size_t i = 0; + status = + observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); + EXPECT_EQ(status, + android::hardware::media::omx::V1_0::Status::TIMED_OUT); + // status == TIMED_OUT, it could be due to process time being large + // than DEFAULT_TIMEOUT or component needs output buffers to start + // processing. + if (inputDataIsMeta) { + if (listener->freeBuffers == iBuffer->size()) break; + } else { + for (; i < iBuffer->size(); i++) { + if ((*iBuffer)[i].owner != client) break; + } + if (i == iBuffer->size()) break; + } + + // Dispatch an output buffer assuming outQueue.empty() is true + size_t index; + if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { + dispatchOutputBuffer(omxNode, oBuffer, index); + } + } +} + +int colorFormatConversion(BufferInfo* buffer, void* buff, PixelFormat format, + std::ifstream& eleStream) { + sp mapper = + android::hardware::graphics::mapper::V2_0::IMapper::getService(); + EXPECT_NE(mapper.get(), nullptr); + if (mapper.get() == nullptr) return 1; + + android::hardware::hidl_handle fence; + android::hardware::graphics::mapper::V2_0::IMapper::Rect rect; + android::hardware::graphics::mapper::V2_0::YCbCrLayout ycbcrLayout; + android::hardware::graphics::mapper::V2_0::Error error; + rect.left = 0; + rect.top = 0; + rect.width = buffer->omxBuffer.attr.anwBuffer.width; + rect.height = buffer->omxBuffer.attr.anwBuffer.height; + + if (format == PixelFormat::YV12) { + mapper->lockYCbCr( + buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, fence, + [&](android::hardware::graphics::mapper::V2_0::Error _e, + android::hardware::graphics::mapper::V2_0::YCbCrLayout _n1) { + error = _e; + ycbcrLayout = _n1; + }); + EXPECT_EQ(error, + android::hardware::graphics::mapper::V2_0::Error::NONE); + if (error != android::hardware::graphics::mapper::V2_0::Error::NONE) + return 1; + + EXPECT_EQ(ycbcrLayout.chromaStep, 1U); + char* ipBuffer = static_cast(ycbcrLayout.y); + for (size_t y = rect.height; y > 0; --y) { + eleStream.read(ipBuffer, rect.width); + if (eleStream.gcount() != rect.width) return 1; + ipBuffer += ycbcrLayout.yStride; + } + ipBuffer = static_cast(ycbcrLayout.cb); + for (size_t y = rect.height >> 1; y > 0; --y) { + eleStream.read(ipBuffer, rect.width >> 1); + if (eleStream.gcount() != rect.width >> 1) return 1; + ipBuffer += ycbcrLayout.cStride; + } + ipBuffer = static_cast(ycbcrLayout.cr); + for (size_t y = rect.height >> 1; y > 0; --y) { + eleStream.read(ipBuffer, rect.width >> 1); + if (eleStream.gcount() != rect.width >> 1) return 1; + ipBuffer += ycbcrLayout.cStride; + } + + mapper->unlock(buff, + [&](android::hardware::graphics::mapper::V2_0::Error _e, + android::hardware::hidl_handle _n1) { + error = _e; + fence = _n1; + }); + EXPECT_EQ(error, + android::hardware::graphics::mapper::V2_0::Error::NONE); + if (error != android::hardware::graphics::mapper::V2_0::Error::NONE) + return 1; + } else if (format == PixelFormat::YCBCR_420_888) { + void* data; + mapper->lock(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, fence, + [&](android::hardware::graphics::mapper::V2_0::Error _e, + void* _n1) { + error = _e; + data = _n1; + }); + EXPECT_EQ(error, + android::hardware::graphics::mapper::V2_0::Error::NONE); + if (error != android::hardware::graphics::mapper::V2_0::Error::NONE) + return 1; + + ycbcrLayout.chromaStep = 1; + ycbcrLayout.yStride = buffer->omxBuffer.attr.anwBuffer.stride; + ycbcrLayout.cStride = ycbcrLayout.yStride >> 1; + ycbcrLayout.y = data; + ycbcrLayout.cb = static_cast(ycbcrLayout.y) + + (ycbcrLayout.yStride * rect.height); + ycbcrLayout.cr = static_cast(ycbcrLayout.cb) + + ((ycbcrLayout.yStride * rect.height) >> 2); + + char* ipBuffer = static_cast(ycbcrLayout.y); + for (size_t y = rect.height; y > 0; --y) { + eleStream.read(ipBuffer, rect.width); + if (eleStream.gcount() != rect.width) return 1; + ipBuffer += ycbcrLayout.yStride; + } + ipBuffer = static_cast(ycbcrLayout.cb); + for (size_t y = rect.height >> 1; y > 0; --y) { + eleStream.read(ipBuffer, rect.width >> 1); + if (eleStream.gcount() != rect.width >> 1) return 1; + ipBuffer += ycbcrLayout.cStride; + } + ipBuffer = static_cast(ycbcrLayout.cr); + for (size_t y = rect.height >> 1; y > 0; --y) { + eleStream.read(ipBuffer, rect.width >> 1); + if (eleStream.gcount() != rect.width >> 1) return 1; + ipBuffer += ycbcrLayout.cStride; + } + + mapper->unlock(buff, + [&](android::hardware::graphics::mapper::V2_0::Error _e, + android::hardware::hidl_handle _n1) { + error = _e; + fence = _n1; + }); + EXPECT_EQ(error, + android::hardware::graphics::mapper::V2_0::Error::NONE); + if (error != android::hardware::graphics::mapper::V2_0::Error::NONE) + return 1; + } else { + EXPECT_TRUE(false) << "un expected pixel format"; + return 1; + } + + return 0; +} + +int fillGraphicBuffer(BufferInfo* buffer, PixelFormat format, + std::ifstream& eleStream) { + sp mapper = + android::hardware::graphics::mapper::V2_0::IMapper::getService(); + EXPECT_NE(mapper.get(), nullptr); + if (mapper.get() == nullptr) return 1; + + void* buff = nullptr; + android::hardware::graphics::mapper::V2_0::Error error; + mapper->importBuffer( + buffer->omxBuffer.nativeHandle, + [&](android::hardware::graphics::mapper::V2_0::Error _e, void* _n1) { + error = _e; + buff = _n1; + }); + EXPECT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE); + if (error != android::hardware::graphics::mapper::V2_0::Error::NONE) + return 1; + + if (colorFormatConversion(buffer, buff, format, eleStream)) return 1; + + error = mapper->freeBuffer(buff); + EXPECT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE); + if (error != android::hardware::graphics::mapper::V2_0::Error::NONE) + return 1; + + return 0; +} + +int dispatchGraphicBuffer(sp omxNode, + sp producer, + sp listener, + android::Vector* buffArray, + OMX_U32 portIndex, std::ifstream& eleStream, + uint64_t timestamp) { + 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); + if (status != ::android::hardware::media::omx::V1_0::Status::OK) return 1; + + enum { + // A flag returned by dequeueBuffer when the client needs to call + // requestBuffer immediately thereafter. + BUFFER_NEEDS_REALLOCATION = 0x1, + // A flag returned by dequeueBuffer when all mirrored slots should be + // released by the client. This flag should always be processed first. + RELEASE_ALL_BUFFERS = 0x2, + }; + + int32_t slot; + int32_t result; + ::android::hardware::hidl_handle fence; + IGraphicBufferProducer::FrameEventHistoryDelta outTimestamps; + ::android::hardware::media::V1_0::AnwBuffer AnwBuffer; + PixelFormat format = PixelFormat::YV12; + producer->dequeueBuffer( + portDef.format.video.nFrameWidth, portDef.format.video.nFrameHeight, + format, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN, + true, [&](int32_t _s, int32_t const& _n1, + ::android::hardware::hidl_handle const& _n2, + IGraphicBufferProducer::FrameEventHistoryDelta const& _n3) { + result = _s; + slot = _n1; + fence = _n2; + outTimestamps = _n3; + }); + if (result & BUFFER_NEEDS_REALLOCATION) { + producer->requestBuffer( + slot, [&](int32_t _s, + ::android::hardware::media::V1_0::AnwBuffer const& _n1) { + result = _s; + AnwBuffer = _n1; + }); + EXPECT_EQ(result, 0); + if (result != 0) return 1; + size_t i; + for (i = 0; i < buffArray->size(); i++) { + if ((*buffArray)[i].slot == -1) { + buffArray->editItemAt(i).slot = slot; + buffArray->editItemAt(i).omxBuffer.nativeHandle = + AnwBuffer.nativeHandle; + buffArray->editItemAt(i).omxBuffer.attr.anwBuffer = + AnwBuffer.attr; + break; + } + } + EXPECT_NE(i, buffArray->size()); + if (i == buffArray->size()) return 1; + } + EXPECT_EQ(result, 0); + if (result != 0) return 1; + + // fill Buffer + BufferInfo buffer; + size_t i; + for (i = 0; i < buffArray->size(); i++) { + if ((*buffArray)[i].slot == slot) { + buffer = (*buffArray)[i]; + break; + } + } + EXPECT_NE(i, buffArray->size()); + if (i == buffArray->size()) return 1; + if (fillGraphicBuffer(&buffer, format, eleStream)) return 1; + + // queue Buffer + IGraphicBufferProducer::QueueBufferOutput output; + IGraphicBufferProducer::QueueBufferInput input; + android::hardware::media::V1_0::Rect rect; + rect.left = 0; + rect.top = 0; + rect.right = buffer.omxBuffer.attr.anwBuffer.width; + rect.bottom = buffer.omxBuffer.attr.anwBuffer.height; + input.timestamp = timestamp; + input.isAutoTimestamp = false; + input.dataSpace = + android::hardware::graphics::common::V1_0::Dataspace::UNKNOWN; + input.crop = rect; + input.scalingMode = 0; + input.transform = 0; + input.stickyTransform = 0; + input.fence = android::hardware::hidl_handle(); + input.surfaceDamage = + android::hardware::hidl_vec{rect}; + input.getFrameTimestamps = false; + producer->queueBuffer( + buffer.slot, input, + [&](int32_t _s, const IGraphicBufferProducer::QueueBufferOutput& _n1) { + result = _s; + output = _n1; + }); + EXPECT_EQ(result, 0); + if (result != 0) return 1; + + listener->reduceCount(); + + return 0; +} + // Encode N Frames void encodeNFrames(sp omxNode, sp observer, - OMX_U32 portIndexOutput, + OMX_U32 portIndexInput, OMX_U32 portIndexOutput, android::Vector* iBuffer, android::Vector* oBuffer, uint32_t nFrames, uint32_t xFramerate, int bytesCount, - std::ifstream& eleStream) { + std::ifstream& eleStream, + ::android::List* timestampUslist = nullptr, + bool signalEOS = true, bool inputDataIsMeta = false, + sp producer = nullptr, + sp listener = nullptr) { android::hardware::media::omx::V1_0::Status status; Message msg; uint32_t ipCount = 0; @@ -398,20 +814,39 @@ void encodeNFrames(sp omxNode, sp observer, } // dispatch input buffers int32_t timestampIncr = (int)((float)1000000 / (xFramerate >> 16)); + // timestamp scale = Nano sec + if (inputDataIsMeta) timestampIncr *= 1000; uint64_t timestamp = 0; + uint32_t flags = 0; for (size_t i = 0; i < iBuffer->size() && nFrames != 0; i++) { - char* ipBuffer = static_cast( - static_cast((*iBuffer)[i].mMemory->getPointer())); - ASSERT_LE(bytesCount, - static_cast((*iBuffer)[i].mMemory->getSize())); - eleStream.read(ipBuffer, bytesCount); - if (eleStream.gcount() != bytesCount) break; - dispatchInputBuffer(omxNode, iBuffer, i, bytesCount, 0, timestamp); - timestamp += timestampIncr; - nFrames--; - ipCount++; + if (inputDataIsMeta) { + if (listener->freeBuffers > listener->minUnDequeuedCount) { + if (dispatchGraphicBuffer(omxNode, producer, listener, iBuffer, + portIndexInput, eleStream, timestamp)) + break; + timestamp += timestampIncr; + nFrames--; + ipCount++; + } + } else { + char* ipBuffer = static_cast( + static_cast((*iBuffer)[i].mMemory->getPointer())); + ASSERT_LE(bytesCount, + static_cast((*iBuffer)[i].mMemory->getSize())); + eleStream.read(ipBuffer, bytesCount); + if (eleStream.gcount() != bytesCount) break; + if (signalEOS && (nFrames == 1)) flags = OMX_BUFFERFLAG_EOS; + dispatchInputBuffer(omxNode, iBuffer, i, bytesCount, flags, + timestamp); + if (timestampUslist) timestampUslist->push_back(timestamp); + timestamp += timestampIncr; + nFrames--; + ipCount++; + } } + int timeOut = TIMEOUT_COUNTER; + bool stall = false; while (1) { status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); @@ -422,6 +857,9 @@ void encodeNFrames(sp omxNode, sp observer, ASSERT_EQ(msg.data.eventData.data1, portIndexOutput); ASSERT_EQ(msg.data.eventData.data2, OMX_IndexConfigAndroidIntraRefresh); + } else if (msg.data.eventData.event == OMX_EventError) { + EXPECT_TRUE(false) << "Received OMX_EventError, not sure why"; + break; } else { ASSERT_TRUE(false); } @@ -431,21 +869,51 @@ void encodeNFrames(sp omxNode, sp observer, // Dispatch input buffer size_t index = 0; - if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) { - char* ipBuffer = static_cast( - static_cast((*iBuffer)[index].mMemory->getPointer())); - ASSERT_LE(bytesCount, - static_cast((*iBuffer)[index].mMemory->getSize())); - eleStream.read(ipBuffer, bytesCount); - if (eleStream.gcount() != bytesCount) break; - dispatchInputBuffer(omxNode, iBuffer, index, bytesCount, 0, - timestamp); - timestamp += timestampIncr; - nFrames--; - ipCount++; + if (inputDataIsMeta) { + if (listener->freeBuffers > listener->minUnDequeuedCount) { + if (dispatchGraphicBuffer(omxNode, producer, listener, iBuffer, + portIndexInput, eleStream, timestamp)) + break; + timestamp += timestampIncr; + nFrames--; + ipCount++; + stall = false; + } else { + stall = true; + } + } else { + if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) { + char* ipBuffer = static_cast(static_cast( + (*iBuffer)[index].mMemory->getPointer())); + ASSERT_LE( + bytesCount, + static_cast((*iBuffer)[index].mMemory->getSize())); + eleStream.read(ipBuffer, bytesCount); + if (eleStream.gcount() != bytesCount) break; + if (signalEOS && (nFrames == 1)) flags = OMX_BUFFERFLAG_EOS; + dispatchInputBuffer(omxNode, iBuffer, index, bytesCount, flags, + timestamp); + if (timestampUslist) timestampUslist->push_back(timestamp); + timestamp += timestampIncr; + nFrames--; + ipCount++; + stall = false; + } else { + stall = true; + } } if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) { dispatchOutputBuffer(omxNode, oBuffer, index); + stall = false; + } else + stall = true; + if (stall) + timeOut--; + else + timeOut = TIMEOUT_COUNTER; + if (timeOut == 0) { + EXPECT_TRUE(false) << "Wait on Input/Output is found indefinite"; + break; } if (ipCount == 15) { changeBitrate(omxNode, portIndexOutput, 768000); @@ -491,7 +959,7 @@ TEST_F(VideoEncHidlTest, EnumeratePortFormat) { EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); } -// test raw stream encode +// test raw stream encode (input is byte buffers) TEST_F(VideoEncHidlTest, EncodeTest) { description("Test Encode"); if (disableTest) return; @@ -511,8 +979,8 @@ TEST_F(VideoEncHidlTest, EncodeTest) { GetURLForComponent(mURL); std::ifstream eleStream; - eleStream.open(mURL, std::ifstream::binary); - ASSERT_EQ(eleStream.is_open(), true); + + timestampDevTest = true; // Configure input port uint32_t nFrameWidth = 352; @@ -526,6 +994,7 @@ TEST_F(VideoEncHidlTest, EncodeTest) { setDefaultPortParam(omxNode, kPortIndexOutput, eCompressionFormat, nBitRate, xFramerate); setRefreshPeriod(omxNode, kPortIndexOutput, 0); + unsigned int index; omxNode->getExtensionIndex( "OMX.google.android.index.prependSPSPPSToIDRFrames", @@ -542,24 +1011,299 @@ TEST_F(VideoEncHidlTest, EncodeTest) { if (status != ::android::hardware::media::omx::V1_0::Status::OK) std::cerr << "[ ] Warning ! unable to prependSPSPPSToIDRFrames\n"; + else + prependSPSPPS = true; + + // set port mode + PortMode portMode[2]; + portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER; + if (isSecure && prependSPSPPS) portMode[1] = PortMode::PRESET_SECURE_BUFFER; + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); android::Vector iBuffer, oBuffer; // set state to idle changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, - kPortIndexInput, kPortIndexOutput); + kPortIndexInput, kPortIndexOutput, portMode); // set state to executing changeStateIdletoExecute(omxNode, observer); - encodeNFrames(omxNode, observer, kPortIndexOutput, &iBuffer, &oBuffer, 1024, - xFramerate, (nFrameWidth * nFrameHeight * 3) >> 1, eleStream); + eleStream.open(mURL, std::ifstream::binary); + ASSERT_EQ(eleStream.is_open(), true); + encodeNFrames(omxNode, observer, kPortIndexInput, kPortIndexOutput, + &iBuffer, &oBuffer, 32, xFramerate, + (nFrameWidth * nFrameHeight * 3) >> 1, eleStream, + ×tampUslist); + eleStream.close(); + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer); + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag); + EXPECT_EQ(timestampUslist.empty(), true); + // set state to idle changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); // set state to executing changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput, kPortIndexOutput); +} + +// test raw stream encode (input is ANW buffers) +TEST_F(VideoEncHidlTest, EncodeTestBufferMetaModes) { + description("Test Encode Input buffer metamodes"); + if (disableTest) return; + 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_IndexParamVideoInit, ¶ms); + if (status == ::android::hardware::media::omx::V1_0::Status::OK) { + ASSERT_EQ(params.nPorts, 2U); + kPortIndexInput = params.nStartPortNumber; + kPortIndexOutput = kPortIndexInput + 1; + } + + // Configure input port + uint32_t nFrameWidth = 352; + uint32_t nFrameHeight = 288; + uint32_t xFramerate = (30U << 16); + OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatAndroidOpaque; + setupRAWPort(omxNode, kPortIndexInput, nFrameWidth, nFrameHeight, 0, + xFramerate, eColorFormat); + + // CreateInputSurface + EXPECT_TRUE(omx->createInputSurface( + [&](android::hardware::media::omx::V1_0::Status _s, + sp const& _nl, + sp const& _n2) { + status = _s; + producer = _nl; + source = _n2; + }) + .isOk()); + ASSERT_NE(producer, nullptr); + ASSERT_NE(source, nullptr); + + // Do setInputSurface() + // enable MetaMode on input port + status = source->configure( + omxNode, android::hardware::graphics::common::V1_0::Dataspace::UNKNOWN); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + + // setMaxDequeuedBufferCount + int32_t returnval; + int32_t value; + producer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + [&returnval, &value](int32_t _s, int32_t _n1) { + returnval = _s; + value = _n1; + }); + ASSERT_EQ(returnval, 0); + OMX_PARAM_PORTDEFINITIONTYPE portDef; + status = getPortParam(omxNode, OMX_IndexParamPortDefinition, + kPortIndexInput, &portDef); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + ASSERT_EQ(::android::OK, + producer->setMaxDequeuedBufferCount(portDef.nBufferCountActual)); + + // Connect :: Mock Producer Listener + IGraphicBufferProducer::QueueBufferOutput qbo; + sp listener = + new CodecProducerListener(portDef.nBufferCountActual + value, value); + producer->connect( + listener, NATIVE_WINDOW_API_CPU, false, + [&](int32_t _s, IGraphicBufferProducer::QueueBufferOutput const& _n1) { + returnval = _s; + qbo = _n1; + }); + ASSERT_EQ(returnval, 0); + + portDef.nBufferCountActual = portDef.nBufferCountActual + value; + status = setPortParam(omxNode, OMX_IndexParamPortDefinition, + kPortIndexInput, &portDef); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + + // set port mode + PortMode portMode[2]; + portMode[0] = PortMode::DYNAMIC_ANW_BUFFER; + portMode[1] = PortMode::PRESET_BYTE_BUFFER; + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + + char mURL[512]; + strcpy(mURL, gEnv->getRes().c_str()); + GetURLForComponent(mURL); + + std::ifstream eleStream; + + status = source->setSuspend(false, 0); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = source->setRepeatPreviousFrameDelayUs(100000); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = source->setMaxFps(24.0f); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = source->setTimeLapseConfig(24.0, 24.0); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = source->setTimeOffsetUs(-100); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = source->setStartTimeUs(10); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = source->setStopTimeUs(1000000); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + ::android::hardware::media::omx::V1_0::ColorAspects aspects; + aspects.range = + ::android::hardware::media::omx::V1_0::ColorAspects::Range::UNSPECIFIED; + aspects.primaries = ::android::hardware::media::omx::V1_0::ColorAspects:: + Primaries::UNSPECIFIED; + aspects.transfer = ::android::hardware::media::omx::V1_0::ColorAspects:: + Transfer::UNSPECIFIED; + aspects.matrixCoeffs = ::android::hardware::media::omx::V1_0::ColorAspects:: + MatrixCoeffs::UNSPECIFIED; + status = source->setColorAspects(aspects); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + int64_t stopTimeOffsetUs; + source->getStopTimeOffsetUs( + [&](android::hardware::media::omx::V1_0::Status _s, int64_t _n1) { + status = _s; + stopTimeOffsetUs = _n1; + }); + EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + + android::Vector iBuffer, oBuffer; + // set state to idle + changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode); + // set state to executing + changeStateIdletoExecute(omxNode, observer); + eleStream.open(mURL, std::ifstream::binary); + ASSERT_EQ(eleStream.is_open(), true); + encodeNFrames(omxNode, observer, kPortIndexInput, kPortIndexOutput, + &iBuffer, &oBuffer, 1024, xFramerate, + (nFrameWidth * nFrameHeight * 3) >> 1, eleStream, nullptr, + false, true, producer, listener); eleStream.close(); + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, true, + listener); + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag); + + // set state to idle + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + EXPECT_EQ(portDef.nBufferCountActual, listener->freeBuffers); + // set state to executing + changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput); + + returnval = producer->disconnect( + NATIVE_WINDOW_API_CPU, IGraphicBufferProducer::DisconnectMode::API); + ASSERT_EQ(returnval, 0); +} + +// Test end of stream +TEST_F(VideoEncHidlTest, EncodeTestEOS) { + description("Test EOS"); + if (disableTest) return; + 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_IndexParamVideoInit, ¶ms); + if (status == ::android::hardware::media::omx::V1_0::Status::OK) { + ASSERT_EQ(params.nPorts, 2U); + kPortIndexInput = params.nStartPortNumber; + kPortIndexOutput = kPortIndexInput + 1; + } + + // CreateInputSurface + EXPECT_TRUE(omx->createInputSurface( + [&](android::hardware::media::omx::V1_0::Status _s, + sp const& _nl, + sp const& _n2) { + status = _s; + producer = _nl; + source = _n2; + }) + .isOk()); + ASSERT_NE(producer, nullptr); + ASSERT_NE(source, nullptr); + + // Do setInputSurface() + // enable MetaMode on input port + status = source->configure( + omxNode, android::hardware::graphics::common::V1_0::Dataspace::UNKNOWN); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + + // setMaxDequeuedBufferCount + int32_t returnval; + int32_t value; + producer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + [&returnval, &value](int32_t _s, int32_t _n1) { + returnval = _s; + value = _n1; + }); + ASSERT_EQ(returnval, 0); + OMX_PARAM_PORTDEFINITIONTYPE portDef; + status = getPortParam(omxNode, OMX_IndexParamPortDefinition, + kPortIndexInput, &portDef); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + ASSERT_EQ(::android::OK, + producer->setMaxDequeuedBufferCount(portDef.nBufferCountActual)); + + // Connect :: Mock Producer Listener + IGraphicBufferProducer::QueueBufferOutput qbo; + sp listener = + new CodecProducerListener(portDef.nBufferCountActual + value, value); + producer->connect( + listener, NATIVE_WINDOW_API_CPU, false, + [&](int32_t _s, IGraphicBufferProducer::QueueBufferOutput const& _n1) { + returnval = _s; + qbo = _n1; + }); + ASSERT_EQ(returnval, 0); + + portDef.nBufferCountActual = portDef.nBufferCountActual + value; + status = setPortParam(omxNode, OMX_IndexParamPortDefinition, + kPortIndexInput, &portDef); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + + // set port mode + PortMode portMode[2]; + portMode[0] = PortMode::DYNAMIC_ANW_BUFFER; + portMode[1] = PortMode::PRESET_BYTE_BUFFER; + status = omxNode->setPortMode(kPortIndexInput, portMode[0]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + + android::Vector iBuffer, oBuffer; + // set state to idle + changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput, portMode); + // set state to executing + changeStateIdletoExecute(omxNode, observer); + + // send EOS + status = source->signalEndOfInputStream(); + ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer, true, + listener); + testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag); + + // set state to idle + changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer); + EXPECT_EQ(portDef.nBufferCountActual, listener->freeBuffers); + // set state to executing + changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer, + kPortIndexInput, kPortIndexOutput); + + returnval = producer->disconnect( + NATIVE_WINDOW_API_CPU, IGraphicBufferProducer::DisconnectMode::API); + ASSERT_EQ(returnval, 0); } int main(int argc, char** argv) { diff --git a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp index 70350480..271b4d41 100644 --- a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp +++ b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.cpp @@ -15,6 +15,11 @@ */ #define LOG_TAG "media_omx_hidl_video_test_common" + +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + #include #include @@ -30,6 +35,7 @@ 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::hardware::media::omx::V1_0::PortMode; using ::android::hidl::allocator::V1_0::IAllocator; using ::android::hidl::memory::V1_0::IMemory; using ::android::hidl::memory::V1_0::IMapper; @@ -41,281 +47,11 @@ using ::android::sp; #include #include +#include #include #include #include -// allocate buffers needed on a component port -void allocatePortBuffers(sp omxNode, - android::Vector* buffArray, - OMX_U32 portIndex) { - android::hardware::media::omx::V1_0::Status status; - OMX_PARAM_PORTDEFINITIONTYPE portDef; - - buffArray->clear(); - - sp allocator = IAllocator::getService("ashmem"); - EXPECT_NE(allocator.get(), 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 = false; - allocator->allocate( - portDef.nBufferSize, - [&success, &buffer](bool _s, - ::android::hardware::hidl_memory const& mem) { - success = _s; - buffer.omxBuffer.sharedMemory = mem; - }); - ASSERT_EQ(success, true); - ASSERT_EQ(buffer.omxBuffer.sharedMemory.size(), portDef.nBufferSize); - 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); - } -} - -// State Transition : Loaded -> Idle -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateLoadedtoIdle(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, - OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // 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 are populated - 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, iBuffer, kPortIndexInput); - - // Dont switch states until the ports are populated - 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, oBuffer, kPortIndexOutput); - - // As the ports are populated, check if the state transition is complete - 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); - - return; -} - -// State Transition : Idle -> Loaded -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateIdletoLoaded(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, - OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // 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); - - return; -} - -// State Transition : Idle -> Execute -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateIdletoExecute(sp omxNode, - sp observer) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // set state to 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); - 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); - - return; -} - -// State Transition : Execute -> Idle -// Note: This function does not make any background checks for this transition. -// The callee holds the reponsibility to ensure the legality of the transition. -void changeStateExecutetoIdle(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // 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); - } - for (size_t i = 0; i < iBuffer->size(); ++i) { - EXPECT_EQ((*iBuffer)[i].owner, client); - } -} - -// get empty buffer index -size_t getEmptyBufferID(android::Vector* buffArray) { - for (size_t i = 0; i < buffArray->size(); i++) { - if ((*buffArray)[i].owner == client) return i; - } - return buffArray->size(); -} - -// dispatch buffer to output port -void dispatchOutputBuffer(sp omxNode, - android::Vector* 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; -} - -// dispatch buffer to input port -void dispatchInputBuffer(sp omxNode, - android::Vector* 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; -} - -// Flush input and output ports -void flushPorts(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput, int64_t timeoutUs) { - android::hardware::media::omx::V1_0::Status status; - Message msg; - - // Flush input port - status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), - kPortIndexInput); - ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); - status = observer->dequeueMessage(&msg, timeoutUs, 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); - } - - // Flush output port - status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush), - kPortIndexOutput); - ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); - status = observer->dequeueMessage(&msg, timeoutUs, 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); - } -} - Return setVideoPortFormat( sp omxNode, OMX_U32 portIndex, OMX_VIDEO_CODINGTYPE eCompressionFormat, OMX_COLOR_FORMATTYPE eColorFormat, diff --git a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h index 00f9afe2..ce4272cb 100644 --- a/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h +++ b/media/omx/1.0/vts/functional/video/media_video_hidl_test_common.h @@ -25,41 +25,6 @@ /* * Common video utils */ -void allocatePortBuffers(sp omxNode, - android::Vector* buffArray, - OMX_U32 portIndex); - -void changeStateLoadedtoIdle(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, - OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput); - -void changeStateIdletoLoaded(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, - OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput); - -void changeStateIdletoExecute(sp omxNode, sp observer); - -void changeStateExecutetoIdle(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer); - -size_t getEmptyBufferID(android::Vector* buffArray); - -void dispatchOutputBuffer(sp omxNode, - android::Vector* buffArray, - size_t bufferIndex); - -void dispatchInputBuffer(sp omxNode, - android::Vector* buffArray, - size_t bufferIndex, int bytesCount, uint32_t flags, - uint64_t timestamp); - -void flushPorts(sp omxNode, sp observer, - android::Vector* iBuffer, - android::Vector* oBuffer, OMX_U32 kPortIndexInput, - OMX_U32 kPortIndexOutput, int64_t timeoutUs = DEFAULT_TIMEOUT); Return setVideoPortFormat( sp omxNode, OMX_U32 portIndex, -- 2.11.0