Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

vdevicev4l.C

Go to the documentation of this file.
00001 // V4L2 is incompatible with large file support
00002 // ALPHA C++ can't compile 64 bit headers
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 // Use read instead.
00146                         perror("VDeviceV4L::v4l_init mmap");
00147                         shared_memory = 0;
00148                         capture_buffer = new char[capture_params.size];
00149                 }
00150                 else
00151                 {
00152 // Get all frames capturing
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 // Finished
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 // Open audio, which obviously is controlled by the video driver.
00201 // and apparently resets the input source.
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 // Get best colormodel for hardware acceleration
00247 
00248         result = File::get_best_colormodel(asset, device->in_config->driver);
00249 
00250 
00251 // Need to get color model before opening device but don't call this
00252 // unless you want to open the device either.
00253         if(!initialization_complete)
00254         {
00255                 device_colormodel = translate_colormodel(result);
00256                 this->colormodel = result;
00257                 v4l_init();
00258                 initialization_complete = 1;
00259         }
00260 // printf("VDeviceV4L::get_best_colormodel %c%c%c%c\n", 
00261 //      ((char*)&device_colormodel)[0],
00262 //      ((char*)&device_colormodel)[1],
00263 //      ((char*)&device_colormodel)[2],
00264 //      ((char*)&device_colormodel)[3]);
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 //printf("VDeviceV4L::translate_colormodel %d\n", result);
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 // Mute changed the input to TV
00296 //      set_mute(1);
00297 
00298 //printf("VDeviceV4L::v4l1_set_channel 1 %d\n", channel->input);
00299 // Read norm/input defaults
00300         channel_struct.channel = channel->input;
00301         if(ioctl(input_fd, VIDIOCGCHAN, &channel_struct) < 0)
00302                 perror("VDeviceV4L::v4l1_set_channel VIDIOCGCHAN");
00303 
00304 // Set norm/input
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 // Read tuner defaults
00313                 tuner_struct.tuner = channel->input;
00314                 if(ioctl(input_fd, VIDIOCGTUNER, &tuner_struct) < 0)
00315                         perror("VDeviceV4L::v4l1_set_channel VIDIOCGTUNER");
00316 
00317 // Set tuner
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 //      set_mute(0);
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 // Bogus.  Values are only set in the capture routine.
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 // Required to actually set the palette.
00383         params.format = device_colormodel;
00384 // Tells the driver the buffer is available for writing
00385         if(ioctl(input_fd, VIDIOCMCAPTURE, &params) < 0)
00386                 perror("VDeviceV4L::capture_frame VIDIOCMCAPTURE");
00387         return 0;
00388 }
00389 
00390 int VDeviceV4L::wait_v4l_frame()
00391 {
00392 //printf("VDeviceV4L::wait_v4l_frame 1 %d\n", capture_frame_number);
00393         if(ioctl(input_fd, VIDIOCSYNC, &capture_frame_number))
00394                 perror("VDeviceV4L::wait_v4l_frame VIDIOCSYNC");
00395 //printf("VDeviceV4L::wait_v4l_frame 2 %d\n", capture_frame_number);
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 //printf("VDeviceV4L::frame_to_vframe %d %d\n", colormodel, frame->get_color_model());
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 // Read the current frame
00523                 if(!got_first_frame) v4l1_start_capture();
00524                 wait_v4l_frame();
00525                 read_v4l_frame(frame);
00526 // Free this frame up for capturing
00527                 capture_frame(capture_frame_number);
00528 // Advance the frame to capture.
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 

Generated on Sun Jan 8 13:39:01 2006 for Cinelerra-svn by  doxygen 1.4.4