mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge branch 4.x
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
// Copyright (C) 2020-2022 Intel Corporation
|
||||
|
||||
#include "gapi_ocv_stateful_kernel_test_utils.hpp"
|
||||
#include <opencv2/gapi/cpu/core.hpp>
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <opencv2/video.hpp>
|
||||
#endif
|
||||
|
||||
#include <memory> // required by std::shared_ptr
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
@@ -21,6 +22,11 @@ namespace opencv_test
|
||||
{
|
||||
std::string method;
|
||||
};
|
||||
|
||||
struct CountStateSetupsParams
|
||||
{
|
||||
std::shared_ptr<int> pSetupsCount;
|
||||
};
|
||||
} // namespace opencv_test
|
||||
|
||||
namespace cv
|
||||
@@ -34,6 +40,14 @@ namespace cv
|
||||
return "org.opencv.test.background_substractor_state_params";
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct CompileArgTag<opencv_test::CountStateSetupsParams>
|
||||
{
|
||||
static const char* tag()
|
||||
{
|
||||
return "org.opencv.test.count_state_setups_params";
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
@@ -127,8 +141,101 @@ namespace
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
G_TYPED_KERNEL(GCountStateSetups, <cv::GOpaque<bool>(GMat)>,
|
||||
"org.opencv.test.count_state_setups")
|
||||
{
|
||||
static GOpaqueDesc outMeta(GMatDesc /* in */) { return empty_gopaque_desc(); }
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL_ST(GOCVCountStateSetups, GCountStateSetups, int)
|
||||
{
|
||||
static void setup(const cv::GMatDesc &, std::shared_ptr<int> &,
|
||||
const cv::GCompileArgs &compileArgs)
|
||||
{
|
||||
auto params = cv::gapi::getCompileArg<CountStateSetupsParams>(compileArgs)
|
||||
.value_or(CountStateSetupsParams { });
|
||||
if (params.pSetupsCount != nullptr) {
|
||||
(*params.pSetupsCount)++;
|
||||
}
|
||||
}
|
||||
|
||||
static void run(const cv::Mat & , bool &out, int &)
|
||||
{
|
||||
out = true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
TEST(StatefulKernel, StateInitOnceInRegularMode)
|
||||
{
|
||||
cv::GMat in;
|
||||
cv::GOpaque<bool> out = GCountStateSetups::on(in);
|
||||
cv::GComputation c(cv::GIn(in), cv::GOut(out));
|
||||
|
||||
// Input mat:
|
||||
cv::Mat inputData(1080, 1920, CV_8UC1);
|
||||
cv::randu(inputData, cv::Scalar::all(1), cv::Scalar::all(128));
|
||||
|
||||
// variable to update when state is initialized in the kernel
|
||||
CountStateSetupsParams params;
|
||||
params.pSetupsCount.reset(new int(0));
|
||||
|
||||
// Testing for 100 frames
|
||||
bool result { };
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
c.apply(cv::gin(inputData), cv::gout(result),
|
||||
cv::compile_args(cv::gapi::kernels<GOCVCountStateSetups>(), params));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_TRUE(params.pSetupsCount != nullptr);
|
||||
EXPECT_EQ(1, *params.pSetupsCount);
|
||||
}
|
||||
};
|
||||
|
||||
struct StateInitOnce : public ::testing::TestWithParam<bool>{};
|
||||
TEST_P(StateInitOnce, StreamingCompiledWithMeta)
|
||||
{
|
||||
bool compileWithMeta = GetParam();
|
||||
cv::GMat in;
|
||||
cv::GOpaque<bool> out = GCountStateSetups::on(in);
|
||||
cv::GComputation c(cv::GIn(in), cv::GOut(out));
|
||||
|
||||
// Input mat:
|
||||
cv::Mat inputData(1080, 1920, CV_8UC1);
|
||||
cv::randu(inputData, cv::Scalar::all(1), cv::Scalar::all(128));
|
||||
|
||||
// variable to update when state is initialized in the kernel
|
||||
CountStateSetupsParams params;
|
||||
params.pSetupsCount.reset(new int(0));
|
||||
|
||||
// Compilation & testing
|
||||
auto ccomp = (compileWithMeta)
|
||||
? c.compileStreaming(cv::descr_of(inputData),
|
||||
cv::compile_args(cv::gapi::kernels<GOCVCountStateSetups>(),
|
||||
params))
|
||||
: c.compileStreaming(
|
||||
cv::compile_args(cv::gapi::kernels<GOCVCountStateSetups>(),
|
||||
params));
|
||||
|
||||
ccomp.setSource(cv::gin(inputData));
|
||||
|
||||
ccomp.start();
|
||||
EXPECT_TRUE(ccomp.running());
|
||||
|
||||
int counter { };
|
||||
bool result;
|
||||
// Process mat 100 times
|
||||
while (ccomp.pull(cv::gout(result)) && (counter++ < 100)) {
|
||||
EXPECT_TRUE(params.pSetupsCount != nullptr);
|
||||
EXPECT_EQ(1, *params.pSetupsCount);
|
||||
}
|
||||
|
||||
ccomp.stop();
|
||||
EXPECT_FALSE(ccomp.running());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(StatefulKernel, StateInitOnce, ::testing::Bool());
|
||||
|
||||
TEST(StatefulKernel, StateIsMutableInRuntime)
|
||||
{
|
||||
constexpr int expectedCallsCount = 10;
|
||||
@@ -163,7 +270,43 @@ TEST(StatefulKernel, StateIsMutableInRuntime)
|
||||
|
||||
}
|
||||
|
||||
TEST(StatefulKernel, StateIsAutoResetForNewStream)
|
||||
TEST(StateIsResetOnNewStream, RegularMode)
|
||||
{
|
||||
cv::GMat in;
|
||||
cv::GOpaque<bool> out = GCountStateSetups::on(in);
|
||||
cv::GComputation c(cv::GIn(in), cv::GOut(out));
|
||||
|
||||
// Input mat:
|
||||
cv::Mat inputData(1080, 1920, CV_8UC1);
|
||||
cv::randu(inputData, cv::Scalar::all(1), cv::Scalar::all(128));
|
||||
|
||||
// variable to update when state is initialized in the kernel
|
||||
CountStateSetupsParams params;
|
||||
params.pSetupsCount.reset(new int(0));
|
||||
|
||||
auto setupsCounter = c.compile(cv::descr_of(inputData),
|
||||
cv::compile_args(cv::gapi::kernels<GOCVCountStateSetups>(),
|
||||
params));
|
||||
|
||||
bool result { };
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
setupsCounter(cv::gin(inputData), cv::gout(result));
|
||||
EXPECT_TRUE(params.pSetupsCount != nullptr);
|
||||
EXPECT_EQ(1, *params.pSetupsCount);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(params.pSetupsCount != nullptr);
|
||||
EXPECT_EQ(1, *params.pSetupsCount);
|
||||
setupsCounter.prepareForNewStream();
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
setupsCounter(cv::gin(inputData), cv::gout(result));
|
||||
EXPECT_TRUE(params.pSetupsCount != nullptr);
|
||||
EXPECT_EQ(2, *params.pSetupsCount);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateIsResetOnNewStream, StreamingMode)
|
||||
{
|
||||
cv::GMat in;
|
||||
cv::GOpaque<bool> out = GIsStateUpToDate::on(in);
|
||||
@@ -272,7 +415,7 @@ TEST(StatefulKernel, StateIsInitViaCompArgs)
|
||||
// Allowing 1% difference of all pixels between G-API and OpenCV results
|
||||
compareBackSubResults(gapiForeground, ocvForeground, 1);
|
||||
|
||||
// Additionally, test the case where state is resetted
|
||||
// Additionally, test the case where state is reset
|
||||
gapiBackSub.prepareForNewStream();
|
||||
gapiBackSub(cv::gin(frame), cv::gout(gapiForeground));
|
||||
pOcvBackSub->apply(frame, ocvForeground);
|
||||
@@ -342,7 +485,118 @@ TEST(StatefulKernel, StateIsInitViaCompArgsInStreaming)
|
||||
// Allowing 5% difference of all pixels between G-API and reference OpenCV results
|
||||
testBackSubInStreaming(gapiBackSub, 5);
|
||||
}
|
||||
|
||||
TEST(StatefulKernel, StateIsChangedViaCompArgsOnReshape)
|
||||
{
|
||||
cv::GMat in;
|
||||
cv::GComputation comp(in, GBackSub::on(in));
|
||||
|
||||
const auto pkg = cv::gapi::kernels<GOCVBackSub>();
|
||||
|
||||
// OpenCV reference substractor
|
||||
auto pOCVBackSubKNN = createBackgroundSubtractorKNN();
|
||||
auto pOCVBackSubMOG2 = createBackgroundSubtractorMOG2();
|
||||
|
||||
const auto run = [&](const std::string& videoPath, const std::string& method) {
|
||||
auto path = findDataFile(videoPath);
|
||||
cv::gapi::wip::IStreamSource::Ptr source;
|
||||
try {
|
||||
source = gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path);
|
||||
} catch(...) {
|
||||
throw SkipTestException("Video file can not be opened");
|
||||
}
|
||||
cv::Mat inMat, gapiForeground, ocvForeground;
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
cv::gapi::wip::Data inData;
|
||||
source->pull(inData);
|
||||
inMat = cv::util::get<cv::Mat>(inData);
|
||||
comp.apply(inMat, gapiForeground,
|
||||
cv::compile_args(pkg, BackSubStateParams{method}));
|
||||
|
||||
if (method == "knn") {
|
||||
pOCVBackSubKNN->apply(inMat, ocvForeground, -1);
|
||||
// Allowing 1% difference among all pixels
|
||||
compareBackSubResults(gapiForeground, ocvForeground, 1);
|
||||
} else if (method == "mog2") {
|
||||
pOCVBackSubMOG2->apply(inMat, ocvForeground, -1);
|
||||
compareBackSubResults(gapiForeground, ocvForeground, 5);
|
||||
} else {
|
||||
CV_Assert(false && "Unknown BackSub method");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
run("cv/video/768x576.avi", "knn");
|
||||
run("cv/video/1920x1080.avi", "mog2");
|
||||
}
|
||||
|
||||
TEST(StatefulKernel, StateIsResetOnceOnReshapeInStreaming)
|
||||
{
|
||||
cv::GMat in;
|
||||
cv::GOpaque<bool> out = GCountStateSetups::on(in);
|
||||
cv::GComputation c(cv::GIn(in), cv::GOut(out));
|
||||
|
||||
// variable to update when state is initialized in the kernel
|
||||
CountStateSetupsParams params;
|
||||
params.pSetupsCount.reset(new int(0));
|
||||
|
||||
auto ccomp = c.compileStreaming(
|
||||
cv::compile_args(cv::gapi::kernels<GOCVCountStateSetups>(), params));
|
||||
|
||||
auto run = [&ccomp, ¶ms](const std::string& videoPath, int expectedSetupsCount) {
|
||||
auto path = findDataFile(videoPath);
|
||||
try {
|
||||
ccomp.setSource<cv::gapi::wip::GCaptureSource>(path);
|
||||
} catch(...) {
|
||||
throw SkipTestException("Video file can not be opened");
|
||||
}
|
||||
ccomp.start();
|
||||
|
||||
int frames = 0;
|
||||
bool result = false;
|
||||
while (ccomp.pull(cv::gout(result)) && (frames++ < 10)) {
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_TRUE(params.pSetupsCount != nullptr);
|
||||
EXPECT_EQ(expectedSetupsCount, *params.pSetupsCount);
|
||||
}
|
||||
ccomp.stop();
|
||||
};
|
||||
|
||||
run("cv/video/768x576.avi", 1);
|
||||
// FIXME: it should be 2, not 3 for expectedSetupsCount here.
|
||||
// With current implemention both GCPUExecutable reshape() and
|
||||
// handleNewStream() call setupKernelStates()
|
||||
run("cv/video/1920x1080.avi", 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(StatefulKernel, StateIsAutoResetOnReshape)
|
||||
{
|
||||
cv::GMat in;
|
||||
cv::GOpaque<bool> up_to_date = GIsStateUpToDate::on(in);
|
||||
cv::GOpaque<int> calls_count = GCountCalls::on(in);
|
||||
cv::GComputation comp(cv::GIn(in), cv::GOut(up_to_date, calls_count));
|
||||
|
||||
auto run = [&comp](const cv::Mat& in_mat) {
|
||||
const auto pkg = cv::gapi::kernels<GOCVIsStateUpToDate, GOCVCountCalls>();
|
||||
bool stateIsUpToDate = false;
|
||||
int callsCount = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
comp.apply(cv::gin(in_mat), cv::gout(stateIsUpToDate, callsCount),
|
||||
cv::compile_args(pkg));
|
||||
EXPECT_TRUE(stateIsUpToDate);
|
||||
EXPECT_EQ(i+1, callsCount);
|
||||
}
|
||||
};
|
||||
|
||||
cv::Mat in_mat1(32, 32, CV_8UC1);
|
||||
run(in_mat1);
|
||||
|
||||
cv::Mat in_mat2(16, 16, CV_8UC1);
|
||||
run(in_mat2);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
@@ -49,7 +49,25 @@ namespace
|
||||
static GMatDesc outMeta(GMatDesc in) { return in; }
|
||||
};
|
||||
|
||||
// These definitons test the correct macro work if the kernel has multiple output values
|
||||
G_TYPED_KERNEL(GZeros, <GMat(GMat, GMatDesc)>, "org.opencv.test.zeros")
|
||||
{
|
||||
static GMatDesc outMeta(GMatDesc /*in*/, GMatDesc user_desc)
|
||||
{
|
||||
return user_desc;
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(GOCVZeros, GZeros)
|
||||
{
|
||||
static void run(const cv::Mat& /*in*/,
|
||||
const cv::GMatDesc& /*desc*/,
|
||||
cv::Mat& out)
|
||||
{
|
||||
out.setTo(0);
|
||||
}
|
||||
};
|
||||
|
||||
// These definitions test the correct macro work if the kernel has multiple output values
|
||||
G_TYPED_KERNEL(GRetGArrayTupleOfGMat2Kernel, <GArray<std::tuple<GMat, GMat>>(GMat, Scalar)>, "org.opencv.test.retarrayoftupleofgmat2kernel") {};
|
||||
G_TYPED_KERNEL(GRetGArraTupleyOfGMat3Kernel, <GArray<std::tuple<GMat, GMat, GMat>>(GMat)>, "org.opencv.test.retarrayoftupleofgmat3kernel") {};
|
||||
G_TYPED_KERNEL(GRetGArraTupleyOfGMat4Kernel, <GArray<std::tuple<GMat, GMat, GMat, GMat>>(GMat)>, "org.opencv.test.retarrayoftupleofgmat4kernel") {};
|
||||
@@ -430,4 +448,69 @@ TEST(GAPI_Pipeline, ReplaceDefaultByFunctor)
|
||||
EXPECT_TRUE(f.is_called);
|
||||
}
|
||||
|
||||
TEST(GAPI_Pipeline, GraphOutputIs1DMat)
|
||||
{
|
||||
int dim = 100;
|
||||
cv::Mat in_mat(1, 1, CV_8UC3);
|
||||
cv::Mat out_mat;
|
||||
|
||||
cv::GMat in;
|
||||
auto cc = cv::GComputation(in, GZeros::on(in, cv::GMatDesc(CV_8U, {dim})))
|
||||
.compile(cv::descr_of(in_mat), cv::compile_args(cv::gapi::kernels<GOCVZeros>()));
|
||||
|
||||
// NB: Computation is able to write 1D output cv::Mat to empty out_mat.
|
||||
ASSERT_NO_THROW(cc(cv::gin(in_mat), cv::gout(out_mat)));
|
||||
ASSERT_EQ(1, out_mat.size.dims());
|
||||
ASSERT_EQ(dim, out_mat.size[0]);
|
||||
|
||||
// NB: Computation is able to write 1D output cv::Mat
|
||||
// to pre-allocated with the same meta out_mat.
|
||||
ASSERT_NO_THROW(cc(cv::gin(in_mat), cv::gout(out_mat)));
|
||||
ASSERT_EQ(1, out_mat.size.dims());
|
||||
ASSERT_EQ(dim, out_mat.size[0]);
|
||||
}
|
||||
|
||||
TEST(GAPI_Pipeline, 1DMatBetweenIslands)
|
||||
{
|
||||
int dim = 100;
|
||||
cv::Mat in_mat(1, 1, CV_8UC3);
|
||||
cv::Mat out_mat;
|
||||
|
||||
cv::Mat ref_mat({dim}, CV_8U);
|
||||
ref_mat.dims = 1;
|
||||
ref_mat.setTo(0);
|
||||
|
||||
cv::GMat in;
|
||||
auto out = cv::gapi::copy(GZeros::on(cv::gapi::copy(in), cv::GMatDesc(CV_8U, {dim})));
|
||||
auto cc = cv::GComputation(in, out)
|
||||
.compile(cv::descr_of(in_mat), cv::compile_args(cv::gapi::kernels<GOCVZeros>()));
|
||||
|
||||
cc(cv::gin(in_mat), cv::gout(out_mat));
|
||||
|
||||
EXPECT_EQ(0, cv::norm(out_mat, ref_mat));
|
||||
}
|
||||
|
||||
TEST(GAPI_Pipeline, 1DMatWithinSingleIsland)
|
||||
{
|
||||
int dim = 100;
|
||||
cv::Size blur_sz(3, 3);
|
||||
cv::Mat in_mat(10, 10, CV_8UC3);
|
||||
cv::randu(in_mat, 0, 255);
|
||||
cv::Mat out_mat;
|
||||
|
||||
cv::Mat ref_mat({dim}, CV_8U);
|
||||
ref_mat.dims = 1;
|
||||
ref_mat.setTo(0);
|
||||
|
||||
cv::GMat in;
|
||||
auto out = cv::gapi::blur(
|
||||
GZeros::on(cv::gapi::blur(in, blur_sz), cv::GMatDesc(CV_8U, {dim})), blur_sz);
|
||||
auto cc = cv::GComputation(in, out)
|
||||
.compile(cv::descr_of(in_mat), cv::compile_args(cv::gapi::kernels<GOCVZeros>()));
|
||||
|
||||
cc(cv::gin(in_mat), cv::gout(out_mat));
|
||||
|
||||
EXPECT_EQ(0, cv::norm(out_mat, ref_mat));
|
||||
}
|
||||
|
||||
} // namespace opencv_test
|
||||
|
||||
@@ -2915,6 +2915,47 @@ TEST(Infer, ModelWith2DInputs)
|
||||
|
||||
#endif // HAVE_NGRAPH
|
||||
|
||||
TEST(TestAgeGender, ThrowBlobAndInputPrecisionMismatchStreaming)
|
||||
{
|
||||
const std::string device = "MYRIAD";
|
||||
skipIfDeviceNotAvailable(device);
|
||||
|
||||
initDLDTDataPath();
|
||||
|
||||
cv::gapi::ie::detail::ParamDesc params;
|
||||
// NB: Precision for inputs is U8.
|
||||
params.model_path = compileAgeGenderBlob(device);
|
||||
params.device_id = device;
|
||||
|
||||
// Configure & run G-API
|
||||
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
|
||||
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender");
|
||||
|
||||
auto pp = cv::gapi::ie::Params<AgeGender> {
|
||||
params.model_path, params.device_id
|
||||
}.cfgOutputLayers({ "age_conv3", "prob" });
|
||||
|
||||
cv::GMat in, age, gender;
|
||||
std::tie(age, gender) = cv::gapi::infer<AgeGender>(in);
|
||||
auto pipeline = cv::GComputation(cv::GIn(in), cv::GOut(age, gender))
|
||||
.compileStreaming(cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
cv::Mat in_mat(320, 240, CV_32FC3);
|
||||
cv::randu(in_mat, 0, 1);
|
||||
cv::Mat gapi_age, gapi_gender;
|
||||
|
||||
pipeline.setSource(cv::gin(in_mat));
|
||||
pipeline.start();
|
||||
|
||||
// NB: Blob precision is U8, but user pass FP32 data, so exception will be thrown.
|
||||
// Now exception comes directly from IE, but since G-API has information
|
||||
// about data precision at the compile stage, consider the possibility of
|
||||
// throwing exception from there.
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
EXPECT_ANY_THROW(pipeline.pull(cv::gout(gapi_age, gapi_gender)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace opencv_test
|
||||
|
||||
#endif // HAVE_INF_ENGINE
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2018 Intel Corporation
|
||||
// Copyright (C) 2018-2022 Intel Corporation
|
||||
|
||||
|
||||
#include "../test_precomp.hpp"
|
||||
#include "../gapi_mock_kernels.hpp"
|
||||
|
||||
#include <opencv2/gapi/core.hpp>
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
|
||||
@@ -294,6 +296,28 @@ TEST_F(GExecutorReshapeTest, ReshapeCallAllocate)
|
||||
EXPECT_EQ(1, island1.getReshapeCounter());
|
||||
}
|
||||
|
||||
TEST_F(GExecutorReshapeTest, CPUBackendIsReshapable)
|
||||
{
|
||||
comp = cv::GComputation([](){
|
||||
cv::GMat in;
|
||||
cv::GMat foo = I::Foo::on(in);
|
||||
cv::GMat out = cv::gapi::bitwise_not(cv::gapi::bitwise_not(in));
|
||||
return cv::GComputation(cv::GIn(in), cv::GOut(foo, out));
|
||||
});
|
||||
// NB: Initial state
|
||||
EXPECT_EQ(0, island1.getReshapeCounter());
|
||||
|
||||
// NB: First compilation.
|
||||
cv::Mat out_mat2;
|
||||
comp.apply(cv::gin(in_mat1), cv::gout(out_mat, out_mat2), cv::compile_args(pkg));
|
||||
EXPECT_EQ(0, island1.getReshapeCounter());
|
||||
|
||||
// NB: The entire graph is reshapable, so it won't be recompiled, but reshaped.
|
||||
comp.apply(cv::gin(in_mat2), cv::gout(out_mat, out_mat2), cv::compile_args(pkg));
|
||||
EXPECT_EQ(1, island1.getReshapeCounter());
|
||||
EXPECT_EQ(0, cvtest::norm(out_mat2, in_mat2, NORM_INF));
|
||||
}
|
||||
|
||||
// FIXME: Add explicit tests on GMat/GScalar/GArray<T> being connectors
|
||||
// between executed islands
|
||||
|
||||
|
||||
@@ -304,6 +304,66 @@ void checkPullOverload(const cv::Mat& ref,
|
||||
EXPECT_EQ(0., cv::norm(ref, out_mat, cv::NORM_INF));
|
||||
}
|
||||
|
||||
class InvalidSource : public cv::gapi::wip::IStreamSource {
|
||||
public:
|
||||
InvalidSource(const size_t throw_every_nth_frame,
|
||||
const size_t num_frames)
|
||||
: m_throw_every_nth_frame(throw_every_nth_frame),
|
||||
m_curr_frame_id(0u),
|
||||
m_num_frames(num_frames),
|
||||
m_mat(1, 1, CV_8U) {
|
||||
}
|
||||
|
||||
static std::string exception_msg()
|
||||
{
|
||||
return "InvalidSource sucessfuly failed!";
|
||||
}
|
||||
|
||||
bool pull(cv::gapi::wip::Data& d) {
|
||||
++m_curr_frame_id;
|
||||
if (m_curr_frame_id > m_num_frames) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_curr_frame_id % m_throw_every_nth_frame == 0) {
|
||||
throw std::logic_error(InvalidSource::exception_msg());
|
||||
return true;
|
||||
} else {
|
||||
d = cv::Mat(m_mat);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cv::GMetaArg descr_of() const override {
|
||||
return cv::GMetaArg{cv::descr_of(m_mat)};
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_throw_every_nth_frame;
|
||||
size_t m_curr_frame_id;
|
||||
size_t m_num_frames;
|
||||
cv::Mat m_mat;
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL(GThrowExceptionOp, <GMat(GMat)>, "org.opencv.test.throw_error_op")
|
||||
{
|
||||
static GMatDesc outMeta(GMatDesc in) { return in; }
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(GThrowExceptionKernel, GThrowExceptionOp)
|
||||
{
|
||||
static std::string exception_msg()
|
||||
{
|
||||
return "GThrowExceptionKernel sucessfuly failed";
|
||||
}
|
||||
|
||||
static void run(const cv::Mat&, cv::Mat&)
|
||||
{
|
||||
throw std::logic_error(GThrowExceptionKernel::exception_msg());
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
TEST_P(GAPI_Streaming, SmokeTest_ConstInput_GMat)
|
||||
@@ -2512,5 +2572,109 @@ TEST(GAPI_Streaming, TestDesyncMediaFrameGray) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(GAPI_Streaming_Exception, SingleKernelThrow) {
|
||||
cv::GMat in;
|
||||
auto pipeline = cv::GComputation(in, GThrowExceptionOp::on(in))
|
||||
.compileStreaming(cv::compile_args(cv::gapi::kernels<GThrowExceptionKernel>()));
|
||||
|
||||
cv::Mat in_mat(cv::Size(300, 300), CV_8UC3);
|
||||
cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
|
||||
pipeline.setSource(cv::gin(in_mat));
|
||||
pipeline.start();
|
||||
|
||||
EXPECT_THROW(
|
||||
try {
|
||||
cv::Mat out_mat;
|
||||
pipeline.pull(cv::gout(out_mat));
|
||||
} catch (const std::logic_error& e) {
|
||||
EXPECT_EQ(GThrowExceptionKernel::exception_msg(), e.what());
|
||||
throw;
|
||||
}, std::logic_error);
|
||||
}
|
||||
|
||||
TEST(GAPI_Streaming_Exception, StreamingBackendExceptionAsInput) {
|
||||
cv::GMat in;
|
||||
auto pipeline = cv::GComputation(in,
|
||||
cv::gapi::copy(GThrowExceptionOp::on(in)))
|
||||
.compileStreaming(cv::compile_args(cv::gapi::kernels<GThrowExceptionKernel>()));
|
||||
|
||||
cv::Mat in_mat(cv::Size(300, 300), CV_8UC3);
|
||||
cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
|
||||
pipeline.setSource(cv::gin(in_mat));
|
||||
pipeline.start();
|
||||
|
||||
EXPECT_THROW(
|
||||
try {
|
||||
cv::Mat out_mat;
|
||||
pipeline.pull(cv::gout(out_mat));
|
||||
} catch (const std::logic_error& e) {
|
||||
EXPECT_EQ(GThrowExceptionKernel::exception_msg(), e.what());
|
||||
throw;
|
||||
}, std::logic_error);
|
||||
}
|
||||
|
||||
TEST(GAPI_Streaming_Exception, RegularBacckendsExceptionAsInput) {
|
||||
cv::GMat in;
|
||||
auto pipeline = cv::GComputation(in,
|
||||
cv::gapi::add(GThrowExceptionOp::on(in), GThrowExceptionOp::on(in)))
|
||||
.compileStreaming(cv::compile_args(cv::gapi::kernels<GThrowExceptionKernel>()));
|
||||
|
||||
cv::Mat in_mat(cv::Size(300, 300), CV_8UC3);
|
||||
cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
|
||||
pipeline.setSource(cv::gin(in_mat));
|
||||
pipeline.start();
|
||||
|
||||
EXPECT_THROW(
|
||||
try {
|
||||
cv::Mat out_mat;
|
||||
pipeline.pull(cv::gout(out_mat));
|
||||
} catch (const std::logic_error& e) {
|
||||
EXPECT_EQ(GThrowExceptionKernel::exception_msg(), e.what());
|
||||
throw;
|
||||
}, std::logic_error);
|
||||
}
|
||||
|
||||
TEST(GAPI_Streaming_Exception, SourceThrow) {
|
||||
cv::GMat in;
|
||||
auto pipeline = cv::GComputation(in, cv::gapi::copy(in)).compileStreaming();
|
||||
|
||||
pipeline.setSource(std::make_shared<InvalidSource>(1u, 1u));
|
||||
pipeline.start();
|
||||
|
||||
EXPECT_THROW(
|
||||
try {
|
||||
cv::Mat out_mat;
|
||||
pipeline.pull(cv::gout(out_mat));
|
||||
} catch (const std::logic_error& e) {
|
||||
EXPECT_EQ(InvalidSource::exception_msg(), e.what());
|
||||
throw;
|
||||
}, std::logic_error);
|
||||
}
|
||||
|
||||
TEST(GAPI_Streaming_Exception, SourceThrowEverySecondFrame) {
|
||||
constexpr size_t throw_every_nth_frame = 2u;
|
||||
constexpr size_t num_frames = 10u;
|
||||
size_t curr_frame = 0;
|
||||
bool has_frame = true;
|
||||
cv::Mat out_mat;
|
||||
|
||||
cv::GMat in;
|
||||
auto pipeline = cv::GComputation(in, cv::gapi::copy(in)).compileStreaming();
|
||||
|
||||
pipeline.setSource(std::make_shared<InvalidSource>(throw_every_nth_frame, num_frames));
|
||||
pipeline.start();
|
||||
while (has_frame) {
|
||||
++curr_frame;
|
||||
try {
|
||||
has_frame = pipeline.pull(cv::gout(out_mat));
|
||||
} catch (const std::exception& e) {
|
||||
EXPECT_TRUE(curr_frame % throw_every_nth_frame == 0);
|
||||
EXPECT_EQ(InvalidSource::exception_msg(), e.what());
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Pull was called num_frames + 1(stop).
|
||||
EXPECT_EQ(num_frames, curr_frame - 1);
|
||||
}
|
||||
|
||||
} // namespace opencv_test
|
||||
|
||||
@@ -68,7 +68,7 @@ struct EmptyDataProvider : public cv::gapi::wip::onevpl::IDataProvider {
|
||||
|
||||
struct TestProcessingSession : public cv::gapi::wip::onevpl::EngineSession {
|
||||
TestProcessingSession(mfxSession mfx_session) :
|
||||
EngineSession(mfx_session, {}) {
|
||||
EngineSession(mfx_session) {
|
||||
}
|
||||
|
||||
const mfxFrameInfo& get_video_param() const override {
|
||||
@@ -319,7 +319,8 @@ TEST(OneVPL_Source_CPU_FrameAdapter, InitFrameAdapter)
|
||||
EXPECT_EQ(0, surf->get_locks_count());
|
||||
|
||||
{
|
||||
VPLMediaFrameCPUAdapter adapter(surf);
|
||||
mfxSession stub_session = reinterpret_cast<mfxSession>(0x1);
|
||||
VPLMediaFrameCPUAdapter adapter(surf, stub_session);
|
||||
EXPECT_EQ(1, surf->get_locks_count());
|
||||
}
|
||||
EXPECT_EQ(0, surf->get_locks_count());
|
||||
@@ -528,9 +529,9 @@ TEST(OneVPL_Source_DX11_Accel, Init)
|
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
|
||||
VPLDX11AccelerationPolicy accel(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11));
|
||||
|
||||
mfxLoader mfx_handle = MFXLoad();
|
||||
mfxLoader test_mfx_handle = MFXLoad();
|
||||
|
||||
mfxConfig cfg_inst_0 = MFXCreateConfig(mfx_handle);
|
||||
mfxConfig cfg_inst_0 = MFXCreateConfig(test_mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_0);
|
||||
mfxVariant mfx_param_0;
|
||||
mfx_param_0.Type = MFX_VARIANT_TYPE_U32;
|
||||
@@ -538,7 +539,7 @@ TEST(OneVPL_Source_DX11_Accel, Init)
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)CfgParam::implementation_name(),
|
||||
mfx_param_0), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_1 = MFXCreateConfig(mfx_handle);
|
||||
mfxConfig cfg_inst_1 = MFXCreateConfig(test_mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_1);
|
||||
mfxVariant mfx_param_1;
|
||||
mfx_param_1.Type = MFX_VARIANT_TYPE_U32;
|
||||
@@ -546,7 +547,7 @@ TEST(OneVPL_Source_DX11_Accel, Init)
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_1,(mfxU8 *)CfgParam::acceleration_mode_name(),
|
||||
mfx_param_1), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_2 = MFXCreateConfig(mfx_handle);
|
||||
mfxConfig cfg_inst_2 = MFXCreateConfig(test_mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_2);
|
||||
mfxVariant mfx_param_2;
|
||||
mfx_param_2.Type = MFX_VARIANT_TYPE_U32;
|
||||
@@ -556,7 +557,7 @@ TEST(OneVPL_Source_DX11_Accel, Init)
|
||||
|
||||
// create session
|
||||
mfxSession mfx_session{};
|
||||
mfxStatus sts = MFXCreateSession(mfx_handle, 0, &mfx_session);
|
||||
mfxStatus sts = MFXCreateSession(test_mfx_handle, 0, &mfx_session);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// assign acceleration
|
||||
@@ -600,7 +601,7 @@ TEST(OneVPL_Source_DX11_Accel, Init)
|
||||
|
||||
EXPECT_NO_THROW(accel.deinit(mfx_session));
|
||||
MFXClose(mfx_session);
|
||||
MFXUnload(mfx_handle);
|
||||
MFXUnload(test_mfx_handle);
|
||||
}
|
||||
|
||||
TEST(OneVPL_Source_DX11_Accel_VPL, Init)
|
||||
@@ -611,9 +612,9 @@ TEST(OneVPL_Source_DX11_Accel_VPL, Init)
|
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
|
||||
std::unique_ptr<VPLAccelerationPolicy> acceleration_policy (new VPLDX11AccelerationPolicy(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11)));
|
||||
|
||||
mfxLoader mfx_handle = MFXLoad();
|
||||
mfxLoader test_mfx_handle = MFXLoad();
|
||||
|
||||
mfxConfig cfg_inst_0 = MFXCreateConfig(mfx_handle);
|
||||
mfxConfig cfg_inst_0 = MFXCreateConfig(test_mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_0);
|
||||
mfxVariant mfx_param_0;
|
||||
mfx_param_0.Type = MFX_VARIANT_TYPE_U32;
|
||||
@@ -621,7 +622,7 @@ TEST(OneVPL_Source_DX11_Accel_VPL, Init)
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)CfgParam::implementation_name(),
|
||||
mfx_param_0), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_1 = MFXCreateConfig(mfx_handle);
|
||||
mfxConfig cfg_inst_1 = MFXCreateConfig(test_mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_1);
|
||||
mfxVariant mfx_param_1;
|
||||
mfx_param_1.Type = MFX_VARIANT_TYPE_U32;
|
||||
@@ -629,7 +630,7 @@ TEST(OneVPL_Source_DX11_Accel_VPL, Init)
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_1,(mfxU8 *)CfgParam::acceleration_mode_name(),
|
||||
mfx_param_1), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_2 = MFXCreateConfig(mfx_handle);
|
||||
mfxConfig cfg_inst_2 = MFXCreateConfig(test_mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_2);
|
||||
mfxVariant mfx_param_2;
|
||||
mfx_param_2.Type = MFX_VARIANT_TYPE_U32;
|
||||
@@ -637,7 +638,7 @@ TEST(OneVPL_Source_DX11_Accel_VPL, Init)
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_2,(mfxU8 *)CfgParam::decoder_id_name(),
|
||||
mfx_param_2), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_3 = MFXCreateConfig(mfx_handle);
|
||||
mfxConfig cfg_inst_3 = MFXCreateConfig(test_mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_3);
|
||||
mfxVariant mfx_param_3;
|
||||
mfx_param_3.Type = MFX_VARIANT_TYPE_U32;
|
||||
@@ -647,7 +648,7 @@ TEST(OneVPL_Source_DX11_Accel_VPL, Init)
|
||||
mfx_param_3), MFX_ERR_NONE);
|
||||
// create session
|
||||
mfxSession mfx_session{};
|
||||
mfxStatus sts = MFXCreateSession(mfx_handle, 0, &mfx_session);
|
||||
mfxStatus sts = MFXCreateSession(test_mfx_handle, 0, &mfx_session);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// assign acceleration
|
||||
@@ -732,7 +733,7 @@ TEST(OneVPL_Source_DX11_Accel_VPL, Init)
|
||||
sess_ptr->init_transcode_surface_pool(vpp_out_pool_key);
|
||||
|
||||
// prepare working surfaces
|
||||
sess_ptr->swap_surface(engine);
|
||||
sess_ptr->swap_decode_surface(engine);
|
||||
sess_ptr->swap_transcode_surface(engine);
|
||||
|
||||
// launch pipeline
|
||||
@@ -756,11 +757,8 @@ TEST(OneVPL_Source_DX11_Accel_VPL, Init)
|
||||
{
|
||||
my_sess.last_status =
|
||||
MFXVideoDECODE_DecodeFrameAsync(my_sess.session,
|
||||
(my_sess.data_provider || (my_sess.stream && my_sess.stream->DataLength))
|
||||
? my_sess.stream.get()
|
||||
|
||||
: nullptr, /* No more data to read, start decode draining mode*/
|
||||
my_sess.procesing_surface_ptr.lock()->get_handle(),
|
||||
my_sess.get_mfx_bitstream_ptr(),
|
||||
my_sess.processing_surface_ptr.lock()->get_handle(),
|
||||
&sync_pair.second,
|
||||
&sync_pair.first);
|
||||
|
||||
@@ -771,12 +769,12 @@ TEST(OneVPL_Source_DX11_Accel_VPL, Init)
|
||||
my_sess.last_status == MFX_WRN_DEVICE_BUSY) {
|
||||
try {
|
||||
if (my_sess.last_status == MFX_ERR_MORE_SURFACE) {
|
||||
my_sess.swap_surface(engine);
|
||||
my_sess.swap_decode_surface(engine);
|
||||
}
|
||||
my_sess.last_status =
|
||||
MFXVideoDECODE_DecodeFrameAsync(my_sess.session,
|
||||
my_sess.stream.get(),
|
||||
my_sess.procesing_surface_ptr.lock()->get_handle(),
|
||||
my_sess.get_mfx_bitstream_ptr(),
|
||||
my_sess.processing_surface_ptr.lock()->get_handle(),
|
||||
&sync_pair.second,
|
||||
&sync_pair.first);
|
||||
|
||||
@@ -808,6 +806,224 @@ TEST(OneVPL_Source_DX11_Accel_VPL, Init)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OneVPL_Source_DX11_Accel_VPL, preproc)
|
||||
{
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
|
||||
std::vector<CfgParam> cfg_params_w_dx11;
|
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
|
||||
std::unique_ptr<VPLAccelerationPolicy> acceleration_policy (new VPLDX11AccelerationPolicy(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11)));
|
||||
|
||||
mfxLoader test_mfx_handle = MFXLoad();
|
||||
|
||||
mfxConfig cfg_inst_0 = MFXCreateConfig(test_mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_0);
|
||||
mfxVariant mfx_param_0;
|
||||
mfx_param_0.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_0.Data.U32 = MFX_IMPL_TYPE_HARDWARE;
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)CfgParam::implementation_name(),
|
||||
mfx_param_0), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_1 = MFXCreateConfig(test_mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_1);
|
||||
mfxVariant mfx_param_1;
|
||||
mfx_param_1.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_1.Data.U32 = MFX_ACCEL_MODE_VIA_D3D11;
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_1,(mfxU8 *)CfgParam::acceleration_mode_name(),
|
||||
mfx_param_1), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_2 = MFXCreateConfig(test_mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_2);
|
||||
mfxVariant mfx_param_2;
|
||||
mfx_param_2.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_2.Data.U32 = MFX_CODEC_HEVC;
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_2,(mfxU8 *)CfgParam::decoder_id_name(),
|
||||
mfx_param_2), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_3 = MFXCreateConfig(test_mfx_handle);
|
||||
EXPECT_TRUE(cfg_inst_3);
|
||||
mfxVariant mfx_param_3;
|
||||
mfx_param_3.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_3.Data.U32 = MFX_EXTBUFF_VPP_SCALING;
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_3,
|
||||
(mfxU8 *)"mfxImplDescription.mfxVPPDescription.filter.FilterFourCC",
|
||||
mfx_param_3), MFX_ERR_NONE);
|
||||
// create session
|
||||
mfxSession mfx_decode_session{};
|
||||
mfxStatus sts = MFXCreateSession(test_mfx_handle, 0, &mfx_decode_session);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// assign acceleration
|
||||
EXPECT_NO_THROW(acceleration_policy->init(mfx_decode_session));
|
||||
|
||||
// create proper bitstream
|
||||
std::string file_path = findDataFile("highgui/video/big_buck_bunny.h265");
|
||||
std::shared_ptr<IDataProvider> data_provider(new FileDataProvider(file_path,
|
||||
{CfgParam::create_decoder_id(MFX_CODEC_HEVC)}));
|
||||
IDataProvider::mfx_codec_id_type decoder_id_name = data_provider->get_mfx_codec_id();
|
||||
|
||||
// Prepare video param
|
||||
mfxVideoParam mfxDecParams {};
|
||||
mfxDecParams.mfx.CodecId = decoder_id_name;
|
||||
mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
|
||||
|
||||
// try fetch & decode input data
|
||||
sts = MFX_ERR_NONE;
|
||||
std::shared_ptr<IDataProvider::mfx_bitstream> bitstream{};
|
||||
do {
|
||||
EXPECT_TRUE(data_provider->fetch_bitstream_data(bitstream));
|
||||
sts = MFXVideoDECODE_DecodeHeader(mfx_decode_session, bitstream.get(), &mfxDecParams);
|
||||
EXPECT_TRUE(MFX_ERR_NONE == sts || MFX_ERR_MORE_DATA == sts);
|
||||
} while (sts == MFX_ERR_MORE_DATA && !data_provider->empty());
|
||||
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
mfxFrameAllocRequest request{};
|
||||
memset(&request, 0, sizeof(request));
|
||||
sts = MFXVideoDECODE_QueryIOSurf(mfx_decode_session, &mfxDecParams, &request);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// Allocate surfaces for decoder
|
||||
request.Type |= MFX_MEMTYPE_EXTERNAL_FRAME | MFX_MEMTYPE_FROM_DECODE | MFX_MEMTYPE_FROM_VPPIN;
|
||||
VPLAccelerationPolicy::pool_key_t decode_pool_key = acceleration_policy->create_surface_pool(request,
|
||||
mfxDecParams.mfx.FrameInfo);
|
||||
sts = MFXVideoDECODE_Init(mfx_decode_session, &mfxDecParams);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// initialize VPL session
|
||||
mfxSession mfx_vpl_session{};
|
||||
sts = MFXCreateSession(test_mfx_handle, 0, &mfx_vpl_session);
|
||||
// assign acceleration
|
||||
EXPECT_NO_THROW(acceleration_policy->init(mfx_vpl_session));
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// request VPL surface
|
||||
mfxU16 vppOutImgWidth = 672;
|
||||
mfxU16 vppOutImgHeight = 382;
|
||||
|
||||
mfxVideoParam mfxVPPParams{0};
|
||||
mfxVPPParams.vpp.In = mfxDecParams.mfx.FrameInfo;
|
||||
|
||||
mfxVPPParams.vpp.Out.FourCC = MFX_FOURCC_NV12;
|
||||
mfxVPPParams.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
|
||||
mfxVPPParams.vpp.Out.Width = ALIGN16(vppOutImgWidth);
|
||||
mfxVPPParams.vpp.Out.Height = ALIGN16(vppOutImgHeight);
|
||||
mfxVPPParams.vpp.Out.CropX = 0;
|
||||
mfxVPPParams.vpp.Out.CropY = 0;
|
||||
mfxVPPParams.vpp.Out.CropW = vppOutImgWidth;
|
||||
mfxVPPParams.vpp.Out.CropH = vppOutImgHeight;
|
||||
mfxVPPParams.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
|
||||
mfxVPPParams.vpp.Out.FrameRateExtN = 30;
|
||||
mfxVPPParams.vpp.Out.FrameRateExtD = 1;
|
||||
|
||||
mfxVPPParams.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
|
||||
|
||||
mfxFrameAllocRequest vppRequests[2];
|
||||
memset(&vppRequests, 0, sizeof(mfxFrameAllocRequest) * 2);
|
||||
EXPECT_EQ(MFXVideoVPP_QueryIOSurf(mfx_vpl_session, &mfxVPPParams, vppRequests), MFX_ERR_NONE);
|
||||
|
||||
vppRequests[1].AllocId = 666;
|
||||
VPLAccelerationPolicy::pool_key_t vpp_out_pool_key =
|
||||
acceleration_policy->create_surface_pool(vppRequests[1], mfxVPPParams.vpp.Out);
|
||||
EXPECT_EQ(MFXVideoVPP_Init(mfx_vpl_session, &mfxVPPParams), MFX_ERR_NONE);
|
||||
|
||||
// finalize session creation
|
||||
DecoderParams d_param{bitstream, mfxDecParams};
|
||||
TranscoderParams t_param{mfxVPPParams};
|
||||
VPLLegacyDecodeEngine engine(std::move(acceleration_policy));
|
||||
std::shared_ptr<LegacyDecodeSession> sess_ptr =
|
||||
engine.register_session<LegacyDecodeSession>(
|
||||
mfx_decode_session,
|
||||
std::move(d_param),
|
||||
data_provider);
|
||||
|
||||
sess_ptr->init_surface_pool(decode_pool_key);
|
||||
|
||||
// prepare working surfaces
|
||||
sess_ptr->swap_decode_surface(engine);
|
||||
|
||||
// launch pipeline
|
||||
LegacyDecodeSession &my_sess = *sess_ptr;
|
||||
|
||||
size_t min_available_frames_count =
|
||||
std::min(engine.get_accel()->get_surface_count(decode_pool_key),
|
||||
engine.get_accel()->get_surface_count(vpp_out_pool_key));
|
||||
size_t frame_num = 0;
|
||||
do {
|
||||
if (!my_sess.data_provider) {
|
||||
my_sess.last_status = MFX_ERR_MORE_DATA;
|
||||
} else {
|
||||
my_sess.last_status = MFX_ERR_NONE;
|
||||
if (!my_sess.data_provider->fetch_bitstream_data(my_sess.stream)) {
|
||||
my_sess.last_status = MFX_ERR_MORE_DATA;
|
||||
my_sess.data_provider.reset(); //close source
|
||||
}
|
||||
}
|
||||
|
||||
// 2) enqueue ASYNC decode operation
|
||||
// prepare sync object for new surface
|
||||
LegacyTranscodeSession::op_handle_t sync_pair{};
|
||||
|
||||
// enqueue decode operation with current session surface
|
||||
{
|
||||
my_sess.last_status =
|
||||
MFXVideoDECODE_DecodeFrameAsync(my_sess.session,
|
||||
my_sess.get_mfx_bitstream_ptr(),
|
||||
my_sess.processing_surface_ptr.lock()->get_handle(),
|
||||
&sync_pair.second,
|
||||
&sync_pair.first);
|
||||
|
||||
// process wait-like statuses in-place:
|
||||
// It had better to use up all VPL decoding resources in pipeline
|
||||
// as soon as possible. So waiting more free-surface or device free
|
||||
while (my_sess.last_status == MFX_ERR_MORE_SURFACE ||
|
||||
my_sess.last_status == MFX_WRN_DEVICE_BUSY) {
|
||||
try {
|
||||
if (my_sess.last_status == MFX_ERR_MORE_SURFACE) {
|
||||
my_sess.swap_decode_surface(engine);
|
||||
}
|
||||
my_sess.last_status =
|
||||
MFXVideoDECODE_DecodeFrameAsync(my_sess.session,
|
||||
my_sess.get_mfx_bitstream_ptr(),
|
||||
my_sess.processing_surface_ptr.lock()->get_handle(),
|
||||
&sync_pair.second,
|
||||
&sync_pair.first);
|
||||
|
||||
} catch (const std::runtime_error&) {
|
||||
// NB: not an error, yield CPU ticks to check
|
||||
// surface availability at a next phase.
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
do {
|
||||
my_sess.last_status = MFXVideoCORE_SyncOperation(my_sess.session, sync_pair.first, 0);
|
||||
// put frames in ready queue on success
|
||||
if (MFX_ERR_NONE == my_sess.last_status) {
|
||||
break;
|
||||
}
|
||||
} while (MFX_WRN_IN_EXECUTION == my_sess.last_status);
|
||||
EXPECT_EQ(my_sess.last_status, MFX_ERR_NONE);
|
||||
}
|
||||
|
||||
// perform VPP operation on decoder synchronized surface
|
||||
|
||||
auto vpp_out = engine.get_accel()->get_free_surface(vpp_out_pool_key).lock();
|
||||
EXPECT_TRUE(vpp_out.get());
|
||||
my_sess.last_status = MFXVideoVPP_RunFrameVPPAsync(mfx_vpl_session,
|
||||
sync_pair.second,
|
||||
vpp_out->get_handle(),
|
||||
nullptr, &sync_pair.first);
|
||||
if (my_sess.last_status == MFX_ERR_MORE_SURFACE ||
|
||||
my_sess.last_status == MFX_ERR_NONE) {
|
||||
my_sess.last_status = MFXVideoCORE_SyncOperation(mfx_vpl_session, sync_pair.first, INFINITE);
|
||||
EXPECT_EQ(my_sess.last_status, MFX_ERR_NONE);
|
||||
frame_num++;
|
||||
}
|
||||
} while(frame_num < min_available_frames_count);
|
||||
}
|
||||
#endif // HAVE_DIRECTX
|
||||
#endif // HAVE_D3D11
|
||||
|
||||
|
||||
@@ -73,9 +73,9 @@ TEST_P(OneVPL_Source_MFPAsyncDispatcherTest, open_and_decode_file)
|
||||
EXPECT_TRUE(dd_result);
|
||||
|
||||
// initialize MFX
|
||||
mfxLoader mfx_handle = MFXLoad();
|
||||
mfxLoader mfx = MFXLoad();
|
||||
|
||||
mfxConfig cfg_inst_0 = MFXCreateConfig(mfx_handle);
|
||||
mfxConfig cfg_inst_0 = MFXCreateConfig(mfx);
|
||||
EXPECT_TRUE(cfg_inst_0);
|
||||
mfxVariant mfx_param_0;
|
||||
mfx_param_0.Type = MFX_VARIANT_TYPE_U32;
|
||||
@@ -85,7 +85,7 @@ TEST_P(OneVPL_Source_MFPAsyncDispatcherTest, open_and_decode_file)
|
||||
|
||||
// create MFX session
|
||||
mfxSession mfx_session{};
|
||||
mfxStatus sts = MFXCreateSession(mfx_handle, 0, &mfx_session);
|
||||
mfxStatus sts = MFXCreateSession(mfx, 0, &mfx_session);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// create proper bitstream
|
||||
@@ -112,7 +112,7 @@ TEST_P(OneVPL_Source_MFPAsyncDispatcherTest, open_and_decode_file)
|
||||
|
||||
MFXVideoDECODE_Close(mfx_session);
|
||||
MFXClose(mfx_session);
|
||||
MFXUnload(mfx_handle);
|
||||
MFXUnload(mfx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,710 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2022 Intel Corporation
|
||||
|
||||
|
||||
#include "../test_precomp.hpp"
|
||||
|
||||
#include "../common/gapi_tests_common.hpp"
|
||||
#include "../common/gapi_streaming_tests_common.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <tuple>
|
||||
|
||||
#include <opencv2/gapi/media.hpp>
|
||||
#include <opencv2/gapi/cpu/core.hpp>
|
||||
#include <opencv2/gapi/cpu/imgproc.hpp>
|
||||
|
||||
#include <opencv2/gapi/fluid/core.hpp>
|
||||
#include <opencv2/gapi/fluid/imgproc.hpp>
|
||||
#include <opencv2/gapi/fluid/gfluidkernel.hpp>
|
||||
|
||||
#include <opencv2/gapi/ocl/core.hpp>
|
||||
#include <opencv2/gapi/ocl/imgproc.hpp>
|
||||
|
||||
#include <opencv2/gapi/streaming/cap.hpp>
|
||||
#include <opencv2/gapi/streaming/desync.hpp>
|
||||
#include <opencv2/gapi/streaming/format.hpp>
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
|
||||
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
|
||||
#include "streaming/onevpl/file_data_provider.hpp"
|
||||
#include "streaming/onevpl/cfg_param_device_selector.hpp"
|
||||
|
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/cpu_frame_adapter.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/dx11_frame_adapter.hpp"
|
||||
#include "streaming/onevpl/accelerators/accel_policy_cpu.hpp"
|
||||
#include "streaming/onevpl/accelerators/accel_policy_dx11.hpp"
|
||||
#include "streaming/onevpl/accelerators/dx11_alloc_resource.hpp"
|
||||
#include "streaming/onevpl/accelerators/utils/shared_lock.hpp"
|
||||
#define private public
|
||||
#define protected public
|
||||
#include "streaming/onevpl/engine/decode/decode_engine_legacy.hpp"
|
||||
#include "streaming/onevpl/engine/decode/decode_session.hpp"
|
||||
|
||||
#include "streaming/onevpl/engine/preproc/preproc_engine.hpp"
|
||||
#include "streaming/onevpl/engine/preproc/preproc_session.hpp"
|
||||
#include "streaming/onevpl/engine/preproc/preproc_dispatcher.hpp"
|
||||
|
||||
#include "streaming/onevpl/engine/transcode/transcode_engine_legacy.hpp"
|
||||
#include "streaming/onevpl/engine/transcode/transcode_session.hpp"
|
||||
#undef protected
|
||||
#undef private
|
||||
#include "logger.hpp"
|
||||
|
||||
#define ALIGN16(value) (((value + 15) >> 4) << 4)
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template<class ProcessingEngine>
|
||||
cv::MediaFrame extract_decoded_frame(mfxSession sessId, ProcessingEngine& engine) {
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
ProcessingEngineBase::ExecutionStatus status = ProcessingEngineBase::ExecutionStatus::Continue;
|
||||
while (0 == engine.get_ready_frames_count() &&
|
||||
status == ProcessingEngineBase::ExecutionStatus::Continue) {
|
||||
status = engine.process(sessId);
|
||||
}
|
||||
|
||||
if (engine.get_ready_frames_count() == 0) {
|
||||
GAPI_LOG_WARNING(nullptr, "failed: cannot obtain preprocessed frames, last status: " <<
|
||||
ProcessingEngineBase::status_to_string(status));
|
||||
throw std::runtime_error("cannot finalize VPP preprocessing operation");
|
||||
}
|
||||
cv::gapi::wip::Data data;
|
||||
engine.get_frame(data);
|
||||
return cv::util::get<cv::MediaFrame>(data);
|
||||
}
|
||||
|
||||
std::tuple<mfxLoader, mfxConfig> prepare_mfx(int mfx_codec, int mfx_accel_mode) {
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
mfxLoader mfx = MFXLoad();
|
||||
mfxConfig cfg_inst_0 = MFXCreateConfig(mfx);
|
||||
EXPECT_TRUE(cfg_inst_0);
|
||||
mfxVariant mfx_param_0;
|
||||
mfx_param_0.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_0.Data.U32 = MFX_IMPL_TYPE_HARDWARE;
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)CfgParam::implementation_name(),
|
||||
mfx_param_0), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_1 = MFXCreateConfig(mfx);
|
||||
EXPECT_TRUE(cfg_inst_1);
|
||||
mfxVariant mfx_param_1;
|
||||
mfx_param_1.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_1.Data.U32 = mfx_accel_mode;
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_1,(mfxU8 *)CfgParam::acceleration_mode_name(),
|
||||
mfx_param_1), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_2 = MFXCreateConfig(mfx);
|
||||
EXPECT_TRUE(cfg_inst_2);
|
||||
mfxVariant mfx_param_2;
|
||||
mfx_param_2.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_2.Data.U32 = mfx_codec;
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_2,(mfxU8 *)CfgParam::decoder_id_name(),
|
||||
mfx_param_2), MFX_ERR_NONE);
|
||||
|
||||
mfxConfig cfg_inst_3 = MFXCreateConfig(mfx);
|
||||
EXPECT_TRUE(cfg_inst_3);
|
||||
mfxVariant mfx_param_3;
|
||||
mfx_param_3.Type = MFX_VARIANT_TYPE_U32;
|
||||
mfx_param_3.Data.U32 = MFX_EXTBUFF_VPP_SCALING;
|
||||
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_3,
|
||||
(mfxU8 *)"mfxImplDescription.mfxVPPDescription.filter.FilterFourCC",
|
||||
mfx_param_3), MFX_ERR_NONE);
|
||||
return std::make_tuple(mfx, cfg_inst_3);
|
||||
}
|
||||
|
||||
class SafeQueue {
|
||||
public:
|
||||
void push(cv::MediaFrame&& f) {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
queue.push(std::move(f));
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
cv::MediaFrame pop() {
|
||||
cv::MediaFrame ret;
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
cv.wait(lock, [this] () {
|
||||
return !queue.empty();
|
||||
});
|
||||
ret = queue.front();
|
||||
queue.pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void push_stop() {
|
||||
push(cv::MediaFrame::Create<IStopAdapter>());
|
||||
}
|
||||
|
||||
static bool is_stop(const cv::MediaFrame &f) {
|
||||
try {
|
||||
return f.get<IStopAdapter>();
|
||||
} catch(...) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
struct IStopAdapter final : public cv::MediaFrame::IAdapter {
|
||||
~IStopAdapter() {}
|
||||
cv::GFrameDesc meta() const { return {}; };
|
||||
MediaFrame::View access(MediaFrame::Access) { return {{}, {}}; };
|
||||
};
|
||||
private:
|
||||
std::condition_variable cv;
|
||||
std::mutex mutex;
|
||||
std::queue<cv::MediaFrame> queue;
|
||||
};
|
||||
|
||||
struct EmptyDataProvider : public cv::gapi::wip::onevpl::IDataProvider {
|
||||
|
||||
bool empty() const override {
|
||||
return true;
|
||||
}
|
||||
mfx_codec_id_type get_mfx_codec_id() const override {
|
||||
return std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
bool fetch_bitstream_data(std::shared_ptr<mfx_bitstream> &) override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
using source_t = std::string;
|
||||
using decoder_t = int;
|
||||
using acceleration_t = int;
|
||||
using out_frame_info_t = cv::GFrameDesc;
|
||||
using preproc_args_t = std::tuple<source_t, decoder_t, acceleration_t, out_frame_info_t>;
|
||||
|
||||
static cv::util::optional<cv::Rect> empty_roi;
|
||||
|
||||
class VPPPreprocParams : public ::testing::TestWithParam<preproc_args_t> {};
|
||||
|
||||
preproc_args_t files[] = {
|
||||
preproc_args_t {"highgui/video/big_buck_bunny.h264",
|
||||
MFX_CODEC_AVC, MFX_ACCEL_MODE_VIA_D3D11,
|
||||
cv::GFrameDesc {cv::MediaFormat::NV12, {1920, 1080}}},
|
||||
preproc_args_t {"highgui/video/big_buck_bunny.h265",
|
||||
MFX_CODEC_HEVC, MFX_ACCEL_MODE_VIA_D3D11,
|
||||
cv::GFrameDesc {cv::MediaFormat::NV12, {1920, 1280}}}
|
||||
};
|
||||
|
||||
#ifdef HAVE_DIRECTX
|
||||
#ifdef HAVE_D3D11
|
||||
TEST(OneVPL_Source_PreprocEngine, functional_single_thread)
|
||||
{
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
using namespace cv::gapi::wip;
|
||||
|
||||
std::vector<CfgParam> cfg_params_w_dx11;
|
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
|
||||
std::unique_ptr<VPLAccelerationPolicy> decode_accel_policy (
|
||||
new VPLDX11AccelerationPolicy(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11)));
|
||||
|
||||
// create file data provider
|
||||
std::string file_path = findDataFile("highgui/video/big_buck_bunny.h265");
|
||||
std::shared_ptr<IDataProvider> data_provider(new FileDataProvider(file_path,
|
||||
{CfgParam::create_decoder_id(MFX_CODEC_HEVC)}));
|
||||
|
||||
mfxLoader mfx{};
|
||||
mfxConfig mfx_cfg{};
|
||||
std::tie(mfx, mfx_cfg) = prepare_mfx(MFX_CODEC_HEVC, MFX_ACCEL_MODE_VIA_D3D11);
|
||||
|
||||
// create decode session
|
||||
mfxSession mfx_decode_session{};
|
||||
mfxStatus sts = MFXCreateSession(mfx, 0, &mfx_decode_session);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// create decode engine
|
||||
auto device_selector = decode_accel_policy->get_device_selector();
|
||||
VPLLegacyDecodeEngine decode_engine(std::move(decode_accel_policy));
|
||||
auto sess_ptr = decode_engine.initialize_session(mfx_decode_session,
|
||||
cfg_params_w_dx11,
|
||||
data_provider);
|
||||
|
||||
// simulate net info
|
||||
cv::GFrameDesc required_frame_param {cv::MediaFormat::NV12,
|
||||
{1920, 1080}};
|
||||
|
||||
// create VPP preproc engine
|
||||
VPPPreprocEngine preproc_engine(std::unique_ptr<VPLAccelerationPolicy>{
|
||||
new VPLDX11AccelerationPolicy(device_selector)});
|
||||
|
||||
// launch pipeline
|
||||
// 1) decode frame
|
||||
cv::MediaFrame first_decoded_frame;
|
||||
ASSERT_NO_THROW(first_decoded_frame = extract_decoded_frame(sess_ptr->session, decode_engine));
|
||||
cv::GFrameDesc first_frame_decoded_desc = first_decoded_frame.desc();
|
||||
|
||||
// 1.5) create preproc session based on frame description & network info
|
||||
cv::util::optional<pp_params> first_pp_params = preproc_engine.is_applicable(first_decoded_frame);
|
||||
ASSERT_TRUE(first_pp_params.has_value());
|
||||
pp_session first_pp_sess = preproc_engine.initialize_preproc(first_pp_params.value(),
|
||||
required_frame_param);
|
||||
|
||||
// 2) make preproc using incoming decoded frame & preproc session
|
||||
cv::MediaFrame first_pp_frame = preproc_engine.run_sync(first_pp_sess,
|
||||
first_decoded_frame,
|
||||
empty_roi);
|
||||
cv::GFrameDesc first_outcome_pp_desc = first_pp_frame.desc();
|
||||
ASSERT_FALSE(first_frame_decoded_desc == first_outcome_pp_desc);
|
||||
|
||||
// do not hold media frames because they share limited DX11 surface pool resources
|
||||
first_decoded_frame = cv::MediaFrame();
|
||||
first_pp_frame = cv::MediaFrame();
|
||||
|
||||
// make test in loop
|
||||
bool in_progress = false;
|
||||
size_t frames_processed_count = 1;
|
||||
const auto &first_pp_param_value_impl =
|
||||
cv::util::get<cv::gapi::wip::onevpl::vpp_pp_params>(first_pp_params.value().value);
|
||||
try {
|
||||
while(true) {
|
||||
cv::MediaFrame decoded_frame = extract_decoded_frame(sess_ptr->session, decode_engine);
|
||||
in_progress = true;
|
||||
ASSERT_EQ(decoded_frame.desc(), first_frame_decoded_desc);
|
||||
|
||||
cv::util::optional<pp_params> params = preproc_engine.is_applicable(decoded_frame);
|
||||
ASSERT_TRUE(params.has_value());
|
||||
const auto &cur_pp_param_value_impl =
|
||||
cv::util::get<cv::gapi::wip::onevpl::vpp_pp_params>(params.value().value);
|
||||
|
||||
ASSERT_EQ(first_pp_param_value_impl.handle, cur_pp_param_value_impl.handle);
|
||||
ASSERT_TRUE(FrameInfoComparator::equal_to(first_pp_param_value_impl.info, cur_pp_param_value_impl.info));
|
||||
|
||||
pp_session pp_sess = preproc_engine.initialize_preproc(params.value(),
|
||||
required_frame_param);
|
||||
ASSERT_EQ(pp_sess.get<vpp_pp_session>().handle.get(),
|
||||
first_pp_sess.get<vpp_pp_session>().handle.get());
|
||||
|
||||
cv::MediaFrame pp_frame = preproc_engine.run_sync(pp_sess,
|
||||
decoded_frame,
|
||||
empty_roi);
|
||||
cv::GFrameDesc pp_desc = pp_frame.desc();
|
||||
ASSERT_TRUE(pp_desc == first_outcome_pp_desc);
|
||||
in_progress = false;
|
||||
frames_processed_count++;
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
// test if interruption has happened
|
||||
ASSERT_FALSE(in_progress);
|
||||
ASSERT_NE(frames_processed_count, 1);
|
||||
}
|
||||
|
||||
void decode_function(cv::gapi::wip::onevpl::VPLLegacyDecodeEngine &decode_engine,
|
||||
cv::gapi::wip::onevpl::ProcessingEngineBase::session_ptr sess_ptr,
|
||||
SafeQueue &queue, size_t &decoded_number) {
|
||||
// decode first frame
|
||||
{
|
||||
cv::MediaFrame decoded_frame;
|
||||
ASSERT_NO_THROW(decoded_frame = extract_decoded_frame(sess_ptr->session, decode_engine));
|
||||
queue.push(std::move(decoded_frame));
|
||||
}
|
||||
|
||||
// launch pipeline
|
||||
try {
|
||||
while(true) {
|
||||
queue.push(extract_decoded_frame(sess_ptr->session, decode_engine));
|
||||
decoded_number++;
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
// send stop
|
||||
queue.push_stop();
|
||||
}
|
||||
|
||||
void preproc_function(cv::gapi::wip::IPreprocEngine &preproc_engine, SafeQueue&queue,
|
||||
size_t &preproc_number, const out_frame_info_t &required_frame_param,
|
||||
const cv::util::optional<cv::Rect> &roi_rect = {}) {
|
||||
using namespace cv::gapi::wip;
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
// create preproc session based on frame description & network info
|
||||
cv::MediaFrame first_decoded_frame = queue.pop();
|
||||
cv::util::optional<pp_params> first_pp_params = preproc_engine.is_applicable(first_decoded_frame);
|
||||
ASSERT_TRUE(first_pp_params.has_value());
|
||||
pp_session first_pp_sess =
|
||||
preproc_engine.initialize_preproc(first_pp_params.value(),
|
||||
required_frame_param);
|
||||
|
||||
// make preproc using incoming decoded frame & preproc session
|
||||
cv::MediaFrame first_pp_frame = preproc_engine.run_sync(first_pp_sess,
|
||||
first_decoded_frame,
|
||||
roi_rect);
|
||||
cv::GFrameDesc first_outcome_pp_desc = first_pp_frame.desc();
|
||||
|
||||
// do not hold media frames because they share limited DX11 surface pool resources
|
||||
first_decoded_frame = cv::MediaFrame();
|
||||
first_pp_frame = cv::MediaFrame();
|
||||
|
||||
// launch pipeline
|
||||
bool in_progress = false;
|
||||
// let's allow counting of preprocessed frames to check this value later:
|
||||
// Currently, it looks redundant to implement any kind of graceful shutdown logic
|
||||
// in this test - so let's apply agreement that media source is processed
|
||||
// successfully when preproc_number != 1 in result.
|
||||
// Specific validation logic which adhere to explicit counter value may be implemented
|
||||
// in particular test scope
|
||||
preproc_number = 1;
|
||||
try {
|
||||
while(true) {
|
||||
cv::MediaFrame decoded_frame = queue.pop();
|
||||
if (SafeQueue::is_stop(decoded_frame)) {
|
||||
break;
|
||||
}
|
||||
in_progress = true;
|
||||
|
||||
cv::util::optional<pp_params> params = preproc_engine.is_applicable(decoded_frame);
|
||||
ASSERT_TRUE(params.has_value());
|
||||
const auto &vpp_params = params.value().get<vpp_pp_params>();
|
||||
const auto &first_vpp_params = first_pp_params.value().get<vpp_pp_params>();
|
||||
ASSERT_EQ(vpp_params.handle, first_vpp_params.handle);
|
||||
ASSERT_TRUE(0 == memcmp(&vpp_params.info, &first_vpp_params.info, sizeof(mfxFrameInfo)));
|
||||
|
||||
pp_session pp_sess = preproc_engine.initialize_preproc(params.value(),
|
||||
required_frame_param);
|
||||
ASSERT_EQ(pp_sess.get<vpp_pp_session>().handle.get(),
|
||||
first_pp_sess.get<vpp_pp_session>().handle.get());
|
||||
|
||||
cv::MediaFrame pp_frame = preproc_engine.run_sync(pp_sess, decoded_frame, empty_roi);
|
||||
cv::GFrameDesc pp_desc = pp_frame.desc();
|
||||
ASSERT_TRUE(pp_desc == first_outcome_pp_desc);
|
||||
in_progress = false;
|
||||
preproc_number++;
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
// test if interruption has happened
|
||||
ASSERT_FALSE(in_progress);
|
||||
ASSERT_NE(preproc_number, 1);
|
||||
}
|
||||
|
||||
void multi_source_preproc_function(size_t source_num,
|
||||
cv::gapi::wip::IPreprocEngine &preproc_engine, SafeQueue&queue,
|
||||
size_t &preproc_number, const out_frame_info_t &required_frame_param,
|
||||
const cv::util::optional<cv::Rect> &roi_rect = {}) {
|
||||
using namespace cv::gapi::wip;
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
// create preproc session based on frame description & network info
|
||||
cv::MediaFrame first_decoded_frame = queue.pop();
|
||||
cv::util::optional<pp_params> first_pp_params = preproc_engine.is_applicable(first_decoded_frame);
|
||||
ASSERT_TRUE(first_pp_params.has_value());
|
||||
pp_session first_pp_sess =
|
||||
preproc_engine.initialize_preproc(first_pp_params.value(),
|
||||
required_frame_param);
|
||||
|
||||
// make preproc using incoming decoded frame & preproc session
|
||||
cv::MediaFrame first_pp_frame = preproc_engine.run_sync(first_pp_sess,
|
||||
first_decoded_frame,
|
||||
roi_rect);
|
||||
cv::GFrameDesc first_outcome_pp_desc = first_pp_frame.desc();
|
||||
|
||||
// do not hold media frames because they share limited DX11 surface pool resources
|
||||
first_decoded_frame = cv::MediaFrame();
|
||||
first_pp_frame = cv::MediaFrame();
|
||||
|
||||
// launch pipeline
|
||||
bool in_progress = false;
|
||||
preproc_number = 1;
|
||||
size_t received_stop_count = 0;
|
||||
try {
|
||||
while(received_stop_count != source_num) {
|
||||
cv::MediaFrame decoded_frame = queue.pop();
|
||||
if (SafeQueue::is_stop(decoded_frame)) {
|
||||
++received_stop_count;
|
||||
continue;
|
||||
}
|
||||
in_progress = true;
|
||||
|
||||
cv::util::optional<pp_params> params = preproc_engine.is_applicable(decoded_frame);
|
||||
ASSERT_TRUE(params.has_value());
|
||||
|
||||
pp_session pp_sess = preproc_engine.initialize_preproc(params.value(),
|
||||
required_frame_param);
|
||||
cv::MediaFrame pp_frame = preproc_engine.run_sync(pp_sess, decoded_frame, empty_roi);
|
||||
cv::GFrameDesc pp_desc = pp_frame.desc();
|
||||
ASSERT_TRUE(pp_desc == first_outcome_pp_desc);
|
||||
in_progress = false;
|
||||
decoded_frame = cv::MediaFrame();
|
||||
preproc_number++;
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
GAPI_LOG_WARNING(nullptr, "Caught exception in preproc worker: " << ex.what());
|
||||
}
|
||||
|
||||
// test if interruption has happened
|
||||
if (in_progress) {
|
||||
while (true) {
|
||||
cv::MediaFrame decoded_frame = queue.pop();
|
||||
if (SafeQueue::is_stop(decoded_frame)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_FALSE(in_progress);
|
||||
ASSERT_NE(preproc_number, 1);
|
||||
}
|
||||
using roi_t = cv::util::optional<cv::Rect>;
|
||||
using preproc_roi_args_t = decltype(std::tuple_cat(std::declval<preproc_args_t>(),
|
||||
std::declval<std::tuple<roi_t>>()));
|
||||
class VPPPreprocROIParams : public ::testing::TestWithParam<preproc_roi_args_t> {};
|
||||
TEST_P(VPPPreprocROIParams, functional_roi_different_threads)
|
||||
{
|
||||
using namespace cv::gapi::wip;
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
source_t file_path;
|
||||
decoder_t decoder_id;
|
||||
acceleration_t accel;
|
||||
out_frame_info_t required_frame_param;
|
||||
roi_t opt_roi;
|
||||
std::tie(file_path, decoder_id, accel, required_frame_param, opt_roi) = GetParam();
|
||||
|
||||
file_path = findDataFile(file_path);
|
||||
|
||||
std::vector<CfgParam> cfg_params_w_dx11;
|
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(accel));
|
||||
std::unique_ptr<VPLAccelerationPolicy> decode_accel_policy (
|
||||
new VPLDX11AccelerationPolicy(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11)));
|
||||
|
||||
// create file data provider
|
||||
std::shared_ptr<IDataProvider> data_provider(new FileDataProvider(file_path,
|
||||
{CfgParam::create_decoder_id(decoder_id)}));
|
||||
|
||||
mfxLoader mfx{};
|
||||
mfxConfig mfx_cfg{};
|
||||
std::tie(mfx, mfx_cfg) = prepare_mfx(decoder_id, accel);
|
||||
|
||||
// create decode session
|
||||
mfxSession mfx_decode_session{};
|
||||
mfxStatus sts = MFXCreateSession(mfx, 0, &mfx_decode_session);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// create decode engine
|
||||
auto device_selector = decode_accel_policy->get_device_selector();
|
||||
VPLLegacyDecodeEngine decode_engine(std::move(decode_accel_policy));
|
||||
auto sess_ptr = decode_engine.initialize_session(mfx_decode_session,
|
||||
cfg_params_w_dx11,
|
||||
data_provider);
|
||||
|
||||
// create VPP preproc engine
|
||||
VPPPreprocEngine preproc_engine(std::unique_ptr<VPLAccelerationPolicy>{
|
||||
new VPLDX11AccelerationPolicy(device_selector)});
|
||||
|
||||
// launch threads
|
||||
SafeQueue queue;
|
||||
size_t decoded_number = 1;
|
||||
size_t preproc_number = 0;
|
||||
|
||||
std::thread decode_thread(decode_function, std::ref(decode_engine), sess_ptr,
|
||||
std::ref(queue), std::ref(decoded_number));
|
||||
std::thread preproc_thread(preproc_function, std::ref(preproc_engine),
|
||||
std::ref(queue), std::ref(preproc_number),
|
||||
std::cref(required_frame_param),
|
||||
std::cref(opt_roi));
|
||||
|
||||
decode_thread.join();
|
||||
preproc_thread.join();
|
||||
ASSERT_EQ(preproc_number, decoded_number);
|
||||
}
|
||||
|
||||
preproc_roi_args_t files_w_roi[] = {
|
||||
preproc_roi_args_t {"highgui/video/big_buck_bunny.h264",
|
||||
MFX_CODEC_AVC, MFX_ACCEL_MODE_VIA_D3D11,
|
||||
out_frame_info_t{cv::GFrameDesc {cv::MediaFormat::NV12, {1920, 1080}}},
|
||||
roi_t{cv::Rect{0,0,50,50}}},
|
||||
preproc_roi_args_t {"highgui/video/big_buck_bunny.h264",
|
||||
MFX_CODEC_AVC, MFX_ACCEL_MODE_VIA_D3D11,
|
||||
out_frame_info_t{cv::GFrameDesc {cv::MediaFormat::NV12, {1920, 1080}}},
|
||||
roi_t{}},
|
||||
preproc_roi_args_t {"highgui/video/big_buck_bunny.h264",
|
||||
MFX_CODEC_AVC, MFX_ACCEL_MODE_VIA_D3D11,
|
||||
out_frame_info_t{cv::GFrameDesc {cv::MediaFormat::NV12, {1920, 1080}}},
|
||||
roi_t{cv::Rect{0,0,100,100}}},
|
||||
preproc_roi_args_t {"highgui/video/big_buck_bunny.h264",
|
||||
MFX_CODEC_AVC, MFX_ACCEL_MODE_VIA_D3D11,
|
||||
out_frame_info_t{cv::GFrameDesc {cv::MediaFormat::NV12, {1920, 1080}}},
|
||||
roi_t{cv::Rect{100,100,200,200}}},
|
||||
preproc_roi_args_t {"highgui/video/big_buck_bunny.h265",
|
||||
MFX_CODEC_HEVC, MFX_ACCEL_MODE_VIA_D3D11,
|
||||
out_frame_info_t{cv::GFrameDesc {cv::MediaFormat::NV12, {1920, 1280}}},
|
||||
roi_t{cv::Rect{0,0,100,100}}},
|
||||
preproc_roi_args_t {"highgui/video/big_buck_bunny.h265",
|
||||
MFX_CODEC_HEVC, MFX_ACCEL_MODE_VIA_D3D11,
|
||||
out_frame_info_t{cv::GFrameDesc {cv::MediaFormat::NV12, {1920, 1280}}},
|
||||
roi_t{}},
|
||||
preproc_roi_args_t {"highgui/video/big_buck_bunny.h265",
|
||||
MFX_CODEC_HEVC, MFX_ACCEL_MODE_VIA_D3D11,
|
||||
out_frame_info_t{cv::GFrameDesc {cv::MediaFormat::NV12, {1920, 1280}}},
|
||||
roi_t{cv::Rect{100,100,200,200}}}
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(OneVPL_Source_PreprocEngineROI, VPPPreprocROIParams,
|
||||
testing::ValuesIn(files_w_roi));
|
||||
|
||||
|
||||
using VPPInnerPreprocParams = VPPPreprocParams;
|
||||
TEST_P(VPPInnerPreprocParams, functional_inner_preproc_size)
|
||||
{
|
||||
using namespace cv::gapi::wip;
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
source_t file_path;
|
||||
decoder_t decoder_id;
|
||||
acceleration_t accel;
|
||||
out_frame_info_t required_frame_param;
|
||||
std::tie(file_path, decoder_id, accel, required_frame_param) = GetParam();
|
||||
|
||||
file_path = findDataFile(file_path);
|
||||
|
||||
std::vector<CfgParam> cfg_params_w_dx11_vpp;
|
||||
|
||||
// create accel policy
|
||||
cfg_params_w_dx11_vpp.push_back(CfgParam::create_acceleration_mode(accel));
|
||||
std::unique_ptr<VPLAccelerationPolicy> accel_policy (
|
||||
new VPLDX11AccelerationPolicy(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11_vpp)));
|
||||
|
||||
// create file data provider
|
||||
std::shared_ptr<IDataProvider> data_provider(new FileDataProvider(file_path,
|
||||
{CfgParam::create_decoder_id(decoder_id)}));
|
||||
|
||||
// create decode session
|
||||
mfxLoader mfx{};
|
||||
mfxConfig mfx_cfg{};
|
||||
std::tie(mfx, mfx_cfg) = prepare_mfx(decoder_id, accel);
|
||||
|
||||
mfxSession mfx_decode_session{};
|
||||
mfxStatus sts = MFXCreateSession(mfx, 0, &mfx_decode_session);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// fill vpp params beforehand: resolution
|
||||
cfg_params_w_dx11_vpp.push_back(CfgParam::create_vpp_out_width(
|
||||
static_cast<uint16_t>(required_frame_param.size.width)));
|
||||
cfg_params_w_dx11_vpp.push_back(CfgParam::create_vpp_out_height(
|
||||
static_cast<uint16_t>(required_frame_param.size.height)));
|
||||
|
||||
// create transcode engine
|
||||
auto device_selector = accel_policy->get_device_selector();
|
||||
VPLLegacyTranscodeEngine engine(std::move(accel_policy));
|
||||
auto sess_ptr = engine.initialize_session(mfx_decode_session,
|
||||
cfg_params_w_dx11_vpp,
|
||||
data_provider);
|
||||
// make test in loop
|
||||
bool in_progress = false;
|
||||
size_t frames_processed_count = 1;
|
||||
try {
|
||||
while(true) {
|
||||
cv::MediaFrame decoded_frame = extract_decoded_frame(sess_ptr->session, engine);
|
||||
in_progress = true;
|
||||
ASSERT_EQ(decoded_frame.desc().size.width,
|
||||
ALIGN16(required_frame_param.size.width));
|
||||
ASSERT_EQ(decoded_frame.desc().size.height,
|
||||
ALIGN16(required_frame_param.size.height));
|
||||
ASSERT_EQ(decoded_frame.desc().fmt, required_frame_param.fmt);
|
||||
frames_processed_count++;
|
||||
in_progress = false;
|
||||
}
|
||||
} catch (...) {}
|
||||
|
||||
// test if interruption has happened
|
||||
ASSERT_FALSE(in_progress);
|
||||
ASSERT_NE(frames_processed_count, 1);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(OneVPL_Source_PreprocInner, VPPInnerPreprocParams,
|
||||
testing::ValuesIn(files));
|
||||
|
||||
// Dispatcher test suite
|
||||
class VPPPreprocDispatcherROIParams : public ::testing::TestWithParam<preproc_roi_args_t> {};
|
||||
TEST_P(VPPPreprocDispatcherROIParams, functional_roi_different_threads)
|
||||
{
|
||||
using namespace cv::gapi::wip;
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
source_t file_path;
|
||||
decoder_t decoder_id;
|
||||
acceleration_t accel = MFX_ACCEL_MODE_VIA_D3D11;
|
||||
out_frame_info_t required_frame_param;
|
||||
roi_t opt_roi;
|
||||
std::tie(file_path, decoder_id, std::ignore, required_frame_param, opt_roi) = GetParam();
|
||||
|
||||
file_path = findDataFile(file_path);
|
||||
|
||||
std::vector<CfgParam> cfg_params_w_dx11;
|
||||
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(accel));
|
||||
std::unique_ptr<VPLAccelerationPolicy> decode_accel_policy (
|
||||
new VPLDX11AccelerationPolicy(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11)));
|
||||
|
||||
// create file data provider
|
||||
std::shared_ptr<IDataProvider> data_provider(new FileDataProvider(file_path,
|
||||
{CfgParam::create_decoder_id(decoder_id)}));
|
||||
std::shared_ptr<IDataProvider> cpu_data_provider(new FileDataProvider(file_path,
|
||||
{CfgParam::create_decoder_id(decoder_id)}));
|
||||
|
||||
mfxLoader mfx{};
|
||||
mfxConfig mfx_cfg{};
|
||||
std::tie(mfx, mfx_cfg) = prepare_mfx(decoder_id, accel);
|
||||
|
||||
// create decode session
|
||||
mfxSession mfx_decode_session{};
|
||||
mfxStatus sts = MFXCreateSession(mfx, 0, &mfx_decode_session);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
mfxSession mfx_cpu_decode_session{};
|
||||
sts = MFXCreateSession(mfx, 0, &mfx_cpu_decode_session);
|
||||
EXPECT_EQ(MFX_ERR_NONE, sts);
|
||||
|
||||
// create decode engines
|
||||
auto device_selector = decode_accel_policy->get_device_selector();
|
||||
VPLLegacyDecodeEngine decode_engine(std::move(decode_accel_policy));
|
||||
auto sess_ptr = decode_engine.initialize_session(mfx_decode_session,
|
||||
cfg_params_w_dx11,
|
||||
data_provider);
|
||||
std::vector<CfgParam> cfg_params_cpu;
|
||||
auto cpu_device_selector = std::make_shared<CfgParamDeviceSelector>(cfg_params_cpu);
|
||||
VPLLegacyDecodeEngine cpu_decode_engine(std::unique_ptr<VPLAccelerationPolicy>{
|
||||
new VPLCPUAccelerationPolicy(cpu_device_selector)});
|
||||
auto cpu_sess_ptr = cpu_decode_engine.initialize_session(mfx_cpu_decode_session,
|
||||
cfg_params_cpu,
|
||||
cpu_data_provider);
|
||||
|
||||
// create VPP preproc engines
|
||||
VPPPreprocDispatcher preproc_dispatcher;
|
||||
preproc_dispatcher.insert_worker<VPPPreprocEngine>(std::unique_ptr<VPLAccelerationPolicy>{
|
||||
new VPLDX11AccelerationPolicy(device_selector)});
|
||||
preproc_dispatcher.insert_worker<VPPPreprocEngine>(std::unique_ptr<VPLAccelerationPolicy>{
|
||||
new VPLCPUAccelerationPolicy(cpu_device_selector)});
|
||||
|
||||
// launch threads
|
||||
SafeQueue queue;
|
||||
size_t decoded_number = 1;
|
||||
size_t cpu_decoded_number = 1;
|
||||
size_t preproc_number = 0;
|
||||
|
||||
std::thread decode_thread(decode_function, std::ref(decode_engine), sess_ptr,
|
||||
std::ref(queue), std::ref(decoded_number));
|
||||
std::thread cpu_decode_thread(decode_function, std::ref(cpu_decode_engine), cpu_sess_ptr,
|
||||
std::ref(queue), std::ref(cpu_decoded_number));
|
||||
std::thread preproc_thread(multi_source_preproc_function,
|
||||
preproc_dispatcher.size(),
|
||||
std::ref(preproc_dispatcher),
|
||||
std::ref(queue), std::ref(preproc_number),
|
||||
std::cref(required_frame_param),
|
||||
std::cref(opt_roi));
|
||||
|
||||
decode_thread.join();
|
||||
cpu_decode_thread.join();
|
||||
preproc_thread.join();
|
||||
ASSERT_EQ(preproc_number, decoded_number + cpu_decoded_number);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(OneVPL_Source_PreprocDispatcherROI, VPPPreprocDispatcherROIParams,
|
||||
testing::ValuesIn(files_w_roi));
|
||||
|
||||
#endif // HAVE_DIRECTX
|
||||
#endif // HAVE_D3D11
|
||||
} // namespace opencv_test
|
||||
#endif // HAVE_ONEVPL
|
||||
Reference in New Issue
Block a user