This document describes how to properly detect and use the extended features of the Philps USB webcams, should you wish to write or enhance your own program.
You may wonder why there is a separate API (Application Programming Interface) document for the Philips webcams. It uses the Video4Linux API so that should be enough, right?
Well, not quite. The V4L document and interface is geared towards TV grabber cards and not for webcams. Consequently it does not support some features that webcams have, and vice versa. For example: the framerate of the Philips webcams can be set, while a TV card uses a fixed rate which is not even controlled by the card, but by the video signal. And there are a few more differences.
Note that this document just describes the Philips cams; it could be that other driver-developers will use the same kind of features in their webcams and use this document as a reference. More likely, they will not :) Also, I tried to make sure my enhancements do not interfer with other programs and how they 'talk' to a V4L device.
I assume you have the V4L document available, and know a bit of how to program with it. This documents also amends the V4L interface, since some things have changed in the BTTV driver (you could consider this the reference upon which the V4L interface was designed), but not in the document.
If you want to program the Philips webcam you will need the file pwc-ioctl.h from your kernel source (somewhere around /usr/src/linux/drivers/usb); make sure you include an up-to-date version in your program. This file lists a number of private ioctl() calls and some useful #defines.
Second, you will have to program in a language that supports the ioctl() call, like C, or has a C interface. Although it is possible to open the video device and simply start reading images from that, there's no way to manipulate the device then.
You will need these includes at the top of your source file(s):
#include <linux/videodev.h> #include <sys/ioctl.h> #include "pwc-ioctl.h"
Note: all code fragments below are just snippets of code, and don't compile on their own. They are purely meant as an example.
Note: as of PWC 8.6, the detection procedure will change slightly. The detection by name will be superseeded by a PROBE ioctl(). The main reason is that so many different cameras are now supported by the driver, I decided to include the "real" name in the device name. After all, it looks a bit weird if you buy a Logitech QuickCam 3000 Pro and it shows up on your system as a "Philips 730 webcam". So, together with the name change I've added an extra VIDIOCPWCPROBE call, which can be used to safely detect the presence of a Philips (compatible) webcam.
In order to remain backwards compatible, you should first check the name in the usual way; if that fails, use the PROBE ioctl(); if that succeeds, you are using a Philips cam. This change will make 'older' programs fail to detect the OEM models (the original Philips cams are still detected of course since they still follow the old naming scheme).
After you open() the device, you use the VIDIOCGCAP ioctl() to get a struct video_capability which has a 'name' field. This name field is filled with eitther the following pattern:
Philips %d webcam
where %d is the model number (645, 646, 675, 730, etc), or any of the other names (Samsung MPC-C10, Creative Labs Webcam 5, etc.). Now, rather than programming tons of names to match in your own tool (which would always be outdated), use the VIDIOCPWCPROBE call and see if it returns valid data.
Example (pseudo) code:
struct video_capability vcap; struct pwc_probe probe; int type; bool IsPhilips; IsPhilips = FALSE; if (ioctl(cam_fd, VIDIOCGCAP, &vcap) < 0) return; if (sscanf(vcap.name, "Philips %d webcam", &type) == 1) IsPhilips = TRUE; else { /* No match yet; try the PROBE */ if (ioctl(cam_fd, VIDIOCPWCPROBE, &probe) == 0) { if (!strcmp(vcap.name, probe.name)) { IsPhilips = TRUE; type = probe.type; } } }
Note: it is considered bad programming practice to write code specific for one model; rather, try to make your program work for ALL Philips webcams.
The driver supports the following libc functions:
Although you can open the /dev/video device read-write, trying to write() to the device will result in an error. Only one process can open the device at the same time.
You can do 'partial reads', that is, read the image in chunks. The last chunk will be shorter if the image size isn't an exact multiple of the chunk buffer. In other words: you will never read across an image border, reading the first lines of the next image after the last lines of the current image. Of course you can also opt to read the image in one go.
read() will block until an image is available, unless you opened the device with O_NONBLOCK, in which case read() will return -EAGAIN when no image is available. You are advised to use the select() call (with only the bit in the 'readfs' set on).
In case you are using mmap(), the select() call will also return when an image is available.
In case you read the Video4Linux 1 standard, there are a few things you should be aware of... First, as stated before, the Video4Linux API is heavily geared towards TV grabber cards and assumes a few things which are simply not true for webcams. But we can work around that.
Second, it's incomplete as it misses a few important ioctl() calls, like querying the current input setting (most TV cards have multiple inputs, one for tuner, one for S-VHS, etc). But there is no way to ask which input has currently been selected. The same applies to the tuner.
Third, the API makes a distinction between input and tuners, which is okay. You can query which inputs there are, and which tuners there are, but not which tuner is connected to which input. This is usally not a problem, since most cards will only have one tuner attached to one input, but it's still an oversight.
After this small rant, let's get started :-)
The spec says this ioctl call takes an integer argument, but the 'bttv' driver (which acts as a reference for all video devices, it seems) takes a struct video_channel, just like its counterpart VIDIOCGCHAN. This actually makes sense as the struct video_channel also has a field for the TV norm.
Note that this change is not specific for the Philips webcams, but to all (most?) video devices.
The 'whiteness' field in struct video_picture is used for the gamma setting of the cameras. The spec says it is only for black & white cameras, but that makes very little sense. So I use it for the gamma correction. The other three settings: brightness, contrast and colour (saturation) work as expected, although some older models do not actually have colour saturation, so this settings does nothing for them.
When a setting is not supported, 0xFFFF is returned in the field with the VIDIOGPICT call. This value is not returned during normal operation.
Note that the struct video_picture also has a palette field, which is described in a separate chapter below. A value of 0 leaves the current palette intact.
Starting from Release 6.2, the Philips driver now supports any image size between the minimum and maximum size. For image sizes that are not an 'integral' image size directly supported by the camera, the image is now padded with a gray border.
Note: the driver only pads the image; it selects a format that is smaller or equal to the requested size; it does not crop an image that is only a bit larger than the requested current image.
However, the best way to program (and not just with webcams!) is to do a VIDIOCGWIN call right after VIDIOCSWIN, so you know exactly what resolution will be used. For example, a TV card may still decide to use the nearest multiple of 2, 4 or 8 pixels of the desired size, simply because the hardware is limited to such sizes. This is a programming strategy of mine that I call "the hardware knows best".
Here's a table which lists all supported resolutions on all camera models:
Size | PCA 645/646 & VC010 | PCVC 675/680/690 | PCVC 730/740/750 | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
3.75 | 5 | 7.5 | 10 | 12 | 15 | 20 | 24 | 5 | 10 | 15 | 20 | 25 | 30 | 5 | 10 | 15 | 20 | 25 | 30 | |||
sQCIF 128x96 |
||||||||||||||||||||||
QSIF 160x120 |
||||||||||||||||||||||
QCIF 176x144 |
||||||||||||||||||||||
SIF 320x240 |
||||||||||||||||||||||
CIF 352x288 | ||||||||||||||||||||||
VGA 640x480 |
You may notice that most sizes are derived from two main image sizes: all SIF formats are subformats of 640x480, and all CIF sizes (except subQCIF) are derived from 352x288 (which is a standard size for video conferencing).
The VIDIOCSWIN call is also used to set the frame rate. A TV grabber card doesn't have this of course, since its 'framerate' is dictated by the video signal (50 Hz for PAL/SECAM, and 59.94 Hz for NTSC 1). The frame rate is defined in the higher 16 bits of the 'flags' field, since some of the lower 16 bits are already used by Video4Linux:
bits | 31..23 | 21..16 | 15..0 |
---|---|---|---|
function | None; set to 0. | framerate | reserved for V4L |
So there are 6 bits for the framerate, giving a maximum framerate of 63. The highest 10 bits are undefined and should be 0.
Normally the framerate is a number between 4 and 30, but if you set the framerate bits to 0, the current framerate is unaffected. This way the VIDIOCSWIN call is backwards compatible with current applications who normally set this field to 0, or use the previous value from a VIDIOCGWIN call. However, do not set a framerate in a device that doesn't support it and hope the driver will just ignore it. It won't, and you'll get barfed upon.
To set a framerate of 3.75 or 7.5 Hz, use a framerate of 4 resp. 8. You can use any value between 5 (4) and 30, The driver will choose the nearest framerate. For critical applications, use a VIDIOCGWIN call to query what the real framerate is!
Use these defines from pwc-ioctl.h
to filter out or set the
framerate settings:
Example code:
struct video_window vwin; ioctl(cam_fd, VIDIOCGWIN, &vwin); if (vwin.flags & PWC_FPS_FRMASK) printf("Camera has framerate setting; current framerate: %d fps\n", (vwin.flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT); else return; /* Set new framerate */ vwin.flags &= ~PWC_FPS_FRMASK; vwin.flags |= (new_frame_rate << PWC_FPS_SHIFT); ioctl(cam_fd, VIDIOCSWIN, &vwin);
You may wonder why I stashed the framerate setting in the VIDIOCSWIN call, and not made it a private ioctl() call. Well, the reason is that some combinations of size and framerate are not allowed, and if size and framerate were set in 2 separate calls, this would make it difficult to 'reach' some of these combinations. Now, you immediately know the setting was not valid because ioctl() returned -EINVAL.
One of the greatest sources of confusion (and irritation for programmers, I might add), is the palette of colour images returned by a V4L device. A palette basicly tells the driver in which format you would like the image returned. There are 3 main formats in use these days:
All formats can be converted to another without loss (in other words, none is 'better' than the others). I won't go into details as to why these formats exist and what their properties are, but it suffices to say that RGB is best for viewing on a monitor, and YUV/YIQ is better suited for compression and video transmission.
The biggest problem format so far is the RGB format, since nobody seems to agree in which order it should be delivered: RGB suggests Red first, then Green, and finally Blue. But of course, some had to do it differently and put Blue first, then Green and finally Red (mind you, Green stays where it is). The endresult is that you look like a Smurf if you get the RGB/BGR order wrong :-)
The consensus among webcam driver programmers these days is to use the BGR format, esp. since this matches better with what TV grabber cards can deliver. Also, the YUV format is used by virtually all grabber cards and most webcam drivers, though with some small variations.
The Philips webcam driver (as of version 7.0) only delivers the
YUV420P palette, or in techno speak YUV 4:2:0 planar. However, for
completeness I list the other palettes in use among webcams as well.
The first byte is at offset 0, the second byte at offset 1, etc... The
last column lists the number of bytes per pixel (with this, you can
calculate how large your image buffer must be).
VIDEO_PALETTE_RGB24 | BGRB GRBG RBGR .... | 3 |
---|---|---|
VIDEO_PALETTE_RGB24 | 0x80 | RGBR GBRG BRGB .... | 3 |
VIDEO_PALETTE_RGB32 | BGR0 BGR0 BGR0 .... | 4 |
VIDEO_PALETTE_RGB32 | 0x80 | RGB0 RGB0 RGB0 ... | 4 |
VIDEO_PALETTE_YUYV VIDEO_PALETTE_YUV422 |
YUYV YUYV YUYV ... | 2 |
VIDEO_PALETTE_YUV420 | Even lines: YYYY UU YYYY UU .... Odd lines: YYYY VV YYYY VV .... |
1.5 |
VIDEO_PALETTE_YUV420P | YYYY .... YYYY YYYY .... YYYY UU .. UU VV .. VV Planar format: First all Y (luminance) values are written, exactly width * height bytes. This is followed by the U values, 1/4th of the number of Y pixels, followed by the same amount of V values. The U and V values are decimated by 2 in both horizontal and vertical direction. In other words: for every 4 Y values there is one U and one V value. Conversely, each U and V value apply to a block of 2x2 Y values. |
1.5 |
Note: each channel takes up one byte; the Philips driver does not support
the 'packed' formats or the grayscale format.
The fourth byte of the 32 bit palettes is a '0', and does not change
places in the RGB format!
The YUV420 palette is the camera's native palette; the U and V values
are interleaved between the Y values on alternating even and odd lines. So
you should always process 2 lines simultaneously.
Oh yes: the only way to find out which palettes are supported is to try them all out one bye one with a VIDIOCSPICT call. Another glaring omission from the V4L API....
Apart from the (backwards compatible) calls defined in the Video4Linux API, the driver has a number of extra ioctl() calls for Philips specific stuff. They are called 'private' because they use the number range marked 'private' in videodev.h. Be careful to check if you are really talking to a Philips webcam, because other drivers have their own set of private calls and you never know what may happen! These ioctl() calls are defined in the pwc-ioctl.h file.
All ioctl() calls below describe the argument they take; some take no argument at all, others take an integer or a structure. Note that the 3rd argument to an ioctl() call is virtually always the address of a variable, so use the & operator (this also means you cannot pass constants to ioctl() directly: you must place them in a variable first).
Of course, functions get added and removed; however, this is easy to detect. If the private function is not implemented, the ioctl() call will return -ENOIOCTLCMD. Any other value is an indication the function is available but failed at some other point (not supported by the camera, for example; -EFAULT probably means you forgot the & with your argument).
Brief: Prove existance of Philips (compatible) cam.
Argument:
struct pwc_probe { char name[32]; int type; };
This function can be used to prove the presence of a Philips OEM cam beyond reasonable doubt. The OEM models carry their own name in the video_capability field, thus making it a bit harder to determine if a camera has all the extra features. When this ioctl() call returns 0, compare the name field from pwc_probe to the name field of video_capability; if they match, the probe was succesful.
The type parameters returns the closest Philips compatible type (645, 680, 730, etc). It's purely informational.
Brief: Saves user settings.
Argument: none.
This function will write the current brightness, contrast, colour and whiteness (gamma) settings into the camera's internal EEPROM, where they can be restored by the following call.
Do not over-use this call; EEPROMs can only be written a limited number of times (usually around 10,000 times). After that, the EEPROM gets damaged and may not work at all.
Brief: Restore user settings.
Argument: none.
With this function, the values a user previously stored in the internal EEPROM will be recalled. This function only reads from the EEPROM and is thus safe.
Brief: Restore factory defaults.
Argument: none.
This function will restore all internal settings to a reasonable factory default, including the values set by the user with VIDIOCPWCSUSER. This function will also write to the camera's interal EEPROM, so don't overdo it.
Brief: Set compression preference.
Argument: integer.
The Philips webcams use compression techniques to get the images across the (narrow) USB bus. With this ioctl() call you can specify if you like no compression, low, medium or high compression. Higher compression means less bandwidth is used, but could introduce artefacts into the image.
The function takes an integer in the range 0 - 3. 0 Means that you prefer no compression, 3 = high compression. This setting is per camera, in contrast to the 'compression' module parameter you supply when loading the webcam module (which is only a default). This setting is also retained between close() and open() (but not between plug/unplug).
This setting does take effect immediately.
Brief: Get compression preference.
Argument: integer.
See above
Brief: Set AGC (Automatic Gain Control)
Argument: integer.
The webcams have features like auto-exposure and some additional circuitry to accomodate for changing light conditions. One of these features is an AGC circuit that amplifies or attenuates the signal that comes from the CCD/CMOS sensor.
Normally this circuit is in auto mode, but you can set it to a fixed value if you like. The VIDIOCPWCSAGC call takes an integer argument, in the range 0..65535 (0x0..0xFFFF). 0 is low gain, and 65535 sets it to highest gain possible. If you supply a negative number, the AGC is set to automatic mode.
Example code:
int agc; /* Select a high gain. Note the use of the & with the 3rd parameter */ agc = 40000; ioctl(fd, VIDIOCSAGC, &agc);
Brief: Get AGC (Automatic Gain Control) value.
Argument: integer.
This function has a double meaning. If the returned value is negative, it means the camera is in auto-AGC mode and the absolute value is the current gain (range: -65535..-1). A positive value indicates the camera has been set to fixed AGC mode and the selected gain is returned.
Brief: Set shutter speed
Argument: integer.
With this call you can manipulate the shutter speed of the camera, or the rate at which it takes images from the CCD/CMOS sensor. The higher the value, the longer it will take. Together with the AGC settings you can manipulate the light-sensitivity of the camera quite a lot. Do not expect any miracles though; it will not turn your $70 webcam into the Hubble Space Telescope with an exposure time of 10 days (!).
A negative value sets the shutter speed to automatic (controlled by the camera's firmware). A value of 0..65535 will set manual mode, where the values have been calibrated such that 65535 is the longest possible exposure time that I could find on any camera model. It is not a linear scale, where a value of '1' is 1/65536th of a second, etc.
Despite claims by some people who hacked at the Windows driver, I have not been able to verify that the shutter speed can be set to anything large, like 1 second or so. The longest exposure time is limited by the framerate (at least 5 frames per second, so 1/5th of a second).
Brief: Set Automatic White Balance
Argument:
struct pwc_whitebalance { int mode; int manual_red, manual_blue; /* read/write */ int read_red, read_blue; /* read/only */ };
The camera has built-in White Balance compensation; that is, it has the ability to correct for different lighting conditions (outdoor, indoor, artificial lighting, etc), by adjusting the gains for the red en blue pixels (green is never affected). Normally you leave it in automatic mode, but in certain circumstances you might want a fixed setting, or query the current values. This is what VIDIOCPWCSAWB and VIDIOCPWCGAWB are for.
mode can be one of these defined values:
I suppose these names speak for themselves, with the exception of PWC_WB_FL: FL stands for fluorescent lighting, or tubes.
Only when mode = PWC_WB_MANUAL, the manual_red and manual_blue parameters are valid; they are used to program the camera with your own red and blue gain values; their range is 0..65535 (0x0..0xffff). In all other modes these parameters are ignored. The read_red and read_blue parameters are never used with VIDIOCPWCSAWB.
Brief: Get Automatic White Balance
Argument: See Set Automatic White Balance
This function is used to query the current Auto White Balance mode and optionally the red and blue gain values of the camera. It takes a pwc_whitebalance struct, which is filled with the mode (see above). If mode == PWC_WB_MANUAL, the manual_red and manual_blue parameters are set; if mode == PWC_WB_AUTO the read_red and read_blue parameters are set. In any other mode the *red and *blue parameters are not filled at all.
Brief: Control speed of Automatic White Balance
Argument:
struct pwc_wb_speed { int control_speed; int control_delay; };
Supported: PWC 8.6 and above.
These two functions are also part of the Auto White Balance mode of the cameras, but are separated from the SAWB/GAWB calls since they are probably not used much and this way I don't break the pwc_whitebalance struct.
control_speed and control_delay parameters determine how fast the camera reacts to changes in lighting when it is in automatic mode, and how long it waits before it starts adjusting the red/blue gains. There are no absolute times (it seems to be related to the number of frames processed). The range of both numbers is 1..65535 (0x1..0xffff); a setting of 0 leaves the settings untouched.
NB: the term 'speed' is a bit misleading; in fact, the higher the number, the slower it reacts.
Brief: Control and query the LED on the camera.
Argument:
struct pwc_leds { int led_on; /* Led on-time; range = 0..25000 */ int led_off; /* Led off-time; idem. */ };
Supported: Only by ToUCam series (730 to 750). Not every OEM cam based on this chipset supports this feature!
These 2 functions may sound less functional, but they can be useful. With the VIDIOCPWCSLED function you can determine if the LED on the camera should be on while it is in use (the default), off (handy for survaillance cams), or blink (draws extra attention). VIDIOCPWCGLED returns the current settings.
The time is specified in milliseconds, with a resolution of 100 ms; the maximum is 25500 (about 25 seconds; a very long blinking time :-)). If you want a LED that is always on, specify a led_on time >= 100, and a led_off time of 0. To get a a dark LED, specify a led_on time of 0, and time_off may be >= 100. For a blinking LED, set both led_on and led_off to a value larger than 100.
Example code:
#include "pwc-ioctl.h" ..... struct pwc_leds LED; /* Turn LED off */ LED.led_on = 0; LED.led_off = 0; ioctl(fd, VIDIOCPWCSLED, &LED); /* Turn LED on solid */ LED.led_on = 100; LED.led_off = 0; ioctl(fd, VIDIOCPWCSLED, &LED); /* Blinking LED, 1 second interval, 20% duty cycle */ LED.led_on = 200; LED.led_off = 800; ioctl(fd, VIDIOCPWCSLED, &LED);
Note 1: There is a parameter that can be specified when loading the pwc module that also controls the LED time; this is the default timing.
Note 2: When the video device is closed, the LED is always turned off. This is done by the driver.
Brief: Control and query electronic sharpness
Argument: integer
Supported: PWC 8.6 and up
This is an interesting functions: it can blur or sharpen the image from the cam. This is done electronically, not by actually focussing the camera (you have to do this manually by rotating the canule, thus screwing the lens in or out). But it produces some interesting results: you can blur the image a bit to get a soft-focus effect, or sharpen it to enhance the edges in the image.
Don't overdo it, though. Sharpening the image also introduces more noise, makes it harder to compress the image for videoconferencing and makes the image look unnatural. And of course it can't correct for a camera that is out of focus. If you blur too much, people who are watching the images will tend to clean their glasses a lot or advise you to get a better webcam :-)
A negative argument indicates the webcam determines the contour value automatically (this value cannot be queried); a positive value in the range 0..65535 is will set the contour value manually. Low values will give a blurred image, a high value sharpens it.
Brief: Backlight compensation mode
Argument: integer
Supported: PWC 8.6 and up
In case the object you are viewing with the camera is in front of a bright background (for example, a window or some bright lights), the automatic exposure unit may make the image too dark. In that case you can turn the backlight compensation mode off; setting a value if 0 will just do that. Any other value means the backlight compensation mode is (turned) on.
Brief: Anti-flicker mode
Argument: integer
Supported: PWC 8.6 and up
Due to the different frequencies of the webcam, monitor refresh rate and the electrical power supply, the intensity of the image may 'pulsate' which is quite annoying to watch. The Philips cams have a way to suppress this (don't ask me how...) This function turns that feature on or off. A value of 0 turns if off, any other value means its on; simple as that.
Brief: Control the dynamic noise reduction mode
Argument: integer
Supported: PWC 8.6 and up
One of the more advanced features of the camera. It has an internal noise reduction algorithm (probably some temporal filtering), and works quite well to smooth out noise in the images. It can be set from None (value = 0) to High (value = 3).
Brief: Get the image size as produced by the camera
Argument:
struct pwc_imagesize { int width; int height; };
Supported: PWC 8.10 and up
Sometimes it's handy to know the real size of the image that is delivered by the camera (see this chart), because PWC pads any image size that is not directly supported with a gray border (doing interpolation in the kernel is a no-no). This function will tell what the 'real' current image size is, in pixels.
Before you delve into the VIDIOCPWCMPT functions below, there's some general information you should know.
The Logitech QuickCam Orbit or Sphere (they are the same cam, just named differently) has two built-in motors with which you can rotate the camera. One motor rotates the camera horizontally (called panning), the other vertically (called tilting). This is currently the only camera supported by PWC which has this feature. In addition, the cam has an extension rod which raises the bulb with the actual cam about 30 cm above your desk, earning it the nickname "cam-on-a-stick" (in a bun).
The cam can swivel about 70 degrees left and right from its home position, and 30 degrees up and down, giving you a total view of about 180 degrees horizontally and 120 degrees vertically. It's perfect for remote (security) operation without requiring additional hardware.
Below, the ioctl() commands are described which allow you to rotate the camera. When the camera does not have motorized pan & tilt, the ioctl() will return an errno of -ENXIO (no such device or address). The safest way to probe for this feature is by using VIDIOCPWCMPTGRANGE (get range), as this does not affect the cams position or operation, plus you get some useful information in case the cam does have the feature.
All angles described below are in degrees * 100, even though the cam cannot be set this accurate (it's best positioning accuracy is about 0.08 degrees; far more than you'll ever need). Also, there's mention of a zoom factor; this cam does not have hardware zoom, but I'd like to be prepared in case any future model cam will have this.
For panning, positive angles are clockwise from the home position, and for tilting positive angles are up.
You need PWC 8.12 or higher in order to call these functions; previous versions will return an ENOIOCTLCMD error (in which case you know the PWC driver you're talking to is too old).
Brief: Reset motorized pan/tilt position
Argument: integer
Supported: PWC 8.12 and up
This will reset the webcam to it's home position, which is horizontally halfway between its outermost left and right position and looking ahead level. The cam will perform a reset by first going to its topleft position, and then moving forward to its home position.
bits | 31..2 | 1 | 0 |
---|---|---|---|
function | Unused; set to 0. | reset tilt position | reset pan position |
After this call, the driver will set its internal angle position to 0,0.
Brief: Get pan/tilt range
Argument:
struct pwc_mpt_range { int pan_min, pan_max; int tilt_min, tilt_max; int zoom_min, zoom_max; }
Supported: PWC 8.12 and up
This function will query the driver for the minimum and maximum angles by which the cam can be rotated. All angles are expressed in degrees * 100.
These angles have been derived from the documentation and some experimentation. Trying to set an angle beyond these bounds will return in an -ERANGE error code.
The (hardware) zoom function is currently not available on any camera, so -1,-1 is returned in the zoom_min and zoom_max fields.
Brief: Set pan/tilt position
Argument:
struct pwc_mpt_angles { int absolute; /* write-only */ int pan; /* degrees * 100 */ int tilt /* degrees * 100 */ }
Supported: PWC 8.12 and up
With this command you order the Orbit/Sphere to rotate. You can rotate to an absolute position or relative to the current one. In all cases, trying to rotate beyond the allowed angles will return an -ERANGE error.
Note: do not send another VIDIOCPWCMPGSANGLE command until the last one has finished (either succesfully or with an error). Use the VIDIOCPWCMPTGSTATUS call to determine when the camera is ready (see below).
Brief: Get pan/tilt position
Argument: struct pwc_mpt_angles
Supported: PWC 8.12 and up
Query the current angle of the camera. The angle is not really queried from the camera, as it does not have position sensors. Rather, the last position set with VIDIOCPWCMPTSANGLE or VIDIOCPWCMPTRESET is remembered. It is therefor entirely possible that after several movements the camera is not quite looking at where you think it is. But there's always VIDIOCPWCMPTRESET, of course :-)
Brief: Query pan/tilt status
Argument:
struct pwc_mpt_status { int status; int time_pan; int time_tilt; }
Supported: PWC 8.12 and up
With this function you request the MPG status of the camera; while the camera
is moving these status bits will change.
Bits of 'status' | 31...3 | 2 | 1 | 0 |
---|---|---|---|---|
Function | Unused | General status bit | Tilt status | Pan status |
0x00 | Command running |
---|---|
0x01 | Timeout |
0x02 | Timeout |
0x03 | Timeout |
0x04 | Both axis hit hard stop |
0x05 | Tilt hit hard stop |
0x06 | Pan hit hard stop |
0x07 | Command completed succesfully |
Do not poll too quickly; an interval of 250 to 500 ms should be fine. The camera usually completes rotating within 2 seconds.
I'm not 100% sure what the time_pan and time_tilt parameters contain; I think they hold the time in milliseconds that the motor for that particular axis is running/has been running.
As I implement more features, I will describe them here.
[1]: Yes, 59.94 Hz, not 60 Hz, but for all practical purposes 60 Hz will do.
2004-06-17 - Nemosoft Unv