[PATCH 1/6] qcap/videocapture: Storage capabilities information.

Jactry Zeng jzeng at codeweavers.com
Thu Apr 23 00:28:18 CDT 2020


Signed-off-by: Jactry Zeng <jzeng at codeweavers.com>
---
 dlls/qcap/v4l.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 155 insertions(+), 3 deletions(-)

diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c
index 6fe92d2d0a..26eccf6ee3 100644
--- a/dlls/qcap/v4l.c
+++ b/dlls/qcap/v4l.c
@@ -93,9 +93,20 @@ static BOOL video_init(void)
 #endif
 }
 
+struct capabilitie
+{
+    __u32 pixelformat;
+    UINT width, height, depth;
+    AM_MEDIA_TYPE media_type;
+    VIDEO_STREAM_CONFIG_CAPS config;
+};
+
 struct _Capture
 {
     UINT width, height, bitDepth, fps, outputwidth, outputheight;
+    struct capabilitie *current_cap;
+    struct capabilitie **caps;
+    LONG caps_count;
     BOOL swresize;
 
     struct strmbase_source *pin;
@@ -116,13 +127,22 @@ static int xioctl(int fd, int request, void * arg)
     return r;
 }
 
+static void free_capabilitie(struct capabilitie *cap)
+{
+    heap_free(cap->media_type.pbFormat);
+    heap_free(cap);
+}
+
 HRESULT qcap_driver_destroy(Capture *capBox)
 {
     TRACE("%p\n", capBox);
 
-    if( capBox->fd != -1 )
+    if (capBox->fd != -1)
         video_close(capBox->fd);
-    CoTaskMemFree(capBox);
+    while (--capBox->caps_count >= 0)
+        free_capabilitie(capBox->caps[capBox->caps_count]);
+    heap_free(capBox);
+
     return S_OK;
 }
 
@@ -495,9 +515,83 @@ void qcap_driver_cleanup_stream(Capture *device)
         ERR("Failed to decommit allocator, hr %#x.\n", hr);
 }
 
+
+static HRESULT create_capabilitie(__u32 pixelformat, __u32 width, __u32 height,
+        __u32 max_fps, __u32 min_fps, struct capabilitie **out)
+{
+    VIDEOINFOHEADER *video_info;
+    struct capabilitie *cap;
+    DWORD compression;
+    BOOL compressed;
+    GUID subtype;
+    LONG depth;
+
+    *out = NULL;
+    switch (pixelformat)
+    {
+        case V4L2_PIX_FMT_BGR24:
+            subtype = MEDIASUBTYPE_RGB24;
+            compression = BI_RGB;
+            compressed = FALSE;
+            depth = 24;
+            break;
+        default:
+            FIXME("Unknown format: %#x (%dx%d).\n", pixelformat, width, height);
+            return E_FAIL;
+    }
+
+    cap = heap_alloc_zero(sizeof(*cap));
+    if (!cap)
+        return E_OUTOFMEMORY;
+
+    video_info = heap_alloc_zero(sizeof(*video_info));
+    if (!video_info)
+    {
+        heap_free(cap);
+        return E_OUTOFMEMORY;
+    }
+
+    video_info->rcSource.right = width;
+    video_info->rcSource.bottom = height;
+    video_info->rcTarget.right = width;
+    video_info->rcTarget.bottom = height;
+    video_info->dwBitRate = max_fps * width * height * depth;
+    video_info->bmiHeader.biSize = sizeof(video_info->bmiHeader);
+    video_info->bmiHeader.biWidth = width;
+    video_info->bmiHeader.biHeight = height;
+    video_info->bmiHeader.biPlanes = 1;
+    video_info->bmiHeader.biBitCount = depth;
+    video_info->bmiHeader.biCompression = compression;
+    video_info->bmiHeader.biSizeImage = width * height * depth / 8;
+    cap->media_type.majortype = MEDIATYPE_Video;
+    cap->media_type.subtype = subtype;
+    cap->media_type.bFixedSizeSamples = TRUE;
+    cap->media_type.bTemporalCompression = compressed;
+    cap->media_type.lSampleSize = width * height * depth / 8;
+    cap->media_type.formattype = FORMAT_VideoInfo;
+    cap->media_type.pUnk = NULL;
+    cap->media_type.cbFormat = sizeof(VIDEOINFOHEADER);
+    cap->media_type.pbFormat = (void *)video_info;
+    cap->config.MaxFrameInterval = 10000000 * max_fps;
+    cap->config.MinFrameInterval = 10000000 * min_fps;;
+    cap->config.MaxOutputSize.cx = width;
+    cap->config.MaxOutputSize.cy = height;
+    cap->config.MinOutputSize.cx = width;
+    cap->config.MinOutputSize.cy = height;
+    cap->config.guid = FORMAT_VideoInfo;
+    cap->pixelformat = pixelformat;
+    cap->width = width;
+    cap->height = height;
+    cap->depth = depth;
+
+    *out = cap;
+    return S_OK;
+}
+
 Capture *qcap_driver_init(struct strmbase_source *pin, USHORT card)
 {
     struct v4l2_capability caps = {{0}};
+    struct v4l2_fmtdesc fmtdesc = {0};
     struct v4l2_format format = {0};
     Capture *device = NULL;
     BOOL have_libv4l2;
@@ -506,7 +600,7 @@ Capture *qcap_driver_init(struct strmbase_source *pin, USHORT card)
 
     have_libv4l2 = video_init();
 
-    if (!(device = CoTaskMemAlloc(sizeof(*device))))
+    if (!(device = heap_alloc_zero(sizeof(*device))))
         return NULL;
 
     sprintf(path, "/dev/video%i", card);
@@ -559,6 +653,64 @@ Capture *qcap_driver_init(struct strmbase_source *pin, USHORT card)
         goto error;
     }
 
+    /* Feeding a RGB format to VIDIOC_TRY_FMT is helpful and necessary for
+       making VIDIOC_ENUM_FMT return more supproted RGB formats. */
+    format.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
+    if (xioctl(fd, VIDIOC_TRY_FMT, &format) == -1
+            || format.fmt.pix.pixelformat != V4L2_PIX_FMT_BGR24)
+        WARN("This device doesn't support V4L2_PIX_FMT_BGR24.\n");
+
+    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    while(xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1)
+    {
+        struct v4l2_frmsizeenum frmsize = {0};
+
+        frmsize.pixel_format = fmtdesc.pixelformat;
+        while(xioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) != -1)
+        {
+            struct v4l2_frmivalenum frmival = {0};
+            struct capabilitie *cap, **new_caps;
+            __u32 max_fps = 30, min_fps = 30;
+
+            frmival.pixel_format = fmtdesc.pixelformat;
+            frmival.width = frmsize.discrete.width;
+            frmival.height = frmsize.discrete.height;
+            if (xioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) != -1)
+            {
+                if (frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE)
+                {
+                    max_fps = frmival.discrete.denominator / frmival.discrete.numerator;
+                    min_fps = max_fps;
+                }
+                else if (frmival.type == V4L2_FRMIVAL_TYPE_STEPWISE)
+                {
+                    max_fps = frmival.stepwise.max.denominator / frmival.stepwise.max.numerator;
+                    min_fps = frmival.stepwise.min.denominator / frmival.stepwise.min.numerator;
+                }
+            }
+            else
+                ERR("Failed to get fps: %s.\n", strerror(errno));
+
+            if (SUCCEEDED(create_capabilitie(fmtdesc.pixelformat, frmsize.discrete.width, frmsize.discrete.height,
+                                    max_fps, min_fps, &cap)))
+            {
+                new_caps = heap_realloc(device->caps, (device->caps_count + 1) * sizeof(*device->caps));
+                if (!new_caps)
+                {
+                    free_capabilitie(cap);
+                    goto error;
+                }
+                device->caps = new_caps;
+                device->caps[device->caps_count] = cap;
+                device->caps_count++;
+            }
+            frmsize.index++;
+        }
+        fmtdesc.index++;
+    }
+
+    device->current_cap = device->caps[0];
+
     format.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
     if (xioctl(fd, VIDIOC_S_FMT, &format) == -1
             || format.fmt.pix.pixelformat != V4L2_PIX_FMT_BGR24)
-- 
2.26.1




More information about the wine-devel mailing list