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