mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-19 17:06:04 -07:00
Merge branch 'master2' into 'master'
qcap: Add implementation of IAMVideoControl_GetFrameRateList. See merge request wine/wine!4636
This commit is contained in:
commit
230b932795
3 changed files with 229 additions and 26 deletions
|
@ -132,6 +132,22 @@ struct read_frame_params
|
|||
void *data;
|
||||
};
|
||||
|
||||
struct get_frame_rates_size_params
|
||||
{
|
||||
video_capture_device_t device;
|
||||
unsigned int index;
|
||||
SIZE *dimensions;
|
||||
LONG *list_size;
|
||||
};
|
||||
|
||||
struct get_frame_avg_time_params
|
||||
{
|
||||
video_capture_device_t device;
|
||||
unsigned int index;
|
||||
LONG list_size;
|
||||
LONGLONG *frame_rate;
|
||||
};
|
||||
|
||||
enum unix_funcs
|
||||
{
|
||||
unix_create,
|
||||
|
@ -147,6 +163,8 @@ enum unix_funcs
|
|||
unix_get_prop,
|
||||
unix_set_prop,
|
||||
unix_read_frame,
|
||||
unix_get_frame_rates_size,
|
||||
unix_get_frame_avg_time,
|
||||
unix_funcs_count
|
||||
};
|
||||
|
||||
|
|
192
dlls/qcap/v4l.c
192
dlls/qcap/v4l.c
|
@ -60,6 +60,9 @@ static typeof(close) *video_close = close;
|
|||
static typeof(ioctl) *video_ioctl = ioctl;
|
||||
static typeof(read) *video_read = read;
|
||||
|
||||
#define SECOND_IN_100NS (LONGLONG)10000000
|
||||
#define DEFAULT_FPS 25
|
||||
|
||||
static BOOL video_init(void)
|
||||
{
|
||||
#ifdef SONAME_LIBV4L2
|
||||
|
@ -86,6 +89,8 @@ struct caps
|
|||
AM_MEDIA_TYPE media_type;
|
||||
VIDEOINFOHEADER video_info;
|
||||
VIDEO_STREAM_CONFIG_CAPS config;
|
||||
LONG fps_count;
|
||||
__u32* fps_list;
|
||||
};
|
||||
|
||||
struct video_capture_device
|
||||
|
@ -122,6 +127,10 @@ static void device_destroy(struct video_capture_device *device)
|
|||
{
|
||||
if (device->fd != -1)
|
||||
video_close(device->fd);
|
||||
for (int index = 0; index < device->caps_count; index++)
|
||||
{
|
||||
free(device->caps[index].fps_list) ;
|
||||
}
|
||||
if (device->caps_count)
|
||||
free(device->caps);
|
||||
free(device->image_data);
|
||||
|
@ -367,10 +376,72 @@ static NTSTATUS v4l_device_read_frame( void *args )
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static int get_fps_list(int fd, __u32 format, __u32 width, __u32 height, __u32 *fps_count, __u32 **fps_list)
|
||||
{
|
||||
struct v4l2_frmivalenum frmival = {.index=0, .pixel_format=format, .width=width, .height=height};
|
||||
__u32 fps_index = 0, *fps_frame = NULL;
|
||||
|
||||
while (xioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) != -1)
|
||||
{
|
||||
if (frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE)
|
||||
{
|
||||
fps_frame = realloc(fps_frame, (fps_index + 1) * sizeof(__u32));
|
||||
if (fps_frame && frmival.discrete.denominator && frmival.discrete.numerator)
|
||||
{
|
||||
fps_frame[fps_index] = frmival.discrete.denominator / frmival.discrete.numerator;
|
||||
fps_index++;
|
||||
}
|
||||
}
|
||||
else if (frmival.type == V4L2_FRMIVAL_TYPE_STEPWISE
|
||||
|| frmival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)
|
||||
{
|
||||
__u32 fps_step = 0, fps_max = 0, fps_min = 0;
|
||||
if(frmival.stepwise.step.denominator && frmival.stepwise.step.numerator)
|
||||
fps_step = frmival.stepwise.step.denominator / frmival.stepwise.step.numerator;
|
||||
/*The maximum FPS is the inverse of the minimum frame time, not the maximum frame time, and vice versa.*/
|
||||
if(frmival.stepwise.min.denominator && frmival.stepwise.min.numerator)
|
||||
fps_max = frmival.stepwise.min.denominator / frmival.stepwise.min.numerator;
|
||||
if(frmival.stepwise.max.denominator && frmival.stepwise.max.numerator)
|
||||
fps_min = frmival.stepwise.max.denominator / frmival.stepwise.max.numerator;
|
||||
|
||||
if(fps_step && fps_max && fps_min)
|
||||
{
|
||||
do
|
||||
{
|
||||
fps_frame = realloc(fps_frame, (fps_index + 1) * sizeof(__u32));
|
||||
if (fps_frame)
|
||||
{
|
||||
fps_frame[fps_index] = fps_max;
|
||||
fps_index++;
|
||||
}
|
||||
fps_max -= fps_step;
|
||||
}while(fps_max >= fps_min);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
frmival.index++;
|
||||
}
|
||||
|
||||
if(fps_count) *fps_count = fps_index;
|
||||
if(fps_list) *fps_list = fps_frame;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fill_caps(__u32 pixelformat, __u32 width, __u32 height,
|
||||
__u32 max_fps, __u32 min_fps, struct caps *caps)
|
||||
__u32 fps_count, __u32 *fps_list, struct caps *caps)
|
||||
{
|
||||
LONG depth = 24;
|
||||
__u32 max_fps = DEFAULT_FPS, min_fps = DEFAULT_FPS;
|
||||
|
||||
for(int i = 0; i < fps_count; ++i)
|
||||
{
|
||||
if(max_fps < fps_list[i])
|
||||
max_fps = fps_list[i];
|
||||
if(min_fps > fps_list[i])
|
||||
min_fps = fps_list[i];
|
||||
}
|
||||
|
||||
memset(caps, 0, sizeof(*caps));
|
||||
caps->video_info.dwBitRate = width * height * depth * max_fps;
|
||||
|
@ -391,8 +462,8 @@ static void fill_caps(__u32 pixelformat, __u32 width, __u32 height,
|
|||
caps->media_type.cbFormat = sizeof(VIDEOINFOHEADER);
|
||||
/* We reallocate the caps array, so pbFormat has to be set after all caps
|
||||
* have been enumerated. */
|
||||
caps->config.MaxFrameInterval = 10000000 / max_fps;
|
||||
caps->config.MinFrameInterval = 10000000 / min_fps;
|
||||
caps->config.MaxFrameInterval = SECOND_IN_100NS / max_fps;
|
||||
caps->config.MinFrameInterval = SECOND_IN_100NS / min_fps;
|
||||
caps->config.MaxOutputSize.cx = width;
|
||||
caps->config.MaxOutputSize.cy = height;
|
||||
caps->config.MinOutputSize.cx = width;
|
||||
|
@ -401,6 +472,8 @@ static void fill_caps(__u32 pixelformat, __u32 width, __u32 height,
|
|||
caps->config.MinBitsPerSecond = width * height * depth * min_fps;
|
||||
caps->config.MaxBitsPerSecond = width * height * depth * max_fps;
|
||||
caps->pixelformat = pixelformat;
|
||||
caps->fps_count = fps_count;
|
||||
caps->fps_list = fps_list;
|
||||
}
|
||||
|
||||
static NTSTATUS v4l_device_get_caps( void *args )
|
||||
|
@ -502,10 +575,10 @@ static NTSTATUS v4l_device_create( void *args )
|
|||
while (xioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) != -1)
|
||||
{
|
||||
struct v4l2_frmivalenum frmival = {0};
|
||||
__u32 max_fps = 30, min_fps = 30;
|
||||
__u32 fps_count, *fps_list;
|
||||
struct caps *new_caps;
|
||||
|
||||
frmival.pixel_format = format.fmt.pix.pixelformat;
|
||||
frmival.pixel_format = frmsize.pixel_format;
|
||||
if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE)
|
||||
{
|
||||
frmival.width = frmsize.discrete.width;
|
||||
|
@ -522,29 +595,14 @@ static NTSTATUS v4l_device_create( void *args )
|
|||
continue;
|
||||
}
|
||||
|
||||
if (xioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) != -1)
|
||||
{
|
||||
if (frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE)
|
||||
{
|
||||
max_fps = frmival.discrete.denominator / frmival.discrete.numerator;
|
||||
min_fps = max_fps;
|
||||
}
|
||||
else if (frmival.type == V4L2_FRMIVAL_TYPE_STEPWISE
|
||||
|| frmival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)
|
||||
{
|
||||
min_fps = frmival.stepwise.max.denominator / frmival.stepwise.max.numerator;
|
||||
max_fps = frmival.stepwise.min.denominator / frmival.stepwise.min.numerator;
|
||||
}
|
||||
}
|
||||
else
|
||||
ERR("Failed to get fps: %s.\n", strerror(errno));
|
||||
get_fps_list(fd, frmival.pixel_format, frmival.width, frmival.height, &fps_count, &fps_list);
|
||||
|
||||
new_caps = realloc(device->caps, (device->caps_count + 1) * sizeof(*device->caps));
|
||||
if (!new_caps)
|
||||
goto error;
|
||||
device->caps = new_caps;
|
||||
fill_caps(format.fmt.pix.pixelformat, frmsize.discrete.width, frmsize.discrete.height,
|
||||
max_fps, min_fps, &device->caps[device->caps_count]);
|
||||
fill_caps(frmival.pixel_format, frmival.width, frmival.height,
|
||||
fps_count, fps_list, &device->caps[device->caps_count]);
|
||||
device->caps_count++;
|
||||
|
||||
frmsize.index++;
|
||||
|
@ -597,6 +655,48 @@ static NTSTATUS v4l_device_destroy( void *args )
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS v4l_device_get_frame_rates_size( void *args )
|
||||
{
|
||||
const struct get_frame_rates_size_params *params = args;
|
||||
struct video_capture_device *device = get_device(params->device);
|
||||
SIZE *dimensions = (SIZE *)params->dimensions;
|
||||
|
||||
LONG width, height;
|
||||
|
||||
unsigned int caps_count = device->caps_count;
|
||||
if (params->index >= caps_count)
|
||||
return E_INVALIDARG;
|
||||
|
||||
width = device->caps[params->index].video_info.bmiHeader.biWidth;
|
||||
height = device->caps[params->index].video_info.bmiHeader.biHeight;
|
||||
if((dimensions->cx != width) || (dimensions->cy != height))
|
||||
{
|
||||
WARN("requested demensions unsupport !!!\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
*params->list_size = device->caps[params->index].fps_count;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS v4l_device_get_frame_avg_time( void *args )
|
||||
{
|
||||
const struct get_frame_avg_time_params *params = args;
|
||||
struct video_capture_device *device = get_device(params->device);
|
||||
|
||||
unsigned int caps_count = device->caps_count;
|
||||
if (params->index >= caps_count)
|
||||
return E_INVALIDARG ;
|
||||
|
||||
for(int i = 0; i < params->list_size; ++i)
|
||||
{
|
||||
__u32* fps = device->caps[params->index].fps_list;
|
||||
if(fps[i]) (params->frame_rate)[i] = SECOND_IN_100NS / fps[i];
|
||||
else (params->frame_rate)[i] = SECOND_IN_100NS / DEFAULT_FPS;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
const unixlib_entry_t __wine_unix_call_funcs[] =
|
||||
{
|
||||
v4l_device_create,
|
||||
|
@ -612,6 +712,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
|
|||
v4l_device_get_prop,
|
||||
v4l_device_set_prop,
|
||||
v4l_device_read_frame,
|
||||
v4l_device_get_frame_rates_size,
|
||||
v4l_device_get_frame_avg_time,
|
||||
};
|
||||
|
||||
C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs) == unix_funcs_count );
|
||||
|
@ -864,6 +966,48 @@ static NTSTATUS wow64_v4l_device_read_frame( void *args )
|
|||
return v4l_device_read_frame( ¶ms );
|
||||
}
|
||||
|
||||
static NTSTATUS wow64_v4l_device_get_frame_rates_size( void *args )
|
||||
{
|
||||
struct
|
||||
{
|
||||
video_capture_device_t device;
|
||||
unsigned int index;
|
||||
PTR32 dimensions;
|
||||
PTR32 list_size;
|
||||
} const *params32 = args;
|
||||
|
||||
struct get_frame_rates_size_params params =
|
||||
{
|
||||
params32->device,
|
||||
params32->index,
|
||||
ULongToPtr(params32->dimensions),
|
||||
ULongToPtr(params32->list_size)
|
||||
};
|
||||
|
||||
return v4l_device_get_frame_rates_size( ¶ms );
|
||||
}
|
||||
|
||||
static NTSTATUS wow64_v4l_device_get_frame_avg_time( void *args )
|
||||
{
|
||||
struct
|
||||
{
|
||||
video_capture_device_t device;
|
||||
unsigned int index;
|
||||
int list_size;
|
||||
PTR32 frame_rate;
|
||||
} const *params32 = args;
|
||||
|
||||
struct get_frame_avg_time_params params =
|
||||
{
|
||||
params32->device,
|
||||
params32->index,
|
||||
params32->list_size,
|
||||
ULongToPtr(params32->frame_rate)
|
||||
};
|
||||
|
||||
return v4l_device_get_frame_avg_time( ¶ms );
|
||||
}
|
||||
|
||||
const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
|
||||
{
|
||||
wow64_v4l_device_create,
|
||||
|
@ -879,6 +1023,8 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
|
|||
wow64_v4l_device_get_prop,
|
||||
v4l_device_set_prop,
|
||||
wow64_v4l_device_read_frame,
|
||||
wow64_v4l_device_get_frame_rates_size,
|
||||
wow64_v4l_device_get_frame_avg_time,
|
||||
};
|
||||
|
||||
C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_funcs_count );
|
||||
|
|
|
@ -429,7 +429,7 @@ static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
|
|||
TRACE("filter %p, index %d, pmt %p, vscc %p.\n", filter, index, pmt, vscc);
|
||||
|
||||
V4L_CALL( get_caps_count, &count_params );
|
||||
if (index > count)
|
||||
if (index >= count)
|
||||
return S_FALSE;
|
||||
|
||||
if (!(mt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
|
||||
|
@ -860,12 +860,51 @@ static HRESULT WINAPI video_control_GetMaxAvailableFrameRate(IAMVideoControl *if
|
|||
static HRESULT WINAPI video_control_GetFrameRateList(IAMVideoControl *iface, IPin *pin, LONG index,
|
||||
SIZE dimensions, LONG *list_size, LONGLONG **frame_rate)
|
||||
{
|
||||
LONG size;
|
||||
LONGLONG *rate;
|
||||
int count;
|
||||
HRESULT hr;
|
||||
struct get_caps_count_params count_params;
|
||||
struct get_frame_rates_size_params size_params;
|
||||
struct get_frame_avg_time_params rate_params;
|
||||
struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
|
||||
|
||||
FIXME("filter %p, pin %p, index %ld, dimensions (%ldx%ld), list size %p, frame rate %p, stub.\n",
|
||||
TRACE("filter %p, pin %p, index %ld, dimensions (%ldx%ld), list size %p, frame rate: %p\n",
|
||||
filter, pin, index, dimensions.cx, dimensions.cy, list_size, frame_rate);
|
||||
|
||||
return E_NOTIMPL;
|
||||
if(!list_size) return S_FALSE;
|
||||
count_params.device = filter->device;
|
||||
count_params.count = &count;
|
||||
V4L_CALL( get_caps_count, &count_params );
|
||||
if (index >= count)
|
||||
return S_FALSE;
|
||||
|
||||
size_params.device = filter->device;
|
||||
size_params.index = index;
|
||||
size_params.dimensions = &dimensions;
|
||||
size_params.list_size = &size;
|
||||
V4L_CALL( get_frame_rates_size, &size_params );
|
||||
if(size < 0)
|
||||
return E_FAIL;
|
||||
|
||||
*list_size=size;
|
||||
if(!frame_rate) return S_OK;
|
||||
|
||||
if (!(rate = CoTaskMemAlloc(sizeof(LONGLONG)*size)))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
rate_params.device = filter->device;
|
||||
rate_params.index = index;
|
||||
rate_params.list_size = size;
|
||||
rate_params.frame_rate = rate;
|
||||
if ((hr = V4L_CALL( get_frame_avg_time, &rate_params )) != S_OK)
|
||||
{
|
||||
CoTaskMemFree(rate);
|
||||
return hr;
|
||||
}
|
||||
|
||||
*frame_rate=rate;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IAMVideoControlVtbl IAMVideoControl_VTable =
|
||||
|
|
Loading…
Reference in a new issue