diff --git a/media/omx/1.0/vts/functional/README.md b/media/omx/1.0/vts/functional/README.md index fa88811e9e..acffc42943 100644 --- a/media/omx/1.0/vts/functional/README.md +++ b/media/omx/1.0/vts/functional/README.md @@ -9,7 +9,7 @@ Functionality of master is to enumerate all the omx components (and the roles it usage: VtsHalMediaOmxV1\_0TargetMasterTest -I default #### component : -This folder includes test fixtures that tests aspects common to all omx compatible components. For instance, port enabling/disabling, enumerating port formats, state transitions, flush, ..., stay common to all components irrespective of the service they offer. Test fixtures are directed towards testing the omx core. Every standard OMX compatible component is expected to pass these tests. +This folder includes test fixtures that tests aspects common to all omx compatible components. For instance, port enabling/disabling, enumerating port formats, state transitions, flush, ..., stay common to all components irrespective of the service they offer. Test fixtures here are directed towards testing these (omx core). Every standard OMX compatible component is expected to pass these tests. usage: VtsHalMediaOmxV1\_0TargetComponentTest -I default -C -R @@ -31,3 +31,4 @@ VtsHalMediaOmxV1\_0TargetVideoDecTest -I default -C -R video_decoder VtsHalMediaOmxV1\_0TargetVideoEncTest -I default -C -R video_encoder. -P /sdcard/media/ +While tesing audio/video encoder, decoder components, test fixtures require input files. These input are files are present in the folder 'res'. Before running the tests all the files in 'res' have to be placed in '/media/sdcard/' or a path of your choice and this path needs to be provided as an argument to the test application \ No newline at end of file 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 index 30344a1ee2..01d7751d26 100755 --- 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 @@ -425,8 +425,15 @@ void testEOS(sp omxNode, sp observer, Message msg; status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); - EXPECT_EQ(status, - android::hardware::media::omx::V1_0::Status::TIMED_OUT); + if (status == android::hardware::media::omx::V1_0::Status::OK) { + if (msg.data.eventData.event == OMX_EventBufferFlag) { + // soft omx components donot send this, we will just ignore it + // for now + } else { + // something unexpected happened + EXPECT_TRUE(false); + } + } if (eosFlag == true) break; } // test for flag 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 8caf697cdb..8ab01b537d 100644 --- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp +++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoDecTest.cpp @@ -214,7 +214,7 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { strlen(gEnv->getComponent().c_str()) - suffixLen, ".secure"); if (isSecure) disableTest = true; - if (disableTest) std::cerr << "[ ] Warning ! Test Disabled\n"; + if (disableTest) std::cout << "[ ] Warning ! Test Disabled\n"; } virtual void TearDown() override { @@ -257,7 +257,7 @@ class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { EXPECT_EQ(tsHit, true) << "TimeStamp not recognized"; } else { - std::cerr + std::cout << "[ ] Warning ! Received non-zero " "output / TimeStamp not recognized \n"; } @@ -478,7 +478,8 @@ void portReconfiguration(sp omxNode, sp observer, if (msg.data.eventData.event == OMX_EventPortSettingsChanged) { ASSERT_EQ(msg.data.eventData.data1, kPortIndexOutput); - if (msg.data.eventData.data2 == 0) { + if (msg.data.eventData.data2 == OMX_IndexParamPortDefinition || + msg.data.eventData.data2 == 0) { status = omxNode->sendCommand( toRawCommandType(OMX_CommandPortDisable), kPortIndexOutput); ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); @@ -532,6 +533,20 @@ void portReconfiguration(sp omxNode, sp observer, allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput, oPortMode); + if (oPortMode != 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); + } status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer); ASSERT_EQ(status, @@ -549,16 +564,19 @@ void portReconfiguration(sp omxNode, sp observer, } } else if (msg.data.eventData.data2 == OMX_IndexConfigCommonOutputCrop) { - std::cerr << "[ ] Warning ! OMX_EventPortSettingsChanged/ " + std::cout << "[ ] Warning ! OMX_EventPortSettingsChanged/ " "OMX_IndexConfigCommonOutputCrop not handled \n"; } else if (msg.data.eventData.data2 == OMX_IndexVendorStartUnused + 3) { - std::cerr << "[ ] Warning ! OMX_EventPortSettingsChanged/ " + std::cout << "[ ] Warning ! OMX_EventPortSettingsChanged/ " "kDescribeColorAspectsIndex not handled \n"; } } else if (msg.data.eventData.event == OMX_EventError) { - std::cerr << "[ ] Warning ! OMX_EventError/ " + std::cout << "[ ] Warning ! OMX_EventError/ " "Decode Frame Call might be failed \n"; return; + } else if (msg.data.eventData.event == OMX_EventBufferFlag) { + // soft omx components donot send this, we will just ignore it + // for now } else { // something unexpected happened ASSERT_TRUE(false); 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 6bc95cab15..7a57430770 100644 --- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp +++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ 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::IOmxBufferSource; using ::android::hardware::media::omx::V1_0::IOmx; using ::android::hardware::media::omx::V1_0::IOmxObserver; using ::android::hardware::media::omx::V1_0::IOmxNode; @@ -345,6 +347,82 @@ struct CodecProducerListener : public IProducerListener { android::Mutex bufferLock; }; +// Mock IOmxBufferSource class. GraphicBufferSource.cpp in libstagefright/omx/ +// implements this class. Below is dummy class introduced to test if callback +// functions are actually being called or not +struct DummyBufferSource : public IOmxBufferSource { + public: + DummyBufferSource(sp node) { + callback = 0; + executing = false; + omxNode = node; + } + virtual Return onOmxExecuting(); + virtual Return onOmxIdle(); + virtual Return onOmxLoaded(); + virtual Return onInputBufferAdded(uint32_t buffer); + virtual Return onInputBufferEmptied( + uint32_t buffer, const ::android::hardware::hidl_handle& fence); + + int callback; + bool executing; + sp omxNode; + android::Vector iBuffer, oBuffer; +}; + +Return DummyBufferSource::onOmxExecuting() { + executing = true; + callback |= 0x1; + size_t index; + // Fetch a client owned input buffer and send an EOS + if ((index = getEmptyBufferID(&iBuffer)) < iBuffer.size()) { + android::hardware::media::omx::V1_0::Status status; + CodecBuffer t = iBuffer[index].omxBuffer; + t.type = CodecBuffer::Type::ANW_BUFFER; + native_handle_t* fenceNh = native_handle_create(0, 0); + EXPECT_NE(fenceNh, nullptr); + status = omxNode->emptyBuffer(iBuffer[index].id, t, OMX_BUFFERFLAG_EOS, + 0, fenceNh); + native_handle_close(fenceNh); + native_handle_delete(fenceNh); + EXPECT_EQ(status, android::hardware::media::omx::V1_0::Status::OK); + iBuffer.editItemAt(index).owner = component; + } + return Void(); +}; + +Return DummyBufferSource::onOmxIdle() { + callback |= 0x2; + executing = false; + return Void(); +}; + +Return DummyBufferSource::onOmxLoaded() { + callback |= 0x4; + return Void(); +}; + +Return DummyBufferSource::onInputBufferAdded(uint32_t buffer) { + (void)buffer; + EXPECT_EQ(executing, false); + callback |= 0x8; + return Void(); +}; + +Return DummyBufferSource::onInputBufferEmptied( + uint32_t buffer, const ::android::hardware::hidl_handle& fence) { + (void)fence; + callback |= 0x10; + size_t i; + for (i = 0; i < iBuffer.size(); i++) { + if (iBuffer[i].id == buffer) { + iBuffer.editItemAt(i).owner = client; + break; + } + } + return Void(); +}; + // request VOP refresh void requestIDR(sp omxNode, OMX_U32 portIndex) { android::hardware::media::omx::V1_0::Status status; @@ -419,6 +497,27 @@ void setRefreshPeriod(sp omxNode, OMX_U32 portIndex, std::cerr << "[ ] Warning ! unable to set Refresh Period \n"; } +void setLatency(sp omxNode, OMX_U32 portIndex, uint32_t latency) { + android::hardware::media::omx::V1_0::Status status; + OMX_PARAM_U32TYPE param; + param.nU32 = (OMX_U32)latency; + status = setPortConfig(omxNode, (OMX_INDEXTYPE)OMX_IndexConfigLatency, + portIndex, ¶m); + if (status != ::android::hardware::media::omx::V1_0::Status::OK) + std::cerr << "[ ] Warning ! unable to set latency\n"; +} + +void getLatency(sp omxNode, OMX_U32 portIndex, uint32_t* latency) { + android::hardware::media::omx::V1_0::Status status; + OMX_PARAM_U32TYPE param; + status = getPortConfig(omxNode, (OMX_INDEXTYPE)OMX_IndexConfigLatency, + portIndex, ¶m); + if (status != ::android::hardware::media::omx::V1_0::Status::OK) + std::cerr << "[ ] Warning ! unable to get latency\n"; + else + *latency = param.nU32; +} + // Set Default port param. void setDefaultPortParam(sp omxNode, OMX_U32 portIndex, OMX_VIDEO_CODINGTYPE eCompressionFormat, @@ -586,7 +685,7 @@ int colorFormatConversion(BufferInfo* buffer, void* buff, PixelFormat format, 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) { + } else { void* data; mapper->lock(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, fence, [&](android::hardware::graphics::mapper::V2_0::Error _e, @@ -599,32 +698,75 @@ int colorFormatConversion(BufferInfo* buffer, void* buff, PixelFormat format, 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); + if (format == PixelFormat::YCBCR_420_888) { + 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; + 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; + } + } else if (format == PixelFormat::YCRCB_420_SP) { + ycbcrLayout.chromaStep = 2; + ycbcrLayout.yStride = buffer->omxBuffer.attr.anwBuffer.stride; + ycbcrLayout.cStride = ycbcrLayout.yStride; + ycbcrLayout.y = data; + ycbcrLayout.cr = static_cast(ycbcrLayout.y) + + (ycbcrLayout.yStride * rect.height); + ycbcrLayout.cb = static_cast(ycbcrLayout.cr) + 1; + + 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) { + for (int32_t x = 0; x> 1; ++x) { + eleStream.read(&ipBuffer[2 * x], 1); + if (eleStream.gcount() != 1) return 1; + } + ipBuffer += ycbcrLayout.cStride; + } + ipBuffer = static_cast(ycbcrLayout.cr); + for (size_t y = rect.height >> 1; y > 0; --y) { + for (int32_t x = 0; x> 1; ++x) { + eleStream.read(&ipBuffer[2 * x], 1); + if (eleStream.gcount() != 1) return 1; + } + ipBuffer += ycbcrLayout.cStride; + } + } else if (format == PixelFormat::BGRA_8888) { + char* ipBuffer = static_cast(data); + for (size_t y = rect.height; y > 0; --y) { + eleStream.read(ipBuffer, rect.width * 4); + if (eleStream.gcount() != rect.width * 4) return 1; + ipBuffer += buffer->omxBuffer.attr.anwBuffer.stride * 4; + } + } else { + EXPECT_TRUE(false) << "un expected pixel format"; + return 1; } mapper->unlock(buff, @@ -637,9 +779,6 @@ int colorFormatConversion(BufferInfo* buffer, void* buff, PixelFormat format, 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; @@ -959,6 +1098,63 @@ TEST_F(VideoEncHidlTest, EnumeratePortFormat) { EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); } +// Test IOmxBufferSource CallBacks +TEST_F(VideoEncHidlTest, BufferSourceCallBacks) { + description("Test IOmxBufferSource CallBacks"); + 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); + + sp buffersource = new DummyBufferSource(omxNode); + EXPECT_NE(buffersource, nullptr); + status = omxNode->setInputSurface(buffersource); + 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); + + // set state to idle + changeStateLoadedtoIdle(omxNode, observer, &buffersource->iBuffer, + &buffersource->oBuffer, kPortIndexInput, + kPortIndexOutput, portMode); + // set state to executing + changeStateIdletoExecute(omxNode, observer); + testEOS(omxNode, observer, &buffersource->iBuffer, &buffersource->oBuffer, + false, eosFlag); + // set state to idle + changeStateExecutetoIdle(omxNode, observer, &buffersource->iBuffer, + &buffersource->oBuffer); + // set state to executing + changeStateIdletoLoaded(omxNode, observer, &buffersource->iBuffer, + &buffersource->oBuffer, kPortIndexInput, + kPortIndexOutput); + // test for callbacks + EXPECT_EQ(buffersource->callback, 31); +} + // test raw stream encode (input is byte buffers) TEST_F(VideoEncHidlTest, EncodeTest) { description("Test Encode"); @@ -1023,6 +1219,10 @@ TEST_F(VideoEncHidlTest, EncodeTest) { status = omxNode->setPortMode(kPortIndexOutput, portMode[1]); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + uint32_t latency = 0; + setLatency(omxNode, kPortIndexInput, latency); + getLatency(omxNode, kPortIndexInput, &latency); + android::Vector iBuffer, oBuffer; // set state to idle @@ -1086,12 +1286,6 @@ TEST_F(VideoEncHidlTest, EncodeTestBufferMetaModes) { 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; @@ -1125,6 +1319,12 @@ TEST_F(VideoEncHidlTest, EncodeTestBufferMetaModes) { kPortIndexInput, &portDef); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + // 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); + // set port mode PortMode portMode[2]; portMode[0] = PortMode::DYNAMIC_ANW_BUFFER; @@ -1138,6 +1338,10 @@ TEST_F(VideoEncHidlTest, EncodeTestBufferMetaModes) { strcpy(mURL, gEnv->getRes().c_str()); GetURLForComponent(mURL); + uint32_t latency = 0; + setLatency(omxNode, kPortIndexInput, latency); + getLatency(omxNode, kPortIndexInput, &latency); + std::ifstream eleStream; status = source->setSuspend(false, 0); @@ -1232,12 +1436,6 @@ TEST_F(VideoEncHidlTest, EncodeTestEOS) { 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; @@ -1271,6 +1469,12 @@ TEST_F(VideoEncHidlTest, EncodeTestEOS) { kPortIndexInput, &portDef); ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK); + // 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); + // set port mode PortMode portMode[2]; portMode[0] = PortMode::DYNAMIC_ANW_BUFFER;