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.1 2003/12/12 04:38:17 rogerhardiman
28 * Add plugin for the BSD Video Capture API (also called the meteor API)
29 * for FreeBSD, NetBSD and OpenBSD
31 * Revision 1.20 2002/10/28 19:12:45 rogerh
32 * Add svideo input support for Lars Eggert <larse@isi.edu>
34 * Revision 1.19 2002/04/10 08:40:36 rogerh
35 * Simplify the SetVideoChannelFormat() code. Use the implementation in the
38 * Revision 1.18 2002/04/05 06:41:54 rogerh
39 * Apply video changes from Damien Sandras <dsandras@seconix.com>.
40 * The Video Channel and Format are no longer set in Open(). Instead
41 * call the new SetVideoChannelFormat() method. This makes video capture
42 * and GnomeMeeting more stable with certain Linux video capture devices.
44 * Revision 1.17 2002/01/08 17:16:13 rogerh
45 * Add code to grab Even fields (instead of interlaced frames) whenever
46 * possible. This improves the image quality.
49 * Revision 1.16 2001/12/05 14:45:20 rogerh
50 * Implement GetFrameData and GetFrameDataNoDelay
52 * Revision 1.15 2001/12/05 14:32:48 rogerh
53 * Add GetParemters function
55 * Revision 1.14 2001/08/06 06:56:16 rogerh
56 * Add scaling for new methods to match BSD's Meteor API
58 * Revision 1.13 2001/08/06 06:19:33 rogerh
59 * Implement Brightness, Contract and Hue methods.
61 * Revision 1.12 2001/03/26 16:02:01 rogerh
62 * Add dummy function for VerifyHardwareFrameSize
64 * Revision 1.11 2001/03/08 03:59:13 robertj
65 * Fixed previous change, needed to allow for -1 as chammelNumber in Open().
67 * Revision 1.10 2001/03/08 02:23:17 robertj
68 * Added improved defaulting of video formats so Open() does not fail.
70 * Revision 1.9 2001/03/07 00:10:05 robertj
71 * Improved the device list, uses /proc, thanks Thorsten Westheider.
73 * Revision 1.8 2001/03/03 23:29:00 robertj
74 * Oops, fixed BSD version of video.
76 * Revision 1.7 2001/03/03 23:25:07 robertj
77 * Fixed use of video conversion function, returning bytes in destination frame.
79 * Revision 1.6 2001/03/03 06:13:01 robertj
80 * Major upgrade of video conversion and grabbing classes.
82 * Revision 1.5 2001/01/11 13:26:39 rogerh
83 * Add me in the Contributors section
85 * Revision 1.4 2001/01/05 18:12:30 rogerh
86 * First fully working version of video4bsd.
87 * Note that Start() and Stop() are not called, hence the first time hacks
88 * in GetFrameData(). Also video is always grabbed in interlaced mode
89 * so it does not look as good as it could.
91 * Revision 1.3 2001/01/05 14:52:36 rogerh
92 * More work on the FreeBSD video capture code
94 * Revision 1.2 2001/01/04 18:02:16 rogerh
95 * remove some old parts refering to linux
97 * Revision 1.1 2001/01/04 18:00:43 rogerh
98 * Start to add support for video capture using on FreeBSD/NetBSD and OpenBSD
99 * using the Meteor API (used by the Matrox Meteor and the bktr driver for
100 * Bt848/Bt878 TV Tuner Cards). This is incomplete but it does compile.
103 #pragma implementation "vidinput_bsd.h"
105 #include "vidinput_bsd.h"
106 #include <sys/mman.h>
108 PCREATE_VIDINPUT_PLUGIN(BSDCAP
, PVideoInputBSDDevice
);
110 ///////////////////////////////////////////////////////////////////////////////
111 // PVideoInputBSDDevice
113 PVideoInputBSDDevice::PVideoInputBSDDevice()
119 PVideoInputBSDDevice::~PVideoInputBSDDevice()
124 BOOL
PVideoInputBSDDevice::Open(const PString
& devName
, BOOL startImmediate
)
128 deviceName
= devName
;
129 videoFd
= ::open((const char *)devName
, O_RDONLY
);
135 // fill in a device capabilities structure
136 videoCapability
.minheight
= 32;
137 videoCapability
.minwidth
= 32;
138 videoCapability
.maxheight
= 768;
139 videoCapability
.maxwidth
= 576;
140 videoCapability
.channels
= 5;
142 // set height and width
143 frameHeight
= videoCapability
.maxheight
;
144 frameWidth
= videoCapability
.maxwidth
;
146 // select the specified input
147 if (!SetChannel(channelNumber
)) {
153 // select the video format (eg PAL, NTSC)
154 if (!SetVideoFormat(videoFormat
)) {
160 // select the colpur format (eg YUV420, or RGB)
161 if (!SetColourFormat(colourFormat
)) {
167 // select the image size
168 if (!SetFrameSize(frameWidth
, frameHeight
)) {
178 BOOL
PVideoInputBSDDevice::IsOpen()
184 BOOL
PVideoInputBSDDevice::Close()
197 BOOL
PVideoInputBSDDevice::Start()
203 BOOL
PVideoInputBSDDevice::Stop()
209 BOOL
PVideoInputBSDDevice::IsCapturing()
215 PStringList
PVideoInputBSDDevice::GetInputDeviceNames()
219 list
.AppendString("/dev/bktr0");
220 list
.AppendString("/dev/bktr1");
221 list
.AppendString("/dev/meteor0");
222 list
.AppendString("/dev/meteor1");
228 BOOL
PVideoInputBSDDevice::SetVideoFormat(VideoFormat newFormat
)
230 if (!PVideoDevice::SetVideoFormat(newFormat
))
233 // set channel information
234 static int fmt
[4] = { METEOR_FMT_PAL
, METEOR_FMT_NTSC
,
235 METEOR_FMT_SECAM
, METEOR_FMT_AUTOMODE
};
236 int format
= fmt
[newFormat
];
238 // set the information
239 if (::ioctl(videoFd
, METEORSFMT
, &format
) >= 0)
242 // setting the format failed. Fall back trying other standard formats
244 if (newFormat
!= Auto
)
247 if (SetVideoFormat(PAL
))
249 if (SetVideoFormat(NTSC
))
251 if (SetVideoFormat(SECAM
))
258 int PVideoInputBSDDevice::GetNumChannels()
260 return videoCapability
.channels
;
264 BOOL
PVideoInputBSDDevice::SetChannel(int newChannel
)
266 if (!PVideoDevice::SetChannel(newChannel
))
269 // set channel information
270 static int chnl
[5] = { METEOR_INPUT_DEV0
, METEOR_INPUT_DEV1
,
271 METEOR_INPUT_DEV2
, METEOR_INPUT_DEV3
,
272 METEOR_INPUT_DEV_SVIDEO
};
273 int channel
= chnl
[newChannel
];
275 // set the information
276 if (::ioctl(videoFd
, METEORSINPUT
, &channel
) < 0)
283 BOOL
PVideoInputBSDDevice::SetColourFormat(const PString
& newFormat
)
285 if (!PVideoDevice::SetColourFormat(newFormat
))
290 frameBytes
= CalculateFrameBytes(frameWidth
, frameHeight
, colourFormat
);
297 BOOL
PVideoInputBSDDevice::SetFrameRate(unsigned rate
)
299 if (!PVideoDevice::SetFrameRate(rate
))
306 BOOL
PVideoInputBSDDevice::GetFrameSizeLimits(unsigned & minWidth
,
307 unsigned & minHeight
,
309 unsigned & maxHeight
)
314 minWidth
= videoCapability
.minwidth
;
315 minHeight
= videoCapability
.minheight
;
316 maxWidth
= videoCapability
.maxwidth
;
317 maxHeight
= videoCapability
.maxheight
;
323 BOOL
PVideoInputBSDDevice::SetFrameSize(unsigned width
, unsigned height
)
325 if (!PVideoDevice::SetFrameSize(width
, height
))
330 frameBytes
= CalculateFrameBytes(frameWidth
, frameHeight
, colourFormat
);
336 PINDEX
PVideoInputBSDDevice::GetMaxFrameBytes()
342 BOOL
PVideoInputBSDDevice::GetFrameData(BYTE
* buffer
, PINDEX
* bytesReturned
)
345 frameTimeError
+= msBetweenFrames
;
348 if ( !GetFrameDataNoDelay(buffer
, bytesReturned
))
351 PTimeInterval delay
= now
- previousFrameTime
;
352 frameTimeError
-= (int)delay
.GetMilliSeconds();
353 previousFrameTime
= now
;
354 } while(frameTimeError
> 0) ;
358 return GetFrameDataNoDelay(buffer
,bytesReturned
);
362 BOOL
PVideoInputBSDDevice::GetFrameDataNoDelay(BYTE
* buffer
, PINDEX
* bytesReturned
)
365 // Hack time. It seems that the Start() and Stop() functions are not
366 // actually called, so we will have to initialise the frame grabber
367 // here on the first pass through this GetFrameData() function
371 struct meteor_geomet geo
;
372 geo
.rows
= frameHeight
;
373 geo
.columns
= frameWidth
;
375 geo
.oformat
= METEOR_GEO_YUV_422
| METEOR_GEO_YUV_12
;
377 // Grab even field (instead of interlaced frames) where possible to stop
378 // jagged interlacing artifacts. NTSC is 640x480, PAL/SECAM is 768x576.
379 if ( ((PVideoDevice::GetVideoFormat() == PAL
) && (frameHeight
<= 288))
380 || ((PVideoDevice::GetVideoFormat() == SECAM
) && (frameHeight
<= 288))
381 || ((PVideoDevice::GetVideoFormat() == NTSC
) && (frameHeight
<= 240)) ){
382 geo
.oformat
|= METEOR_GEO_EVEN_ONLY
;
385 // set the new geometry
386 if (ioctl(videoFd
, METEORSETGEO
, &geo
) < 0) {
390 mmap_size
= frameBytes
;
391 videoBuffer
= (BYTE
*)::mmap(0, mmap_size
, PROT_READ
, 0, videoFd
, 0);
392 if (videoBuffer
< 0) {
398 // put the grabber into continuous capture mode
399 int mode
= METEOR_CAP_CONTINOUS
;
400 if (ioctl(videoFd
, METEORCAPTUR
, &mode
) < 0 ) {
406 // Copy a snapshot of the image from the mmap buffer
407 // Really there should be some synchronisation here to avoid tearing
408 // in the image, but we will worry about that later
410 if (converter
!= NULL
)
411 return converter
->Convert(videoBuffer
, buffer
, bytesReturned
);
413 memcpy(buffer
, videoBuffer
, frameBytes
);
415 if (bytesReturned
!= NULL
)
416 *bytesReturned
= frameBytes
;
423 void PVideoInputBSDDevice::ClearMapping()
427 // better stop grabbing first
428 // Really this should be in the Stop() function, but that is
429 // not actually called anywhere.
431 int mode
= METEOR_CAP_STOP_CONT
;
432 ioctl(videoFd
, METEORCAPTUR
, &mode
);
434 if (videoBuffer
!= NULL
)
435 ::munmap(videoBuffer
, mmap_size
);
442 BOOL
PVideoInputBSDDevice::VerifyHardwareFrameSize(unsigned width
,
445 // Assume the size is valid
450 int PVideoInputBSDDevice::GetBrightness()
456 if (::ioctl(videoFd
, METEORGBRIG
, &data
) < 0)
458 frameBrightness
= (data
<< 8);
460 return frameBrightness
;
463 int PVideoInputBSDDevice::GetContrast()
469 if (::ioctl(videoFd
, METEORGCONT
, &data
) < 0)
471 frameContrast
= (data
<< 8);
473 return frameContrast
;
476 int PVideoInputBSDDevice::GetHue()
482 if (::ioctl(videoFd
, METEORGHUE
, &data
) < 0)
484 frameHue
= ((data
+ 128) << 8);
489 BOOL
PVideoInputBSDDevice::SetBrightness(unsigned newBrightness
)
494 unsigned char data
= (newBrightness
>> 8); // rescale for the ioctl
495 if (::ioctl(videoFd
, METEORSBRIG
, &data
) < 0)
498 frameBrightness
=newBrightness
;
502 BOOL
PVideoInputBSDDevice::SetContrast(unsigned newContrast
)
507 unsigned char data
= (newContrast
>> 8); // rescale for the ioctl
508 if (::ioctl(videoFd
, METEORSCONT
, &data
) < 0)
511 frameContrast
= newContrast
;
515 BOOL
PVideoInputBSDDevice::SetHue(unsigned newHue
)
520 char data
= (newHue
>> 8) - 128; // ioctl takes a signed char
521 if (::ioctl(videoFd
, METEORSHUE
, &data
) < 0)
528 BOOL
PVideoInputBSDDevice::GetParameters (int *whiteness
, int *brightness
,
529 int *colour
, int *contrast
, int *hue
)
537 if (::ioctl(videoFd
, METEORGBRIG
, &data
) < 0)
539 *brightness
= (data
<< 8);
541 if (::ioctl(videoFd
, METEORGCONT
, &data
) < 0)
543 *contrast
= (data
<< 8);
545 if (::ioctl(videoFd
, METEORGHUE
, &signed_data
) < 0)
547 *hue
= ((data
+ 128) << 8);
549 // The bktr driver does not have colour or whiteness ioctls
550 // so set them to the current global values
551 *colour
= frameColour
;
552 *whiteness
= frameWhiteness
;
554 // update the global settings
555 frameBrightness
= *brightness
;
556 frameContrast
= *contrast
;
562 BOOL
PVideoInputBSDDevice::TestAllFormats()
566 // End Of File ///////////////////////////////////////////////////////////////