1 // V4L2 is incompatible with large file support
2 // ALPHA C++ can't compile 64 bit headers
3 #undef _FILE_OFFSET_BITS
4 #undef _LARGEFILE_SOURCE
5 #undef _LARGEFILE64_SOURCE
11 #include "chantables.h"
15 #include "preferences.h"
16 #include "quicktime.h"
17 #include "recordconfig.h"
18 #include "vdevicev4l.h"
20 #include "videodevice.h"
23 #include <sys/ioctl.h>
28 VDeviceV4L::VDeviceV4L(VideoDevice *device)
34 VDeviceV4L::~VDeviceV4L()
38 int VDeviceV4L::initialize()
41 capture_frame_number = 0;
42 read_frame_number = 0;
44 initialization_complete = 0;
48 int VDeviceV4L::open_input()
50 device->channel->use_frequency = 1;
51 device->channel->use_fine = 1;
52 device->channel->use_norm = 1;
53 device->channel->use_input = 1;
56 device->picture->use_brightness = 1;
57 device->picture->use_contrast = 1;
58 device->picture->use_color = 1;
59 device->picture->use_hue = 1;
60 device->picture->use_whiteness = 1;
62 if((input_fd = open(device->in_config->v4l_in_device, O_RDWR)) < 0)
64 perror("VDeviceV4L::open_input");
75 int VDeviceV4L::close_all()
81 int VDeviceV4L::close_v4l()
84 if(input_fd != -1) close(input_fd);
88 int VDeviceV4L::unmap_v4l_shmem()
93 munmap(capture_buffer, capture_params.size);
95 delete capture_buffer;
101 int VDeviceV4L::v4l_init()
105 input_fd = open(device->in_config->v4l_in_device, O_RDWR);
108 perror("VDeviceV4L::v4l_init");
111 set_cloexec_flag(input_fd, 1);
113 if(ioctl(input_fd, VIDIOCGWIN, &window_params) < 0)
114 perror("VDeviceV4L::v4l_init VIDIOCGWIN");
117 window_params.width = device->in_config->w;
118 window_params.height = device->in_config->h;
119 window_params.chromakey = 0;
120 window_params.flags = 0;
121 window_params.clipcount = 0;
122 if(ioctl(input_fd, VIDIOCSWIN, &window_params) < 0)
123 perror("VDeviceV4L::v4l_init VIDIOCSWIN");
124 if(ioctl(input_fd, VIDIOCGWIN, &window_params) < 0)
125 perror("VDeviceV4L::v4l_init VIDIOCGWIN");
127 device->in_config->w = window_params.width;
128 device->in_config->h = window_params.height;
130 PictureConfig picture(0);
131 set_picture(&picture);
133 if(ioctl(input_fd, VIDIOCGMBUF, &capture_params) < 0)
134 perror("VDeviceV4L::v4l_init VIDIOCGMBUF");
136 capture_buffer = (char*)mmap(0,
138 PROT_READ|PROT_WRITE,
143 capture_frame_number = 0;
145 if((long)capture_buffer < 0)
148 perror("VDeviceV4L::v4l_init mmap");
150 capture_buffer = new char[capture_params.size];
154 // Get all frames capturing
162 void VDeviceV4L::v4l1_start_capture()
164 for(int i = 0; i < MIN(capture_params.frames, device->in_config->capture_length); i++)
175 int VDeviceV4L::v4l1_get_inputs()
177 struct video_channel channel_struct;
181 while(!done && i < 20)
183 channel_struct.channel = i;
184 if(ioctl(input_fd, VIDIOCGCHAN, &channel_struct) < 0)
191 Channel *channel = new Channel;
192 strcpy(channel->device_name, channel_struct.name);
193 device->input_sources.append(channel);
200 int VDeviceV4L::set_mute(int muted)
202 // Open audio, which obviously is controlled by the video driver.
203 // and apparently resets the input source.
204 v4l1_set_mute(muted);
207 int VDeviceV4L::v4l1_set_mute(int muted)
209 struct video_audio audio;
211 if(ioctl(input_fd, VIDIOCGAUDIO, &audio))
212 if(ioctl(input_fd, VIDIOCGAUDIO, &audio) < 0)
213 perror("VDeviceV4L::ioctl VIDIOCGAUDIO");
215 audio.volume = 65535;
217 audio.treble = 65535;
219 audio.flags |= VIDEO_AUDIO_MUTE | VIDEO_AUDIO_VOLUME;
221 audio.flags &= ~VIDEO_AUDIO_MUTE;
223 if(ioctl(input_fd, VIDIOCSAUDIO, &audio) < 0)
224 perror("VDeviceV4L::ioctl VIDIOCSAUDIO");
229 int VDeviceV4L::set_cloexec_flag(int desc, int value)
231 int oldflags = fcntl(desc, F_GETFD, 0);
232 if(oldflags < 0) return oldflags;
234 oldflags |= FD_CLOEXEC;
236 oldflags &= ~FD_CLOEXEC;
237 return fcntl(desc, F_SETFD, oldflags);
244 int VDeviceV4L::get_best_colormodel(Asset *asset)
246 int result = BC_RGB888;
248 // Get best colormodel for hardware acceleration
250 result = File::get_best_colormodel(asset, device->in_config->driver);
253 // Need to get color model before opening device but don't call this
254 // unless you want to open the device either.
255 if(!initialization_complete)
257 device_colormodel = translate_colormodel(result);
258 this->colormodel = result;
260 initialization_complete = 1;
262 // printf("VDeviceV4L::get_best_colormodel %c%c%c%c\n",
263 // ((char*)&device_colormodel)[0],
264 // ((char*)&device_colormodel)[1],
265 // ((char*)&device_colormodel)[2],
266 // ((char*)&device_colormodel)[3]);
270 unsigned long VDeviceV4L::translate_colormodel(int colormodel)
272 unsigned long result = 0;
275 case BC_YUV422: result = VIDEO_PALETTE_YUV422; break;
276 case BC_YUV420P: result = VIDEO_PALETTE_YUV420P; break;
277 case BC_YUV422P: result = VIDEO_PALETTE_YUV422P; break;
278 case BC_YUV411P: result = VIDEO_PALETTE_YUV411P; break;
279 case BC_RGB888: result = VIDEO_PALETTE_RGB24; break;
280 default: result = VIDEO_PALETTE_RGB24; break;
282 //printf("VDeviceV4L::translate_colormodel %d\n", result);
286 int VDeviceV4L::set_channel(Channel *channel)
288 return v4l1_set_channel(channel);
291 int VDeviceV4L::v4l1_set_channel(Channel *channel)
293 struct video_channel channel_struct;
294 struct video_tuner tuner_struct;
295 unsigned long new_freq;
297 // Mute changed the input to TV
300 //printf("VDeviceV4L::v4l1_set_channel 1 %d\n", channel->input);
301 // Read norm/input defaults
302 channel_struct.channel = channel->input;
303 if(ioctl(input_fd, VIDIOCGCHAN, &channel_struct) < 0)
304 perror("VDeviceV4L::v4l1_set_channel VIDIOCGCHAN");
307 channel_struct.channel = channel->input;
308 channel_struct.norm = v4l1_get_norm(channel->norm);
309 if(ioctl(input_fd, VIDIOCSCHAN, &channel_struct) < 0)
310 perror("VDeviceV4L::v4l1_set_channel VIDIOCSCHAN");
312 if(channel_struct.flags & VIDEO_VC_TUNER)
314 // Read tuner defaults
315 tuner_struct.tuner = channel->input;
316 if(ioctl(input_fd, VIDIOCGTUNER, &tuner_struct) < 0)
317 perror("VDeviceV4L::v4l1_set_channel VIDIOCGTUNER");
320 tuner_struct.mode = v4l1_get_norm(channel->norm);
321 if(ioctl(input_fd, VIDIOCSTUNER, &tuner_struct) < 0)
322 perror("VDeviceV4L::v4l1_set_channel VIDIOCSTUNER");
324 new_freq = chanlists[channel->freqtable].list[channel->entry].freq;
325 new_freq = (int)(new_freq * 0.016);
326 new_freq += channel->fine_tune;
328 if(ioctl(input_fd, VIDIOCSFREQ, &new_freq) < 0)
329 perror("VDeviceV4L::v4l1_set_channel VIDIOCSFREQ");
335 int VDeviceV4L::v4l1_get_norm(int norm)
339 case NTSC: return VIDEO_MODE_NTSC; break;
340 case PAL: return VIDEO_MODE_PAL; break;
341 case SECAM: return VIDEO_MODE_SECAM; break;
346 int VDeviceV4L::set_picture(PictureConfig *picture)
348 v4l1_set_picture(picture);
352 int VDeviceV4L::v4l1_set_picture(PictureConfig *picture)
354 int brightness = (int)((float)picture->brightness / 100 * 32767 + 32768);
355 int hue = (int)((float)picture->hue / 100 * 32767 + 32768);
356 int color = (int)((float)picture->color / 100 * 32767 + 32768);
357 int contrast = (int)((float)picture->contrast / 100 * 32767 + 32768);
358 int whiteness = (int)((float)picture->whiteness / 100 * 32767 + 32768);
360 if(ioctl(input_fd, VIDIOCGPICT, &picture_params) < 0)
361 perror("VDeviceV4L::v4l1_set_picture VIDIOCGPICT");
362 picture_params.brightness = brightness;
363 picture_params.hue = hue;
364 picture_params.colour = color;
365 picture_params.contrast = contrast;
366 picture_params.whiteness = whiteness;
367 // Bogus. Values are only set in the capture routine.
368 picture_params.depth = 3;
369 picture_params.palette = device_colormodel;
370 if(ioctl(input_fd, VIDIOCSPICT, &picture_params) < 0)
371 perror("VDeviceV4L::v4l1_set_picture VIDIOCSPICT");
372 if(ioctl(input_fd, VIDIOCGPICT, &picture_params) < 0)
373 perror("VDeviceV4L::v4l1_set_picture VIDIOCGPICT");
378 int VDeviceV4L::capture_frame(int capture_frame_number)
380 struct video_mmap params;
381 params.frame = capture_frame_number;
382 params.width = device->in_config->w;
383 params.height = device->in_config->h;
384 // Required to actually set the palette.
385 params.format = device_colormodel;
386 // Tells the driver the buffer is available for writing
387 if(ioctl(input_fd, VIDIOCMCAPTURE, ¶ms) < 0)
388 perror("VDeviceV4L::capture_frame VIDIOCMCAPTURE");
392 int VDeviceV4L::wait_v4l_frame()
394 //printf("VDeviceV4L::wait_v4l_frame 1 %d\n", capture_frame_number);
395 if(ioctl(input_fd, VIDIOCSYNC, &capture_frame_number))
396 perror("VDeviceV4L::wait_v4l_frame VIDIOCSYNC");
397 //printf("VDeviceV4L::wait_v4l_frame 2 %d\n", capture_frame_number);
401 int VDeviceV4L::read_v4l_frame(VFrame *frame)
403 frame_to_vframe(frame, (unsigned char*)capture_buffer + capture_params.offsets[capture_frame_number]);
408 #define MIN(x, y) ((x) < (y) ? (x) : (y))
411 int VDeviceV4L::frame_to_vframe(VFrame *frame, unsigned char *input)
413 int inwidth, inheight;
416 inwidth = window_params.width;
417 inheight = window_params.height;
419 width = MIN(inwidth, frame->get_w());
420 height = MIN(inheight, frame->get_h());
421 //printf("VDeviceV4L::frame_to_vframe %d %d\n", colormodel, frame->get_color_model());
423 if(frame->get_color_model() == colormodel)
425 switch(frame->get_color_model())
429 unsigned char *row_in;
430 unsigned char *row_out_start, *row_out_end;
431 int bytes_per_inrow = inwidth * 3;
432 int bytes_per_outrow = frame->get_bytes_per_line();
433 unsigned char **rows_out = frame->get_rows();
435 for(int i = 0; i < frame->get_h(); i++)
437 row_in = input + bytes_per_inrow * i;
438 row_out_start = rows_out[i];
439 row_out_end = row_out_start +
440 MIN(bytes_per_outrow, bytes_per_inrow);
442 while(row_out_start < row_out_end)
444 *row_out_start++ = row_in[2];
445 *row_out_start++ = row_in[1];
446 *row_out_start++ = row_in[0];
455 memcpy(frame->get_y(), input, width * height);
456 memcpy(frame->get_u(), input + width * height, width * height / 4);
457 memcpy(frame->get_v(), input + width * height + width * height / 4, width * height / 4);
461 memcpy(frame->get_y(), input, width * height);
462 memcpy(frame->get_u(), input + width * height, width * height / 2);
463 memcpy(frame->get_v(), input + width * height + width * height / 2, width * height / 2);
467 memcpy(frame->get_data(),
469 VFrame::calculate_data_size(width,
472 frame->get_color_model()));
478 VFrame *in_frame = new VFrame(input,
483 cmodel_transfer(frame->get_rows(),
484 in_frame->get_rows(),
500 frame->get_color_model(),
510 int VDeviceV4L::next_frame(int previous_frame)
512 int result = previous_frame + 1;
514 if(result >= MIN(capture_params.frames, device->in_config->capture_length)) result = 0;
518 int VDeviceV4L::read_buffer(VFrame *frame)
525 // Read the current frame
526 if(!got_first_frame) v4l1_start_capture();
528 read_v4l_frame(frame);
529 // Free this frame up for capturing
530 capture_frame(capture_frame_number);
531 // Advance the frame to capture.
532 capture_frame_number = next_frame(capture_frame_number);
536 read(input_fd, capture_buffer, capture_params.size);