Removed debugging (oops!)
[pwlib.git] / plugins / vidinput_bsd / vidinput_bsd.cxx
blob23183471e757bb2766739687ddc547207c3345c6
1 /*
2 * video4bsd.cxx
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
18 * under the License.
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>
26 * $Log$
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
36 * ancestor class.
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.
47 * Add TestAllFormats
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()
115 videoFd = -1;
116 canMap = -1;
119 PVideoInputBSDDevice::~PVideoInputBSDDevice()
121 Close();
124 BOOL PVideoInputBSDDevice::Open(const PString & devName, BOOL startImmediate)
126 Close();
128 deviceName = devName;
129 videoFd = ::open((const char *)devName, O_RDONLY);
130 if (videoFd < 0) {
131 videoFd = -1;
132 return FALSE;
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)) {
148 ::close (videoFd);
149 videoFd = -1;
150 return FALSE;
153 // select the video format (eg PAL, NTSC)
154 if (!SetVideoFormat(videoFormat)) {
155 ::close (videoFd);
156 videoFd = -1;
157 return FALSE;
160 // select the colpur format (eg YUV420, or RGB)
161 if (!SetColourFormat(colourFormat)) {
162 ::close (videoFd);
163 videoFd = -1;
164 return FALSE;
167 // select the image size
168 if (!SetFrameSize(frameWidth, frameHeight)) {
169 ::close (videoFd);
170 videoFd = -1;
171 return FALSE;
174 return TRUE;
178 BOOL PVideoInputBSDDevice::IsOpen()
180 return videoFd >= 0;
184 BOOL PVideoInputBSDDevice::Close()
186 if (!IsOpen())
187 return FALSE;
189 ClearMapping();
190 ::close(videoFd);
191 videoFd = -1;
192 canMap = -1;
194 return TRUE;
197 BOOL PVideoInputBSDDevice::Start()
199 return TRUE;
203 BOOL PVideoInputBSDDevice::Stop()
205 return TRUE;
209 BOOL PVideoInputBSDDevice::IsCapturing()
211 return IsOpen();
215 PStringList PVideoInputBSDDevice::GetInputDeviceNames()
217 PStringList list;
219 list.AppendString("/dev/bktr0");
220 list.AppendString("/dev/bktr1");
221 list.AppendString("/dev/meteor0");
222 list.AppendString("/dev/meteor1");
224 return list;
228 BOOL PVideoInputBSDDevice::SetVideoFormat(VideoFormat newFormat)
230 if (!PVideoDevice::SetVideoFormat(newFormat))
231 return FALSE;
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)
240 return TRUE;
242 // setting the format failed. Fall back trying other standard formats
244 if (newFormat != Auto)
245 return FALSE;
247 if (SetVideoFormat(PAL))
248 return TRUE;
249 if (SetVideoFormat(NTSC))
250 return TRUE;
251 if (SetVideoFormat(SECAM))
252 return TRUE;
254 return FALSE;
258 int PVideoInputBSDDevice::GetNumChannels()
260 return videoCapability.channels;
264 BOOL PVideoInputBSDDevice::SetChannel(int newChannel)
266 if (!PVideoDevice::SetChannel(newChannel))
267 return FALSE;
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)
277 return FALSE;
279 return TRUE;
283 BOOL PVideoInputBSDDevice::SetColourFormat(const PString & newFormat)
285 if (!PVideoDevice::SetColourFormat(newFormat))
286 return FALSE;
288 ClearMapping();
290 frameBytes = CalculateFrameBytes(frameWidth, frameHeight, colourFormat);
292 return TRUE;
297 BOOL PVideoInputBSDDevice::SetFrameRate(unsigned rate)
299 if (!PVideoDevice::SetFrameRate(rate))
300 return FALSE;
302 return TRUE;
306 BOOL PVideoInputBSDDevice::GetFrameSizeLimits(unsigned & minWidth,
307 unsigned & minHeight,
308 unsigned & maxWidth,
309 unsigned & maxHeight)
311 if (!IsOpen())
312 return FALSE;
314 minWidth = videoCapability.minwidth;
315 minHeight = videoCapability.minheight;
316 maxWidth = videoCapability.maxwidth;
317 maxHeight = videoCapability.maxheight;
318 return TRUE;
323 BOOL PVideoInputBSDDevice::SetFrameSize(unsigned width, unsigned height)
325 if (!PVideoDevice::SetFrameSize(width, height))
326 return FALSE;
328 ClearMapping();
330 frameBytes = CalculateFrameBytes(frameWidth, frameHeight, colourFormat);
332 return TRUE;
336 PINDEX PVideoInputBSDDevice::GetMaxFrameBytes()
338 return frameBytes;
342 BOOL PVideoInputBSDDevice::GetFrameData(BYTE * buffer, PINDEX * bytesReturned)
344 if(frameRate>0) {
345 frameTimeError += msBetweenFrames;
347 do {
348 if ( !GetFrameDataNoDelay(buffer, bytesReturned))
349 return FALSE;
350 PTime now;
351 PTimeInterval delay = now - previousFrameTime;
352 frameTimeError -= (int)delay.GetMilliSeconds();
353 previousFrameTime = now;
354 } while(frameTimeError > 0) ;
356 return TRUE;
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
369 if (canMap < 0) {
371 struct meteor_geomet geo;
372 geo.rows = frameHeight;
373 geo.columns = frameWidth;
374 geo.frames = 1;
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) {
387 return FALSE;
390 mmap_size = frameBytes;
391 videoBuffer = (BYTE *)::mmap(0, mmap_size, PROT_READ, 0, videoFd, 0);
392 if (videoBuffer < 0) {
393 return FALSE;
394 } else {
395 canMap = 1;
398 // put the grabber into continuous capture mode
399 int mode = METEOR_CAP_CONTINOUS;
400 if (ioctl(videoFd, METEORCAPTUR, &mode) < 0 ) {
401 return FALSE;
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;
419 return TRUE;
423 void PVideoInputBSDDevice::ClearMapping()
425 if (canMap == 1) {
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);
437 canMap = -1;
438 videoBuffer = NULL;
442 BOOL PVideoInputBSDDevice::VerifyHardwareFrameSize(unsigned width,
443 unsigned height)
445 // Assume the size is valid
446 return TRUE;
450 int PVideoInputBSDDevice::GetBrightness()
452 if (!IsOpen())
453 return -1;
455 unsigned char data;
456 if (::ioctl(videoFd, METEORGBRIG, &data) < 0)
457 return -1;
458 frameBrightness = (data << 8);
460 return frameBrightness;
463 int PVideoInputBSDDevice::GetContrast()
465 if (!IsOpen())
466 return -1;
468 unsigned char data;
469 if (::ioctl(videoFd, METEORGCONT, &data) < 0)
470 return -1;
471 frameContrast = (data << 8);
473 return frameContrast;
476 int PVideoInputBSDDevice::GetHue()
478 if (!IsOpen())
479 return -1;
481 char data;
482 if (::ioctl(videoFd, METEORGHUE, &data) < 0)
483 return -1;
484 frameHue = ((data + 128) << 8);
486 return frameHue;
489 BOOL PVideoInputBSDDevice::SetBrightness(unsigned newBrightness)
491 if (!IsOpen())
492 return FALSE;
494 unsigned char data = (newBrightness >> 8); // rescale for the ioctl
495 if (::ioctl(videoFd, METEORSBRIG, &data) < 0)
496 return FALSE;
498 frameBrightness=newBrightness;
499 return TRUE;
502 BOOL PVideoInputBSDDevice::SetContrast(unsigned newContrast)
504 if (!IsOpen())
505 return FALSE;
507 unsigned char data = (newContrast >> 8); // rescale for the ioctl
508 if (::ioctl(videoFd, METEORSCONT, &data) < 0)
509 return FALSE;
511 frameContrast = newContrast;
512 return TRUE;
515 BOOL PVideoInputBSDDevice::SetHue(unsigned newHue)
517 if (!IsOpen())
518 return FALSE;
520 char data = (newHue >> 8) - 128; // ioctl takes a signed char
521 if (::ioctl(videoFd, METEORSHUE, &data) < 0)
522 return FALSE;
524 frameHue=newHue;
525 return TRUE;
528 BOOL PVideoInputBSDDevice::GetParameters (int *whiteness, int *brightness,
529 int *colour, int *contrast, int *hue)
531 if (!IsOpen())
532 return FALSE;
534 unsigned char data;
535 char signed_data;
537 if (::ioctl(videoFd, METEORGBRIG, &data) < 0)
538 return -1;
539 *brightness = (data << 8);
541 if (::ioctl(videoFd, METEORGCONT, &data) < 0)
542 return -1;
543 *contrast = (data << 8);
545 if (::ioctl(videoFd, METEORGHUE, &signed_data) < 0)
546 return -1;
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;
557 frameHue = *hue;
559 return TRUE;
562 BOOL PVideoInputBSDDevice::TestAllFormats()
564 return TRUE;
566 // End Of File ///////////////////////////////////////////////////////////////