8000 G-API gst source gray support by dbudniko · Pull Request #21560 · opencv/opencv · GitHub
[go: up one dir, main page]

Skip to content

G-API gst source gray support #21560

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
e0cb364
gray draft
Jan 25, 2022
a7e0ea8
Merge remote-tracking branch 'origin/4.x' into dbudniko/gapi_media_fo…
Jan 25, 2022
a5956e6
remove uv_plane from gray code path
Jan 25, 2022
198e6e1
trying to address comments from Asya (accessors are modified)
Jan 27, 2022
52adfdc
try to push one more time
Jan 27, 2022
987ce91
address more comments from Asya and Sergey
Jan 27, 2022
bd796c8
add gray to streaming tests
Jan 27, 2022
6795ecf
some gray source corrections and copy gray frame
Jan 27, 2022
10bc6fd
try to fix copy frame gray test
Jan 27, 2022
338473e
try to add reshape gray test
Jan 27, 2022
76a6735
fix test source
Jan 27, 2022
3fc50fa
disable reshape gray test
Jan 27, 2022
1886642
debug prints
Jan 28, 2022
7a308cb
Merge branch 'dbudniko/gapi_media_format_gray' of github.com:dbudniko…
Jan 28, 2022
e7e98ec
try to convert BGR to gray
Jan 28, 2022
10d6b76
roll back
Jan 28, 2022
8e83d55
try to fix gray reshape test
Jan 28, 2022
add328f
clean up
Jan 28, 2022
7983d37
try bgr to gray again
Jan 28, 2022
7f3fdb7
try to add media frame tests
Jan 28, 2022
da64f69
size media frame gray test
Jan 28, 2022
8446626
more comments are addressed
Jan 31, 2022
f74f205
rmat on mat adapter
Jan 31, 2022
1fae2d0
more streaming tests
Jan 31, 2022
f8a0dca
try to add more test instances
Jan 31, 2022
155a2cd
try to fix accuracy
Jan 31, 2022
1884dd0
remove source type gray
Jan 31, 2022
d89a8d4
streaming tests fix - source type gray
Jan 31, 2022
a272fe1
fix streaming test logic
Jan 31, 2022
e025398
try to fix test
Jan 31, 2022
22282c9
clean up
Jan 31, 2022
0ce365f
return back single flag
Jan 31, 2022
0153a46
remove redundant coma
Feb 1, 2022
273d007
fix assert to fix debug tests run
Feb 1, 2022
d5f6a53
draft to test build
Feb 2, 2022
ba0ad34
build fixed
Feb 2, 2022
02e1acd
some clean up and formatting
Feb 2, 2022
68dcd3f
tests are fixed
Feb 3, 2022
bfeeea3
CAPS suggestion from Asya is added - build OK tests OK
Feb 3, 2022
4edd04f
media adapter gray logic draft
Feb 3, 2022
93248ca
try to fix build
Feb 3, 2022
86048f7
try to fix BGR warning. Not clear how to do it properly
Feb 3, 2022
08bc99d
Merge remote-tracking branch 'origin/4.x' into dbudniko/gapi_media_fo…
Feb 3, 2022
bc36b0a
more offsets and pointers
Feb 3, 2022
270e827
try to fix build
Feb 3, 2022
ad74b03
try to add separate nv12 and gray8 tests
Feb 3, 2022
81a2bb3
try to fix tests
Feb 3, 2022
181adbe
try to fix tests build
Feb 3, 2022
3fc47e9
one more attempt to fix kernel
Feb 3, 2022
630a365
try to 8000 enable GRAY8 test
Feb 3, 2022
04d495a
try to fix gray8 test
Feb 3, 2022
436b083
more attempts
Feb 3, 2022
cc70cfe
more fixes
Feb 3, 2022
0a27161
further extension of tests
Feb 3, 2022
898c60b
more tests
Feb 3, 2022
9961c68
try to add multisource tests
Feb 3, 2022
41212cb
clean up and try to use default in switches
Feb 3, 2022
48d4ce2
more clean-ups
Feb 3, 2022
8306134
NV12 check
Feb 4, 2022
487f9b0
try to fix build and clean up
Feb 4, 2022
574ac9a
compile args fix
Feb 4, 2022
561cd42
build fixed
Feb 4, 2022
aa2d906
fix logic
Feb 4, 2022
c1e191a
try to fix computation
Feb 4, 2022
d7c8cce
build ok tests ok
Feb 4, 2022
9b2a150
refactor tests
Feb 4, 2022
ab338ef
clean up
Feb 4, 2022
29e8acb
assert fix
Feb 4, 2022
be281dd
more comments are addressed
Feb 7, 2022
7e310a6
Address comments from Orest
Feb 7, 2022
fe2927d
roll back
Feb 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ namespace gst {
* Pipeline can actually contain many sink elements, but it must have one and only one
* appsink among them.
*
* - data passed to appsink should be video-frame in NV12 format.
* - data passed to appsink should be video-frame in NV12 or GRAY8 format.
*
* 'outputType' is used to select type of output data to produce: 'cv::MediaFrame' or 'cv::Mat'.
* To produce 'cv::MediaFrame'-s you need to pass 'GStreamerSource::OutputType::FRAME' and,
* correspondingly, 'GStreamerSource::OutputType::MAT' to produce 'cv::Mat'-s.
* Please note, that in the last case, output 'cv::Mat' will be of BGR format, internal conversion
* from NV12 GStreamer data will happen.
* from NV12 / GRAY8 GStreamer data will happen.
* Default value for 'outputType' is 'GStreamerSource::OutputType::MAT'.
*
* @note Stream sources are passed to G-API via shared pointers, so please use gapi::make_src<>
Expand Down
105 changes: 82 additions & 23 deletions modules/gapi/src/streaming/gstreamer/gstreamer_media_adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,41 @@ GStreamerMediaAdapter::GStreamerMediaAdapter(const cv::GFrameDesc& frameDesc,

GstVideoMeta* videoMeta = gst_buffer_get_video_meta(m_buffer);
if (videoMeta != nullptr) {
m_strides = { videoMeta->stride[0], videoMeta->stride[1] };
m_offsets = { videoMeta->offset[0], videoMeta->offset[1] };
switch (m_frameDesc.fmt) {
case cv::MediaFormat::NV12: {
m_strides = { videoMeta->stride[0], videoMeta->stride[1] };
m_offsets = { videoMeta->offset[0], videoMeta->offset[1] };
break;
}
case cv::MediaFormat::GRAY: {
m_strides = { videoMeta->stride[0]};
m_offsets = { videoMeta->offset[0]};
break;
}
default: {
GAPI_Assert(false && "Non NV12 or GRAY Media format is not expected here");
break;
}
}
} else {
m_strides = { GST_VIDEO_INFO_PLANE_STRIDE(m_videoInfo.get(), 0),
GST_VIDEO_INFO_PLANE_STRIDE(m_videoInfo.get(), 1) };
m_offsets = { GST_VIDEO_INFO_PLANE_OFFSET(m_videoInfo.get(), 0),
GST_VIDEO_INFO_PLANE_OFFSET(m_videoInfo.get(), 1) };
switch (m_frameDesc.fmt) {
case cv::MediaFormat::NV12: {
m_strides = { GST_VIDEO_INFO_PLANE_STRIDE(m_videoInfo.get(), 0),
GST_VIDEO_INFO_PLANE_STRIDE(m_videoInfo.get(), 1) };
m_offsets = { GST_VIDEO_INFO_PLANE_OFFSET(m_videoInfo.get(), 0),
GST_VIDEO_INFO_PLANE_OFFSET(m_videoInfo.get(), 1) };
break;
}
case cv::MediaFormat::GRAY: {
m_strides = { GST_VIDEO_INFO_PLANE_STRIDE(m_videoInfo.get(), 0)};
m_offsets = { GST_VIDEO_INFO_PLANE_OFFSET(m_videoInfo.get(), 0)};
break;
}
default: {
GAPI_Assert(false && "Non NV12 or GRAY Media format is not expected here");
break;
}
}
}
}

Expand Down Expand Up @@ -71,8 +99,10 @@ cv::MediaFrame::View GStreamerMediaAdapter::access(cv::MediaFrame::Access access

if(!m_isMapped.load(std::memory_order_relaxed)) {

GAPI_Assert(GST_VIDEO_INFO_N_PLANES(m_videoInfo.get()) == 2);
GAPI_Assert(GST_VIDEO_INFO_FORMAT(m_videoInfo.get()) == GST_VIDEO_FORMAT_NV12);
GAPI_Assert(GST_VIDEO_INFO_N_PLANES(m_videoInfo.get()) == 2 ||
GST_VIDEO_INFO_N_PLANES(m_videoInfo.get()) == 1);
GAPI_Assert(GST_VIDEO_INFO_FORMAT(m_videoInfo.get()) == GST_VIDEO_FORMAT_NV12 ||
GST_VIDEO_INFO_FORMAT(m_videoInfo.get()) == GST_VIDEO_FORMAT_GRAY8);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, these asserts above should be combined, like

GAPI_Assert((GST_VIDEO_INFO_N_PLANES(m_videoInfo.get()) == 2 &&
                    GST_VIDEO_INFO_FORMAT(m_videoInfo.get()) == GST_VIDEO_FORMAT_NV12)
                          ||
                    (GST_VIDEO_INFO_N_PLANES(m_videoInfo.get()) == 1 &&
                    GST_VIDEO_INFO_FORMAT(m_videoInfo.get()) == GST_VIDEO_FORMAT_GRAY8));

But perhaps it looks too heavy


// TODO: Use RAII for map/unmap
if (access == cv::MediaFrame::Access::W) {
Expand All @@ -85,27 +115,56 @@ cv::MediaFrame::View GStreamerMediaAdapter::access(cv::MediaFrame::Access access
}

GAPI_Assert(GST_VIDEO_FRAME_PLANE_STRIDE(&m_videoFrame, 0) == m_strides[0]);
GAPI_Assert(GST_VIDEO_FRAME_PLANE_STRIDE(&m_videoFrame, 1) == m_strides[1]);
GAPI_Assert(GST_VIDEO_FRAME_PLANE_OFFSET(&m_videoFrame, 0) == m_offsets[0]);
GAPI_Assert(GST_VIDEO_FRAME_PLANE_OFFSET(&m_videoFrame, 1) == m_offsets[1]);
if (m_frameDesc.fmt == cv::MediaFormat::NV12) {
GAPI_Assert(GST_VIDEO_FRAME_PLANE_STRIDE(&m_videoFrame, 1) == m_strides[1]);
GAPI_Assert(GST_VIDEO_FRAME_PLANE_OFFSET(&m_videoFrame, 1) == m_offsets[1]);
}

m_isMapped.store(true, std::memory_order_release);
}
}

cv::MediaFrame::View::Ptrs ps {
static_cast<uint8_t*>(GST_VIDEO_FRAME_PLANE_DATA(&m_videoFrame, 0)) + m_offsets[0], // Y-plane
static_cast<uint8_t*>(GST_VIDEO_FRAME_PLANE_DATA(&m_videoFrame, 0)) + m_offsets[1], // UV-plane
nullptr,
nullptr
};

cv::MediaFrame::View::Strides ss = {
static_cast<std::size_t>(m_strides[0]), // Y-plane stride
static_cast<std::size_t>(m_strides[1]), // UV-plane stride
0u,
0u
};
cv::MediaFrame::View::Ptrs ps;
cv::MediaFrame::View::Strides ss;

switch (m_frameDesc.fmt) {
case cv::MediaFormat::NV12: {
ps = {
static_cast<uint8_t*>(GST_VIDEO_FRAME_PLANE_DATA(&m_videoFrame, 0)) + m_offsets[0], // Y-plane
static_cast<uint8_t*>(GST_VIDEO_FRAME_PLANE_DATA(&m_videoFrame, 0)) + m_offsets[1], // UV-plane
nullptr,
nullptr
};
ss = {
static_cast<std::size_t>(m_strides[0]), // Y-plane stride
static_cast<std::size_t>(m_strides[1]), // UV-plane stride
0u,
0u
};
break;
}
case cv::MediaFormat::GRAY: {
ps = {
static_cast<uint8_t*>(GST_VIDEO_FRAME_PLANE_DATA(&m_videoFrame, 0)) + m_offsets[0], // Y-plane
nullptr,
nullptr,
nullptr
};
ss = {
static_cast<std::size_t>(m_strides[0]), // Y-plane stride
0u,
0u,
0u
};
break;
}
default: {
GAPI_Assert(false && "Non NV12 or GRAY Media format is not expected here");
break;
}
}


--thread_counters;
return cv::MediaFrame::View(std::move(ps), std::move(ss));
Expand Down
87 changes: 59 additions & 28 deletions modules/gapi/src/streaming/gstreamer/gstreamersource.cpp
< 8000 tr data-hunk="bad5379844ae76103fc8f149aaeb0cf06c726c979a712541aa633563bb987a2c" class="show-top-border">
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ namespace gst {

#ifdef HAVE_GSTREAMER

constexpr char NV12_CAPS_STRING[] =
"video/x-raw,format=NV12;video/x-raw(memory:DMABuf),format=NV12";
constexpr char ALLOWED_CAPS_STRING[] =
"video/x-raw,format=(string){NV12, GRAY8};video/x-raw(memory:DMABuf),format=(string){NV12, GRAY8}";


namespace {
GstPadProbeReturn appsinkQueryCallback(GstPad*, GstPadProbeInfo* info, gpointer)
Expand Down Expand Up @@ -137,17 +138,17 @@ void GStreamerSource::Priv::configureAppsink() {
// Do not emit signals: all calls will be synchronous and blocking.
gst_app_sink_set_emit_signals(GST_APP_SINK(m_appsink.get()), FALSE);

GStreamerPtr<GstCaps> nv12Caps(gst_caps_from_string(NV12_CAPS_STRING));
GStreamerPtr<GstCaps> gstCaps(gst_caps_from_string(ALLOWED_CAPS_STRING));

GStreamerPtr<GstPad> appsinkPad(gst_element_get_static_pad(m_appsink, "sink"));
GStreamerPtr<GstCaps> peerCaps(gst_pad_peer_query_caps(appsinkPad, NULL));
if (!gst_caps_can_intersect(peerCaps, nv12Caps)) {
if (!gst_caps_can_intersect(peerCaps, gstCaps)) {
cv::util::throw_error(
std::logic_error("appsink element can only consume video-frame in NV12 format in "
std::logic_error("appsink element can only consume video-frame in NV12 or GRAY8 format in "
"GStreamerSource"));
}

gst_app_sink_set_caps(GST_APP_SINK(m_appsink.get()), nv12Caps);
gst_app_sink_set_caps(GST_APP_SINK(m_appsink.get()), gstCaps);

gst_pad_add_probe(appsinkPad, GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM, appsinkQueryCallback,
NULL, NULL);
Expand Down Expand Up @@ -184,10 +185,29 @@ void GStreamerSource::Priv::prepareVideoMeta()
cv::util::throw_error(std::logic_error("Cannot query video width/height."));
}

// Fill GstVideoInfo structure to work further with GstVideoFrame class.
if (!gst_video_info_from_caps(&m_videoInfo, prerollCaps)) {
cv::util::throw_error(std::logic_error("preroll sample has invalid caps."));
}
m_type = GST_VIDEO_INFO_FORMAT(&m_videoInfo);
switch(m_outputType) {
case GStreamerSource::OutputType::FRAME: {
// Construct metadata for media frame.
m_mediaFrameMeta = GFrameDesc { cv::MediaFormat::NV12, cv::Size(width, height) };
switch (m_type) {
case GST_VIDEO_FORMAT_NV12: {
m_mediaFrameMeta = GFrameDesc{ cv::MediaFormat::NV12, cv::Size(width, height) };
GAPI_Assert(GST_VIDEO_INFO_N_PLANES(&m_videoInfo) == 2);
break;
}
case GST_VIDEO_FORMAT_GRAY8: {
m_mediaFrameMeta = GFrameDesc{ cv::MediaFormat::GRAY, cv::Size(width, height) };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so is it GRAY or GRAY8? I believe I've seen GRAY8 somewhere in the doxygen comments (and I believe it is quite legit)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are different Gst gray formats. GRAY8 GRAY16. MediaFormat GRAY assumes 8-bit integer numbers. Should we align our naming approach with Gst. I have some doubts that 16 bit will be asked by someone.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some doubts that 16 bit will be asked by someone.

It seem to be useful for some scenarios, see #18694. Furthermore, there are two variants of this format: GRAY16_LE and GRAY16_BE

GAPI_Assert(GST_VIDEO_INFO_N_PLANES(&m_videoInfo) == 1);
break;
}
default: {
GAPI_Assert(false && "Unsupported GStreamerSource FRAME type.");
}
}
break;
}
case GStreamerSource::OutputType::MAT: {
Expand All @@ -197,13 +217,6 @@ void GStreamerSource::Priv::prepareVideoMeta()
}
}

// Fill GstVideoInfo structure to work further with GstVideoFrame class.
if (!gst_video_info_from_caps(&m_videoInfo, prerollCaps)) {
cv::util::throw_error(std::logic_error("preroll sample has invalid caps."));
}
GAPI_Assert(GST_VIDEO_INFO_N_PLANES(&m_videoInfo) == 2);
GAPI_Assert(GST_VIDEO_INFO_FORMAT(&m_videoInfo) == GST_VIDEO_FORMAT_NV12);

m_isMetaPrepared = true;
}
}
Expand Down Expand Up @@ -272,28 +285,46 @@ bool GStreamerSource::Priv::retrieveFrame(cv::Mat& data)

try
{
// m_matMeta holds width and height for 8U BGR frame, but actual
// frame m_buffer we request from GStreamer pipeline has 8U NV12 format.
// Constructing y and uv cv::Mat-s from such a m_buffer:
GAPI_Assert((uint8_t*)GST_VIDEO_FRAME_PLANE_DATA(&videoFrame, 1) ==
switch (m_type) {
case GST_VIDEO_FORMAT_NV12: {
// m_matMeta holds width and height for 8U BGR frame, but actual
// frame m_buffer we request from GStreamer pipeline has 8U NV12 format.
// Constructing y and uv cv::Mat-s from such a m_buffer:
GAPI_Assert((uint8_t*)GST_VIDEO_FRAME_PLANE_DATA(&videoFrame, 1) ==
(uint8_t*)GST_VIDEO_FRAME_PLANE_DATA(&videoFrame, 0) +
GST_VIDEO_FRAME_PLANE_OFFSET(&videoFrame, 1));
GAPI_Assert(GST_VIDEO_INFO_N_PLANES(&m_videoInfo) == 2);

cv::Mat y(m_matMeta.size, CV_8UC1,
(uint8_t*)GST_VIDEO_FRAME_PLANE_DATA(&videoFrame, 0) +
GST_VIDEO_FRAME_PLANE_OFFSET(&videoFrame, 0),
GST_VIDEO_FRAME_PLANE_STRIDE(&videoFrame, 0));
cv::Mat uv(m_matMeta.size / 2, CV_8UC2,
(uint8_t*)GST_VIDEO_FRAME_PLANE_DATA(&videoFrame, 0) +
GST_VIDEO_FRAME_PLANE_OFFSET(&videoFrame, 1),
GST_VIDEO_FRAME_PLANE_STRIDE(&videoFrame, 1));
cv::Mat y(m_matMeta.size, CV_8UC1,
(uint8_t*)GST_VIDEO_FRAME_PLANE_DATA(&videoFrame, 0) +
GST_VIDEO_FRAME_PLANE_OFFSET(&videoFrame, 0),
GST_VIDEO_FRAME_PLANE_STRIDE(&videoFrame, 0));
cv::Mat uv(m_matMeta.size / 2, CV_8UC2,
(uint8_t*)GST_VIDEO_FRAME_PLANE_DATA(&videoFrame, 0) +
GST_VIDEO_FRAME_PLANE_OFFSET(&videoFrame, 1),
GST_VIDEO_FRAME_PLANE_STRIDE(&videoFrame, 1));

cv::cvtColorTwoPlane(y, uv, data, cv::COLOR_YUV2BGR_NV12);
cv::cvtColorTwoPlane(y, uv, data, cv::COLOR_YUV2BGR_NV12);
break;
}
case GST_VIDEO_FORMAT_GRAY8: {
GAPI_Assert(GST_VIDEO_INFO_N_PLANES(&m_videoInfo) == 1);
cv::Mat y(m_matMeta.size, CV_8UC1,
(uint8_t*)GST_VIDEO_FRAME_PLANE_DATA(&videoFrame, 0) +
GST_VIDEO_FRAME_PLANE_OFFSET(&videoFrame, 0),
GST_VIDEO_FRAME_PLANE_STRIDE(&videoFrame, 0));
cv::cvtColor(y, data, cv::COLOR_GRAY2BGR);
break;
}
default: {
GAPI_Assert(false && "retrieveFrame - unsupported GStreamerSource FRAME type.");
}
}
}
catch (...)
{
gst_video_frame_unmap(&videoFrame);
cv::util::throw_error(std::runtime_error("NV12 buffer conversion to BGR is failed!"));
cv::util::throw_error(std::runtime_error("NV12 or GRAY8 buffer conversion to BGR is failed!"));
}
gst_video_frame_unmap(&videoFrame);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class GStreamerSource::Priv
bool m_isPipelinePlaying = false;

int64_t m_frameId = 0L;
size_t m_type = 0; //Gstreamer video format type

protected:
void configureAppsink();
Expand Down
Loading
0