Commit 26cbb3dd authored by Zebediah Figura's avatar Zebediah Figura Committed by Alexandre Julliard

qcap: Move the video capture streaming thread to vfwcapture.c.

parent db143ed0
......@@ -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);
};
......
......@@ -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,
};
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment