Skip to content

Consider video meta on GStreamer video capture#22018

Merged
opencv-pushbot merged 1 commit intoopencv:4.xfrom
RidgeRun:gstreamer-consider-video-meta-if-available
Jun 8, 2022
Merged

Consider video meta on GStreamer video capture#22018
opencv-pushbot merged 1 commit intoopencv:4.xfrom
RidgeRun:gstreamer-consider-video-meta-if-available

Conversation

@michaelgruner
Copy link
Copy Markdown
Contributor

@michaelgruner michaelgruner commented May 23, 2022

Some GStreamer elements may produce buffers with very non
standard strides, offsets and/or even transport each plane
in different, non-contiguous pointers. This non-standard
layout is communicated via GstVideoMeta structures attached
to the buffers. Given this, when a GstVideoMeta is available,
one should parse the layout from it instead of generating
a generic one from the caps.

The GstVideoFrame utility does precisely this: if the buffer
contains a video meta, it uses that to fill the format and
memory layout. If there is no meta available, the layout is
inferred from the caps.

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
  • The PR is proposed to the proper branch
  • There is a reference to the original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake

Some GStreamer elements may produce buffers with very non
standard strides, offsets and/or even transport each plane
in different, non-contiguous pointers. This non-standard
layout is communicated via GstVideoMeta structures attached
to the buffers. Given this, when a GstVideoMeta is available,
one should parse the layout from it instead of generating
a generic one from the caps.

The GstVideoFrame utility does precisely this: if the buffer
contains a video meta, it uses that to fill the format and
memory layout. If there is no meta available, the layout is
inferred from the caps.
@asmorkalov
Copy link
Copy Markdown
Contributor

Thanks for the contribution! Could you point me the case where per-frame memory layout differs from the video one. Is it specific to GStreamer version or some codec/camera ?

@michaelgruner
Copy link
Copy Markdown
Contributor Author

Hey @asmorkalov. I just experienced this with a proprietary camera that gave odd widths and no padding. GStreamer, if not explicitly indicated otherwise, assumes the stride will be a multiple of 4 bytes, which wasn't true for this camera. So the way I communicated the correct stride was using the video meta. I created a dirty mock element that causes this same effect. Consider the following video capture app:

#include <opencv2/opencv.hpp>

using namespace cv;
int main(int argc, char** argv )
{
  cv::VideoCapture cap(
     "oddsrc ! video/x-raw,width=321,height=240,format=BGR ! appsink", cv::CAP_GSTREAMER);
  cv::namedWindow("Display Image", WINDOW_AUTOSIZE );

  while(1){
    cv::Mat frame;
    cap >> frame;

    imshow("Display Image", frame);
    waitKey(33);
  }

  cap.release();
  return 0;
}

The oddsrc camera element will create BGR images with a 321 pixels width and no padding, resulting in a 963 (321*3) bytes stride. With the master branch, Gstreamer automatically computes a 964 stride, resulting in image artifacts:
gstreamer_video_capture_gst_buffer_map.png

On the other hand, if one uses video_frame_map (as in the PR), the correct stride is considered and the image is properly displayed:
gstreamer_video_capture_frame_map.png

To verify this yourself, you can build the oddsrc by downloading the contents of gstoddsrc.c and building as

gcc gstoddsrc.c `pkg-config --cflags --libs gstreamer-1.0 gstreamer-base-1.0 gstreamer-video-1.0` -shared -o libgstoddsrc.so

@asmorkalov
Copy link
Copy Markdown
Contributor

Thanks a lot for the contribution. The patch works for me and looks very reasonable. 5 cents from my side:

  • To reproduce the issue need to build the plugin with -fPIC option and add plugin folder to GST_PLUGIN_PATH environment variable.
  • I tried to reproduce the issue with videotestsrc. "videotestsrc pattern=\"checkers-8\" ! video/x-raw,width=321,height=240,format=BGR ! appsink" Generates accurate images and does not trigger the issue. It looks like it announce correct frame meta from the very beginning.
  • It'll be great to contribute the oddsrc as videotestsrc option to GStreamer to have it as test solution everywhere. What do you think?

@asmorkalov asmorkalov self-requested a review June 6, 2022 09:56
@asmorkalov
Copy link
Copy Markdown
Contributor

Test system: Ubuntu 18.04. GStreamer 1.14.5. OpenCV cannot convert YUV with odd width. All branches tested manually.

Image size: [321 x 360] step:321
terminate called after throwing an instance of 'cv::Exception'
  what():  OpenCV(4.5.5-dev) /mnt/projects/Projects/OpenCV/opencv-master/modules/imgproc/src/color.simd_helpers.hpp:108: error: (-215:Assertion failed) sz.width % 2 == 0 && sz.height % 3 == 0 in function 'CvtHelper'

Copy link
Copy Markdown
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

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

LGTM 👍 Thank you for contribution!

@opencv-pushbot opencv-pushbot merged commit dda2e93 into opencv:4.x Jun 8, 2022
@alalek alalek mentioned this pull request Aug 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants