Zebediah Figura : qcap: Use a condition variable to synchronize with the video capture thread.

Alexandre Julliard julliard at winehq.org
Mon Jun 29 14:59:21 CDT 2020


Module: wine
Branch: master
Commit: 6d675064f8f9eeb873a2c91d02c3ccbbfd982d56
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=6d675064f8f9eeb873a2c91d02c3ccbbfd982d56

Author: Zebediah Figura <z.figura12 at gmail.com>
Date:   Mon Jun 29 10:26:18 2020 -0500

qcap: Use a condition variable to synchronize with the video capture thread.

This fixes a hang that can be triggered by calling Pause() followed by Stop().

Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/qcap/v4l.c | 58 ++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 39 insertions(+), 19 deletions(-)

diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c
index 2cf50b0c28..d8c5e168e1 100644
--- a/dlls/qcap/v4l.c
+++ b/dlls/qcap/v4l.c
@@ -98,9 +98,11 @@ struct v4l_device
 
     struct strmbase_source *pin;
     int fd, mmap;
-    FILTER_STATE state;
 
-    HANDLE thread, run_event;
+    HANDLE thread;
+    FILTER_STATE state;
+    CONDITION_VARIABLE state_cv;
+    CRITICAL_SECTION state_cs;
 };
 
 static inline struct v4l_device *v4l_device(struct video_capture_device *iface)
@@ -123,6 +125,8 @@ static void v4l_device_destroy(struct video_capture_device *iface)
 {
     struct v4l_device *device = v4l_device(iface);
 
+    device->state_cs.DebugInfo->Spare[0] = 0;
+    DeleteCriticalSection(&device->state_cs);
     if (device->fd != -1)
         video_close(device->fd);
     if (device->caps_count)
@@ -320,19 +324,18 @@ static void reverse_image(struct v4l_device *device, LPBYTE output, const BYTE *
     }
 }
 
-static DWORD WINAPI ReadThread(LPVOID lParam)
+static DWORD WINAPI ReadThread(void *arg)
 {
-    struct v4l_device *capBox = lParam;
+    struct v4l_device *device = arg;
     HRESULT hr;
     IMediaSample *pSample = NULL;
-    ULONG framecount = 0;
     unsigned char *pTarget, *image_data;
     unsigned int image_size;
     UINT width, height, depth;
 
-    width = capBox->current_caps->video_info.bmiHeader.biWidth;
-    height = capBox->current_caps->video_info.bmiHeader.biHeight;
-    depth = capBox->current_caps->video_info.bmiHeader.biBitCount / 8;
+    width = device->current_caps->video_info.bmiHeader.biWidth;
+    height = device->current_caps->video_info.bmiHeader.biHeight;
+    depth = device->current_caps->video_info.bmiHeader.biBitCount / 8;
     image_size = width * height * depth;
     if (!(image_data = heap_alloc(image_size)))
     {
@@ -340,12 +343,22 @@ static DWORD WINAPI ReadThread(LPVOID lParam)
         return 0;
     }
 
-    while (capBox->state != State_Stopped)
+    for (;;)
     {
-        if (capBox->state == State_Paused)
-            WaitForSingleObject(capBox->run_event, INFINITE);
+        EnterCriticalSection(&device->state_cs);
+
+        while (device->state == State_Paused)
+            SleepConditionVariableCS(&device->state_cv, &device->state_cs, INFINITE);
 
-        hr = BaseOutputPinImpl_GetDeliveryBuffer(capBox->pin, &pSample, NULL, NULL, 0);
+        if (device->state == State_Stopped)
+        {
+            LeaveCriticalSection(&device->state_cs);
+            break;
+        }
+
+        LeaveCriticalSection(&device->state_cs);
+
+        hr = BaseOutputPinImpl_GetDeliveryBuffer(device->pin, &pSample, NULL, NULL, 0);
         if (SUCCEEDED(hr))
         {
             int len;
@@ -358,7 +371,7 @@ static DWORD WINAPI ReadThread(LPVOID lParam)
 
             IMediaSample_GetPointer(pSample, &pTarget);
 
-            while (video_read(capBox->fd, image_data, image_size) == -1)
+            while (video_read(device->fd, image_data, image_size) == -1)
             {
                 if (errno != EAGAIN)
                 {
@@ -367,11 +380,11 @@ static DWORD WINAPI ReadThread(LPVOID lParam)
                 }
             }
 
-            reverse_image(capBox, pTarget, image_data);
-            hr = IMemInputPin_Receive(capBox->pin->pMemInputPin, pSample);
-            TRACE("%p -> Frame %u: %x\n", capBox, ++framecount, hr);
+            reverse_image(device, pTarget, 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);
@@ -412,15 +425,17 @@ static void v4l_device_init_stream(struct video_capture_device *iface)
 static void v4l_device_start_stream(struct video_capture_device *iface)
 {
     struct v4l_device *device = v4l_device(iface);
+    EnterCriticalSection(&device->state_cs);
     device->state = State_Running;
-    SetEvent(device->run_event);
+    LeaveCriticalSection(&device->state_cs);
 }
 
 static void v4l_device_stop_stream(struct video_capture_device *iface)
 {
     struct v4l_device *device = v4l_device(iface);
+    EnterCriticalSection(&device->state_cs);
     device->state = State_Paused;
-    ResetEvent(device->run_event);
+    LeaveCriticalSection(&device->state_cs);
 }
 
 static void v4l_device_cleanup_stream(struct video_capture_device *iface)
@@ -428,7 +443,10 @@ static void v4l_device_cleanup_stream(struct video_capture_device *iface)
     struct v4l_device *device = v4l_device(iface);
     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;
@@ -656,7 +674,9 @@ struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHO
     device->d.ops = &v4l_device_ops;
     device->pin = pin;
     device->state = State_Stopped;
-    device->run_event = CreateEventW(NULL, TRUE, FALSE, NULL);
+    InitializeConditionVariable(&device->state_cv);
+    InitializeCriticalSection(&device->state_cs);
+    device->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": v4l_device.state_cs");
 
     TRACE("Format: %d bpp - %dx%d.\n", device->current_caps->video_info.bmiHeader.biBitCount,
             device->current_caps->video_info.bmiHeader.biWidth,




More information about the wine-cvs mailing list