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): Roger Hardiman <roger@freebsd.org>
27 * Revision 1.21 2004/01/02 23:30:18 rjongbloed
28 * Removed extraneous static function for getting input device names that has been deprecated during the plug ins addition.
30 * Revision 1.20 2002/10/28 19:12:45 rogerh
31 * Add svideo input support for Lars Eggert <larse@isi.edu>
33 * Revision 1.19 2002/04/10 08:40:36 rogerh
34 * Simplify the SetVideoChannelFormat() code. Use the implementation in the
37 * Revision 1.18 2002/04/05 06:41:54 rogerh
38 * Apply video changes from Damien Sandras <dsandras@seconix.com>.
39 * The Video Channel and Format are no longer set in Open(). Instead
40 * call the new SetVideoChannelFormat() method. This makes video capture
41 * and GnomeMeeting more stable with certain Linux video capture devices.
43 * Revision 1.17 2002/01/08 17:16:13 rogerh
44 * Add code to grab Even fields (instead of interlaced frames) whenever
45 * possible. This improves the image quality.
48 * Revision 1.16 2001/12/05 14:45:20 rogerh
49 * Implement GetFrameData and GetFrameDataNoDelay
51 * Revision 1.15 2001/12/05 14:32:48 rogerh
52 * Add GetParemters function
54 * Revision 1.14 2001/08/06 06:56:16 rogerh
55 * Add scaling for new methods to match BSD's Meteor API
57 * Revision 1.13 2001/08/06 06:19:33 rogerh
58 * Implement Brightness, Contract and Hue methods.
60 * Revision 1.12 2001/03/26 16:02:01 rogerh
61 * Add dummy function for VerifyHardwareFrameSize
63 * Revision 1.11 2001/03/08 03:59:13 robertj
64 * Fixed previous change, needed to allow for -1 as chammelNumber in Open().
66 * Revision 1.10 2001/03/08 02:23:17 robertj
67 * Added improved defaulting of video formats so Open() does not fail.
69 * Revision 1.9 2001/03/07 00:10:05 robertj
70 * Improved the device list, uses /proc, thanks Thorsten Westheider.
72 * Revision 1.8 2001/03/03 23:29:00 robertj
73 * Oops, fixed BSD version of video.
75 * Revision 1.7 2001/03/03 23:25:07 robertj
76 * Fixed use of video conversion function, returning bytes in destination frame.
78 * Revision 1.6 2001/03/03 06:13:01 robertj
79 * Major upgrade of video conversion and grabbing classes.
81 * Revision 1.5 2001/01/11 13:26:39 rogerh
82 * Add me in the Contributors section
84 * Revision 1.4 2001/01/05 18:12:30 rogerh
85 * First fully working version of video4bsd.
86 * Note that Start() and Stop() are not called, hence the first time hacks
87 * in GetFrameData(). Also video is always grabbed in interlaced mode
88 * so it does not look as good as it could.
90 * Revision 1.3 2001/01/05 14:52:36 rogerh
91 * More work on the FreeBSD video capture code
93 * Revision 1.2 2001/01/04 18:02:16 rogerh
94 * remove some old parts refering to linux
96 * Revision 1.1 2001/01/04 18:00:43 rogerh
97 * Start to add support for video capture using on FreeBSD/NetBSD and OpenBSD
98 * using the Meteor API (used by the Matrox Meteor and the bktr driver for
99 * Bt848/Bt878 TV Tuner Cards). This is incomplete but it does compile.
102 #pragma implementation "videoio.h"
105 #include <ptlib/videoio.h>
106 #include <ptlib/vfakeio.h>
107 #include <ptlib/vconvert.h>
109 #include <sys/mman.h>
112 ///////////////////////////////////////////////////////////////////////////////
115 PVideoInputDevice::PVideoInputDevice()
122 BOOL
PVideoInputDevice::Open(const PString
& devName
, BOOL startImmediate
)
126 deviceName
= devName
;
127 videoFd
= ::open((const char *)devName
, O_RDONLY
);
133 // fill in a device capabilities structure
134 videoCapability
.minheight
= 32;
135 videoCapability
.minwidth
= 32;
136 videoCapability
.maxheight
= 768;
137 videoCapability
.maxwidth
= 576;
138 videoCapability
.channels
= 5;
140 // set height and width
141 frameHeight
= videoCapability
.maxheight
;
142 frameWidth
= videoCapability
.maxwidth
;
144 // select the specified input
145 if (!SetChannel(channelNumber
)) {
151 // select the video format (eg PAL, NTSC)
152 if (!SetVideoFormat(videoFormat
)) {
158 // select the colpur format (eg YUV420, or RGB)
159 if (!SetColourFormat(colourFormat
)) {
165 // select the image size
166 if (!SetFrameSize(frameWidth
, frameHeight
)) {
176 BOOL
PVideoInputDevice::IsOpen()
182 BOOL
PVideoInputDevice::Close()
195 BOOL
PVideoInputDevice::Start()
201 BOOL
PVideoInputDevice::Stop()
207 BOOL
PVideoInputDevice::IsCapturing()
213 BOOL
PVideoInputDevice::SetVideoFormat(VideoFormat newFormat
)
215 if (!PVideoDevice::SetVideoFormat(newFormat
))
218 // set channel information
219 static int fmt
[4] = { METEOR_FMT_PAL
, METEOR_FMT_NTSC
,
220 METEOR_FMT_SECAM
, METEOR_FMT_AUTOMODE
};
221 int format
= fmt
[newFormat
];
223 // set the information
224 if (::ioctl(videoFd
, METEORSFMT
, &format
) >= 0)
227 // setting the format failed. Fall back trying other standard formats
229 if (newFormat
!= Auto
)
232 if (SetVideoFormat(PAL
))
234 if (SetVideoFormat(NTSC
))
236 if (SetVideoFormat(SECAM
))
243 int PVideoInputDevice::GetNumChannels()
245 return videoCapability
.channels
;
249 BOOL
PVideoInputDevice::SetChannel(int newChannel
)
251 if (!PVideoDevice::SetChannel(newChannel
))
254 // set channel information
255 static int chnl
[5] = { METEOR_INPUT_DEV0
, METEOR_INPUT_DEV1
,
256 METEOR_INPUT_DEV2
, METEOR_INPUT_DEV3
,
257 METEOR_INPUT_DEV_SVIDEO
};
258 int channel
= chnl
[newChannel
];
260 // set the information
261 if (::ioctl(videoFd
, METEORSINPUT
, &channel
) < 0)
268 BOOL
PVideoInputDevice::SetColourFormat(const PString
& newFormat
)
270 if (!PVideoDevice::SetColourFormat(newFormat
))
275 frameBytes
= CalculateFrameBytes(frameWidth
, frameHeight
, colourFormat
);
282 BOOL
PVideoInputDevice::SetFrameRate(unsigned rate
)
284 if (!PVideoDevice::SetFrameRate(rate
))
291 BOOL
PVideoInputDevice::GetFrameSizeLimits(unsigned & minWidth
,
292 unsigned & minHeight
,
294 unsigned & maxHeight
)
299 minWidth
= videoCapability
.minwidth
;
300 minHeight
= videoCapability
.minheight
;
301 maxWidth
= videoCapability
.maxwidth
;
302 maxHeight
= videoCapability
.maxheight
;
308 BOOL
PVideoInputDevice::SetFrameSize(unsigned width
, unsigned height
)
310 if (!PVideoDevice::SetFrameSize(width
, height
))
315 frameBytes
= CalculateFrameBytes(frameWidth
, frameHeight
, colourFormat
);
321 PINDEX
PVideoInputDevice::GetMaxFrameBytes()
327 BOOL
PVideoInputDevice::GetFrameData(BYTE
* buffer
, PINDEX
* bytesReturned
)
330 frameTimeError
+= msBetweenFrames
;
333 if ( !GetFrameDataNoDelay(buffer
, bytesReturned
))
336 PTimeInterval delay
= now
- previousFrameTime
;
337 frameTimeError
-= (int)delay
.GetMilliSeconds();
338 previousFrameTime
= now
;
339 } while(frameTimeError
> 0) ;
343 return GetFrameDataNoDelay(buffer
,bytesReturned
);
347 BOOL
PVideoInputDevice::GetFrameDataNoDelay(BYTE
* buffer
, PINDEX
* bytesReturned
)
350 // Hack time. It seems that the Start() and Stop() functions are not
351 // actually called, so we will have to initialise the frame grabber
352 // here on the first pass through this GetFrameData() function
356 struct meteor_geomet geo
;
357 geo
.rows
= frameHeight
;
358 geo
.columns
= frameWidth
;
360 geo
.oformat
= METEOR_GEO_YUV_422
| METEOR_GEO_YUV_12
;
362 // Grab even field (instead of interlaced frames) where possible to stop
363 // jagged interlacing artifacts. NTSC is 640x480, PAL/SECAM is 768x576.
364 if ( ((PVideoDevice::GetVideoFormat() == PAL
) && (frameHeight
<= 288))
365 || ((PVideoDevice::GetVideoFormat() == SECAM
) && (frameHeight
<= 288))
366 || ((PVideoDevice::GetVideoFormat() == NTSC
) && (frameHeight
<= 240)) ){
367 geo
.oformat
|= METEOR_GEO_EVEN_ONLY
;
370 // set the new geometry
371 if (ioctl(videoFd
, METEORSETGEO
, &geo
) < 0) {
375 mmap_size
= frameBytes
;
376 videoBuffer
= (BYTE
*)::mmap(0, mmap_size
, PROT_READ
, 0, videoFd
, 0);
377 if (videoBuffer
< 0) {
383 // put the grabber into continuous capture mode
384 int mode
= METEOR_CAP_CONTINOUS
;
385 if (ioctl(videoFd
, METEORCAPTUR
, &mode
) < 0 ) {
391 // Copy a snapshot of the image from the mmap buffer
392 // Really there should be some synchronisation here to avoid tearing
393 // in the image, but we will worry about that later
395 if (converter
!= NULL
)
396 return converter
->Convert(videoBuffer
, buffer
, bytesReturned
);
398 memcpy(buffer
, videoBuffer
, frameBytes
);
400 if (bytesReturned
!= NULL
)
401 *bytesReturned
= frameBytes
;
408 void PVideoInputDevice::ClearMapping()
412 // better stop grabbing first
413 // Really this should be in the Stop() function, but that is
414 // not actually called anywhere.
416 int mode
= METEOR_CAP_STOP_CONT
;
417 ioctl(videoFd
, METEORCAPTUR
, &mode
);
419 if (videoBuffer
!= NULL
)
420 ::munmap(videoBuffer
, mmap_size
);
427 BOOL
PVideoInputDevice::VerifyHardwareFrameSize(unsigned width
,
430 // Assume the size is valid
435 int PVideoInputDevice::GetBrightness()
441 if (::ioctl(videoFd
, METEORGBRIG
, &data
) < 0)
443 frameBrightness
= (data
<< 8);
445 return frameBrightness
;
448 int PVideoInputDevice::GetContrast()
454 if (::ioctl(videoFd
, METEORGCONT
, &data
) < 0)
456 frameContrast
= (data
<< 8);
458 return frameContrast
;
461 int PVideoInputDevice::GetHue()
467 if (::ioctl(videoFd
, METEORGHUE
, &data
) < 0)
469 frameHue
= ((data
+ 128) << 8);
474 BOOL
PVideoInputDevice::SetBrightness(unsigned newBrightness
)
479 unsigned char data
= (newBrightness
>> 8); // rescale for the ioctl
480 if (::ioctl(videoFd
, METEORSBRIG
, &data
) < 0)
483 frameBrightness
=newBrightness
;
487 BOOL
PVideoInputDevice::SetContrast(unsigned newContrast
)
492 unsigned char data
= (newContrast
>> 8); // rescale for the ioctl
493 if (::ioctl(videoFd
, METEORSCONT
, &data
) < 0)
496 frameContrast
= newContrast
;
500 BOOL
PVideoInputDevice::SetHue(unsigned newHue
)
505 char data
= (newHue
>> 8) - 128; // ioctl takes a signed char
506 if (::ioctl(videoFd
, METEORSHUE
, &data
) < 0)
513 BOOL
PVideoInputDevice::GetParameters (int *whiteness
, int *brightness
,
514 int *colour
, int *contrast
, int *hue
)
522 if (::ioctl(videoFd
, METEORGBRIG
, &data
) < 0)
524 *brightness
= (data
<< 8);
526 if (::ioctl(videoFd
, METEORGCONT
, &data
) < 0)
528 *contrast
= (data
<< 8);
530 if (::ioctl(videoFd
, METEORGHUE
, &signed_data
) < 0)
532 *hue
= ((data
+ 128) << 8);
534 // The bktr driver does not have colour or whiteness ioctls
535 // so set them to the current global values
536 *colour
= frameColour
;
537 *whiteness
= frameWhiteness
;
539 // update the global settings
540 frameBrightness
= *brightness
;
541 frameContrast
= *contrast
;
547 BOOL
PVideoInputDevice::TestAllFormats()
551 // End Of File ///////////////////////////////////////////////////////////////