qcap: Rework v4l2 state change logic.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2019-12-04 23:03:30 -06:00 committed by Alexandre Julliard
parent 74df86d8ed
commit 84e55192fa
3 changed files with 98 additions and 153 deletions

View File

@ -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__ */

View File

@ -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;
}
@ -397,16 +393,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))
{
@ -440,124 +434,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);
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;
if (*state == State_Running) return S_OK;
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);
EnterCriticalSection(&capBox->CritSect);
capBox->stopped = FALSE;
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);
device->state = State_Paused;
ResetEvent(device->run_event);
}
if (*state == State_Stopped)
return S_OK;
void qcap_driver_cleanup_stream(Capture *device)
{
HRESULT hr;
EnterCriticalSection(&capBox->CritSect);
device->state = State_Stopped;
WaitForSingleObject(device->thread, INFINITE);
CloseHandle(device->thread);
device->thread = NULL;
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);
if (hr != S_OK && hr != VFW_E_NOT_COMMITTED)
WARN("Decommitting allocator: %x\n", hr);
}
}
*state = State_Stopped;
LeaveCriticalSection(&capBox->CritSect);
return S_OK;
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)
@ -574,9 +510,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
@ -643,8 +576,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);
@ -709,19 +642,24 @@ 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;
ERR("v4l absent: shouldn't be called\n");
}
HRESULT qcap_driver_pause(Capture *capBox, FILTER_STATE *state)
void qcap_driver_start_stream(Capture *device)
{
FAIL_WITH_ERR;
ERR("v4l absent: shouldn't be called\n");
}
HRESULT qcap_driver_stop(Capture *capBox, FILTER_STATE *state)
void qcap_driver_stop_stream(Capture *device)
{
FAIL_WITH_ERR;
ERR("v4l absent: shouldn't be called\n");
}
void qcap_driver_cleanup_stream(Capture *device)
{
ERR("v4l absent: shouldn't be called\n");
}
#endif /* defined(VIDIOCMCAPTURE) */

View File

@ -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 HRESULT vfw_capture_init_stream(struct strmbase_filter *iface)
{
VfwCapture *filter = impl_from_strmbase_filter(iface);
qcap_driver_init_stream(filter->driver_info);
return VFW_S_CANT_CUE;
}
static HRESULT vfw_capture_start_stream(struct strmbase_filter *iface, REFERENCE_TIME time)
{
VfwCapture *filter = impl_from_strmbase_filter(iface);
qcap_driver_start_stream(filter->driver_info);
return S_OK;
}
static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface)
{
VfwCapture *filter = impl_from_strmbase_filter(iface);
qcap_driver_stop_stream(filter->driver_info);
return VFW_S_CANT_CUE;
}
static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface)
{
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,
};
/** IMediaFilter methods **/
static HRESULT WINAPI VfwCapture_Stop(IBaseFilter * iface)
{
VfwCapture *This = impl_from_IBaseFilter(iface);
TRACE("()\n");
return qcap_driver_stop(This->driver_info, &This->filter.state);
}
static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface)
{
VfwCapture *This = impl_from_IBaseFilter(iface);
TRACE("()\n");
return qcap_driver_pause(This->driver_info, &This->filter.state);
}
static HRESULT WINAPI VfwCapture_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
{
VfwCapture *This = impl_from_IBaseFilter(iface);
TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
return qcap_driver_run(This->driver_info, &This->filter.state);
}
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,