2 * DirectShow capture services (QCAP.DLL)
4 * Copyright 2005 Maarten Lankhorst
6 * This file contains the part of the vfw capture interface that
7 * does the actual Video4Linux(1/2) stuff required for capturing
8 * and setting/getting media format..
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
33 #ifdef HAVE_SYS_IOCTL_H
34 #include <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>
64 #include "wine/debug.h"
65 #include "wine/library.h"
68 #include "qcap_main.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(qcap_v4l
);
74 static typeof(open
) *video_open
= open
;
75 static typeof(close
) *video_close
= close
;
76 static typeof(ioctl
) *video_ioctl
= ioctl
;
77 static typeof(read
) *video_read
= read
;
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
;
88 video_lib
= wine_dlopen(SONAME_LIBV4L1
, RTLD_NOW
, NULL
, 0);
91 video_open
= wine_dlsym(video_lib
, "v4l1_open", NULL
, 0);
92 video_close
= wine_dlsym(video_lib
, "v4l1_close", NULL
, 0);
93 video_ioctl
= wine_dlsym(video_lib
, "v4l1_ioctl", NULL
, 0);
94 video_read
= wine_dlsym(video_lib
, "v4l1_read", NULL
, 0);
95 video_mmap
= wine_dlsym(video_lib
, "v4l1_mmap", NULL
, 0);
96 video_munmap
= wine_dlsym(video_lib
, "v4l1_munmap", NULL
, 0);
100 typedef void (* Renderer
)(const Capture
*, LPBYTE bufferin
, const BYTE
*stream
);
104 UINT width
, height
, bitDepth
, fps
, outputwidth
, outputheight
;
107 CRITICAL_SECTION CritSect
;
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
;
138 static void renderer_RGB(const Capture
*capBox
, LPBYTE bufferin
, const BYTE
*stream
);
139 static void renderer_YUV(const Capture
*capBox
, LPBYTE bufferin
, const BYTE
*stream
);
141 static const struct renderlist renderlist_V4l
[] = {
142 { 0, "NULL renderer", NULL
},
143 { 8, "Gray scales", NULL
}, /* 1, Don't support */
144 { 0, "High 240 cube (BT848)", NULL
}, /* 2, Don't support */
145 { 16, "16 bit RGB (565)", NULL
}, /* 3, Don't support */
146 { 24, "24 bit RGB values", renderer_RGB
}, /* 4, Supported, */
147 { 32, "32 bit RGB values", renderer_RGB
}, /* 5, Supported */
148 { 16, "15 bit RGB (555)", NULL
}, /* 6, Don't support */
149 { 16, "YUV 422 (Not P)", renderer_YUV
}, /* 7, Supported */
150 { 16, "YUYV (Not P)", renderer_YUV
}, /* 8, Supported */
151 { 16, "UYVY (Not P)", renderer_YUV
}, /* 9, Supported */
152 { 16, "YUV 420 (Not P)", NULL
}, /* 10, Not supported, if I had to guess it's YYUYYV */
153 { 12, "YUV 411 (Not P)", renderer_YUV
}, /* 11, Supported */
154 { 0, "Raw capturing (BT848)", NULL
}, /* 12, Don't support */
155 { 16, "YUV 422 (Planar)", renderer_YUV
}, /* 13, Supported */
156 { 12, "YUV 411 (Planar)", renderer_YUV
}, /* 14, Supported */
157 { 12, "YUV 420 (Planar)", renderer_YUV
}, /* 15, Supported */
158 { 10, "YUV 410 (Planar)", renderer_YUV
}, /* 16, Supported */
159 /* FIXME: add YUV420 support */
163 static const int fallback_V4l
[] = { 4, 5, 7, 8, 9, 13, 15, 14, 16, 11, -1 };
164 /* Fallback: First try raw formats (Should try yuv first perhaps?), then yuv */
166 /* static const Capture defbox; */
168 static int xioctl(int fd
, int request
, void * arg
)
173 r
= video_ioctl (fd
, request
, arg
);
174 } while (-1 == r
&& EINTR
== errno
);
179 /* Prepare the capture buffers */
180 static HRESULT
V4l_Prepare(Capture
*capBox
)
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 );
197 if (capBox
->pmap
!= MAP_FAILED
)
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
);
205 return E_OUTOFMEMORY
;
208 /* Setup mmap capture buffers. */
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;
224 capBox
->grab_data
= CoTaskMemAlloc(capBox
->imagesize
);
225 if (!capBox
->grab_data
)
226 return E_OUTOFMEMORY
;
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
);
239 CoTaskMemFree(capBox
->grab_buf
);
242 CoTaskMemFree(capBox
->grab_data
);
245 HRESULT
qcap_driver_destroy(Capture
*capBox
)
247 TRACE("%p\n", capBox
);
249 if( capBox
->fd
!= -1 )
250 video_close(capBox
->fd
);
251 capBox
->CritSect
.DebugInfo
->Spare
[0] = 0;
252 DeleteCriticalSection(&capBox
->CritSect
);
253 CoTaskMemFree(capBox
);
257 HRESULT
qcap_driver_set_format(Capture
*capBox
, AM_MEDIA_TYPE
* mT
)
259 int newheight
, newwidth
;
260 struct video_window window
;
261 VIDEOINFOHEADER
*format
;
263 TRACE("%p\n", capBox
);
265 format
= (VIDEOINFOHEADER
*) mT
->pbFormat
;
266 if (format
->bmiHeader
.biBitCount
!= 24 ||
267 format
->bmiHeader
.biCompression
!= BI_RGB
)
269 FIXME("unsupported media type %d %d\n", format
->bmiHeader
.biBitCount
,
270 format
->bmiHeader
.biCompression
);
271 return VFW_E_INVALIDMEDIATYPE
;
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
);
287 window
.width
= newwidth
;
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
;
306 HRESULT
qcap_driver_get_format(const Capture
*capBox
, AM_MEDIA_TYPE
** mT
)
310 mT
[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
312 return E_OUTOFMEMORY
;
313 vi
= CoTaskMemAlloc(sizeof(VIDEOINFOHEADER
));
314 mT
[0]->cbFormat
= sizeof(VIDEOINFOHEADER
);
317 CoTaskMemFree(mT
[0]);
319 return E_OUTOFMEMORY
;
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;
336 vi
->AvgTimePerFrame
= (LONGLONG
)10000000.0 / (LONGLONG
)capBox
->fps
;
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
;
348 dump_AM_MEDIA_TYPE(mT
[0]);
352 HRESULT
qcap_driver_get_prop_range( Capture
*capBox
,
353 VideoProcAmpProperty Property
, LONG
*pMin
, LONG
*pMax
,
354 LONG
*pSteppingDelta
, LONG
*pDefault
, LONG
*pCapsFlags
)
356 TRACE("%p -> %d %p %p %p %p %p\n", capBox
, Property
,
357 pMin
, pMax
, pSteppingDelta
, pDefault
, pCapsFlags
);
361 case VideoProcAmp_Brightness
:
362 *pDefault
= capBox
->dbrightness
;
364 case VideoProcAmp_Contrast
:
365 *pDefault
= capBox
->dcontrast
;
367 case VideoProcAmp_Hue
:
368 *pDefault
= capBox
->dhue
;
370 case VideoProcAmp_Saturation
:
371 *pDefault
= capBox
->dcolour
;
374 FIXME("Not implemented %d\n", Property
);
379 *pSteppingDelta
= 65536/256;
380 *pCapsFlags
= VideoProcAmp_Flags_Manual
;
384 HRESULT
qcap_driver_get_prop( Capture
*capBox
,
385 VideoProcAmpProperty Property
, LONG
*lValue
, LONG
*Flags
)
387 TRACE("%p -> %d %p %p\n", capBox
, Property
, lValue
, Flags
);
391 case VideoProcAmp_Brightness
:
392 *lValue
= capBox
->pict
.brightness
;
394 case VideoProcAmp_Contrast
:
395 *lValue
= capBox
->pict
.contrast
;
397 case VideoProcAmp_Hue
:
398 *lValue
= capBox
->pict
.hue
;
400 case VideoProcAmp_Saturation
:
401 *lValue
= capBox
->pict
.colour
;
404 FIXME("Not implemented %d\n", Property
);
407 *Flags
= VideoProcAmp_Flags_Manual
;
411 HRESULT
qcap_driver_set_prop(Capture
*capBox
, VideoProcAmpProperty Property
,
412 LONG lValue
, LONG Flags
)
414 TRACE("%p -> %d %d %d\n", capBox
, Property
, lValue
, Flags
);
418 case VideoProcAmp_Brightness
:
419 capBox
->pict
.brightness
= lValue
;
421 case VideoProcAmp_Contrast
:
422 capBox
->pict
.contrast
= lValue
;
424 case VideoProcAmp_Hue
:
425 capBox
->pict
.hue
= lValue
;
427 case VideoProcAmp_Saturation
:
428 capBox
->pict
.colour
= lValue
;
431 FIXME("Not implemented %d\n", Property
);
435 if (xioctl(capBox
->fd
, VIDIOCSPICT
, &capBox
->pict
) == -1)
437 ERR("ioctl(VIDIOCSPICT) failed (%d)\n",errno
);
443 static void renderer_RGB(const Capture
*capBox
, LPBYTE bufferin
, const BYTE
*stream
)
445 int depth
= renderlist_V4l
[capBox
->pict
.palette
].depth
;
446 int size
= capBox
->height
* capBox
->width
* depth
/ 8;
452 memcpy(bufferin
, stream
, size
);
457 while (pointer
+ offset
<= size
)
459 bufferin
[pointer
] = stream
[pointer
+ offset
];
461 bufferin
[pointer
] = stream
[pointer
+ offset
];
463 bufferin
[pointer
] = stream
[pointer
+ offset
];
469 ERR("Unknown bit depth %d\n", depth
);
474 static void renderer_YUV(const Capture
*capBox
, LPBYTE bufferin
, const BYTE
*stream
)
476 enum YUV_Format format
;
478 switch (capBox
->pict
.palette
)
480 case 7: /* YUV422 - same as YUYV */
487 case 11: /* YUV411 */
490 case 13: /* YUV422P */
493 case 14: /* YUV411P */
496 case 15: /* YUV420P */
499 case 16: /* YUV410P */
503 ERR("Unknown palette %d\n", capBox
->pict
.palette
);
506 YUV_To_RGB24(format
, bufferin
, stream
, capBox
->width
, capBox
->height
);
509 static void Resize(const Capture
* capBox
, LPBYTE output
, const BYTE
*input
)
511 /* the whole image needs to be reversed,
512 because the dibs are messed up in windows */
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
++)
523 output
[outoffset
+ x
] = input
[inoffset
+ x
];
530 HBITMAP bmp_s
, bmp_d
;
531 int depth
= capBox
->bitDepth
/ 8;
532 int inoffset
= 0, outoffset
= (capBox
->outputheight
) * capBox
->outputwidth
* depth
;
533 int ow
= capBox
->outputwidth
* depth
;
536 /* FIXME: Improve software resizing: add error checks and optimize */
538 myarray
= CoTaskMemAlloc(capBox
->outputwidth
* capBox
->outputheight
* depth
);
539 dc_s
= CreateCompatibleDC(NULL
);
540 dc_d
= CreateCompatibleDC(NULL
);
541 bmp_s
= CreateBitmap(capBox
->width
, capBox
->height
, 1, capBox
->bitDepth
, input
);
542 bmp_d
= CreateBitmap(capBox
->outputwidth
, capBox
->outputheight
, 1, capBox
->bitDepth
, NULL
);
543 SelectObject(dc_s
, bmp_s
);
544 SelectObject(dc_d
, bmp_d
);
545 StretchBlt(dc_d
, 0, 0, capBox
->outputwidth
, capBox
->outputheight
,
546 dc_s
, 0, 0, capBox
->width
, capBox
->height
, SRCCOPY
);
547 GetBitmapBits(bmp_d
, capBox
->outputwidth
* capBox
->outputheight
* depth
, myarray
);
548 while (outoffset
> 0)
553 for (i
= 0; i
< ow
; i
++)
554 output
[outoffset
+ i
] = myarray
[inoffset
+ i
];
557 CoTaskMemFree(myarray
);
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)
578 if (errno
!= EAGAIN
) break;
580 WARN("Error occurred while reading from device: %s\n", strerror(errno
));
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)
591 ERR("Freeing frame for capture failed: %s\n", strerror(errno
));
593 if (++capBox
->curframe
== capBox
->buffers
)
594 capBox
->curframe
= 0;
597 static DWORD WINAPI
ReadThread(LPVOID lParam
)
599 Capture
* capBox
= lParam
;
601 IMediaSample
*pSample
= NULL
;
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);
622 EnterCriticalSection(&capBox
->CritSect
);
625 hr
= BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin
*)capBox
->pOut
, &pSample
, NULL
, NULL
, 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
);
640 /* FIXME: Check return values.. */
641 V4l_GetFrame(capBox
, &pInput
);
642 capBox
->renderer(capBox
, pOutput
, pInput
);
643 Resize(capBox
, pTarget
, pOutput
);
644 hr
= BaseOutputPinImpl_Deliver((BaseOutputPin
*)capBox
->pOut
, pSample
);
645 TRACE("%p -> Frame %u: %x\n", capBox
, ++framecount
, hr
);
646 IMediaSample_Release(pSample
);
647 V4l_FreeFrame(capBox
);
649 if (FAILED(hr
) && hr
!= VFW_E_NOT_CONNECTED
)
651 TRACE("Return %x, stop IFilterGraph\n", hr
);
652 V4l_Unprepare(capBox
);
654 capBox
->stopped
= TRUE
;
657 LeaveCriticalSection(&capBox
->CritSect
);
660 LeaveCriticalSection(&capBox
->CritSect
);
661 CoTaskMemFree(pOutput
);
665 HRESULT
qcap_driver_run(Capture
*capBox
, FILTER_STATE
*state
)
670 TRACE("%p -> (%p)\n", capBox
, state
);
672 if (*state
== State_Running
) return S_OK
;
674 EnterCriticalSection(&capBox
->CritSect
);
676 capBox
->stopped
= FALSE
;
678 if (*state
== State_Stopped
)
680 *state
= State_Running
;
681 if (!capBox
->iscommitted
)
683 ALLOCATOR_PROPERTIES ap
, actual
;
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;
697 out
= (BaseOutputPin
*)capBox
->pOut
;
699 hr
= IMemAllocator_SetProperties(out
->pAllocator
, &ap
, &actual
);
702 hr
= IMemAllocator_Commit(out
->pAllocator
);
704 TRACE("Committing allocator: %x\n", hr
);
707 thread
= CreateThread(NULL
, 0, ReadThread
, capBox
, 0, NULL
);
710 capBox
->thread
= thread
;
711 SetThreadPriority(thread
, THREAD_PRIORITY_LOWEST
);
712 LeaveCriticalSection(&capBox
->CritSect
);
715 ERR("Creating thread failed.. %u\n", GetLastError());
716 LeaveCriticalSection(&capBox
->CritSect
);
720 ResumeThread(capBox
->thread
);
721 *state
= State_Running
;
722 LeaveCriticalSection(&capBox
->CritSect
);
726 HRESULT
qcap_driver_pause(Capture
*capBox
, FILTER_STATE
*state
)
728 TRACE("%p -> (%p)\n", capBox
, state
);
730 if (*state
== State_Paused
)
732 if (*state
== State_Stopped
)
733 qcap_driver_run(capBox
, state
);
735 EnterCriticalSection(&capBox
->CritSect
);
736 *state
= State_Paused
;
737 SuspendThread(capBox
->thread
);
738 LeaveCriticalSection(&capBox
->CritSect
);
743 HRESULT
qcap_driver_stop(Capture
*capBox
, FILTER_STATE
*state
)
745 TRACE("%p -> (%p)\n", capBox
, state
);
747 if (*state
== State_Stopped
)
750 EnterCriticalSection(&capBox
->CritSect
);
754 if (*state
== State_Paused
)
755 ResumeThread(capBox
->thread
);
756 capBox
->stopped
= TRUE
;
758 if (capBox
->iscommitted
)
763 capBox
->iscommitted
= FALSE
;
765 out
= (BaseOutputPin
*)capBox
->pOut
;
767 hr
= IMemAllocator_Decommit(out
->pAllocator
);
769 if (hr
!= S_OK
&& hr
!= VFW_E_NOT_COMMITTED
)
770 WARN("Decommitting allocator: %x\n", hr
);
772 V4l_Unprepare(capBox
);
775 *state
= State_Stopped
;
776 LeaveCriticalSection(&capBox
->CritSect
);
780 Capture
* qcap_driver_init( IPin
*pOut
, USHORT card
)
782 Capture
* capBox
= NULL
;
784 struct video_capability capa
;
785 struct video_picture pict
;
786 struct video_window window
;
791 capBox
= CoTaskMemAlloc(sizeof(Capture
));
795 /* capBox->vtbl = &defboxVtbl; */
797 InitializeCriticalSection( &capBox
->CritSect
);
798 capBox
->CritSect
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": Capture.CritSect");
800 sprintf(device
, "/dev/video%i", card
);
801 TRACE("opening %s\n", device
);
803 if ((capBox
->fd
= video_open(device
, O_RDWR
| O_NONBLOCK
| O_CLOEXEC
)) == -1 && errno
== EINVAL
)
805 capBox
->fd
= video_open(device
, O_RDWR
| O_NONBLOCK
);
806 if (capBox
->fd
== -1)
808 WARN("open failed (%d)\n", errno
);
811 fcntl( capBox
->fd
, F_SETFD
, FD_CLOEXEC
); /* in case O_CLOEXEC isn't supported */
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
));
886 memset(&window
, 0, sizeof(window
));
887 if (xioctl(capBox
->fd
, VIDIOCGWIN
, &window
) == -1)
889 WARN("VIDIOCGWIN failed (%d)\n", errno
);
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
);
909 qcap_driver_destroy( capBox
);
916 Capture
* qcap_driver_init( IPin
*pOut
, USHORT card
)
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"); \
929 HRESULT
qcap_driver_destroy(Capture
*capBox
)
934 HRESULT
qcap_driver_set_format(Capture
*capBox
, AM_MEDIA_TYPE
* mT
)
939 HRESULT
qcap_driver_get_format(const Capture
*capBox
, AM_MEDIA_TYPE
** mT
)
944 HRESULT
qcap_driver_get_prop_range( Capture
*capBox
,
945 VideoProcAmpProperty Property
, LONG
*pMin
, LONG
*pMax
,
946 LONG
*pSteppingDelta
, LONG
*pDefault
, LONG
*pCapsFlags
)
951 HRESULT
qcap_driver_get_prop(Capture
*capBox
,
952 VideoProcAmpProperty Property
, LONG
*lValue
, LONG
*Flags
)
957 HRESULT
qcap_driver_set_prop(Capture
*capBox
, VideoProcAmpProperty Property
,
958 LONG lValue
, LONG Flags
)
963 HRESULT
qcap_driver_run(Capture
*capBox
, FILTER_STATE
*state
)
968 HRESULT
qcap_driver_pause(Capture
*capBox
, FILTER_STATE
*state
)
973 HRESULT
qcap_driver_stop(Capture
*capBox
, FILTER_STATE
*state
)
978 #endif /* defined(VIDIOCMCAPTURE) */