camera-gstreamer: Add pipewire source to capture video streams 19/29119/8
authorAshok Sidipotu <ashok.sidipotu@collabora.com>
Mon, 14 Aug 2023 03:52:54 +0000 (09:22 +0530)
committerAshok Sidipotu <ashok.sidipotu@collabora.com>
Thu, 12 Oct 2023 00:43:56 +0000 (06:13 +0530)
Pipewire can be used for capturing camera video streams, add it as one of the
sources and make it the default source.

V4L2 path can be chosen with an env variable.

Enhance the README file with info that helps with the usage of the app.

Bug-AGL: SPEC-4881
Change-Id: Ia1d989da229304b1b514d6b25ebbc2530503d370
Signed-off-by: Ashok Sidipotu <ashok.sidipotu@collabora.com>
README.md
app/main.cpp

index bb1db89..6b0565f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,7 +1,57 @@
-camera-gstreamer
-----------------
+- [how to run camera-gstreamer app](#how-to-run-camera-gstreamer-app)
+  - [With PipeWire](#with-pipewire)
+  - [With V4L2](#with-v4l2)
+  - [Without a physical camera device](#without-a-physical-camera-device)
+  - [Other Details](#other-details)
+  - [cmd examples](#cmd-examples)
+
+how to run camera-gstreamer app
+===============================
+
+With PipeWire
+-------------
+- PipeWire is the default path
+- attach camera
+       - attach a camera to Hardware.
+       - make sure it is enumerated properly with `wpctl status` cmd
+       - make the desired device node the default node with `wpctl set-default
+       <camera-node-id>` cmd
+- run
+       - start camera-gstreamer from the UI.
+       - The app can also be run from cmd prompt, make sure you login with `agl-driver` usr name.
+
+With V4L2
+---------
+- login with `agl-driver` and start the app with `ENABLE_V4L2_PATH=true camera-gstreamer` cmd
+- V4L2 path cannot be taken when the app is run from the UI.
+
+Without a physical camera device
+---------------------------------
+
+The Virtual Video Test Driver (vivid) can be used for this purpose.
+
+- run `modprobe vivid allocators=0x1` cmd
+- check dmesg to know the capture device created.
+- with PipeWire this device has to be made a default device, check [above](#with-pipewire) on how
+  to do it.
+- with V4L2 use DEFAULT_V4L2_DEVICE to pass this new device
+
+Other Details
+-------------
+- For V4L2 path assumes that /dev/video0 is present and is set as a capture device.
+  - Use DEFAULT_V4L2_DEVICE environmental variable to change it.
+- use DEFAULT_DEVICE_WIDTH and DEFAULT_DEVICE_HEIGHT environmental variable to
+override the default dimensions.
+
+cmd examples
+------------
+run app with V4L2 path and on `/dev/video24`
+
+```
+DEFAULT_V4L2_DEVICE=/dev/video24 ENABLE_V4L2_PATH=true camera-gstreamer
+```
+run app with default path(PipeWire) with a video frame of height 480
+```
+DEFAULT_DEVICE_HEIGHT=480 camera-gstreamer
+```
 
-Assumes that /dev/video0 is present and is set as a capture device.  Use
-DEFAULT_V4L2_DEVICE environmental variable to change it.
-DEFAULT_V4L2_DEVICE_WIDTH and DEFAULT_V4L2_DEVICE_HEIGHT to specify the
-dimensions.
index 4451261..2068143 100644 (file)
@@ -147,7 +147,7 @@ prune_old_released_buffers(struct window *window)
 
        wl_list_for_each_safe(b, b_next,
                              &window->buffer_list, buffer_link) {
-               if (!b->busy && (b->width != window->width || 
+               if (!b->busy && (b->width != window->width ||
                                 b->height != window->height))
                        destroy_buffer(b);
        }
@@ -529,7 +529,7 @@ handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
 
        // use our own macro as C++ can't typecast from (void *) directly
        WL_ARRAY_FOR_EACH(p, states, uint32_t *) {
-               uint32_t state = *p; 
+               uint32_t state = *p;
                switch (state) {
                case XDG_TOPLEVEL_STATE_FULLSCREEN:
                        window->fullscreen = 1;
@@ -713,6 +713,10 @@ int main(int argc, char *argv[])
        int width;
        int height;
 
+       // pipewire is default.
+       char *v4l2_path = getenv("ENABLE_V4L2_PATH");
+       bool v4l2 = false;
+
        char pipeline_str[1024];
        GError *error = NULL;
        const char *app_id = "camera-gstreamer";
@@ -731,21 +735,33 @@ int main(int argc, char *argv[])
        camera_device = getenv("DEFAULT_V4L2_DEVICE");
        if (!camera_device)
                camera_device = get_first_camera_device();
-       width_str = getenv("DEFAULT_V4L2_DEVICE_WIDTH");
+
+       width_str = getenv("DEFAULT_DEVICE_WIDTH");
        if (!width_str)
                width = WINDOW_WIDTH_SIZE;
        else
                width = atoi(width_str);
 
-       height_str = getenv("DEFAULT_V4L2_DEVICE_HEIGHT");
+       height_str = getenv("DEFAULT_DEVICE_HEIGHT");
        if (!height_str)
                height = WINDOW_HEIGHT_SIZE;
        else
                height = atoi(height_str);
 
+       if (v4l2_path == NULL)
+               v4l2 = false;
+       else if (g_str_equal(v4l2_path, "yes") || g_str_equal(v4l2_path, "true"))
+               v4l2 = true;
+
        memset(pipeline_str, 0, sizeof(pipeline_str));
-       snprintf(pipeline_str, sizeof(pipeline_str), "v4l2src device=%s ! video/x-raw,width=%d,height=%d ! waylandsink", 
-               camera_device, width, height);
+
+       if (v4l2)
+               snprintf(pipeline_str, sizeof(pipeline_str), "v4l2src device=%s ! video/x-raw,width=%d,height=%d ! waylandsink",
+                       camera_device, width, height);
+       else
+               snprintf(pipeline_str, sizeof(pipeline_str), "pipewiresrc ! video/x-raw,width=%d,height=%d ! waylandsink",
+      width, height);
+
        gst_init(&gargc, &gargv);
 
        setbuf(stdout, NULL);
@@ -766,7 +782,7 @@ int main(int argc, char *argv[])
                return -1;
 
        // if you'd want to place the video in a pop-up/dialog type of window:
-       // agl_shell_desktop_set_app_property(display->agl_shell_desktop, app_id, 
+       // agl_shell_desktop_set_app_property(display->agl_shell_desktop, app_id,
        //                                 AGL_SHELL_DESKTOP_APP_ROLE_POPUP,
        //                                 WINDOW_WIDTH_POS_X, WINDOW_WIDTH_POS_Y,
        //                                 0, 0, WINDOW_WIDTH_SIZE, WINDOW_HEIGHT_SIZE,
@@ -775,7 +791,7 @@ int main(int argc, char *argv[])
        // we use the role to set a correspondence between the top level
        // surface and our application, with the previous call letting the
        // compositor know that we're one and the same
-       window = create_window(display, WINDOW_WIDTH_SIZE, WINDOW_HEIGHT_SIZE, app_id); 
+       window = create_window(display, WINDOW_WIDTH_SIZE, WINDOW_HEIGHT_SIZE, app_id);
 
        if (!window) {
                free(gargv);