[PATCH 3/4] qcap: Rework v4l2 state change logic.

Zebediah Figura z.figura12 at gmail.com
Wed Dec 4 23:03:30 CST 2019


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/qcap/capture.h    |   7 +-
 dlls/qcap/v4l.c        | 166 +++++++++++++----------------------------
 dlls/qcap/vfwcapture.c |  60 ++++++++-------
 3 files changed, 89 insertions(+), 144 deletions(-)

diff --git a/dlls/qcap/capture.h b/dlls/qcap/capture.h
index 6433f37d88f..7d2be332488 100644
--- a/dlls/qcap/capture.h
+++ b/dlls/qcap/capture.h
@@ -31,8 +31,9 @@ HRESULT qcap_driver_get_format(const Capture *, AM_MEDIA_TYPE *) DECLSPEC_HIDDEN
 HRESULT qcap_driver_get_prop_range(Capture*,VideoProcAmpProperty,LONG*,LONG*,LONG*,LONG*,LONG*) DECLSPEC_HIDDEN;
 HRESULT qcap_driver_get_prop(Capture*,VideoProcAmpProperty,LONG*,LONG*) DECLSPEC_HIDDEN;
 HRESULT qcap_driver_set_prop(Capture*,VideoProcAmpProperty,LONG,LONG) DECLSPEC_HIDDEN;
-HRESULT qcap_driver_run(Capture*,FILTER_STATE*) DECLSPEC_HIDDEN;
-HRESULT qcap_driver_pause(Capture*,FILTER_STATE*) DECLSPEC_HIDDEN;
-HRESULT qcap_driver_stop(Capture*,FILTER_STATE*) DECLSPEC_HIDDEN;
+void qcap_driver_init_stream(Capture *device) DECLSPEC_HIDDEN;
+void qcap_driver_start_stream(Capture *device) DECLSPEC_HIDDEN;
+void qcap_driver_stop_stream(Capture *device) DECLSPEC_HIDDEN;
+void qcap_driver_cleanup_stream(Capture *device) DECLSPEC_HIDDEN;
 
 #endif /* __QCAP_CAPTURE_H__ */
diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c
index a203e91e52b..75121fd8518 100644
--- a/dlls/qcap/v4l.c
+++ b/dlls/qcap/v4l.c
@@ -99,13 +99,11 @@ struct _Capture
     UINT width, height, bitDepth, fps, outputwidth, outputheight;
     BOOL swresize;
 
-    CRITICAL_SECTION CritSect;
-
     struct strmbase_source *pin;
     int fd, mmap;
-    BOOL iscommitted, stopped;
+    FILTER_STATE state;
 
-    HANDLE thread;
+    HANDLE thread, run_event;
 };
 
 static int xioctl(int fd, int request, void * arg)
@@ -125,8 +123,6 @@ HRESULT qcap_driver_destroy(Capture *capBox)
 
     if( capBox->fd != -1 )
         video_close(capBox->fd);
-    capBox->CritSect.DebugInfo->Spare[0] = 0;
-    DeleteCriticalSection(&capBox->CritSect);
     CoTaskMemFree(capBox);
     return S_OK;
 }
@@ -389,16 +385,14 @@ static DWORD WINAPI ReadThread(LPVOID lParam)
     if (!(image_data = heap_alloc(image_size)))
     {
         ERR("Failed to allocate memory.\n");
-        capBox->thread = 0;
-        capBox->stopped = TRUE;
         return 0;
     }
 
-    while (1)
+    while (capBox->state != State_Stopped)
     {
-        EnterCriticalSection(&capBox->CritSect);
-        if (capBox->stopped)
-            break;
+        if (capBox->state == State_Paused)
+            WaitForSingleObject(capBox->run_event, INFINITE);
+
         hr = BaseOutputPinImpl_GetDeliveryBuffer(capBox->pin, &pSample, NULL, NULL, 0);
         if (SUCCEEDED(hr))
         {
@@ -432,124 +426,66 @@ static DWORD WINAPI ReadThread(LPVOID lParam)
         if (FAILED(hr) && hr != VFW_E_NOT_CONNECTED)
         {
             TRACE("Return %x, stop IFilterGraph\n", hr);
-            capBox->thread = 0;
-            capBox->stopped = TRUE;
             break;
         }
-        LeaveCriticalSection(&capBox->CritSect);
     }
 
-    LeaveCriticalSection(&capBox->CritSect);
     heap_free(image_data);
     return 0;
 }
 
-HRESULT qcap_driver_run(Capture *capBox, FILTER_STATE *state)
+void qcap_driver_init_stream(Capture *device)
 {
-    HANDLE thread;
+    ALLOCATOR_PROPERTIES req_props, ret_props;
     HRESULT hr;
 
-    TRACE("%p -> (%p)\n", capBox, state); 
-
-    if (*state == State_Running) return S_OK;
-
-    EnterCriticalSection(&capBox->CritSect);
+    req_props.cBuffers = 3;
+    if (!device->swresize)
+        req_props.cbBuffer = device->width * device->height;
+    else
+        req_props.cbBuffer = device->outputwidth * device->outputheight;
+    req_props.cbBuffer = (req_props.cbBuffer * device->bitDepth) / 8;
+    req_props.cbAlign = 1;
+    req_props.cbPrefix = 0;
 
-    capBox->stopped = FALSE;
+    hr = IMemAllocator_SetProperties(device->pin->pAllocator, &req_props, &ret_props);
+    if (FAILED(hr))
+        ERR("Failed to set allocator properties (buffer size %u), hr %#x.\n", req_props.cbBuffer, hr);
 
-    if (*state == State_Stopped && capBox->pin->pin.peer)
+    if (SUCCEEDED(hr))
     {
-        *state = State_Running;
-        if (!capBox->iscommitted)
-        {
-            ALLOCATOR_PROPERTIES ap, actual;
-
-            capBox->iscommitted = TRUE;
-
-            ap.cBuffers = 3;
-            if (!capBox->swresize)
-                ap.cbBuffer = capBox->width * capBox->height;
-            else
-                ap.cbBuffer = capBox->outputwidth * capBox->outputheight;
-            ap.cbBuffer = (ap.cbBuffer * capBox->bitDepth) / 8;
-            ap.cbAlign = 1;
-            ap.cbPrefix = 0;
-
-            hr = IMemAllocator_SetProperties(capBox->pin->pAllocator, &ap, &actual);
-
-            if (SUCCEEDED(hr))
-                hr = IMemAllocator_Commit(capBox->pin->pAllocator);
-
-            TRACE("Committing allocator: %x\n", hr);
-        }
-
-        thread = CreateThread(NULL, 0, ReadThread, capBox, 0, NULL);
-        if (thread)
-        {
-            capBox->thread = thread;
-            SetThreadPriority(thread, THREAD_PRIORITY_LOWEST);
-            LeaveCriticalSection(&capBox->CritSect);
-            return S_OK;
-        }
-        ERR("Creating thread failed.. %u\n", GetLastError());
-        LeaveCriticalSection(&capBox->CritSect);
-        return E_FAIL;
+        if (FAILED(hr = IMemAllocator_Commit(device->pin->pAllocator)))
+            ERR("Failed to commit allocator, hr %#x.\n", hr);
     }
 
-    ResumeThread(capBox->thread);
-    *state = State_Running;
-    LeaveCriticalSection(&capBox->CritSect);
-    return S_OK;
+    device->state = State_Paused;
+    device->thread = CreateThread(NULL, 0, ReadThread, device, 0, NULL);
 }
 
-HRESULT qcap_driver_pause(Capture *capBox, FILTER_STATE *state)
+void qcap_driver_start_stream(Capture *device)
 {
-    TRACE("%p -> (%p)\n", capBox, state);     
-
-    if (*state == State_Paused)
-        return S_OK;
-    if (*state == State_Stopped)
-        qcap_driver_run(capBox, state);
-
-    EnterCriticalSection(&capBox->CritSect);
-    *state = State_Paused;
-    SuspendThread(capBox->thread);
-    LeaveCriticalSection(&capBox->CritSect);
-
-    return S_OK;
+    device->state = State_Running;
+    SetEvent(device->run_event);
 }
 
-HRESULT qcap_driver_stop(Capture *capBox, FILTER_STATE *state)
+void qcap_driver_stop_stream(Capture *device)
 {
-    TRACE("%p -> (%p)\n", capBox, state);
-
-    if (*state == State_Stopped)
-        return S_OK;
-
-    EnterCriticalSection(&capBox->CritSect);
-
-    if (capBox->thread)
-    {
-        if (*state == State_Paused)
-            ResumeThread(capBox->thread);
-        capBox->stopped = TRUE;
-        capBox->thread = 0;
-        if (capBox->iscommitted)
-        {
-            HRESULT hr;
-
-            capBox->iscommitted = FALSE;
-
-            hr = IMemAllocator_Decommit(capBox->pin->pAllocator);
+    device->state = State_Paused;
+    ResetEvent(device->run_event);
+}
 
-            if (hr != S_OK && hr != VFW_E_NOT_COMMITTED)
-                WARN("Decommitting allocator: %x\n", hr);
-        }
-    }
+void qcap_driver_cleanup_stream(Capture *device)
+{
+    HRESULT hr;
 
-    *state = State_Stopped;
-    LeaveCriticalSection(&capBox->CritSect);
-    return S_OK;
+    device->state = State_Stopped;
+    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);
 }
 
 Capture *qcap_driver_init(struct strmbase_source *pin, USHORT card)
@@ -566,9 +502,6 @@ Capture *qcap_driver_init(struct strmbase_source *pin, USHORT card)
     if (!(device = CoTaskMemAlloc(sizeof(*device))))
         return NULL;
 
-    InitializeCriticalSection(&device->CritSect);
-    device->CritSect.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Capture.CritSect");
-
     sprintf(path, "/dev/video%i", card);
     TRACE("Opening device %s.\n", path);
 #ifdef O_CLOEXEC
@@ -635,8 +568,8 @@ Capture *qcap_driver_init(struct strmbase_source *pin, USHORT card)
     device->bitDepth = 24;
     device->pin = pin;
     device->fps = 3;
-    device->stopped = FALSE;
-    device->iscommitted = FALSE;
+    device->state = State_Stopped;
+    device->run_event = CreateEventW(NULL, TRUE, FALSE, NULL);
 
     TRACE("Format: %d bpp - %dx%d.\n", device->bitDepth, device->width, device->height);
 
@@ -701,17 +634,22 @@ HRESULT qcap_driver_set_prop(Capture *capBox, VideoProcAmpProperty Property,
     FAIL_WITH_ERR;
 }
 
-HRESULT qcap_driver_run(Capture *capBox, FILTER_STATE *state)
+void qcap_driver_init_stream(Capture *device)
+{
+    FAIL_WITH_ERR;
+}
+
+void qcap_driver_start_stream(Capture *device)
 {
     FAIL_WITH_ERR;
 }
 
-HRESULT qcap_driver_pause(Capture *capBox, FILTER_STATE *state)
+void qcap_driver_stop_stream(Capture *device)
 {
     FAIL_WITH_ERR;
 }
 
-HRESULT qcap_driver_stop(Capture *capBox, FILTER_STATE *state)
+void qcap_driver_cleanup_stream(Capture *device)
 {
     FAIL_WITH_ERR;
 }
diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c
index 2b60e542eba..0f8beb0f495 100644
--- a/dlls/qcap/vfwcapture.c
+++ b/dlls/qcap/vfwcapture.c
@@ -62,11 +62,6 @@ static inline VfwCapture *impl_from_strmbase_filter(struct strmbase_filter *ifac
     return CONTAINING_RECORD(iface, VfwCapture, filter);
 }
 
-static inline VfwCapture *impl_from_IBaseFilter(IBaseFilter *iface)
-{
-    return CONTAINING_RECORD(iface, VfwCapture, filter.IBaseFilter_iface);
-}
-
 static inline VfwCapture *impl_from_IAMStreamConfig(IAMStreamConfig *iface)
 {
     return CONTAINING_RECORD(iface, VfwCapture, IAMStreamConfig_iface);
@@ -99,7 +94,7 @@ static void vfw_capture_destroy(struct strmbase_filter *iface)
     if (filter->init)
     {
         if (filter->filter.state != State_Stopped)
-            qcap_driver_stop(filter->driver_info, &filter->filter.state);
+            qcap_driver_stop_stream(filter->driver_info);
         qcap_driver_destroy(filter->driver_info);
     }
 
@@ -129,47 +124,58 @@ static HRESULT vfw_capture_query_interface(struct strmbase_filter *iface, REFIID
     return S_OK;
 }
 
-static const struct strmbase_filter_ops filter_ops =
+static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface)
 {
-    .filter_get_pin = vfw_capture_get_pin,
-    .filter_destroy = vfw_capture_destroy,
-    .filter_query_interface = vfw_capture_query_interface,
-};
+    VfwCapture *filter = impl_from_strmbase_filter(iface);
 
-/** IMediaFilter methods **/
+    qcap_driver_init_stream(filter->driver_info);
+    return VFW_S_CANT_CUE;
+}
 
-static HRESULT WINAPI VfwCapture_Stop(IBaseFilter * iface)
+static HRESULT vfw_capture_start_stream(struct strmbase_filter *iface, REFERENCE_TIME time)
 {
-    VfwCapture *This = impl_from_IBaseFilter(iface);
+    VfwCapture *filter = impl_from_strmbase_filter(iface);
 
-    TRACE("()\n");
-    return qcap_driver_stop(This->driver_info, &This->filter.state);
+    qcap_driver_start_stream(filter->driver_info);
+    return S_OK;
 }
 
-static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface)
+static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface)
 {
-    VfwCapture *This = impl_from_IBaseFilter(iface);
+    VfwCapture *filter = impl_from_strmbase_filter(iface);
 
-    TRACE("()\n");
-    return qcap_driver_pause(This->driver_info, &This->filter.state);
+    qcap_driver_stop_stream(filter->driver_info);
+    return VFW_S_CANT_CUE;
 }
 
-static HRESULT WINAPI VfwCapture_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
+static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface)
 {
-    VfwCapture *This = impl_from_IBaseFilter(iface);
-    TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
-    return qcap_driver_run(This->driver_info, &This->filter.state);
+    VfwCapture *filter = impl_from_strmbase_filter(iface);
+
+    qcap_driver_cleanup_stream(filter->driver_info);
+    return S_OK;
 }
 
+static const struct strmbase_filter_ops filter_ops =
+{
+    .filter_get_pin = vfw_capture_get_pin,
+    .filter_destroy = vfw_capture_destroy,
+    .filter_query_interface = vfw_capture_query_interface,
+    .filter_init_stream = vfw_capture_init_stream,
+    .filter_start_stream = vfw_capture_start_stream,
+    .filter_stop_stream = vfw_capture_stop_stream,
+    .filter_cleanup_stream = vfw_capture_cleanup_stream,
+};
+
 static const IBaseFilterVtbl VfwCapture_Vtbl =
 {
     BaseFilterImpl_QueryInterface,
     BaseFilterImpl_AddRef,
     BaseFilterImpl_Release,
     BaseFilterImpl_GetClassID,
-    VfwCapture_Stop,
-    VfwCapture_Pause,
-    VfwCapture_Run,
+    BaseFilterImpl_Stop,
+    BaseFilterImpl_Pause,
+    BaseFilterImpl_Run,
     BaseFilterImpl_GetState,
     BaseFilterImpl_SetSyncSource,
     BaseFilterImpl_GetSyncSource,
-- 
2.23.0




More information about the wine-devel mailing list