26 #include "wine/port.h" 33 #ifdef HAVE_SYS_IOCTL_H 36 #ifdef HAVE_SYS_MMAN_H 40 #ifdef HAVE_SYS_TIME_H 43 #ifdef HAVE_ASM_TYPES_H 44 #include <asm/types.h> 49 #ifdef HAVE_LINUX_VIDEODEV_H 50 #include <linux/videodev.h> 78 static typeof(mmap) *video_mmap = mmap;
79 static typeof(munmap) *video_munmap = munmap;
81 static void video_init(
void)
84 static void *video_lib;
111 BOOL iscommitted, stopped;
112 struct video_picture pict;
113 int dbrightness, dhue, dcolour, dcontrast;
116 struct video_mmap *grab_buf;
117 struct video_mbuf gb_buffers;
141 static const struct renderlist renderlist_V4l[] = {
142 { 0,
"NULL renderer",
NULL },
143 { 8,
"Gray scales",
NULL },
144 { 0,
"High 240 cube (BT848)",
NULL },
145 { 16,
"16 bit RGB (565)",
NULL },
146 { 24,
"24 bit RGB values", renderer_RGB },
147 { 32,
"32 bit RGB values", renderer_RGB },
148 { 16,
"15 bit RGB (555)",
NULL },
149 { 16,
"YUV 422 (Not P)", renderer_YUV },
150 { 16,
"YUYV (Not P)", renderer_YUV },
151 { 16,
"UYVY (Not P)", renderer_YUV },
152 { 16,
"YUV 420 (Not P)",
NULL },
153 { 12,
"YUV 411 (Not P)", renderer_YUV },
154 { 0,
"Raw capturing (BT848)",
NULL },
155 { 16,
"YUV 422 (Planar)", renderer_YUV },
156 { 12,
"YUV 411 (Planar)", renderer_YUV },
157 { 12,
"YUV 420 (Planar)", renderer_YUV },
158 { 10,
"YUV 410 (Planar)", renderer_YUV },
163 static const int fallback_V4l[] = { 4, 5, 7, 8, 9, 13, 15, 14, 16, 11, -1 };
182 TRACE(
"%p: Preparing for %dx%d resolution\n", capBox, capBox->width, capBox->height);
186 if (xioctl(capBox->fd, VIDIOCGMBUF, &capBox->gb_buffers) != -1 &&
187 capBox->gb_buffers.frames)
189 capBox->buffers = capBox->gb_buffers.frames;
190 if (capBox->gb_buffers.frames > 1)
192 TRACE(
"%p: Using %d/%d buffers\n", capBox,
193 capBox->buffers, capBox->gb_buffers.frames);
195 capBox->pmap = video_mmap( 0, capBox->gb_buffers.size, PROT_READ|PROT_WRITE,
196 MAP_SHARED, capBox->fd, 0 );
201 capBox->grab_buf =
CoTaskMemAlloc(
sizeof(
struct video_mmap) * capBox->buffers);
202 if (!capBox->grab_buf)
204 video_munmap(capBox->pmap, capBox->gb_buffers.size);
209 for (
i = 0;
i < capBox->buffers;
i++)
211 capBox->grab_buf[
i].format = capBox->pict.palette;
212 capBox->grab_buf[
i].frame =
i;
213 capBox->grab_buf[
i].width = capBox->width;
214 capBox->grab_buf[
i].height = capBox->height;
222 capBox->imagesize = renderlist_V4l[capBox->pict.palette].depth *
223 capBox->height * capBox->width / 8;
225 if (!capBox->grab_data)
228 TRACE(
"Using mmap: %d\n", capBox->mmap);
232 static void V4l_Unprepare(
Capture *capBox)
236 for (capBox->curframe = 0; capBox->curframe < capBox->buffers; capBox->curframe++)
237 xioctl(capBox->fd, VIDIOCSYNC, &capBox->grab_buf[capBox->curframe]);
238 video_munmap(capBox->pmap, capBox->gb_buffers.size);
247 TRACE(
"%p\n", capBox);
249 if( capBox->fd != -1 )
250 video_close(capBox->fd);
251 capBox->CritSect.DebugInfo->Spare[0] = 0;
259 int newheight, newwidth;
260 struct video_window
window;
263 TRACE(
"%p\n", capBox);
266 if (
format->bmiHeader.biBitCount != 24 ||
269 FIXME(
"unsupported media type %d %d\n",
format->bmiHeader.biBitCount,
270 format->bmiHeader.biCompression );
274 newwidth =
format->bmiHeader.biWidth;
275 newheight =
format->bmiHeader.biHeight;
277 TRACE(
"%p -> (%p) - %d %d\n", capBox, mT, newwidth, newheight);
279 if (capBox->height == newheight && capBox->width == newwidth)
282 if(-1 == xioctl(capBox->fd, VIDIOCGWIN, &
window))
284 ERR(
"ioctl(VIDIOCGWIN) failed (%d)\n",
errno);
288 window.height = newheight;
289 if (xioctl(capBox->fd, VIDIOCSWIN, &
window) == -1)
291 TRACE(
"using software resize: %dx%d -> %dx%d\n",
292 window.width,
window.height, capBox->width, capBox->height);
293 capBox->swresize =
TRUE;
297 capBox->height =
window.height;
298 capBox->width =
window.width;
299 capBox->swresize =
FALSE;
301 capBox->outputwidth =
window.width;
302 capBox->outputheight =
window.height;
321 mT[0]->majortype = MEDIATYPE_Video;
322 mT[0]->subtype = MEDIASUBTYPE_RGB24;
323 mT[0]->formattype = FORMAT_VideoInfo;
324 mT[0]->bFixedSizeSamples =
TRUE;
325 mT[0]->bTemporalCompression =
FALSE;
327 mT[0]->lSampleSize = capBox->outputwidth * capBox->outputheight * capBox->bitDepth / 8;
328 TRACE(
"Output format: %dx%d - %d bits = %u KB\n", capBox->outputwidth,
329 capBox->outputheight, capBox->bitDepth, mT[0]->lSampleSize/1024);
330 vi->rcSource.left = 0;
vi->rcSource.top = 0;
331 vi->rcTarget.left = 0;
vi->rcTarget.top = 0;
332 vi->rcSource.right = capBox->width;
vi->rcSource.bottom = capBox->height;
333 vi->rcTarget.right = capBox->outputwidth;
vi->rcTarget.bottom = capBox->outputheight;
334 vi->dwBitRate = capBox->fps * mT[0]->lSampleSize;
335 vi->dwBitErrorRate = 0;
337 vi->bmiHeader.biSize = 40;
338 vi->bmiHeader.biWidth = capBox->outputwidth;
339 vi->bmiHeader.biHeight = capBox->outputheight;
340 vi->bmiHeader.biPlanes = 1;
341 vi->bmiHeader.biBitCount = 24;
342 vi->bmiHeader.biCompression =
BI_RGB;
343 vi->bmiHeader.biSizeImage = mT[0]->lSampleSize;
344 vi->bmiHeader.biClrUsed =
vi->bmiHeader.biClrImportant = 0;
345 vi->bmiHeader.biXPelsPerMeter = 100;
346 vi->bmiHeader.biYPelsPerMeter = 100;
347 mT[0]->pbFormat = (
void *)
vi;
354 LONG *pSteppingDelta,
LONG *pDefault,
LONG *pCapsFlags )
357 pMin, pMax, pSteppingDelta, pDefault, pCapsFlags);
361 case VideoProcAmp_Brightness:
362 *pDefault = capBox->dbrightness;
365 *pDefault = capBox->dcontrast;
368 *pDefault = capBox->dhue;
371 *pDefault = capBox->dcolour;
379 *pSteppingDelta = 65536/256;
391 case VideoProcAmp_Brightness:
392 *lValue = capBox->pict.brightness;
395 *lValue = capBox->pict.contrast;
398 *lValue = capBox->pict.hue;
401 *lValue = capBox->pict.colour;
418 case VideoProcAmp_Brightness:
419 capBox->pict.brightness = lValue;
422 capBox->pict.contrast = lValue;
425 capBox->pict.hue = lValue;
428 capBox->pict.colour = lValue;
435 if (xioctl(capBox->fd, VIDIOCSPICT, &capBox->pict) == -1)
437 ERR(
"ioctl(VIDIOCSPICT) failed (%d)\n",
errno);
445 int depth = renderlist_V4l[capBox->pict.palette].depth;
446 int size = capBox->height * capBox->width *
depth / 8;
469 ERR(
"Unknown bit depth %d\n",
depth);
478 switch (capBox->pict.palette)
503 ERR(
"Unknown palette %d\n", capBox->pict.palette);
513 if (!capBox->swresize)
515 int depth = capBox->bitDepth / 8;
516 int inoffset = 0, outoffset = capBox->height * capBox->width *
depth;
517 int ow = capBox->width *
depth;
518 while (outoffset > 0)
522 for (
x = 0;
x < ow;
x++)
531 int depth = capBox->bitDepth / 8;
532 int inoffset = 0, outoffset = (capBox->outputheight) * capBox->outputwidth *
depth;
533 int ow = capBox->outputwidth *
depth;
542 bmp_d =
CreateBitmap(capBox->outputwidth, capBox->outputheight, 1, capBox->bitDepth,
NULL);
545 StretchBlt(dc_d, 0, 0, capBox->outputwidth, capBox->outputheight,
546 dc_s, 0, 0, capBox->width, capBox->height,
SRCCOPY);
548 while (outoffset > 0)
553 for (
i = 0;
i < ow;
i++)
554 output[outoffset +
i] = myarray[inoffset +
i];
565 static void V4l_GetFrame(
Capture * capBox,
unsigned char ** pInput)
569 if (xioctl(capBox->fd, VIDIOCSYNC, &capBox->grab_buf[capBox->curframe]) == -1)
570 WARN(
"Syncing ioctl failed: %d\n",
errno);
572 *pInput = capBox->pmap + capBox->gb_buffers.offsets[capBox->curframe];
577 while ((retval = video_read(capBox->fd, capBox->grab_data, capBox->imagesize)) == -1)
581 *pInput = (
unsigned char*) capBox->grab_data;
585 static void V4l_FreeFrame(
Capture * capBox)
590 if (xioctl(capBox->fd, VIDIOCMCAPTURE, &capBox->grab_buf[capBox->curframe]) == -1)
593 if (++capBox->curframe == capBox->buffers)
594 capBox->curframe = 0;
602 ULONG framecount = 0;
603 unsigned char *
pTarget, *pInput, *pOutput;
605 hr = V4l_Prepare(capBox);
608 ERR(
"Stop IFilterGraph: %x\n",
hr);
610 capBox->stopped =
TRUE;
614 pOutput =
CoTaskMemAlloc(capBox->width * capBox->height * capBox->bitDepth / 8);
615 capBox->curframe = 0;
617 V4l_FreeFrame(capBox);
618 }
while (capBox->curframe != 0);
630 if (!capBox->swresize)
631 len = capBox->height * capBox->width * capBox->bitDepth / 8;
633 len = capBox->outputheight * capBox->outputwidth * capBox->bitDepth / 8;
634 IMediaSample_SetActualDataLength(pSample,
len);
636 len = IMediaSample_GetActualDataLength(pSample);
637 TRACE(
"Data length: %d KB\n",
len / 1024);
639 IMediaSample_GetPointer(pSample, &
pTarget);
641 V4l_GetFrame(capBox, &pInput);
642 capBox->renderer(capBox, pOutput, pInput);
643 Resize(capBox,
pTarget, pOutput);
645 TRACE(
"%p -> Frame %u: %x\n", capBox, ++framecount,
hr);
646 IMediaSample_Release(pSample);
647 V4l_FreeFrame(capBox);
651 TRACE(
"Return %x, stop IFilterGraph\n",
hr);
652 V4l_Unprepare(capBox);
654 capBox->stopped =
TRUE;
672 if (*
state == State_Running)
return S_OK;
676 capBox->stopped =
FALSE;
678 if (*
state == State_Stopped)
680 *
state = State_Running;
681 if (!capBox->iscommitted)
686 capBox->iscommitted =
TRUE;
689 if (!capBox->swresize)
690 ap.cbBuffer = capBox->width * capBox->height;
692 ap.cbBuffer = capBox->outputwidth * capBox->outputheight;
693 ap.cbBuffer = (
ap.cbBuffer * capBox->bitDepth) / 8;
699 hr = IMemAllocator_SetProperties(
out->pAllocator, &
ap, &actual);
702 hr = IMemAllocator_Commit(
out->pAllocator);
704 TRACE(
"Committing allocator: %x\n",
hr);
721 *
state = State_Running;
730 if (*
state == State_Paused)
732 if (*
state == State_Stopped)
736 *
state = State_Paused;
747 if (*
state == State_Stopped)
754 if (*
state == State_Paused)
756 capBox->stopped =
TRUE;
758 if (capBox->iscommitted)
763 capBox->iscommitted =
FALSE;
767 hr = IMemAllocator_Decommit(
out->pAllocator);
770 WARN(
"Decommitting allocator: %x\n",
hr);
772 V4l_Unprepare(capBox);
775 *
state = State_Stopped;
784 struct video_capability capa;
785 struct video_picture pict;
786 struct video_window
window;
798 capBox->CritSect.DebugInfo->Spare[0] = (
DWORD_PTR)(__FILE__
": Capture.CritSect");
806 if (capBox->fd == -1)
813 memset(&capa, 0,
sizeof(capa));
815 if (xioctl(capBox->fd, VIDIOCGCAP, &capa) == -1)
817 WARN(
"ioctl(VIDIOCGCAP) failed (%d)\n",
errno);
821 if (!(capa.type & VID_TYPE_CAPTURE))
823 WARN(
"not a video capture device\n");
827 TRACE(
"%d inputs on %s\n", capa.channels, capa.name );
829 if (xioctl(capBox->fd, VIDIOCGPICT, &pict) == -1)
831 ERR(
"ioctl(VIDIOCGPICT) failed (%d)\n",
errno );
835 TRACE(
"depth %d palette %d (%s) hue %d color %d contrast %d\n",
836 pict.depth, pict.palette, renderlist_V4l[pict.palette].name,
837 pict.hue, pict.colour, pict.contrast );
839 capBox->dbrightness = pict.brightness;
840 capBox->dcolour = pict.colour;
841 capBox->dhue = pict.hue;
842 capBox->dcontrast = pict.contrast;
844 if (!renderlist_V4l[pict.palette].renderer)
846 int palet = pict.palette,
i;
848 TRACE(
"No renderer available for %s, falling back to defaults\n",
849 renderlist_V4l[pict.palette].name);
850 capBox->renderer =
NULL;
851 for (
i = 0; fallback_V4l[
i] >=0 ;
i++)
853 int n = fallback_V4l[
i];
855 if (renderlist_V4l[
n].renderer ==
NULL)
858 pict.depth = renderlist_V4l[
n].depth;
860 if (xioctl(capBox->fd, VIDIOCSPICT, &pict) == -1)
862 TRACE(
"Could not render with %s (%d)\n",
863 renderlist_V4l[
n].
name,
n);
866 TRACE(
"using renderer %s (%d)\n",
867 renderlist_V4l[
n].
name,
n);
868 capBox->renderer = renderlist_V4l[
n].renderer;
872 if (!capBox->renderer)
874 ERR(
"video format %s isn't available\n",
875 renderlist_V4l[palet].
name);
881 TRACE(
"Using the suggested format\n");
882 capBox->renderer = renderlist_V4l[pict.palette].renderer;
884 memcpy(&capBox->pict, &pict,
sizeof(
struct video_picture));
887 if (xioctl(capBox->fd, VIDIOCGWIN, &
window) == -1)
893 capBox->height = capBox->outputheight =
window.height;
894 capBox->width = capBox->outputwidth =
window.width;
895 capBox->swresize =
FALSE;
896 capBox->bitDepth = 24;
899 capBox->stopped =
FALSE;
900 capBox->curframe = 0;
901 capBox->iscommitted =
FALSE;
903 TRACE(
"format: %d bits - %d x %d\n", capBox->bitDepth, capBox->width, capBox->height);
919 "The v4l headers were not available at compile time,\n" 920 "so video capture support is not available.\n";
925 #define FAIL_WITH_ERR \ 926 ERR("v4l absent: shouldn't be called\n"); \ 946 LONG *pSteppingDelta,
LONG *pDefault,
LONG *pCapsFlags )
HRESULT WINAPI BaseOutputPinImpl_GetDeliveryBuffer(BaseOutputPin *This, IMediaSample **ppSample, REFERENCE_TIME *tStart, REFERENCE_TIME *tStop, DWORD dwFlags)
enum VideoProcAmp_Contrast
HRESULT qcap_driver_stop(Capture *capBox, FILTER_STATE *state)
HRESULT qcap_driver_get_prop_range(Capture *capBox, VideoProcAmpProperty Property, LONG *pMin, LONG *pMax, LONG *pSteppingDelta, LONG *pDefault, LONG *pCapsFlags)
#define THREAD_PRIORITY_LOWEST
GLint GLint GLsizei width
static UCHAR ULONG UCHAR ULONG UCHAR * output
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
VOID WINAPI CoTaskMemFree(LPVOID ptr)
HRESULT qcap_driver_get_prop(Capture *capBox, VideoProcAmpProperty Property, LONG *lValue, LONG *Flags)
static CRITICAL_SECTION CritSect
GLsizei const GLvoid * pointer
GLdouble GLdouble GLdouble r
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
DWORD WINAPI GetLastError(VOID)
BOOL WINAPI DeleteObject(_In_ HGDIOBJ)
GLint GLint GLint GLint GLint x
WINE_DEFAULT_DEBUG_CHANNEL(qcap_v4l)
struct msdos_volume_info vi
void * wine_dlsym(void *handle, const char *symbol, char *error, size_t errorsize)
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
Capture * qcap_driver_init(IPin *pOut, USHORT card)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
const char * strerror(int err)
BOOL WINAPI StretchBlt(_In_ HDC, _In_ int, _In_ int, _In_ int, _In_ int, _In_opt_ HDC, _In_ int, _In_ int, _In_ int, _In_ int, _In_ DWORD)
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
#define sprintf(buf, format,...)
HRESULT qcap_driver_set_prop(Capture *capBox, VideoProcAmpProperty Property, LONG lValue, LONG Flags)
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
void * wine_dlopen(const char *filename, int flag, char *error, size_t errorsize)
HRESULT qcap_driver_run(Capture *capBox, FILTER_STATE *state)
#define VFW_E_NOT_CONNECTED
BOOL WINAPI SetThreadPriority(IN HANDLE hThread, IN int nPriority)
_Must_inspect_result_ _In_ ULONG Flags
HRESULT qcap_driver_pause(Capture *capBox, FILTER_STATE *state)
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
LONG WINAPI GetBitmapBits(_In_ HBITMAP hbit, _In_ LONG cb, _Out_writes_bytes_(cb) LPVOID lpvBits)
HRESULT qcap_driver_destroy(Capture *capBox)
void YUV_Init(void) DECLSPEC_HIDDEN
HRESULT qcap_driver_get_format(const Capture *capBox, AM_MEDIA_TYPE **mT)
GLint GLint GLsizei GLsizei GLsizei depth
#define VFW_E_INVALIDMEDIATYPE
DWORD WINAPI SuspendThread(IN HANDLE hThread)
#define memcpy(s1, s2, n)
static IHTMLWindow2 * window
GLint GLint GLsizei GLsizei height
GLenum GLenum GLenum input
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
enum VideoProcAmp_Saturation
#define VFW_E_NOT_COMMITTED
HRESULT WINAPI BaseOutputPinImpl_Deliver(BaseOutputPin *This, IMediaSample *pSample)
void int int ULONGLONG int va_list * ap
HRESULT qcap_driver_set_format(Capture *capBox, AM_MEDIA_TYPE *mT)
DWORD WINAPI ResumeThread(IN HANDLE hThread)
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void YUV_To_RGB24(enum YUV_Format format, unsigned char *target, const unsigned char *source, int width, int height) DECLSPEC_HIDDEN
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
struct tagVIDEOINFOHEADER VIDEOINFOHEADER
HBITMAP WINAPI CreateBitmap(_In_ INT cx, _In_ INT cy, _In_ UINT cPlanes, _In_ UINT cBitsPerPel, _In_opt_ const VOID *pvBits)
GLuint const GLchar * name