00001
00002
00003 #undef _FILE_OFFSET_BITS
00004 #undef _LARGEFILE_SOURCE
00005 #undef _LARGEFILE64_SOURCE
00006
00007
00008 #include "assets.h"
00009 #include "channel.h"
00010 #include "chantables.h"
00011 #include "clip.h"
00012 #include "file.h"
00013 #include "picture.h"
00014 #include "preferences.h"
00015 #include "quicktime.h"
00016 #include "recordconfig.h"
00017 #include "vdevicev4l.h"
00018 #include "vframe.h"
00019 #include "videodevice.h"
00020
00021 #include <unistd.h>
00022 #include <sys/ioctl.h>
00023 #include <fcntl.h>
00024 #include <sys/mman.h>
00025 #include <string.h>
00026
00027 VDeviceV4L::VDeviceV4L(VideoDevice *device)
00028 : VDeviceBase(device)
00029 {
00030 initialize();
00031 }
00032
00033 VDeviceV4L::~VDeviceV4L()
00034 {
00035 }
00036
00037 int VDeviceV4L::initialize()
00038 {
00039 capture_buffer = 0;
00040 capture_frame_number = 0;
00041 read_frame_number = 0;
00042 shared_memory = 0;
00043 initialization_complete = 0;
00044 return 0;
00045 }
00046
00047 int VDeviceV4L::open_input()
00048 {
00049 device->channel->use_frequency = 1;
00050 device->channel->use_fine = 1;
00051 device->channel->use_norm = 1;
00052 device->channel->use_input = 1;
00053
00054
00055 device->picture->use_brightness = 1;
00056 device->picture->use_contrast = 1;
00057 device->picture->use_color = 1;
00058 device->picture->use_hue = 1;
00059 device->picture->use_whiteness = 1;
00060
00061 if((input_fd = open(device->in_config->v4l_in_device, O_RDWR)) < 0)
00062 {
00063 perror("VDeviceV4L::open_input");
00064 return 1;
00065 }
00066 else
00067 {
00068 v4l1_get_inputs();
00069 close(input_fd);
00070 }
00071 return 0;
00072 }
00073
00074 int VDeviceV4L::close_all()
00075 {
00076 close_v4l();
00077 return 0;
00078 }
00079
00080 int VDeviceV4L::close_v4l()
00081 {
00082 unmap_v4l_shmem();
00083 if(input_fd != -1) close(input_fd);
00084 return 0;
00085 }
00086
00087 int VDeviceV4L::unmap_v4l_shmem()
00088 {
00089 if(capture_buffer)
00090 {
00091 if(shared_memory)
00092 munmap(capture_buffer, capture_params.size);
00093 else
00094 delete capture_buffer;
00095 }
00096 return 0;
00097 }
00098
00099 int VDeviceV4L::v4l_init()
00100 {
00101 int i;
00102
00103 input_fd = open(device->in_config->v4l_in_device, O_RDWR);
00104
00105 if(input_fd < 0)
00106 perror("VDeviceV4L::init_video4linux");
00107 else
00108 {
00109 set_cloexec_flag(input_fd, 1);
00110 set_mute(0);
00111 if(ioctl(input_fd, VIDIOCGWIN, &window_params) < 0)
00112 perror("VDeviceV4L::v4l_init VIDIOCGWIN");
00113 window_params.x = 0;
00114 window_params.y = 0;
00115 window_params.width = device->in_config->w;
00116 window_params.height = device->in_config->h;
00117 window_params.chromakey = 0;
00118 window_params.flags = 0;
00119 window_params.clipcount = 0;
00120 if(ioctl(input_fd, VIDIOCSWIN, &window_params) < 0)
00121 perror("VDeviceV4L::v4l_init VIDIOCSWIN");
00122 if(ioctl(input_fd, VIDIOCGWIN, &window_params) < 0)
00123 perror("VDeviceV4L::v4l_init VIDIOCGWIN");
00124
00125 device->in_config->w = window_params.width;
00126 device->in_config->h = window_params.height;
00127
00128 PictureConfig picture(0);
00129 set_picture(&picture);
00130
00131 if(ioctl(input_fd, VIDIOCGMBUF, &capture_params) < 0)
00132 perror("VDeviceV4L::v4l_init VIDIOCGMBUF");
00133
00134 capture_buffer = (char*)mmap(0,
00135 capture_params.size,
00136 PROT_READ|PROT_WRITE,
00137 MAP_SHARED,
00138 input_fd,
00139 0);
00140
00141 capture_frame_number = 0;
00142
00143 if((long)capture_buffer < 0)
00144 {
00145
00146 perror("VDeviceV4L::v4l_init mmap");
00147 shared_memory = 0;
00148 capture_buffer = new char[capture_params.size];
00149 }
00150 else
00151 {
00152
00153 shared_memory = 1;
00154 }
00155 }
00156 got_first_frame = 0;
00157 return 0;
00158 }
00159
00160 void VDeviceV4L::v4l1_start_capture()
00161 {
00162 for(int i = 0; i < MIN(capture_params.frames, device->in_config->capture_length); i++)
00163 capture_frame(i);
00164 }
00165
00166
00167
00168
00169
00170
00171
00172
00173 int VDeviceV4L::v4l1_get_inputs()
00174 {
00175 struct video_channel channel_struct;
00176 int i = 0, done = 0;
00177 char *new_source;
00178
00179 while(!done && i < 20)
00180 {
00181 channel_struct.channel = i;
00182 if(ioctl(input_fd, VIDIOCGCHAN, &channel_struct) < 0)
00183 {
00184
00185 done = 1;
00186 }
00187 else
00188 {
00189 Channel *channel = new Channel;
00190 strcpy(channel->device_name, channel_struct.name);
00191 device->input_sources.append(channel);
00192 }
00193 i++;
00194 }
00195 return 0;
00196 }
00197
00198 int VDeviceV4L::set_mute(int muted)
00199 {
00200
00201
00202 v4l1_set_mute(muted);
00203 }
00204
00205 int VDeviceV4L::v4l1_set_mute(int muted)
00206 {
00207 struct video_audio audio;
00208
00209 if(ioctl(input_fd, VIDIOCGAUDIO, &audio))
00210 if(ioctl(input_fd, VIDIOCGAUDIO, &audio) < 0)
00211 perror("VDeviceV4L::ioctl VIDIOCGAUDIO");
00212
00213 audio.volume = 65535;
00214 audio.bass = 65535;
00215 audio.treble = 65535;
00216 if(muted)
00217 audio.flags |= VIDEO_AUDIO_MUTE | VIDEO_AUDIO_VOLUME;
00218 else
00219 audio.flags &= ~VIDEO_AUDIO_MUTE;
00220
00221 if(ioctl(input_fd, VIDIOCSAUDIO, &audio) < 0)
00222 perror("VDeviceV4L::ioctl VIDIOCSAUDIO");
00223 return 0;
00224 }
00225
00226
00227 int VDeviceV4L::set_cloexec_flag(int desc, int value)
00228 {
00229 int oldflags = fcntl(desc, F_GETFD, 0);
00230 if(oldflags < 0) return oldflags;
00231 if(value != 0)
00232 oldflags |= FD_CLOEXEC;
00233 else
00234 oldflags &= ~FD_CLOEXEC;
00235 return fcntl(desc, F_SETFD, oldflags);
00236 }
00237
00238
00239
00240
00241
00242 int VDeviceV4L::get_best_colormodel(Asset *asset)
00243 {
00244 int result = BC_RGB888;
00245
00246
00247
00248 result = File::get_best_colormodel(asset, device->in_config->driver);
00249
00250
00251
00252
00253 if(!initialization_complete)
00254 {
00255 device_colormodel = translate_colormodel(result);
00256 this->colormodel = result;
00257 v4l_init();
00258 initialization_complete = 1;
00259 }
00260
00261
00262
00263
00264
00265 return result;
00266 }
00267
00268 unsigned long VDeviceV4L::translate_colormodel(int colormodel)
00269 {
00270 unsigned long result = 0;
00271 switch(colormodel)
00272 {
00273 case BC_YUV422: result = VIDEO_PALETTE_YUV422; break;
00274 case BC_YUV420P: result = VIDEO_PALETTE_YUV420P; break;
00275 case BC_YUV422P: result = VIDEO_PALETTE_YUV422P; break;
00276 case BC_YUV411P: result = VIDEO_PALETTE_YUV411P; break;
00277 case BC_RGB888: result = VIDEO_PALETTE_RGB24; break;
00278 default: result = VIDEO_PALETTE_RGB24; break;
00279 }
00280
00281 return result;
00282 }
00283
00284 int VDeviceV4L::set_channel(Channel *channel)
00285 {
00286 return v4l1_set_channel(channel);
00287 }
00288
00289 int VDeviceV4L::v4l1_set_channel(Channel *channel)
00290 {
00291 struct video_channel channel_struct;
00292 struct video_tuner tuner_struct;
00293 unsigned long new_freq;
00294
00295
00296
00297
00298
00299
00300 channel_struct.channel = channel->input;
00301 if(ioctl(input_fd, VIDIOCGCHAN, &channel_struct) < 0)
00302 perror("VDeviceV4L::v4l1_set_channel VIDIOCGCHAN");
00303
00304
00305 channel_struct.channel = channel->input;
00306 channel_struct.norm = v4l1_get_norm(channel->norm);
00307 if(ioctl(input_fd, VIDIOCSCHAN, &channel_struct) < 0)
00308 perror("VDeviceV4L::v4l1_set_channel VIDIOCSCHAN");
00309
00310 if(channel_struct.flags & VIDEO_VC_TUNER)
00311 {
00312
00313 tuner_struct.tuner = channel->input;
00314 if(ioctl(input_fd, VIDIOCGTUNER, &tuner_struct) < 0)
00315 perror("VDeviceV4L::v4l1_set_channel VIDIOCGTUNER");
00316
00317
00318 tuner_struct.mode = v4l1_get_norm(channel->norm);
00319 if(ioctl(input_fd, VIDIOCSTUNER, &tuner_struct) < 0)
00320 perror("VDeviceV4L::v4l1_set_channel VIDIOCSTUNER");
00321
00322 new_freq = chanlists[channel->freqtable].list[channel->entry].freq;
00323 new_freq = (int)(new_freq * 0.016);
00324 new_freq += channel->fine_tune;
00325
00326 if(ioctl(input_fd, VIDIOCSFREQ, &new_freq) < 0)
00327 perror("VDeviceV4L::v4l1_set_channel VIDIOCSFREQ");
00328 }
00329
00330 return 0;
00331 }
00332
00333 int VDeviceV4L::v4l1_get_norm(int norm)
00334 {
00335 switch(norm)
00336 {
00337 case NTSC: return VIDEO_MODE_NTSC; break;
00338 case PAL: return VIDEO_MODE_PAL; break;
00339 case SECAM: return VIDEO_MODE_SECAM; break;
00340 }
00341 return 0;
00342 }
00343
00344 int VDeviceV4L::set_picture(PictureConfig *picture)
00345 {
00346 v4l1_set_picture(picture);
00347 }
00348
00349
00350 int VDeviceV4L::v4l1_set_picture(PictureConfig *picture)
00351 {
00352 int brightness = (int)((float)picture->brightness / 100 * 32767 + 32768);
00353 int hue = (int)((float)picture->hue / 100 * 32767 + 32768);
00354 int color = (int)((float)picture->color / 100 * 32767 + 32768);
00355 int contrast = (int)((float)picture->contrast / 100 * 32767 + 32768);
00356 int whiteness = (int)((float)picture->whiteness / 100 * 32767 + 32768);
00357
00358 if(ioctl(input_fd, VIDIOCGPICT, &picture_params) < 0)
00359 perror("VDeviceV4L::v4l1_set_picture VIDIOCGPICT");
00360 picture_params.brightness = brightness;
00361 picture_params.hue = hue;
00362 picture_params.colour = color;
00363 picture_params.contrast = contrast;
00364 picture_params.whiteness = whiteness;
00365
00366 picture_params.depth = 3;
00367 picture_params.palette = device_colormodel;
00368 if(ioctl(input_fd, VIDIOCSPICT, &picture_params) < 0)
00369 perror("VDeviceV4L::v4l1_set_picture VIDIOCSPICT");
00370 if(ioctl(input_fd, VIDIOCGPICT, &picture_params) < 0)
00371 perror("VDeviceV4L::v4l1_set_picture VIDIOCGPICT");
00372 return 0;
00373 }
00374
00375
00376 int VDeviceV4L::capture_frame(int capture_frame_number)
00377 {
00378 struct video_mmap params;
00379 params.frame = capture_frame_number;
00380 params.width = device->in_config->w;
00381 params.height = device->in_config->h;
00382
00383 params.format = device_colormodel;
00384
00385 if(ioctl(input_fd, VIDIOCMCAPTURE, ¶ms) < 0)
00386 perror("VDeviceV4L::capture_frame VIDIOCMCAPTURE");
00387 return 0;
00388 }
00389
00390 int VDeviceV4L::wait_v4l_frame()
00391 {
00392
00393 if(ioctl(input_fd, VIDIOCSYNC, &capture_frame_number))
00394 perror("VDeviceV4L::wait_v4l_frame VIDIOCSYNC");
00395
00396 return 0;
00397 }
00398
00399 int VDeviceV4L::read_v4l_frame(VFrame *frame)
00400 {
00401 frame_to_vframe(frame, (unsigned char*)capture_buffer + capture_params.offsets[capture_frame_number]);
00402 return 0;
00403 }
00404
00405 #ifndef MIN
00406 #define MIN(x, y) ((x) < (y) ? (x) : (y))
00407 #endif
00408
00409 int VDeviceV4L::frame_to_vframe(VFrame *frame, unsigned char *input)
00410 {
00411 int inwidth, inheight;
00412 int width, height;
00413
00414 inwidth = window_params.width;
00415 inheight = window_params.height;
00416
00417 width = MIN(inwidth, frame->get_w());
00418 height = MIN(inheight, frame->get_h());
00419
00420
00421 if(frame->get_color_model() == colormodel)
00422 {
00423 switch(frame->get_color_model())
00424 {
00425 case BC_RGB888:
00426 {
00427 unsigned char *row_in;
00428 unsigned char *row_out_start, *row_out_end;
00429 int bytes_per_inrow = inwidth * 3;
00430 int bytes_per_outrow = frame->get_bytes_per_line();
00431 unsigned char **rows_out = frame->get_rows();
00432
00433 for(int i = 0; i < frame->get_h(); i++)
00434 {
00435 row_in = input + bytes_per_inrow * i;
00436 row_out_start = rows_out[i];
00437 row_out_end = row_out_start +
00438 MIN(bytes_per_outrow, bytes_per_inrow);
00439
00440 while(row_out_start < row_out_end)
00441 {
00442 *row_out_start++ = row_in[2];
00443 *row_out_start++ = row_in[1];
00444 *row_out_start++ = row_in[0];
00445 row_in += 3;
00446 }
00447 }
00448 break;
00449 }
00450
00451 case BC_YUV420P:
00452 case BC_YUV411P:
00453 memcpy(frame->get_y(), input, width * height);
00454 memcpy(frame->get_u(), input + width * height, width * height / 4);
00455 memcpy(frame->get_v(), input + width * height + width * height / 4, width * height / 4);
00456 break;
00457
00458 case BC_YUV422P:
00459 memcpy(frame->get_y(), input, width * height);
00460 memcpy(frame->get_u(), input + width * height, width * height / 2);
00461 memcpy(frame->get_v(), input + width * height + width * height / 2, width * height / 2);
00462 break;
00463
00464 case BC_YUV422:
00465 memcpy(frame->get_data(),
00466 input,
00467 VFrame::calculate_data_size(width,
00468 height,
00469 -1,
00470 frame->get_color_model()));
00471 break;
00472 }
00473 }
00474 else
00475 {
00476 VFrame *in_frame = new VFrame(input,
00477 inwidth,
00478 inheight,
00479 colormodel,
00480 -1);
00481 cmodel_transfer(frame->get_rows(),
00482 in_frame->get_rows(),
00483 frame->get_y(),
00484 frame->get_u(),
00485 frame->get_v(),
00486 in_frame->get_y(),
00487 in_frame->get_u(),
00488 in_frame->get_v(),
00489 0,
00490 0,
00491 inwidth,
00492 inheight,
00493 0,
00494 0,
00495 frame->get_w(),
00496 frame->get_h(),
00497 colormodel,
00498 frame->get_color_model(),
00499 0,
00500 inwidth,
00501 inheight);
00502 }
00503 return 0;
00504 }
00505
00506
00507
00508 int VDeviceV4L::next_frame(int previous_frame)
00509 {
00510 int result = previous_frame + 1;
00511
00512 if(result >= MIN(capture_params.frames, device->in_config->capture_length)) result = 0;
00513 return result;
00514 }
00515
00516 int VDeviceV4L::read_buffer(VFrame *frame)
00517 {
00518 int result = 0;
00519
00520 if(shared_memory)
00521 {
00522
00523 if(!got_first_frame) v4l1_start_capture();
00524 wait_v4l_frame();
00525 read_v4l_frame(frame);
00526
00527 capture_frame(capture_frame_number);
00528
00529 capture_frame_number = next_frame(capture_frame_number);
00530 }
00531 else
00532 {
00533 read(input_fd, capture_buffer, capture_params.size);
00534 }
00535 got_first_frame = 1;
00536
00537 return 0;
00538 }
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549