diff --git a/media/Android.bp b/media/Android.bp index f25a609b1f..53e82bd711 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 d6c73ced79..66fd20be2c 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 1cc18174eb..5ba195e565 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 7d5f9685c2..ecd9ef98aa 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 f09d21d60b..abd044d769 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 d420ab5799..a7624367b8 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 0000000000..93251fe89b --- /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 0000000000..30344a1ee2 --- /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 52d8ae2079..a402532551 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 02fe182834..fd3210fb91 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 17c49ca441..39e8864f77 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 a8c8d99250..4e94f3b35b 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 35c2b0cafd..8caf697cdb 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 72ab9373f2..6bc95cab15 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 703504807d..271b4d41a7 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 00f9afe2d2..ce4272cbc0 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,