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

vdevicev4l2.C

Go to the documentation of this file.
00001 #undef _FILE_OFFSET_BITS
00002 #undef _LARGEFILE_SOURCE
00003 #undef _LARGEFILE64_SOURCE
00004 
00005 #include "assets.h"
00006 #include "channel.h"
00007 #include "chantables.h"
00008 #include "clip.h"
00009 #include "condition.h"
00010 #include "file.h"
00011 #include "picture.h"
00012 #include "preferences.h"
00013 #include "quicktime.h"
00014 #include "recordconfig.h"
00015 #include "vdevicev4l2.h"
00016 #include "vframe.h"
00017 #include "videodevice.h"
00018 
00019 #ifdef HAVE_VIDEO4LINUX2
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 
00028 
00029 
00030 
00031 
00032 
00033 VDeviceV4L2Put::VDeviceV4L2Put(VDeviceV4L2Thread *thread)
00034  : Thread(1, 0, 0)
00035 {
00036         this->thread = thread;
00037         done = 0;
00038         lock = new Mutex("VDeviceV4L2Put::lock");
00039         more_buffers = new Condition(0, "VDeviceV4L2Put::more_buffers");
00040         putbuffers = new int[0xff];
00041         total = 0;
00042 }
00043 
00044 VDeviceV4L2Put::~VDeviceV4L2Put()
00045 {
00046         if(Thread::running())
00047         {
00048                 done = 1;
00049                 more_buffers->unlock();
00050                 Thread::cancel();
00051                 Thread::join();
00052         }
00053         delete lock;
00054         delete more_buffers;
00055         delete [] putbuffers;
00056 }
00057 
00058 void VDeviceV4L2Put::run()
00059 {
00060         while(!done)
00061         {
00062                 more_buffers->lock("VDeviceV4L2Put::run");
00063                 if(done) break;
00064                 lock->lock("VDeviceV4L2Put::run");
00065                 int buffer = -1;
00066                 if(total)
00067                 {
00068                         buffer = putbuffers[0];
00069                         for(int i = 0; i < total - 1; i++)
00070                                 putbuffers[i] = putbuffers[i + 1];
00071                         total--;
00072                 }
00073                 lock->unlock();
00074 
00075                 if(buffer >= 0)
00076                 {
00077                         struct v4l2_buffer arg;
00078                         bzero(&arg, sizeof(arg));
00079                         arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00080                         arg.index = buffer;
00081                         arg.memory = V4L2_MEMORY_MMAP;
00082 
00083                         Thread::enable_cancel();
00084                         thread->ioctl_lock->lock("VDeviceV4L2Put::run");
00085 // This locks up if there's no signal.
00086                         if(ioctl(thread->input_fd, VIDIOC_QBUF, &arg) < 0)
00087                                 perror("VDeviceV4L2Put::run 1 VIDIOC_QBUF");
00088                         thread->ioctl_lock->unlock();
00089 // Delay to keep mutexes from getting stuck
00090                         usleep(1000000 * 1001 / 60000);
00091                         Thread::disable_cancel();
00092                 }
00093         }
00094 }
00095 
00096 void VDeviceV4L2Put::put_buffer(int number)
00097 {
00098         lock->lock("VDeviceV4L2Put::put_buffer");
00099         putbuffers[total++] = number;
00100         lock->unlock();
00101         more_buffers->unlock();
00102 }
00103 
00104 
00105 
00106 
00107 
00108 
00109 
00110 
00111 
00112 
00113 
00114 VDeviceV4L2Thread::VDeviceV4L2Thread(VideoDevice *device, int color_model)
00115  : Thread(1, 0, 0)
00116 {
00117         this->device = device;
00118         this->color_model = color_model;
00119 
00120         video_lock = new Condition(0, "VDeviceV4L2Thread::video_lock");
00121         buffer_lock = new Mutex("VDeviceV4L2Thread::buffer_lock");
00122         ioctl_lock = new Mutex("VDeviceV4L2Thread::ioctl_lock");
00123         device_buffers = 0;
00124         buffer_valid = 0;
00125         current_inbuffer = 0;
00126         current_outbuffer = 0;
00127         total_buffers = 0;
00128         first_frame = 1;
00129         done = 0;
00130         input_fd = 0;
00131         total_valid = 0;
00132         put_thread = 0;
00133 }
00134 
00135 VDeviceV4L2Thread::~VDeviceV4L2Thread()
00136 {
00137         if(Thread::running())
00138         {
00139                 done = 1;
00140                 Thread::cancel();
00141                 Thread::join();
00142         }
00143 
00144         if(put_thread) delete put_thread;
00145 
00146         if(buffer_valid)
00147         {
00148                 delete [] buffer_valid;
00149         }
00150 
00151 // Buffers are not unmapped by close.
00152         if(device_buffers)
00153         {
00154                 for(int i = 0; i < total_buffers; i++)
00155                 {
00156                         if(color_model == BC_COMPRESSED)
00157                         {
00158                                 if(device_buffers[i]->get_data()) 
00159                                         munmap(device_buffers[i]->get_data(),
00160                                                 device_buffers[i]->get_compressed_allocated());
00161                         }
00162                         else
00163                         {
00164                                 if(device_buffers[i]->get_data()) 
00165                                         munmap(device_buffers[i]->get_data(),
00166                                                 device_buffers[i]->get_data_size());
00167                         }
00168                         delete device_buffers[i];
00169                 }
00170                 delete [] device_buffers;
00171         }
00172 
00173         if(input_fd > 0) 
00174         {
00175                 int streamoff_arg = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00176                 if(ioctl(input_fd, VIDIOC_STREAMOFF, &streamoff_arg) < 0)
00177                         perror("VDeviceV4L2Thread::~VDeviceV4L2Thread VIDIOC_STREAMOFF");
00178                 close(input_fd);
00179         }
00180 
00181         delete video_lock;
00182         delete buffer_lock;
00183         delete ioctl_lock;
00184 }
00185 
00186 void VDeviceV4L2Thread::start()
00187 {
00188         total_buffers = device->in_config->capture_length;
00189         total_buffers = MAX(total_buffers, 2);
00190         total_buffers = MIN(total_buffers, 0xff);
00191         put_thread = new VDeviceV4L2Put(this);
00192         put_thread->start();
00193         Thread::start();
00194 }
00195 
00196 // Allocate user space buffers
00197 void VDeviceV4L2Thread::allocate_buffers(int number)
00198 {
00199         if(number != total_buffers)
00200         {
00201                 if(buffer_valid) delete [] buffer_valid;
00202                 if(device_buffers)
00203                 {
00204                         for(int i = 0; i < total_buffers; i++)
00205                         {
00206                                 delete device_buffers[i];
00207                         }
00208                         delete [] device_buffers;
00209                 }
00210         }
00211 
00212         total_buffers = number;
00213         buffer_valid = new int[total_buffers];
00214         device_buffers = new VFrame*[total_buffers];
00215         for(int i = 0; i < total_buffers; i++)
00216         {
00217                 device_buffers[i] = new VFrame;
00218         }
00219         bzero(buffer_valid, sizeof(int) * total_buffers);
00220 }
00221 
00222 void VDeviceV4L2Thread::run()
00223 {
00224 // Set up the device
00225         int error = 0;
00226         Thread::enable_cancel();
00227 
00228 
00229 
00230         if((input_fd = open(device->in_config->v4l2jpeg_in_device, 
00231                 O_RDWR)) < 0)
00232         {
00233                 perror("VDeviceV4L2Thread::run");
00234                 error = 1;
00235         }
00236 
00237         if(!error)
00238         {
00239                 device->set_cloexec_flag(input_fd, 1);
00240 
00241 
00242                 struct v4l2_capability cap;
00243                 if(ioctl(input_fd, VIDIOC_QUERYCAP, &cap))
00244                         perror("VDeviceV4L2Thread::run VIDIOC_QUERYCAP");
00245 
00246 // printf("VDeviceV4L2Thread::run input_fd=%d driver=%s card=%s bus_info=%s version=%d\n",
00247 // input_fd,
00248 // cap.driver,
00249 // cap.card,
00250 // cap.bus_info,
00251 // cap.version);
00252 // printf("    %s%s%s%s%s%s%s%s%s%s%s%s\n", 
00253 // (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ? "V4L2_CAP_VIDEO_CAPTURE " : "",
00254 // (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) ? "V4L2_CAP_VIDEO_OUTPUT " : "",
00255 // (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) ? "V4L2_CAP_VIDEO_OVERLAY " : "",
00256 // (cap.capabilities & V4L2_CAP_VBI_CAPTURE) ? "V4L2_CAP_VBI_CAPTURE " : "",
00257 // (cap.capabilities & V4L2_CAP_VBI_OUTPUT) ? "V4L2_CAP_VBI_OUTPUT " : "",
00258 // (cap.capabilities & V4L2_CAP_RDS_CAPTURE) ? "V4L2_CAP_RDS_CAPTURE " : "",
00259 // (cap.capabilities & V4L2_CAP_TUNER) ? "V4L2_CAP_TUNER " : "",
00260 // (cap.capabilities & V4L2_CAP_AUDIO) ? "V4L2_CAP_AUDIO " : "",
00261 // (cap.capabilities & V4L2_CAP_RADIO) ? "V4L2_CAP_RADIO " : "",
00262 // (cap.capabilities & V4L2_CAP_READWRITE) ? "V4L2_CAP_READWRITE " : "",
00263 // (cap.capabilities & V4L2_CAP_ASYNCIO) ? "V4L2_CAP_ASYNCIO " : "",
00264 // (cap.capabilities & V4L2_CAP_STREAMING) ? "V4L2_CAP_STREAMING " : "");
00265 
00266 
00267 // Set up frame rate
00268                 struct v4l2_streamparm v4l2_parm;
00269                 v4l2_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00270                 if(ioctl(input_fd, VIDIOC_G_PARM, &v4l2_parm) < 0)
00271                         perror("VDeviceV4L2Thread::run VIDIOC_G_PARM");
00272                 if(v4l2_parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)
00273                 {
00274                         v4l2_parm.parm.capture.capturemode |= V4L2_CAP_TIMEPERFRAME;
00275 
00276 
00277                         v4l2_parm.parm.capture.timeperframe.numerator = 1;
00278                         v4l2_parm.parm.capture.timeperframe.denominator = 
00279                                 (unsigned long)((float)1 / 
00280                                 device->frame_rate * 
00281                                 10000000);
00282                         if(ioctl(input_fd, VIDIOC_S_PARM, &v4l2_parm) < 0)
00283                                 perror("VDeviceV4L2Thread::run VIDIOC_S_PARM");
00284 
00285                         if(ioctl(input_fd, VIDIOC_G_PARM, &v4l2_parm) < 0)
00286                                 perror("VDeviceV4L2Thread::run VIDIOC_G_PARM");
00287                 }
00288 
00289 
00290 // Set up data format
00291                 struct v4l2_format v4l2_params;
00292                 v4l2_params.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00293                 if(ioctl(input_fd, VIDIOC_G_FMT, &v4l2_params) < 0)
00294                         perror("VDeviceV4L2Thread::run VIDIOC_G_FMT");
00295                 v4l2_params.fmt.pix.width = device->in_config->w;
00296                 v4l2_params.fmt.pix.height = device->in_config->h;
00297 
00298                 if(color_model == BC_COMPRESSED)
00299                         v4l2_params.fmt.pix.pixelformat = 
00300                                 V4L2_PIX_FMT_MJPEG;
00301                 else
00302                         v4l2_params.fmt.pix.pixelformat = 
00303                                 VDeviceV4L2::cmodel_to_device(color_model);
00304 
00305 
00306                 if(ioctl(input_fd, VIDIOC_S_FMT, &v4l2_params) < 0)
00307                         perror("VDeviceV4L2Thread::run VIDIOC_S_FMT");
00308                 if(ioctl(input_fd, VIDIOC_G_FMT, &v4l2_params) < 0)
00309                         perror("VDeviceV4L2Thread::run VIDIOC_G_FMT");
00310 
00311 // Set input
00312                 Channel *device_channel = 0;
00313                 if(device->channel->input >= 0 &&
00314                         device->channel->input < device->get_inputs()->total)
00315                 {
00316                         device_channel = device->get_inputs()->values[
00317                                 device->channel->input];
00318                 }
00319 
00320 // Try first input
00321                 if(!device_channel)
00322                 {
00323                         if(device->get_inputs()->total)
00324                         {
00325                                 device_channel = device->get_inputs()->values[0];
00326                                 printf("VDeviceV4L2Thread::run user channel not found.  Using %s\n",
00327                                         device_channel->device_name);
00328                         }
00329                         else
00330                         {
00331                                 printf("VDeviceV4L2Thread::run channel \"%s\" not found.\n",
00332                                         device->channel->title);
00333                         }
00334                 }
00335 
00336 
00337 
00338 
00339 // Set picture controls.  This driver requires the values to be set once to default
00340 // values and then again to different values before it takes up the values.
00341 // Unfortunately VIDIOC_S_CTRL resets the audio to mono in 2.6.7.
00342                 PictureConfig *picture = device->picture;
00343                 for(int i = 0; i < picture->controls.total; i++)
00344                 {
00345                         struct v4l2_control ctrl_arg;
00346                         struct v4l2_queryctrl arg;
00347                         PictureItem *item = picture->controls.values[i];
00348                         arg.id = item->device_id;
00349                         if(!ioctl(input_fd, VIDIOC_QUERYCTRL, &arg))
00350                         {
00351                                 ctrl_arg.id = item->device_id;
00352                                 ctrl_arg.value = 0;
00353                                 if(ioctl(input_fd, VIDIOC_S_CTRL, &ctrl_arg) < 0)
00354                                         perror("VDeviceV4L2Thread::run VIDIOC_S_CTRL");
00355                         }
00356                         else
00357                         {
00358                                 printf("VDeviceV4L2Thread::run VIDIOC_S_CTRL 1 id %d failed\n",
00359                                         item->device_id);
00360                         }
00361                 }
00362 
00363                 for(int i = 0; i < picture->controls.total; i++)
00364                 {
00365                         struct v4l2_control ctrl_arg;
00366                         struct v4l2_queryctrl arg;
00367                         PictureItem *item = picture->controls.values[i];
00368                         arg.id = item->device_id;
00369                         if(!ioctl(input_fd, VIDIOC_QUERYCTRL, &arg))
00370                         {
00371                                 ctrl_arg.id = item->device_id;
00372                                 ctrl_arg.value = item->value;
00373                                 if(ioctl(input_fd, VIDIOC_S_CTRL, &ctrl_arg) < 0)
00374                                         perror("VDeviceV4L2Thread::run VIDIOC_S_CTRL");
00375                         }
00376                         else
00377                         {
00378                                 printf("VDeviceV4L2Thread::run VIDIOC_S_CTRL 2 id %d failed\n",
00379                                         item->device_id);
00380                         }
00381                 }
00382 
00383 
00384 // Translate input to API structures
00385                 struct v4l2_tuner tuner;
00386                 int input = 0;
00387 
00388                 if(ioctl(input_fd, VIDIOC_G_TUNER, &tuner) < 0)
00389                         perror("VDeviceV4L2Thread::run VIDIOC_G_INPUT");
00390 
00391 // printf("VDeviceV4L2Thread::run audmode=%d rxsubchans=%d\n",
00392 // tuner.audmode,
00393 // tuner.rxsubchans);
00394                 if(device_channel)
00395                 {
00396                         tuner.index = device_channel->device_index;
00397                         input = device_channel->device_index;
00398                 }
00399                 else
00400                 {
00401                         tuner.index = 0;
00402                         input = 0;
00403                 }
00404 
00405                 tuner.type = V4L2_TUNER_ANALOG_TV;
00406                 tuner.audmode = V4L2_TUNER_MODE_STEREO;
00407                 tuner.rxsubchans = V4L2_TUNER_SUB_STEREO;
00408 
00409                 if(ioctl(input_fd, VIDIOC_S_INPUT, &input) < 0)
00410                         perror("VDeviceV4L2Thread::run VIDIOC_S_INPUT");
00411 
00412 
00413 
00414 
00415 
00416 
00417 
00418 
00419 // Set norm
00420                 v4l2_std_id std_id;
00421                 switch(device->channel->norm)
00422                 {
00423                         case NTSC: std_id = V4L2_STD_NTSC; break;
00424                         case PAL: std_id = V4L2_STD_PAL; break;
00425                         case SECAM: std_id = V4L2_STD_SECAM; break;
00426                         default: std_id = V4L2_STD_NTSC_M; break;
00427                 }
00428 
00429                 if(ioctl(input_fd, VIDIOC_S_STD, &std_id))
00430                         perror("VDeviceV4L2Thread::run VIDIOC_S_STD");
00431 
00432 
00433                 if(cap.capabilities & V4L2_CAP_TUNER)
00434                 {
00435                         if(ioctl(input_fd, VIDIOC_S_TUNER, &tuner) < 0)
00436                                 perror("VDeviceV4L2Thread::run VIDIOC_S_TUNER");
00437 // Set frequency
00438                         struct v4l2_frequency frequency;
00439                         frequency.tuner = device->channel->tuner;
00440                         frequency.type = V4L2_TUNER_ANALOG_TV;
00441                         frequency.frequency = (int)(chanlists[
00442                                 device->channel->freqtable].list[
00443                                         device->channel->entry].freq * 0.016);
00444 // printf("VDeviceV4L2Thread::run tuner=%d freq=%d norm=%d\n",
00445 // device->channel->tuner,
00446 // frequency.frequency,
00447 // device->channel->norm);
00448                         if(ioctl(input_fd, VIDIOC_S_FREQUENCY, &frequency) < 0)
00449                                 perror("VDeviceV4L2Thread::run VIDIOC_S_FREQUENCY");
00450                 }
00451 
00452 
00453 
00454 // Set compression
00455                 if(color_model == BC_COMPRESSED)
00456                 {
00457                         struct v4l2_jpegcompression jpeg_arg;
00458                         if(ioctl(input_fd, VIDIOC_G_JPEGCOMP, &jpeg_arg) < 0)
00459                                 perror("VDeviceV4L2Thread::run VIDIOC_G_JPEGCOMP");
00460                         jpeg_arg.quality = device->quality / 2;
00461                         if(ioctl(input_fd, VIDIOC_S_JPEGCOMP, &jpeg_arg) < 0)
00462                                 perror("VDeviceV4L2Thread::run VIDIOC_S_JPEGCOMP");
00463                 }
00464 
00465 // Allocate buffers.  Errors here are fatal.
00466                 Thread::disable_cancel();
00467                 struct v4l2_requestbuffers requestbuffers;
00468 
00469 printf("VDeviceV4L2Thread::run requested %d buffers\n", total_buffers);
00470                 requestbuffers.count = total_buffers;
00471                 requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00472                 requestbuffers.memory = V4L2_MEMORY_MMAP;
00473                 if(ioctl(input_fd, VIDIOC_REQBUFS, &requestbuffers) < 0)
00474                 {
00475                         perror("VDeviceV4L2Thread::run VIDIOC_REQBUFS");
00476                         error = 1;
00477                 }
00478                 else
00479                 {
00480 // The requestbuffers.count changes in the 2.6.5 version of the API
00481                         allocate_buffers(requestbuffers.count);
00482 printf("VDeviceV4L2Thread::run got %d buffers\n", total_buffers);
00483                         for(int i = 0; i < total_buffers; i++)
00484                         {
00485                                 struct v4l2_buffer buffer;
00486                                 buffer.type = requestbuffers.type;
00487                                 buffer.index = i;
00488                                 if(ioctl(input_fd, VIDIOC_QUERYBUF, &buffer) < 0)
00489                                 {
00490                                         perror("VDeviceV4L2Thread::run VIDIOC_QUERYBUF");
00491                                         error = 1;
00492                                         break;
00493                                 }
00494 
00495                                 unsigned char *data = (unsigned char*)mmap(NULL,
00496                                         buffer.length,
00497                                         PROT_READ | PROT_WRITE,
00498                                         MAP_SHARED,
00499                                         input_fd,
00500                                         buffer.m.offset);
00501                                 if(data == MAP_FAILED)
00502                                 {
00503                                         perror("VDeviceV4L2Thread::run mmap");
00504                                         error = 1;
00505                                         break;
00506                                 }
00507 
00508                                 VFrame *frame = device_buffers[i];
00509                                 if(color_model == BC_COMPRESSED)
00510                                 {
00511                                         frame->set_compressed_memory(data,
00512                                                 0,
00513                                                 buffer.length);
00514                                 }
00515                                 else
00516                                 {
00517                                         int y_offset = 0;
00518                                         int u_offset = 0;
00519                                         int v_offset = 0;
00520 
00521                                         switch(color_model)
00522                                         {
00523                                                 case BC_YUV422P:
00524                                                         u_offset = device->in_config->w * device->in_config->h;
00525                                                         v_offset = device->in_config->w * device->in_config->h + device->in_config->w * device->in_config->h / 2;
00526                                                         break;
00527                                                 case BC_YUV420P:
00528                                                 case BC_YUV411P:
00529 // In 2.6.7, the v and u are inverted for 420 but not 422
00530                                                         v_offset = device->in_config->w * device->in_config->h;
00531                                                         u_offset = device->in_config->w * device->in_config->h + device->in_config->w * device->in_config->h / 4;
00532                                                         break;
00533                                         }
00534 
00535                                         frame->reallocate(data,
00536                                                 y_offset,
00537                                                 u_offset,
00538                                                 v_offset,
00539                                                 device->in_config->w,
00540                                                 device->in_config->h,
00541                                                 color_model,
00542                                                 VFrame::calculate_bytes_per_pixel(color_model) *
00543                                                         device->in_config->w);
00544                                 }
00545                         }
00546                 }
00547                 Thread::enable_cancel();
00548         }
00549 
00550 
00551 
00552 // Start capturing
00553         if(!error)
00554         {
00555                 for(int i = 0; i < total_buffers; i++)
00556                 {
00557                         struct v4l2_buffer buffer;
00558                         buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00559                         buffer.index = i;
00560                         if(ioctl(input_fd, VIDIOC_QBUF, &buffer) < 0)
00561                         {
00562                                 perror("VDeviceV4L2Thread::run VIDIOC_QBUF");
00563                                 break;
00564                         }
00565                 }
00566 
00567 
00568                 int streamon_arg = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00569                 if(ioctl(input_fd, VIDIOC_STREAMON, &streamon_arg) < 0)
00570                         perror("VDeviceV4L2Thread::run VIDIOC_STREAMON");
00571         }
00572 
00573         Thread::disable_cancel();
00574 
00575 
00576 // Read buffers continuously
00577         first_frame = 0;
00578         while(!done && !error)
00579         {
00580                 struct v4l2_buffer buffer;
00581                 bzero(&buffer, sizeof(buffer));
00582                 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00583                 buffer.memory = V4L2_MEMORY_MMAP;
00584 
00585 // The driver returns the first buffer not queued, so only one buffer
00586 // can be unqueued at a time.
00587                 Thread::enable_cancel();
00588                 ioctl_lock->lock("VDeviceV4L2Thread::run");
00589                 int result = ioctl(input_fd, VIDIOC_DQBUF, &buffer);
00590                 ioctl_lock->unlock();
00591 // Delay so the mutexes don't get stuck
00592                 usleep(1000000 * 1001 / 60000);
00593                 Thread::disable_cancel();
00594 
00595 
00596                 if(result < 0)
00597                 {
00598                         perror("VDeviceV4L2Thread::run VIDIOC_DQBUF");
00599                         Thread::enable_cancel();
00600                         usleep(100000);
00601                         Thread::disable_cancel();
00602                 }
00603                 else
00604                 {
00605                         buffer_lock->lock("VDeviceV4L2Thread::run");
00606 
00607 // Set output frame as valid and set data size
00608                         current_inbuffer = buffer.index;
00609                         if(color_model == BC_COMPRESSED)
00610                         {
00611                                 device_buffers[current_inbuffer]->set_compressed_size(
00612                                         buffer.bytesused);
00613                         }
00614 
00615                         if(!buffer_valid[current_inbuffer])
00616                         {
00617 // Increase valid total only if current is invalid
00618                                 buffer_valid[current_inbuffer] = 1;
00619                                 total_valid++;
00620                                 buffer_lock->unlock();
00621                                 video_lock->unlock();
00622                         }
00623                         else
00624                         {
00625 // Driver won't block on the next QBUF call because we're not requeueing the buffer.
00626                                 buffer_lock->unlock();
00627                                 video_lock->unlock();
00628                                 usleep(33000);
00629                         }
00630                 }
00631 //printf("VDeviceV4L2::run 100 %lld\n", timer.get_difference());
00632         }
00633 }
00634 
00635 VFrame* VDeviceV4L2Thread::get_buffer(int *timed_out)
00636 {
00637         VFrame *result = 0;
00638         *timed_out = 0;
00639 
00640 // Acquire buffer table
00641         buffer_lock->lock("VDeviceV4L2Thread::get_buffer 1");
00642 
00643 
00644 // Test for buffer availability
00645         while(total_valid < 2 && !*timed_out && !first_frame)
00646         {
00647                 buffer_lock->unlock();
00648                 *timed_out = video_lock->timed_lock(BUFFER_TIMEOUT, 
00649                         "VDeviceV4L2Thread::read_frame 2");
00650                 buffer_lock->lock("VDeviceV4L2Thread::get_buffer 3");
00651         }
00652 
00653 // Copy frame
00654         if(total_valid >= 2)
00655         {
00656                 result = device_buffers[current_outbuffer];
00657         }
00658 
00659         buffer_lock->unlock();
00660 
00661         return result;
00662 }
00663 
00664 void VDeviceV4L2Thread::put_buffer()
00665 {
00666         buffer_lock->lock("VDeviceV4L2Thread::put_buffer");
00667         buffer_valid[current_outbuffer] = 0;
00668 
00669 // Release buffer for capturing.
00670         put_thread->put_buffer(current_outbuffer);
00671 
00672         current_outbuffer++;
00673         total_valid--;
00674         if(current_outbuffer >= total_buffers)
00675                 current_outbuffer = 0;
00676         buffer_lock->unlock();
00677 }
00678 
00679 
00680 
00681 
00682 
00683 
00684 
00685 
00686 
00687 
00688 
00689 
00690 
00691 
00692 
00693 
00694 
00695 
00696 VDeviceV4L2::VDeviceV4L2(VideoDevice *device)
00697  : VDeviceBase(device)
00698 {
00699         initialize();
00700 }
00701 
00702 VDeviceV4L2::~VDeviceV4L2()
00703 {
00704         close_all();
00705 }
00706 
00707 int VDeviceV4L2::close_all()
00708 {
00709         if(thread) delete thread;
00710         thread = 0;
00711         return 0;
00712 }
00713 
00714 
00715 int VDeviceV4L2::initialize()
00716 {
00717         thread = 0;
00718         return 0;
00719 }
00720 
00721 
00722 
00723 int VDeviceV4L2::open_input()
00724 {
00725         int result = get_sources(device,
00726                 device->in_config->v4l2_in_device);
00727         device->channel->use_frequency = 1;
00728         device->channel->use_fine = 1;
00729         return result;
00730 }
00731 
00732 int VDeviceV4L2::get_sources(VideoDevice *device,
00733         char *path)
00734 {
00735         int input_fd = -1;
00736 
00737 
00738         device->channel->use_norm = 1;
00739         device->channel->use_input = 1;
00740         if(device->in_config->driver != VIDEO4LINUX2JPEG) 
00741                 device->channel->has_scanning = 1;
00742         else
00743                 device->channel->has_scanning = 0;
00744 
00745         if((input_fd = open(path, O_RDWR)) < 0)
00746         {
00747                 perror("VDeviceV4L::open_input");
00748                 return 1;
00749         }
00750         else
00751         {
00752 // Get the inputs
00753                 int i = 0;
00754                 int done = 0;
00755                 char *new_source;
00756 
00757                 while(!done && i < 20)
00758                 {
00759                         struct v4l2_input arg;
00760                         bzero(&arg, sizeof(arg));
00761                         arg.index = i;
00762                         
00763                         if(ioctl(input_fd, VIDIOC_ENUMINPUT, &arg) < 0)
00764                         {
00765 // Finished
00766                                 done = 1;
00767                         }
00768                         else
00769                         {
00770                                 Channel *channel = device->new_input_source((char*)arg.name);
00771                                 channel->device_index = i;
00772                                 channel->tuner = arg.tuner;
00773                         }
00774                         i++;
00775                 }
00776 
00777 // Get the picture controls
00778                 for(i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++)
00779                 {
00780                         struct v4l2_queryctrl arg;
00781                         bzero(&arg, sizeof(arg));
00782                         arg.id = i;
00783 // This returns errors for unsupported controls which is what we want.
00784                         if(!ioctl(input_fd, VIDIOC_QUERYCTRL, &arg))
00785                         {
00786 // Test if control exists already
00787                                 if(!device->picture->get_item((const char*)arg.name, arg.id))
00788                                 {
00789 // Add control
00790                                         PictureItem *item = device->picture->new_item((const char*)arg.name);
00791                                         item->device_id = arg.id;
00792                                         item->min = arg.minimum;
00793                                         item->max = arg.maximum;
00794                                         item->step = arg.step;
00795                                         item->default_ = arg.default_value;
00796                                         item->type = arg.type;
00797                                         item->value = arg.default_value;
00798                                 }
00799                         }
00800                 }
00801 
00802 // Load defaults for picture controls
00803                 device->picture->load_defaults();
00804 
00805                 close(input_fd);
00806         }
00807         return 0;
00808 }
00809 
00810 int VDeviceV4L2::cmodel_to_device(int color_model)
00811 {
00812         switch(color_model)
00813         {
00814                 case BC_YUV422:
00815                         return V4L2_PIX_FMT_YUYV;
00816                         break;
00817                 case BC_YUV411P:
00818                         return V4L2_PIX_FMT_Y41P;
00819                         break;
00820                 case BC_YUV420P:
00821                         return V4L2_PIX_FMT_YVU420;
00822                         break;
00823                 case BC_YUV422P:
00824                         return V4L2_PIX_FMT_YUV422P;
00825                         break;
00826                 case BC_RGB888:
00827                         return V4L2_PIX_FMT_RGB24;
00828                         break;
00829         }
00830         return 0;
00831 }
00832 
00833 int VDeviceV4L2::get_best_colormodel(Asset *asset)
00834 {
00835         int result = BC_RGB888;
00836         result = File::get_best_colormodel(asset, device->in_config->driver);
00837         return result;
00838 }
00839 
00840 int VDeviceV4L2::has_signal()
00841 {
00842         if(thread)
00843         {
00844                 struct v4l2_tuner tuner;
00845                 if(ioctl(thread->input_fd, VIDIOC_G_TUNER, &tuner) < 0)
00846                         perror("VDeviceV4L2::has_signal VIDIOC_S_TUNER");
00847                 return tuner.signal;
00848         }
00849         return 0;
00850 }
00851 
00852 int VDeviceV4L2::read_buffer(VFrame *frame)
00853 {
00854         int result = 0;
00855 
00856         if((device->channel_changed || device->picture_changed) && thread)
00857         {
00858                 delete thread;
00859                 thread = 0;
00860         }
00861 
00862         if(!thread)
00863         {
00864                 device->channel_changed = 0;
00865                 device->picture_changed = 0;
00866                 thread = new VDeviceV4L2Thread(device, frame->get_color_model());
00867                 thread->start();
00868         }
00869 
00870 
00871 // Get buffer from thread
00872         int timed_out;
00873         VFrame *buffer = thread->get_buffer(&timed_out);
00874         if(buffer)
00875         {
00876                 frame->copy_from(buffer);
00877                 thread->put_buffer();
00878         }
00879         else
00880         {
00881 // Driver in 2.6.4 needs to be restarted when it loses sync.
00882                 if(timed_out)
00883                 {
00884                         delete thread;
00885                         thread = 0;
00886                 }
00887                 result = 1;
00888         }
00889 
00890 
00891         return result;
00892 }
00893 
00894 #endif

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