Conversion of cv::Mat to GstBuffer

Saurabh Bora saurabh9bora at gmail.com
Mon Mar 25 11:36:55 UTC 2019


Thanks Michael,
It seems there is some problem with the input image itself. I tried
different image of 640*480 resolution and code worked just fine.

Regards,
Saurabh Bora

On Fri, Mar 15, 2019 at 2:52 AM Michael Gruner <michael.gruner at ridgerun.com>
wrote:

> Can you run your app with warning logging enabled? Any of the following
> should work:
>
> ./app --gst-debug=2
>
> Or
>
> GST_DEBUG=2 ./app
>
>
>
> On Mar 14, 2019, at 2:17 PM, Saurabh Bora <saurabh9bora at gmail.com> wrote:
>
> Hi Experts!,
>
> Thanks!! Michael, I tried the approach suggested by you and it works fine.
> I could verify the conversion of cv::Mat to GstBuffer and vice versa. On
> cv::write I get exact image that I had copied to GstBuffer.
>
> However, I am unable to get correct image on autovidesink. With current
> code below, I see a skewed and distorted grayscale image. Note that I had
> to set width and height of videocaps on appsrc element as 133, 133
> respectively, even though dimesnions of my input image is 134*134. If I set
> width and height as 134, 134 in videocaps, I see a black videosink.
>
> //----------------------------------------------------------
> #include <gst/gst.h>
> #include <opencv2/opencv.hpp>
> #include <opencv2/highgui.hpp>
>
> static GMainLoop *loop;
>
> void buffer_destroy(gpointer data)
> {
> cv::Mat* done = (cv::Mat*)data;
> delete done;
> }
>
> static void
> cb_need_data(GstElement *appsrc,
> guint       unused_size,
> gpointer    user_data)
> {
> static GstClockTime timestamp = 0;
> GstBuffer *buffer;
> GstFlowReturn ret;
> char *data1;
> GstMapInfo map;
>
> cv::Mat* img = new
> cv::Mat(cv::imread("C:/Users/212730892.LOGON/Desktop/lena.jpg"));
>
> std::cout << "cb_need_data called" << std::endl;
>
> gsize sizeInBytes = img->total() * img->elemSize();
> std::cout << "Size getting copied: " << sizeInBytes << std::endl;
> buffer = gst_buffer_new_wrapped_full((GstMemoryFlags)0,
> (gpointer)(img->data), sizeInBytes, 0, sizeInBytes, (gpointer)img,
> (GDestroyNotify)buffer_destroy);
>
> gsize bufferSize = gst_buffer_get_size(buffer);
> std::cout << "Buffer Size: " << bufferSize << std::endl;
>
> //Convert GstBuffer back to cv::Mat, to check if data was correctly copied
> GstMapInfo info;
> gst_buffer_map(buffer, &info, GST_MAP_READ);
> cv::Mat img2(cv::Size(img->size().height, img->size().width), CV_8UC3,
> (char*)(info.data));
> cv::imwrite("C:/Users/212730892.LOGON/Desktop/dummy1.jpg", img2);
>
> GST_BUFFER_OFFSET(buffer) = 0;
> GST_BUFFER_PTS(buffer) = timestamp;
> GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale_int(1, GST_SECOND, 30);
> //GST_BUFFER_DURATION(buffer) = GST_CLOCK_TIME_NONE;
>
> timestamp += GST_BUFFER_DURATION(buffer);
>
> g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
> gst_buffer_unref(buffer);
>
> if (ret != GST_FLOW_OK) {
> /* something wrong, stop pushing */
> g_main_loop_quit(loop);
> }
> }
>
> gint
> main(gint   argc,
> gchar *argv[])
> {
> GstElement *pipeline, *appsrc, *conv, *videosink;
>
> /* init GStreamer */
> gst_init(&argc, &argv);
> loop = g_main_loop_new(NULL, FALSE);
>
> /* setup pipeline */
> pipeline = gst_pipeline_new("pipeline");
> appsrc = gst_element_factory_make("appsrc", "source");
> conv = gst_element_factory_make("videoconvert", "conv");
> videosink = gst_element_factory_make("autovideosink", "videosink");
>
> /* setup */
> g_object_set(G_OBJECT(appsrc), "caps",
> gst_caps_new_simple("video/x-raw",
> "format", G_TYPE_STRING, "RGB",
> "width", G_TYPE_INT, 133,
> "height", G_TYPE_INT, 133,
> "framerate", GST_TYPE_FRACTION, 1, 30,
> NULL), NULL);
> gst_bin_add_many(GST_BIN(pipeline), appsrc, conv, videosink, NULL);
> gst_element_link_many(appsrc, conv, videosink, NULL);
>
> /* setup appsrc */
> g_object_set(G_OBJECT(appsrc),
> "stream-type", 0,
> "format", GST_FORMAT_TIME, NULL);
> g_signal_connect(appsrc, "need-data", G_CALLBACK(cb_need_data), NULL);
>
> /* play */
> gst_element_set_state(pipeline, GST_STATE_PLAYING);
> g_main_loop_run(loop);
>
> if (gst_element_set_state(pipeline, GST_STATE_NULL) ==
> GST_STATE_CHANGE_FAILURE)
> {
> g_printerr("Unable to set the pipeline to the playing state.\n");
> }
>
> // Free resources
> gst_object_unref(GST_OBJECT(pipeline));
> g_main_loop_unref(loop);
>
> return 0;
> }
> //-------------------------------------------------------------------------
>
> I am new to gstreamer framework and it would be a great help if someone
> could point me in right direction.
>
> Thanks and Regards,
> Saurabh Bora
>
>
> On Wed, Mar 13, 2019 at 11:48 PM Michael Gruner <
> michael.gruner at ridgerun.com> wrote:
>
>> It looks like img2, being a local variable, ends  its life when
>> “cb_need_data” ends. That leaves the pointer in “buffer” invalid. For this
>> one you’re better off with the copy.
>>
>> Another option is to alloc img2 on the heap, and use
>> gst_buffer_new_wrapped_full to carry img2 along with buffer and free then
>> together.
>>
>> Michael
>> www.ridgerun.com
>>
>> On Mar 13, 2019, at 10:51 AM, Saurabh Bora <saurabh9bora at gmail.com>
>> wrote:
>>
>> Hi Michael,
>>
>> Thanks! for your input. I tried what you suggested as below:
>>
>> //---------------------------------------------------------------
>> #include <gst/gst.h>
>> #include <opencv2/opencv.hpp>
>> #include <opencv2/highgui.hpp>
>> #include <opencv2/imgproc/imgproc.hpp>
>>
>> static GMainLoop *loop;
>>
>> static void
>> cb_need_data(GstElement *appsrc,
>> guint       unused_size,
>> gpointer    user_data)
>> {
>> static GstClockTime timestamp = 0;
>> GstBuffer *buffer;
>> guint size, depth, height, width, step, channels;
>> GstFlowReturn ret;
>> guchar *data1;
>> GstMapInfo map;
>>
>> cv::Mat img2;
>> cv::Mat img = cv::imread("C:/Users/212730892.LOGON/Desktop/lena.jpg");
>> cv::cvtColor(img, img2, cv::COLOR_BGR2RGB);
>>
>> height = img.size().height;
>> width = img.size().width;
>> //step = img.widthStep;
>> channels = img.channels();
>> //depth = img->depth;
>> data1 = (guchar *)img.data;
>> size = height * width * channels * sizeof(guchar);
>>
>> std::cout << "cb_need_data called" << std::endl;
>>
>> buffer = gst_buffer_new_wrapped(img2.data, img2.total() *
>> img2.elemSize());
>>
>> GstMapInfo info;
>> gst_buffer_map(buffer, &info, GST_MAP_READ);
>> cv::Mat mat(height, width, CV_8UC3, info.data);
>> cv::imshow("Output", mat);
>> //gst_buffer_unmap(buffer, &info);
>>
>> GST_BUFFER_PTS(buffer) = timestamp;
>> GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale_int(1, GST_SECOND, 2);
>>
>> timestamp += GST_BUFFER_DURATION(buffer);
>>
>> g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
>> //gst_buffer_unref(buffer);
>>
>> if (ret != GST_FLOW_OK) {
>> /* something wrong, stop pushing */
>> g_main_loop_quit(loop);
>> }
>> }
>>
>> gint
>> main(gint   argc,
>> gchar *argv[])
>> {
>> GstElement *pipeline, *appsrc, *conv, *videosink;
>>
>> /* init GStreamer */
>> gst_init(&argc, &argv);
>> loop = g_main_loop_new(NULL, FALSE);
>>
>> /* setup pipeline */
>> pipeline = gst_pipeline_new("pipeline");
>> appsrc = gst_element_factory_make("appsrc", "source");
>> conv = gst_element_factory_make("videoconvert", "conv");
>> videosink = gst_element_factory_make("autovideosink", "videosink");
>>
>> /* setup */
>> g_object_set(G_OBJECT(appsrc), "caps",
>> gst_caps_new_simple("video/x-raw",
>> "format", G_TYPE_STRING, "RGB",
>> "width", G_TYPE_INT, 134,
>> "height", G_TYPE_INT, 134,
>> "framerate", GST_TYPE_FRACTION, 1, 1,
>> NULL), NULL);
>> gst_bin_add_many(GST_BIN(pipeline), appsrc, conv, videosink, NULL);
>> gst_element_link_many(appsrc, conv, videosink, NULL);
>> //g_object_set (videosink, "device", "/dev/video0", NULL);
>> /* setup appsrc */
>> g_object_set(G_OBJECT(appsrc),
>> "stream-type", 0,
>> "format", GST_FORMAT_TIME, NULL);
>> g_signal_connect(appsrc, "need-data", G_CALLBACK(cb_need_data), NULL);
>>
>> /* play */
>> gst_element_set_state(pipeline, GST_STATE_PLAYING);
>> g_main_loop_run(loop);
>>
>> if (gst_element_set_state(pipeline, GST_STATE_NULL) ==
>> GST_STATE_CHANGE_FAILURE)
>> {
>> g_printerr("Unable to set the pipeline to the playing state.\n");
>> }
>>
>> // Free resources
>> gst_object_unref(GST_OBJECT(pipeline));
>> g_main_loop_unref(loop);
>>
>> return 0;
>> }
>>
>> //----------------------------------------------------------------------------------------------
>>
>> It still does not work as expected. It would be a great help if you could
>> point out where I am going wrong.
>> Thanks!!
>>
>> On Wed, Mar 13, 2019 at 7:40 PM Michael Gruner <
>> michael.gruner at ridgerun.com> wrote:
>>
>>> Hi Saurabh
>>>
>>> Yo may convert from a cv::Mat to a GstBuffer without a memory copy by
>>> using gst_buffer_new_wrapped:
>>>
>>>
>>> https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#gst-buffer-new-wrapped
>>>
>>> Something like:
>>> buffer = gst_buffer_new_wrapped (mat.data, mat.total()*mat.elemSize());
>>>
>>> In order to make a cv::Mat from a GstBuffer you first need to take the
>>> data out of the buffer.
>>>
>>> GstMapInfo info;
>>> gst_buffer_map (buffer, &info, GST_MAP_READ); // or write
>>> mat = cv::Mat(height, width, CV_8C3, map.data); // change your format
>>> accordingly
>>> ...
>>> gst_buffer_unmap (buffer, &info);
>>>
>>> Hope it helps.
>>>
>>> Michael
>>> www.ridgerun.com
>>>
>>> On Mar 13, 2019, at 7:15 AM, Saurabh Bora <saurabh9bora at gmail.com>
>>> wrote:
>>>
>>> Hi Experts!!,
>>>
>>> I am trying to read opencv images locally and push them into gstreamer
>>> pipeline. I am using appsrc element with "need-data" signal attached to
>>> call-back function.
>>> Please look at the code below.
>>>
>>>
>>> //------------------------------------------------------------------------------------------------------
>>> #include <gst/gst.h>
>>> #include <opencv2/opencv.hpp>
>>> #include <opencv2/highgui.hpp>
>>>
>>> static GMainLoop *loop;
>>>
>>> static void
>>> cb_need_data(GstElement *appsrc,
>>> guint       unused_size,
>>> gpointer    user_data)
>>> {
>>> static GstClockTime timestamp = 0;
>>> GstBuffer *buffer;
>>> guint size, depth, height, width, step, channels;
>>> GstFlowReturn ret;
>>> guchar *data1;
>>> GstMapInfo map;
>>>
>>> cv::Mat img = cv::imread("C:/Users/212730892.LOGON/Desktop/lena.jpg");
>>> height = img.size().height;
>>> width = img.size().width;
>>> //step = img.widthStep;
>>> channels = img.channels();
>>> //depth = img->depth;
>>> data1 = (guchar *)img.data;
>>> size = height * width* channels;
>>>
>>> // Copy cv::Mat to GstBuffer
>>> buffer = gst_buffer_new_allocate(NULL, size, NULL);
>>> gst_buffer_map(buffer, &map, GST_MAP_WRITE);
>>> memcpy((guchar *)map.data, data1, gst_buffer_get_size(buffer));
>>>
>>> //Convert GstBuffer back to cv::Mat and write it, to check if data was
>>> correctly copied. //This is where I get to know that data is not correct.
>>> cv::Mat img2(cv::Size(134, 134), CV_8UC3, (char*)(buffer));
>>> cv::imwrite("C:/Users/212730892.LOGON/Desktop/dummy1.jpg", img2);
>>>
>>> GST_BUFFER_PTS(buffer) = timestamp;
>>> GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale_int(1, GST_SECOND,
>>> 2);
>>>
>>> timestamp += GST_BUFFER_DURATION(buffer);
>>>
>>> g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
>>> //gst_buffer_unref(buffer);
>>>
>>> if (ret != GST_FLOW_OK) {
>>> /* something wrong, stop pushing */
>>> g_main_loop_quit(loop);
>>> }
>>> }
>>>
>>> gint
>>> main(gint   argc,
>>> gchar *argv[])
>>> {
>>> GstElement *pipeline, *appsrc, *conv, *videosink;
>>>
>>> /* init GStreamer */
>>> gst_init(&argc, &argv);
>>> loop = g_main_loop_new(NULL, FALSE);
>>>
>>> /* setup pipeline */
>>> pipeline = gst_pipeline_new("pipeline");
>>> appsrc = gst_element_factory_make("appsrc", "source");
>>> conv = gst_element_factory_make("videoconvert", "conv");
>>> videosink = gst_element_factory_make("autovideosink", "videosink");
>>>
>>> /* setup */
>>> g_object_set(G_OBJECT(appsrc), "caps",
>>> gst_caps_new_simple("video/x-raw",
>>> "format", G_TYPE_STRING, "RGB",
>>> "width", G_TYPE_INT, 134,
>>> "height", G_TYPE_INT, 134,
>>> "framerate", GST_TYPE_FRACTION, 1, 1,
>>> NULL), NULL);
>>> gst_bin_add_many(GST_BIN(pipeline), appsrc, conv, videosink, NULL);
>>> gst_element_link_many(appsrc, conv, videosink, NULL);
>>> //g_object_set (videosink, "device", "/dev/video0", NULL);
>>> /* setup appsrc */
>>> g_object_set(G_OBJECT(appsrc),
>>> "stream-type", 0,
>>> "format", GST_FORMAT_TIME, NULL);
>>> g_signal_connect(appsrc, "need-data", G_CALLBACK(cb_need_data), NULL);
>>>
>>> /* play */
>>> gst_element_set_state(pipeline, GST_STATE_PLAYING);
>>> g_main_loop_run(loop);
>>>
>>> if (gst_element_set_state(pipeline, GST_STATE_NULL) ==
>>> GST_STATE_CHANGE_FAILURE)
>>> {
>>> g_printerr("Unable to set the pipeline to the playing state.\n");
>>> }
>>>
>>> // Free resources
>>> gst_object_unref(GST_OBJECT(pipeline));
>>> g_main_loop_unref(loop);
>>>
>>> return 0;
>>> }
>>>
>>> //-------------------------------------------------------------------------------------------------------------------------------------
>>>
>>> In cb_need_data, the part where copying I am copying to GstBuffer seems
>>> to be wrong and it does not work as expected.
>>> Can anyone, please help me understand, how can I copy the image data
>>> perfectly and pass it downstream to other elements without losing any data?
>>>
>>> --
>>> Thanks and Regards,
>>> Saurabh Bora
>>>
>>> PH NO : 7038166900
>>> EMAIL : saurabh9bora at gmail.com
>>>              saurabh9bora at outlook.com
>>>
>>> _______________________________________________
>>> gstreamer-devel mailing list
>>> gstreamer-devel at lists.freedesktop.org
>>> https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>>>
>>> _______________________________________________
>>> gstreamer-devel mailing list
>>> gstreamer-devel at lists.freedesktop.org
>>> https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>>
>>
>>
>> --
>> Thanks and Regards,
>> Saurabh Bora
>>
>> PH NO : 7038166900
>> EMAIL : saurabh9bora at gmail.com
>>              saurabh9bora at outlook.com
>>
>> _______________________________________________
>> gstreamer-devel mailing list
>> gstreamer-devel at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>>
>> _______________________________________________
>> gstreamer-devel mailing list
>> gstreamer-devel at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>
>
>
> --
> Thanks and Regards,
> Saurabh Bora
>
> PH NO : 7038166900
> EMAIL : saurabh9bora at gmail.com
>              saurabh9bora at outlook.com
> _______________________________________________
> gstreamer-devel mailing list
> gstreamer-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>
>
> _______________________________________________
> gstreamer-devel mailing list
> gstreamer-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel



-- 
Thanks and Regards,
Saurabh Bora

PH NO : 7038166900
EMAIL : saurabh9bora at gmail.com
             saurabh9bora at outlook.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/gstreamer-devel/attachments/20190325/3d91d6fc/attachment-0001.html>


More information about the gstreamer-devel mailing list