2 * README for IEEE 1394 digital camera support routine in PWLib
3 * ------------------------------------------------------------
5 * PWLib now contains preliminary support for the IEEE 1394 digital
11 * There are two kind of the specifications of IEEE 1394 digital video
12 * cameras, one is called "digital camera" and another is "AV/C camera".
13 * A digital camera sends uncompressed video data while an AV/C camera
14 * sends compressed data. Currently PWLib only supports digital
15 * cameras. We can find a list of supported digital cameras by the Linux
17 * http://www.tele.ucl.ac.be/PEOPLE/DOUXCHAMPS/ieee1394/cameras/
19 * AV/C cameras seem able to be used for video phone. You are welcome to
20 * write supporting codes for AV/C cameras!
23 * Installation and Use:
25 * To enable 1394 camera support, you have to define the "TRY_1394DC"
26 * shell environment variable at compilation time of PWLib, OpenH323, and
27 * ohphone. To select your 1394 camera for video input device instead of
28 * usual Video4Linux devices, specify "/dev/raw1394" or "/dev/video1394"
29 * as the filename of video input device. For example "ohphone
30 * --videoinput /dev/raw1394" should use your 1394 camera as video input.
32 * "/dev/video1394" uses faster DMA transfer for video input.
34 * If you use DEVFS, the filename for DMA transfer may be /dev/video1394/0.
36 * Requirements for Installation:
38 * You needs the following softwares to compile the 1394 camera support
41 * - libdc1394 0.9.0 or later.
42 * - Linux 2.4.19 or later, which is required by the above version of
44 * - libraw1394 0.9.0 or later
46 * You cannot compile it with older versions of libdc1394.
50 * If this module does not work for you, please verify the following
51 * items before sending email:
53 * 1) Can you view image of your camera by other programs? A sample
54 * program called "grab_gray_image" is included in the example
55 * directory of libdc1394. Please run grab_gray_image and see what
56 * happens. You can also use Coriander instead.
57 * (http://www.tele.ucl.ac.be/PEOPLE/DOUXCHAMPS/ieee1394/coriander/).
58 * 2) If you have make sure other programs can use the camera, but
59 * this module still does not work, please run the debbuging version
60 * of ohphone with option "-tttt -o log.txt". Examine the file "log.txt"
61 * and you may see what is wrong.
65 * They should be send to Ryutaroh Matsumoto <ryutaroh@rmatsumoto.org>.
69 * R. Matsumoto thanks Dr. Derek Smithies for his kind support for making
73 * Technical Notes for Programmers
74 * ------------------------------------------------------------
77 * This module was tested against:
84 * Irez StealthFire Camera (http://www.irez.com)
85 * OrangeMicro iBot Camera (http://www.orangemicro.com)
89 * This module has been tested against the ohphone and GnomeMeeting
90 * video phone programs. They use 352x288 and 176x144 resolutions in
91 * YUV420P color format. So this module only supports these
92 * resolutions and YUV420P.
94 * 1394 Digital Cameras has many resolutions and color formats. Among
95 * them, this module uses:
96 * 160x120 YUV(4:4:4) for 176x144 PTlib resolution, and
97 * 320x240 YUV(4:2:2) for 352x288 PTlib resolution.
98 * The bus speed is always set to P_DC1394_DEFAULT_SPEED (400 Mbps).
99 * If transfer at P_DC1394_DEFAULT_SPEED is not supported by your
100 * camera, this module does not capture images from yours. In such
101 * a case please set P_DC1394_DEFAULT_SPEED to appropriate value.
103 * Conversion routines from above formats to YUV420P were added to
104 * src/ptlib/common/vconvert.cxx
107 * This module does not implement GetBrightness() etc. 1394 cameras
108 * can do both automatic control and manual control of brightness
109 * etc., and they are usually set to automatic
110 * control. Get/SetBrightness() etc. cannot access manual/automatic
111 * selection. So we cannot implement an interface that can fully
112 * control all of 1394 camera features. I decided not to implement
113 * controlling interface at all. Those features can be controlled by
114 * Coriander program even when ohphone or GnomeMeeting is being used.
115 * Please use Coriander.
117 * PVideoInput1394DcDevice does not allow creation of two or more instances.
119 * The bus speed is always set to P_DC1394_DEFAULT_SPEED (400 Mbps).
120 * If transfer at P_DC1394_DEFAULT_SPEED is not supported by your
121 * camera, this module does not capture images from yours. In such
122 * a case please set P_DC1394_DEFAULT_SPEED to appropriate value.
125 * Copyright (c) 2002 Ryutaroh Matsumoto <ryutaroh@rmatsumoto.org>
127 * The contents of this file are subject to the Mozilla Public License
128 * Version 1.0 (the "License"); you may not use this file except in
129 * compliance with the License. You may obtain a copy of the License at
130 * http://www.mozilla.org/MPL/
132 * Software distributed under the License is distributed on an "AS IS"
133 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
134 * the License for the specific language governing rights and limitations
140 * Revision 1.9 2003/03/17 07:53:04 robertj
141 * Removed canCaptureVideo variable as this is really a virtual function to
142 * distinguish PVideoOutputDevice from PVideoInputDevice, it is not dynamic.
144 * Revision 1.8 2002/08/21 00:00:31 dereks
145 * Patches from Ryutaroh, to improve firewire (linux only) support. Many thanks.
147 * Revision 1.7 2002/05/30 22:49:35 dereks
148 * correct implementation of GetInputDeviceNames().
150 * Revision 1.6 2002/03/04 01:21:31 dereks
151 * Add frame rate support to Firewire camera. Thanks Ryutaroh Matsumoto.
153 * Revision 1.5 2002/02/28 19:44:03 dereks
154 * Add complete readme on Firewire usage. Thanks to Ryutaroh Matsumoto.
156 * Revision 1.4 2002/02/21 20:00:21 dereks
157 * Fix memory leak. Thanks Ryutaroh Matsumoto.
159 * Revision 1.3 2002/02/21 19:49:57 dereks
160 * Fix spelling mistake. Thanks Ryutaroh
162 * Revision 1.2 2002/02/20 20:27:28 dereks
163 * updates to previous checkin.
165 * Revision 1.1 2002/02/20 02:37:26 dereks
166 * Initial release of Firewire camera support for linux.
167 * Many thanks to Ryutaroh Matsumoto <ryutaroh@rmatsumoto.org>.
174 #pragma implementation "videoio1394dc.h"
177 #include <ptlib/videoio.h>
178 #include <ptlib/videoio1394dc.h>
179 #include <ptlib/vconvert.h>
180 #include <ptlib/file.h>
181 #include <sys/utsname.h>
183 #ifndef P_DC1394_DEFAULT_SPEED
184 #define P_DC1394_DEFAULT_SPEED SPEED_400
187 //#define ESTIMATE_CAPTURE_PERFORMANCE
189 #ifdef ESTIMATE_CAPTURE_PERFORMANCE
191 static PInt64 start_time
;
192 static int num_captured
;
196 ///////////////////////////////////////////////////////////////////////////////
199 PVideoInput1394DcDevice::PVideoInput1394DcDevice()
202 is_capturing
= FALSE
;
203 capturing_duration
= 10000; // arbitrary large value suffices
206 PVideoInput1394DcDevice::~PVideoInput1394DcDevice()
213 static int kernel_version_ok(void)
215 struct utsname utsbuf
;
216 unsigned major_ver
, minor_ver
, minorminor_ver
;
218 if (uname(&utsbuf
) == -1)
221 /* utsbuf.release looks like "2.4.19-pre8". */
222 if (sscanf(utsbuf
.release
, "%u.%u.%u", &major_ver
, &minor_ver
,
223 &minorminor_ver
) < 3)
224 return NG
; /* Should we return OK? */
228 else if (major_ver
<= 1)
233 else if (minor_ver
<= 3)
235 else if (minor_ver
== 4)
236 return minorminor_ver
>= 19;
237 else /* if (minor_ver == 5) */
238 return minorminor_ver
>= 9;
241 BOOL
PVideoInput1394DcDevice::Open(const PString
& devName
, BOOL startImmediate
)
243 if (!kernel_version_ok()) {
244 PTRACE(0, "The Linux kernel version is too old.");
249 PTRACE(0, "You cannot open PVideoInput1394DcDevice twice.");
253 if (devName
== "/dev/raw1394")
255 // Don't forget /dev/video1394/0
256 else if (strncmp(devName
, "/dev/video1394", 14) == 0)
259 PTRACE(0, "devName must be /dev/raw1394 or /dev/video1394");
263 // See if devName is accessible.
264 if (!PFile::Exists(devName
)) {
265 PTRACE(1, devName
<< " is not accessible.");
269 /*-----------------------------------------------------------------------
270 * Open ohci and asign handle to it
271 *-----------------------------------------------------------------------*/
272 handle
= dc1394_create_handle(0);
275 PTRACE(0, "Unable to aquire a raw1394 handle\n"
276 "did you insmod the drivers?\n");
280 /*-----------------------------------------------------------------------
281 * get the camera nodes and describe them as we find them
282 *-----------------------------------------------------------------------*/
283 int numNodes
= raw1394_get_nodecount(handle
);
284 camera_nodes
= dc1394_get_camera_nodes(handle
,&numCameras
,0);
287 PTRACE(0, "no cameras found :(\n");
288 dc1394_destroy_handle(handle
);
293 /*-----------------------------------------------------------------------
294 * to prevent the iso-transfer bug from raw1394 system, check if
295 * camera is highest node. For details see
296 * http://linux1394.sourceforge.net/faq.html#DCbusmgmt
298 * http://sourceforge.net/tracker/index.php?func=detail&aid=435107&group_id=8157&atid=108157
299 *-----------------------------------------------------------------------*/
300 for (int i
=0; i
<numCameras
; i
++) {
301 if( camera_nodes
[i
] == numNodes
-1) {
302 PTRACE(0,"Sorry, your camera is the highest numbered node\n"
303 "of the bus, and has therefore become the root node.\n"
304 "The root node is responsible for maintaining \n"
305 "the timing of isochronous transactions on the IEEE \n"
306 "1394 bus. However, if the root node is not cycle master \n"
307 "capable (it doesn't have to be), then isochronous \n"
308 "transactions will not work. The host controller card is \n"
309 "cycle master capable, however, most cameras are not.\n"
311 "The quick solution is to add the parameter \n"
312 "attempt_root=1 when loading the OHCI driver as a \n"
313 "module. So please do (as root):\n"
316 " insmod ohci1394 attempt_root=1\n"
318 "for more information see the FAQ at \n"
319 "http://linux1394.sourceforge.net/faq.html#DCbusmgmt\n"
321 dc1394_destroy_handle(handle
);
329 colourFormat
= "UYVY422";
330 desiredFrameHeight
= CIFHeight
;
331 desiredFrameWidth
= CIFWidth
;
332 desiredColourFormat
= "YUV420P";
333 capturing_duration
= 10000; // arbitrary large value suffices
334 deviceName
= devName
;
336 // select the specified input and video format
337 if (!SetChannel(channelNumber
) ||
338 !SetVideoFormat(videoFormat
)) {
339 PTRACE(1, "SetChannel() or SetVideoFormat() failed");
344 if (startImmediate
&& !Start()) {
348 PTRACE(3, "Successfully opended\n");
353 BOOL
PVideoInput1394DcDevice::IsOpen()
355 return handle
!= NULL
;
359 BOOL
PVideoInput1394DcDevice::Close()
364 dc1394_destroy_handle(handle
);
371 BOOL
PVideoInput1394DcDevice::Start()
374 if (!IsOpen()) return FALSE
;
375 if (is_capturing
) return TRUE
;
376 if (frameWidth
== 320 && frameHeight
== 240)
377 dc1394_mode
= MODE_320x240_YUV422
;
378 else if (frameWidth
== 160 && frameHeight
== 120)
379 dc1394_mode
= MODE_160x120_YUV444
;
381 PTRACE(1, "Frame size is neither 320x240 or 160x120" << frameWidth
<<
385 PTRACE(1, deviceName
<< " " << channelNumber
);
387 quadlet_t supported_framerates
;
388 if (dc1394_query_supported_framerates(handle
, camera_nodes
[channelNumber
],
389 FORMAT_VGA_NONCOMPRESSED
, dc1394_mode
,
390 &supported_framerates
) != DC1394_SUCCESS
) {
391 PTRACE(1, "dc1394_query_supported_framerates() failed.");
397 // supported_framerates seems always in the network byte order.
398 if (supported_framerates
& (1U << (31-5)))
399 framerate
= FRAMERATE_60
;
400 else if (supported_framerates
& (1U << (31-4)))
401 framerate
= FRAMERATE_30
;
402 else if (supported_framerates
& (1U << (31-3)))
403 framerate
= FRAMERATE_15
;
404 else if (supported_framerates
& (1U << (31-2)))
405 framerate
= FRAMERATE_7_5
;
406 else if (supported_framerates
& (1U << (31-1)))
407 framerate
= FRAMERATE_3_75
;
408 else if (supported_framerates
& (1U << (31-0)))
409 framerate
= FRAMERATE_1_875
;
411 PTRACE(1, "No supported frame rate??!!" << supported_framerates
);
415 // In order to compile the following line, you need libdc1394 0.9.0 or later.
416 if ((UseDMA
&&dc1394_dma_setup_capture(handle
,camera_nodes
[channelNumber
],
417 0, /* channel of IEEE 1394 */
418 FORMAT_VGA_NONCOMPRESSED
,
420 P_DC1394_DEFAULT_SPEED
,
421 framerate
, 4, 1, deviceName
,
422 &camera
)!=DC1394_SUCCESS
) ||
423 (!UseDMA
&& dc1394_setup_capture(handle
,camera_nodes
[channelNumber
],
424 0, /* channel of IEEE 1394 */
425 FORMAT_VGA_NONCOMPRESSED
,
427 P_DC1394_DEFAULT_SPEED
,
429 &camera
)!=DC1394_SUCCESS
))
431 PTRACE(0,"unable to setup camera-\n"
432 "check " __FILE__
" to make sure\n"
433 "that the video mode,framerate and format are\n"
434 "supported by your camera\n");
438 /*-----------------------------------------------------------------------
439 * have the camera start sending us data
440 *-----------------------------------------------------------------------*/
441 if (dc1394_start_iso_transmission(handle
,camera
.node
)
444 PTRACE(0, "unable to start camera iso transmission\n");
446 dc1394_dma_release_camera(handle
,&camera
);
448 dc1394_release_camera(handle
,&camera
);
452 #ifdef ESTIMATE_CAPTURE_PERFORMANCE
454 start_time
= now
.GetTimestamp();
461 BOOL
PVideoInput1394DcDevice::Stop()
464 dc1394_stop_iso_transmission(handle
,camera
.node
);
466 dc1394_dma_unlisten(handle
, &camera
);
467 dc1394_dma_release_camera(handle
,&camera
);
469 dc1394_release_camera(handle
,&camera
);
470 is_capturing
= FALSE
;
477 BOOL
PVideoInput1394DcDevice::IsCapturing()
482 PStringList
PVideoInput1394DcDevice::GetInputDeviceNames()
486 if (PFile::Exists("/dev/raw1394"))
487 list
.AppendString("/dev/raw1394");
488 if (PFile::Exists("/dev/video1394/0"))
489 // DEVFS naming scheme
490 for (int i
=0; ; i
++) {
491 PString devname
= PString("/dev/video1394/") + PString(i
);
492 if (PFile::Exists(devname
))
493 list
.AppendString(devname
);
497 else if (PFile::Exists("/dev/video1394"))
498 /* traditional naming */
499 list
.AppendString("/dev/video1394");
504 BOOL
PVideoInput1394DcDevice::SetVideoFormat(VideoFormat newFormat
)
506 if (!PVideoDevice::SetVideoFormat(newFormat
)) {
507 PTRACE(3,"PVideoDevice::SetVideoFormat\t failed for format "<<newFormat
);
513 int PVideoInput1394DcDevice::GetBrightness()
519 BOOL
PVideoInput1394DcDevice::SetBrightness(unsigned newBrightness
)
525 int PVideoInput1394DcDevice::GetHue()
531 BOOL
PVideoInput1394DcDevice::SetHue(unsigned newHue
)
537 int PVideoInput1394DcDevice::GetContrast()
543 BOOL
PVideoInput1394DcDevice::SetContrast(unsigned newContrast
)
548 BOOL
PVideoInput1394DcDevice::SetColour(unsigned newColour
)
553 int PVideoInput1394DcDevice::GetColour()
559 BOOL
PVideoInput1394DcDevice::SetWhiteness(unsigned newWhiteness
)
564 int PVideoInput1394DcDevice::GetWhiteness()
570 BOOL
PVideoInput1394DcDevice::GetParameters (int *whiteness
, int *brightness
,
571 int *colour
, int *contrast
, int *hue
)
581 int PVideoInput1394DcDevice::GetNumChannels()
587 BOOL
PVideoInput1394DcDevice::SetChannel(int newChannel
)
589 if (PVideoDevice::SetChannel(newChannel
) == FALSE
)
600 BOOL
PVideoInput1394DcDevice::SetFrameRate(unsigned rate
)
602 return PVideoDevice::SetFrameRate(rate
);
606 BOOL
PVideoInput1394DcDevice::GetFrameSizeLimits(unsigned & minWidth
,
607 unsigned & minHeight
,
609 unsigned & maxHeight
)
620 PINDEX
PVideoInput1394DcDevice::GetMaxFrameBytes()
622 if (converter
!= NULL
) {
623 PINDEX bytes
= converter
->GetMaxDstFrameBytes();
624 if (bytes
> frameBytes
)
631 BOOL
PVideoInput1394DcDevice::GetFrameDataNoDelay(BYTE
* buffer
, PINDEX
* bytesReturned
)
633 if (!IsCapturing()) return FALSE
;
635 PTRACE(3, "We are going to single capture.\n");
636 if ((UseDMA
&& dc1394_dma_single_capture(&camera
)!=DC1394_SUCCESS
) ||
637 (!UseDMA
&& dc1394_single_capture(handle
,&camera
)!=DC1394_SUCCESS
)){
638 PTRACE(1, "dc1394_single_capture() failed.");
642 PTRACE(3, "single captured, try to convert\n");
644 // If converting on the fly do it from frame store to output buffer, otherwise do
646 if (converter
!= NULL
)
647 converter
->Convert((const BYTE
*)camera
.capture_buffer
, buffer
, bytesReturned
);
649 PTRACE(1, "Converter must exist. Something goes wrong.");
653 #ifdef ESTIMATE_CAPTURE_PERFORMANCE
656 double capturing_time
= (double)((now
.GetTimestamp()-start_time
))/1000000;
657 ::fprintf(stderr
, "time %f, num_captured=%d, fps=%f\n",
658 capturing_time
, num_captured
, num_captured
/capturing_time
);
662 dc1394_dma_done_with_buffer(&camera
);
666 BOOL
PVideoInput1394DcDevice::GetFrameData(BYTE
* buffer
, PINDEX
* bytesReturned
)
669 if (msBetweenFrames
> capturing_duration
)
670 PThread::Current()->Sleep(msBetweenFrames
- capturing_duration
);
672 if ( !GetFrameDataNoDelay(buffer
, bytesReturned
))
675 capturing_duration
= (int)((end
-start
).GetMilliSeconds());
678 return GetFrameDataNoDelay(buffer
,bytesReturned
);
682 void PVideoInput1394DcDevice::ClearMapping()
687 BOOL
PVideoInput1394DcDevice::TestAllFormats()
692 BOOL
PVideoInput1394DcDevice::SetColourFormat(const PString
& newFormat
)
694 if (newFormat
!= colourFormat
) {
701 BOOL
PVideoInput1394DcDevice::SetFrameSize(unsigned width
, unsigned height
)
703 if ((!(width
== 320 && height
== 240)) &&
704 (!(width
== 160 && height
== 120)))
708 frameHeight
= height
;
710 if (frameWidth
== 320 && frameHeight
== 240)
711 colourFormat
= "UYVY422";
712 else if (frameWidth
== 160 && frameHeight
== 120)
713 colourFormat
= "UYV444";
715 frameBytes
= PVideoDevice::CalculateFrameBytes(frameWidth
, frameHeight
, colourFormat
);
725 BOOL
PVideoInput1394DcDevice::SetFrameSizeConverter(unsigned width
, unsigned height
,
728 if (width
== CIFWidth
&& height
== CIFHeight
)
729 SetFrameSize(320, 240);
730 else if (width
== QCIFWidth
&& height
== QCIFHeight
)
731 SetFrameSize(160, 120);
733 PTRACE(1, width
<< "x" << height
<< " is not supported.");
737 if (converter
!= NULL
)
740 desiredFrameWidth
= width
;
741 desiredFrameHeight
= height
;
743 converter
= PColourConverter::Create(colourFormat
, desiredColourFormat
, width
, height
);
744 if (converter
== NULL
) {
745 PTRACE(1, "Failed to make a converter.");
748 if (converter
->SetSrcFrameSize(frameWidth
, frameHeight
) == FALSE
) {
749 PTRACE(1, "Failed to set source frame size of a converter.");
755 BOOL
PVideoInput1394DcDevice::SetColourFormatConverter(const PString
& colourFmt
)
757 if (colourFmt
!= "YUV420P") {
758 PTRACE(1, colourFmt
<< " is unsupported.");
761 desiredColourFormat
= colourFmt
;
762 return SetFrameSizeConverter(desiredFrameWidth
, desiredFrameHeight
, FALSE
);
767 // End Of File ///////////////////////////////////////////////////////////////