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:
parent
74df86d8ed
commit
84e55192fa
|
@ -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__ */
|
||||
|
|
170
dlls/qcap/v4l.c
170
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;
|
||||
}
|
||||
|
@ -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) */
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue