From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/v4l.c | 126 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 119 insertions(+), 7 deletions(-)
diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index 6fe92d2d0a..53f379d80b 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -93,9 +93,19 @@ static BOOL video_init(void) #endif }
+struct caps +{ + __u32 pixelformat; + AM_MEDIA_TYPE media_type; + VIDEOINFOHEADER video_info; + VIDEO_STREAM_CONFIG_CAPS config; +}; + struct _Capture { UINT width, height, bitDepth, fps, outputwidth, outputheight; + struct caps *caps; + LONG caps_count; BOOL swresize;
struct strmbase_source *pin; @@ -116,13 +126,14 @@ static int xioctl(int fd, int request, void * arg) return r; }
-HRESULT qcap_driver_destroy(Capture *capBox) +HRESULT qcap_driver_destroy(Capture *device) { - TRACE("%p\n", capBox); + if (device->fd != -1) + video_close(device->fd); + if (device->caps_count) + heap_free(device->caps); + heap_free(device);
- if( capBox->fd != -1 ) - video_close(capBox->fd); - CoTaskMemFree(capBox); return S_OK; }
@@ -495,18 +506,55 @@ void qcap_driver_cleanup_stream(Capture *device) ERR("Failed to decommit allocator, hr %#x.\n", hr); }
+ +static void fill_caps(__u32 pixelformat, __u32 width, __u32 height, + __u32 max_fps, __u32 min_fps, struct caps *caps) +{ + LONG depth = 24; + + caps->video_info.dwBitRate = width * height * depth * max_fps; + caps->video_info.bmiHeader.biSize = sizeof(caps->video_info.bmiHeader); + caps->video_info.bmiHeader.biWidth = width; + caps->video_info.bmiHeader.biHeight = height; + caps->video_info.bmiHeader.biPlanes = 1; + caps->video_info.bmiHeader.biBitCount = depth; + caps->video_info.bmiHeader.biCompression = BI_RGB; + caps->video_info.bmiHeader.biSizeImage = width * height * depth / 8; + caps->media_type.majortype = MEDIATYPE_Video; + caps->media_type.subtype = MEDIASUBTYPE_RGB24; + caps->media_type.bFixedSizeSamples = TRUE; + caps->media_type.bTemporalCompression = FALSE; + caps->media_type.lSampleSize = width * height * depth / 8; + caps->media_type.formattype = FORMAT_VideoInfo; + caps->media_type.pUnk = NULL; + 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.MaxOutputSize.cx = width; + caps->config.MaxOutputSize.cy = height; + caps->config.MinOutputSize.cx = width; + caps->config.MinOutputSize.cy = height; + caps->config.guid = FORMAT_VideoInfo; + caps->config.MinBitsPerSecond = width * height * depth * min_fps; + caps->config.MaxBitsPerSecond = width * height * depth * max_fps; + caps->pixelformat = pixelformat; +} + Capture *qcap_driver_init(struct strmbase_source *pin, USHORT card) { + struct v4l2_frmsizeenum frmsize = {0}; struct v4l2_capability caps = {{0}}; struct v4l2_format format = {0}; Capture *device = NULL; BOOL have_libv4l2; char path[20]; - int fd; + int fd, i;
have_libv4l2 = video_init();
- if (!(device = CoTaskMemAlloc(sizeof(*device)))) + if (!(device = heap_alloc_zero(sizeof(*device)))) return NULL;
sprintf(path, "/dev/video%i", card); @@ -559,6 +607,70 @@ Capture *qcap_driver_init(struct strmbase_source *pin, USHORT card) goto error; }
+ format.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24; + if (xioctl(fd, VIDIOC_TRY_FMT, &format) == -1 + || format.fmt.pix.pixelformat != V4L2_PIX_FMT_BGR24) + { + ERR("This device doesn't support V4L2_PIX_FMT_BGR24 format.\n"); + goto error; + } + + frmsize.pixel_format = V4L2_PIX_FMT_BGR24; + while (xioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) != -1) + { + struct v4l2_frmivalenum frmival = {0}; + __u32 max_fps = 30, min_fps = 30; + struct caps *new_caps; + + frmival.pixel_format = format.fmt.pix.pixelformat; + if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) + { + frmival.width = frmsize.discrete.width; + frmival.height = frmsize.discrete.height; + } + else if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) + { + frmival.width = frmsize.stepwise.max_width; + frmival.height = frmsize.stepwise.min_height; + } + else + { + FIXME("Unhandled frame size type: %d.\n", frmsize.type); + 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) + { + max_fps = frmival.stepwise.max.denominator / frmival.stepwise.max.numerator; + min_fps = frmival.stepwise.min.denominator / frmival.stepwise.min.numerator; + } + } + else + ERR("Failed to get fps: %s.\n", strerror(errno)); + + new_caps = heap_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]); + device->caps_count++; + + frmsize.index++; + } + + /* We reallocate the caps array, so we have to delay setting pbFormat. */ + for (i = 0; i < device->caps_count; ++i) + device->caps[i].media_type.pbFormat = (BYTE *)&device->caps[i].video_info; + format.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24; if (xioctl(fd, VIDIOC_S_FMT, &format) == -1 || format.fmt.pix.pixelformat != V4L2_PIX_FMT_BGR24)
From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/tests/videocapture.c | 63 ++++++++++ dlls/qcap/v4l.c | 203 ++++++++++++++------------------- dlls/qcap/vfwcapture.c | 3 + 3 files changed, 154 insertions(+), 115 deletions(-)
diff --git a/dlls/qcap/tests/videocapture.c b/dlls/qcap/tests/videocapture.c index 5532654650..39535adece 100644 --- a/dlls/qcap/tests/videocapture.c +++ b/dlls/qcap/tests/videocapture.c @@ -21,6 +21,7 @@ #define COBJMACROS #include "dshow.h" #include "wine/test.h" +#include "wine/strmbase.h"
static void test_media_types(IPin *pin) { @@ -59,6 +60,65 @@ static void test_media_types(IPin *pin) ok(hr != S_OK, "Got hr %#x.\n", hr); }
+static void test_stream_config(IPin *pin) +{ + VIDEOINFOHEADER *video_info, *video_info2; + AM_MEDIA_TYPE *format, *format2; + IAMStreamConfig *stream_config; + LONG depth, compression; + HRESULT hr; + + hr = IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **)&stream_config); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IAMStreamConfig_GetFormat(stream_config, &format); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(IsEqualGUID(&format->majortype, &MEDIATYPE_Video), "Got wrong majortype: %s.\n", + debugstr_guid(&format->majortype)); + + hr = IAMStreamConfig_SetFormat(stream_config, format); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + format->majortype = MEDIATYPE_Audio; + hr = IAMStreamConfig_SetFormat(stream_config, format); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + format->majortype = MEDIATYPE_Video; + video_info = (VIDEOINFOHEADER *)format->pbFormat; + video_info->bmiHeader.biWidth--; + video_info->bmiHeader.biHeight--; + hr = IAMStreamConfig_SetFormat(stream_config, format); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + depth = video_info->bmiHeader.biBitCount; + compression = video_info->bmiHeader.biCompression; + video_info->bmiHeader.biWidth++; + video_info->bmiHeader.biHeight++; + video_info->bmiHeader.biBitCount = 0; + video_info->bmiHeader.biCompression = 0; + hr = IAMStreamConfig_SetFormat(stream_config, format); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IAMStreamConfig_GetFormat(stream_config, &format2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(IsEqualGUID(&format2->majortype, &MEDIATYPE_Video), "Got wrong majortype: %s.\n", + debugstr_guid(&format2->majortype)); + video_info2 = (VIDEOINFOHEADER *)format2->pbFormat; + ok(video_info2->bmiHeader.biBitCount == depth, "Got wrong depth: %d.\n", + video_info2->bmiHeader.biBitCount); + ok(video_info2->bmiHeader.biCompression == compression, + "Got wrong compression: %d.\n", video_info2->bmiHeader.biCompression); + FreeMediaType(format2); + + video_info->bmiHeader.biWidth = 10000000; + video_info->bmiHeader.biHeight = 10000000; + hr = IAMStreamConfig_SetFormat(stream_config, format); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + FreeMediaType(format); + + IAMStreamConfig_Release(stream_config); +} + static void test_capture(IBaseFilter *filter) { IEnumPins *enum_pins; @@ -73,7 +133,10 @@ static void test_capture(IBaseFilter *filter) PIN_DIRECTION pin_direction; IPin_QueryDirection(pin, &pin_direction); if (pin_direction == PINDIR_OUTPUT) + { test_media_types(pin); + test_stream_config(pin); + } IPin_Release(pin); }
diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index 53f379d80b..f638aa18b9 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -103,7 +103,8 @@ struct caps
struct _Capture { - UINT width, height, bitDepth, fps, outputwidth, outputheight; + UINT outputwidth, outputheight; + const struct caps *current_caps; struct caps *caps; LONG caps_count; BOOL swresize; @@ -137,126 +138,95 @@ HRESULT qcap_driver_destroy(Capture *device) return S_OK; }
+static const struct caps *find_caps(Capture *device, const AM_MEDIA_TYPE *mt) +{ + const VIDEOINFOHEADER *video_info = (VIDEOINFOHEADER *)mt->pbFormat; + LONG index; + + if (mt->cbFormat < sizeof(VIDEOINFOHEADER) || !video_info) + return NULL; + + for (index = 0; index < device->caps_count; index++) + { + struct caps *caps = &device->caps[index]; + + if (IsEqualGUID(&mt->formattype, &caps->media_type.formattype) + && video_info->bmiHeader.biWidth == caps->video_info.bmiHeader.biWidth + && video_info->bmiHeader.biHeight == caps->video_info.bmiHeader.biHeight) + return caps; + } + return NULL; +} + HRESULT qcap_driver_check_format(Capture *device, const AM_MEDIA_TYPE *mt) { - HRESULT hr; TRACE("device %p, mt %p.\n", device, mt);
if (!mt) return E_POINTER;
if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Video)) - return S_FALSE; + return E_FAIL; + + if (find_caps(device, mt)) + return S_OK;
- if (IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo) && mt->pbFormat - && mt->cbFormat >= sizeof(VIDEOINFOHEADER)) + return E_FAIL; +} + +static BOOL set_caps(Capture *device, const struct caps *caps) +{ + struct v4l2_format format = {0}; + LONG width, height; + + width = caps->video_info.bmiHeader.biWidth; + height = caps->video_info.bmiHeader.biHeight; + + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + format.fmt.pix.pixelformat = caps->pixelformat; + format.fmt.pix.width = width; + format.fmt.pix.height = height; + if (xioctl(device->fd, VIDIOC_S_FMT, &format) == -1 + || format.fmt.pix.pixelformat != caps->pixelformat + || format.fmt.pix.width != width + || format.fmt.pix.height != height) { - VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)mt->pbFormat; - if (vih->bmiHeader.biBitCount == 24 && vih->bmiHeader.biCompression == BI_RGB) - hr = S_OK; - else - { - FIXME("Unsupported compression %#x, bpp %u.\n", vih->bmiHeader.biCompression, - vih->bmiHeader.biBitCount); - hr = S_FALSE; - } + ERR("Failed to set pixel format: %s.\n", strerror(errno)); + return FALSE; } - else - hr = VFW_E_INVALIDMEDIATYPE;
- return hr; + device->current_caps = caps; + device->outputwidth = width; + device->outputheight = height; + device->swresize = FALSE; + + return TRUE; }
HRESULT qcap_driver_set_format(Capture *device, AM_MEDIA_TYPE *mt) { - struct v4l2_format format = {0}; - int newheight, newwidth; - VIDEOINFOHEADER *vih; - int fd = device->fd; - HRESULT hr; + const struct caps *caps;
- if (FAILED(hr = qcap_driver_check_format(device, mt))) - return hr; - vih = (VIDEOINFOHEADER *)mt->pbFormat; - - newwidth = vih->bmiHeader.biWidth; - newheight = vih->bmiHeader.biHeight; + caps = find_caps(device, mt); + if (!caps) + return E_FAIL;
- if (device->height == newheight && device->width == newwidth) + if (device->current_caps == caps) return S_OK;
- format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (xioctl(fd, VIDIOC_G_FMT, &format) == -1) - { - ERR("Failed to get current format: %s\n", strerror(errno)); + if (!set_caps(device, caps)) return VFW_E_TYPE_NOT_ACCEPTED; - } - - format.fmt.pix.width = newwidth; - format.fmt.pix.height = newheight;
- if (!xioctl(fd, VIDIOC_S_FMT, &format) - && format.fmt.pix.width == newwidth - && format.fmt.pix.height == newheight) - { - device->width = newwidth; - device->height = newheight; - device->swresize = FALSE; - } - else - { - TRACE("Using software resize: %dx%d -> %dx%d.\n", - format.fmt.pix.width, format.fmt.pix.height, device->width, device->height); - device->swresize = TRUE; - } - device->outputwidth = format.fmt.pix.width; - device->outputheight = format.fmt.pix.height; return S_OK; }
-HRESULT qcap_driver_get_format(const Capture *capBox, AM_MEDIA_TYPE ** mT) +HRESULT qcap_driver_get_format(const Capture *device, AM_MEDIA_TYPE **mt) { - VIDEOINFOHEADER *vi; - - mT[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); - if (!mT[0]) + *mt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + if (!*mt) return E_OUTOFMEMORY; - vi = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER)); - mT[0]->cbFormat = sizeof(VIDEOINFOHEADER); - if (!vi) - { - CoTaskMemFree(mT[0]); - mT[0] = NULL; - return E_OUTOFMEMORY; - } - mT[0]->majortype = MEDIATYPE_Video; - mT[0]->subtype = MEDIASUBTYPE_RGB24; - mT[0]->formattype = FORMAT_VideoInfo; - mT[0]->bFixedSizeSamples = TRUE; - mT[0]->bTemporalCompression = FALSE; - mT[0]->pUnk = NULL; - mT[0]->lSampleSize = capBox->outputwidth * capBox->outputheight * capBox->bitDepth / 8; - TRACE("Output format: %dx%d - %d bits = %u KB\n", capBox->outputwidth, - capBox->outputheight, capBox->bitDepth, mT[0]->lSampleSize/1024); - vi->rcSource.left = 0; vi->rcSource.top = 0; - vi->rcTarget.left = 0; vi->rcTarget.top = 0; - vi->rcSource.right = capBox->width; vi->rcSource.bottom = capBox->height; - vi->rcTarget.right = capBox->outputwidth; vi->rcTarget.bottom = capBox->outputheight; - vi->dwBitRate = capBox->fps * mT[0]->lSampleSize; - vi->dwBitErrorRate = 0; - vi->AvgTimePerFrame = (LONGLONG)10000000.0 / (LONGLONG)capBox->fps; - vi->bmiHeader.biSize = 40; - vi->bmiHeader.biWidth = capBox->outputwidth; - vi->bmiHeader.biHeight = capBox->outputheight; - vi->bmiHeader.biPlanes = 1; - vi->bmiHeader.biBitCount = 24; - vi->bmiHeader.biCompression = BI_RGB; - vi->bmiHeader.biSizeImage = mT[0]->lSampleSize; - vi->bmiHeader.biClrUsed = vi->bmiHeader.biClrImportant = 0; - vi->bmiHeader.biXPelsPerMeter = 100; - vi->bmiHeader.biYPelsPerMeter = 100; - mT[0]->pbFormat = (void *)vi; - return S_OK; + + return CopyMediaType(*mt, &device->current_caps->media_type); }
static __u32 v4l2_cid_from_qcap_property(VideoProcAmpProperty property) @@ -336,13 +306,18 @@ HRESULT qcap_driver_set_prop(Capture *device, VideoProcAmpProperty property,
static void Resize(const Capture * capBox, LPBYTE output, const BYTE *input) { + UINT width, height, bitdepth, depth; + + width = capBox->current_caps->video_info.bmiHeader.biWidth; + height = capBox->current_caps->video_info.bmiHeader.biHeight; + bitdepth = capBox->current_caps->video_info.bmiHeader.biBitCount; + depth = bitdepth / 8; /* the whole image needs to be reversed, because the dibs are messed up in windows */ if (!capBox->swresize) { - int depth = capBox->bitDepth / 8; - int inoffset = 0, outoffset = capBox->height * capBox->width * depth; - int ow = capBox->width * depth; + int inoffset = 0, outoffset = width * height * depth; + int ow = width * depth; while (outoffset > 0) { int x; @@ -356,7 +331,6 @@ static void Resize(const Capture * capBox, LPBYTE output, const BYTE *input) { HDC dc_s, dc_d; HBITMAP bmp_s, bmp_d; - int depth = capBox->bitDepth / 8; int inoffset = 0, outoffset = (capBox->outputheight) * capBox->outputwidth * depth; int ow = capBox->outputwidth * depth; LPBYTE myarray; @@ -366,12 +340,12 @@ static void Resize(const Capture * capBox, LPBYTE output, const BYTE *input) myarray = CoTaskMemAlloc(capBox->outputwidth * capBox->outputheight * depth); dc_s = CreateCompatibleDC(NULL); dc_d = CreateCompatibleDC(NULL); - bmp_s = CreateBitmap(capBox->width, capBox->height, 1, capBox->bitDepth, input); - bmp_d = CreateBitmap(capBox->outputwidth, capBox->outputheight, 1, capBox->bitDepth, NULL); + bmp_s = CreateBitmap(width, height, 1, bitdepth, input); + bmp_d = CreateBitmap(capBox->outputwidth, capBox->outputheight, 1, bitdepth, NULL); SelectObject(dc_s, bmp_s); SelectObject(dc_d, bmp_d); StretchBlt(dc_d, 0, 0, capBox->outputwidth, capBox->outputheight, - dc_s, 0, 0, capBox->width, capBox->height, SRCCOPY); + dc_s, 0, 0, width, height, SRCCOPY); GetBitmapBits(bmp_d, capBox->outputwidth * capBox->outputheight * depth, myarray); while (outoffset > 0) { @@ -398,8 +372,12 @@ static DWORD WINAPI ReadThread(LPVOID lParam) ULONG framecount = 0; unsigned char *pTarget, *image_data; unsigned int image_size; + UINT width, height, depth;
- image_size = capBox->height * capBox->width * 3; + width = capBox->current_caps->video_info.bmiHeader.biWidth; + height = capBox->current_caps->video_info.bmiHeader.biHeight; + depth = capBox->current_caps->video_info.bmiHeader.biBitCount / 8; + image_size = width * height * depth; if (!(image_data = heap_alloc(image_size))) { ERR("Failed to allocate memory.\n"); @@ -417,9 +395,9 @@ static DWORD WINAPI ReadThread(LPVOID lParam) int len;
if (!capBox->swresize) - len = capBox->height * capBox->width * capBox->bitDepth / 8; + len = width * height * depth; else - len = capBox->outputheight * capBox->outputwidth * capBox->bitDepth / 8; + len = capBox->outputheight * capBox->outputwidth * depth; IMediaSample_SetActualDataLength(pSample, len);
len = IMediaSample_GetActualDataLength(pSample); @@ -459,10 +437,10 @@ void qcap_driver_init_stream(Capture *device)
req_props.cBuffers = 3; if (!device->swresize) - req_props.cbBuffer = device->width * device->height; + req_props.cbBuffer = device->current_caps->video_info.bmiHeader.biWidth * device->current_caps->video_info.bmiHeader.biHeight; else req_props.cbBuffer = device->outputwidth * device->outputheight; - req_props.cbBuffer = (req_props.cbBuffer * device->bitDepth) / 8; + req_props.cbBuffer = (req_props.cbBuffer * device->current_caps->video_info.bmiHeader.biBitCount) / 8; req_props.cbAlign = 1; req_props.cbPrefix = 0;
@@ -671,9 +649,7 @@ Capture *qcap_driver_init(struct strmbase_source *pin, USHORT card) for (i = 0; i < device->caps_count; ++i) device->caps[i].media_type.pbFormat = (BYTE *)&device->caps[i].video_info;
- format.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24; - if (xioctl(fd, VIDIOC_S_FMT, &format) == -1 - || format.fmt.pix.pixelformat != V4L2_PIX_FMT_BGR24) + if (!set_caps(device, &device->caps[0])) { ERR("Failed to set pixel format: %s\n", strerror(errno)); if (!have_libv4l2) @@ -681,16 +657,13 @@ Capture *qcap_driver_init(struct strmbase_source *pin, USHORT card) goto error; }
- device->outputwidth = device->width = format.fmt.pix.width; - device->outputheight = device->height = format.fmt.pix.height; - device->swresize = FALSE; - device->bitDepth = 24; device->pin = pin; - device->fps = 3; 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); + TRACE("Format: %d bpp - %dx%d.\n", device->current_caps->video_info.bmiHeader.biBitCount, + device->current_caps->video_info.bmiHeader.biWidth, + device->current_caps->video_info.bmiHeader.biHeight);
return device;
diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c index 4b1d14082a..6c9cc3ce51 100644 --- a/dlls/qcap/vfwcapture.c +++ b/dlls/qcap/vfwcapture.c @@ -207,6 +207,9 @@ AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt) return E_POINTER; }
+ if (!IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video)) + return E_FAIL; + if (This->source.pin.peer) { hr = IPin_QueryAccept(This->source.pin.peer, pmt);
From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/v4l.c | 84 +++++++++++-------------------------------------- 1 file changed, 18 insertions(+), 66 deletions(-)
diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index f638aa18b9..27970ff228 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -103,11 +103,9 @@ struct caps
struct _Capture { - UINT outputwidth, outputheight; const struct caps *current_caps; struct caps *caps; LONG caps_count; - BOOL swresize;
struct strmbase_source *pin; int fd, mmap; @@ -196,9 +194,6 @@ static BOOL set_caps(Capture *device, const struct caps *caps) }
device->current_caps = caps; - device->outputwidth = width; - device->outputheight = height; - device->swresize = FALSE;
return TRUE; } @@ -304,63 +299,26 @@ HRESULT qcap_driver_set_prop(Capture *device, VideoProcAmpProperty property, return S_OK; }
-static void Resize(const Capture * capBox, LPBYTE output, const BYTE *input) +static void reverse_image(const Capture *device, LPBYTE output, const BYTE *input) { - UINT width, height, bitdepth, depth; + int inoffset, outoffset, pitch; + UINT width, height, depth;
- width = capBox->current_caps->video_info.bmiHeader.biWidth; - height = capBox->current_caps->video_info.bmiHeader.biHeight; - bitdepth = capBox->current_caps->video_info.bmiHeader.biBitCount; - depth = bitdepth / 8; + width = device->current_caps->video_info.bmiHeader.biWidth; + height = device->current_caps->video_info.bmiHeader.biHeight; + depth = device->current_caps->video_info.bmiHeader.biBitCount / 8; /* the whole image needs to be reversed, because the dibs are messed up in windows */ - if (!capBox->swresize) - { - int inoffset = 0, outoffset = width * height * depth; - int ow = width * depth; - while (outoffset > 0) - { - int x; - outoffset -= ow; - for (x = 0; x < ow; x++) - output[outoffset + x] = input[inoffset + x]; - inoffset += ow; - } - } - else + outoffset = width * height * depth; + pitch = width * depth; + inoffset = 0; + while (outoffset > 0) { - HDC dc_s, dc_d; - HBITMAP bmp_s, bmp_d; - int inoffset = 0, outoffset = (capBox->outputheight) * capBox->outputwidth * depth; - int ow = capBox->outputwidth * depth; - LPBYTE myarray; - - /* FIXME: Improve software resizing: add error checks and optimize */ - - myarray = CoTaskMemAlloc(capBox->outputwidth * capBox->outputheight * depth); - dc_s = CreateCompatibleDC(NULL); - dc_d = CreateCompatibleDC(NULL); - bmp_s = CreateBitmap(width, height, 1, bitdepth, input); - bmp_d = CreateBitmap(capBox->outputwidth, capBox->outputheight, 1, bitdepth, NULL); - SelectObject(dc_s, bmp_s); - SelectObject(dc_d, bmp_d); - StretchBlt(dc_d, 0, 0, capBox->outputwidth, capBox->outputheight, - dc_s, 0, 0, width, height, SRCCOPY); - GetBitmapBits(bmp_d, capBox->outputwidth * capBox->outputheight * depth, myarray); - while (outoffset > 0) - { - int i; - - outoffset -= ow; - for (i = 0; i < ow; i++) - output[outoffset + i] = myarray[inoffset + i]; - inoffset += ow; - } - CoTaskMemFree(myarray); - DeleteObject(dc_s); - DeleteObject(dc_d); - DeleteObject(bmp_s); - DeleteObject(bmp_d); + int x; + outoffset -= pitch; + for (x = 0; x < pitch; x++) + output[outoffset + x] = input[inoffset + x]; + inoffset += pitch; } }
@@ -394,10 +352,7 @@ static DWORD WINAPI ReadThread(LPVOID lParam) { int len;
- if (!capBox->swresize) - len = width * height * depth; - else - len = capBox->outputheight * capBox->outputwidth * depth; + len = width * height * depth; IMediaSample_SetActualDataLength(pSample, len);
len = IMediaSample_GetActualDataLength(pSample); @@ -414,7 +369,7 @@ static DWORD WINAPI ReadThread(LPVOID lParam) } }
- Resize(capBox, pTarget, image_data); + reverse_image(capBox, pTarget, image_data); hr = IMemInputPin_Receive(capBox->pin->pMemInputPin, pSample); TRACE("%p -> Frame %u: %x\n", capBox, ++framecount, hr); IMediaSample_Release(pSample); @@ -436,10 +391,7 @@ void qcap_driver_init_stream(Capture *device) HRESULT hr;
req_props.cBuffers = 3; - if (!device->swresize) - req_props.cbBuffer = device->current_caps->video_info.bmiHeader.biWidth * device->current_caps->video_info.bmiHeader.biHeight; - else - req_props.cbBuffer = device->outputwidth * device->outputheight; + req_props.cbBuffer = device->current_caps->video_info.bmiHeader.biWidth * device->current_caps->video_info.bmiHeader.biHeight; req_props.cbBuffer = (req_props.cbBuffer * device->current_caps->video_info.bmiHeader.biBitCount) / 8; req_props.cbAlign = 1; req_props.cbPrefix = 0;
From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/capture.h | 1 + dlls/qcap/tests/videocapture.c | 18 ++++++++++++++++++ dlls/qcap/v4l.c | 11 +++++++++++ dlls/qcap/vfwcapture.c | 20 +++++++++++++------- 4 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/dlls/qcap/capture.h b/dlls/qcap/capture.h index fa48324dd6..e34c33fb0f 100644 --- a/dlls/qcap/capture.h +++ b/dlls/qcap/capture.h @@ -27,6 +27,7 @@ Capture *qcap_driver_init(struct strmbase_source *,USHORT) DECLSPEC_HIDDEN; HRESULT qcap_driver_destroy(Capture*) DECLSPEC_HIDDEN; HRESULT qcap_driver_check_format(Capture*,const AM_MEDIA_TYPE*) DECLSPEC_HIDDEN; HRESULT qcap_driver_set_format(Capture*,AM_MEDIA_TYPE*) DECLSPEC_HIDDEN; +LONG qcap_driver_get_caps_count(Capture *device) DECLSPEC_HIDDEN; 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; diff --git a/dlls/qcap/tests/videocapture.c b/dlls/qcap/tests/videocapture.c index 39535adece..ab9e19b461 100644 --- a/dlls/qcap/tests/videocapture.c +++ b/dlls/qcap/tests/videocapture.c @@ -66,6 +66,7 @@ static void test_stream_config(IPin *pin) AM_MEDIA_TYPE *format, *format2; IAMStreamConfig *stream_config; LONG depth, compression; + LONG count, size; HRESULT hr;
hr = IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **)&stream_config); @@ -116,6 +117,23 @@ static void test_stream_config(IPin *pin) ok(hr == E_FAIL, "Got hr %#x.\n", hr); FreeMediaType(format);
+ count = 0xdeadbeef; + size = 0xdeadbeef; + /* Crash on Windows */ + if (0) + { + hr = IAMStreamConfig_GetNumberOfCapabilities(stream_config, &count, NULL); + ok(hr == E_POINTER, "Got hr %#x.\n", hr); + + hr = IAMStreamConfig_GetNumberOfCapabilities(stream_config, NULL, &size); + ok(hr == E_POINTER, "Got hr %#x.\n", hr); + } + + hr = IAMStreamConfig_GetNumberOfCapabilities(stream_config, &count, &size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(count != 0xdeadbeef, "Got wrong count: %d.\n", count); + ok(size == sizeof(VIDEO_STREAM_CONFIG_CAPS), "Got wrong size: %d.\n", size); + IAMStreamConfig_Release(stream_config); }
diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index 27970ff228..979ace6d66 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -624,6 +624,11 @@ error: return NULL; }
+LONG qcap_driver_get_caps_count(Capture *device) +{ + return device->caps_count; +} + #else
Capture *qcap_driver_init(struct strmbase_source *pin, USHORT card) @@ -698,4 +703,10 @@ void qcap_driver_cleanup_stream(Capture *device) ERR("v4l absent: shouldn't be called\n"); }
+LONG qcap_driver_get_caps_count(Capture *device) +{ + ERR("v4l absent: shouldn't be called\n"); + return 0; +} + #endif /* defined(VIDIOCMCAPTURE) */ diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c index 6c9cc3ce51..8fb0c0d7bd 100644 --- a/dlls/qcap/vfwcapture.c +++ b/dlls/qcap/vfwcapture.c @@ -167,7 +167,6 @@ static const struct strmbase_filter_ops filter_ops = .filter_cleanup_stream = vfw_capture_cleanup_stream, };
-/* AMStreamConfig interface, we only need to implement {G,S}etFormat */ static HRESULT WINAPI AMStreamConfig_QueryInterface(IAMStreamConfig *iface, REFIID iid, void **out) { VfwCapture *filter = impl_from_IAMStreamConfig(iface); @@ -242,13 +241,20 @@ AMStreamConfig_GetFormat( IAMStreamConfig *iface, AM_MEDIA_TYPE **pmt ) return hr; }
-static HRESULT WINAPI -AMStreamConfig_GetNumberOfCapabilities( IAMStreamConfig *iface, int *piCount, - int *piSize ) +static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface, + int *count, int *size) { - FIXME("%p: %p %p - stub, intentional\n", iface, piCount, piSize); - *piCount = 0; - return E_NOTIMPL; /* Not implemented for this interface */ + VfwCapture *filter = impl_from_IAMStreamConfig(iface); + + TRACE("filter %p, count %p, size %p.\n", filter, count, size); + + if (!count || !size) + return E_POINTER; + + *count = qcap_driver_get_caps_count(filter->driver_info); + *size = sizeof(VIDEO_STREAM_CONFIG_CAPS); + + return S_OK; }
static HRESULT WINAPI
From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com Signed-off-by: Zebediah Figura z.figura12@gmail.com --- v4: Also fix the function in the non-v4l case.
dlls/qcap/capture.h | 2 ++ dlls/qcap/tests/videocapture.c | 22 ++++++++++++++++++++++ dlls/qcap/v4l.c | 21 +++++++++++++++++++++ dlls/qcap/vfwcapture.c | 12 +++++++----- 4 files changed, 52 insertions(+), 5 deletions(-)
diff --git a/dlls/qcap/capture.h b/dlls/qcap/capture.h index e34c33fb0f..615988bda3 100644 --- a/dlls/qcap/capture.h +++ b/dlls/qcap/capture.h @@ -27,6 +27,8 @@ Capture *qcap_driver_init(struct strmbase_source *,USHORT) DECLSPEC_HIDDEN; HRESULT qcap_driver_destroy(Capture*) DECLSPEC_HIDDEN; HRESULT qcap_driver_check_format(Capture*,const AM_MEDIA_TYPE*) DECLSPEC_HIDDEN; HRESULT qcap_driver_set_format(Capture*,AM_MEDIA_TYPE*) DECLSPEC_HIDDEN; +HRESULT qcap_driver_get_caps(Capture *device, LONG index, AM_MEDIA_TYPE **pmt, + VIDEO_STREAM_CONFIG_CAPS *vscc) DECLSPEC_HIDDEN; LONG qcap_driver_get_caps_count(Capture *device) DECLSPEC_HIDDEN; 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; diff --git a/dlls/qcap/tests/videocapture.c b/dlls/qcap/tests/videocapture.c index ab9e19b461..448136791b 100644 --- a/dlls/qcap/tests/videocapture.c +++ b/dlls/qcap/tests/videocapture.c @@ -64,6 +64,7 @@ static void test_stream_config(IPin *pin) { VIDEOINFOHEADER *video_info, *video_info2; AM_MEDIA_TYPE *format, *format2; + VIDEO_STREAM_CONFIG_CAPS vscc; IAMStreamConfig *stream_config; LONG depth, compression; LONG count, size; @@ -127,6 +128,12 @@ static void test_stream_config(IPin *pin)
hr = IAMStreamConfig_GetNumberOfCapabilities(stream_config, NULL, &size); ok(hr == E_POINTER, "Got hr %#x.\n", hr); + + hr = IAMStreamConfig_GetStreamCaps(stream_config, 0, NULL, (BYTE *)&vscc); + ok(hr == E_POINTER, "Got hr %#x.\n", hr); + + hr = IAMStreamConfig_GetStreamCaps(stream_config, 0, &format, NULL); + ok(hr == E_POINTER, "Got hr %#x.\n", hr); }
hr = IAMStreamConfig_GetNumberOfCapabilities(stream_config, &count, &size); @@ -134,6 +141,21 @@ static void test_stream_config(IPin *pin) ok(count != 0xdeadbeef, "Got wrong count: %d.\n", count); ok(size == sizeof(VIDEO_STREAM_CONFIG_CAPS), "Got wrong size: %d.\n", size);
+ hr = IAMStreamConfig_GetStreamCaps(stream_config, 100000, NULL, NULL); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + + hr = IAMStreamConfig_GetStreamCaps(stream_config, 100000, &format, (BYTE *)&vscc); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + + hr = IAMStreamConfig_GetStreamCaps(stream_config, 0, &format, (BYTE *)&vscc); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(IsEqualGUID(&format->majortype, &MEDIATYPE_Video), "Got wrong majortype: %s.\n", + debugstr_guid(&MEDIATYPE_Video)); + ok(IsEqualGUID(&vscc.guid, &FORMAT_VideoInfo) + || IsEqualGUID(&vscc.guid, &FORMAT_VideoInfo2), "Got wrong guid: %s.\n", + debugstr_guid(&vscc.guid)); + FreeMediaType(format); + IAMStreamConfig_Release(stream_config); }
diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index 979ace6d66..c5352cb018 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -624,6 +624,21 @@ error: return NULL; }
+HRESULT qcap_driver_get_caps(Capture *device, LONG index, AM_MEDIA_TYPE **type, + VIDEO_STREAM_CONFIG_CAPS *vscc) +{ + if (index >= device->caps_count) + return S_FALSE; + + *type = CreateMediaType(&device->caps[index].media_type); + if (!*type) + return E_OUTOFMEMORY; + + if (vscc) + memcpy(vscc, &device->caps[index].config, sizeof(VIDEO_STREAM_CONFIG_CAPS)); + return S_OK; +} + LONG qcap_driver_get_caps_count(Capture *device) { return device->caps_count; @@ -703,6 +718,12 @@ void qcap_driver_cleanup_stream(Capture *device) ERR("v4l absent: shouldn't be called\n"); }
+HRESULT qcap_driver_get_caps(Capture *device, LONG index, AM_MEDIA_TYPE **type, + VIDEO_STREAM_CONFIG_CAPS *vscc) +{ + FAIL_WITH_ERR; +} + LONG qcap_driver_get_caps_count(Capture *device) { ERR("v4l absent: shouldn't be called\n"); diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c index 8fb0c0d7bd..71ca4502b9 100644 --- a/dlls/qcap/vfwcapture.c +++ b/dlls/qcap/vfwcapture.c @@ -257,12 +257,14 @@ static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *if return S_OK; }
-static HRESULT WINAPI -AMStreamConfig_GetStreamCaps( IAMStreamConfig *iface, int iIndex, - AM_MEDIA_TYPE **pmt, BYTE *pSCC ) +static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface, + int index, AM_MEDIA_TYPE **pmt, BYTE *vscc) { - FIXME("%p: %d %p %p - stub, intentional\n", iface, iIndex, pmt, pSCC); - return E_NOTIMPL; /* Not implemented for this interface */ + VfwCapture *filter = impl_from_IAMStreamConfig(iface); + + TRACE("filter %p, index %d, pmt %p, vscc %p.\n", filter, index, pmt, vscc); + + return qcap_driver_get_caps(filter->driver_info, index, pmt, (VIDEO_STREAM_CONFIG_CAPS *)vscc); }
static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/vfwcapture.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c index 71ca4502b9..7b759f0173 100644 --- a/dlls/qcap/vfwcapture.c +++ b/dlls/qcap/vfwcapture.c @@ -515,16 +515,16 @@ static HRESULT source_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE }
static HRESULT source_get_media_type(struct strmbase_pin *pin, - unsigned int iPosition, AM_MEDIA_TYPE *pmt) + unsigned int index, AM_MEDIA_TYPE *pmt) { VfwCapture *filter = impl_from_strmbase_pin(pin); AM_MEDIA_TYPE *vfw_pmt; HRESULT hr;
- if (iPosition > 0) + if (index >= qcap_driver_get_caps_count(filter->driver_info)) return VFW_S_NO_MORE_ITEMS;
- hr = qcap_driver_get_format(filter->driver_info, &vfw_pmt); + hr = qcap_driver_get_caps(filter->driver_info, index, &vfw_pmt, NULL); if (SUCCEEDED(hr)) { CopyMediaType(pmt, vfw_pmt); DeleteMediaType(vfw_pmt);