4 * Classes to support streaming video input (grabbing) and output.
6 * Portable Windows Library
8 * Copyright (c) 1993-2000 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): Mark Cooke (mpc@star.sr.bham.ac.uk)
27 * Revision 1.67 2007/04/05 01:53:00 rjongbloed
28 * Changed PVideoOutputDevice::CreateDeviceByName() to include driverName parameter so symmetric with PVideoInputDevice.
30 * Revision 1.66 2007/04/03 12:09:38 rjongbloed
31 * Fixed various "file video device" issues:
32 * Remove filename from PVideoDevice::OpenArgs (use deviceName)
33 * Added driverName to PVideoDevice::OpenArgs (so can select YUVFile)
34 * Added new statics to create correct video input/output device object
35 * given a PVideoDevice::OpenArgs structure.
36 * Fixed begin able to write to YUVFile when YUV420P colour format
37 * is not actually selected.
38 * Fixed truncating output video file if overwriting.
40 * Revision 1.65 2006/12/07 21:33:24 dominance
41 * make sure we support also webcams that do *only* do 640x480 properly.
42 * Thanks goes to Luc Saillard for this patch.
44 * Revision 1.64 2006/10/31 04:10:40 csoutheren
45 * Make sure PVidFileDev class is loaded, and make it work with OPAL
47 * Revision 1.63 2006/10/25 11:04:38 shorne
48 * fix for devices having same name for different drivers.
50 * Revision 1.62 2006/06/21 03:28:44 csoutheren
51 * Various cleanups thanks for Frederic Heem
53 * Revision 1.61 2006/04/19 04:10:27 csoutheren
54 * Fix problem when using converter when frame size not supported
56 * Revision 1.60 2006/03/07 20:53:51 dsandras
57 * Added support for JPEG based webcams, thanks to Luc Saillard <luc saillard org>.
59 * Revision 1.59 2006/01/29 22:46:39 csoutheren
60 * Added support for cameras that return MJPEG streams
61 * Thanks to Luc Saillard and Damien Sandras
63 * Revision 1.58 2006/01/09 18:19:13 dsandras
64 * Add YUY2 (or YUV420) format. Resizing to YUV420P is done, but it's not very
66 * Fix the gray border when doing padding for YUV420P (change it to black).
67 * Logitech webcam fusion export only big format in yuy2.
68 * Patches provided by Luc Saillard <luc _AT____ saillard.org>. Many thanks!
70 * Revision 1.57 2005/11/30 12:47:42 csoutheren
71 * Removed tabs, reformatted some code, and changed tags for Doxygen
73 * Revision 1.56 2005/09/06 12:41:22 rjongbloed
74 * Fixed correct creation (or non creation) of converter when using SetFrameSizeConverter()
76 * Revision 1.55 2005/08/23 12:42:23 rjongbloed
77 * Fixed problems with negative hight native flipping not working with all sizes.
79 * Revision 1.54 2005/08/09 09:08:12 rjongbloed
80 * Merged new video code from branch back to the trunk.
82 * Revision 1.53.6.2 2005/07/17 12:17:41 rjongbloed
83 * Fixed deadlock changing size
85 * Revision 1.53.6.1 2005/07/17 09:27:08 rjongbloed
86 * Major revisions of the PWLib video subsystem including:
87 * removal of F suffix on colour formats for vertical flipping, all done with existing bool
88 * working through use of RGB and BGR formats so now consistent
89 * cleaning up the plug in system to use virtuals instead of pointers to functions.
90 * rewrite of SDL to be a plug in compatible video output device.
91 * extensive enhancement of video test program
93 * Revision 1.53 2005/01/04 08:09:42 csoutheren
94 * Fixed Linux configure problems
96 * Revision 1.52 2004/11/17 10:13:14 csoutheren
97 * Fixed compilation with gcc 4.0.0
99 * Revision 1.51 2004/10/27 09:24:18 dsandras
100 * Added patch from Nicola Orru' to convert from SBGGR8 to YUV420P. Thanks!
102 * Revision 1.50 2004/10/23 10:54:39 ykiryanov
103 * Added ifdef _WIN32_WCE for PocketPC 2003 SDK port
105 * Revision 1.49 2004/08/16 06:40:59 csoutheren
106 * Added adapters template to make device plugins available via the abstract factory interface
108 * Revision 1.48 2004/04/18 12:49:22 csoutheren
109 * Patches to video code thanks to Guilhem Tardy (hope I get it right this time :)
111 * Revision 1.47 2004/04/03 23:53:10 csoutheren
112 * Added various changes to improce compatibility with the Sun Forte compiler
113 * Thanks to Brian Cameron
114 * Added detection of readdir_r version
116 * Revision 1.46 2004/01/18 14:25:58 dereksmithies
117 * New methods to make the opening of video input devices easier.
119 * Revision 1.45 2004/01/17 17:41:50 csoutheren
120 * Changed to use PString::MakeEmpty
122 * Revision 1.44 2003/12/14 10:01:02 rjongbloed
123 * Resolved issue with name space conflict os static and virtual forms of GetDeviceNames() function.
125 * Revision 1.43 2003/11/23 22:17:35 dsandras
126 * Added YUV420P to BGR24 and BGR32 conversion.
128 * Revision 1.42 2003/11/19 04:30:15 csoutheren
129 * Changed to support video output plugins
131 * Revision 1.41 2003/11/18 10:40:51 csoutheren
132 * Added pragma implementation to fix vtable link problems
134 * Revision 1.40 2003/11/18 06:46:38 csoutheren
135 * Changed to support video input plugins
137 * Revision 1.39 2003/05/14 07:51:23 rjongbloed
138 * Changed SetColourFormatConverter so if converter already in place no
140 * Fixed some trace logs.
142 * Revision 1.38 2003/04/03 23:21:34 robertj
143 * Added reversed RGB byte order versions (BGR24), thanks Damien Sandras
145 * Revision 1.37 2003/03/21 04:09:33 robertj
146 * Changed PPM video output device so you can specify the full format of the
147 * output file uinng printf command for the frame number eg %u or %03i or
148 * something. If there is no %u in the Opan() argument, a %u is added after
150 * Fixed video output RGB SetFrameData so abide by correct semantics. The input
151 * is aways to be what was set using SetColourFormat() or
152 * SetColourFormatConverter().
154 * Revision 1.36 2003/03/20 23:42:01 dereks
155 * Make PPM video output device work correctly.
157 * Revision 1.35 2003/03/17 07:50:41 robertj
158 * Added OpenFull() function to open with all video parameters in one go.
159 * Made sure vflip variable is set in converter even if converter has not
160 * been set yet, should not depend on the order of functions!
161 * Removed canCaptureVideo variable as this is really a virtual function to
162 * distinguish PVideoOutputDevice from PVideoInputDevice, it is not dynamic.
163 * Made significant enhancements to PVideoOutputDevice class.
164 * Added PVideoOutputDevice descendants for NULL and PPM files.
166 * Revision 1.34 2002/09/01 23:25:26 dereks
167 * Documentation fix from Walter Whitlock. Many thanks.
169 * Revision 1.33 2002/09/01 22:38:21 dereks
170 * Remove previous clarification, cause it breaks openphone code.
172 * Revision 1.32 2002/08/30 02:31:43 dereks
173 * Make operation of the code more clear. Thanks Diego Tartara
175 * Revision 1.31 2002/04/12 08:24:53 robertj
176 * Added text string output for tracing video format.
178 * Revision 1.30 2002/04/07 22:49:32 rogerh
181 * Revision 1.29 2002/04/05 06:41:54 rogerh
182 * Apply video changes from Damien Sandras <dsandras@seconix.com>.
183 * The Video Channel and Format are no longer set in Open(). Instead
184 * call the new SetVideoChannelFormat() method. This makes video capture
185 * and GnomeMeeting more stable with certain Linux video capture devices.
187 * Revision 1.28 2002/02/20 02:37:26 dereks
188 * Initial release of Firewire camera support for linux.
189 * Many thanks to Ryutaroh Matsumoto <ryutaroh@rmatsumoto.org>.
191 * Revision 1.27 2002/01/17 20:20:46 dereks
192 * Adjust PVideoInputDevice::SetVFlipState to cope better when a converter class is
193 * not attached. Thanks Walter Whitlock.
195 * Revision 1.26 2002/01/16 07:51:16 robertj
196 * MSVC compatibilty changes
198 * Revision 1.25 2002/01/14 02:59:41 robertj
199 * Added preferred colour format selection, thanks Walter Whitlock
201 * Revision 1.24 2002/01/08 01:32:20 robertj
202 * Tidied up some PTRACE debug output.
204 * Revision 1.23 2002/01/04 04:11:45 dereks
205 * Add video flip code from Walter Whitlock, which flips code at the grabber.
207 * Revision 1.22 2001/12/10 22:23:43 dereks
208 * Enable resize of CIF source image into QCIF size.
210 * Revision 1.21 2001/12/06 22:15:09 dereks
211 * Additional debugging lines
213 * Revision 1.20 2001/11/28 04:45:14 robertj
214 * Added Win32 flipped RGB colour formats.
216 * Revision 1.19 2001/11/28 00:07:32 dereks
217 * Locking added to PVideoChannel, allowing reader/writer to be changed mid call
218 * Enabled adjustment of the video frame rate
219 * New fictitous image, a blank grey area
221 * Revision 1.18 2001/09/25 04:25:38 dereks
222 * Add fix from Stelian Pop to improve the field of view for
223 * the small image with a Sony Vaio Motion Eye. Many thanks.
225 * Revision 1.17 2001/08/03 04:21:51 dereks
226 * Add colour/size conversion for YUV422->YUV411P
227 * Add Get/Set Brightness,Contrast,Hue,Colour for PVideoDevice, and
228 * Linux PVideoInputDevice.
229 * Add lots of PTRACE statement for debugging colour conversion.
230 * Add support for Sony Vaio laptop under linux. Requires 2.4.7 kernel.
232 * Revision 1.16 2001/06/27 17:23:33 rogerh
233 * Back out my previous change
235 * Revision 1.15 2001/06/26 15:48:31 rogerh
236 * Do not call GetInputDeviceName if there is no video grabber code
238 * Revision 1.14 2001/05/22 23:38:45 robertj
239 * Fixed bug in PVideoOutputDevice, removed redundent SetFrameSize.
241 * Revision 1.13 2001/03/20 02:21:57 robertj
242 * More enhancements from Mark Cooke
244 * Revision 1.12 2001/03/08 08:31:34 robertj
245 * Numerous enhancements to the video grabbing code including resizing
246 * infrastructure to converters. Thanks a LOT, Mark Cooke.
248 * Revision 1.11 2001/03/08 02:18:45 robertj
249 * Added improved defaulting of video formats so Open() does not fail.
250 * Removed the requirement that the device be open before you can set
251 * formats such as colour, video, channel number etc.
253 * Revision 1.10 2001/03/07 01:41:03 dereks
254 * Fix memory leak, on destroying PVideoDevice
255 * Ensure converter class is resized correctly.
257 * Revision 1.9 2001/03/06 23:34:20 robertj
258 * Added static function to get input device names.
259 * Moved some inline virtuals to non-inline.
261 * Revision 1.8 2001/03/05 01:12:41 robertj
262 * Added more source formats for conversion, use list. Thanks Mark Cooke.
264 * Revision 1.7 2001/03/03 05:06:31 robertj
265 * Major upgrade of video conversion and grabbing classes.
267 * Revision 1.6 2000/12/19 22:20:26 dereks
268 * Add video channel classes to connect to the PwLib PVideoInputDevice class.
269 * Add PFakeVideoInput class to generate test images for video.
271 * Revision 1.5 2000/11/09 00:20:58 robertj
272 * Added qcif size constants
274 * Revision 1.4 2000/07/26 03:50:50 robertj
275 * Added last error variable to video device.
277 * Revision 1.3 2000/07/26 02:13:48 robertj
278 * Added some more "common" bounds checking to video device.
280 * Revision 1.2 2000/07/25 13:38:26 robertj
281 * Added frame rate parameter to video frame grabber.
283 * Revision 1.1 2000/07/15 09:47:35 robertj
284 * Added video I/O device classes.
289 #pragma implementation "videoio.h"
290 #endif // !_WIN32_WCE
293 #include <ptlib/pluginmgr.h>
294 #include <ptlib/videoio.h>
295 #include <ptlib/vconvert.h>
297 namespace PWLibStupidWindowsHacks
{
302 PFactory
<PDevicePluginAdapterBase
>::Worker
< PDevicePluginAdapter
<PVideoInputDevice
> > vidinChannelFactoryAdapter("PVideoInputDevice", TRUE
);
303 PFactory
<PDevicePluginAdapterBase
>::Worker
< PDevicePluginAdapter
<PVideoOutputDevice
> > vidoutChannelFactoryAdapter("PVideoOutputDevice", TRUE
);
306 template <> PVideoInputDevice
* PDevicePluginFactory
<PVideoInputDevice
>::Worker::Create(const PString
& type
) const
308 return PVideoInputDevice::CreateDevice(type
);
311 template <> PVideoOutputDevice
* PDevicePluginFactory
<PVideoOutputDevice
>::Worker::Create(const PString
& type
) const
313 return PVideoOutputDevice::CreateDevice(type
);
316 ///////////////////////////////////////////////////////////////////////////////
319 ostream
& operator<<(ostream
& strm
, PVideoDevice::VideoFormat fmt
)
321 static const char * const VideoFormatNames
[PVideoDevice::NumVideoFormats
] = {
328 if (fmt
< PVideoDevice::NumVideoFormats
&& VideoFormatNames
[fmt
] != NULL
)
329 strm
<< VideoFormatNames
[fmt
];
331 strm
<< "VideoFormat<" << (unsigned)fmt
<< '>';
337 ///////////////////////////////////////////////////////////////////////////////
340 PVideoDevice::PVideoDevice()
345 channelNumber
= -1; // -1 will find the first working channel number.
346 frameWidth
= CIFWidth
;
347 frameHeight
= CIFHeight
;
348 nativeVerticalFlip
= FALSE
;
355 PVideoDevice::~PVideoDevice()
362 PVideoDevice::OpenArgs::OpenArgs()
367 colourFormat("YUV420P"),
384 BOOL
PVideoDevice::OpenFull(const OpenArgs
& args
, BOOL startImmediate
)
386 if (args
.deviceName
[0] == '#') {
387 PStringArray devices
= GetDeviceNames();
388 PINDEX id
= args
.deviceName
.Mid(1).AsUnsigned();
389 if (id
== 0 || id
> devices
.GetSize())
392 if (!Open(devices
[id
-1], FALSE
))
396 if (!Open(args
.deviceName
, FALSE
))
400 if (!SetVideoFormat(args
.videoFormat
))
403 if (!SetChannel(args
.channelNumber
))
406 if (args
.convertFormat
) {
407 if (!SetColourFormatConverter(args
.colourFormat
))
411 if (!SetColourFormat(args
.colourFormat
))
416 if (!SetFrameRate(args
.rate
))
420 if (args
.convertSize
) {
421 if (!SetFrameSizeConverter(args
.width
, args
.height
, args
.scaleSize
))
425 if (!SetFrameSize(args
.width
, args
.height
))
429 if (!SetVFlipState(args
.flip
))
432 if (args
.brightness
>= 0) {
433 if (!SetBrightness(args
.brightness
))
437 if (args
.whiteness
>= 0) {
438 if (!SetWhiteness(args
.whiteness
))
442 if (args
.contrast
>= 0) {
443 if (!SetContrast(args
.contrast
))
447 if (args
.colour
>= 0) {
448 if (!SetColour(args
.colour
))
453 if (!SetColour(args
.hue
))
464 BOOL
PVideoDevice::Close()
470 BOOL
PVideoDevice::Start()
476 BOOL
PVideoDevice::Stop()
482 BOOL
PVideoDevice::SetVideoFormat(VideoFormat videoFmt
)
484 videoFormat
= videoFmt
;
489 PVideoDevice::VideoFormat
PVideoDevice::GetVideoFormat() const
495 int PVideoDevice::GetNumChannels()
501 BOOL
PVideoDevice::SetChannel(int channelNum
)
503 if (channelNum
< 0) { // Seek out the first available channel
504 for (int c
= 0; c
< GetNumChannels(); c
++) {
511 if (channelNum
>= GetNumChannels())
514 channelNumber
= channelNum
;
519 int PVideoDevice::GetChannel() const
521 return channelNumber
;
525 //Colour format bit per pixel table.
526 // These are in rough order of colour gamut size
528 const char * colourFormat
;
529 unsigned bitsPerPixel
;
530 } colourFormatBPPTab
[] = {
558 BOOL
PVideoDevice::SetColourFormatConverter(const PString
& colourFmt
)
560 if (converter
!= NULL
) {
561 if (CanCaptureVideo()) {
562 if (converter
->GetDstColourFormat() == colourFmt
)
566 if (converter
->GetSrcColourFormat() == colourFmt
)
573 if (!preferredColourFormat
.IsEmpty()) {
574 PTRACE(4,"PVidDev\tSetColourFormatConverter, want " << colourFmt
<< " trying " << preferredColourFormat
);
575 if (SetColourFormat(preferredColourFormat
)) {
576 if (CanCaptureVideo()) {
577 PTRACE(4,"PVidDev\tSetColourFormatConverter set camera to native "<< preferredColourFormat
);
578 if (preferredColourFormat
!= colourFmt
)
579 converter
= PColourConverter::Create(preferredColourFormat
, colourFmt
, frameWidth
, frameHeight
);
582 PTRACE(4,"PVidDev\tSetColourFormatConverter set renderer to "<< preferredColourFormat
);
583 if (preferredColourFormat
!= colourFmt
)
584 converter
= PColourConverter::Create(colourFmt
, preferredColourFormat
, frameWidth
, frameHeight
);
587 if (nativeVerticalFlip
&& converter
== NULL
)
588 converter
= PColourConverter::Create(colourFmt
, colourFmt
, frameWidth
, frameHeight
);
590 if (converter
!= NULL
) {
591 converter
->SetVFlipState(nativeVerticalFlip
);
597 if (SetColourFormat(colourFmt
)) {
598 if (nativeVerticalFlip
) {
599 converter
= PColourConverter::Create(colourFmt
, colourFmt
, frameWidth
, frameHeight
);
600 if (PAssertNULL(converter
) == NULL
)
602 converter
->SetVFlipState(nativeVerticalFlip
);
605 PTRACE(3, "PVidDev\tSetColourFormatConverter success for native " << colourFmt
);
609 /************************
610 Eventually, need something more sophisticated than this, but for the
611 moment pick the known colour formats that the device is very likely to
612 support and then look for a conversion routine from that to the
615 What we really want is some sort of better heuristic that looks at
616 computational requirements of each converter and picks a pair of formats
617 that the hardware supports and uses the least CPU.
620 PINDEX knownFormatIdx
= 0;
621 while (knownFormatIdx
< PARRAYSIZE(colourFormatBPPTab
)) {
622 PString formatToTry
= colourFormatBPPTab
[knownFormatIdx
].colourFormat
;
623 PTRACE(4,"PVidDev\tSetColourFormatConverter, want " << colourFmt
<< " trying " << formatToTry
);
624 if (SetColourFormat(formatToTry
)) {
625 if (CanCaptureVideo()) {
626 PTRACE(4,"PVidDev\tSetColourFormatConverter set camera to "<< formatToTry
);
627 converter
= PColourConverter::Create(formatToTry
, colourFmt
, frameWidth
, frameHeight
);
630 PTRACE(4,"PVidDev\tSetColourFormatConverter set renderer to "<< formatToTry
);
631 converter
= PColourConverter::Create(colourFmt
, formatToTry
, frameWidth
, frameHeight
);
633 if (converter
!= NULL
) {
634 // set converter properties that depend on this color format
635 PTRACE(3, "PVidDev\tSetColourFormatConverter succeeded for " << colourFmt
<< " and device using " << formatToTry
);
636 converter
->SetVFlipState(nativeVerticalFlip
);
643 PTRACE(2, "PVidDev\tSetColourFormatConverter FAILED for " << colourFmt
);
648 BOOL
PVideoDevice::SetColourFormat(const PString
& colourFmt
)
651 colourFormat
= colourFmt
.ToUpper();
655 for (PINDEX i
= 0; i
< PARRAYSIZE(colourFormatBPPTab
); i
++) {
656 if (SetColourFormat(colourFormatBPPTab
[i
].colourFormat
))
664 const PString
& PVideoDevice::GetColourFormat() const
670 BOOL
PVideoDevice::SetFrameRate(unsigned rate
)
679 previousFrameTime
= PTime();
680 msBetweenFrames
= 1000/rate
;
687 BOOL
PVideoDevice::GetVFlipState()
689 if (converter
!= NULL
)
690 return converter
->GetVFlipState() ^ nativeVerticalFlip
;
692 return nativeVerticalFlip
;
696 BOOL
PVideoDevice::SetVFlipState(BOOL newVFlip
)
698 if (newVFlip
&& converter
== NULL
)
699 converter
= PColourConverter::Create(colourFormat
, colourFormat
, frameWidth
, frameHeight
);
701 if (converter
!= NULL
)
702 converter
->SetVFlipState(newVFlip
^ nativeVerticalFlip
);
708 unsigned PVideoDevice::GetFrameRate() const
714 BOOL
PVideoDevice::GetFrameSizeLimits(unsigned & minWidth
,
715 unsigned & minHeight
,
717 unsigned & maxHeight
)
719 minWidth
= minHeight
= 1;
720 maxWidth
= maxHeight
= UINT_MAX
;
726 unsigned asked_width
, asked_height
, device_width
, device_height
;
728 { 704, 576, 640, 480 },
729 { 640, 480, 704, 576 },
730 { 640, 480, 352, 288 },
732 { 352, 288, 704, 576 },
733 { 352, 288, 640, 480 },
734 { 352, 288, 352, 240 },
735 { 352, 288, 320, 240 },
736 { 352, 288, 176, 144 },
737 { 352, 288, 1024, 576 }, /* High resolution need to be set at the end */
738 { 352, 288, 1280, 960 },
740 { 352, 240, 352, 288 },
741 { 352, 240, 320, 240 },
742 { 352, 240, 640, 480 },
744 { 320, 240, 352, 288 },
745 { 320, 240, 352, 240 },
746 { 320, 240, 640, 480 },
748 { 176, 144, 352, 288 },
749 { 176, 144, 352, 240 },
750 { 176, 144, 320, 240 },
751 { 176, 144, 176, 120 },
752 { 176, 144, 160, 120 },
753 { 176, 144, 640, 480 },
754 { 176, 144, 1024, 576 },
755 { 176, 144, 1280, 960 }, /* High resolution need to be set at the end */
757 { 176, 120, 352, 288 },
758 { 176, 120, 352, 240 },
759 { 176, 120, 320, 240 },
760 { 176, 120, 176, 144 },
761 { 176, 120, 160, 120 },
762 { 176, 120, 640, 480 },
764 { 160, 120, 352, 288 },
765 { 160, 120, 352, 240 },
766 { 160, 120, 320, 240 },
767 { 160, 120, 176, 144 },
768 { 160, 120, 176, 120 },
769 { 160, 120, 640, 480 },
772 BOOL
PVideoDevice::SetFrameSizeConverter(unsigned width
, unsigned height
,
775 if (SetFrameSize(width
, height
)) {
776 if (nativeVerticalFlip
&& converter
== NULL
) {
777 converter
= PColourConverter::Create(colourFormat
, colourFormat
, frameWidth
, frameHeight
);
778 if (PAssertNULL(converter
) == NULL
)
781 if (converter
!= NULL
) {
782 converter
->SetFrameSize(frameWidth
, frameHeight
);
783 converter
->SetVFlipState(nativeVerticalFlip
);
788 if (converter
== NULL
) {
789 converter
= PColourConverter::Create(colourFormat
, colourFormat
, frameWidth
, frameHeight
);
790 if (converter
== NULL
) {
791 PTRACE(1, "PVidDev\tSetFrameSizeConverter Colour converter creation failed");
796 PTRACE(3,"PVidDev\tColour converter used for " << width
<< 'x' << height
);
798 unsigned minWidth
, minHeight
, maxWidth
, maxHeight
;
799 BOOL limits
= GetFrameSizeLimits(minWidth
, minHeight
, maxWidth
, maxHeight
);
801 for (PINDEX i
= 0; i
< PARRAYSIZE(framesizeTab
); i
++) {
802 if (framesizeTab
[i
].asked_width
== width
&&
803 framesizeTab
[i
].asked_height
== height
&&
805 (framesizeTab
[i
].device_width
>= minWidth
&&
806 framesizeTab
[i
].device_width
<= maxWidth
&&
807 framesizeTab
[i
].device_height
>= minHeight
&&
808 framesizeTab
[i
].device_height
<= maxHeight
)) &&
809 SetFrameSize(framesizeTab
[i
].device_width
,
810 framesizeTab
[i
].device_height
)) {
811 if (CanCaptureVideo() ?
812 converter
->SetDstFrameSize(width
, height
, bScaleNotCrop
)
814 converter
->SetSrcFrameSize(width
, height
) &&
815 converter
->SetDstFrameSize(framesizeTab
[i
].device_width
,
816 framesizeTab
[i
].device_height
,
818 PTRACE(4,"PVideoDevice\tSetFrameSizeConverter succeeded for converting from "
819 << framesizeTab
[i
].device_width
<< 'x' << framesizeTab
[i
].device_height
820 << " to " << width
<< 'x' << height
);
822 converter
->SetVFlipState(converter
->GetVFlipState() ^ nativeVerticalFlip
);
828 if (CanCaptureVideo()) {
829 // Failed to find a resolution the device can do so far, so try
830 // using the maximum width and height it claims it can do.
832 SetFrameSize(maxWidth
, maxHeight
)) {
833 if (converter
->SetDstFrameSize(width
, height
, bScaleNotCrop
)) {
834 PTRACE(4,"PVideoDevice\tSetFrameSizeConverter succeeded for converting from "
835 << maxWidth
<< 'x' << maxHeight
836 << " to " << width
<< 'x' << height
);
838 converter
->SetVFlipState(converter
->GetVFlipState() ^ nativeVerticalFlip
);
844 PTRACE(2,"PVideoDevice\tSetFrameSizeConverter failed for " << width
<< 'x' << height
);
850 BOOL
PVideoDevice::SetFrameSize(unsigned width
, unsigned height
)
853 unsigned oldWidth
= frameWidth
;
854 unsigned oldHeight
= frameHeight
;
857 unsigned minWidth
, minHeight
, maxWidth
, maxHeight
;
858 GetFrameSizeLimits(minWidth
, minHeight
, maxWidth
, maxHeight
);
860 if (width
< minWidth
)
861 frameWidth
= minWidth
;
862 else if (width
> maxWidth
)
863 frameWidth
= maxWidth
;
867 if (height
< minHeight
)
868 frameHeight
= minHeight
;
869 else if (height
> maxHeight
)
870 frameHeight
= maxHeight
;
872 frameHeight
= height
;
874 if (converter
!= NULL
) {
875 if (!converter
->SetSrcFrameSize(width
, height
) ||
876 !converter
->SetDstFrameSize(width
, height
, FALSE
)) {
877 PTRACE(1, "PVidDev\tSetFrameSize with converter failed with " << width
<< 'x' << height
);
882 PTRACE_IF(2, oldWidth
!= frameWidth
|| oldHeight
!= frameHeight
,
883 "PVidDev\tSetFrameSize to " << frameWidth
<< 'x' << frameHeight
);
888 BOOL
PVideoDevice::GetFrameSize(unsigned & width
, unsigned & height
)
891 // Channels get very upset at this not returning the output size.
893 return converter
->GetDstFrameSize(width
, height
);
896 height
= frameHeight
;
901 unsigned PVideoDevice::GetFrameWidth() const
906 // Channels get very upset at this not returning the output size.
908 converter
->GetDstFrameSize(w
, h
);
916 unsigned PVideoDevice::GetFrameHeight() const
921 // Channels get very upset at this not returning the output size.
923 converter
->GetDstFrameSize(w
, h
);
931 unsigned PVideoDevice::CalculateFrameBytes(unsigned width
, unsigned height
,
932 const PString
& colourFormat
)
934 for (PINDEX i
= 0; i
< PARRAYSIZE(colourFormatBPPTab
); i
++) {
935 if (colourFormat
*= colourFormatBPPTab
[i
].colourFormat
)
936 return width
* height
* colourFormatBPPTab
[i
].bitsPerPixel
/8;
942 PINDEX
PVideoDevice::GetMaxFrameBytesConverted(PINDEX rawFrameBytes
) const
944 if (converter
== NULL
)
945 return rawFrameBytes
;
947 PINDEX srcFrameBytes
= converter
->GetMaxSrcFrameBytes();
948 PINDEX dstFrameBytes
= converter
->GetMaxDstFrameBytes();
949 PINDEX convertedFrameBytes
= PMAX(srcFrameBytes
, dstFrameBytes
);
950 return PMAX(rawFrameBytes
, convertedFrameBytes
);
954 int PVideoDevice::GetBrightness()
956 return frameBrightness
;
960 BOOL
PVideoDevice::SetBrightness(unsigned newBrightness
)
962 frameBrightness
= newBrightness
;
967 int PVideoDevice::GetWhiteness()
969 return frameWhiteness
;
973 BOOL
PVideoDevice::SetWhiteness(unsigned newWhiteness
)
975 frameWhiteness
= newWhiteness
;
980 int PVideoDevice::GetColour()
986 BOOL
PVideoDevice::SetColour(unsigned newColour
)
988 frameColour
=newColour
;
993 int PVideoDevice::GetContrast()
995 return frameContrast
;
999 BOOL
PVideoDevice::SetContrast(unsigned newContrast
)
1001 frameContrast
=newContrast
;
1006 int PVideoDevice::GetHue()
1012 BOOL
PVideoDevice::SetHue(unsigned newHue
)
1019 BOOL
PVideoDevice::GetParameters (int *whiteness
,
1028 *brightness
= frameBrightness
;
1029 *colour
= frameColour
;
1030 *contrast
= frameContrast
;
1032 *whiteness
= frameWhiteness
;
1037 BOOL
PVideoDevice::SetVideoChannelFormat (int newNumber
, VideoFormat newFormat
)
1041 err1
= SetChannel (newNumber
);
1042 err2
= SetVideoFormat (newFormat
);
1044 return (err1
&& err2
);
1047 PStringList
PVideoDevice::GetDeviceNames() const
1049 return PStringList();
1053 ///////////////////////////////////////////////////////////////////////////////
1054 // PVideoOutputDevice
1056 PVideoOutputDevice::PVideoOutputDevice()
1061 BOOL
PVideoOutputDevice::CanCaptureVideo() const
1067 ///////////////////////////////////////////////////////////////////////////////
1068 // PVideoOutputDeviceRGB
1070 PVideoOutputDeviceRGB::PVideoOutputDeviceRGB()
1072 PTRACE(6, "RGB\t Constructor of PVideoOutputDeviceRGB");
1074 colourFormat
= "RGB24";
1076 swappedRedAndBlue
= false;
1077 SetFrameSize(frameWidth
, frameHeight
);
1081 BOOL
PVideoOutputDeviceRGB::SetColourFormat(const PString
& colourFormat
)
1083 PWaitAndSignal
m(mutex
);
1085 PINDEX newBytesPerPixel
;
1086 bool newSwappedRedAndBlue
;
1087 if (colourFormat
*= "RGB32") {
1088 newBytesPerPixel
= 4;
1089 newSwappedRedAndBlue
= false;
1091 else if (colourFormat
*= "RGB24") {
1092 newBytesPerPixel
= 3;
1093 newSwappedRedAndBlue
= false;
1095 else if (colourFormat
*= "BGR32") {
1096 newBytesPerPixel
= 4;
1097 newSwappedRedAndBlue
= true;
1099 else if (colourFormat
*= "BGR24") {
1100 newBytesPerPixel
= 3;
1101 newSwappedRedAndBlue
= true;
1106 if (!PVideoOutputDevice::SetColourFormat(colourFormat
))
1109 bytesPerPixel
= newBytesPerPixel
;
1110 scanLineWidth
= ((frameWidth
*bytesPerPixel
+3)/4)*4;
1111 return frameStore
.SetSize(frameHeight
*scanLineWidth
);
1115 BOOL
PVideoOutputDeviceRGB::SetFrameSize(unsigned width
, unsigned height
)
1117 PWaitAndSignal
m(mutex
);
1119 if (!PVideoOutputDevice::SetFrameSize(width
, height
))
1122 scanLineWidth
= ((frameWidth
*bytesPerPixel
+3)/4)*4;
1123 return frameStore
.SetSize(frameHeight
*scanLineWidth
);
1127 PINDEX
PVideoOutputDeviceRGB::GetMaxFrameBytes()
1129 PWaitAndSignal
m(mutex
);
1130 return GetMaxFrameBytesConverted(frameStore
.GetSize());
1134 BOOL
PVideoOutputDeviceRGB::SetFrameData(unsigned x
, unsigned y
,
1135 unsigned width
, unsigned height
,
1139 PWaitAndSignal
m(mutex
);
1141 if (x
+width
> frameWidth
|| y
+height
> frameHeight
)
1144 if (x
== 0 && width
== frameWidth
&& y
== 0 && height
== frameHeight
) {
1145 if (converter
!= NULL
)
1146 converter
->Convert(data
, frameStore
.GetPointer());
1148 memcpy(frameStore
.GetPointer(), data
, height
*scanLineWidth
);
1151 if (converter
!= NULL
) {
1152 PAssertAlways("Converted output of partial RGB frame not supported");
1156 if (x
== 0 && width
== frameWidth
)
1157 memcpy(frameStore
.GetPointer() + y
*scanLineWidth
, data
, height
*scanLineWidth
);
1159 for (unsigned dy
= 0; dy
< height
; dy
++)
1160 memcpy(frameStore
.GetPointer() + (y
+dy
)*scanLineWidth
+ x
*bytesPerPixel
,
1161 data
+ dy
*width
*bytesPerPixel
, width
*bytesPerPixel
);
1166 return FrameComplete();
1172 ///////////////////////////////////////////////////////////////////////////////
1173 // PVideoOutputDevicePPM
1175 #ifdef SHOULD_BE_MOVED_TO_PLUGIN
1177 PVideoOutputDevicePPM::PVideoOutputDevicePPM()
1179 PTRACE(6, "PPM\t Constructor of PVideoOutputDevicePPM");
1184 BOOL
PVideoOutputDevicePPM::Open(const PString
& name
,
1185 BOOL
/*startImmediate*/)
1189 PFilePath path
= name
;
1190 if (!PDirectory::Exists(path
.GetDirectory()))
1193 if (path
!= psprintf(path
, 12345))
1196 deviceName
= path
.GetDirectory() + path
.GetTitle() + "%u" + path
.GetType();
1202 BOOL
PVideoOutputDevicePPM::IsOpen()
1208 BOOL
PVideoOutputDevicePPM::Close()
1210 deviceName
.MakeEmpty();
1215 PStringList
PVideoOutputDevicePPM::GetDeviceNames() const
1218 list
+= PDirectory();
1223 BOOL
PVideoOutputDevicePPM::EndFrame()
1226 if (!file
.Open(psprintf(deviceName
, frameNumber
++), PFile::WriteOnly
)) {
1227 PTRACE(1, "PPMVid\tFailed to open PPM output file \""
1228 << file
.GetName() << "\": " << file
.GetErrorText());
1232 file
<< "P6 " << frameWidth
<< " " << frameHeight
<< " " << 255 << "\n";
1234 if (!file
.Write(frameStore
, frameStore
.GetSize())) {
1235 PTRACE(1, "PPMVid\tFailed to write frame data to PPM output file " << file
.GetName());
1239 PTRACE(6, "PPMVid\tFinished writing PPM file " << file
.GetName());
1240 return file
.Close();
1243 #endif // SHOULD_BE_MOVED_TO_PLUGIN
1246 ///////////////////////////////////////////////////////////////////////////////
1247 // PVideoInputDevice
1249 BOOL
PVideoInputDevice::CanCaptureVideo() const
1254 static const char videoInputPluginBaseClass
[] = "PVideoInputDevice";
1257 PStringList
PVideoInputDevice::GetDriverNames(PPluginManager
* pluginMgr
)
1259 if (pluginMgr
== NULL
)
1260 pluginMgr
= &PPluginManager::GetPluginManager();
1262 return pluginMgr
->GetPluginsProviding(videoInputPluginBaseClass
);
1266 PStringList
PVideoInputDevice::GetDriversDeviceNames(const PString
& driverName
, PPluginManager
* pluginMgr
)
1268 if (pluginMgr
== NULL
)
1269 pluginMgr
= &PPluginManager::GetPluginManager();
1271 return pluginMgr
->GetPluginsDeviceNames(driverName
, videoInputPluginBaseClass
);
1275 PVideoInputDevice
* PVideoInputDevice::CreateDevice(const PString
&driverName
, PPluginManager
* pluginMgr
)
1277 if (pluginMgr
== NULL
)
1278 pluginMgr
= &PPluginManager::GetPluginManager();
1280 return (PVideoInputDevice
*)pluginMgr
->CreatePluginsDevice(driverName
, videoInputPluginBaseClass
);
1284 PVideoInputDevice
* PVideoInputDevice::CreateDeviceByName(const PString
& deviceName
, const PString
& driverName
, PPluginManager
* pluginMgr
)
1286 if (pluginMgr
== NULL
)
1287 pluginMgr
= &PPluginManager::GetPluginManager();
1289 return (PVideoInputDevice
*)pluginMgr
->CreatePluginsDeviceByName(deviceName
, videoInputPluginBaseClass
,0,driverName
);
1293 PVideoInputDevice
* PVideoInputDevice::CreateOpenedDevice(const PString
& driverName
,
1294 const PString
& deviceName
,
1295 BOOL startImmediate
,
1296 PPluginManager
* pluginMgr
)
1298 PVideoInputDevice
* device
= CreateDeviceByName(deviceName
, driverName
, pluginMgr
);
1300 if (device
!= NULL
&& device
->Open(deviceName
, startImmediate
))
1308 PVideoInputDevice
* PVideoInputDevice::CreateOpenedDevice(const OpenArgs
& args
,
1309 BOOL startImmediate
)
1311 PVideoInputDevice
* device
= CreateDeviceByName(args
.deviceName
, args
.driverName
, args
.pluginMgr
);
1313 if (device
!= NULL
&& device
->OpenFull(args
, startImmediate
))
1321 BOOL
PVideoInputDevice::GetFrame(PBYTEArray
& frame
)
1324 if (!GetFrameData(frame
.GetPointer(GetMaxFrameBytes()), &returned
))
1327 frame
.SetSize(returned
);
1332 ////////////////////////////////////////////////////////////////////////////////////////////
1334 static const char videoOutputPluginBaseClass
[] = "PVideoOutputDevice";
1337 PStringList
PVideoOutputDevice::GetDriverNames(PPluginManager
* pluginMgr
)
1339 if (pluginMgr
== NULL
)
1340 pluginMgr
= &PPluginManager::GetPluginManager();
1342 return pluginMgr
->GetPluginsProviding(videoOutputPluginBaseClass
);
1346 PStringList
PVideoOutputDevice::GetDriversDeviceNames(const PString
& driverName
, PPluginManager
* pluginMgr
)
1348 if (pluginMgr
== NULL
)
1349 pluginMgr
= &PPluginManager::GetPluginManager();
1351 return pluginMgr
->GetPluginsDeviceNames(driverName
, videoOutputPluginBaseClass
);
1355 PVideoOutputDevice
* PVideoOutputDevice::CreateDevice(const PString
& driverName
, PPluginManager
* pluginMgr
)
1357 if (pluginMgr
== NULL
)
1358 pluginMgr
= &PPluginManager::GetPluginManager();
1360 return (PVideoOutputDevice
*)pluginMgr
->CreatePluginsDevice(driverName
, videoOutputPluginBaseClass
);
1364 PVideoOutputDevice
* PVideoOutputDevice::CreateDeviceByName(const PString
& deviceName
, const PString
& driverName
, PPluginManager
* pluginMgr
)
1366 if (pluginMgr
== NULL
)
1367 pluginMgr
= &PPluginManager::GetPluginManager();
1369 return (PVideoOutputDevice
*)pluginMgr
->CreatePluginsDeviceByName(deviceName
, videoOutputPluginBaseClass
, 0, driverName
);
1373 PVideoOutputDevice
* PVideoOutputDevice::CreateOpenedDevice(const PString
&driverName
,
1374 const PString
&deviceName
,
1375 BOOL startImmediate
,
1376 PPluginManager
* pluginMgr
)
1378 PVideoOutputDevice
* device
;
1379 if (driverName
.IsEmpty() || driverName
== "*")
1380 device
= CreateDeviceByName(deviceName
, driverName
, pluginMgr
);
1382 device
= CreateDevice(driverName
, pluginMgr
);
1384 if (device
!= NULL
&& device
->Open(deviceName
, startImmediate
))
1392 PVideoOutputDevice
* PVideoOutputDevice::CreateOpenedDevice(const OpenArgs
& args
,
1393 BOOL startImmediate
)
1395 PVideoOutputDevice
* device
;
1396 if (args
.driverName
.IsEmpty() || args
.driverName
== "*")
1397 device
= CreateDeviceByName(args
.deviceName
, args
.driverName
, args
.pluginMgr
);
1399 device
= CreateDevice(args
.driverName
, args
.pluginMgr
);
1401 if (device
!= NULL
&& device
->OpenFull(args
, startImmediate
))
1409 // End Of File ///////////////////////////////////////////////////////////////