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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "wine/port.h"
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
41 #include "wine/debug.h"
44 #include "qcap_main.h"
50 #ifdef HAVE_SYS_IOCTL_H
51 #include <sys/ioctl.h>
53 #ifdef HAVE_SYS_MMAN_H
56 #ifdef HAVE_SYS_ERRNO_H
57 #include <sys/errno.h>
59 #ifdef HAVE_SYS_TIME_H
62 #ifdef HAVE_ASM_TYPES_H
63 #include <asm/types.h>
65 #ifdef HAVE_LINUX_VIDEODEV_H
66 #include <linux/videodev.h>
72 WINE_DEFAULT_DEBUG_CHANNEL(qcap_v4l
);
74 #ifdef HAVE_LINUX_VIDEODEV_H
76 typedef void (* Renderer
)(Capture
*, LPBYTE bufferin
, LPBYTE stream
);
80 UINT width
, height
, bitDepth
, fps
, outputwidth
, outputheight
;
83 CRITICAL_SECTION CritSect
;
87 int iscommitted
, stopped
;
88 struct video_picture pict
;
89 int dbrightness
, dhue
, dcolour
, dcontrast
;
92 struct video_mmap
*grab_buf
;
93 struct video_mbuf gb_buffers
;
114 static void renderer_RGB(Capture
*capBox
, LPBYTE bufferin
, LPBYTE stream
);
115 static void renderer_YUV(Capture
*capBox
, LPBYTE bufferin
, LPBYTE stream
);
117 static const struct renderlist renderlist_V4l
[] = {
118 { 0, "NULL renderer", NULL
},
119 { 8, "Gray scales", NULL
}, /* 1, Don't support */
120 { 0, "High 240 cube (BT848)", NULL
}, /* 2, Don't support */
121 { 16, "16 bit RGB (565)", NULL
}, /* 3, Don't support */
122 { 24, "24 bit RGB values", renderer_RGB
}, /* 4, Supported, */
123 { 32, "32 bit RGB values", renderer_RGB
}, /* 5, Supported */
124 { 16, "15 bit RGB (555)", NULL
}, /* 6, Don't support */
125 { 16, "YUV 422 (Not P)", renderer_YUV
}, /* 7, Supported */
126 { 16, "YUYV (Not P)", renderer_YUV
}, /* 8, Supported */
127 { 16, "UYVY (Not P)", renderer_YUV
}, /* 9, Supported */
128 { 16, "YUV 420 (Not P)", NULL
}, /* 10, Not supported, if I had to guess it's YYUYYV */
129 { 12, "YUV 411 (Not P)", renderer_YUV
}, /* 11, Supported */
130 { 0, "Raw capturing (BT848)", NULL
}, /* 12, Don't support */
131 { 16, "YUV 422 (Planar)", renderer_YUV
}, /* 13, Supported */
132 { 12, "YUV 411 (Planar)", renderer_YUV
}, /* 14, Supported */
133 { 12, "YUV 420 (Planar)", renderer_YUV
}, /* 15, Supported */
134 { 10, "YUV 410 (Planar)", renderer_YUV
}, /* 16, Supported */
135 /* FIXME: add YUV420 support */
139 const int fallback_V4l
[] = { 4, 5, 7, 8, 9, 13, 15, 14, 16, 11, -1 };
140 /* Fallback: First try raw formats (Should try yuv first perhaps?), then yuv */
142 /* static const Capture defbox; */
144 static int xioctl(int fd
, int request
, void * arg
)
149 r
= ioctl (fd
, request
, arg
);
150 } while (-1 == r
&& EINTR
== errno
);
155 /* Prepare the capture buffers */
156 static HRESULT
V4l_Prepare(Capture
*capBox
)
158 TRACE("%p: Preparing for %dx%d resolution\n", capBox
, capBox
->width
, capBox
->height
);
162 if (xioctl(capBox
->fd
, VIDIOCGMBUF
, &capBox
->gb_buffers
) != -1 &&
163 capBox
->gb_buffers
.frames
)
165 capBox
->buffers
= capBox
->gb_buffers
.frames
;
166 if (capBox
->gb_buffers
.frames
> 1)
168 TRACE("%p: Using %d/%d buffers\n", capBox
,
169 capBox
->buffers
, capBox
->gb_buffers
.frames
);
171 capBox
->pmap
= mmap( 0, capBox
->gb_buffers
.size
, PROT_READ
|PROT_WRITE
,
172 MAP_SHARED
, capBox
->fd
, 0 );
173 if (capBox
->pmap
!= MAP_FAILED
)
177 capBox
->grab_buf
= CoTaskMemAlloc(sizeof(struct video_mmap
) * capBox
->buffers
);
178 if (!capBox
->grab_buf
)
180 munmap(capBox
->pmap
, capBox
->gb_buffers
.size
);
181 return E_OUTOFMEMORY
;
184 /* Setup mmap capture buffers. */
185 for (i
= 0; i
< capBox
->buffers
; i
++)
187 capBox
->grab_buf
[i
].format
= capBox
->pict
.palette
;
188 capBox
->grab_buf
[i
].frame
= i
;
189 capBox
->grab_buf
[i
].width
= capBox
->width
;
190 capBox
->grab_buf
[i
].height
= capBox
->height
;
198 capBox
->imagesize
= renderlist_V4l
[capBox
->pict
.palette
].depth
*
199 capBox
->height
* capBox
->width
/ 8;
200 capBox
->grab_data
= CoTaskMemAlloc(capBox
->imagesize
);
201 if (!capBox
->grab_data
)
202 return E_OUTOFMEMORY
;
204 TRACE("Using mmap: %d\n", capBox
->mmap
);
208 static void V4l_Unprepare(Capture
*capBox
)
212 for (capBox
->curframe
= 0; capBox
->curframe
< capBox
->buffers
; capBox
->curframe
++)
213 xioctl(capBox
->fd
, VIDIOCSYNC
, &capBox
->grab_buf
[capBox
->curframe
]);
214 munmap(capBox
->pmap
, capBox
->gb_buffers
.size
);
215 CoTaskMemFree(capBox
->grab_buf
);
218 CoTaskMemFree(capBox
->grab_data
);
221 HRESULT
qcap_driver_destroy(Capture
*capBox
)
223 TRACE("%p\n", capBox
);
225 if( capBox
->fd
!= -1 )
227 DeleteCriticalSection(&capBox
->CritSect
);
228 CoTaskMemFree(capBox
);
232 HRESULT
qcap_driver_set_format(Capture
*capBox
, AM_MEDIA_TYPE
* mT
)
234 int newheight
, newwidth
;
235 struct video_window window
;
236 VIDEOINFOHEADER
*format
;
238 TRACE("%p\n", capBox
);
240 format
= (VIDEOINFOHEADER
*) mT
->pbFormat
;
241 if (format
->bmiHeader
.biBitCount
!= 24 ||
242 format
->bmiHeader
.biCompression
!= BI_RGB
)
244 FIXME("unsupported media type %d %ld\n", format
->bmiHeader
.biBitCount
,
245 format
->bmiHeader
.biCompression
);
246 return VFW_E_INVALIDMEDIATYPE
;
249 newwidth
= format
->bmiHeader
.biWidth
;
250 newheight
= format
->bmiHeader
.biHeight
;
252 TRACE("%p -> (%p) - %d %d\n", capBox
, mT
, newwidth
, newheight
);
254 if (capBox
->height
== newheight
&& capBox
->width
== newwidth
)
257 if(-1 == xioctl(capBox
->fd
, VIDIOCGWIN
, &window
))
259 ERR("ioctl(VIDIOCGWIN) failed (%d)\n", errno
);
262 window
.width
= newwidth
;
263 window
.height
= newheight
;
264 if (xioctl(capBox
->fd
, VIDIOCSWIN
, &window
) == -1)
266 TRACE("using software resize: %dx%d -> %dx%d\n",
267 window
.width
, window
.height
, capBox
->width
, capBox
->height
);
268 capBox
->swresize
= TRUE
;
272 capBox
->height
= window
.height
;
273 capBox
->width
= window
.width
;
274 capBox
->swresize
= FALSE
;
276 capBox
->outputwidth
= window
.width
;
277 capBox
->outputheight
= window
.height
;
281 HRESULT
qcap_driver_get_format(Capture
*capBox
, AM_MEDIA_TYPE
** mT
)
285 mT
[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
287 return E_OUTOFMEMORY
;
288 vi
= CoTaskMemAlloc(sizeof(VIDEOINFOHEADER
));
289 mT
[0]->cbFormat
= sizeof(VIDEOINFOHEADER
);
292 CoTaskMemFree(mT
[0]);
293 return E_OUTOFMEMORY
;
295 memcpy(&mT
[0]->majortype
, &MEDIATYPE_Video
, sizeof(GUID
));
296 memcpy(&mT
[0]->subtype
, &MEDIASUBTYPE_RGB24
, sizeof(GUID
));
297 memcpy(&mT
[0]->formattype
, &FORMAT_VideoInfo
, sizeof(GUID
));
298 mT
[0]->bFixedSizeSamples
= TRUE
;
299 mT
[0]->bTemporalCompression
= FALSE
;
301 mT
[0]->lSampleSize
= capBox
->outputwidth
* capBox
->outputheight
* capBox
->bitDepth
/ 8;
302 TRACE("Output format: %dx%d - %d bits = %lu KB\n", capBox
->outputwidth
,
303 capBox
->outputheight
, capBox
->bitDepth
, mT
[0]->lSampleSize
/1024);
304 vi
->rcSource
.left
= 0; vi
->rcSource
.top
= 0;
305 vi
->rcTarget
.left
= 0; vi
->rcTarget
.top
= 0;
306 vi
->rcSource
.right
= capBox
->width
; vi
->rcSource
.bottom
= capBox
->height
;
307 vi
->rcTarget
.right
= capBox
->outputwidth
; vi
->rcTarget
.bottom
= capBox
->outputheight
;
308 vi
->dwBitRate
= capBox
->fps
* mT
[0]->lSampleSize
;
309 vi
->dwBitErrorRate
= 0;
310 vi
->AvgTimePerFrame
= (LONGLONG
)10000000.0 / (LONGLONG
)capBox
->fps
;
311 vi
->bmiHeader
.biSize
= 40;
312 vi
->bmiHeader
.biWidth
= capBox
->outputwidth
;
313 vi
->bmiHeader
.biHeight
= capBox
->outputheight
;
314 vi
->bmiHeader
.biPlanes
= 1;
315 vi
->bmiHeader
.biBitCount
= 24;
316 vi
->bmiHeader
.biCompression
= BI_RGB
;
317 vi
->bmiHeader
.biSizeImage
= mT
[0]->lSampleSize
;
318 vi
->bmiHeader
.biClrUsed
= vi
->bmiHeader
.biClrImportant
= 0;
319 vi
->bmiHeader
.biXPelsPerMeter
= 100;
320 vi
->bmiHeader
.biYPelsPerMeter
= 100;
321 mT
[0]->pbFormat
= (void *)vi
;
322 dump_AM_MEDIA_TYPE(mT
[0]);
326 HRESULT
qcap_driver_get_prop_range( Capture
*capBox
, long Property
, long *pMin
,
327 long *pMax
, long *pSteppingDelta
, long *pDefault
, long *pCapsFlags
)
329 TRACE("%p -> %ld %p %p %p %p %p\n", capBox
, Property
,
330 pMin
, pMax
, pSteppingDelta
, pDefault
, pCapsFlags
);
334 case VideoProcAmp_Brightness
:
335 *pDefault
= capBox
->dbrightness
;
337 case VideoProcAmp_Contrast
:
338 *pDefault
= capBox
->dcontrast
;
340 case VideoProcAmp_Hue
:
341 *pDefault
= capBox
->dhue
;
343 case VideoProcAmp_Saturation
:
344 *pDefault
= capBox
->dcolour
;
347 FIXME("Not implemented %ld\n", Property
);
352 *pSteppingDelta
= 65536/256;
353 *pCapsFlags
= VideoProcAmp_Flags_Manual
;
357 HRESULT
qcap_driver_get_prop( Capture
*capBox
, long Property
, long *lValue
, long *Flags
)
359 TRACE("%p -> %ld %p %p\n", capBox
, Property
, lValue
, Flags
);
363 case VideoProcAmp_Brightness
:
364 *lValue
= capBox
->pict
.brightness
;
366 case VideoProcAmp_Contrast
:
367 *lValue
= capBox
->pict
.contrast
;
369 case VideoProcAmp_Hue
:
370 *lValue
= capBox
->pict
.hue
;
372 case VideoProcAmp_Saturation
:
373 *lValue
= capBox
->pict
.colour
;
376 FIXME("Not implemented %ld\n", Property
);
379 *Flags
= VideoProcAmp_Flags_Manual
;
383 HRESULT
qcap_driver_set_prop(Capture
*capBox
, long Property
, long lValue
, long Flags
)
385 TRACE("%p -> %ld %ld %ld\n", capBox
, Property
, lValue
, Flags
);
389 case VideoProcAmp_Brightness
:
390 capBox
->pict
.brightness
= lValue
;
392 case VideoProcAmp_Contrast
:
393 capBox
->pict
.contrast
= lValue
;
395 case VideoProcAmp_Hue
:
396 capBox
->pict
.hue
= lValue
;
398 case VideoProcAmp_Saturation
:
399 capBox
->pict
.colour
= lValue
;
402 FIXME("Not implemented %ld\n", Property
);
406 if (xioctl(capBox
->fd
, VIDIOCSPICT
, &capBox
->pict
) == -1)
408 ERR("ioctl(VIDIOCSPICT) failed (%d)\n",errno
);
414 static void renderer_RGB(Capture
*capBox
, LPBYTE bufferin
, LPBYTE stream
)
416 int depth
= renderlist_V4l
[capBox
->pict
.palette
].depth
;
417 int size
= capBox
->height
* capBox
->width
* depth
/ 8;
423 memcpy(bufferin
, stream
, size
);
428 while (pointer
+ offset
<= size
)
430 bufferin
[pointer
] = stream
[pointer
+ offset
];
432 bufferin
[pointer
] = stream
[pointer
+ offset
];
434 bufferin
[pointer
] = stream
[pointer
+ offset
];
440 ERR("Unknown bit depth %d\n", depth
);
445 static void renderer_YUV(Capture
*capBox
, LPBYTE bufferin
, LPBYTE stream
)
447 enum YUV_Format format
;
449 switch (capBox
->pict
.palette
)
451 case 7: /* YUV422 - same as YUYV */
458 case 11: /* YUV411 */
461 case 13: /* YUV422P */
464 case 14: /* YUV411P */
467 case 15: /* YUV420P */
470 case 16: /* YUV410P */
474 ERR("Unknown palette %d\n", capBox
->pict
.palette
);
477 YUV_To_RGB24(format
, bufferin
, stream
, capBox
->width
, capBox
->height
);
480 static void Resize(Capture
* capBox
, LPBYTE output
, LPBYTE input
)
482 /* the whole image needs to be reversed,
483 because the dibs are messed up in windows */
484 if (!capBox
->swresize
)
486 int depth
= capBox
->bitDepth
/ 8;
487 int inoffset
= 0, outoffset
= capBox
->height
* capBox
->width
* depth
;
488 int ow
= capBox
->width
* depth
;
489 while (outoffset
> 0)
493 for (x
= 0; x
< ow
; x
++)
494 output
[outoffset
+ x
] = input
[inoffset
+ x
];
501 HBITMAP bmp_s
, bmp_d
;
502 int depth
= capBox
->bitDepth
/ 8;
503 int inoffset
= 0, outoffset
= (capBox
->outputheight
) * capBox
->outputwidth
* depth
;
504 int ow
= capBox
->outputwidth
* depth
;
507 /* FIXME: Improve software resizing: add error checks and optimize */
509 myarray
= CoTaskMemAlloc(capBox
->outputwidth
* capBox
->outputheight
* depth
);
510 dc_s
= CreateCompatibleDC(NULL
);
511 dc_d
= CreateCompatibleDC(NULL
);
512 bmp_s
= CreateBitmap(capBox
->width
, capBox
->height
, 1, capBox
->bitDepth
, input
);
513 bmp_d
= CreateBitmap(capBox
->outputwidth
, capBox
->outputheight
, 1, capBox
->bitDepth
, NULL
);
514 SelectObject(dc_s
, bmp_s
);
515 SelectObject(dc_d
, bmp_d
);
516 StretchBlt(dc_d
, 0, 0, capBox
->outputwidth
, capBox
->outputheight
,
517 dc_s
, 0, 0, capBox
->width
, capBox
->height
, SRCCOPY
);
518 GetBitmapBits(bmp_d
, capBox
->outputwidth
* capBox
->outputheight
* depth
, myarray
);
519 while (outoffset
> 0)
524 for (i
= 0; i
< ow
; i
++)
525 output
[outoffset
+ i
] = myarray
[inoffset
+ i
];
528 CoTaskMemFree(myarray
);
536 static void V4l_GetFrame(Capture
* capBox
, unsigned char ** pInput
)
540 if (xioctl(capBox
->fd
, VIDIOCSYNC
, &capBox
->grab_buf
[capBox
->curframe
]) == -1)
541 WARN("Syncing ioctl failed: %d\n", errno
);
543 *pInput
= capBox
->pmap
+ capBox
->gb_buffers
.offsets
[capBox
->curframe
];
548 while ((retval
= read(capBox
->fd
, capBox
->grab_data
, capBox
->imagesize
)) == -1)
549 if (errno
!= EAGAIN
) break;
551 WARN("Error occurred while reading from device: %s\n", strerror(errno
));
552 *pInput
= (unsigned char*) capBox
->grab_data
;
556 static void V4l_FreeFrame(Capture
* capBox
)
561 if (xioctl(capBox
->fd
, VIDIOCMCAPTURE
, &capBox
->grab_buf
[capBox
->curframe
]) == -1)
562 ERR("Freeing frame for capture failed: %s\n", strerror(errno
));
564 if (++capBox
->curframe
== capBox
->buffers
)
565 capBox
->curframe
= 0;
568 static DWORD WINAPI
ReadThread(LPVOID lParam
)
570 Capture
* capBox
= (Capture
*)lParam
;
572 IMediaSample
*pSample
= NULL
;
573 unsigned long framecount
= 0;
574 unsigned char *pTarget
, *pInput
, *pOutput
;
576 hr
= V4l_Prepare(capBox
);
580 pOutput
= CoTaskMemAlloc(capBox
->width
* capBox
->height
* capBox
->bitDepth
/ 8);
581 capBox
->curframe
= 0;
583 V4l_FreeFrame(capBox
);
584 } while (capBox
->curframe
!= 0);
588 EnterCriticalSection(&capBox
->CritSect
);
591 hr
= OutputPin_GetDeliveryBuffer((OutputPin
*)capBox
->pOut
, &pSample
, NULL
, NULL
, 0);
596 if (!capBox
->swresize
)
597 len
= capBox
->height
* capBox
->width
* capBox
->bitDepth
/ 8;
599 len
= capBox
->outputheight
* capBox
->outputwidth
* capBox
->bitDepth
/ 8;
600 IMediaSample_SetActualDataLength(pSample
, len
);
602 len
= IMediaSample_GetActualDataLength(pSample
);
603 TRACE("Data length: %d KB\n", len
/ 1024);
605 IMediaSample_GetPointer(pSample
, &pTarget
);
606 /* FIXME: Check return values.. */
607 V4l_GetFrame(capBox
, &pInput
);
608 capBox
->renderer(capBox
, pOutput
, pInput
);
609 Resize(capBox
, pTarget
, pOutput
);
610 hr
= OutputPin_SendSample((OutputPin
*)capBox
->pOut
, pSample
);
611 TRACE("%p -> Frame %lu: %lx\n", capBox
, ++framecount
, hr
);
612 IMediaSample_Release(pSample
);
613 V4l_FreeFrame(capBox
);
615 LeaveCriticalSection(&capBox
->CritSect
);
616 if (FAILED(hr
) && hr
!= VFW_E_NOT_CONNECTED
)
618 ERR("Received error: %lx\n", hr
);
622 LeaveCriticalSection(&capBox
->CritSect
);
623 CoTaskMemFree(pOutput
);
628 CoTaskMemFree(pOutput
);
629 V4l_Unprepare(capBox
);
630 LeaveCriticalSection(&capBox
->CritSect
);
633 capBox
->thread
= 0; capBox
->stopped
= 1;
634 FIXME("Stop IFilterGraph\n");
638 HRESULT
qcap_driver_run(Capture
*capBox
, FILTER_STATE
*state
)
643 TRACE("%p -> (%p)\n", capBox
, state
);
645 if (*state
== State_Running
) return S_OK
;
647 EnterCriticalSection(&capBox
->CritSect
);
651 if (*state
== State_Stopped
)
653 *state
= State_Running
;
654 if (!capBox
->iscommitted
++)
656 IMemAllocator
* pAlloc
= NULL
;
657 ALLOCATOR_PROPERTIES ap
, actual
;
661 if (!capBox
->swresize
)
662 ap
.cbBuffer
= capBox
->width
* capBox
->height
;
664 ap
.cbBuffer
= capBox
->outputwidth
* capBox
->outputheight
;
665 ap
.cbBuffer
= (ap
.cbBuffer
* capBox
->bitDepth
) / 8;
669 out
= (OutputPin
*)capBox
->pOut
;
670 hr
= IMemInputPin_GetAllocator(out
->pMemInputPin
, &pAlloc
);
673 hr
= IMemAllocator_SetProperties(pAlloc
, &ap
, &actual
);
676 hr
= IMemAllocator_Commit(pAlloc
);
679 IMemAllocator_Release(pAlloc
);
681 TRACE("Committing allocator: %lx\n", hr
);
684 thread
= CreateThread(NULL
, 0, ReadThread
, capBox
, 0, NULL
);
687 capBox
->thread
= thread
;
688 SetThreadPriority(thread
, THREAD_PRIORITY_LOWEST
);
689 LeaveCriticalSection(&capBox
->CritSect
);
692 ERR("Creating thread failed.. %lx\n", GetLastError());
693 LeaveCriticalSection(&capBox
->CritSect
);
697 ResumeThread(capBox
->thread
);
698 *state
= State_Running
;
699 LeaveCriticalSection(&capBox
->CritSect
);
703 HRESULT
qcap_driver_pause(Capture
*capBox
, FILTER_STATE
*state
)
705 TRACE("%p -> (%p)\n", capBox
, state
);
707 if (*state
== State_Paused
)
709 if (*state
== State_Stopped
)
710 qcap_driver_run(capBox
, state
);
712 EnterCriticalSection(&capBox
->CritSect
);
713 *state
= State_Paused
;
714 SuspendThread(capBox
->thread
);
715 LeaveCriticalSection(&capBox
->CritSect
);
720 HRESULT
qcap_driver_stop(Capture
*capBox
, FILTER_STATE
*state
)
722 TRACE("%p -> (%p)\n", capBox
, state
);
724 if (*state
== State_Stopped
)
727 EnterCriticalSection(&capBox
->CritSect
);
731 if (*state
== State_Paused
)
732 ResumeThread(capBox
->thread
);
735 if (capBox
->iscommitted
)
737 IMemInputPin
*pMem
= NULL
;
738 IMemAllocator
* pAlloc
= NULL
;
739 IPin
*pConnect
= NULL
;
742 capBox
->iscommitted
= 0;
744 hr
= IPin_ConnectedTo(capBox
->pOut
, &pConnect
);
747 hr
= IPin_QueryInterface(pConnect
, &IID_IMemInputPin
, (void **) &pMem
);
750 hr
= IMemInputPin_GetAllocator(pMem
, &pAlloc
);
753 hr
= IMemAllocator_Decommit(pAlloc
);
756 IMemAllocator_Release(pAlloc
);
759 IMemInputPin_Release(pMem
);
762 IPin_Release(pConnect
);
764 if (hr
!= S_OK
&& hr
!= VFW_E_NOT_COMMITTED
)
765 WARN("Decommitting allocator: %lx\n", hr
);
767 V4l_Unprepare(capBox
);
770 *state
= State_Stopped
;
771 LeaveCriticalSection(&capBox
->CritSect
);
775 Capture
* qcap_driver_init( IPin
*pOut
, USHORT card
)
777 Capture
* capBox
= NULL
;
779 struct video_capability capa
;
780 struct video_picture pict
;
781 struct video_window window
;
785 capBox
= CoTaskMemAlloc(sizeof(Capture
));
789 /* capBox->vtbl = &defboxVtbl; */
791 InitializeCriticalSection( &capBox
->CritSect
);
793 sprintf(device
, "/dev/video%i", card
);
794 TRACE("opening %s\n", device
);
795 capBox
->fd
= open(device
, O_RDWR
| O_NONBLOCK
);
796 if (capBox
->fd
== -1)
798 WARN("open failed (%d)\n", errno
);
802 memset(&capa
, 0, sizeof(capa
));
804 if (xioctl(capBox
->fd
, VIDIOCGCAP
, &capa
) == -1)
806 WARN("ioctl(VIDIOCGCAP) failed (%d)\n", errno
);
810 if (!(capa
.type
& VID_TYPE_CAPTURE
))
812 WARN("not a video capture device\n");
816 TRACE("%d inputs on %s\n", capa
.channels
, capa
.name
);
818 if (xioctl(capBox
->fd
, VIDIOCGPICT
, &pict
) == -1)
820 ERR("ioctl(VIDIOCGPICT) failed (%d)\n", errno
);
824 TRACE("depth %d palette %d (%s) hue %d color %d contrast %d\n",
825 pict
.depth
, pict
.palette
, renderlist_V4l
[pict
.palette
].name
,
826 pict
.hue
, pict
.colour
, pict
.contrast
);
828 capBox
->dbrightness
= pict
.brightness
;
829 capBox
->dcolour
= pict
.colour
;
830 capBox
->dhue
= pict
.hue
;
831 capBox
->dcontrast
= pict
.contrast
;
833 if (!renderlist_V4l
[pict
.palette
].renderer
)
835 int palet
= pict
.palette
, i
;
837 TRACE("No renderer available for %s, falling back to defaults\n",
838 renderlist_V4l
[pict
.palette
].name
);
839 capBox
->renderer
= NULL
;
840 for (i
= 0; fallback_V4l
[i
] >=0 ; i
++)
842 int n
= fallback_V4l
[i
];
844 if (renderlist_V4l
[n
].renderer
== NULL
)
847 pict
.depth
= renderlist_V4l
[n
].depth
;
849 if (xioctl(capBox
->fd
, VIDIOCSPICT
, &pict
) == -1)
851 TRACE("Could not render with %s (%d)\n",
852 renderlist_V4l
[n
].name
, n
);
855 TRACE("using renderer %s (%d)\n",
856 renderlist_V4l
[n
].name
, n
);
857 capBox
->renderer
= renderlist_V4l
[n
].renderer
;
861 if (!capBox
->renderer
)
863 ERR("video format %s isn't available\n",
864 renderlist_V4l
[palet
].name
);
870 TRACE("Using the suggested format\n");
871 capBox
->renderer
= renderlist_V4l
[pict
.palette
].renderer
;
873 memcpy(&capBox
->pict
, &pict
, sizeof(struct video_picture
));
875 memset(&window
, 0, sizeof(window
));
876 if (xioctl(capBox
->fd
, VIDIOCGWIN
, &window
) == -1)
878 WARN("VIDIOCGWIN failed (%d)\n", errno
);
882 capBox
->height
= capBox
->outputheight
= window
.height
;
883 capBox
->width
= capBox
->outputwidth
= window
.width
;
884 capBox
->swresize
= FALSE
;
885 capBox
->bitDepth
= 24;
889 capBox
->curframe
= 0;
890 capBox
->iscommitted
= 0;
892 TRACE("format: %d bits - %d x %d\n", capBox
->bitDepth
, capBox
->width
, capBox
->height
);
894 return (Capture
*) capBox
;
898 qcap_driver_destroy( (Capture
*) capBox
);
905 Capture
* qcap_driver_init( IPin
*pOut
, USHORT card
)
908 "The v4l headers were not available at compile time,\n"
909 "so video capture support is not available.\n";
914 #define FAIL_WITH_ERR \
915 ERR("v4l absent: shouldn't be called\n"); \
918 HRESULT
qcap_driver_destroy(Capture
*capBox
)
923 HRESULT
qcap_driver_set_format(Capture
*capBox
, AM_MEDIA_TYPE
* mT
)
928 HRESULT
qcap_driver_get_format(Capture
*capBox
, AM_MEDIA_TYPE
** mT
)
933 HRESULT
qcap_driver_get_prop_range( Capture
*capBox
, long Property
, long *pMin
,
934 long *pMax
, long *pSteppingDelta
, long *pDefault
, long *pCapsFlags
)
939 HRESULT
qcap_driver_get_prop(Capture
*capBox
, long Property
, long *lValue
, long *Flags
)
944 HRESULT
qcap_driver_set_prop(Capture
*capBox
, long Property
, long lValue
, long Flags
)
949 HRESULT
qcap_driver_run(Capture
*capBox
, FILTER_STATE
*state
)
954 HRESULT
qcap_driver_pause(Capture
*capBox
, FILTER_STATE
*state
)
959 HRESULT
qcap_driver_stop(Capture
*capBox
, FILTER_STATE
*state
)
964 #endif /* HAVE_LINUX_VIDEODEV_H */