[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