Omx vts test.

Bug:32023356
Test: make vts.

Merged-In: I83b454b999203fb94bc4cc50c91bd99f788131b3

secure buffer allocation for secure components

As of now, we see a crash in encoder test application on secure components
This is due to nullptr access. setting property media.mediadrmservice.enable
to 1 causes a different crash sigabrt(). In decoder securebufferallocation
call passes but we havent done anything with it. This commit needs more work.

Change-Id: I19127e39ad7daf66ac5277406e3857ec45c99e0a

add debug code

This can come in handy to view the decoded/encoded content or
for computation of psnr

Change-Id: I80e60349c76c02e5098df667223a0227f59b8324

video encoder test with anw input buffer

In this commit, anw buffers are provided as input for encoding
as opposed to byte buffers. In process IOmxNode, IGraphicBufferSource api
calls are tested

Change-Id: I7ec4af0746fe59221de42e56b344852d8fadc4f2

add support for additional color formats

Change-Id: Ia88ef9c95882958a68fee5cc68e146c3502a1b48

add eos and timestamp deviation test to video encoder

Change-Id: I9ebeaa53a986ec3f8a2ef55306877aec808d2add

add metamode support for video decoders

Change-Id: I7d6d6991cdc0ed36241d0e99c7a23675664acb10

add a timeout while processing input buffers

do not wait on input buffers processing to complete for an
indefinite amount of time. wait for a predefined duration and
leave

Change-Id: Icceaf0737a52e62f47bc052367e7ddbdc1868a46

move duplicate code to a library

move routines common across audio, video, component folders to a static
library

Change-Id: I55bf21e47571490e989b52b82c48c6e9a4b23745

add end of stream test for audio encoder

add eos test for audio encoder and some more code cleanup

Change-Id: I9d670ed53f6bba5802f919ec915e67bb0fa83518

Ensure all the buffers allocated are cycled

use all buffers provided by the component (even if it is greater than the
number of buffers needed by the bitstream)

Change-Id: I83b454b999203fb94bc4cc50c91bd99f788131b3

move duplicate code to a library - II

Change-Id: I375603feb9da303adc6a2d75ef59e43a11c3bd6d

Change-Id: I83b454b999203fb94bc4cc50c91bd99f788131b3
(cherry picked from commit 1da607c513)
This commit is contained in:
Ram Mohan M
2017-05-11 18:52:47 +05:30
committed by Zhuoyao Zhang
parent 5b14a8823e
commit ccc194cffd
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,