Merge "Omx vts test." into oc-dev

This commit is contained in:
Zhuoyao Zhang 2017-05-26 00:15:41 +00:00 committed by Android (Google) Code Review
commit 9a9c8da39b
16 changed files with 1722 additions and 1067 deletions

View file

@ -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",

View file

@ -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",

View file

@ -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<void*>(buffer->mMemory->getPointer()),
sizeof(char),
msg.data.extendedBufferData.rangeLength, ofp);
fclose(ofp);
count++;
}
#endif
}
}
}
void testEOS(android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding,
@ -580,8 +559,9 @@ void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> observer,
if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
dispatchOutputBuffer(omxNode, oBuffer, index);
}
timeOut--;
}
}
@ -642,6 +623,8 @@ void decodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> 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;

View file

@ -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<IOmx>(
gEnv->getInstance());
ASSERT_NE(omx, nullptr);
observer = new CodecObserver([this](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<void*>(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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<IOmxNode> omxNode, sp<CodecObserver> 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<char*>(
static_cast<void*>((*iBuffer)[i].mMemory->getPointer()));
@ -314,11 +383,14 @@ void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
static_cast<int>((*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<IOmxNode> omxNode, sp<CodecObserver> observer,
static_cast<int>((*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) {

View file

@ -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 <media_hidl_test_common.h>
#include <memory>
// allocate buffers needed on a component port
void allocatePortBuffers(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
OMX_U32 portIndex) {
android::hardware::media::omx::V1_0::Status status;
OMX_PARAM_PORTDEFINITIONTYPE portDef;
buffArray->clear();
sp<IAllocator> allocator = IAllocator::getService("ashmem");
EXPECT_NE(allocator.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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput,
OMX_U32 kPortIndexOutput) {
android::hardware::media::omx::V1_0::Status status;
Message msg;
// 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput,
OMX_U32 kPortIndexOutput) {
android::hardware::media::omx::V1_0::Status status;
Message msg;
// 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<IOmxNode> omxNode,
sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<BufferInfo>* 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<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex) {
android::hardware::media::omx::V1_0::Status status;
CodecBuffer t;
t.sharedMemory = android::hardware::hidl_memory();
t.nativeHandle = android::hardware::hidl_handle();
t.type = CodecBuffer::Type::PRESET;
t.attr.preset.rangeOffset = 0;
t.attr.preset.rangeLength = 0;
native_handle_t* fenceNh = native_handle_create(0, 0);
ASSERT_NE(fenceNh, nullptr);
status = omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh);
native_handle_close(fenceNh);
native_handle_delete(fenceNh);
ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
buffArray->editItemAt(bufferIndex).owner = component;
}
// dispatch buffer to input port
void dispatchInputBuffer(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex, int bytesCount, uint32_t flags,
uint64_t timestamp) {
android::hardware::media::omx::V1_0::Status status;
CodecBuffer t;
t.sharedMemory = android::hardware::hidl_memory();
t.nativeHandle = android::hardware::hidl_handle();
t.type = CodecBuffer::Type::PRESET;
t.attr.preset.rangeOffset = 0;
t.attr.preset.rangeLength = bytesCount;
native_handle_t* fenceNh = native_handle_create(0, 0);
ASSERT_NE(fenceNh, nullptr);
status = omxNode->emptyBuffer((*buffArray)[bufferIndex].id, t, flags,
timestamp, fenceNh);
native_handle_close(fenceNh);
native_handle_delete(fenceNh);
ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
buffArray->editItemAt(bufferIndex).owner = component;
}
// Flush input and output ports
void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding) {
OMX_U32 index = 0;

View file

@ -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 <media_hidl_test_common.h>
/*
* Random Index used for monkey testing while get/set parameters
*/
@ -26,42 +27,6 @@
/*
* Common audio utils
*/
void allocatePortBuffers(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
OMX_U32 portIndex);
void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput);
void changeStateIdletoLoaded(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput);
void changeStateIdletoExecute(sp<IOmxNode> omxNode, sp<CodecObserver> observer);
void changeStateExecutetoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer);
size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray);
void dispatchOutputBuffer(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex);
void dispatchInputBuffer(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex, int bytesCount, uint32_t flags,
uint64_t timestamp);
void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput,
OMX_U32 kPortIndexOutput, int64_t timeoutUs = DEFAULT_TIMEOUT);
Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding);

View file

@ -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/",
],
}

View file

@ -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 <android-base/logging.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
#include <android/hardware/media/omx/1.0/types.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMapper.h>
#include <android/hidl/memory/1.0/IMemory.h>
using ::android::hardware::media::omx::V1_0::IOmx;
using ::android::hardware::media::omx::V1_0::IOmxObserver;
using ::android::hardware::media::omx::V1_0::IOmxNode;
using ::android::hardware::media::omx::V1_0::Message;
using ::android::hardware::media::omx::V1_0::CodecBuffer;
using ::android::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 <VtsHalHidlTargetTestBase.h>
#include <hidlmemory/mapping.h>
#include <media/hardware/HardwareAPI.h>
#include <media_hidl_test_common.h>
#include <memory>
// allocate buffers needed on a component port
void allocatePortBuffers(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* 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<IAllocator> 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<android::VideoNativeMetadata*>(
static_cast<void*>(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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput,
OMX_U32 kPortIndexOutput) {
android::hardware::media::omx::V1_0::Status status;
Message msg;
// 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<IOmxNode> omxNode,
sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<BufferInfo>* buffArray) {
android::Vector<BufferInfo>::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<IOmxNode> omxNode,
android::Vector<BufferInfo>* 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<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex, int bytesCount, uint32_t flags,
uint64_t timestamp) {
android::hardware::media::omx::V1_0::Status status;
CodecBuffer t;
t.sharedMemory = android::hardware::hidl_memory();
t.nativeHandle = android::hardware::hidl_handle();
t.type = CodecBuffer::Type::PRESET;
t.attr.preset.rangeOffset = 0;
t.attr.preset.rangeLength = bytesCount;
native_handle_t* fenceNh = native_handle_create(0, 0);
ASSERT_NE(fenceNh, nullptr);
status = omxNode->emptyBuffer((*buffArray)[bufferIndex].id, t, flags,
timestamp, fenceNh);
native_handle_close(fenceNh);
native_handle_delete(fenceNh);
ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
buffArray->editItemAt(bufferIndex).owner = component;
}
// Flush input and output ports
void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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;
}

View file

@ -33,9 +33,19 @@
#include <media/openmax/OMX_AudioExt.h>
#include <media/openmax/OMX_VideoExt.h>
#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<uint32_t>(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<IMemory> 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<void(Message)> fn) : callBack(fn) {}
CodecObserver(std::function<void(Message, const BufferInfo*)> fn)
: callBack(fn) {}
Return<void> onMessages(const hidl_vec<Message>& messages) override {
android::Mutex::Autolock autoLock(msgLock);
for (hidl_vec<Message>::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<Message> msgQueue;
android::Mutex msgLock;
android::Condition msgCondition;
std::function<void(Message)> callBack;
std::function<void(Message, const BufferInfo*)> callBack;
};
/*
@ -245,4 +253,51 @@ Return<android::hardware::media::omx::V1_0::Status> setPortConfig(
inHidlBytes(params, sizeof(*params)));
}
/*
* common functions declarations
*/
void allocatePortBuffers(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
OMX_U32 portIndex,
PortMode portMode = PortMode::PRESET_BYTE_BUFFER);
void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
PortMode* portMode = nullptr);
void changeStateIdletoLoaded(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput);
void changeStateIdletoExecute(sp<IOmxNode> omxNode, sp<CodecObserver> observer);
void changeStateExecutetoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer);
size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray);
void dispatchOutputBuffer(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex,
PortMode portMode = PortMode::PRESET_BYTE_BUFFER);
void dispatchInputBuffer(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex, int bytesCount, uint32_t flags,
uint64_t timestamp);
void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput,
OMX_U32 kPortIndexOutput, int64_t timeoutUs = DEFAULT_TIMEOUT);
void testEOS(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer, bool signalEOS,
bool& eosFlag, PortMode* portMode = nullptr);
#endif // MEDIA_HIDL_TEST_COMMON_H

View file

@ -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",

View file

@ -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<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
OMX_U32 portIndex) {
android::hardware::media::omx::V1_0::Status status;
OMX_PARAM_PORTDEFINITIONTYPE portDef;
buffArray->clear();
sp<IAllocator> allocator = IAllocator::getService("ashmem");
EXPECT_NE(allocator.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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput,
OMX_U32 kPortIndexOutput) {
android::hardware::media::omx::V1_0::Status status;
Message msg;
// 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput,
OMX_U32 kPortIndexOutput) {
android::hardware::media::omx::V1_0::Status status;
Message msg;
// 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<IOmxNode> omxNode,
sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex) {
android::hardware::media::omx::V1_0::Status status;
CodecBuffer t;
t.sharedMemory = android::hardware::hidl_memory();
t.nativeHandle = android::hardware::hidl_handle();
t.type = CodecBuffer::Type::PRESET;
t.attr.preset.rangeOffset = 0;
t.attr.preset.rangeLength = 0;
native_handle_t* fenceNh = native_handle_create(0, 0);
ASSERT_NE(fenceNh, nullptr);
status = omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh);
native_handle_close(fenceNh);
native_handle_delete(fenceNh);
ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
buffArray->editItemAt(bufferIndex).owner = component;
}
// dispatch buffer to input port
void dispatchInputBuffer(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex, int bytesCount, uint32_t flags,
uint64_t timestamp) {
android::hardware::media::omx::V1_0::Status status;
CodecBuffer t;
t.sharedMemory = android::hardware::hidl_memory();
t.nativeHandle = android::hardware::hidl_handle();
t.type = CodecBuffer::Type::PRESET;
t.attr.preset.rangeOffset = 0;
t.attr.preset.rangeLength = bytesCount;
native_handle_t* fenceNh = native_handle_create(0, 0);
ASSERT_NE(fenceNh, nullptr);
status = omxNode->emptyBuffer((*buffArray)[bufferIndex].id, t, flags,
timestamp, fenceNh);
native_handle_close(fenceNh);
native_handle_delete(fenceNh);
ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
buffArray->editItemAt(bufferIndex).owner = component;
}
// Flush input and output ports
void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput,
OMX_U32 kPortIndexOutput) {
android::hardware::media::omx::V1_0::Status status;
Message msg;
// Flush 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<android::hardware::media::omx::V1_0::Status> setVideoPortFormat(
sp<IOmxNode> omxNode, OMX_U32 portIndex,

View file

@ -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",

View file

@ -17,6 +17,9 @@
#define LOG_TAG "media_omx_hidl_video_dec_test"
#include <android-base/logging.h>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/2.0/types.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
@ -25,11 +28,14 @@
#include <android/hidl/memory/1.0/IMapper.h>
#include <android/hidl/memory/1.0/IMemory.h>
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<void*>(buffer->mMemory->getPointer()),
sizeof(char),
msg.data.extendedBufferData.rangeLength, ofp);
fclose(ofp);
count++;
}
#endif
}
}
}
void testEOS(android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<uint64_t> 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<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<IOmxNode> omxNode, OMX_U32 portIndex,
OMX_VIDEO_CODINGTYPE eCompressionFormat,
@ -399,12 +395,85 @@ void GetURLForComponent(VideoDecHidlTest::standardComp comp, char* mURL,
}
}
void allocateGraphicBuffers(sp<IOmxNode> omxNode, OMX_U32 portIndex,
android::Vector<BufferInfo>* buffArray,
uint32_t nFrameWidth, uint32_t nFrameHeight,
int32_t* nStride, uint32_t count) {
android::hardware::media::omx::V1_0::Status status;
sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator =
android::hardware::graphics::allocator::V2_0::IAllocator::getService();
ASSERT_NE(nullptr, allocator.get());
sp<android::hardware::graphics::mapper::V2_0::IMapper> 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<uint64_t>(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<uint32_t> 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<uint32_t> _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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<IOmxNode> omxNode, sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> observer,
void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<IOmxNode> omxNode, sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
std::ifstream& eleStream, android::Vector<FrameData>* 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<IOmxNode> omxNode, sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> 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<BufferInfo> 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<BufferInfo> 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<BufferInfo> 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<BufferInfo> 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<BufferInfo> 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,

View file

@ -21,6 +21,11 @@
#include <android-base/logging.h>
#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/2.0/types.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
@ -29,11 +34,17 @@
#include <android/hidl/memory/1.0/IMapper.h>
#include <android/hidl/memory/1.0/IMemory.h>
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 <media/hardware/HardwareAPI.h>
#include <media_hidl_test_common.h>
#include <media_video_hidl_test_common.h>
#include <system/window.h>
#include <fstream>
// A class for test environment setup
@ -140,7 +152,10 @@ class VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
omx = ::testing::VtsHalHidlTargetTestBase::getService<IOmx>(
gEnv->getInstance());
ASSERT_NE(omx, nullptr);
observer = new CodecObserver([this](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<uint64_t>::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<void*>(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<uint64_t> timestampUslist;
bool timestampDevTest;
bool isSecure;
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferSource> 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<void> onBufferReleased() override {
android::Mutex::Autolock autoLock(bufferLock);
freeBuffers += 1;
return Void();
}
virtual ::android::hardware::Return<bool> 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<IOmxNode> 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
bool inputDataIsMeta = false,
sp<CodecProducerListener> 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<android::hardware::graphics::mapper::V2_0::IMapper> 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<char*>(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<char*>(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<char*>(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<char*>(ycbcrLayout.y) +
(ycbcrLayout.yStride * rect.height);
ycbcrLayout.cr = static_cast<char*>(ycbcrLayout.cb) +
((ycbcrLayout.yStride * rect.height) >> 2);
char* ipBuffer = static_cast<char*>(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<char*>(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<char*>(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<android::hardware::graphics::mapper::V2_0::IMapper> 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<IOmxNode> omxNode,
sp<IGraphicBufferProducer> producer,
sp<CodecProducerListener> listener,
android::Vector<BufferInfo>* 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<android::hardware::media::V1_0::Rect>{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<IOmxNode> omxNode, sp<CodecObserver> observer,
OMX_U32 portIndexOutput,
OMX_U32 portIndexInput, OMX_U32 portIndexOutput,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer, uint32_t nFrames,
uint32_t xFramerate, int bytesCount,
std::ifstream& eleStream) {
std::ifstream& eleStream,
::android::List<uint64_t>* timestampUslist = nullptr,
bool signalEOS = true, bool inputDataIsMeta = false,
sp<IGraphicBufferProducer> producer = nullptr,
sp<CodecProducerListener> listener = nullptr) {
android::hardware::media::omx::V1_0::Status status;
Message msg;
uint32_t ipCount = 0;
@ -398,20 +814,39 @@ void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> 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<char*>(
static_cast<void*>((*iBuffer)[i].mMemory->getPointer()));
ASSERT_LE(bytesCount,
static_cast<int>((*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<char*>(
static_cast<void*>((*iBuffer)[i].mMemory->getPointer()));
ASSERT_LE(bytesCount,
static_cast<int>((*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<IOmxNode> omxNode, sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> observer,
// Dispatch input buffer
size_t index = 0;
if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) {
char* ipBuffer = static_cast<char*>(
static_cast<void*>((*iBuffer)[index].mMemory->getPointer()));
ASSERT_LE(bytesCount,
static_cast<int>((*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<char*>(static_cast<void*>(
(*iBuffer)[index].mMemory->getPointer()));
ASSERT_LE(
bytesCount,
static_cast<int>((*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<BufferInfo> 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,
&timestampUslist);
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, &params);
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<IGraphicBufferProducer> const& _nl,
sp<IGraphicBufferSource> 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<CodecProducerListener> 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<BufferInfo> 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, &params);
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<IGraphicBufferProducer> const& _nl,
sp<IGraphicBufferSource> 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<CodecProducerListener> 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<BufferInfo> 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) {

View file

@ -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 <android-base/logging.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
@ -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 <VtsHalHidlTargetTestBase.h>
#include <hidlmemory/mapping.h>
#include <media/hardware/HardwareAPI.h>
#include <media_hidl_test_common.h>
#include <media_video_hidl_test_common.h>
#include <memory>
// allocate buffers needed on a component port
void allocatePortBuffers(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
OMX_U32 portIndex) {
android::hardware::media::omx::V1_0::Status status;
OMX_PARAM_PORTDEFINITIONTYPE portDef;
buffArray->clear();
sp<IAllocator> allocator = IAllocator::getService("ashmem");
EXPECT_NE(allocator.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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput,
OMX_U32 kPortIndexOutput) {
android::hardware::media::omx::V1_0::Status status;
Message msg;
// 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput,
OMX_U32 kPortIndexOutput) {
android::hardware::media::omx::V1_0::Status status;
Message msg;
// 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<IOmxNode> omxNode,
sp<CodecObserver> 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<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<BufferInfo>* 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<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex) {
android::hardware::media::omx::V1_0::Status status;
CodecBuffer t;
t.sharedMemory = android::hardware::hidl_memory();
t.nativeHandle = android::hardware::hidl_handle();
t.type = CodecBuffer::Type::PRESET;
t.attr.preset.rangeOffset = 0;
t.attr.preset.rangeLength = 0;
native_handle_t* fenceNh = native_handle_create(0, 0);
ASSERT_NE(fenceNh, nullptr);
status = omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh);
native_handle_close(fenceNh);
native_handle_delete(fenceNh);
ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
buffArray->editItemAt(bufferIndex).owner = component;
}
// dispatch buffer to input port
void dispatchInputBuffer(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex, int bytesCount, uint32_t flags,
uint64_t timestamp) {
android::hardware::media::omx::V1_0::Status status;
CodecBuffer t;
t.sharedMemory = android::hardware::hidl_memory();
t.nativeHandle = android::hardware::hidl_handle();
t.type = CodecBuffer::Type::PRESET;
t.attr.preset.rangeOffset = 0;
t.attr.preset.rangeLength = bytesCount;
native_handle_t* fenceNh = native_handle_create(0, 0);
ASSERT_NE(fenceNh, nullptr);
status = omxNode->emptyBuffer((*buffArray)[bufferIndex].id, t, flags,
timestamp, fenceNh);
native_handle_close(fenceNh);
native_handle_delete(fenceNh);
ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
buffArray->editItemAt(bufferIndex).owner = component;
}
// Flush input and output ports
void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* 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<android::hardware::media::omx::V1_0::Status> setVideoPortFormat(
sp<IOmxNode> omxNode, OMX_U32 portIndex,
OMX_VIDEO_CODINGTYPE eCompressionFormat, OMX_COLOR_FORMATTYPE eColorFormat,

View file

@ -25,41 +25,6 @@
/*
* Common video utils
*/
void allocatePortBuffers(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
OMX_U32 portIndex);
void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput);
void changeStateIdletoLoaded(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer,
OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput);
void changeStateIdletoExecute(sp<IOmxNode> omxNode, sp<CodecObserver> observer);
void changeStateExecutetoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer);
size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray);
void dispatchOutputBuffer(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex);
void dispatchInputBuffer(sp<IOmxNode> omxNode,
android::Vector<BufferInfo>* buffArray,
size_t bufferIndex, int bytesCount, uint32_t flags,
uint64_t timestamp);
void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
android::Vector<BufferInfo>* iBuffer,
android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput,
OMX_U32 kPortIndexOutput, int64_t timeoutUs = DEFAULT_TIMEOUT);
Return<android::hardware::media::omx::V1_0::Status> setVideoPortFormat(
sp<IOmxNode> omxNode, OMX_U32 portIndex,