Merge "Convert VtsHalMediaC2V1_0HostTest to individual gtest" into rvc-dev

gugelfrei
Dan Shi 4 years ago committed by Android (Google) Code Review
commit 5dfd0a2360

@ -5,5 +5,4 @@ taklee@google.com
wonsik@google.com wonsik@google.com
# VTS team # VTS team
yim@google.com dshi@google.com
zhuoyao@google.com

@ -0,0 +1,101 @@
//
// Copyright (C) 2020 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.
//
filegroup {
name: "media_c2_v1_audio_decode_res",
path: "res",
srcs: [
"res/bbb_aac_stereo_128kbps_48000hz.aac",
"res/bbb_aac_stereo_128kbps_48000hz.info",
"res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info",
"res/bbb_amrwb_1ch_14kbps_16000hz.amrwb",
"res/bbb_amrwb_1ch_14kbps_16000hz.info",
"res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info",
"res/bbb_flac_stereo_680kbps_48000hz.flac",
"res/bbb_flac_stereo_680kbps_48000hz.info",
"res/bbb_g711alaw_1ch_8khz.info",
"res/bbb_g711alaw_1ch_8khz.raw",
"res/bbb_g711mulaw_1ch_8khz.info",
"res/bbb_g711mulaw_1ch_8khz.raw",
"res/bbb_gsm_1ch_8khz_13kbps.info",
"res/bbb_gsm_1ch_8khz_13kbps.raw",
"res/bbb_mp3_stereo_192kbps_48000hz.info",
"res/bbb_mp3_stereo_192kbps_48000hz.mp3",
"res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info",
"res/bbb_opus_stereo_128kbps_48000hz.info",
"res/bbb_opus_stereo_128kbps_48000hz.opus",
"res/bbb_raw_1ch_8khz_s32le.info",
"res/bbb_raw_1ch_8khz_s32le.raw",
"res/bbb_vorbis_stereo_128kbps_48000hz.info",
"res/bbb_vorbis_stereo_128kbps_48000hz.vorbis",
"res/sine_amrnb_1ch_12kbps_8000hz.amrnb",
"res/sine_amrnb_1ch_12kbps_8000hz.info",
"res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info",
],
}
filegroup {
name: "media_c2_v1_audio_encode_res",
path: "res",
srcs: [
"res/bbb_raw_2ch_48khz_s16le.raw",
"res/bbb_raw_1ch_8khz_s16le.raw",
"res/bbb_raw_1ch_16khz_s16le.raw",
],
}
filegroup {
name: "media_c2_v1_video_decode_res",
path: "res",
srcs: [
"res/bbb_avc_176x144_300kbps_60fps.h264",
"res/bbb_avc_640x360_768kbps_30fps.h264",
"res/bbb_avc_176x144_300kbps_60fps.info",
"res/bbb_avc_640x360_768kbps_30fps.info",
"res/bbb_hevc_176x144_176kbps_60fps.hevc",
"res/bbb_hevc_640x360_1600kbps_30fps.hevc",
"res/bbb_hevc_176x144_176kbps_60fps.info",
"res/bbb_hevc_640x360_1600kbps_30fps.info",
"res/bbb_mpeg2_176x144_105kbps_25fps.m2v",
"res/bbb_mpeg2_352x288_1mbps_60fps.m2v",
"res/bbb_mpeg2_176x144_105kbps_25fps.info",
"res/bbb_mpeg2_352x288_1mbps_60fps.info",
"res/bbb_h263_352x288_300kbps_12fps.h263",
"res/bbb_h263_352x288_300kbps_12fps.info",
"res/bbb_mpeg4_352x288_512kbps_30fps.m4v",
"res/bbb_mpeg4_352x288_512kbps_30fps.info",
"res/bbb_vp8_176x144_240kbps_60fps.vp8",
"res/bbb_vp8_640x360_2mbps_30fps.vp8",
"res/bbb_vp8_176x144_240kbps_60fps.info",
"res/bbb_vp8_640x360_2mbps_30fps.info",
"res/bbb_vp9_176x144_285kbps_60fps.vp9",
"res/bbb_vp9_640x360_1600kbps_30fps.vp9",
"res/bbb_vp9_176x144_285kbps_60fps.info",
"res/bbb_vp9_640x360_1600kbps_30fps.info",
"res/bbb_av1_640_360.av1",
"res/bbb_av1_176_144.av1",
"res/bbb_av1_640_360.info",
"res/bbb_av1_176_144.info",
],
}
filegroup {
name: "media_c2_v1_video_encode_res",
path: "res",
srcs: [
"res/bbb_352x288_420p_30fps_32frames.yuv",
],
}

@ -16,18 +16,22 @@
cc_test { cc_test {
name: "VtsHalMediaC2V1_0TargetAudioDecTest", name: "VtsHalMediaC2V1_0TargetAudioDecTest",
stem: "vts_media_c2_v1_0_audio_dec_test",
defaults: ["VtsHalMediaC2V1_0Defaults"], defaults: ["VtsHalMediaC2V1_0Defaults"],
srcs: [ srcs: [
"VtsHalMediaC2V1_0TargetAudioDecTest.cpp", "VtsHalMediaC2V1_0TargetAudioDecTest.cpp",
//"media_audio_hidl_test_common.cpp"
], ],
data: [":media_c2_v1_audio_decode_res"],
test_config: "VtsHalMediaC2V1_0TargetAudioDecTest.xml",
} }
cc_test { cc_test {
name: "VtsHalMediaC2V1_0TargetAudioEncTest", name: "VtsHalMediaC2V1_0TargetAudioEncTest",
stem: "vts_media_c2_v1_0_audio_enc_test",
defaults: ["VtsHalMediaC2V1_0Defaults"], defaults: ["VtsHalMediaC2V1_0Defaults"],
srcs: [ srcs: [
"VtsHalMediaC2V1_0TargetAudioEncTest.cpp", "VtsHalMediaC2V1_0TargetAudioEncTest.cpp",
//"media_audio_hidl_test_common.cpp"
], ],
data: [":media_c2_v1_audio_encode_res"],
test_config: "VtsHalMediaC2V1_0TargetAudioEncTest.xml",
} }

@ -19,21 +19,20 @@
#include <android-base/logging.h> #include <android-base/logging.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <algorithm> #include <hidl/GtestPrinter.h>
#include <stdio.h> #include <stdio.h>
#include <algorithm>
#include <fstream> #include <fstream>
#include <codec2/hidl/client.h>
#include <C2AllocatorIon.h> #include <C2AllocatorIon.h>
#include <C2Config.h>
#include <C2Debug.h>
#include <C2Buffer.h> #include <C2Buffer.h>
#include <C2BufferPriv.h> #include <C2BufferPriv.h>
#include <C2Config.h>
#include <C2Debug.h>
#include <codec2/hidl/client.h>
using android::C2AllocatorIon; using android::C2AllocatorIon;
#include <VtsHalHidlTargetTestBase.h>
#include "media_c2_audio_hidl_test_common.h"
#include "media_c2_hidl_test_common.h" #include "media_c2_hidl_test_common.h"
struct FrameInfo { struct FrameInfo {
@ -42,57 +41,44 @@ struct FrameInfo {
int64_t timestamp; int64_t timestamp;
}; };
static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
kDecodeTestParameters;
// Resource directory
static std::string sResourceDir = "";
class LinearBuffer : public C2Buffer { class LinearBuffer : public C2Buffer {
public: public:
explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block) explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
: C2Buffer( : C2Buffer({block->share(block->offset(), block->size(), ::C2Fence())}) {}
{block->share(block->offset(), block->size(), ::C2Fence())}) {}
}; };
static ComponentTestEnvironment* gEnv = nullptr;
namespace { namespace {
class Codec2AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { class Codec2AudioDecHidlTestBase : public ::testing::Test {
private: public:
typedef ::testing::VtsHalHidlTargetTestBase Super;
public:
::std::string getTestCaseInfo() const override {
return ::std::string() +
"Component: " + gEnv->getComponent().c_str() + " | " +
"Instance: " + gEnv->getInstance().c_str() + " | " +
"Res: " + gEnv->getRes().c_str();
}
// google.codec2 Audio test setup // google.codec2 Audio test setup
virtual void SetUp() override { virtual void SetUp() override {
Super::SetUp(); getParams();
mDisableTest = false; mDisableTest = false;
ALOGV("Codec2AudioDecHidlTest SetUp"); ALOGV("Codec2AudioDecHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService( mClient = android::Codec2Client::CreateFromService(
gEnv->getInstance().c_str(), mInstanceName.c_str(),
!bool(android::Codec2Client::CreateFromService("default", true))); !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr); ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener( mListener.reset(new CodecListener([this](std::list<std::unique_ptr<C2Work>>& workItems) {
[this](std::list<std::unique_ptr<C2Work>>& workItems) { handleWorkDone(workItems);
handleWorkDone(workItems); }));
}));
ASSERT_NE(mListener, nullptr); ASSERT_NE(mListener, nullptr);
for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) { for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
mWorkQueue.emplace_back(new C2Work); mWorkQueue.emplace_back(new C2Work);
} }
mClient->createComponent(gEnv->getComponent().c_str(), mListener, mClient->createComponent(mComponentName, mListener, &mComponent);
&mComponent);
ASSERT_NE(mComponent, nullptr); ASSERT_NE(mComponent, nullptr);
std::shared_ptr<C2AllocatorStore> store = std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
android::GetCodec2PlatformAllocatorStore(); CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
&mLinearAllocator),
C2_OK);
mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator,
mBlockPoolId++);
ASSERT_NE(mLinearPool, nullptr); ASSERT_NE(mLinearPool, nullptr);
mCompName = unknown_comp; mCompName = unknown_comp;
@ -101,27 +87,17 @@ class Codec2AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
standardComp CompName; standardComp CompName;
}; };
const StringToName kStringToName[] = { const StringToName kStringToName[] = {
{"xaac", xaac}, {"xaac", xaac}, {"mp3", mp3}, {"amrnb", amrnb},
{"mp3", mp3}, {"amrwb", amrwb}, {"aac", aac}, {"vorbis", vorbis},
{"amrnb", amrnb}, {"opus", opus}, {"pcm", pcm}, {"g711.alaw", g711alaw},
{"amrwb", amrwb}, {"g711.mlaw", g711mlaw}, {"gsm", gsm}, {"raw", raw},
{"aac", aac}, {"flac", flac},
{"vorbis", vorbis},
{"opus", opus},
{"pcm", pcm},
{"g711.alaw", g711alaw},
{"g711.mlaw", g711mlaw},
{"gsm", gsm},
{"raw", raw},
{"flac", flac},
}; };
const size_t kNumStringToName = const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]);
sizeof(kStringToName) / sizeof(kStringToName[0]);
// Find the component type // Find the component type
std::string comp = std::string(gEnv->getComponent());
for (size_t i = 0; i < kNumStringToName; ++i) { for (size_t i = 0; i < kNumStringToName; ++i) {
if (strcasestr(comp.c_str(), kStringToName[i].Name)) { if (strcasestr(mComponentName.c_str(), kStringToName[i].Name)) {
mCompName = kStringToName[i].CompName; mCompName = kStringToName[i].CompName;
break; break;
} }
@ -140,9 +116,11 @@ class Codec2AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
mComponent->release(); mComponent->release();
mComponent = nullptr; mComponent = nullptr;
} }
Super::TearDown();
} }
// Get the test parameters from GetParam call.
virtual void getParams() {}
struct outputMetaData { struct outputMetaData {
uint64_t timestampUs; uint64_t timestampUs;
uint32_t rangeLength; uint32_t rangeLength;
@ -155,25 +133,27 @@ class Codec2AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
// previous timestamp // previous timestamp
bool codecConfig = ((work->worklets.front()->output.flags & bool codecConfig = ((work->worklets.front()->output.flags &
C2FrameData::FLAG_CODEC_CONFIG) != 0); C2FrameData::FLAG_CODEC_CONFIG) != 0);
if (!codecConfig && if (!codecConfig && !work->worklets.front()->output.buffers.empty()) {
!work->worklets.front()->output.buffers.empty()) {
EXPECT_GE(work->worklets.front()->output.ordinal.timestamp.peeku(), EXPECT_GE(work->worklets.front()->output.ordinal.timestamp.peeku(),
mTimestampUs); mTimestampUs);
mTimestampUs = mTimestampUs = work->worklets.front()->output.ordinal.timestamp.peeku();
work->worklets.front()->output.ordinal.timestamp.peeku(); uint32_t rangeLength = work->worklets.front()
uint32_t rangeLength = ->output.buffers[0]
work->worklets.front()->output.buffers[0]->data() ->data()
.linearBlocks().front().map().get().capacity(); .linearBlocks()
//List of timestamp values and output size to calculate timestamp .front()
.map()
.get()
.capacity();
// List of timestamp values and output size to calculate timestamp
if (mTimestampDevTest) { if (mTimestampDevTest) {
outputMetaData meta = {mTimestampUs, rangeLength}; outputMetaData meta = {mTimestampUs, rangeLength};
oBufferMetaData.push_back(meta); oBufferMetaData.push_back(meta);
} }
} }
bool mCsd = false; bool mCsd = false;
workDone(mComponent, work, mFlushedIndices, mQueueLock, workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
mQueueCondition, mWorkQueue, mEos, mCsd, mEos, mCsd, mFramesReceived);
mFramesReceived);
(void)mCsd; (void)mCsd;
} }
} }
@ -196,6 +176,8 @@ class Codec2AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
unknown_comp, unknown_comp,
}; };
std::string mInstanceName;
std::string mComponentName;
bool mEos; bool mEos;
bool mDisableTest; bool mDisableTest;
bool mTimestampDevTest; bool mTimestampDevTest;
@ -218,15 +200,23 @@ class Codec2AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
std::shared_ptr<android::Codec2Client::Listener> mListener; std::shared_ptr<android::Codec2Client::Listener> mListener;
std::shared_ptr<android::Codec2Client::Component> mComponent; std::shared_ptr<android::Codec2Client::Component> mComponent;
protected: protected:
static void description(const std::string& description) { static void description(const std::string& description) {
RecordProperty("description", description); RecordProperty("description", description);
} }
}; };
void validateComponent( class Codec2AudioDecHidlTest
const std::shared_ptr<android::Codec2Client::Component>& component, : public Codec2AudioDecHidlTestBase,
Codec2AudioDecHidlTest::standardComp compName, bool& disableTest) { public ::testing::WithParamInterface<std::tuple<std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
}
};
void validateComponent(const std::shared_ptr<android::Codec2Client::Component>& component,
Codec2AudioDecHidlTest::standardComp compName, bool& disableTest) {
// Validate its a C2 Component // Validate its a C2 Component
if (component->getName().find("c2") == std::string::npos) { if (component->getName().find("c2") == std::string::npos) {
ALOGE("Not a c2 component"); ALOGE("Not a c2 component");
@ -241,14 +231,12 @@ void validateComponent(
return; return;
} }
std::vector<std::unique_ptr<C2Param>> queried; std::vector<std::unique_ptr<C2Param>> queried;
c2_status_t c2err = c2_status_t c2err = component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK, &queried);
C2_DONT_BLOCK, &queried);
if (c2err != C2_OK && queried.size() == 0) { if (c2err != C2_OK && queried.size() == 0) {
ALOGE("Query media type failed => %d", c2err); ALOGE("Query media type failed => %d", c2err);
} else { } else {
std::string inputDomain = std::string inputDomain = ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
if (inputDomain.find("audio/") == std::string::npos) { if (inputDomain.find("audio/") == std::string::npos) {
ALOGE("Expected Audio Component"); ALOGE("Expected Audio Component");
disableTest = true; disableTest = true;
@ -266,16 +254,14 @@ void validateComponent(
} }
// Set Default config param. // Set Default config param.
bool setupConfigParam( bool setupConfigParam(const std::shared_ptr<android::Codec2Client::Component>& component,
const std::shared_ptr<android::Codec2Client::Component>& component, int32_t* bitStreamInfo) {
int32_t* bitStreamInfo) {
std::vector<std::unique_ptr<C2SettingResult>> failures; std::vector<std::unique_ptr<C2SettingResult>> failures;
C2StreamSampleRateInfo::output sampleRateInfo(0u, bitStreamInfo[0]); C2StreamSampleRateInfo::output sampleRateInfo(0u, bitStreamInfo[0]);
C2StreamChannelCountInfo::output channelCountInfo(0u, bitStreamInfo[1]); C2StreamChannelCountInfo::output channelCountInfo(0u, bitStreamInfo[1]);
std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo}; std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo};
c2_status_t status = c2_status_t status = component->config(configParam, C2_DONT_BLOCK, &failures);
component->config(configParam, C2_DONT_BLOCK, &failures);
if (status == C2_OK && failures.size() == 0u) return true; if (status == C2_OK && failures.size() == 0u) return true;
return false; return false;
} }
@ -283,17 +269,15 @@ bool setupConfigParam(
// In decoder components, often the input parameters get updated upon // In decoder components, often the input parameters get updated upon
// parsing the header of elementary stream. Client needs to collect this // parsing the header of elementary stream. Client needs to collect this
// information and reconfigure // information and reconfigure
void getInputChannelInfo( void getInputChannelInfo(const std::shared_ptr<android::Codec2Client::Component>& component,
const std::shared_ptr<android::Codec2Client::Component>& component, Codec2AudioDecHidlTest::standardComp compName, int32_t* bitStreamInfo) {
Codec2AudioDecHidlTest::standardComp compName, int32_t* bitStreamInfo) {
// query nSampleRate and nChannels // query nSampleRate and nChannels
std::initializer_list<C2Param::Index> indices{ std::initializer_list<C2Param::Index> indices{
C2StreamSampleRateInfo::output::PARAM_TYPE, C2StreamSampleRateInfo::output::PARAM_TYPE,
C2StreamChannelCountInfo::output::PARAM_TYPE, C2StreamChannelCountInfo::output::PARAM_TYPE,
}; };
std::vector<std::unique_ptr<C2Param>> inParams; std::vector<std::unique_ptr<C2Param>> inParams;
c2_status_t status = c2_status_t status = component->query({}, indices, C2_DONT_BLOCK, &inParams);
component->query({}, indices, C2_DONT_BLOCK, &inParams);
if (status != C2_OK && inParams.size() == 0) { if (status != C2_OK && inParams.size() == 0) {
ALOGE("Query media type failed => %d", status); ALOGE("Query media type failed => %d", status);
ASSERT_TRUE(false); ASSERT_TRUE(false);
@ -328,8 +312,8 @@ void getInputChannelInfo(
#define STREAM_COUNT 2 #define STREAM_COUNT 2
// LookUpTable of clips and metadata for component testing // LookUpTable of clips and metadata for component testing
void GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp, char* mURL, void GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp, char* mURL, char* info,
char* info, size_t streamIndex = 0) { size_t streamIndex = 0) {
struct CompToURL { struct CompToURL {
Codec2AudioDecHidlTest::standardComp comp; Codec2AudioDecHidlTest::standardComp comp;
const char mURL[STREAM_COUNT][512]; const char mURL[STREAM_COUNT][512];
@ -338,52 +322,47 @@ void GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp, char* mURL,
ASSERT_TRUE(streamIndex < STREAM_COUNT); ASSERT_TRUE(streamIndex < STREAM_COUNT);
static const CompToURL kCompToURL[] = { static const CompToURL kCompToURL[] = {
{Codec2AudioDecHidlTest::standardComp::xaac, {Codec2AudioDecHidlTest::standardComp::xaac,
{"bbb_aac_stereo_128kbps_48000hz.aac", {"bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.aac"},
"bbb_aac_stereo_128kbps_48000hz.aac"}, {"bbb_aac_stereo_128kbps_48000hz.info",
{"bbb_aac_stereo_128kbps_48000hz.info", "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
"bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}}, {Codec2AudioDecHidlTest::standardComp::mp3,
{Codec2AudioDecHidlTest::standardComp::mp3, {"bbb_mp3_stereo_192kbps_48000hz.mp3", "bbb_mp3_stereo_192kbps_48000hz.mp3"},
{"bbb_mp3_stereo_192kbps_48000hz.mp3", {"bbb_mp3_stereo_192kbps_48000hz.info",
"bbb_mp3_stereo_192kbps_48000hz.mp3"}, "bbb_mp3_stereo_192kbps_48000hz_multi_frame.info"}},
{"bbb_mp3_stereo_192kbps_48000hz.info", {Codec2AudioDecHidlTest::standardComp::aac,
"bbb_mp3_stereo_192kbps_48000hz_multi_frame.info"}}, {"bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.aac"},
{Codec2AudioDecHidlTest::standardComp::aac, {"bbb_aac_stereo_128kbps_48000hz.info",
{"bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
"bbb_aac_stereo_128kbps_48000hz.aac"}, {Codec2AudioDecHidlTest::standardComp::amrnb,
{"bbb_aac_stereo_128kbps_48000hz.info", {"sine_amrnb_1ch_12kbps_8000hz.amrnb", "sine_amrnb_1ch_12kbps_8000hz.amrnb"},
"bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}}, {"sine_amrnb_1ch_12kbps_8000hz.info",
{Codec2AudioDecHidlTest::standardComp::amrnb, "sine_amrnb_1ch_12kbps_8000hz_multi_frame.info"}},
{"sine_amrnb_1ch_12kbps_8000hz.amrnb", {Codec2AudioDecHidlTest::standardComp::amrwb,
"sine_amrnb_1ch_12kbps_8000hz.amrnb"}, {"bbb_amrwb_1ch_14kbps_16000hz.amrwb", "bbb_amrwb_1ch_14kbps_16000hz.amrwb"},
{"sine_amrnb_1ch_12kbps_8000hz.info", {"bbb_amrwb_1ch_14kbps_16000hz.info",
"sine_amrnb_1ch_12kbps_8000hz_multi_frame.info"}}, "bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info"}},
{Codec2AudioDecHidlTest::standardComp::amrwb, {Codec2AudioDecHidlTest::standardComp::vorbis,
{"bbb_amrwb_1ch_14kbps_16000hz.amrwb", {"bbb_vorbis_stereo_128kbps_48000hz.vorbis", ""},
"bbb_amrwb_1ch_14kbps_16000hz.amrwb"}, {"bbb_vorbis_stereo_128kbps_48000hz.info", ""}},
{"bbb_amrwb_1ch_14kbps_16000hz.info", {Codec2AudioDecHidlTest::standardComp::opus,
"bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info"}}, {"bbb_opus_stereo_128kbps_48000hz.opus", ""},
{Codec2AudioDecHidlTest::standardComp::vorbis, {"bbb_opus_stereo_128kbps_48000hz.info", ""}},
{"bbb_vorbis_stereo_128kbps_48000hz.vorbis", ""}, {Codec2AudioDecHidlTest::standardComp::g711alaw,
{"bbb_vorbis_stereo_128kbps_48000hz.info", ""}}, {"bbb_g711alaw_1ch_8khz.raw", ""},
{Codec2AudioDecHidlTest::standardComp::opus, {"bbb_g711alaw_1ch_8khz.info", ""}},
{"bbb_opus_stereo_128kbps_48000hz.opus", ""}, {Codec2AudioDecHidlTest::standardComp::g711mlaw,
{"bbb_opus_stereo_128kbps_48000hz.info", ""}}, {"bbb_g711mulaw_1ch_8khz.raw", ""},
{Codec2AudioDecHidlTest::standardComp::g711alaw, {"bbb_g711mulaw_1ch_8khz.info", ""}},
{"bbb_g711alaw_1ch_8khz.raw", ""}, {Codec2AudioDecHidlTest::standardComp::gsm,
{"bbb_g711alaw_1ch_8khz.info", ""}}, {"bbb_gsm_1ch_8khz_13kbps.raw", ""},
{Codec2AudioDecHidlTest::standardComp::g711mlaw, {"bbb_gsm_1ch_8khz_13kbps.info", ""}},
{"bbb_g711mulaw_1ch_8khz.raw", ""}, {Codec2AudioDecHidlTest::standardComp::raw,
{"bbb_g711mulaw_1ch_8khz.info", ""}}, {"bbb_raw_1ch_8khz_s32le.raw", ""},
{Codec2AudioDecHidlTest::standardComp::gsm, {"bbb_raw_1ch_8khz_s32le.info", ""}},
{"bbb_gsm_1ch_8khz_13kbps.raw", ""}, {Codec2AudioDecHidlTest::standardComp::flac,
{"bbb_gsm_1ch_8khz_13kbps.info", ""}}, {"bbb_flac_stereo_680kbps_48000hz.flac", ""},
{Codec2AudioDecHidlTest::standardComp::raw, {"bbb_flac_stereo_680kbps_48000hz.info", ""}},
{"bbb_raw_1ch_8khz_s32le.raw", ""},
{"bbb_raw_1ch_8khz_s32le.info", ""}},
{Codec2AudioDecHidlTest::standardComp::flac,
{"bbb_flac_stereo_680kbps_48000hz.flac", ""},
{"bbb_flac_stereo_680kbps_48000hz.info", ""}},
}; };
for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) { for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
@ -396,13 +375,11 @@ void GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp, char* mURL,
} }
void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component, void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
std::mutex &queueLock, std::condition_variable& queueCondition, std::mutex& queueLock, std::condition_variable& queueCondition,
std::list<std::unique_ptr<C2Work>>& workQueue, std::list<std::unique_ptr<C2Work>>& workQueue,
std::list<uint64_t>& flushedIndices, std::list<uint64_t>& flushedIndices, std::shared_ptr<C2BlockPool>& linearPool,
std::shared_ptr<C2BlockPool>& linearPool, std::ifstream& eleStream, android::Vector<FrameInfo>* Info, int offset,
std::ifstream& eleStream, int range, bool signalEOS = true) {
android::Vector<FrameInfo>* Info,
int offset, int range, bool signalEOS = true) {
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
int frameID = offset; int frameID = offset;
int maxRetry = 0; int maxRetry = 0;
@ -426,8 +403,7 @@ void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
} }
int64_t timestamp = (*Info)[frameID].timestamp; int64_t timestamp = (*Info)[frameID].timestamp;
if ((*Info)[frameID].flags) flags = 1u << ((*Info)[frameID].flags - 1); if ((*Info)[frameID].flags) flags = 1u << ((*Info)[frameID].flags - 1);
if (signalEOS && ((frameID == (int)Info->size() - 1) || if (signalEOS && ((frameID == (int)Info->size() - 1) || (frameID == (offset + range - 1))))
(frameID == (offset + range - 1))))
flags |= C2FrameData::FLAG_END_OF_STREAM; flags |= C2FrameData::FLAG_END_OF_STREAM;
work->input.flags = (C2FrameData::flags_t)flags; work->input.flags = (C2FrameData::flags_t)flags;
@ -448,9 +424,8 @@ void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
if (size) { if (size) {
std::shared_ptr<C2LinearBlock> block; std::shared_ptr<C2LinearBlock> block;
ASSERT_EQ(C2_OK, ASSERT_EQ(C2_OK,
linearPool->fetchLinearBlock( linearPool->fetchLinearBlock(
size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
&block));
ASSERT_TRUE(block); ASSERT_TRUE(block);
// Write View // Write View
@ -482,45 +457,49 @@ void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
} }
} }
TEST_F(Codec2AudioDecHidlTest, validateCompName) { TEST_P(Codec2AudioDecHidlTest, validateCompName) {
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
ALOGV("Checks if the given component is a valid audio component"); ALOGV("Checks if the given component is a valid audio component");
validateComponent(mComponent, mCompName, mDisableTest); validateComponent(mComponent, mCompName, mDisableTest);
ASSERT_EQ(mDisableTest, false); ASSERT_EQ(mDisableTest, false);
} }
TEST_F(Codec2AudioDecHidlTest, configComp) { TEST_P(Codec2AudioDecHidlTest, configComp) {
description("Tests component specific configuration"); description("Tests component specific configuration");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
ASSERT_EQ(mComponent->start(), C2_OK); ASSERT_EQ(mComponent->start(), C2_OK);
int32_t bitStreamInfo[2] = {0}; int32_t bitStreamInfo[2] = {0};
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
setupConfigParam(mComponent, bitStreamInfo); setupConfigParam(mComponent, bitStreamInfo);
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
class Codec2AudioDecDecodeTest class Codec2AudioDecDecodeTest
: public Codec2AudioDecHidlTest, : public Codec2AudioDecHidlTestBase,
public ::testing::WithParamInterface<std::pair<int32_t, bool>> { public ::testing::WithParamInterface<
std::tuple<std::string, std::string, std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
}
}; };
TEST_P(Codec2AudioDecDecodeTest, DecodeTest) { TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
description("Decodes input file"); description("Decodes input file");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
uint32_t streamIndex = GetParam().first; uint32_t streamIndex = std::stoi(std::get<2>(GetParam()));
bool signalEOS = GetParam().second; ;
bool signalEOS = !std::get<3>(GetParam()).compare("true");
mTimestampDevTest = true; mTimestampDevTest = true;
char mURL[512], info[512]; char mURL[512], info[512];
std::ifstream eleStream, eleInfo; std::ifstream eleStream, eleInfo;
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
strcpy(info, gEnv->getRes().c_str()); strcpy(info, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL, info, streamIndex); GetURLForComponent(mCompName, mURL, info, streamIndex);
if (!strcmp(mURL, gEnv->getRes().c_str())) { if (!strcmp(mURL, sResourceDir.c_str())) {
ALOGV("EMPTY INPUT gEnv->getRes().c_str() %s mURL %s ", ALOGV("EMPTY INPUT sResourceDir.c_str() %s mURL %s ", sResourceDir.c_str(), mURL);
gEnv->getRes().c_str(), mURL);
return; return;
} }
@ -534,10 +513,8 @@ TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
if (!(eleInfo >> bytesCount)) break; if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags; eleInfo >> flags;
eleInfo >> timestamp; eleInfo >> timestamp;
bool codecConfig = bool codecConfig = ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0;
((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0; if (mTimestampDevTest && !codecConfig) mTimestampUslist.push_back(timestamp);
if (mTimestampDevTest && !codecConfig)
mTimestampUslist.push_back(timestamp);
Info.push_back({bytesCount, flags, timestamp}); Info.push_back({bytesCount, flags, timestamp});
} }
eleInfo.close(); eleInfo.close();
@ -549,8 +526,7 @@ TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
bitStreamInfo[0] = 8000; bitStreamInfo[0] = 8000;
bitStreamInfo[1] = 1; bitStreamInfo[1] = 1;
} else { } else {
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
} }
if (!setupConfigParam(mComponent, bitStreamInfo)) { if (!setupConfigParam(mComponent, bitStreamInfo)) {
std::cout << "[ WARN ] Test Skipped \n"; std::cout << "[ WARN ] Test Skipped \n";
@ -560,29 +536,25 @@ TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
ALOGV("mURL : %s", mURL); ALOGV("mURL : %s", mURL);
eleStream.open(mURL, std::ifstream::binary); eleStream.open(mURL, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true); ASSERT_EQ(eleStream.is_open(), true);
ASSERT_NO_FATAL_FAILURE(decodeNFrames( ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mFlushedIndices, mLinearPool, eleStream, &Info, 0,
mLinearPool, eleStream, &Info, 0, (int)Info.size(), signalEOS)); (int)Info.size(), signalEOS));
// If EOS is not sent, sending empty input with EOS flag // If EOS is not sent, sending empty input with EOS flag
size_t infoSize = Info.size(); size_t infoSize = Info.size();
if (!signalEOS) { if (!signalEOS) {
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1)); ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
ASSERT_NO_FATAL_FAILURE( C2FrameData::FLAG_END_OF_STREAM, false));
testInputBuffer(mComponent, mQueueLock, mWorkQueue,
C2FrameData::FLAG_END_OF_STREAM, false));
infoSize += 1; infoSize += 1;
} }
// blocking call to ensures application to Wait till all the inputs are // blocking call to ensures application to Wait till all the inputs are
// consumed // consumed
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
eleStream.close(); eleStream.close();
if (mFramesReceived != infoSize) { if (mFramesReceived != infoSize) {
ALOGE("Input buffer count and Output buffer count mismatch"); ALOGE("Input buffer count and Output buffer count mismatch");
ALOGE("framesReceived : %d inputFrames : %zu", mFramesReceived, ALOGE("framesReceived : %d inputFrames : %zu", mFramesReceived, infoSize);
infoSize);
ASSERT_TRUE(false); ASSERT_TRUE(false);
} }
ASSERT_EQ(mEos, true); ASSERT_EQ(mEos, true);
@ -590,8 +562,7 @@ TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
uint64_t expTs; uint64_t expTs;
uint32_t samplesReceived = 0; uint32_t samplesReceived = 0;
// Update SampleRate and ChannelCount // Update SampleRate and ChannelCount
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
int nSampleRate = bitStreamInfo[0]; int nSampleRate = bitStreamInfo[0];
int nChannels = bitStreamInfo[1]; int nChannels = bitStreamInfo[1];
std::list<uint64_t>::iterator itIn = mTimestampUslist.begin(); std::list<uint64_t>::iterator itIn = mTimestampUslist.begin();
@ -614,23 +585,17 @@ TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
} }
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
// DecodeTest with StreamIndex and EOS / No EOS
INSTANTIATE_TEST_CASE_P(StreamIndexAndEOS, Codec2AudioDecDecodeTest,
::testing::Values(std::make_pair(0, false),
std::make_pair(0, true),
std::make_pair(1, false),
std::make_pair(1, true)));
// thumbnail test // thumbnail test
TEST_F(Codec2AudioDecHidlTest, ThumbnailTest) { TEST_P(Codec2AudioDecHidlTest, ThumbnailTest) {
description("Test Request for thumbnail"); description("Test Request for thumbnail");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
char mURL[512], info[512]; char mURL[512], info[512];
std::ifstream eleStream, eleInfo; std::ifstream eleStream, eleInfo;
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
strcpy(info, gEnv->getRes().c_str()); strcpy(info, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL, info); GetURLForComponent(mCompName, mURL, info);
eleInfo.open(info); eleInfo.open(info);
@ -651,8 +616,7 @@ TEST_F(Codec2AudioDecHidlTest, ThumbnailTest) {
bitStreamInfo[0] = 8000; bitStreamInfo[0] = 8000;
bitStreamInfo[1] = 1; bitStreamInfo[1] = 1;
} else { } else {
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
} }
if (!setupConfigParam(mComponent, bitStreamInfo)) { if (!setupConfigParam(mComponent, bitStreamInfo)) {
std::cout << "[ WARN ] Test Skipped \n"; std::cout << "[ WARN ] Test Skipped \n";
@ -672,20 +636,19 @@ TEST_F(Codec2AudioDecHidlTest, ThumbnailTest) {
} while (!(flags & SYNC_FRAME)); } while (!(flags & SYNC_FRAME));
eleStream.open(mURL, std::ifstream::binary); eleStream.open(mURL, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true); ASSERT_EQ(eleStream.is_open(), true);
ASSERT_NO_FATAL_FAILURE(decodeNFrames( ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mFlushedIndices, mLinearPool, eleStream, &Info, 0,
mLinearPool, eleStream, &Info, 0, i + 1)); i + 1));
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
eleStream.close(); eleStream.close();
EXPECT_GE(mFramesReceived, 1U); EXPECT_GE(mFramesReceived, 1U);
ASSERT_EQ(mEos, true); ASSERT_EQ(mEos, true);
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
TEST_F(Codec2AudioDecHidlTest, EOSTest) { TEST_P(Codec2AudioDecHidlTest, EOSTest) {
description("Test empty input buffer with EOS flag"); description("Test empty input buffer with EOS flag");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
ASSERT_EQ(mComponent->start(), C2_OK); ASSERT_EQ(mComponent->start(), C2_OK);
std::unique_ptr<C2Work> work; std::unique_ptr<C2Work> work;
@ -723,15 +686,15 @@ TEST_F(Codec2AudioDecHidlTest, EOSTest) {
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
TEST_F(Codec2AudioDecHidlTest, FlushTest) { TEST_P(Codec2AudioDecHidlTest, FlushTest) {
description("Tests Flush calls"); description("Tests Flush calls");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
char mURL[512], info[512]; char mURL[512], info[512];
std::ifstream eleStream, eleInfo; std::ifstream eleStream, eleInfo;
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
strcpy(info, gEnv->getRes().c_str()); strcpy(info, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL, info); GetURLForComponent(mCompName, mURL, info);
eleInfo.open(info); eleInfo.open(info);
@ -753,8 +716,7 @@ TEST_F(Codec2AudioDecHidlTest, FlushTest) {
bitStreamInfo[0] = 8000; bitStreamInfo[0] = 8000;
bitStreamInfo[1] = 1; bitStreamInfo[1] = 1;
} else { } else {
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
} }
if (!setupConfigParam(mComponent, bitStreamInfo)) { if (!setupConfigParam(mComponent, bitStreamInfo)) {
std::cout << "[ WARN ] Test Skipped \n"; std::cout << "[ WARN ] Test Skipped \n";
@ -768,29 +730,25 @@ TEST_F(Codec2AudioDecHidlTest, FlushTest) {
// frame after this so that the below section can be covered for all // frame after this so that the below section can be covered for all
// components // components
uint32_t numFramesFlushed = 128; uint32_t numFramesFlushed = 128;
ASSERT_NO_FATAL_FAILURE(decodeNFrames( ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mFlushedIndices, mLinearPool, eleStream, &Info, 0,
mLinearPool, eleStream, &Info, 0, numFramesFlushed, false)); numFramesFlushed, false));
// flush // flush
std::list<std::unique_ptr<C2Work>> flushedWork; std::list<std::unique_ptr<C2Work>> flushedWork;
c2_status_t err = c2_status_t err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
(size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
uint64_t frameIndex; uint64_t frameIndex;
{ {
//Update mFlushedIndices based on the index received from flush() // Update mFlushedIndices based on the index received from flush()
ULock l(mQueueLock); ULock l(mQueueLock);
for (std::unique_ptr<C2Work>& work : flushedWork) { for (std::unique_ptr<C2Work>& work : flushedWork) {
ASSERT_NE(work, nullptr); ASSERT_NE(work, nullptr);
frameIndex = work->input.ordinal.frameIndex.peeku(); frameIndex = work->input.ordinal.frameIndex.peeku();
std::list<uint64_t>::iterator frameIndexIt = std::list<uint64_t>::iterator frameIndexIt =
std::find(mFlushedIndices.begin(), mFlushedIndices.end(), std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
frameIndex); if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
if (!mFlushedIndices.empty() &&
(frameIndexIt != mFlushedIndices.end())) {
mFlushedIndices.erase(frameIndexIt); mFlushedIndices.erase(frameIndexIt);
work->input.buffers.clear(); work->input.buffers.clear();
work->worklets.clear(); work->worklets.clear();
@ -814,29 +772,24 @@ TEST_F(Codec2AudioDecHidlTest, FlushTest) {
index++; index++;
} }
if (keyFrame) { if (keyFrame) {
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mLinearPool, eleStream, &Info, index,
mFlushedIndices, mLinearPool, eleStream, &Info, index, (int)Info.size() - index));
(int)Info.size() - index));
} }
eleStream.close(); eleStream.close();
err = err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
(size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
{ {
//Update mFlushedIndices based on the index received from flush() // Update mFlushedIndices based on the index received from flush()
ULock l(mQueueLock); ULock l(mQueueLock);
for (std::unique_ptr<C2Work>& work : flushedWork) { for (std::unique_ptr<C2Work>& work : flushedWork) {
ASSERT_NE(work, nullptr); ASSERT_NE(work, nullptr);
frameIndex = work->input.ordinal.frameIndex.peeku(); frameIndex = work->input.ordinal.frameIndex.peeku();
std::list<uint64_t>::iterator frameIndexIt = std::list<uint64_t>::iterator frameIndexIt =
std::find(mFlushedIndices.begin(), mFlushedIndices.end(), std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
frameIndex); if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
if (!mFlushedIndices.empty() &&
(frameIndexIt != mFlushedIndices.end())) {
mFlushedIndices.erase(frameIndexIt); mFlushedIndices.erase(frameIndexIt);
work->input.buffers.clear(); work->input.buffers.clear();
work->worklets.clear(); work->worklets.clear();
@ -848,15 +801,15 @@ TEST_F(Codec2AudioDecHidlTest, FlushTest) {
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
TEST_F(Codec2AudioDecHidlTest, DecodeTestEmptyBuffersInserted) { TEST_P(Codec2AudioDecHidlTest, DecodeTestEmptyBuffersInserted) {
description("Decode with multiple empty input frames"); description("Decode with multiple empty input frames");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
char mURL[512], info[512]; char mURL[512], info[512];
std::ifstream eleStream, eleInfo; std::ifstream eleStream, eleInfo;
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
strcpy(info, gEnv->getRes().c_str()); strcpy(info, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL, info); GetURLForComponent(mCompName, mURL, info);
eleInfo.open(info); eleInfo.open(info);
@ -871,15 +824,16 @@ TEST_F(Codec2AudioDecHidlTest, DecodeTestEmptyBuffersInserted) {
// and empty input frames at an interval of 5 frames. // and empty input frames at an interval of 5 frames.
while (1) { while (1) {
if (!(frameId % 5)) { if (!(frameId % 5)) {
if (!(frameId % 20)) flags = 32; if (!(frameId % 20))
else flags = 0; flags = 32;
else
flags = 0;
bytesCount = 0; bytesCount = 0;
} else { } else {
if (!(eleInfo >> bytesCount)) break; if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags; eleInfo >> flags;
eleInfo >> timestamp; eleInfo >> timestamp;
codecConfig = flags ? codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
} }
Info.push_back({bytesCount, flags, timestamp}); Info.push_back({bytesCount, flags, timestamp});
frameId++; frameId++;
@ -890,8 +844,7 @@ TEST_F(Codec2AudioDecHidlTest, DecodeTestEmptyBuffersInserted) {
bitStreamInfo[0] = 8000; bitStreamInfo[0] = 8000;
bitStreamInfo[1] = 1; bitStreamInfo[1] = 1;
} else { } else {
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
} }
if (!setupConfigParam(mComponent, bitStreamInfo)) { if (!setupConfigParam(mComponent, bitStreamInfo)) {
std::cout << "[ WARN ] Test Skipped \n"; std::cout << "[ WARN ] Test Skipped \n";
@ -901,40 +854,59 @@ TEST_F(Codec2AudioDecHidlTest, DecodeTestEmptyBuffersInserted) {
ALOGV("mURL : %s", mURL); ALOGV("mURL : %s", mURL);
eleStream.open(mURL, std::ifstream::binary); eleStream.open(mURL, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true); ASSERT_EQ(eleStream.is_open(), true);
ASSERT_NO_FATAL_FAILURE(decodeNFrames( ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mFlushedIndices, mLinearPool, eleStream, &Info, 0,
mLinearPool, eleStream, &Info, 0, (int)Info.size())); (int)Info.size()));
// blocking call to ensures application to Wait till all the inputs are // blocking call to ensures application to Wait till all the inputs are
// consumed // consumed
if (!mEos) { if (!mEos) {
ALOGV("Waiting for input consumption"); ALOGV("Waiting for input consumption");
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
} }
eleStream.close(); eleStream.close();
if (mFramesReceived != Info.size()) { if (mFramesReceived != Info.size()) {
ALOGE("Input buffer count and Output buffer count mismatch"); ALOGE("Input buffer count and Output buffer count mismatch");
ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, Info.size());
Info.size());
ASSERT_TRUE(false); ASSERT_TRUE(false);
} }
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2AudioDecHidlTest, testing::ValuesIn(kTestParameters),
android::hardware::PrintInstanceTupleNameToString<>);
// DecodeTest with StreamIndex and EOS / No EOS
INSTANTIATE_TEST_SUITE_P(StreamIndexAndEOS, Codec2AudioDecDecodeTest,
testing::ValuesIn(kDecodeTestParameters),
android::hardware::PrintInstanceTupleNameToString<>);
} // anonymous namespace } // anonymous namespace
int main(int argc, char** argv) { int main(int argc, char** argv) {
gEnv = new ComponentTestEnvironment(); kTestParameters = getTestParameters(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER);
::testing::AddGlobalTestEnvironment(gEnv); for (auto params : kTestParameters) {
::testing::InitGoogleTest(&argc, argv); kDecodeTestParameters.push_back(
gEnv->init(&argc, argv); std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "false"));
int status = gEnv->initFromOptions(argc, argv); kDecodeTestParameters.push_back(
if (status == 0) { std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "true"));
int status = RUN_ALL_TESTS(); kDecodeTestParameters.push_back(
LOG(INFO) << "C2 Test result = " << status; std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "false"));
kDecodeTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "true"));
}
// Set the resource directory based on command line args.
// Test will fail to set up if the argument is not set.
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-P") == 0 && i < argc - 1) {
sResourceDir = argv[i + 1];
break;
}
} }
return status;
} ::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 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.
-->
<configuration description="Runs VtsHalMediaC2V1_0TargetAudioDecTest.">
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push-file" key="vts_media_c2_v1_0_audio_dec_test" value="/data/local/tmp/vts_media_c2_v1_0_audio_dec_test" />
<!-- Files used for audio testing -->
<option name="push-file" key="bbb_aac_stereo_128kbps_48000hz.aac" value="/data/local/tmp/media/bbb_aac_stereo_128kbps_48000hz.aac" />
<option name="push-file" key="bbb_aac_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_aac_stereo_128kbps_48000hz.info" />
<option name="push-file" key="bbb_aac_stereo_128kbps_48000hz_multi_frame.info" value="/data/local/tmp/media/bbb_aac_stereo_128kbps_48000hz_multi_frame.info" />
<option name="push-file" key="bbb_amrwb_1ch_14kbps_16000hz.amrwb" value="/data/local/tmp/media/bbb_amrwb_1ch_14kbps_16000hz.amrwb" />
<option name="push-file" key="bbb_amrwb_1ch_14kbps_16000hz.info" value="/data/local/tmp/media/bbb_amrwb_1ch_14kbps_16000hz.info" />
<option name="push-file" key="bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info" value="/data/local/tmp/media/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info" />
<option name="push-file" key="bbb_flac_stereo_680kbps_48000hz.flac" value="/data/local/tmp/media/bbb_flac_stereo_680kbps_48000hz.flac" />
<option name="push-file" key="bbb_flac_stereo_680kbps_48000hz.info" value="/data/local/tmp/media/bbb_flac_stereo_680kbps_48000hz.info" />
<option name="push-file" key="bbb_g711alaw_1ch_8khz.info" value="/data/local/tmp/media/bbb_g711alaw_1ch_8khz.info" />
<option name="push-file" key="bbb_g711alaw_1ch_8khz.raw" value="/data/local/tmp/media/bbb_g711alaw_1ch_8khz.raw" />
<option name="push-file" key="bbb_g711mulaw_1ch_8khz.info" value="/data/local/tmp/media/bbb_g711mulaw_1ch_8khz.info" />
<option name="push-file" key="bbb_g711mulaw_1ch_8khz.raw" value="/data/local/tmp/media/bbb_g711mulaw_1ch_8khz.raw" />
<option name="push-file" key="bbb_gsm_1ch_8khz_13kbps.info" value="/data/local/tmp/media/bbb_gsm_1ch_8khz_13kbps.info" />
<option name="push-file" key="bbb_gsm_1ch_8khz_13kbps.raw" value="/data/local/tmp/media/bbb_gsm_1ch_8khz_13kbps.raw" />
<option name="push-file" key="bbb_mp3_stereo_192kbps_48000hz.info" value="/data/local/tmp/media/bbb_mp3_stereo_192kbps_48000hz.info" />
<option name="push-file" key="bbb_mp3_stereo_192kbps_48000hz.mp3" value="/data/local/tmp/media/bbb_mp3_stereo_192kbps_48000hz.mp3" />
<option name="push-file" key="bbb_mp3_stereo_192kbps_48000hz_multi_frame.info" value="/data/local/tmp/media/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info" />
<option name="push-file" key="bbb_opus_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_opus_stereo_128kbps_48000hz.info" />
<option name="push-file" key="bbb_opus_stereo_128kbps_48000hz.opus" value="/data/local/tmp/media/bbb_opus_stereo_128kbps_48000hz.opus" />
<option name="push-file" key="bbb_raw_1ch_8khz_s32le.info" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le.info" />
<option name="push-file" key="bbb_raw_1ch_8khz_s32le.raw" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le.raw" />
<option name="push-file" key="bbb_vorbis_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_vorbis_stereo_128kbps_48000hz.info" />
<option name="push-file" key="bbb_vorbis_stereo_128kbps_48000hz.vorbis" value="/data/local/tmp/media/bbb_vorbis_stereo_128kbps_48000hz.vorbis" />
<option name="push-file" key="sine_amrnb_1ch_12kbps_8000hz.amrnb" value="/data/local/tmp/media/sine_amrnb_1ch_12kbps_8000hz.amrnb" />
<option name="push-file" key="sine_amrnb_1ch_12kbps_8000hz.info" value="/data/local/tmp/media/sine_amrnb_1ch_12kbps_8000hz.info" />
<option name="push-file" key="sine_amrnb_1ch_12kbps_8000hz_multi_frame.info" value="/data/local/tmp/media/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="vts_media_c2_v1_0_audio_dec_test" />
<option name="native-test-flag" value="-P /data/local/tmp/media/" />
</test>
</configuration>

@ -19,74 +19,60 @@
#include <android-base/logging.h> #include <android-base/logging.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <stdio.h> #include <stdio.h>
#include <fstream>
#include <algorithm> #include <algorithm>
#include <fstream>
#include <codec2/hidl/client.h>
#include <C2AllocatorIon.h> #include <C2AllocatorIon.h>
#include <C2Config.h>
#include <C2Debug.h>
#include <C2Buffer.h> #include <C2Buffer.h>
#include <C2BufferPriv.h> #include <C2BufferPriv.h>
#include <C2Config.h>
#include <C2Debug.h>
#include <codec2/hidl/client.h>
using android::C2AllocatorIon; using android::C2AllocatorIon;
#include <VtsHalHidlTargetTestBase.h>
#include "media_c2_audio_hidl_test_common.h"
#include "media_c2_hidl_test_common.h" #include "media_c2_hidl_test_common.h"
static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
kEncodeTestParameters;
// Resource directory
static std::string sResourceDir = "";
class LinearBuffer : public C2Buffer { class LinearBuffer : public C2Buffer {
public: public:
explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block) explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
: C2Buffer( : C2Buffer({block->share(block->offset(), block->size(), ::C2Fence())}) {}
{block->share(block->offset(), block->size(), ::C2Fence())}) {}
}; };
static ComponentTestEnvironment* gEnv = nullptr;
namespace { namespace {
class Codec2AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase { class Codec2AudioEncHidlTestBase : public ::testing::Test {
private: public:
typedef ::testing::VtsHalHidlTargetTestBase Super;
public:
::std::string getTestCaseInfo() const override {
return ::std::string() +
"Component: " + gEnv->getComponent().c_str() + " | " +
"Instance: " + gEnv->getInstance().c_str() + " | " +
"Res: " + gEnv->getRes().c_str();
}
// google.codec2 Audio test setup // google.codec2 Audio test setup
virtual void SetUp() override { virtual void SetUp() override {
Super::SetUp(); getParams();
mDisableTest = false; mDisableTest = false;
ALOGV("Codec2AudioEncHidlTest SetUp"); ALOGV("Codec2AudioEncHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService( mClient = android::Codec2Client::CreateFromService(
gEnv->getInstance().c_str(), mInstanceName.c_str(),
!bool(android::Codec2Client::CreateFromService("default", true))); !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr); ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener( mListener.reset(new CodecListener([this](std::list<std::unique_ptr<C2Work>>& workItems) {
[this](std::list<std::unique_ptr<C2Work>>& workItems) { handleWorkDone(workItems);
handleWorkDone(workItems); }));
}));
ASSERT_NE(mListener, nullptr); ASSERT_NE(mListener, nullptr);
for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) { for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
mWorkQueue.emplace_back(new C2Work); mWorkQueue.emplace_back(new C2Work);
} }
mClient->createComponent(gEnv->getComponent().c_str(), mListener, mClient->createComponent(mComponentName, mListener, &mComponent);
&mComponent);
ASSERT_NE(mComponent, nullptr); ASSERT_NE(mComponent, nullptr);
std::shared_ptr<C2AllocatorStore> store = std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
android::GetCodec2PlatformAllocatorStore(); CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
&mLinearAllocator),
C2_OK);
mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator,
mBlockPoolId++);
ASSERT_NE(mLinearPool, nullptr); ASSERT_NE(mLinearPool, nullptr);
mCompName = unknown_comp; mCompName = unknown_comp;
@ -95,19 +81,13 @@ class Codec2AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
standardComp CompName; standardComp CompName;
}; };
const StringToName kStringToName[] = { const StringToName kStringToName[] = {
{"aac", aac}, {"aac", aac}, {"flac", flac}, {"opus", opus}, {"amrnb", amrnb}, {"amrwb", amrwb},
{"flac", flac},
{"opus", opus},
{"amrnb", amrnb},
{"amrwb", amrwb},
}; };
const size_t kNumStringToName = const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]);
sizeof(kStringToName) / sizeof(kStringToName[0]);
// Find the component type // Find the component type
std::string comp = std::string(gEnv->getComponent());
for (size_t i = 0; i < kNumStringToName; ++i) { for (size_t i = 0; i < kNumStringToName; ++i) {
if (strcasestr(comp.c_str(), kStringToName[i].Name)) { if (strcasestr(mComponentName.c_str(), kStringToName[i].Name)) {
mCompName = kStringToName[i].CompName; mCompName = kStringToName[i].CompName;
break; break;
} }
@ -126,15 +106,17 @@ class Codec2AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
mComponent->release(); mComponent->release();
mComponent = nullptr; mComponent = nullptr;
} }
Super::TearDown();
} }
// Get the test parameters from GetParam call.
virtual void getParams() {}
// callback function to process onWorkDone received by Listener // callback function to process onWorkDone received by Listener
void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) { void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
for (std::unique_ptr<C2Work>& work : workItems) { for (std::unique_ptr<C2Work>& work : workItems) {
if (!work->worklets.empty()) { if (!work->worklets.empty()) {
workDone(mComponent, work, mFlushedIndices, mQueueLock, workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
mQueueCondition, mWorkQueue, mEos, mCsd, mEos, mCsd, mFramesReceived);
mFramesReceived);
} }
} }
} }
@ -147,6 +129,8 @@ class Codec2AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
unknown_comp, unknown_comp,
}; };
std::string mInstanceName;
std::string mComponentName;
bool mEos; bool mEos;
bool mCsd; bool mCsd;
bool mDisableTest; bool mDisableTest;
@ -167,7 +151,7 @@ class Codec2AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
std::shared_ptr<android::Codec2Client::Listener> mListener; std::shared_ptr<android::Codec2Client::Listener> mListener;
std::shared_ptr<android::Codec2Client::Component> mComponent; std::shared_ptr<android::Codec2Client::Component> mComponent;
protected: protected:
static void description(const std::string& description) { static void description(const std::string& description) {
RecordProperty("description", description); RecordProperty("description", description);
} }
@ -176,9 +160,8 @@ class Codec2AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
void getInputMaxBufSize() { void getInputMaxBufSize() {
int32_t bitStreamInfo[1] = {0}; int32_t bitStreamInfo[1] = {0};
std::vector<std::unique_ptr<C2Param>> inParams; std::vector<std::unique_ptr<C2Param>> inParams;
c2_status_t status = mComponent->query( c2_status_t status = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE},
{}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE}, C2_DONT_BLOCK, C2_DONT_BLOCK, &inParams);
&inParams);
if (status != C2_OK && inParams.size() == 0) { if (status != C2_OK && inParams.size() == 0) {
ALOGE("Query MaxBufferSizeInfo failed => %d", status); ALOGE("Query MaxBufferSizeInfo failed => %d", status);
ASSERT_TRUE(false); ASSERT_TRUE(false);
@ -191,12 +174,19 @@ class Codec2AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
} }
mInputMaxBufSize = bitStreamInfo[0]; mInputMaxBufSize = bitStreamInfo[0];
} }
};
class Codec2AudioEncHidlTest
: public Codec2AudioEncHidlTestBase,
public ::testing::WithParamInterface<std::tuple<std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
}
}; };
void validateComponent( void validateComponent(const std::shared_ptr<android::Codec2Client::Component>& component,
const std::shared_ptr<android::Codec2Client::Component>& component, Codec2AudioEncHidlTest::standardComp compName, bool& disableTest) {
Codec2AudioEncHidlTest::standardComp compName, bool& disableTest) {
// Validate its a C2 Component // Validate its a C2 Component
if (component->getName().find("c2") == std::string::npos) { if (component->getName().find("c2") == std::string::npos) {
ALOGE("Not a c2 component"); ALOGE("Not a c2 component");
@ -211,14 +201,12 @@ void validateComponent(
return; return;
} }
std::vector<std::unique_ptr<C2Param>> queried; std::vector<std::unique_ptr<C2Param>> queried;
c2_status_t c2err = c2_status_t c2err = component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK, &queried);
C2_DONT_BLOCK, &queried);
if (c2err != C2_OK && queried.size() == 0) { if (c2err != C2_OK && queried.size() == 0) {
ALOGE("Query media type failed => %d", c2err); ALOGE("Query media type failed => %d", c2err);
} else { } else {
std::string inputDomain = std::string inputDomain = ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
if (inputDomain.find("audio/") == std::string::npos) { if (inputDomain.find("audio/") == std::string::npos) {
ALOGE("Expected Audio Component"); ALOGE("Expected Audio Component");
disableTest = true; disableTest = true;
@ -236,16 +224,14 @@ void validateComponent(
} }
// Set Default config param. // Set Default config param.
bool setupConfigParam( bool setupConfigParam(const std::shared_ptr<android::Codec2Client::Component>& component,
const std::shared_ptr<android::Codec2Client::Component>& component, int32_t nChannels, int32_t nSampleRate) {
int32_t nChannels, int32_t nSampleRate) {
std::vector<std::unique_ptr<C2SettingResult>> failures; std::vector<std::unique_ptr<C2SettingResult>> failures;
C2StreamSampleRateInfo::input sampleRateInfo(0u, nSampleRate); C2StreamSampleRateInfo::input sampleRateInfo(0u, nSampleRate);
C2StreamChannelCountInfo::input channelCountInfo(0u, nChannels); C2StreamChannelCountInfo::input channelCountInfo(0u, nChannels);
std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo}; std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo};
c2_status_t status = c2_status_t status = component->config(configParam, C2_DONT_BLOCK, &failures);
component->config(configParam, C2_DONT_BLOCK, &failures);
if (status == C2_OK && failures.size() == 0u) return true; if (status == C2_OK && failures.size() == 0u) return true;
return false; return false;
} }
@ -257,16 +243,11 @@ void GetURLForComponent(Codec2AudioEncHidlTest::standardComp comp, char* mURL) {
const char* mURL; const char* mURL;
}; };
static const CompToURL kCompToURL[] = { static const CompToURL kCompToURL[] = {
{Codec2AudioEncHidlTest::standardComp::aac, {Codec2AudioEncHidlTest::standardComp::aac, "bbb_raw_2ch_48khz_s16le.raw"},
"bbb_raw_2ch_48khz_s16le.raw"}, {Codec2AudioEncHidlTest::standardComp::amrnb, "bbb_raw_1ch_8khz_s16le.raw"},
{Codec2AudioEncHidlTest::standardComp::amrnb, {Codec2AudioEncHidlTest::standardComp::amrwb, "bbb_raw_1ch_16khz_s16le.raw"},
"bbb_raw_1ch_8khz_s16le.raw"}, {Codec2AudioEncHidlTest::standardComp::flac, "bbb_raw_2ch_48khz_s16le.raw"},
{Codec2AudioEncHidlTest::standardComp::amrwb, {Codec2AudioEncHidlTest::standardComp::opus, "bbb_raw_2ch_48khz_s16le.raw"},
"bbb_raw_1ch_16khz_s16le.raw"},
{Codec2AudioEncHidlTest::standardComp::flac,
"bbb_raw_2ch_48khz_s16le.raw"},
{Codec2AudioEncHidlTest::standardComp::opus,
"bbb_raw_2ch_48khz_s16le.raw"},
}; };
for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) { for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
@ -278,21 +259,18 @@ void GetURLForComponent(Codec2AudioEncHidlTest::standardComp comp, char* mURL) {
} }
void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component, void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
std::mutex &queueLock, std::condition_variable& queueCondition, std::mutex& queueLock, std::condition_variable& queueCondition,
std::list<std::unique_ptr<C2Work>>& workQueue, std::list<std::unique_ptr<C2Work>>& workQueue,
std::list<uint64_t>& flushedIndices, std::list<uint64_t>& flushedIndices, std::shared_ptr<C2BlockPool>& linearPool,
std::shared_ptr<C2BlockPool>& linearPool, std::ifstream& eleStream, uint32_t nFrames, int32_t samplesPerFrame,
std::ifstream& eleStream, uint32_t nFrames, int32_t nChannels, int32_t nSampleRate, bool flushed = false,
int32_t samplesPerFrame, int32_t nChannels,
int32_t nSampleRate, bool flushed = false,
bool signalEOS = true) { bool signalEOS = true) {
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
uint32_t frameID = 0; uint32_t frameID = 0;
uint32_t maxRetry = 0; uint32_t maxRetry = 0;
int bytesCount = samplesPerFrame * nChannels * 2; int bytesCount = samplesPerFrame * nChannels * 2;
int32_t timestampIncr = int32_t timestampIncr = (int)(((float)samplesPerFrame / nSampleRate) * 1000000);
(int)(((float)samplesPerFrame / nSampleRate) * 1000000);
uint64_t timestamp = 0; uint64_t timestamp = 0;
while (1) { while (1) {
if (nFrames == 0) break; if (nFrames == 0) break;
@ -312,8 +290,7 @@ void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
if (!work && (maxRetry >= MAX_RETRY)) { if (!work && (maxRetry >= MAX_RETRY)) {
ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout"; ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout";
} }
if (signalEOS && (nFrames == 1)) if (signalEOS && (nFrames == 1)) flags |= C2FrameData::FLAG_END_OF_STREAM;
flags |= C2FrameData::FLAG_END_OF_STREAM;
if (flushed) { if (flushed) {
flags |= SYNC_FRAME; flags |= SYNC_FRAME;
flushed = false; flushed = false;
@ -330,10 +307,9 @@ void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
eleStream.read(data, bytesCount); eleStream.read(data, bytesCount);
ASSERT_EQ(eleStream.gcount(), bytesCount); ASSERT_EQ(eleStream.gcount(), bytesCount);
std::shared_ptr<C2LinearBlock> block; std::shared_ptr<C2LinearBlock> block;
ASSERT_EQ(C2_OK, linearPool->fetchLinearBlock( ASSERT_EQ(C2_OK,
bytesCount, {C2MemoryUsage::CPU_READ, linearPool->fetchLinearBlock(
C2MemoryUsage::CPU_WRITE}, bytesCount, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
&block));
ASSERT_TRUE(block); ASSERT_TRUE(block);
// Write View // Write View
C2WriteView view = block->map().get(); C2WriteView view = block->map().get();
@ -365,27 +341,33 @@ void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
} }
} }
TEST_F(Codec2AudioEncHidlTest, validateCompName) { TEST_P(Codec2AudioEncHidlTest, validateCompName) {
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
ALOGV("Checks if the given component is a valid audio component"); ALOGV("Checks if the given component is a valid audio component");
validateComponent(mComponent, mCompName, mDisableTest); validateComponent(mComponent, mCompName, mDisableTest);
ASSERT_EQ(mDisableTest, false); ASSERT_EQ(mDisableTest, false);
} }
class Codec2AudioEncEncodeTest class Codec2AudioEncEncodeTest
: public Codec2AudioEncHidlTest, : public Codec2AudioEncHidlTestBase,
public ::testing::WithParamInterface<std::pair<bool, int32_t>> { public ::testing::WithParamInterface<
std::tuple<std::string, std::string, std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
}
}; };
TEST_P(Codec2AudioEncEncodeTest, EncodeTest) { TEST_P(Codec2AudioEncEncodeTest, EncodeTest) {
ALOGV("EncodeTest"); ALOGV("EncodeTest");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
char mURL[512]; char mURL[512];
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL); GetURLForComponent(mCompName, mURL);
bool signalEOS = GetParam().first; bool signalEOS = !std::get<2>(GetParam()).compare("true");
// Ratio w.r.t to mInputMaxBufSize // Ratio w.r.t to mInputMaxBufSize
int32_t inputMaxBufRatio = GetParam().second; int32_t inputMaxBufRatio = std::stoi(std::get<3>(GetParam()));
;
// Setting default sampleRate // Setting default sampleRate
int32_t nChannels = 2; int32_t nChannels = 2;
@ -414,10 +396,9 @@ TEST_P(Codec2AudioEncEncodeTest, EncodeTest) {
default: default:
ASSERT_TRUE(false); ASSERT_TRUE(false);
} }
int32_t samplesPerFrame = int32_t samplesPerFrame = ((mInputMaxBufSize / inputMaxBufRatio) / (nChannels * 2));
((mInputMaxBufSize / inputMaxBufRatio) / (nChannels * 2)); ALOGV("signalEOS %d mInputMaxBufSize %d samplesPerFrame %d", signalEOS, mInputMaxBufSize,
ALOGV("signalEOS %d mInputMaxBufSize %d samplesPerFrame %d", signalEOS, samplesPerFrame);
mInputMaxBufSize, samplesPerFrame);
if (!setupConfigParam(mComponent, nChannels, nSampleRate)) { if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
std::cout << "[ WARN ] Test Skipped \n"; std::cout << "[ WARN ] Test Skipped \n";
@ -429,26 +410,21 @@ TEST_P(Codec2AudioEncEncodeTest, EncodeTest) {
eleStream.open(mURL, std::ifstream::binary); eleStream.open(mURL, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true); ASSERT_EQ(eleStream.is_open(), true);
ALOGV("mURL : %s", mURL); ALOGV("mURL : %s", mURL);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(encodeNFrames(
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mLinearPool,
mFlushedIndices, mLinearPool, eleStream, numFrames, eleStream, numFrames, samplesPerFrame, nChannels, nSampleRate, false, signalEOS));
samplesPerFrame, nChannels, nSampleRate, false,
signalEOS));
// If EOS is not sent, sending empty input with EOS flag // If EOS is not sent, sending empty input with EOS flag
if (!signalEOS) { if (!signalEOS) {
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1)); ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
ASSERT_NO_FATAL_FAILURE( C2FrameData::FLAG_END_OF_STREAM, false));
testInputBuffer(mComponent, mQueueLock, mWorkQueue,
C2FrameData::FLAG_END_OF_STREAM, false));
numFrames += 1; numFrames += 1;
} }
// blocking call to ensures application to Wait till all the inputs are // blocking call to ensures application to Wait till all the inputs are
// consumed // consumed
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
eleStream.close(); eleStream.close();
if (mFramesReceived != numFrames) { if (mFramesReceived != numFrames) {
ALOGE("Input buffer count and Output buffer count mismatch"); ALOGE("Input buffer count and Output buffer count mismatch");
@ -465,18 +441,9 @@ TEST_P(Codec2AudioEncEncodeTest, EncodeTest) {
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
// EncodeTest with EOS / No EOS and inputMaxBufRatio TEST_P(Codec2AudioEncHidlTest, EOSTest) {
// inputMaxBufRatio is ratio w.r.t. to mInputMaxBufSize
INSTANTIATE_TEST_CASE_P(EncodeTest, Codec2AudioEncEncodeTest,
::testing::Values(std::make_pair(false, 1),
std::make_pair(false, 2),
std::make_pair(true, 1),
std::make_pair(true, 2)));
TEST_F(Codec2AudioEncHidlTest, EOSTest) {
description("Test empty input buffer with EOS flag"); description("Test empty input buffer with EOS flag");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
ASSERT_EQ(mComponent->start(), C2_OK); ASSERT_EQ(mComponent->start(), C2_OK);
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
@ -514,13 +481,13 @@ TEST_F(Codec2AudioEncHidlTest, EOSTest) {
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
TEST_F(Codec2AudioEncHidlTest, FlushTest) { TEST_P(Codec2AudioEncHidlTest, FlushTest) {
description("Test Request for flush"); description("Test Request for flush");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
char mURL[512]; char mURL[512];
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL); GetURLForComponent(mCompName, mURL);
// Setting default configuration // Setting default configuration
@ -570,29 +537,24 @@ TEST_F(Codec2AudioEncHidlTest, FlushTest) {
eleStream.open(mURL, std::ifstream::binary); eleStream.open(mURL, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true); ASSERT_EQ(eleStream.is_open(), true);
ALOGV("mURL : %s", mURL); ALOGV("mURL : %s", mURL);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mLinearPool, eleStream, numFramesFlushed,
mFlushedIndices, mLinearPool, eleStream, numFramesFlushed, samplesPerFrame, nChannels, nSampleRate));
samplesPerFrame, nChannels, nSampleRate));
std::list<std::unique_ptr<C2Work>> flushedWork; std::list<std::unique_ptr<C2Work>> flushedWork;
c2_status_t err = c2_status_t err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
(size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
uint64_t frameIndex; uint64_t frameIndex;
{ {
//Update mFlushedIndices based on the index received from flush() // Update mFlushedIndices based on the index received from flush()
ULock l(mQueueLock); ULock l(mQueueLock);
for (std::unique_ptr<C2Work>& work : flushedWork) { for (std::unique_ptr<C2Work>& work : flushedWork) {
ASSERT_NE(work, nullptr); ASSERT_NE(work, nullptr);
frameIndex = work->input.ordinal.frameIndex.peeku(); frameIndex = work->input.ordinal.frameIndex.peeku();
std::list<uint64_t>::iterator frameIndexIt = std::list<uint64_t>::iterator frameIndexIt =
std::find(mFlushedIndices.begin(), mFlushedIndices.end(), std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
frameIndex); if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
if (!mFlushedIndices.empty() &&
(frameIndexIt != mFlushedIndices.end())) {
mFlushedIndices.erase(frameIndexIt); mFlushedIndices.erase(frameIndexIt);
work->input.buffers.clear(); work->input.buffers.clear();
work->worklets.clear(); work->worklets.clear();
@ -601,29 +563,24 @@ TEST_F(Codec2AudioEncHidlTest, FlushTest) {
} }
} }
mFlushedIndices.clear(); mFlushedIndices.clear();
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mLinearPool, eleStream,
mFlushedIndices, mLinearPool, eleStream, numFrames - numFramesFlushed, samplesPerFrame, nChannels,
numFrames - numFramesFlushed, samplesPerFrame, nSampleRate, true));
nChannels, nSampleRate, true));
eleStream.close(); eleStream.close();
err = err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
(size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
{ {
//Update mFlushedIndices based on the index received from flush() // Update mFlushedIndices based on the index received from flush()
ULock l(mQueueLock); ULock l(mQueueLock);
for (std::unique_ptr<C2Work>& work : flushedWork) { for (std::unique_ptr<C2Work>& work : flushedWork) {
ASSERT_NE(work, nullptr); ASSERT_NE(work, nullptr);
frameIndex = work->input.ordinal.frameIndex.peeku(); frameIndex = work->input.ordinal.frameIndex.peeku();
std::list<uint64_t>::iterator frameIndexIt = std::list<uint64_t>::iterator frameIndexIt =
std::find(mFlushedIndices.begin(), mFlushedIndices.end(), std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
frameIndex); if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
if (!mFlushedIndices.empty() &&
(frameIndexIt != mFlushedIndices.end())) {
mFlushedIndices.erase(frameIndexIt); mFlushedIndices.erase(frameIndexIt);
work->input.buffers.clear(); work->input.buffers.clear();
work->worklets.clear(); work->worklets.clear();
@ -635,17 +592,39 @@ TEST_F(Codec2AudioEncHidlTest, FlushTest) {
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2AudioEncHidlTest, testing::ValuesIn(kTestParameters),
android::hardware::PrintInstanceTupleNameToString<>);
// EncodeTest with EOS / No EOS and inputMaxBufRatio
// inputMaxBufRatio is ratio w.r.t. to mInputMaxBufSize
INSTANTIATE_TEST_SUITE_P(EncodeTest, Codec2AudioEncEncodeTest,
testing::ValuesIn(kEncodeTestParameters),
android::hardware::PrintInstanceTupleNameToString<>);
} // anonymous namespace } // anonymous namespace
int main(int argc, char** argv) { int main(int argc, char** argv) {
gEnv = new ComponentTestEnvironment(); kTestParameters = getTestParameters(C2Component::DOMAIN_AUDIO, C2Component::KIND_ENCODER);
::testing::AddGlobalTestEnvironment(gEnv); for (auto params : kTestParameters) {
::testing::InitGoogleTest(&argc, argv); kEncodeTestParameters.push_back(
gEnv->init(&argc, argv); std::make_tuple(std::get<0>(params), std::get<1>(params), "false", "1"));
int status = gEnv->initFromOptions(argc, argv); kEncodeTestParameters.push_back(
if (status == 0) { std::make_tuple(std::get<0>(params), std::get<1>(params), "false", "2"));
int status = RUN_ALL_TESTS(); kEncodeTestParameters.push_back(
LOG(INFO) << "C2 Test result = " << status; std::make_tuple(std::get<0>(params), std::get<1>(params), "true", "1"));
kEncodeTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params), "true", "2"));
}
// Set the resource directory based on command line args.
// Test will fail to set up if the argument is not set.
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-P") == 0 && i < argc - 1) {
sResourceDir = argv[i + 1];
break;
}
} }
return status;
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
} }

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 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.
-->
<configuration description="Runs VtsHalMediaC2V1_0TargetAudioEncTest.">
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push-file" key="vts_media_c2_v1_0_audio_enc_test" value="/data/local/tmp/vts_media_c2_v1_0_audio_enc_test" />
<!-- Files used for audio testing -->
<option name="push-file" key="bbb_raw_2ch_48khz_s16le.raw" value="/data/local/tmp/media/bbb_raw_2ch_48khz_s16le.raw" />
<option name="push-file" key="bbb_raw_1ch_8khz_s16le.raw" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s16le.raw" />
<option name="push-file" key="bbb_raw_1ch_16khz_s16le.raw" value="/data/local/tmp/media/bbb_raw_1ch_16khz_s16le.raw" />
<option name="push-file" key="bbb_raw_2ch_48khz_s16le.raw" value="/data/local/tmp/media/bbb_raw_2ch_48khz_s16le.raw" />
<option name="push-file" key="bbb_raw_2ch_48khz_s16le.raw" value="/data/local/tmp/media/bbb_raw_2ch_48khz_s16le.raw" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="vts_media_c2_v1_0_audio_enc_test" />
<option name="native-test-flag" value="-P /data/local/tmp/media/" />
</test>
</configuration>

@ -1,21 +0,0 @@
/*
* Copyright (C) 2018 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.
*/
#ifndef MEDIA_C2_AUDIO_HIDL_TEST_COMMON_H
#define MEDIA_C2_AUDIO_HIDL_TEST_COMMON_H
#endif // MEDIA_C2_AUDIO_HIDL_TEST_COMMON_H

@ -1,7 +1,7 @@
cc_library_static { cc_library_static {
name: "VtsHalMediaC2V1_0CommonUtil", name: "VtsHalMediaC2V1_0CommonUtil",
defaults: [ defaults: [
"Vts10HalTargetTestDefaults", "VtsHalTargetTestDefaults",
"libcodec2-hidl-client-defaults", "libcodec2-hidl-client-defaults",
], ],
@ -19,15 +19,19 @@ cc_library_static {
cc_defaults { cc_defaults {
name: "VtsHalMediaC2V1_0Defaults", name: "VtsHalMediaC2V1_0Defaults",
defaults: [ defaults: [
"Vts10HalTargetTestDefaults", "VtsHalTargetTestDefaults",
"libcodec2-hidl-client-defaults", "libcodec2-hidl-client-defaults",
], ],
static_libs: [ static_libs: [
"libgtest",
"VtsHalMediaC2V1_0CommonUtil", "VtsHalMediaC2V1_0CommonUtil",
], ],
shared_libs: [ shared_libs: [
"libcodec2_client", "libcodec2_client",
], ],
test_suites: [
"vts",
],
} }

@ -3,34 +3,22 @@
## master : ## master :
Functionality of master is to enumerate all the Codec2 components available in C2 media service. Functionality of master is to enumerate all the Codec2 components available in C2 media service.
usage: `VtsHalMediaC2V1_0TargetMasterTest -I default` usage: `atest VtsHalMediaC2V1_0TargetMasterTest`
## component : ## component :
Functionality of component test is to validate common functionality across all the Codec2 components available in C2 media service. For a standard C2 component, these tests are expected to pass. Functionality of component test is to validate common functionality across all the Codec2 components available in C2 media service. For a standard C2 component, these tests are expected to pass.
usage: `VtsHalMediaC2V1_0TargetComponentTest -I software -C <comp name>` usage: `atest VtsHalMediaC2V1_0TargetComponentTest`
example: `VtsHalMediaC2V1_0TargetComponentTest -I software -C c2.android.vorbis.decoder`
## audio : ## audio :
Functionality of audio test is to validate audio specific functionality of Codec2 components. The resource files for this test are taken from `frameworks/av/media/codec2/hidl/1.0/vts/functional/res`. The path to these files on the device can be specified with `-P`. (If the device path is omitted, `/data/local/tmp/media/` is the default value.) Functionality of audio test is to validate audio specific functionality of Codec2 components. The resource files for this test are taken from `frameworks/av/media/codec2/hidl/1.0/vts/functional/res`. The path to these files on the device can be specified with `-P`. (If the device path is omitted, `/data/local/tmp/media/` is the default value.)
usage: `VtsHalMediaC2V1_0TargetAudioDecTest -I default -C <comp name> -P <path to resource files>` usage: `atest VtsHalMediaC2V1_0TargetAudioDecTest`
usage: `VtsHalMediaC2V1_0TargetAudioEncTest -I software -C <comp name> -P <path to resource files>`
example: `VtsHalMediaC2V1_0TargetAudioDecTest -I software -C c2.android.flac.decoder -P /data/local/tmp/media/` usage: `atest VtsHalMediaC2V1_0TargetAudioEncTest`
example: `VtsHalMediaC2V1_0TargetAudioEncTest -I software -C c2.android.opus.encoder -P /data/local/tmp/media/`
## video : ## video :
Functionality of video test is to validate video specific functionality of Codec2 components. The resource files for this test are taken from `frameworks/av/media/codec2/hidl/1.0/vts/functional/res`. The path to these files on the device can be specified with `-P`. (If the device path is omitted, `/data/local/tmp/media/` is the default value.) Functionality of video test is to validate video specific functionality of Codec2 components. The resource files for this test are taken from `frameworks/av/media/codec2/hidl/1.0/vts/functional/res`. The path to these files on the device can be specified with `-P`. (If the device path is omitted, `/data/local/tmp/media/` is the default value.)
usage: `VtsHalMediaC2V1_0TargetVideoDecTest -I default -C <comp name> -P <path to resource files>` usage: `atest VtsHalMediaC2V1_0TargetVideoDecTest`
usage: `atest VtsHalMediaC2V1_0TargetVideoEncTest`
usage: `VtsHalMediaC2V1_0TargetVideoEncTest -I software -C <comp name> -P <path to resource files>`
example: `VtsHalMediaC2V1_0TargetVideoDecTest -I software -C c2.android.avc.decoder -P /data/local/tmp/media/`
example: `VtsHalMediaC2V1_0TargetVideoEncTest -I software -C c2.android.vp9.encoder -P /data/local/tmp/media/`

@ -22,16 +22,10 @@
#include <android/hardware/media/c2/1.0/IComponentStore.h> #include <android/hardware/media/c2/1.0/IComponentStore.h>
void ComponentTestEnvironment::registerTestServices() {
registerTestService<::android::hardware::media::c2::V1_0::
IComponentStore>();
}
// Test the codecs for NullBuffer, Empty Input Buffer with(out) flags set // Test the codecs for NullBuffer, Empty Input Buffer with(out) flags set
void testInputBuffer( void testInputBuffer(const std::shared_ptr<android::Codec2Client::Component>& component,
const std::shared_ptr<android::Codec2Client::Component>& component, std::mutex& queueLock, std::list<std::unique_ptr<C2Work>>& workQueue,
std::mutex& queueLock, std::list<std::unique_ptr<C2Work>>& workQueue, uint32_t flags, bool isNullBuffer) {
uint32_t flags, bool isNullBuffer) {
std::unique_ptr<C2Work> work; std::unique_ptr<C2Work> work;
{ {
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
@ -61,10 +55,8 @@ void testInputBuffer(
} }
// Wait for all the inputs to be consumed by the plugin. // Wait for all the inputs to be consumed by the plugin.
void waitOnInputConsumption(std::mutex& queueLock, void waitOnInputConsumption(std::mutex& queueLock, std::condition_variable& queueCondition,
std::condition_variable& queueCondition, std::list<std::unique_ptr<C2Work>>& workQueue, size_t bufferCount) {
std::list<std::unique_ptr<C2Work>>& workQueue,
size_t bufferCount) {
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
uint32_t queueSize; uint32_t queueSize;
uint32_t maxRetry = 0; uint32_t maxRetry = 0;
@ -85,29 +77,25 @@ void waitOnInputConsumption(std::mutex& queueLock,
} }
// process onWorkDone received by Listener // process onWorkDone received by Listener
void workDone( void workDone(const std::shared_ptr<android::Codec2Client::Component>& component,
const std::shared_ptr<android::Codec2Client::Component>& component, std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices,
std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices, std::mutex& queueLock, std::condition_variable& queueCondition,
std::mutex& queueLock, std::condition_variable& queueCondition, std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd, uint32_t& framesReceived) {
uint32_t& framesReceived) {
// handle configuration changes in work done // handle configuration changes in work done
if (work->worklets.front()->output.configUpdate.size() != 0) { if (work->worklets.front()->output.configUpdate.size() != 0) {
ALOGV("Config Update"); ALOGV("Config Update");
std::vector<std::unique_ptr<C2Param>> updates = std::vector<std::unique_ptr<C2Param>> updates =
std::move(work->worklets.front()->output.configUpdate); std::move(work->worklets.front()->output.configUpdate);
std::vector<C2Param*> configParam; std::vector<C2Param*> configParam;
std::vector<std::unique_ptr<C2SettingResult>> failures; std::vector<std::unique_ptr<C2SettingResult>> failures;
for (size_t i = 0; i < updates.size(); ++i) { for (size_t i = 0; i < updates.size(); ++i) {
C2Param* param = updates[i].get(); C2Param* param = updates[i].get();
if (param->index() == C2StreamInitDataInfo::output::PARAM_TYPE) { if (param->index() == C2StreamInitDataInfo::output::PARAM_TYPE) {
csd = true; csd = true;
} else if ((param->index() == } else if ((param->index() == C2StreamSampleRateInfo::output::PARAM_TYPE) ||
C2StreamSampleRateInfo::output::PARAM_TYPE) || (param->index() == C2StreamChannelCountInfo::output::PARAM_TYPE) ||
(param->index() == (param->index() == C2StreamPictureSizeInfo::output::PARAM_TYPE)) {
C2StreamChannelCountInfo::output::PARAM_TYPE) ||
(param->index() ==
C2StreamPictureSizeInfo::output::PARAM_TYPE)) {
configParam.push_back(param); configParam.push_back(param);
} }
} }
@ -116,8 +104,7 @@ void workDone(
} }
if (work->worklets.front()->output.flags != C2FrameData::FLAG_INCOMPLETE) { if (work->worklets.front()->output.flags != C2FrameData::FLAG_INCOMPLETE) {
framesReceived++; framesReceived++;
eos = (work->worklets.front()->output.flags & eos = (work->worklets.front()->output.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
C2FrameData::FLAG_END_OF_STREAM) != 0;
auto frameIndexIt = std::find(flushedIndices.begin(), flushedIndices.end(), auto frameIndexIt = std::find(flushedIndices.begin(), flushedIndices.end(),
work->input.ordinal.frameIndex.peeku()); work->input.ordinal.frameIndex.peeku());
ALOGV("WorkDone: frameID received %d", ALOGV("WorkDone: frameID received %d",
@ -143,3 +130,33 @@ int64_t getNowUs() {
return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll; return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll;
} }
// Return all test parameters, a list of tuple of <instance, component>
const std::vector<std::tuple<std::string, std::string>>& getTestParameters() {
return getTestParameters(C2Component::DOMAIN_OTHER, C2Component::KIND_OTHER);
}
// Return all test parameters, a list of tuple of <instance, component> with matching domain and
// kind.
const std::vector<std::tuple<std::string, std::string>>& getTestParameters(
C2Component::domain_t domain, C2Component::kind_t kind) {
static std::vector<std::tuple<std::string, std::string>> parameters;
auto instances = android::Codec2Client::GetServiceNames();
for (std::string instance : instances) {
std::shared_ptr<android::Codec2Client> client =
android::Codec2Client::CreateFromService(instance.c_str());
std::vector<C2Component::Traits> components = client->listComponents();
for (C2Component::Traits traits : components) {
if (instance.compare(traits.owner)) continue;
if (domain != C2Component::DOMAIN_OTHER &&
(traits.domain != domain || traits.kind != kind)) {
continue;
}
parameters.push_back(std::make_tuple(instance, traits.name));
}
}
return parameters;
}

@ -22,31 +22,34 @@
#include <codec2/hidl/client.h> #include <codec2/hidl/client.h>
#include <getopt.h> #include <getopt.h>
#include <gtest/gtest.h>
#include <hidl/HidlSupport.h> #include <hidl/HidlSupport.h>
#include <VtsHalHidlTargetTestEnvBase.h> #include <chrono>
#define MAX_RETRY 20 #define MAX_RETRY 20
#define TIME_OUT 400ms #define TIME_OUT 400ms
#define MAX_INPUT_BUFFERS 8 #define MAX_INPUT_BUFFERS 8
using ::android::hardware::Void;
using ::android::hardware::Return;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string; using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using namespace ::std::chrono;
static std::vector<std::tuple<std::string, std::string>> kTestParameters;
/* /*
* Handle Callback functions onWorkDone(), onTripped(), * Handle Callback functions onWorkDone(), onTripped(),
* onError(), onDeath(), onFramesRendered() * onError(), onDeath(), onFramesRendered()
*/ */
struct CodecListener : public android::Codec2Client::Listener { struct CodecListener : public android::Codec2Client::Listener {
public: public:
CodecListener( CodecListener(
const std::function<void(std::list<std::unique_ptr<C2Work>>& workItems)> fn = const std::function<void(std::list<std::unique_ptr<C2Work>>& workItems)> fn = nullptr)
nullptr)
: callBack(fn) {} : callBack(fn) {}
virtual void onWorkDone( virtual void onWorkDone(const std::weak_ptr<android::Codec2Client::Component>& comp,
const std::weak_ptr<android::Codec2Client::Component>& comp, std::list<std::unique_ptr<C2Work>>& workItems) override {
std::list<std::unique_ptr<C2Work>>& workItems) override {
/* TODO */ /* TODO */
ALOGD("onWorkDone called"); ALOGD("onWorkDone called");
(void)comp; (void)comp;
@ -54,40 +57,34 @@ struct CodecListener : public android::Codec2Client::Listener {
} }
virtual void onTripped( virtual void onTripped(
const std::weak_ptr<android::Codec2Client::Component>& comp, const std::weak_ptr<android::Codec2Client::Component>& comp,
const std::vector<std::shared_ptr<C2SettingResult>>& settingResults) const std::vector<std::shared_ptr<C2SettingResult>>& settingResults) override {
override {
/* TODO */ /* TODO */
(void)comp; (void)comp;
(void)settingResults; (void)settingResults;
} }
virtual void onError( virtual void onError(const std::weak_ptr<android::Codec2Client::Component>& comp,
const std::weak_ptr<android::Codec2Client::Component>& comp, uint32_t errorCode) override {
uint32_t errorCode) override {
/* TODO */ /* TODO */
(void)comp; (void)comp;
ALOGD("onError called"); ALOGD("onError called");
if (errorCode != 0) ALOGE("Error : %u", errorCode); if (errorCode != 0) ALOGE("Error : %u", errorCode);
} }
virtual void onDeath( virtual void onDeath(const std::weak_ptr<android::Codec2Client::Component>& comp) override {
const std::weak_ptr<android::Codec2Client::Component>& comp) override {
/* TODO */ /* TODO */
(void)comp; (void)comp;
} }
virtual void onInputBufferDone( virtual void onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) override {
uint64_t frameIndex, size_t arrayIndex) override {
/* TODO */ /* TODO */
(void)frameIndex; (void)frameIndex;
(void)arrayIndex; (void)arrayIndex;
} }
virtual void onFrameRendered( virtual void onFrameRendered(uint64_t bufferQueueId, int32_t slotId,
uint64_t bufferQueueId, int64_t timestampNs) override {
int32_t slotId,
int64_t timestampNs) override {
/* TODO */ /* TODO */
(void)bufferQueueId; (void)bufferQueueId;
(void)slotId; (void)slotId;
@ -99,96 +96,30 @@ struct CodecListener : public android::Codec2Client::Listener {
std::function<void(std::list<std::unique_ptr<C2Work>>& workItems)> callBack; std::function<void(std::list<std::unique_ptr<C2Work>>& workItems)> callBack;
}; };
// A class for test environment setup // Return all test parameters, a list of tuple of <instance, component>.
class ComponentTestEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { const std::vector<std::tuple<std::string, std::string>>& getTestParameters();
private:
typedef ::testing::VtsHalHidlTargetTestEnvBase Super;
public:
virtual void registerTestServices() override;
ComponentTestEnvironment() : res("/data/local/tmp/media/") {}
void setComponent(const char* _component) { component = _component; }
void setInstance(const char* _instance) { instance = _instance; }
void setRes(const char* _res) { res = _res; }
const hidl_string getInstance() const { return instance; }
const hidl_string getComponent() const { return component; }
const hidl_string getRes() const { return res; }
int initFromOptions(int argc, char** argv) {
static struct option options[] = {
{"instance", required_argument, 0, 'I'},
{"component", required_argument, 0, 'C'},
{"res", required_argument, 0, 'P'},
{0, 0, 0, 0}};
while (true) {
int index = 0;
int c = getopt_long(argc, argv, "I:C:P:", options, &index);
if (c == -1) {
break;
}
switch (c) {
case 'I':
setInstance(optarg);
break;
case 'C':
setComponent(optarg);
break;
case 'P':
setRes(optarg);
break;
case '?':
break;
}
}
if (optind < argc) {
fprintf(stderr,
"unrecognized option: %s\n\n"
"usage: %s <gtest options> <test options>\n\n"
"test options are:\n\n"
"-I, --instance: software for C2 components, else default\n"
"-C, --component: C2 component to test\n"
"-P, --res: Resource files directory location\n",
argv[optind ?: 1], argv[0]);
return 2;
}
return 0;
}
private: // Return all test parameters, a list of tuple of <instance, component> with matching domain and
hidl_string instance; // kind.
hidl_string component; const std::vector<std::tuple<std::string, std::string>>& getTestParameters(
hidl_string res; C2Component::domain_t domain, C2Component::kind_t kind);
};
/* /*
* common functions declarations * common functions declarations
*/ */
void testInputBuffer( void testInputBuffer(const std::shared_ptr<android::Codec2Client::Component>& component,
const std::shared_ptr<android::Codec2Client::Component>& component, std::mutex& queueLock, std::list<std::unique_ptr<C2Work>>& workQueue,
std::mutex& queueLock, std::list<std::unique_ptr<C2Work>>& workQueue, uint32_t flags, bool isNullBuffer);
uint32_t flags, bool isNullBuffer);
void waitOnInputConsumption(std::mutex& queueLock, void waitOnInputConsumption(std::mutex& queueLock, std::condition_variable& queueCondition,
std::condition_variable& queueCondition,
std::list<std::unique_ptr<C2Work>>& workQueue, std::list<std::unique_ptr<C2Work>>& workQueue,
size_t bufferCount = MAX_INPUT_BUFFERS); size_t bufferCount = MAX_INPUT_BUFFERS);
void workDone( void workDone(const std::shared_ptr<android::Codec2Client::Component>& component,
const std::shared_ptr<android::Codec2Client::Component>& component, std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices,
std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices, std::mutex& queueLock, std::condition_variable& queueCondition,
std::mutex& queueLock, std::condition_variable& queueCondition, std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd, uint32_t& framesReceived);
uint32_t& framesReceived);
int64_t getNowUs(); int64_t getNowUs();

@ -19,11 +19,11 @@
#include <android-base/logging.h> #include <android-base/logging.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <C2Config.h> #include <C2Config.h>
#include <codec2/hidl/client.h> #include <codec2/hidl/client.h>
#include <VtsHalHidlTargetTestBase.h>
#include "media_c2_hidl_test_common.h" #include "media_c2_hidl_test_common.h"
/* Time_Out for start(), stop(), reset(), release(), flush(), queue() are /* Time_Out for start(), stop(), reset(), release(), flush(), queue() are
@ -31,50 +31,45 @@
* extra in case of timeout is 500ms, 1ms extra in case timeout is 1ms/5ms. All * extra in case of timeout is 500ms, 1ms extra in case timeout is 1ms/5ms. All
* timeout is calculated in us. * timeout is calculated in us.
*/ */
#define START_TIME_OUT 550000 #define START_TIME_OUT 550000
#define STOP_TIME_OUT 550000 #define STOP_TIME_OUT 550000
#define RESET_TIME_OUT 550000 #define RESET_TIME_OUT 550000
#define RELEASE_TIME_OUT 550000 #define RELEASE_TIME_OUT 550000
#define FLUSH_TIME_OUT 6000 #define FLUSH_TIME_OUT 6000
#define QUEUE_TIME_OUT 2000 #define QUEUE_TIME_OUT 2000
// Time_Out for config(), query(), querySupportedParams() are defined in // Time_Out for config(), query(), querySupportedParams() are defined in
// hardware/interfaces/media/c2/1.0/IConfigurable.hal. // hardware/interfaces/media/c2/1.0/IConfigurable.hal.
#define CONFIG_TIME_OUT 6000 #define CONFIG_TIME_OUT 6000
#define QUERY_TIME_OUT 6000 #define QUERY_TIME_OUT 6000
#define QUERYSUPPORTEDPARAMS_TIME_OUT 2000 #define QUERYSUPPORTEDPARAMS_TIME_OUT 2000
#define CHECK_TIMEOUT(timeConsumed, TIME_OUT, FuncName) \ #define CHECK_TIMEOUT(timeConsumed, TIME_OUT, FuncName) \
if (timeConsumed > TIME_OUT) { \ if (timeConsumed > TIME_OUT) { \
ALOGW( \ ALOGW("TIMED_OUT %s timeConsumed=%" PRId64 \
"TIMED_OUT %s timeConsumed=%" PRId64 " us is " \ " us is " \
"greater than threshold %d us", \ "greater than threshold %d us", \
FuncName, timeConsumed, TIME_OUT); \ FuncName, timeConsumed, TIME_OUT); \
} }
static ComponentTestEnvironment* gEnv = nullptr;
namespace { namespace {
// google.codec2 Component test setup static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
class Codec2ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase { kInputTestParameters;
private:
typedef ::testing::VtsHalHidlTargetTestBase Super;
public: // google.codec2 Component test setup
class Codec2ComponentHidlTestBase : public ::testing::Test {
public:
virtual void SetUp() override { virtual void SetUp() override {
Super::SetUp(); getParams();
mEos = false; mEos = false;
mClient = android::Codec2Client::CreateFromService( mClient = android::Codec2Client::CreateFromService(mInstanceName.c_str());
gEnv->getInstance().c_str());
ASSERT_NE(mClient, nullptr); ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener( mListener.reset(new CodecListener([this](std::list<std::unique_ptr<C2Work>>& workItems) {
[this](std::list<std::unique_ptr<C2Work>>& workItems) { handleWorkDone(workItems);
handleWorkDone(workItems); }));
}));
ASSERT_NE(mListener, nullptr); ASSERT_NE(mListener, nullptr);
mClient->createComponent(gEnv->getComponent().c_str(), mListener, mClient->createComponent(mComponentName.c_str(), mListener, &mComponent);
&mComponent);
ASSERT_NE(mComponent, nullptr); ASSERT_NE(mComponent, nullptr);
for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) { for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
mWorkQueue.emplace_back(new C2Work); mWorkQueue.emplace_back(new C2Work);
@ -90,8 +85,11 @@ class Codec2ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase {
mComponent->release(); mComponent->release();
mComponent = nullptr; mComponent = nullptr;
} }
Super::TearDown();
} }
// Get the test parameters from GetParam call.
virtual void getParams() {}
// callback function to process onWorkDone received by Listener // callback function to process onWorkDone received by Listener
void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) { void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
for (std::unique_ptr<C2Work>& work : workItems) { for (std::unique_ptr<C2Work>& work : workItems) {
@ -99,12 +97,14 @@ class Codec2ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase {
bool mCsd = false; bool mCsd = false;
uint32_t mFramesReceived = 0; uint32_t mFramesReceived = 0;
std::list<uint64_t> mFlushedIndices; std::list<uint64_t> mFlushedIndices;
workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
mWorkQueue, mEos, mCsd, mFramesReceived); mEos, mCsd, mFramesReceived);
} }
} }
} }
std::string mInstanceName;
std::string mComponentName;
bool mEos; bool mEos;
std::mutex mQueueLock; std::mutex mQueueLock;
std::condition_variable mQueueCondition; std::condition_variable mQueueCondition;
@ -114,14 +114,23 @@ class Codec2ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase {
std::shared_ptr<android::Codec2Client::Listener> mListener; std::shared_ptr<android::Codec2Client::Listener> mListener;
std::shared_ptr<android::Codec2Client::Component> mComponent; std::shared_ptr<android::Codec2Client::Component> mComponent;
protected: protected:
static void description(const std::string& description) { static void description(const std::string& description) {
RecordProperty("description", description); RecordProperty("description", description);
} }
}; };
class Codec2ComponentHidlTest
: public Codec2ComponentHidlTestBase,
public ::testing::WithParamInterface<std::tuple<std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
}
};
// Test Empty Flush // Test Empty Flush
TEST_F(Codec2ComponentHidlTest, EmptyFlush) { TEST_P(Codec2ComponentHidlTest, EmptyFlush) {
ALOGV("Empty Flush Test"); ALOGV("Empty Flush Test");
c2_status_t err = mComponent->start(); c2_status_t err = mComponent->start();
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
@ -137,7 +146,7 @@ TEST_F(Codec2ComponentHidlTest, EmptyFlush) {
} }
// Test Queue Empty Work // Test Queue Empty Work
TEST_F(Codec2ComponentHidlTest, QueueEmptyWork) { TEST_P(Codec2ComponentHidlTest, QueueEmptyWork) {
ALOGV("Queue Empty Work Test"); ALOGV("Queue Empty Work Test");
c2_status_t err = mComponent->start(); c2_status_t err = mComponent->start();
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
@ -151,7 +160,7 @@ TEST_F(Codec2ComponentHidlTest, QueueEmptyWork) {
} }
// Test Component Configuration // Test Component Configuration
TEST_F(Codec2ComponentHidlTest, Config) { TEST_P(Codec2ComponentHidlTest, Config) {
ALOGV("Configuration Test"); ALOGV("Configuration Test");
C2String name = mComponent->getName(); C2String name = mComponent->getName();
@ -180,7 +189,7 @@ TEST_F(Codec2ComponentHidlTest, Config) {
} }
// Test Multiple Start Stop Reset Test // Test Multiple Start Stop Reset Test
TEST_F(Codec2ComponentHidlTest, MultipleStartStopReset) { TEST_P(Codec2ComponentHidlTest, MultipleStartStopReset) {
ALOGV("Multiple Start Stop and Reset Test"); ALOGV("Multiple Start Stop and Reset Test");
for (size_t i = 0; i < MAX_RETRY; i++) { for (size_t i = 0; i < MAX_RETRY; i++) {
@ -202,21 +211,21 @@ TEST_F(Codec2ComponentHidlTest, MultipleStartStopReset) {
} }
// Test Component Release API // Test Component Release API
TEST_F(Codec2ComponentHidlTest, MultipleRelease) { TEST_P(Codec2ComponentHidlTest, MultipleRelease) {
ALOGV("Multiple Release Test"); ALOGV("Multiple Release Test");
c2_status_t err = mComponent->start(); c2_status_t err = mComponent->start();
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
// Query Component Domain Type // Query Component Domain Type
std::vector<std::unique_ptr<C2Param>> queried; std::vector<std::unique_ptr<C2Param>> queried;
err = mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, err = mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK,
C2_DONT_BLOCK, &queried); &queried);
EXPECT_NE(queried.size(), 0u); EXPECT_NE(queried.size(), 0u);
// Configure Component Domain // Configure Component Domain
std::vector<std::unique_ptr<C2SettingResult>> failures; std::vector<std::unique_ptr<C2SettingResult>> failures;
C2PortMediaTypeSetting::input* portMediaType = C2PortMediaTypeSetting::input* portMediaType =
C2PortMediaTypeSetting::input::From(queried[0].get()); C2PortMediaTypeSetting::input::From(queried[0].get());
err = mComponent->config({portMediaType}, C2_DONT_BLOCK, &failures); err = mComponent->config({portMediaType}, C2_DONT_BLOCK, &failures);
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
ASSERT_EQ(failures.size(), 0u); ASSERT_EQ(failures.size(), 0u);
@ -226,40 +235,8 @@ TEST_F(Codec2ComponentHidlTest, MultipleRelease) {
} }
} }
class Codec2ComponentInputTests : public Codec2ComponentHidlTest,
public ::testing::WithParamInterface<std::pair<uint32_t, bool> > {
};
TEST_P(Codec2ComponentInputTests, InputBufferTest) {
description("Tests for different inputs");
uint32_t flags = GetParam().first;
bool isNullBuffer = GetParam().second;
if (isNullBuffer) ALOGD("Testing for null input buffer with flag : %u", flags);
else ALOGD("Testing for empty input buffer with flag : %u", flags);
mEos = false;
ASSERT_EQ(mComponent->start(), C2_OK);
ASSERT_NO_FATAL_FAILURE(testInputBuffer(
mComponent, mQueueLock, mWorkQueue, flags, isNullBuffer));
ALOGD("Waiting for input consumption");
ASSERT_NO_FATAL_FAILURE(
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
if (flags == C2FrameData::FLAG_END_OF_STREAM) ASSERT_EQ(mEos, true);
ASSERT_EQ(mComponent->stop(), C2_OK);
ASSERT_EQ(mComponent->reset(), C2_OK);
}
INSTANTIATE_TEST_CASE_P(NonStdInputs, Codec2ComponentInputTests, ::testing::Values(
std::make_pair(0, true),
std::make_pair(C2FrameData::FLAG_END_OF_STREAM, true),
std::make_pair(0, false),
std::make_pair(C2FrameData::FLAG_CODEC_CONFIG, false),
std::make_pair(C2FrameData::FLAG_END_OF_STREAM, false)));
// Test API's Timeout // Test API's Timeout
TEST_F(Codec2ComponentHidlTest, Timeout) { TEST_P(Codec2ComponentHidlTest, Timeout) {
ALOGV("Timeout Test"); ALOGV("Timeout Test");
c2_status_t err = C2_OK; c2_status_t err = C2_OK;
@ -285,10 +262,8 @@ TEST_F(Codec2ComponentHidlTest, Timeout) {
startTime = getNowUs(); startTime = getNowUs();
err = mComponent->querySupportedParams(&params); err = mComponent->querySupportedParams(&params);
timeConsumed = getNowUs() - startTime; timeConsumed = getNowUs() - startTime;
CHECK_TIMEOUT(timeConsumed, QUERYSUPPORTEDPARAMS_TIME_OUT, CHECK_TIMEOUT(timeConsumed, QUERYSUPPORTEDPARAMS_TIME_OUT, "querySupportedParams()");
"querySupportedParams()"); ALOGV("mComponent->querySupportedParams() timeConsumed=%" PRId64 " us", timeConsumed);
ALOGV("mComponent->querySupportedParams() timeConsumed=%" PRId64 " us",
timeConsumed);
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
std::vector<std::unique_ptr<C2Param>> queried; std::vector<std::unique_ptr<C2Param>> queried;
@ -301,8 +276,8 @@ TEST_F(Codec2ComponentHidlTest, Timeout) {
CHECK_TIMEOUT(timeConsumed, QUERY_TIME_OUT, "query()"); CHECK_TIMEOUT(timeConsumed, QUERY_TIME_OUT, "query()");
EXPECT_NE(queried.size(), 0u); EXPECT_NE(queried.size(), 0u);
EXPECT_EQ(err, C2_OK); EXPECT_EQ(err, C2_OK);
ALOGV("mComponent->query() for %s timeConsumed=%" PRId64 " us", ALOGV("mComponent->query() for %s timeConsumed=%" PRId64 " us", p->name().c_str(),
p->name().c_str(), timeConsumed); timeConsumed);
startTime = getNowUs(); startTime = getNowUs();
err = mComponent->config({queried[0].get()}, C2_DONT_BLOCK, &failures); err = mComponent->config({queried[0].get()}, C2_DONT_BLOCK, &failures);
@ -310,8 +285,8 @@ TEST_F(Codec2ComponentHidlTest, Timeout) {
CHECK_TIMEOUT(timeConsumed, CONFIG_TIME_OUT, "config()"); CHECK_TIMEOUT(timeConsumed, CONFIG_TIME_OUT, "config()");
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
ASSERT_EQ(failures.size(), 0u); ASSERT_EQ(failures.size(), 0u);
ALOGV("mComponent->config() for %s timeConsumed=%" PRId64 " us", ALOGV("mComponent->config() for %s timeConsumed=%" PRId64 " us", p->name().c_str(),
p->name().c_str(), timeConsumed); timeConsumed);
} }
std::list<std::unique_ptr<C2Work>> workList; std::list<std::unique_ptr<C2Work>> workList;
@ -340,22 +315,68 @@ TEST_F(Codec2ComponentHidlTest, Timeout) {
ALOGV("mComponent->release() timeConsumed=%" PRId64 " us", timeConsumed); ALOGV("mComponent->release() timeConsumed=%" PRId64 " us", timeConsumed);
CHECK_TIMEOUT(timeConsumed, RELEASE_TIME_OUT, "release()"); CHECK_TIMEOUT(timeConsumed, RELEASE_TIME_OUT, "release()");
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
}
class Codec2ComponentInputTests
: public Codec2ComponentHidlTestBase,
public ::testing::WithParamInterface<
std::tuple<std::string, std::string, std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
}
};
TEST_P(Codec2ComponentInputTests, InputBufferTest) {
description("Tests for different inputs");
uint32_t flags = std::stol(std::get<2>(GetParam()));
bool isNullBuffer = !std::get<3>(GetParam()).compare("true");
if (isNullBuffer)
ALOGD("Testing for null input buffer with flag : %u", flags);
else
ALOGD("Testing for empty input buffer with flag : %u", flags);
mEos = false;
ASSERT_EQ(mComponent->start(), C2_OK);
ASSERT_NO_FATAL_FAILURE(
testInputBuffer(mComponent, mQueueLock, mWorkQueue, flags, isNullBuffer));
ALOGD("Waiting for input consumption");
ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
if (flags == C2FrameData::FLAG_END_OF_STREAM) ASSERT_EQ(mEos, true);
ASSERT_EQ(mComponent->stop(), C2_OK);
ASSERT_EQ(mComponent->reset(), C2_OK);
} }
INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2ComponentHidlTest, testing::ValuesIn(kTestParameters),
android::hardware::PrintInstanceTupleNameToString<>);
INSTANTIATE_TEST_CASE_P(NonStdInputs, Codec2ComponentInputTests,
testing::ValuesIn(kInputTestParameters),
android::hardware::PrintInstanceTupleNameToString<>);
} // anonymous namespace } // anonymous namespace
// TODO: Add test for Invalid work, // TODO: Add test for Invalid work,
// TODO: Add test for Invalid states // TODO: Add test for Invalid states
int main(int argc, char** argv) { int main(int argc, char** argv) {
gEnv = new ComponentTestEnvironment(); kTestParameters = getTestParameters();
::testing::AddGlobalTestEnvironment(gEnv); for (auto params : kTestParameters) {
::testing::InitGoogleTest(&argc, argv); kInputTestParameters.push_back(
gEnv->init(&argc, argv); std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "true"));
int status = gEnv->initFromOptions(argc, argv); kInputTestParameters.push_back(
if (status == 0) { std::make_tuple(std::get<0>(params), std::get<1>(params),
status = RUN_ALL_TESTS(); std::to_string(C2FrameData::FLAG_END_OF_STREAM), "true"));
LOG(INFO) << "C2 Test result = " << status; kInputTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "false"));
kInputTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params),
std::to_string(C2FrameData::FLAG_CODEC_CONFIG), "false"));
kInputTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params),
std::to_string(C2FrameData::FLAG_END_OF_STREAM), "false"));
} }
return status;
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
} }

@ -19,30 +19,25 @@
#include <android-base/logging.h> #include <android-base/logging.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
#include <codec2/hidl/client.h> #include <codec2/hidl/client.h>
#include <VtsHalHidlTargetTestBase.h> #include <VtsHalHidlTargetTestBase.h>
#include "media_c2_hidl_test_common.h" #include "media_c2_hidl_test_common.h"
static ComponentTestEnvironment* gEnv = nullptr;
namespace { namespace {
// google.codec2 Master test setup // google.codec2 Master test setup
class Codec2MasterHalTest : public ::testing::VtsHalHidlTargetTestBase { class Codec2MasterHalTest : public ::testing::TestWithParam<std::string> {
private: public:
typedef ::testing::VtsHalHidlTargetTestBase Super;
public:
virtual void SetUp() override { virtual void SetUp() override {
Super::SetUp(); mClient = android::Codec2Client::CreateFromService(GetParam().c_str());
mClient = android::Codec2Client::CreateFromService(
gEnv->getInstance().c_str());
ASSERT_NE(mClient, nullptr); ASSERT_NE(mClient, nullptr);
} }
protected: protected:
static void description(const std::string& description) { static void description(const std::string& description) {
RecordProperty("description", description); RecordProperty("description", description);
} }
@ -58,15 +53,14 @@ void displayComponentInfo(const std::vector<C2Component::Traits>& compList) {
} }
// List Components // List Components
TEST_F(Codec2MasterHalTest, ListComponents) { TEST_P(Codec2MasterHalTest, ListComponents) {
ALOGV("ListComponents Test"); ALOGV("ListComponents Test");
C2String name = mClient->getName(); C2String name = mClient->getName();
EXPECT_NE(name.empty(), true) << "Invalid Codec2Client Name"; EXPECT_NE(name.empty(), true) << "Invalid Codec2Client Name";
// Get List of components from all known services // Get List of components from all known services
const std::vector<C2Component::Traits> listTraits = const std::vector<C2Component::Traits> listTraits = mClient->ListComponents();
mClient->ListComponents();
if (listTraits.size() == 0) if (listTraits.size() == 0)
ALOGE("Warning, ComponentInfo list empty"); ALOGE("Warning, ComponentInfo list empty");
@ -79,24 +73,16 @@ TEST_F(Codec2MasterHalTest, ListComponents) {
ASSERT_NE(listener, nullptr); ASSERT_NE(listener, nullptr);
// Create component from all known services // Create component from all known services
component = mClient->CreateComponentByName( component =
listTraits[i].name.c_str(), listener, &mClient); mClient->CreateComponentByName(listTraits[i].name.c_str(), listener, &mClient);
ASSERT_NE(component, nullptr) << "Create component failed for " ASSERT_NE(component, nullptr)
<< listTraits[i].name.c_str(); << "Create component failed for " << listTraits[i].name.c_str();
} }
} }
} }
} // anonymous namespace } // anonymous namespace
int main(int argc, char** argv) { INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2MasterHalTest,
gEnv = new ComponentTestEnvironment(); testing::ValuesIn(android::Codec2Client::GetServiceNames()),
::testing::InitGoogleTest(&argc, argv); android::hardware::PrintInstanceNameToString);
gEnv->init(&argc, argv);
int status = gEnv->initFromOptions(argc, argv);
if (status == 0) {
status = RUN_ALL_TESTS();
LOG(INFO) << "C2 Test result = " << status;
}
return status;
}

@ -16,6 +16,7 @@
cc_test { cc_test {
name: "VtsHalMediaC2V1_0TargetVideoDecTest", name: "VtsHalMediaC2V1_0TargetVideoDecTest",
stem: "vts_media_c2_v1_0_video_dec_test",
defaults: ["VtsHalMediaC2V1_0Defaults"], defaults: ["VtsHalMediaC2V1_0Defaults"],
srcs: ["VtsHalMediaC2V1_0TargetVideoDecTest.cpp"], srcs: ["VtsHalMediaC2V1_0TargetVideoDecTest.cpp"],
header_libs: [ header_libs: [
@ -26,11 +27,16 @@ cc_test {
"libgui", "libgui",
"libutils", "libutils",
], ],
data: [":media_c2_v1_video_decode_res"],
test_config: "VtsHalMediaC2V1_0TargetVideoDecTest.xml",
} }
cc_test { cc_test {
name: "VtsHalMediaC2V1_0TargetVideoEncTest", name: "VtsHalMediaC2V1_0TargetVideoEncTest",
stem: "vts_media_c2_v1_0_video_enc_test",
defaults: ["VtsHalMediaC2V1_0Defaults"], defaults: ["VtsHalMediaC2V1_0Defaults"],
srcs: ["VtsHalMediaC2V1_0TargetVideoEncTest.cpp"], srcs: ["VtsHalMediaC2V1_0TargetVideoEncTest.cpp"],
data: [":media_c2_v1_video_encode_res"],
test_config: "VtsHalMediaC2V1_0TargetVideoEncTest.xml",
} }

@ -19,15 +19,16 @@
#include <android-base/logging.h> #include <android-base/logging.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <stdio.h> #include <stdio.h>
#include <fstream> #include <fstream>
#include <codec2/hidl/client.h>
#include <C2AllocatorIon.h> #include <C2AllocatorIon.h>
#include <C2Config.h>
#include <C2Debug.h>
#include <C2Buffer.h> #include <C2Buffer.h>
#include <C2BufferPriv.h> #include <C2BufferPriv.h>
#include <C2Config.h>
#include <C2Debug.h>
#include <codec2/hidl/client.h>
#include <gui/BufferQueue.h> #include <gui/BufferQueue.h>
#include <gui/IConsumerListener.h> #include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h> #include <gui/IProducerListener.h>
@ -35,9 +36,8 @@
using android::C2AllocatorIon; using android::C2AllocatorIon;
#include <VtsHalHidlTargetTestBase.h>
#include "media_c2_video_hidl_test_common.h"
#include "media_c2_hidl_test_common.h" #include "media_c2_hidl_test_common.h"
#include "media_c2_video_hidl_test_common.h"
struct FrameInfo { struct FrameInfo {
int bytesCount; int bytesCount;
@ -45,61 +45,47 @@ struct FrameInfo {
int64_t timestamp; int64_t timestamp;
}; };
static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
kDecodeTestParameters;
// Resource directory
static std::string sResourceDir = "";
class LinearBuffer : public C2Buffer { class LinearBuffer : public C2Buffer {
public: public:
explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block) explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
: C2Buffer( : C2Buffer({block->share(block->offset(), block->size(), ::C2Fence())}) {}
{block->share(block->offset(), block->size(), ::C2Fence())}) {}
explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block, size_t size) explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block, size_t size)
: C2Buffer( : C2Buffer({block->share(block->offset(), size, ::C2Fence())}) {}
{block->share(block->offset(), size, ::C2Fence())}) {}
}; };
static ComponentTestEnvironment* gEnv = nullptr;
namespace { namespace {
class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { class Codec2VideoDecHidlTestBase : public ::testing::Test {
private: public:
typedef ::testing::VtsHalHidlTargetTestBase Super;
public:
::std::string getTestCaseInfo() const override {
return ::std::string() +
"Component: " + gEnv->getComponent().c_str() + " | " +
"Instance: " + gEnv->getInstance().c_str() + " | " +
"Res: " + gEnv->getRes().c_str();
}
// google.codec2 Video test setup // google.codec2 Video test setup
virtual void SetUp() override { virtual void SetUp() override {
Super::SetUp(); getParams();
mDisableTest = false; mDisableTest = false;
ALOGV("Codec2VideoDecHidlTest SetUp"); ALOGV("Codec2VideoDecHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService( mClient = android::Codec2Client::CreateFromService(
gEnv->getInstance().c_str(), mInstanceName.c_str(),
!bool(android::Codec2Client::CreateFromService("default", true))); !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr); ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener( mListener.reset(new CodecListener([this](std::list<std::unique_ptr<C2Work>>& workItems) {
[this](std::list<std::unique_ptr<C2Work>>& workItems) { handleWorkDone(workItems);
handleWorkDone(workItems); }));
}));
ASSERT_NE(mListener, nullptr); ASSERT_NE(mListener, nullptr);
for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) { for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
mWorkQueue.emplace_back(new C2Work); mWorkQueue.emplace_back(new C2Work);
} }
mClient->createComponent(gEnv->getComponent().c_str(), mListener, mClient->createComponent(mComponentName, mListener, &mComponent);
&mComponent);
ASSERT_NE(mComponent, nullptr); ASSERT_NE(mComponent, nullptr);
std::shared_ptr<C2AllocatorStore> store = std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
android::GetCodec2PlatformAllocatorStore(); CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
&mLinearAllocator),
C2_OK);
mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator,
mBlockPoolId++);
ASSERT_NE(mLinearPool, nullptr); ASSERT_NE(mLinearPool, nullptr);
mCompName = unknown_comp; mCompName = unknown_comp;
@ -109,17 +95,15 @@ class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
}; };
const StringToName kStringToName[] = { const StringToName kStringToName[] = {
{"h263", h263}, {"avc", avc}, {"mpeg2", mpeg2}, {"mpeg4", mpeg4}, {"h263", h263}, {"avc", avc}, {"mpeg2", mpeg2}, {"mpeg4", mpeg4},
{"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9}, {"av1", av1}, {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9}, {"av1", av1},
}; };
const size_t kNumStringToName = const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]);
sizeof(kStringToName) / sizeof(kStringToName[0]);
// Find the component type // Find the component type
std::string comp = std::string(gEnv->getComponent());
for (size_t i = 0; i < kNumStringToName; ++i) { for (size_t i = 0; i < kNumStringToName; ++i) {
if (strcasestr(comp.c_str(), kStringToName[i].Name)) { if (strcasestr(mComponentName.c_str(), kStringToName[i].Name)) {
mCompName = kStringToName[i].CompName; mCompName = kStringToName[i].CompName;
break; break;
} }
@ -131,7 +115,7 @@ class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
if (mCompName == unknown_comp) mDisableTest = true; if (mCompName == unknown_comp) mDisableTest = true;
C2SecureModeTuning secureModeTuning{}; C2SecureModeTuning secureModeTuning{};
mComponent->query({ &secureModeTuning }, {}, C2_MAY_BLOCK, nullptr); mComponent->query({&secureModeTuning}, {}, C2_MAY_BLOCK, nullptr);
if (secureModeTuning.value == C2Config::SM_READ_PROTECTED) { if (secureModeTuning.value == C2Config::SM_READ_PROTECTED) {
mDisableTest = true; mDisableTest = true;
} }
@ -145,9 +129,11 @@ class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
mComponent->release(); mComponent->release();
mComponent = nullptr; mComponent = nullptr;
} }
Super::TearDown();
} }
// Get the test parameters from GetParam call.
virtual void getParams() {}
// callback function to process onWorkDone received by Listener // callback function to process onWorkDone received by Listener
void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) { void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
for (std::unique_ptr<C2Work>& work : workItems) { for (std::unique_ptr<C2Work>& work : workItems) {
@ -157,13 +143,10 @@ class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
bool codecConfig = ((work->worklets.front()->output.flags & bool codecConfig = ((work->worklets.front()->output.flags &
C2FrameData::FLAG_CODEC_CONFIG) != 0); C2FrameData::FLAG_CODEC_CONFIG) != 0);
if (!codecConfig && if (!codecConfig && !work->worklets.front()->output.buffers.empty()) {
!work->worklets.front()->output.buffers.empty()) { EXPECT_GE((work->worklets.front()->output.ordinal.timestamp.peeku()),
EXPECT_GE( mTimestampUs);
(work->worklets.front()->output.ordinal.timestamp.peeku()), mTimestampUs = work->worklets.front()->output.ordinal.timestamp.peeku();
mTimestampUs);
mTimestampUs =
work->worklets.front()->output.ordinal.timestamp.peeku();
ULock l(mQueueLock); ULock l(mQueueLock);
if (mTimestampDevTest) { if (mTimestampDevTest) {
@ -179,8 +162,7 @@ class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
} }
if (tsHit == false) { if (tsHit == false) {
if (mTimestampUslist.empty() == false) { if (mTimestampUslist.empty() == false) {
EXPECT_EQ(tsHit, true) EXPECT_EQ(tsHit, true) << "TimeStamp not recognized";
<< "TimeStamp not recognized";
} else { } else {
std::cout << "[ INFO ] Received non-zero " std::cout << "[ INFO ] Received non-zero "
"output / TimeStamp not recognized \n"; "output / TimeStamp not recognized \n";
@ -189,9 +171,8 @@ class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
} }
} }
bool mCsd; bool mCsd;
workDone(mComponent, work, mFlushedIndices, mQueueLock, workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
mQueueCondition, mWorkQueue, mEos, mCsd, mEos, mCsd, mFramesReceived);
mFramesReceived);
(void)mCsd; (void)mCsd;
} }
} }
@ -209,6 +190,9 @@ class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
unknown_comp, unknown_comp,
}; };
std::string mInstanceName;
std::string mComponentName;
bool mEos; bool mEos;
bool mDisableTest; bool mDisableTest;
bool mTimestampDevTest; bool mTimestampDevTest;
@ -229,15 +213,23 @@ class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
std::shared_ptr<android::Codec2Client::Listener> mListener; std::shared_ptr<android::Codec2Client::Listener> mListener;
std::shared_ptr<android::Codec2Client::Component> mComponent; std::shared_ptr<android::Codec2Client::Component> mComponent;
protected: protected:
static void description(const std::string& description) { static void description(const std::string& description) {
RecordProperty("description", description); RecordProperty("description", description);
} }
}; };
void validateComponent( class Codec2VideoDecHidlTest
const std::shared_ptr<android::Codec2Client::Component>& component, : public Codec2VideoDecHidlTestBase,
Codec2VideoDecHidlTest::standardComp compName, bool& disableTest) { public ::testing::WithParamInterface<std::tuple<std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
}
};
void validateComponent(const std::shared_ptr<android::Codec2Client::Component>& component,
Codec2VideoDecHidlTest::standardComp compName, bool& disableTest) {
// Validate its a C2 Component // Validate its a C2 Component
if (component->getName().find("c2") == std::string::npos) { if (component->getName().find("c2") == std::string::npos) {
ALOGE("Not a c2 component"); ALOGE("Not a c2 component");
@ -252,14 +244,12 @@ void validateComponent(
return; return;
} }
std::vector<std::unique_ptr<C2Param>> queried; std::vector<std::unique_ptr<C2Param>> queried;
c2_status_t c2err = c2_status_t c2err = component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK, &queried);
C2_DONT_BLOCK, &queried);
if (c2err != C2_OK && queried.size() == 0) { if (c2err != C2_OK && queried.size() == 0) {
ALOGE("Query media type failed => %d", c2err); ALOGE("Query media type failed => %d", c2err);
} else { } else {
std::string inputDomain = std::string inputDomain = ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
if (inputDomain.find("video/") == std::string::npos) { if (inputDomain.find("video/") == std::string::npos) {
ALOGE("Expected Video Component"); ALOGE("Expected Video Component");
disableTest = true; disableTest = true;
@ -279,8 +269,8 @@ void validateComponent(
// number of elementary streams per component // number of elementary streams per component
#define STREAM_COUNT 2 #define STREAM_COUNT 2
// LookUpTable of clips and metadata for component testing // LookUpTable of clips and metadata for component testing
void GetURLForComponent(Codec2VideoDecHidlTest::standardComp comp, char* mURL, void GetURLForComponent(Codec2VideoDecHidlTest::standardComp comp, char* mURL, char* info,
char* info, size_t streamIndex = 1) { size_t streamIndex = 1) {
struct CompToURL { struct CompToURL {
Codec2VideoDecHidlTest::standardComp comp; Codec2VideoDecHidlTest::standardComp comp;
const char mURL[STREAM_COUNT][512]; const char mURL[STREAM_COUNT][512];
@ -289,42 +279,30 @@ void GetURLForComponent(Codec2VideoDecHidlTest::standardComp comp, char* mURL,
ASSERT_TRUE(streamIndex < STREAM_COUNT); ASSERT_TRUE(streamIndex < STREAM_COUNT);
static const CompToURL kCompToURL[] = { static const CompToURL kCompToURL[] = {
{Codec2VideoDecHidlTest::standardComp::avc, {Codec2VideoDecHidlTest::standardComp::avc,
{"bbb_avc_176x144_300kbps_60fps.h264", {"bbb_avc_176x144_300kbps_60fps.h264", "bbb_avc_640x360_768kbps_30fps.h264"},
"bbb_avc_640x360_768kbps_30fps.h264"}, {"bbb_avc_176x144_300kbps_60fps.info", "bbb_avc_640x360_768kbps_30fps.info"}},
{"bbb_avc_176x144_300kbps_60fps.info", {Codec2VideoDecHidlTest::standardComp::hevc,
"bbb_avc_640x360_768kbps_30fps.info"}}, {"bbb_hevc_176x144_176kbps_60fps.hevc", "bbb_hevc_640x360_1600kbps_30fps.hevc"},
{Codec2VideoDecHidlTest::standardComp::hevc, {"bbb_hevc_176x144_176kbps_60fps.info", "bbb_hevc_640x360_1600kbps_30fps.info"}},
{"bbb_hevc_176x144_176kbps_60fps.hevc", {Codec2VideoDecHidlTest::standardComp::mpeg2,
"bbb_hevc_640x360_1600kbps_30fps.hevc"}, {"bbb_mpeg2_176x144_105kbps_25fps.m2v", "bbb_mpeg2_352x288_1mbps_60fps.m2v"},
{"bbb_hevc_176x144_176kbps_60fps.info", {"bbb_mpeg2_176x144_105kbps_25fps.info", "bbb_mpeg2_352x288_1mbps_60fps.info"}},
"bbb_hevc_640x360_1600kbps_30fps.info"}}, {Codec2VideoDecHidlTest::standardComp::h263,
{Codec2VideoDecHidlTest::standardComp::mpeg2, {"", "bbb_h263_352x288_300kbps_12fps.h263"},
{"bbb_mpeg2_176x144_105kbps_25fps.m2v", {"", "bbb_h263_352x288_300kbps_12fps.info"}},
"bbb_mpeg2_352x288_1mbps_60fps.m2v"}, {Codec2VideoDecHidlTest::standardComp::mpeg4,
{"bbb_mpeg2_176x144_105kbps_25fps.info", {"", "bbb_mpeg4_352x288_512kbps_30fps.m4v"},
"bbb_mpeg2_352x288_1mbps_60fps.info"}}, {"", "bbb_mpeg4_352x288_512kbps_30fps.info"}},
{Codec2VideoDecHidlTest::standardComp::h263, {Codec2VideoDecHidlTest::standardComp::vp8,
{"", "bbb_h263_352x288_300kbps_12fps.h263"}, {"bbb_vp8_176x144_240kbps_60fps.vp8", "bbb_vp8_640x360_2mbps_30fps.vp8"},
{"", "bbb_h263_352x288_300kbps_12fps.info"}}, {"bbb_vp8_176x144_240kbps_60fps.info", "bbb_vp8_640x360_2mbps_30fps.info"}},
{Codec2VideoDecHidlTest::standardComp::mpeg4, {Codec2VideoDecHidlTest::standardComp::vp9,
{"", "bbb_mpeg4_352x288_512kbps_30fps.m4v"}, {"bbb_vp9_176x144_285kbps_60fps.vp9", "bbb_vp9_640x360_1600kbps_30fps.vp9"},
{"", "bbb_mpeg4_352x288_512kbps_30fps.info"}}, {"bbb_vp9_176x144_285kbps_60fps.info", "bbb_vp9_640x360_1600kbps_30fps.info"}},
{Codec2VideoDecHidlTest::standardComp::vp8, {Codec2VideoDecHidlTest::standardComp::av1,
{"bbb_vp8_176x144_240kbps_60fps.vp8", {"bbb_av1_640_360.av1", "bbb_av1_176_144.av1"},
"bbb_vp8_640x360_2mbps_30fps.vp8"}, {"bbb_av1_640_360.info", "bbb_av1_176_144.info"}},
{"bbb_vp8_176x144_240kbps_60fps.info",
"bbb_vp8_640x360_2mbps_30fps.info"}},
{Codec2VideoDecHidlTest::standardComp::vp9,
{"bbb_vp9_176x144_285kbps_60fps.vp9",
"bbb_vp9_640x360_1600kbps_30fps.vp9"},
{"bbb_vp9_176x144_285kbps_60fps.info",
"bbb_vp9_640x360_1600kbps_30fps.info"}},
{Codec2VideoDecHidlTest::standardComp::av1,
{"bbb_av1_640_360.av1",
"bbb_av1_176_144.av1"},
{"bbb_av1_640_360.info",
"bbb_av1_176_144.info"}},
}; };
for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) { for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
@ -337,13 +315,11 @@ void GetURLForComponent(Codec2VideoDecHidlTest::standardComp comp, char* mURL,
} }
void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component, void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
std::mutex &queueLock, std::condition_variable& queueCondition, std::mutex& queueLock, std::condition_variable& queueCondition,
std::list<std::unique_ptr<C2Work>>& workQueue, std::list<std::unique_ptr<C2Work>>& workQueue,
std::list<uint64_t>& flushedIndices, std::list<uint64_t>& flushedIndices, std::shared_ptr<C2BlockPool>& linearPool,
std::shared_ptr<C2BlockPool>& linearPool, std::ifstream& eleStream, android::Vector<FrameInfo>* Info, int offset,
std::ifstream& eleStream, int range, bool signalEOS = true) {
android::Vector<FrameInfo>* Info,
int offset, int range, bool signalEOS = true) {
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
int frameID = offset; int frameID = offset;
int maxRetry = 0; int maxRetry = 0;
@ -367,8 +343,7 @@ void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
} }
int64_t timestamp = (*Info)[frameID].timestamp; int64_t timestamp = (*Info)[frameID].timestamp;
if ((*Info)[frameID].flags) flags = (1 << ((*Info)[frameID].flags - 1)); if ((*Info)[frameID].flags) flags = (1 << ((*Info)[frameID].flags - 1));
if (signalEOS && ((frameID == (int)Info->size() - 1) || if (signalEOS && ((frameID == (int)Info->size() - 1) || (frameID == (offset + range - 1))))
(frameID == (offset + range - 1))))
flags |= C2FrameData::FLAG_END_OF_STREAM; flags |= C2FrameData::FLAG_END_OF_STREAM;
work->input.flags = (C2FrameData::flags_t)flags; work->input.flags = (C2FrameData::flags_t)flags;
@ -390,10 +365,9 @@ void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
auto alignedSize = ALIGN(size, PAGE_SIZE); auto alignedSize = ALIGN(size, PAGE_SIZE);
if (size) { if (size) {
std::shared_ptr<C2LinearBlock> block; std::shared_ptr<C2LinearBlock> block;
ASSERT_EQ(C2_OK, ASSERT_EQ(C2_OK, linearPool->fetchLinearBlock(
linearPool->fetchLinearBlock( alignedSize,
alignedSize, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
&block));
ASSERT_TRUE(block); ASSERT_TRUE(block);
// Write View // Write View
@ -424,16 +398,16 @@ void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
} }
} }
TEST_F(Codec2VideoDecHidlTest, validateCompName) { TEST_P(Codec2VideoDecHidlTest, validateCompName) {
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
ALOGV("Checks if the given component is a valid video component"); ALOGV("Checks if the given component is a valid video component");
validateComponent(mComponent, mCompName, mDisableTest); validateComponent(mComponent, mCompName, mDisableTest);
ASSERT_EQ(mDisableTest, false); ASSERT_EQ(mDisableTest, false);
} }
TEST_F(Codec2VideoDecHidlTest, configureTunnel) { TEST_P(Codec2VideoDecHidlTest, configureTunnel) {
description("Attempts to configure tunneling"); description("Attempts to configure tunneling");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
ALOGV("Checks if the component can be configured for tunneling"); ALOGV("Checks if the component can be configured for tunneling");
native_handle_t* sidebandStream{}; native_handle_t* sidebandStream{};
c2_status_t err = mComponent->configureVideoTunnel(0, &sidebandStream); c2_status_t err = mComponent->configureVideoTunnel(0, &sidebandStream);
@ -449,7 +423,7 @@ TEST_F(Codec2VideoDecHidlTest, configureTunnel) {
BufferQueue::createBufferQueue(&producer, &consumer); BufferQueue::createBufferQueue(&producer, &consumer);
class DummyConsumerListener : public BnConsumerListener { class DummyConsumerListener : public BnConsumerListener {
public: public:
DummyConsumerListener() : BnConsumerListener() {} DummyConsumerListener() : BnConsumerListener() {}
void onFrameAvailable(const BufferItem&) override {} void onFrameAvailable(const BufferItem&) override {}
void onBuffersReleased() override {} void onBuffersReleased() override {}
@ -458,37 +432,39 @@ TEST_F(Codec2VideoDecHidlTest, configureTunnel) {
consumer->consumerConnect(new DummyConsumerListener(), false); consumer->consumerConnect(new DummyConsumerListener(), false);
class DummyProducerListener : public BnProducerListener { class DummyProducerListener : public BnProducerListener {
public: public:
DummyProducerListener() : BnProducerListener() {} DummyProducerListener() : BnProducerListener() {}
virtual void onBufferReleased() override {} virtual void onBufferReleased() override {}
virtual bool needsReleaseNotify() override { return false; } virtual bool needsReleaseNotify() override { return false; }
virtual void onBuffersDiscarded(const std::vector<int32_t>&) override {} virtual void onBuffersDiscarded(const std::vector<int32_t>&) override {}
}; };
IGraphicBufferProducer::QueueBufferOutput qbo{}; IGraphicBufferProducer::QueueBufferOutput qbo{};
producer->connect(new DummyProducerListener(), producer->connect(new DummyProducerListener(), NATIVE_WINDOW_API_MEDIA, false, &qbo);
NATIVE_WINDOW_API_MEDIA,
false,
&qbo);
ASSERT_EQ(producer->setSidebandStream(nativeHandle), NO_ERROR); ASSERT_EQ(producer->setSidebandStream(nativeHandle), NO_ERROR);
} }
class Codec2VideoDecDecodeTest class Codec2VideoDecDecodeTest
: public Codec2VideoDecHidlTest, : public Codec2VideoDecHidlTestBase,
public ::testing::WithParamInterface<std::pair<int32_t, bool>> { public ::testing::WithParamInterface<
std::tuple<std::string, std::string, std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
}
}; };
// Bitstream Test // Bitstream Test
TEST_P(Codec2VideoDecDecodeTest, DecodeTest) { TEST_P(Codec2VideoDecDecodeTest, DecodeTest) {
description("Decodes input file"); description("Decodes input file");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
uint32_t streamIndex = GetParam().first; uint32_t streamIndex = std::stoi(std::get<2>(GetParam()));
bool signalEOS = GetParam().second; bool signalEOS = !std::get<2>(GetParam()).compare("true");
char mURL[512], info[512]; char mURL[512], info[512];
std::ifstream eleStream, eleInfo; std::ifstream eleStream, eleInfo;
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
strcpy(info, gEnv->getRes().c_str()); strcpy(info, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL, info, streamIndex); GetURLForComponent(mCompName, mURL, info, streamIndex);
eleInfo.open(info); eleInfo.open(info);
@ -504,10 +480,8 @@ TEST_P(Codec2VideoDecDecodeTest, DecodeTest) {
if (!(eleInfo >> bytesCount)) break; if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags; eleInfo >> flags;
eleInfo >> timestamp; eleInfo >> timestamp;
bool codecConfig = flags ? bool codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0; if (mTimestampDevTest && !codecConfig) mTimestampUslist.push_back(timestamp);
if (mTimestampDevTest && !codecConfig)
mTimestampUslist.push_back(timestamp);
Info.push_back({bytesCount, flags, timestamp}); Info.push_back({bytesCount, flags, timestamp});
} }
eleInfo.close(); eleInfo.close();
@ -519,52 +493,42 @@ TEST_P(Codec2VideoDecDecodeTest, DecodeTest) {
ALOGV("mURL : %s", mURL); ALOGV("mURL : %s", mURL);
eleStream.open(mURL, std::ifstream::binary); eleStream.open(mURL, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true); ASSERT_EQ(eleStream.is_open(), true);
ASSERT_NO_FATAL_FAILURE(decodeNFrames( ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mFlushedIndices, mLinearPool, eleStream, &Info, 0,
mLinearPool, eleStream, &Info, 0, (int)Info.size(), signalEOS)); (int)Info.size(), signalEOS));
// If EOS is not sent, sending empty input with EOS flag // If EOS is not sent, sending empty input with EOS flag
size_t infoSize = Info.size(); size_t infoSize = Info.size();
if (!signalEOS) { if (!signalEOS) {
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1)); ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
ASSERT_NO_FATAL_FAILURE( C2FrameData::FLAG_END_OF_STREAM, false));
testInputBuffer(mComponent, mQueueLock, mWorkQueue,
C2FrameData::FLAG_END_OF_STREAM, false));
infoSize += 1; infoSize += 1;
} }
// blocking call to ensures application to Wait till all the inputs are // blocking call to ensures application to Wait till all the inputs are
// consumed // consumed
if (!mEos) { if (!mEos) {
ALOGV("Waiting for input consumption"); ALOGV("Waiting for input consumption");
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
} }
eleStream.close(); eleStream.close();
if (mFramesReceived != infoSize) { if (mFramesReceived != infoSize) {
ALOGE("Input buffer count and Output buffer count mismatch"); ALOGE("Input buffer count and Output buffer count mismatch");
ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, infoSize);
infoSize);
ASSERT_TRUE(false); ASSERT_TRUE(false);
} }
if (mTimestampDevTest) EXPECT_EQ(mTimestampUslist.empty(), true); if (mTimestampDevTest) EXPECT_EQ(mTimestampUslist.empty(), true);
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
// DecodeTest with StreamIndex and EOS / No EOS
INSTANTIATE_TEST_CASE_P(StreamIndexAndEOS, Codec2VideoDecDecodeTest,
::testing::Values(std::make_pair(0, false),
std::make_pair(0, true),
std::make_pair(1, false),
std::make_pair(1, true)));
// Adaptive Test // Adaptive Test
TEST_F(Codec2VideoDecHidlTest, AdaptiveDecodeTest) { TEST_P(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
description("Adaptive Decode Test"); description("Adaptive Decode Test");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
if (!(mCompName == avc || mCompName == hevc || mCompName == vp8 || if (!(mCompName == avc || mCompName == hevc || mCompName == vp8 || mCompName == vp9 ||
mCompName == vp9 || mCompName == mpeg2)) mCompName == mpeg2))
return; return;
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
@ -578,8 +542,8 @@ TEST_F(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
char mURL[512], info[512]; char mURL[512], info[512];
std::ifstream eleStream, eleInfo; std::ifstream eleStream, eleInfo;
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
strcpy(info, gEnv->getRes().c_str()); strcpy(info, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL, info, i % STREAM_COUNT); GetURLForComponent(mCompName, mURL, info, i % STREAM_COUNT);
eleInfo.open(info); eleInfo.open(info);
@ -594,13 +558,12 @@ TEST_F(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
eleInfo >> timestamp; eleInfo >> timestamp;
timestamp += timestampOffset; timestamp += timestampOffset;
Info.push_back({bytesCount, flags, timestamp}); Info.push_back({bytesCount, flags, timestamp});
bool codecConfig = flags ? bool codecConfig =
((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0; flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
{ {
ULock l(mQueueLock); ULock l(mQueueLock);
if (mTimestampDevTest && !codecConfig) if (mTimestampDevTest && !codecConfig) mTimestampUslist.push_back(timestamp);
mTimestampUslist.push_back(timestamp);
} }
if (timestampMax < timestamp) timestampMax = timestamp; if (timestampMax < timestamp) timestampMax = timestamp;
} }
@ -612,10 +575,9 @@ TEST_F(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
ALOGV("mURL : %s", mURL); ALOGV("mURL : %s", mURL);
eleStream.open(mURL, std::ifstream::binary); eleStream.open(mURL, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true); ASSERT_EQ(eleStream.is_open(), true);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mLinearPool, eleStream, &Info,
mFlushedIndices, mLinearPool, eleStream, &Info, offset, (int)(Info.size() - offset), false));
offset, (int)(Info.size() - offset), false));
eleStream.close(); eleStream.close();
offset = (int)Info.size(); offset = (int)Info.size();
@ -650,13 +612,11 @@ TEST_F(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
// blocking call to ensures application to Wait till all the inputs are // blocking call to ensures application to Wait till all the inputs are
// consumed // consumed
ALOGV("Waiting for input consumption"); ALOGV("Waiting for input consumption");
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
if (mFramesReceived != ((Info.size()) + 1)) { if (mFramesReceived != ((Info.size()) + 1)) {
ALOGE("Input buffer count and Output buffer count mismatch"); ALOGE("Input buffer count and Output buffer count mismatch");
ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, Info.size() + 1);
Info.size() + 1);
ASSERT_TRUE(false); ASSERT_TRUE(false);
} }
@ -664,15 +624,15 @@ TEST_F(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
} }
// thumbnail test // thumbnail test
TEST_F(Codec2VideoDecHidlTest, ThumbnailTest) { TEST_P(Codec2VideoDecHidlTest, ThumbnailTest) {
description("Test Request for thumbnail"); description("Test Request for thumbnail");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
char mURL[512], info[512]; char mURL[512], info[512];
std::ifstream eleStream, eleInfo; std::ifstream eleStream, eleInfo;
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
strcpy(info, gEnv->getRes().c_str()); strcpy(info, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL, info); GetURLForComponent(mCompName, mURL, info);
eleInfo.open(info); eleInfo.open(info);
@ -703,11 +663,10 @@ TEST_F(Codec2VideoDecHidlTest, ThumbnailTest) {
} while (!(flags & SYNC_FRAME)); } while (!(flags & SYNC_FRAME));
eleStream.open(mURL, std::ifstream::binary); eleStream.open(mURL, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true); ASSERT_EQ(eleStream.is_open(), true);
ASSERT_NO_FATAL_FAILURE(decodeNFrames( ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mLinearPool, eleStream, &Info, 0,
mFlushedIndices, mLinearPool, eleStream, &Info, 0, j + 1)); j + 1));
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
eleStream.close(); eleStream.close();
EXPECT_GE(mFramesReceived, 1U); EXPECT_GE(mFramesReceived, 1U);
ASSERT_EQ(mEos, true); ASSERT_EQ(mEos, true);
@ -716,9 +675,9 @@ TEST_F(Codec2VideoDecHidlTest, ThumbnailTest) {
ASSERT_EQ(mComponent->release(), C2_OK); ASSERT_EQ(mComponent->release(), C2_OK);
} }
TEST_F(Codec2VideoDecHidlTest, EOSTest) { TEST_P(Codec2VideoDecHidlTest, EOSTest) {
description("Test empty input buffer with EOS flag"); description("Test empty input buffer with EOS flag");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
ASSERT_EQ(mComponent->start(), C2_OK); ASSERT_EQ(mComponent->start(), C2_OK);
std::unique_ptr<C2Work> work; std::unique_ptr<C2Work> work;
@ -756,16 +715,16 @@ TEST_F(Codec2VideoDecHidlTest, EOSTest) {
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
TEST_F(Codec2VideoDecHidlTest, FlushTest) { TEST_P(Codec2VideoDecHidlTest, FlushTest) {
description("Tests Flush calls"); description("Tests Flush calls");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
ASSERT_EQ(mComponent->start(), C2_OK); ASSERT_EQ(mComponent->start(), C2_OK);
char mURL[512], info[512]; char mURL[512], info[512];
std::ifstream eleStream, eleInfo; std::ifstream eleStream, eleInfo;
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
strcpy(info, gEnv->getRes().c_str()); strcpy(info, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL, info); GetURLForComponent(mCompName, mURL, info);
eleInfo.open(info); eleInfo.open(info);
@ -790,28 +749,24 @@ TEST_F(Codec2VideoDecHidlTest, FlushTest) {
// frame after this so that the below section can be covered for all // frame after this so that the below section can be covered for all
// components // components
uint32_t numFramesFlushed = 128; uint32_t numFramesFlushed = 128;
ASSERT_NO_FATAL_FAILURE(decodeNFrames( ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mFlushedIndices, mLinearPool, eleStream, &Info, 0,
mLinearPool, eleStream, &Info, 0, numFramesFlushed, false)); numFramesFlushed, false));
// flush // flush
std::list<std::unique_ptr<C2Work>> flushedWork; std::list<std::unique_ptr<C2Work>> flushedWork;
c2_status_t err = c2_status_t err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
(size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
{ {
// Update mFlushedIndices based on the index received from flush() // Update mFlushedIndices based on the index received from flush()
ULock l(mQueueLock); ULock l(mQueueLock);
for (std::unique_ptr<C2Work>& work : flushedWork) { for (std::unique_ptr<C2Work>& work : flushedWork) {
ASSERT_NE(work, nullptr); ASSERT_NE(work, nullptr);
auto frameIndexIt = auto frameIndexIt = std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
std::find(mFlushedIndices.begin(), mFlushedIndices.end(), work->input.ordinal.frameIndex.peeku());
work->input.ordinal.frameIndex.peeku()); if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
if (!mFlushedIndices.empty() &&
(frameIndexIt != mFlushedIndices.end())) {
mFlushedIndices.erase(frameIndexIt); mFlushedIndices.erase(frameIndexIt);
work->input.buffers.clear(); work->input.buffers.clear();
work->worklets.clear(); work->worklets.clear();
@ -835,27 +790,24 @@ TEST_F(Codec2VideoDecHidlTest, FlushTest) {
index++; index++;
} }
if (keyFrame) { if (keyFrame) {
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mLinearPool, eleStream, &Info, index,
mFlushedIndices, mLinearPool, eleStream, &Info, index, (int)Info.size() - index));
(int)Info.size() - index));
} }
eleStream.close(); eleStream.close();
err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork); err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
(size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
{ {
// Update mFlushedIndices based on the index received from flush() // Update mFlushedIndices based on the index received from flush()
ULock l(mQueueLock); ULock l(mQueueLock);
for (std::unique_ptr<C2Work>& work : flushedWork) { for (std::unique_ptr<C2Work>& work : flushedWork) {
ASSERT_NE(work, nullptr); ASSERT_NE(work, nullptr);
uint64_t frameIndex = work->input.ordinal.frameIndex.peeku(); uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
std::list<uint64_t>::iterator frameIndexIt = std::find( std::list<uint64_t>::iterator frameIndexIt =
mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex); std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
if (!mFlushedIndices.empty() && if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
(frameIndexIt != mFlushedIndices.end())) {
mFlushedIndices.erase(frameIndexIt); mFlushedIndices.erase(frameIndexIt);
work->input.buffers.clear(); work->input.buffers.clear();
work->worklets.clear(); work->worklets.clear();
@ -867,15 +819,15 @@ TEST_F(Codec2VideoDecHidlTest, FlushTest) {
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
TEST_F(Codec2VideoDecHidlTest, DecodeTestEmptyBuffersInserted) { TEST_P(Codec2VideoDecHidlTest, DecodeTestEmptyBuffersInserted) {
description("Decode with multiple empty input frames"); description("Decode with multiple empty input frames");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
char mURL[512], info[512]; char mURL[512], info[512];
std::ifstream eleStream, eleInfo; std::ifstream eleStream, eleInfo;
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
strcpy(info, gEnv->getRes().c_str()); strcpy(info, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL, info); GetURLForComponent(mCompName, mURL, info);
eleInfo.open(info); eleInfo.open(info);
@ -890,15 +842,16 @@ TEST_F(Codec2VideoDecHidlTest, DecodeTestEmptyBuffersInserted) {
// and empty input frames at an interval of 5 frames. // and empty input frames at an interval of 5 frames.
while (1) { while (1) {
if (!(frameId % 5)) { if (!(frameId % 5)) {
if (!(frameId % 20)) flags = 32; if (!(frameId % 20))
else flags = 0; flags = 32;
else
flags = 0;
bytesCount = 0; bytesCount = 0;
} else { } else {
if (!(eleInfo >> bytesCount)) break; if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags; eleInfo >> flags;
eleInfo >> timestamp; eleInfo >> timestamp;
codecConfig = flags ? codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
} }
Info.push_back({bytesCount, flags, timestamp}); Info.push_back({bytesCount, flags, timestamp});
frameId++; frameId++;
@ -909,39 +862,58 @@ TEST_F(Codec2VideoDecHidlTest, DecodeTestEmptyBuffersInserted) {
ALOGV("mURL : %s", mURL); ALOGV("mURL : %s", mURL);
eleStream.open(mURL, std::ifstream::binary); eleStream.open(mURL, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true); ASSERT_EQ(eleStream.is_open(), true);
ASSERT_NO_FATAL_FAILURE(decodeNFrames( ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mFlushedIndices, mLinearPool, eleStream, &Info, 0,
mLinearPool, eleStream, &Info, 0, (int)Info.size())); (int)Info.size()));
// blocking call to ensures application to Wait till all the inputs are // blocking call to ensures application to Wait till all the inputs are
// consumed // consumed
if (!mEos) { if (!mEos) {
ALOGV("Waiting for input consumption"); ALOGV("Waiting for input consumption");
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
} }
eleStream.close(); eleStream.close();
if (mFramesReceived != Info.size()) { if (mFramesReceived != Info.size()) {
ALOGE("Input buffer count and Output buffer count mismatch"); ALOGE("Input buffer count and Output buffer count mismatch");
ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, Info.size());
Info.size());
ASSERT_TRUE(false); ASSERT_TRUE(false);
} }
} }
INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2VideoDecHidlTest, testing::ValuesIn(kTestParameters),
android::hardware::PrintInstanceTupleNameToString<>);
// DecodeTest with StreamIndex and EOS / No EOS
INSTANTIATE_TEST_SUITE_P(StreamIndexAndEOS, Codec2VideoDecDecodeTest,
testing::ValuesIn(kDecodeTestParameters),
android::hardware::PrintInstanceTupleNameToString<>);
} // anonymous namespace } // anonymous namespace
// TODO : Video specific configuration Test // TODO : Video specific configuration Test
int main(int argc, char** argv) { int main(int argc, char** argv) {
gEnv = new ComponentTestEnvironment(); kTestParameters = getTestParameters(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER);
::testing::AddGlobalTestEnvironment(gEnv); for (auto params : kTestParameters) {
::testing::InitGoogleTest(&argc, argv); kDecodeTestParameters.push_back(
gEnv->init(&argc, argv); std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "false"));
int status = gEnv->initFromOptions(argc, argv); kDecodeTestParameters.push_back(
if (status == 0) { std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "true"));
int status = RUN_ALL_TESTS(); kDecodeTestParameters.push_back(
LOG(INFO) << "C2 Test result = " << status; std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "false"));
kDecodeTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "true"));
}
// Set the resource directory based on command line args.
// Test will fail to set up if the argument is not set.
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-P") == 0 && i < argc - 1) {
sResourceDir = argv[i + 1];
break;
}
} }
return status;
} ::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 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.
-->
<configuration description="Runs VtsHalMediaC2V1_0TargetVideoDecTest.">
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push-file" key="vts_media_c2_v1_0_video_dec_test" value="/data/local/tmp/vts_media_c2_v1_0_video_dec_test" />
<!-- Files used for video testing -->
<option name="push-file" key="bbb_avc_176x144_300kbps_60fps.h264" value="/data/local/tmp/media/bbb_avc_176x144_300kbps_60fps.h264" />
<option name="push-file" key="bbb_avc_640x360_768kbps_30fps.h264" value="/data/local/tmp/media/bbb_avc_640x360_768kbps_30fps.h264" />
<option name="push-file" key="bbb_avc_176x144_300kbps_60fps.info" value="/data/local/tmp/media/bbb_avc_176x144_300kbps_60fps.info" />
<option name="push-file" key="bbb_avc_640x360_768kbps_30fps.info" value="/data/local/tmp/media/bbb_avc_640x360_768kbps_30fps.info" />
<option name="push-file" key="bbb_hevc_176x144_176kbps_60fps.hevc" value="/data/local/tmp/media/bbb_hevc_176x144_176kbps_60fps.hevc" />
<option name="push-file" key="bbb_hevc_640x360_1600kbps_30fps.hevc" value="/data/local/tmp/media/bbb_hevc_640x360_1600kbps_30fps.hevc" />
<option name="push-file" key="bbb_hevc_176x144_176kbps_60fps.info" value="/data/local/tmp/media/bbb_hevc_176x144_176kbps_60fps.info" />
<option name="push-file" key="bbb_hevc_640x360_1600kbps_30fps.info" value="/data/local/tmp/media/bbb_hevc_640x360_1600kbps_30fps.info" />
<option name="push-file" key="bbb_mpeg2_176x144_105kbps_25fps.m2v" value="/data/local/tmp/media/bbb_mpeg2_176x144_105kbps_25fps.m2v" />
<option name="push-file" key="bbb_mpeg2_352x288_1mbps_60fps.m2v" value="/data/local/tmp/media/bbb_mpeg2_352x288_1mbps_60fps.m2v" />
<option name="push-file" key="bbb_mpeg2_176x144_105kbps_25fps.info" value="/data/local/tmp/media/bbb_mpeg2_176x144_105kbps_25fps.info" />
<option name="push-file" key="bbb_mpeg2_352x288_1mbps_60fps.info" value="/data/local/tmp/media/bbb_mpeg2_352x288_1mbps_60fps.info" />
<option name="push-file" key="bbb_h263_352x288_300kbps_12fps.h263" value="/data/local/tmp/media/bbb_h263_352x288_300kbps_12fps.h263" />
<option name="push-file" key="bbb_h263_352x288_300kbps_12fps.info" value="/data/local/tmp/media/bbb_h263_352x288_300kbps_12fps.info" />
<option name="push-file" key="bbb_mpeg4_352x288_512kbps_30fps.m4v" value="/data/local/tmp/media/bbb_mpeg4_352x288_512kbps_30fps.m4v" />
<option name="push-file" key="bbb_mpeg4_352x288_512kbps_30fps.info" value="/data/local/tmp/media/bbb_mpeg4_352x288_512kbps_30fps.info" />
<option name="push-file" key="bbb_vp8_176x144_240kbps_60fps.vp8" value="/data/local/tmp/media/bbb_vp8_176x144_240kbps_60fps.vp8" />
<option name="push-file" key="bbb_vp8_640x360_2mbps_30fps.vp8" value="/data/local/tmp/media/bbb_vp8_640x360_2mbps_30fps.vp8" />
<option name="push-file" key="bbb_vp8_176x144_240kbps_60fps.info" value="/data/local/tmp/media/bbb_vp8_176x144_240kbps_60fps.info" />
<option name="push-file" key="bbb_vp8_640x360_2mbps_30fps.info" value="/data/local/tmp/media/bbb_vp8_640x360_2mbps_30fps.info" />
<option name="push-file" key="bbb_vp9_176x144_285kbps_60fps.vp9" value="/data/local/tmp/media/bbb_vp9_176x144_285kbps_60fps.vp9" />
<option name="push-file" key="bbb_vp9_640x360_1600kbps_30fps.vp9" value="/data/local/tmp/media/bbb_vp9_640x360_1600kbps_30fps.vp9" />
<option name="push-file" key="bbb_vp9_176x144_285kbps_60fps.info" value="/data/local/tmp/media/bbb_vp9_176x144_285kbps_60fps.info" />
<option name="push-file" key="bbb_vp9_640x360_1600kbps_30fps.info" value="/data/local/tmp/media/bbb_vp9_640x360_1600kbps_30fps.info" />
<option name="push-file" key="bbb_av1_640_360.av1" value="/data/local/tmp/media/bbb_av1_640_360.av1" />
<option name="push-file" key="bbb_av1_176_144.av1" value="/data/local/tmp/media/bbb_av1_176_144.av1" />
<option name="push-file" key="bbb_av1_640_360.info" value="/data/local/tmp/media/bbb_av1_640_360.info" />
<option name="push-file" key="bbb_av1_176_144.info" value="/data/local/tmp/media/bbb_av1_176_144.info" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="vts_media_c2_v1_0_video_dec_test" />
<option name="native-test-flag" value="-P /data/local/tmp/media/" />
</test>
</configuration>

@ -19,73 +19,62 @@
#include <android-base/logging.h> #include <android-base/logging.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <stdio.h> #include <stdio.h>
#include <fstream> #include <fstream>
#include <codec2/hidl/client.h>
#include <C2AllocatorIon.h> #include <C2AllocatorIon.h>
#include <C2Config.h>
#include <C2Debug.h>
#include <C2Buffer.h> #include <C2Buffer.h>
#include <C2BufferPriv.h> #include <C2BufferPriv.h>
#include <C2Config.h>
#include <C2Debug.h>
#include <codec2/hidl/client.h>
using android::C2AllocatorIon; using android::C2AllocatorIon;
#include <VtsHalHidlTargetTestBase.h>
#include "media_c2_video_hidl_test_common.h"
#include "media_c2_hidl_test_common.h" #include "media_c2_hidl_test_common.h"
#include "media_c2_video_hidl_test_common.h"
class GraphicBuffer : public C2Buffer { class GraphicBuffer : public C2Buffer {
public: public:
explicit GraphicBuffer(const std::shared_ptr<C2GraphicBlock> &block) explicit GraphicBuffer(const std::shared_ptr<C2GraphicBlock>& block)
: C2Buffer({block->share(C2Rect(block->width(), block->height()), : C2Buffer({block->share(C2Rect(block->width(), block->height()), ::C2Fence())}) {}
::C2Fence())}) {}
}; };
static ComponentTestEnvironment* gEnv = nullptr; static std::vector<std::tuple<std::string, std::string, std::string>> kEncodeTestParameters;
static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
kEncodeResolutionTestParameters;
namespace { // Resource directory
static std::string sResourceDir = "";
class Codec2VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
private:
typedef ::testing::VtsHalHidlTargetTestBase Super;
public: namespace {
::std::string getTestCaseInfo() const override {
return ::std::string() +
"Component: " + gEnv->getComponent().c_str() + " | " +
"Instance: " + gEnv->getInstance().c_str() + " | " +
"Res: " + gEnv->getRes().c_str();
}
class Codec2VideoEncHidlTestBase : public ::testing::Test {
public:
// google.codec2 Video test setup // google.codec2 Video test setup
virtual void SetUp() override { virtual void SetUp() override {
Super::SetUp(); getParams();
mDisableTest = false; mDisableTest = false;
ALOGV("Codec2VideoEncHidlTest SetUp"); ALOGV("Codec2VideoEncHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService( mClient = android::Codec2Client::CreateFromService(
gEnv->getInstance().c_str(), mInstanceName.c_str(),
!bool(android::Codec2Client::CreateFromService("default", true))); !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr); ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener( mListener.reset(new CodecListener([this](std::list<std::unique_ptr<C2Work>>& workItems) {
[this](std::list<std::unique_ptr<C2Work>>& workItems) { handleWorkDone(workItems);
handleWorkDone(workItems); }));
}));
ASSERT_NE(mListener, nullptr); ASSERT_NE(mListener, nullptr);
for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) { for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
mWorkQueue.emplace_back(new C2Work); mWorkQueue.emplace_back(new C2Work);
} }
mClient->createComponent(gEnv->getComponent().c_str(), mListener, mClient->createComponent(mComponentName, mListener, &mComponent);
&mComponent);
ASSERT_NE(mComponent, nullptr); ASSERT_NE(mComponent, nullptr);
std::shared_ptr<C2AllocatorStore> store = std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
android::GetCodec2PlatformAllocatorStore(); CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &mGraphicAllocator),
CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC,
&mGraphicAllocator),
C2_OK); C2_OK);
mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator, mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator, mBlockPoolId++);
mBlockPoolId++);
ASSERT_NE(mGraphicPool, nullptr); ASSERT_NE(mGraphicPool, nullptr);
mCompName = unknown_comp; mCompName = unknown_comp;
@ -95,17 +84,15 @@ class Codec2VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
}; };
const StringToName kStringToName[] = { const StringToName kStringToName[] = {
{"h263", h263}, {"avc", avc}, {"mpeg4", mpeg4}, {"h263", h263}, {"avc", avc}, {"mpeg4", mpeg4},
{"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9}, {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9},
}; };
const size_t kNumStringToName = const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]);
sizeof(kStringToName) / sizeof(kStringToName[0]);
// Find the component type // Find the component type
std::string comp = std::string(gEnv->getComponent());
for (size_t i = 0; i < kNumStringToName; ++i) { for (size_t i = 0; i < kNumStringToName; ++i) {
if (strcasestr(comp.c_str(), kStringToName[i].Name)) { if (strcasestr(mComponentName.c_str(), kStringToName[i].Name)) {
mCompName = kStringToName[i].CompName; mCompName = kStringToName[i].CompName;
break; break;
} }
@ -126,9 +113,11 @@ class Codec2VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
mComponent->release(); mComponent->release();
mComponent = nullptr; mComponent = nullptr;
} }
Super::TearDown();
} }
// Get the test parameters from GetParam call.
virtual void getParams() {}
bool setupConfigParam(int32_t nWidth, int32_t nHeight); bool setupConfigParam(int32_t nWidth, int32_t nHeight);
// callback function to process onWorkDone received by Listener // callback function to process onWorkDone received by Listener
@ -139,11 +128,9 @@ class Codec2VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
// previous timestamp // previous timestamp
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
if (!mTimestampUslist.empty()) { if (!mTimestampUslist.empty()) {
EXPECT_GE((work->worklets.front() EXPECT_GE((work->worklets.front()->output.ordinal.timestamp.peeku()),
->output.ordinal.timestamp.peeku()),
mTimestampUs); mTimestampUs);
mTimestampUs = work->worklets.front() mTimestampUs = work->worklets.front()->output.ordinal.timestamp.peeku();
->output.ordinal.timestamp.peeku();
// Currently this lock is redundant as no mTimestampUslist is only initialized // Currently this lock is redundant as no mTimestampUslist is only initialized
// before queuing any work to component. Once AdaptiveTest is added similar to // before queuing any work to component. Once AdaptiveTest is added similar to
// the one in video decoders, this is needed. // the one in video decoders, this is needed.
@ -151,8 +138,7 @@ class Codec2VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
if (mTimestampDevTest) { if (mTimestampDevTest) {
bool tsHit = false; bool tsHit = false;
std::list<uint64_t>::iterator it = std::list<uint64_t>::iterator it = mTimestampUslist.begin();
mTimestampUslist.begin();
while (it != mTimestampUslist.end()) { while (it != mTimestampUslist.end()) {
if (*it == mTimestampUs) { if (*it == mTimestampUs) {
mTimestampUslist.erase(it); mTimestampUslist.erase(it);
@ -163,21 +149,18 @@ class Codec2VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
} }
if (tsHit == false) { if (tsHit == false) {
if (mTimestampUslist.empty() == false) { if (mTimestampUslist.empty() == false) {
EXPECT_EQ(tsHit, true) EXPECT_EQ(tsHit, true) << "TimeStamp not recognized";
<< "TimeStamp not recognized";
} else { } else {
std::cout std::cout << "[ INFO ] Received non-zero "
<< "[ INFO ] Received non-zero " "output / TimeStamp not recognized \n";
"output / TimeStamp not recognized \n";
} }
} }
} }
} }
if (work->result != C2_OK) mFailedWorkReceived++; if (work->result != C2_OK) mFailedWorkReceived++;
workDone(mComponent, work, mFlushedIndices, mQueueLock, workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
mQueueCondition, mWorkQueue, mEos, mCsd, mEos, mCsd, mFramesReceived);
mFramesReceived);
} }
} }
} }
@ -192,6 +175,8 @@ class Codec2VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
unknown_comp, unknown_comp,
}; };
std::string mInstanceName;
std::string mComponentName;
bool mEos; bool mEos;
bool mCsd; bool mCsd;
bool mDisableTest; bool mDisableTest;
@ -217,15 +202,23 @@ class Codec2VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
std::shared_ptr<android::Codec2Client::Listener> mListener; std::shared_ptr<android::Codec2Client::Listener> mListener;
std::shared_ptr<android::Codec2Client::Component> mComponent; std::shared_ptr<android::Codec2Client::Component> mComponent;
protected: protected:
static void description(const std::string& description) { static void description(const std::string& description) {
RecordProperty("description", description); RecordProperty("description", description);
} }
}; };
void validateComponent( class Codec2VideoEncHidlTest
const std::shared_ptr<android::Codec2Client::Component>& component, : public Codec2VideoEncHidlTestBase,
Codec2VideoEncHidlTest::standardComp compName, bool& disableTest) { public ::testing::WithParamInterface<std::tuple<std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
}
};
void validateComponent(const std::shared_ptr<android::Codec2Client::Component>& component,
Codec2VideoEncHidlTest::standardComp compName, bool& disableTest) {
// Validate its a C2 Component // Validate its a C2 Component
if (component->getName().find("c2") == std::string::npos) { if (component->getName().find("c2") == std::string::npos) {
ALOGE("Not a c2 component"); ALOGE("Not a c2 component");
@ -240,14 +233,12 @@ void validateComponent(
return; return;
} }
std::vector<std::unique_ptr<C2Param>> queried; std::vector<std::unique_ptr<C2Param>> queried;
c2_status_t c2err = c2_status_t c2err = component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK, &queried);
C2_DONT_BLOCK, &queried);
if (c2err != C2_OK && queried.size() == 0) { if (c2err != C2_OK && queried.size() == 0) {
ALOGE("Query media type failed => %d", c2err); ALOGE("Query media type failed => %d", c2err);
} else { } else {
std::string inputDomain = std::string inputDomain = ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
if (inputDomain.find("video/") == std::string::npos) { if (inputDomain.find("video/") == std::string::npos) {
ALOGE("Expected Video Component"); ALOGE("Expected Video Component");
disableTest = true; disableTest = true;
@ -265,12 +256,11 @@ void validateComponent(
} }
// Set Default config param. // Set Default config param.
bool Codec2VideoEncHidlTest::setupConfigParam(int32_t nWidth, int32_t nHeight) { bool Codec2VideoEncHidlTestBase::setupConfigParam(int32_t nWidth, int32_t nHeight) {
std::vector<std::unique_ptr<C2SettingResult>> failures; std::vector<std::unique_ptr<C2SettingResult>> failures;
C2StreamPictureSizeInfo::input inputSize(0u, nWidth, nHeight); C2StreamPictureSizeInfo::input inputSize(0u, nWidth, nHeight);
std::vector<C2Param*> configParam{&inputSize}; std::vector<C2Param*> configParam{&inputSize};
c2_status_t status = c2_status_t status = mComponent->config(configParam, C2_DONT_BLOCK, &failures);
mComponent->config(configParam, C2_DONT_BLOCK, &failures);
if (status == C2_OK && failures.size() == 0u) return true; if (status == C2_OK && failures.size() == 0u) return true;
return false; return false;
} }
@ -281,13 +271,11 @@ void GetURLForComponent(char* URL) {
} }
void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component, void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
std::mutex &queueLock, std::condition_variable& queueCondition, std::mutex& queueLock, std::condition_variable& queueCondition,
std::list<std::unique_ptr<C2Work>>& workQueue, std::list<std::unique_ptr<C2Work>>& workQueue,
std::list<uint64_t>& flushedIndices, std::list<uint64_t>& flushedIndices, std::shared_ptr<C2BlockPool>& graphicPool,
std::shared_ptr<C2BlockPool>& graphicPool, std::ifstream& eleStream, bool& disableTest, uint32_t frameID, uint32_t nFrames,
std::ifstream& eleStream, bool& disableTest, uint32_t nWidth, int32_t nHeight, bool flushed = false, bool signalEOS = true) {
uint32_t frameID, uint32_t nFrames, uint32_t nWidth,
int32_t nHeight, bool flushed = false, bool signalEOS = true) {
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
uint32_t maxRetry = 0; uint32_t maxRetry = 0;
@ -313,8 +301,7 @@ void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
if (!work && (maxRetry >= MAX_RETRY)) { if (!work && (maxRetry >= MAX_RETRY)) {
ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout"; ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout";
} }
if (signalEOS && (nFrames == 1)) if (signalEOS && (nFrames == 1)) flags |= C2FrameData::FLAG_END_OF_STREAM;
flags |= C2FrameData::FLAG_END_OF_STREAM;
if (flushed) { if (flushed) {
flags |= SYNC_FRAME; flags |= SYNC_FRAME;
flushed = false; flushed = false;
@ -335,9 +322,9 @@ void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
ASSERT_EQ(eleStream.gcount(), bytesCount); ASSERT_EQ(eleStream.gcount(), bytesCount);
} }
std::shared_ptr<C2GraphicBlock> block; std::shared_ptr<C2GraphicBlock> block;
err = graphicPool->fetchGraphicBlock( err = graphicPool->fetchGraphicBlock(nWidth, nHeight, HAL_PIXEL_FORMAT_YV12,
nWidth, nHeight, HAL_PIXEL_FORMAT_YV12, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
{C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block); &block);
if (err != C2_OK) { if (err != C2_OK) {
fprintf(stderr, "fetchGraphicBlock failed : %d\n", err); fprintf(stderr, "fetchGraphicBlock failed : %d\n", err);
disableTest = true; disableTest = true;
@ -380,27 +367,32 @@ void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& comp
} }
} }
TEST_F(Codec2VideoEncHidlTest, validateCompName) { TEST_P(Codec2VideoEncHidlTest, validateCompName) {
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
ALOGV("Checks if the given component is a valid video component"); ALOGV("Checks if the given component is a valid video component");
validateComponent(mComponent, mCompName, mDisableTest); validateComponent(mComponent, mCompName, mDisableTest);
ASSERT_EQ(mDisableTest, false); ASSERT_EQ(mDisableTest, false);
} }
class Codec2VideoEncEncodeTest : public Codec2VideoEncHidlTest, class Codec2VideoEncEncodeTest
public ::testing::WithParamInterface<bool> { : public Codec2VideoEncHidlTestBase,
public ::testing::WithParamInterface<std::tuple<std::string, std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
}
}; };
TEST_P(Codec2VideoEncEncodeTest, EncodeTest) { TEST_P(Codec2VideoEncEncodeTest, EncodeTest) {
description("Encodes input file"); description("Encodes input file");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
char mURL[512]; char mURL[512];
int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH; int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH;
int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT; int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
bool signalEOS = GetParam(); bool signalEOS = !std::get<2>(GetParam()).compare("true");
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
GetURLForComponent(mURL); GetURLForComponent(mURL);
std::ifstream eleStream; std::ifstream eleStream;
@ -425,10 +417,9 @@ TEST_P(Codec2VideoEncEncodeTest, EncodeTest) {
return; return;
} }
ASSERT_EQ(mComponent->start(), C2_OK); ASSERT_EQ(mComponent->start(), C2_OK);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 0,
mFlushedIndices, mGraphicPool, eleStream, mDisableTest, ENC_NUM_FRAMES, nWidth, nHeight, false, signalEOS));
0, ENC_NUM_FRAMES, nWidth, nHeight, false, signalEOS));
// mDisableTest will be set if buffer was not fetched properly. // mDisableTest will be set if buffer was not fetched properly.
// This may happen when resolution is not proper but config suceeded // This may happen when resolution is not proper but config suceeded
// In this cases, we skip encoding the input stream // In this cases, we skip encoding the input stream
@ -441,25 +432,21 @@ TEST_P(Codec2VideoEncEncodeTest, EncodeTest) {
// If EOS is not sent, sending empty input with EOS flag // If EOS is not sent, sending empty input with EOS flag
inputFrames = ENC_NUM_FRAMES; inputFrames = ENC_NUM_FRAMES;
if (!signalEOS) { if (!signalEOS) {
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1)); ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
ASSERT_NO_FATAL_FAILURE( C2FrameData::FLAG_END_OF_STREAM, false));
testInputBuffer(mComponent, mQueueLock, mWorkQueue,
C2FrameData::FLAG_END_OF_STREAM, false));
inputFrames += 1; inputFrames += 1;
} }
// blocking call to ensures application to Wait till all the inputs are // blocking call to ensures application to Wait till all the inputs are
// consumed // consumed
ALOGD("Waiting for input consumption"); ALOGD("Waiting for input consumption");
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
eleStream.close(); eleStream.close();
if (mFramesReceived != inputFrames) { if (mFramesReceived != inputFrames) {
ALOGE("Input buffer count and Output buffer count mismatch"); ALOGE("Input buffer count and Output buffer count mismatch");
ALOGE("framesReceived : %d inputFrames : %d", mFramesReceived, ALOGE("framesReceived : %d inputFrames : %d", mFramesReceived, inputFrames);
inputFrames);
ASSERT_TRUE(false); ASSERT_TRUE(false);
} }
@ -475,13 +462,9 @@ TEST_P(Codec2VideoEncEncodeTest, EncodeTest) {
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
// EncodeTest with EOS / No EOS TEST_P(Codec2VideoEncHidlTest, EOSTest) {
INSTANTIATE_TEST_CASE_P(EncodeTestwithEOS, Codec2VideoEncEncodeTest,
::testing::Values(true, false));
TEST_F(Codec2VideoEncHidlTest, EOSTest) {
description("Test empty input buffer with EOS flag"); description("Test empty input buffer with EOS flag");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
ASSERT_EQ(mComponent->start(), C2_OK); ASSERT_EQ(mComponent->start(), C2_OK);
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
@ -519,15 +502,15 @@ TEST_F(Codec2VideoEncHidlTest, EOSTest) {
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
TEST_F(Codec2VideoEncHidlTest, FlushTest) { TEST_P(Codec2VideoEncHidlTest, FlushTest) {
description("Test Request for flush"); description("Test Request for flush");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
typedef std::unique_lock<std::mutex> ULock; typedef std::unique_lock<std::mutex> ULock;
char mURL[512]; char mURL[512];
int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH; int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH;
int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT; int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
strcpy(mURL, gEnv->getRes().c_str()); strcpy(mURL, sResourceDir.c_str());
GetURLForComponent(mURL); GetURLForComponent(mURL);
if (!setupConfigParam(nWidth, nHeight)) { if (!setupConfigParam(nWidth, nHeight)) {
@ -544,10 +527,9 @@ TEST_F(Codec2VideoEncHidlTest, FlushTest) {
eleStream.open(mURL, std::ifstream::binary); eleStream.open(mURL, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true); ASSERT_EQ(eleStream.is_open(), true);
ALOGV("mURL : %s", mURL); ALOGV("mURL : %s", mURL);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 0,
mFlushedIndices, mGraphicPool, eleStream, mDisableTest, numFramesFlushed, nWidth, nHeight));
0, numFramesFlushed, nWidth, nHeight));
// mDisableTest will be set if buffer was not fetched properly. // mDisableTest will be set if buffer was not fetched properly.
// This may happen when resolution is not proper but config suceeded // This may happen when resolution is not proper but config suceeded
// In this cases, we skip encoding the input stream // In this cases, we skip encoding the input stream
@ -558,23 +540,20 @@ TEST_F(Codec2VideoEncHidlTest, FlushTest) {
} }
std::list<std::unique_ptr<C2Work>> flushedWork; std::list<std::unique_ptr<C2Work>> flushedWork;
c2_status_t err = c2_status_t err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
(size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
uint64_t frameIndex; uint64_t frameIndex;
{ {
//Update mFlushedIndices based on the index received from flush() // Update mFlushedIndices based on the index received from flush()
ULock l(mQueueLock); ULock l(mQueueLock);
for (std::unique_ptr<C2Work>& work : flushedWork) { for (std::unique_ptr<C2Work>& work : flushedWork) {
ASSERT_NE(work, nullptr); ASSERT_NE(work, nullptr);
frameIndex = work->input.ordinal.frameIndex.peeku(); frameIndex = work->input.ordinal.frameIndex.peeku();
std::list<uint64_t>::iterator frameIndexIt = std::find( std::list<uint64_t>::iterator frameIndexIt =
mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex); std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
if (!mFlushedIndices.empty() && if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
(frameIndexIt != mFlushedIndices.end())) {
mFlushedIndices.erase(frameIndexIt); mFlushedIndices.erase(frameIndexIt);
work->input.buffers.clear(); work->input.buffers.clear();
work->worklets.clear(); work->worklets.clear();
@ -583,11 +562,10 @@ TEST_F(Codec2VideoEncHidlTest, FlushTest) {
} }
} }
mFlushedIndices.clear(); mFlushedIndices.clear();
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
mFlushedIndices, mGraphicPool, eleStream, mDisableTest, numFramesFlushed, numFrames - numFramesFlushed, nWidth,
numFramesFlushed, numFrames - numFramesFlushed, nHeight, true));
nWidth, nHeight, true));
eleStream.close(); eleStream.close();
// mDisableTest will be set if buffer was not fetched properly. // mDisableTest will be set if buffer was not fetched properly.
// This may happen when resolution is not proper but config suceeded // This may happen when resolution is not proper but config suceeded
@ -600,19 +578,17 @@ TEST_F(Codec2VideoEncHidlTest, FlushTest) {
err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork); err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
ASSERT_EQ(err, C2_OK); ASSERT_EQ(err, C2_OK);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
(size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
{ {
//Update mFlushedIndices based on the index received from flush() // Update mFlushedIndices based on the index received from flush()
ULock l(mQueueLock); ULock l(mQueueLock);
for (std::unique_ptr<C2Work>& work : flushedWork) { for (std::unique_ptr<C2Work>& work : flushedWork) {
ASSERT_NE(work, nullptr); ASSERT_NE(work, nullptr);
frameIndex = work->input.ordinal.frameIndex.peeku(); frameIndex = work->input.ordinal.frameIndex.peeku();
std::list<uint64_t>::iterator frameIndexIt = std::find( std::list<uint64_t>::iterator frameIndexIt =
mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex); std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
if (!mFlushedIndices.empty() && if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
(frameIndexIt != mFlushedIndices.end())) {
mFlushedIndices.erase(frameIndexIt); mFlushedIndices.erase(frameIndexIt);
work->input.buffers.clear(); work->input.buffers.clear();
work->worklets.clear(); work->worklets.clear();
@ -624,9 +600,9 @@ TEST_F(Codec2VideoEncHidlTest, FlushTest) {
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
TEST_F(Codec2VideoEncHidlTest, InvalidBufferTest) { TEST_P(Codec2VideoEncHidlTest, InvalidBufferTest) {
description("Tests feeding larger/smaller input buffer"); description("Tests feeding larger/smaller input buffer");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
std::ifstream eleStream; std::ifstream eleStream;
int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH / 2; int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH / 2;
@ -638,28 +614,24 @@ TEST_F(Codec2VideoEncHidlTest, InvalidBufferTest) {
} }
ASSERT_EQ(mComponent->start(), C2_OK); ASSERT_EQ(mComponent->start(), C2_OK);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 0,
mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 1, nWidth, nHeight, false, false));
0, 1, nWidth, nHeight, false, false));
// Feed larger input buffer. // Feed larger input buffer.
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 1,
mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 1, nWidth * 2, nHeight * 2, false, false));
1, 1, nWidth*2, nHeight*2, false, false));
// Feed smaller input buffer. // Feed smaller input buffer.
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 2,
mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 1, nWidth / 2, nHeight / 2, false, true));
2, 1, nWidth/2, nHeight/2, false, true));
// blocking call to ensures application to Wait till all the inputs are // blocking call to ensures application to Wait till all the inputs are
// consumed // consumed
ALOGD("Waiting for input consumption"); ALOGD("Waiting for input consumption");
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
if (mFramesReceived != 3) { if (mFramesReceived != 3) {
std::cout << "[ WARN ] Component didn't receive all buffers back \n"; std::cout << "[ WARN ] Component didn't receive all buffers back \n";
@ -674,17 +646,23 @@ TEST_F(Codec2VideoEncHidlTest, InvalidBufferTest) {
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
} }
class Codec2VideoEncResolutionTest : public Codec2VideoEncHidlTest, class Codec2VideoEncResolutionTest
public ::testing::WithParamInterface<std::pair<int32_t, int32_t> > { : public Codec2VideoEncHidlTestBase,
public ::testing::WithParamInterface<
std::tuple<std::string, std::string, std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
}
}; };
TEST_P(Codec2VideoEncResolutionTest, ResolutionTest) { TEST_P(Codec2VideoEncResolutionTest, ResolutionTest) {
description("Tests encoding at different resolutions"); description("Tests encoding at different resolutions");
if (mDisableTest) return; if (mDisableTest) GTEST_SKIP() << "Test is disabled";
std::ifstream eleStream; std::ifstream eleStream;
int32_t nWidth = GetParam().first; int32_t nWidth = std::stoi(std::get<2>(GetParam()));
int32_t nHeight = GetParam().second; int32_t nHeight = std::stoi(std::get<3>(GetParam()));
ALOGD("Trying encode for width %d height %d", nWidth, nHeight); ALOGD("Trying encode for width %d height %d", nWidth, nHeight);
mEos = false; mEos = false;
@ -694,10 +672,9 @@ TEST_P(Codec2VideoEncResolutionTest, ResolutionTest) {
} }
ASSERT_EQ(mComponent->start(), C2_OK); ASSERT_EQ(mComponent->start(), C2_OK);
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 0,
mFlushedIndices, mGraphicPool, eleStream, mDisableTest, MAX_INPUT_BUFFERS, nWidth, nHeight, false, true));
0, MAX_INPUT_BUFFERS, nWidth, nHeight, false, true));
// mDisableTest will be set if buffer was not fetched properly. // mDisableTest will be set if buffer was not fetched properly.
// This may happen when resolution is not proper but config suceeded // This may happen when resolution is not proper but config suceeded
@ -709,31 +686,52 @@ TEST_P(Codec2VideoEncResolutionTest, ResolutionTest) {
} }
ALOGD("Waiting for input consumption"); ALOGD("Waiting for input consumption");
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
ASSERT_EQ(mEos, true); ASSERT_EQ(mEos, true);
ASSERT_EQ(mComponent->stop(), C2_OK); ASSERT_EQ(mComponent->stop(), C2_OK);
ASSERT_EQ(mComponent->reset(), C2_OK); ASSERT_EQ(mComponent->reset(), C2_OK);
} }
INSTANTIATE_TEST_CASE_P(NonStdSizes, Codec2VideoEncResolutionTest, ::testing::Values( INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2VideoEncHidlTest, testing::ValuesIn(kTestParameters),
std::make_pair(52, 18), android::hardware::PrintInstanceTupleNameToString<>);
std::make_pair(365, 365),
std::make_pair(484, 362), INSTANTIATE_TEST_SUITE_P(NonStdSizes, Codec2VideoEncResolutionTest,
std::make_pair(244, 488))); ::testing::ValuesIn(kEncodeResolutionTestParameters));
// EncodeTest with EOS / No EOS
INSTANTIATE_TEST_SUITE_P(EncodeTestwithEOS, Codec2VideoEncEncodeTest,
::testing::ValuesIn(kEncodeTestParameters));
} // anonymous namespace } // anonymous namespace
int main(int argc, char** argv) { int main(int argc, char** argv) {
gEnv = new ComponentTestEnvironment(); kTestParameters = getTestParameters(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER);
::testing::AddGlobalTestEnvironment(gEnv); for (auto params : kTestParameters) {
::testing::InitGoogleTest(&argc, argv); kEncodeTestParameters.push_back(
gEnv->init(&argc, argv); std::make_tuple(std::get<0>(params), std::get<1>(params), "true"));
int status = gEnv->initFromOptions(argc, argv); kEncodeTestParameters.push_back(
if (status == 0) { std::make_tuple(std::get<0>(params), std::get<1>(params), "false"));
int status = RUN_ALL_TESTS();
LOG(INFO) << "C2 Test result = " << status; kEncodeResolutionTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params), "52", "18"));
kEncodeResolutionTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params), "365", "365"));
kEncodeResolutionTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params), "484", "362"));
kEncodeResolutionTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params), "244", "488"));
} }
return status;
} // Set the resource directory based on command line args.
// Test will fail to set up if the argument is not set.
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-P") == 0 && i < argc - 1) {
sResourceDir = argv[i + 1];
break;
}
}
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 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.
-->
<configuration description="Runs VtsHalMediaC2V1_0TargetVideoEncTest.">
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push-file" key="vts_media_c2_v1_0_video_enc_test" value="/data/local/tmp/vts_media_c2_v1_0_video_enc_test" />
<!-- Files used for video testing -->
<option name="push-file" key="bbb_352x288_420p_30fps_32frames.yuv" value="/data/local/tmp/media/bbb_352x288_420p_30fps_32frames.yuv" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="vts_media_c2_v1_0_video_enc_test" />
<option name="native-test-flag" value="-P /data/local/tmp/media/" />
</test>
</configuration>

@ -29,5 +29,4 @@
* Common video utils * Common video utils
*/ */
#endif // MEDIA_C2_VIDEO_HIDL_TEST_COMMON_H #endif // MEDIA_C2_VIDEO_HIDL_TEST_COMMON_H

Loading…
Cancel
Save