[PATCH 3/4] qcap: Move the video capture streaming thread to vfwcapture.c.

Zebediah Figura z.figura12 at gmail.com
Tue Nov 24 20:11:16 CST 2020


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/qcap/qcap_private.h |  3 +-
 dlls/qcap/v4l.c          | 96 ++++-----------------------------------
 dlls/qcap/vfwcapture.c   | 98 ++++++++++++++++++++++++++++++++++++++--
 3 files changed, 103 insertions(+), 94 deletions(-)

diff --git a/dlls/qcap/qcap_private.h b/dlls/qcap/qcap_private.h
index 9df432f8d05..d715219c645 100644
--- a/dlls/qcap/qcap_private.h
+++ b/dlls/qcap/qcap_private.h
@@ -54,9 +54,8 @@ struct video_capture_funcs
             LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags);
     HRESULT (*get_prop)(struct video_capture_device *device, VideoProcAmpProperty property, LONG *value, LONG *flags);
     HRESULT (*set_prop)(struct video_capture_device *device, VideoProcAmpProperty property, LONG value, LONG flags);
+    BOOL (*read_frame)(struct video_capture_device *device, BYTE *data);
     void (*init_stream)(struct video_capture_device *device);
-    void (*start_stream)(struct video_capture_device *device);
-    void (*stop_stream)(struct video_capture_device *device);
     void (*cleanup_stream)(struct video_capture_device *device);
 };
 
diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c
index a007adce492..e0095379b34 100644
--- a/dlls/qcap/v4l.c
+++ b/dlls/qcap/v4l.c
@@ -99,11 +99,6 @@ struct video_capture_device
 
     struct strmbase_source *pin;
     int fd, mmap;
-
-    HANDLE thread;
-    FILTER_STATE state;
-    CONDITION_VARIABLE state_cv;
-    CRITICAL_SECTION state_cs;
 };
 
 static int xioctl(int fd, int request, void * arg)
@@ -119,8 +114,6 @@ static int xioctl(int fd, int request, void * arg)
 
 static void v4l_device_destroy(struct video_capture_device *device)
 {
-    device->state_cs.DebugInfo->Spare[0] = 0;
-    DeleteCriticalSection(&device->state_cs);
     if (device->fd != -1)
         video_close(device->fd);
     if (device->caps_count)
@@ -330,62 +323,19 @@ static void reverse_image(struct video_capture_device *device, LPBYTE output, co
     }
 }
 
-static DWORD WINAPI ReadThread(void *arg)
+static BOOL v4l_device_read_frame(struct video_capture_device *device, BYTE *data)
 {
-    struct video_capture_device *device = arg;
-    HRESULT hr;
-    IMediaSample *pSample = NULL;
-    unsigned char *pTarget;
-
-    for (;;)
+    while (video_read(device->fd, device->image_data, device->image_size) < 0)
     {
-        EnterCriticalSection(&device->state_cs);
-
-        while (device->state == State_Paused)
-            SleepConditionVariableCS(&device->state_cv, &device->state_cs, INFINITE);
-
-        if (device->state == State_Stopped)
+        if (errno != EAGAIN)
         {
-            LeaveCriticalSection(&device->state_cs);
-            break;
-        }
-
-        LeaveCriticalSection(&device->state_cs);
-
-        hr = BaseOutputPinImpl_GetDeliveryBuffer(device->pin, &pSample, NULL, NULL, 0);
-        if (SUCCEEDED(hr))
-        {
-            int len;
-            
-            IMediaSample_SetActualDataLength(pSample, device->image_size);
-
-            len = IMediaSample_GetActualDataLength(pSample);
-            TRACE("Data length: %d KB\n", len / 1024);
-
-            IMediaSample_GetPointer(pSample, &pTarget);
-
-            while (video_read(device->fd, device->image_data, device->image_size) == -1)
-            {
-                if (errno != EAGAIN)
-                {
-                    ERR("Failed to read frame: %s\n", strerror(errno));
-                    break;
-                }
-            }
-
-            reverse_image(device, pTarget, device->image_data);
-            hr = IMemInputPin_Receive(device->pin->pMemInputPin, pSample);
-            IMediaSample_Release(pSample);
-        }
-
-        if (FAILED(hr) && hr != VFW_E_NOT_CONNECTED)
-        {
-            TRACE("Return %x, stop IFilterGraph\n", hr);
-            break;
+            ERR("Failed to read frame: %s\n", strerror(errno));
+            return FALSE;
         }
     }
 
-    return 0;
+    reverse_image(device, data, device->image_data);
+    return TRUE;
 }
 
 static void v4l_device_init_stream(struct video_capture_device *device)
@@ -407,37 +357,12 @@ static void v4l_device_init_stream(struct video_capture_device *device)
         if (FAILED(hr = IMemAllocator_Commit(device->pin->pAllocator)))
             ERR("Failed to commit allocator, hr %#x.\n", hr);
     }
-
-    device->state = State_Paused;
-    device->thread = CreateThread(NULL, 0, ReadThread, device, 0, NULL);
-}
-
-static void v4l_device_start_stream(struct video_capture_device *device)
-{
-    EnterCriticalSection(&device->state_cs);
-    device->state = State_Running;
-    LeaveCriticalSection(&device->state_cs);
-}
-
-static void v4l_device_stop_stream(struct video_capture_device *device)
-{
-    EnterCriticalSection(&device->state_cs);
-    device->state = State_Paused;
-    LeaveCriticalSection(&device->state_cs);
 }
 
 static void v4l_device_cleanup_stream(struct video_capture_device *device)
 {
     HRESULT hr;
 
-    EnterCriticalSection(&device->state_cs);
-    device->state = State_Stopped;
-    LeaveCriticalSection(&device->state_cs);
-    WakeConditionVariable(&device->state_cv);
-    WaitForSingleObject(device->thread, INFINITE);
-    CloseHandle(device->thread);
-    device->thread = NULL;
-
     hr = IMemAllocator_Decommit(device->pin->pAllocator);
     if (hr != S_OK && hr != VFW_E_NOT_COMMITTED)
         ERR("Failed to decommit allocator, hr %#x.\n", hr);
@@ -638,10 +563,6 @@ struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHO
     }
 
     device->pin = pin;
-    device->state = State_Stopped;
-    InitializeConditionVariable(&device->state_cv);
-    InitializeCriticalSection(&device->state_cs);
-    device->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": video_capture_device.state_cs");
 
     TRACE("Format: %d bpp - %dx%d.\n", device->current_caps->video_info.bmiHeader.biBitCount,
             device->current_caps->video_info.bmiHeader.biWidth,
@@ -667,9 +588,8 @@ const struct video_capture_funcs v4l_funcs =
     .get_prop_range = v4l_device_get_prop_range,
     .get_prop = v4l_device_get_prop,
     .set_prop = v4l_device_set_prop,
+    .read_frame = v4l_device_read_frame,
     .init_stream = v4l_device_init_stream,
-    .start_stream = v4l_device_start_stream,
-    .stop_stream = v4l_device_stop_stream,
     .cleanup_stream = v4l_device_cleanup_stream,
 };
 
diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c
index 9ff96f13f91..9fb694ba678 100644
--- a/dlls/qcap/vfwcapture.c
+++ b/dlls/qcap/vfwcapture.c
@@ -34,10 +34,19 @@ struct vfw_capture
     IPersistPropertyBag IPersistPropertyBag_iface;
     BOOL init;
 
-    struct video_capture_device *device;
-
     struct strmbase_source source;
     IKsPropertySet IKsPropertySet_iface;
+
+    struct video_capture_device *device;
+
+    /* FIXME: It would be nice to avoid duplicating this variable with strmbase.
+     * However, synchronization is tricky; we need access to be protected by a
+     * separate lock. */
+    FILTER_STATE state;
+    CONDITION_VARIABLE state_cv;
+    CRITICAL_SECTION state_cs;
+
+    HANDLE thread;
 };
 
 static inline struct vfw_capture *impl_from_strmbase_filter(struct strmbase_filter *iface)
@@ -96,6 +105,8 @@ static void vfw_capture_destroy(struct strmbase_filter *iface)
         IPin_Disconnect(filter->source.pin.peer);
         IPin_Disconnect(&filter->source.pin.IPin_iface);
     }
+    filter->state_cs.DebugInfo->Spare[0] = 0;
+    DeleteCriticalSection(&filter->state_cs);
     strmbase_source_cleanup(&filter->source);
     strmbase_filter_cleanup(&filter->filter);
     CoTaskMemFree(filter);
@@ -121,11 +132,71 @@ static HRESULT vfw_capture_query_interface(struct strmbase_filter *iface, REFIID
     return S_OK;
 }
 
+static DWORD WINAPI stream_thread(void *arg)
+{
+    struct vfw_capture *filter = arg;
+    const VIDEOINFOHEADER *format = (const VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat;
+    const unsigned int image_size = format->bmiHeader.biWidth
+            * format->bmiHeader.biHeight * format->bmiHeader.biBitCount / 8;
+
+    for (;;)
+    {
+        IMediaSample *sample;
+        HRESULT hr;
+        BYTE *data;
+
+        EnterCriticalSection(&filter->state_cs);
+
+        while (filter->state == State_Paused)
+            SleepConditionVariableCS(&filter->state_cv, &filter->state_cs, INFINITE);
+
+        if (filter->state == State_Stopped)
+        {
+            LeaveCriticalSection(&filter->state_cs);
+            break;
+        }
+
+        LeaveCriticalSection(&filter->state_cs);
+
+        if (FAILED(hr = BaseOutputPinImpl_GetDeliveryBuffer(&filter->source, &sample, NULL, NULL, 0)))
+        {
+            ERR("Failed to get sample, hr %#x.\n", hr);
+            break;
+        }
+
+        IMediaSample_SetActualDataLength(sample, image_size);
+        IMediaSample_GetPointer(sample, &data);
+
+        if (!capture_funcs->read_frame(filter->device, data))
+        {
+            IMediaSample_Release(sample);
+            break;
+        }
+
+        hr = IMemInputPin_Receive(filter->source.pMemInputPin, sample);
+        IMediaSample_Release(sample);
+        if (FAILED(hr))
+        {
+            ERR("IMemInputPin::Receive() returned %#x.\n", hr);
+            break;
+        }
+    }
+
+    return 0;
+}
+
 static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface)
 {
     struct vfw_capture *filter = impl_from_strmbase_filter(iface);
 
     capture_funcs->init_stream(filter->device);
+
+    EnterCriticalSection(&filter->state_cs);
+    filter->state = State_Paused;
+    LeaveCriticalSection(&filter->state_cs);
+
+    filter->thread = CreateThread(NULL, 0, stream_thread, filter, 0, NULL);
+
     return S_OK;
 }
 
@@ -133,7 +204,10 @@ static HRESULT vfw_capture_start_stream(struct strmbase_filter *iface, REFERENCE
 {
     struct vfw_capture *filter = impl_from_strmbase_filter(iface);
 
-    capture_funcs->start_stream(filter->device);
+    EnterCriticalSection(&filter->state_cs);
+    filter->state = State_Running;
+    LeaveCriticalSection(&filter->state_cs);
+    WakeConditionVariable(&filter->state_cv);
     return S_OK;
 }
 
@@ -141,7 +215,9 @@ static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface)
 {
     struct vfw_capture *filter = impl_from_strmbase_filter(iface);
 
-    capture_funcs->stop_stream(filter->device);
+    EnterCriticalSection(&filter->state_cs);
+    filter->state = State_Paused;
+    LeaveCriticalSection(&filter->state_cs);
     return S_OK;
 }
 
@@ -149,6 +225,15 @@ static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface)
 {
     struct vfw_capture *filter = impl_from_strmbase_filter(iface);
 
+    EnterCriticalSection(&filter->state_cs);
+    filter->state = State_Stopped;
+    LeaveCriticalSection(&filter->state_cs);
+    WakeConditionVariable(&filter->state_cv);
+
+    WaitForSingleObject(filter->thread, INFINITE);
+    CloseHandle(filter->thread);
+    filter->thread = NULL;
+
     capture_funcs->cleanup_stream(filter->device);
     return S_OK;
 }
@@ -709,6 +794,11 @@ HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out)
 
     object->IKsPropertySet_iface.lpVtbl = &IKsPropertySet_VTable;
 
+    object->state = State_Stopped;
+    InitializeConditionVariable(&object->state_cv);
+    InitializeCriticalSection(&object->state_cs);
+    object->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": vfw_capture.state_cs");
+
     TRACE("Created VFW capture filter %p.\n", object);
     ObjectRefCount(TRUE);
     *out = &object->filter.IUnknown_inner;
-- 
2.29.2




More information about the wine-devel mailing list