4 * Copyright (C) 2001 Rasca, Berlin
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <sys/types.h>
24 #include <sys/ioctl.h>
28 #include <linux/types.h>
29 #include <linux/videodev.h>
32 #define min(a,b) ((a) < (b) ? (a) : (b))
33 #define max(a,b) ((a) > (b) ? (a) : (b))
36 * set the input and norm for the video4linux device
39 v4l_set_input (int fd, int input, int norm)
41 struct video_channel vid_chnl;
43 if (input != INPUT_DEFAULT || norm != NORM_DEFAULT) {
44 if (vid_chnl.channel != INPUT_DEFAULT)
45 vid_chnl.channel = input;
49 if (ioctl (fd, VIDIOCGCHAN, &vid_chnl) == -1) {
50 perror ("ioctl (VIDIOCGCHAN)");
54 vid_chnl.channel = input;
55 if (norm != NORM_DEFAULT)
57 if (ioctl (fd, VIDIOCSCHAN, &vid_chnl) == -1) {
58 perror ("ioctl (VIDIOCSCHAN)");
67 * check the size and readjust if necessary
70 v4l_check_size (int fd, int *width, int *height)
72 struct video_capability vid_caps;
74 if (ioctl (fd, VIDIOCGCAP, &vid_caps) == -1) {
75 perror ("ioctl (VIDIOCGCAP)");
78 /* readjust if necessary */
79 if (*width > vid_caps.maxwidth || *width < vid_caps.minwidth) {
80 *width = min (*width, vid_caps.maxwidth);
81 *width = max (*width, vid_caps.minwidth);
82 fprintf (stderr, "readjusting width to %d\n", *width);
84 if (*height > vid_caps.maxheight || *height < vid_caps.minheight) {
85 *height = min (*height, vid_caps.maxheight);
86 *height = max (*height, vid_caps.minheight);
87 fprintf (stderr, "readjusting height to %d\n", *height);
93 * check the requested palette and adjust if possible
94 * seems not to work :-(
97 v4l_check_palette (int fd, int *palette)
99 struct video_picture vid_pic;
104 if (ioctl (fd, VIDIOCGPICT, &vid_pic) == -1) {
105 perror ("ioctl (VIDIOCGPICT)");
108 vid_pic.palette = *palette;
109 if (ioctl (fd, VIDIOCSPICT, &vid_pic) == -1) {
112 fprintf (stderr, "failed\n");
113 vid_pic.palette = *palette = VIDEO_PALETTE_YUV420P;
114 if (ioctl (fd, VIDIOCSPICT, &vid_pic) == -1) {
115 perror ("ioctl (VIDIOCSPICT) to YUV");
116 /* ok, try grayscale..
118 vid_pic.palette = *palette = VIDEO_PALETTE_GREY;
119 if (ioctl (fd, VIDIOCSPICT, &vid_pic) == -1) {
120 perror ("ioctl (VIDIOCSPICT) to GREY");
129 * check if driver supports mmap'ed buffer
132 v4l_check_mmap (int fd, int *size)
134 struct video_mbuf vid_buf;
136 if (ioctl (fd, VIDIOCGMBUF, &vid_buf) == -1) {
140 *size = vid_buf.size;
145 * mute sound if available
148 v4l_mute_sound (int fd)
150 struct video_capability vid_caps;
151 struct video_audio vid_aud;
153 if (ioctl (fd, VIDIOCGCAP, &vid_caps) == -1) {
154 perror ("ioctl (VIDIOCGCAP)");
157 if (vid_caps.audios > 0) {
159 if (ioctl (fd, VIDIOCGAUDIO, &vid_aud) == -1) {
162 vid_aud.flags = VIDEO_AUDIO_MUTE;
163 if (ioctl (fd, VIDIOCSAUDIO, &vid_aud) == -1)
171 * Turn a YUV4:2:0 block into an RGB block
173 * Video4Linux seems to use the blue, green, red channel
174 * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
176 * Color space conversion coefficients taken from the excellent
177 * http://www.inforamp.net/~poynton/ColorFAQ.html
178 * In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
179 * Y values are given for all 4 pixels, but the U (Pb)
180 * and V (Pr) are assumed constant over the 2x2 block.
182 * To avoid floating point arithmetic, the color conversion
183 * coefficients are scaled into 16.16 fixed-point integers.
184 * They were determined as follows:
186 * double brightness = 1.0; (0->black; 1->full scale)
187 * double saturation = 1.0; (0->greyscale; 1->full color)
188 * double fixScale = brightness * 256 * 256;
189 * int rvScale = (int)(1.402 * saturation * fixScale);
190 * int guScale = (int)(-0.344136 * saturation * fixScale);
191 * int gvScale = (int)(-0.714136 * saturation * fixScale);
192 * int buScale = (int)(1.772 * saturation * fixScale);
193 * int yScale = (int)(fixScale);
196 /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
197 #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
202 v4l_copy_420_block (int yTL, int yTR, int yBL, int yBR, int u, int v,
203 int rowPixels, unsigned char * rgb, int bits)
205 const int rvScale = 91881;
206 const int guScale = -22553;
207 const int gvScale = -46801;
208 const int buScale = 116129;
209 const int yScale = 65536;
212 g = guScale * u + gvScale * v;
216 yTL *= yScale; yTR *= yScale;
217 yBL *= yScale; yBR *= yScale;
220 /* Write out top two pixels */
221 rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL);
222 rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR);
224 /* Skip down to next line to write out bottom two pixels */
225 rgb += 3 * rowPixels;
226 rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL);
227 rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR);
228 } else if (bits == 16) {
229 /* Write out top two pixels */
230 rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) | ((LIMIT(g+yTL) << 3) & 0xE0);
231 rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07) | (LIMIT(r+yTL) & 0xF8);
233 rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) | ((LIMIT(g+yTR) << 3) & 0xE0);
234 rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) | (LIMIT(r+yTR) & 0xF8);
236 /* Skip down to next line to write out bottom two pixels */
237 rgb += 2 * rowPixels;
239 rgb[0] = ((LIMIT(b+yBL) >> 3) & 0x1F) | ((LIMIT(g+yBL) << 3) & 0xE0);
240 rgb[1] = ((LIMIT(g+yBL) >> 5) & 0x07) | (LIMIT(r+yBL) & 0xF8);
242 rgb[2] = ((LIMIT(b+yBR) >> 3) & 0x1F) | ((LIMIT(g+yBR) << 3) & 0xE0);
243 rgb[3] = ((LIMIT(g+yBR) >> 5) & 0x07) | (LIMIT(r+yBR) & 0xF8);
250 v4l_copy_422_block (int yTL, int yTR, int u, int v,
251 int rowPixels, unsigned char * rgb, int bits)
253 const int rvScale = 91881;
254 const int guScale = -22553;
255 const int gvScale = -46801;
256 const int buScale = 116129;
257 const int yScale = 65536;
260 g = guScale * u + gvScale * v;
264 yTL *= yScale; yTR *= yScale;
267 /* Write out top two pixels */
268 rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL);
269 rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR);
271 } else if (bits == 16) {
272 /* Write out top two pixels */
273 rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) | ((LIMIT(g+yTL) << 3) & 0xE0);
274 rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07) | (LIMIT(r+yTL) & 0xF8);
276 rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) | ((LIMIT(g+yTR) << 3) & 0xE0);
277 rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) | (LIMIT(r+yTR) & 0xF8);
282 * convert a YUV420P to a rgb image
285 v4l_yuv420p2rgb (unsigned char *rgb_out, unsigned char *yuv_in,
286 int width, int height, int bits)
288 const int numpix = width * height;
289 const unsigned int bytes = bits >> 3;
290 int h, w, y00, y01, y10, y11, u, v;
291 unsigned char *pY = yuv_in;
292 unsigned char *pU = pY + numpix;
293 unsigned char *pV = pU + numpix / 4;
294 unsigned char *pOut = rgb_out;
296 if (!rgb_out || !yuv_in)
299 for (h = 0; h <= height - 2; h += 2) {
300 for (w = 0; w <= width - 2; w += 2) {
304 y11 = *(pY + width + 1);
308 v4l_copy_420_block (y00, y01, y10, y11, u, v, width, pOut, bits);
315 pOut += width * bytes;
321 * convert a YUV422P to a rgb image
324 v4l_yuv422p2rgb (unsigned char *rgb_out, unsigned char *yuv_in,
325 int width, int height, int bits)
327 const int numpix = width * height;
328 const unsigned int bytes = bits >> 3;
329 int h, w, y00, y01, u, v;
330 unsigned char *pY = yuv_in;
331 unsigned char *pU = pY + numpix;
332 unsigned char *pV = pU + numpix / 2;
333 unsigned char *pOut = rgb_out;
335 if (!rgb_out || !yuv_in)
338 for (h = 0; h < height; h += 1) {
339 for (w = 0; w <= width - 2; w += 2) {
345 v4l_copy_422_block (y00, y01, u, v, width, pOut, bits);
352 //pOut += width * bytes;