GStreamer. How to change v4l2src image resolution?

121 Views Asked by At

There is pipeline:
v4l2src ! decodebin ! queue ! videoconvert ! xvimagesink

After start v4l2src finds many caps with media type image/jpeg and different image resolutions. v4l2src choose the first caps with 1920x1080. I want to 320x240. And I really don't understand how to set this resolution.

Okay, I can do it:
v4l2src ! image/jpeg,width=320,height=240 ! decodebin ! queue ! videoconvert ! xvimagesink
or:
v4l2src ! jpegdec ! video/x-raw,width=320,height=240 ! queue ! videoconvert ! xvimagesink

But it's not universal. What if the webcamera has a different format?
For example, at this moment I work on the virtual machine and virtual webcamera has only image/jpeg, but on the native system webcam has also video/x-raw. And video/x-raw is the first available set.
What if the another webcamera has video/x-h264 or something else?

Do I understand correctly that GStreamer does not have the ability to somehow universally set the image resolution?
v4l2src ! <all-media-type>,width=320,height=240 ! decodebin ! queue ! videoconvert ! xvimagesink
I must somewhere in my program detect the media type and set the resolution with detected type, right?

What did I try to do?
In gst-inspect-1.0 I found out that v4l2src has signal prepare-format. Okay, what if add capsfilter between v4l2src and decodebin? When prepare-format-callback is calling, I will get the media type and set caps to capsfilter, hoping that pipeline will somehow magically update)

void onV4l2Prepare(GstElement *src, gint /*arg0*/, GstCaps *arg1, GstElement *pipeline_)
{
    GstStructure *structure = gst_caps_get_structure(arg1, 0);
    const gchar *media_type = gst_structure_get_name(structure);

    GstElement *capsfilter = gst_bin_get_by_name(GST_BIN(pipeline_), "capsfilter");
    GString *caps_str = g_string_new(nullptr);
    g_string_printf(caps_str, "%s,width=320,height=240", media_type, NULL);
    g_object_set(G_OBJECT(capsfilter), "caps", caps_str, NULL);
    g_string_free(caps_str, TRUE);

    // want to check update
    GstPad *pad = gst_element_get_static_pad(src, "src");
    GstCaps *caps = gst_pad_get_current_caps(pad);
    gchar *str = gst_caps_to_string(caps);
    g_print(str, NULL);  // no updates
    g_free(str);
    gst_caps_unref(caps);
    gst_object_unref(pad);
}

I really have no idea how to do this. Help me, pls)

1

There are 1 best solutions below

5
SeB On

There are several points in your question. You can rescale into a given resolution using videoscale. For managing different paths depending on received caps, you can use switchbin. Try:

gst-launch-1.0 -v v4l2src device=/dev/video0 ! switchbin num-paths=4 \
   path0::caps="video/x-raw"  path0::element="videoconvert" \
   path1::caps="image/jpeg"   path1::element="jpegdec ! videoconvert" \
   path2::caps="video/x-h264" path2::element="h264parse ! avdec_h264 ! videoconvert" \
   path3::caps="ANY"   path3::element="fakesink   videotestsrc ! videoconvert" \
! videoscale ! video/x-raw,width=320,height=240,pixel-aspect-ratio=1/1 ! autovideosink