MythTV  0.26-pre
v4lrecorder.cpp
Go to the documentation of this file.
00001 // -*- Mode: c++ -*-
00002 
00003 #ifdef USING_V4L1
00004 #include <linux/videodev.h> // for vbi_format
00005 #endif // USING_V4L1
00006 
00007 #ifdef USING_V4L2
00008 #include <linux/videodev2.h>
00009 #endif // USING_V4L2
00010 
00011 #include <sys/ioctl.h>      // for ioctl
00012 #include <sys/time.h>       // for gettimeofday
00013 #include <unistd.h>         // for IO_NONBLOCK
00014 #include <fcntl.h>          // for IO_NONBLOCK
00015 
00016 #include "vbi608extractor.h"
00017 #include "mythcontext.h"
00018 #include "mythlogging.h"
00019 #include "v4lrecorder.h"
00020 #include "vbitext/vbi.h"
00021 #include "tv_rec.h"
00022 #include "tv.h" // for VBIMode
00023 
00024 #define TVREC_CARDNUM \
00025         ((tvrec != NULL) ? QString::number(tvrec->GetCaptureCardNum()) : "NULL")
00026 
00027 #define LOC      QString("V4LRec(%1:%2): ") \
00028                  .arg(TVREC_CARDNUM).arg(videodevice)
00029 
00030 V4LRecorder::V4LRecorder(TVRec *tv) :
00031     DTVRecorder(tv),          vbimode(VBIMode::None),
00032     pal_vbi_cb(NULL),         pal_vbi_tt(NULL),
00033     ntsc_vbi_width(0),        ntsc_vbi_start_line(0),
00034     ntsc_vbi_line_count(0),
00035     vbi608(NULL),
00036     vbi_thread(NULL),         vbi_fd(-1),
00037     request_helper(false)
00038 {
00039 }
00040 
00041 V4LRecorder::~V4LRecorder()
00042 {
00043     {
00044         QMutexLocker locker(&pauseLock);
00045         request_helper = false;
00046         unpauseWait.wakeAll();
00047     }
00048 
00049     if (vbi_thread)
00050     {
00051         vbi_thread->wait();
00052         delete vbi_thread;
00053         vbi_thread = NULL;
00054         CloseVBIDevice();
00055     }
00056 }
00057 
00058 void V4LRecorder::StopRecording(void)
00059 {
00060     DTVRecorder::StopRecording();
00061     while (vbi_thread && vbi_thread->isRunning())
00062         vbi_thread->wait();
00063 }
00064 
00065 bool V4LRecorder::IsHelperRequested(void) const
00066 {
00067     QMutexLocker locker(&pauseLock);
00068     return request_helper && request_recording;
00069 }
00070 
00071 void V4LRecorder::SetOption(const QString &name, const QString &value)
00072 {
00073     if (name == "audiodevice")
00074         audiodevice = value;
00075     else if (name == "vbidevice")
00076         vbidevice = value;
00077     else if (name == "vbiformat")
00078         vbimode = VBIMode::Parse(value);
00079     else
00080         DTVRecorder::SetOption(name, value);
00081 }
00082 
00083 static void vbi_event(struct VBIData *data, struct vt_event *ev)
00084 {
00085     switch (ev->type)
00086     {
00087        case EV_PAGE:
00088        {
00089             struct vt_page *vtp = (struct vt_page *) ev->p1;
00090             if (vtp->flags & PG_SUBTITLE)
00091             {
00092 #if 0
00093                 LOG(VB_GENERAL, LOG_DEBUG, QString("subtitle page %1.%2")
00094                       .arg(vtp->pgno, 0, 16) .arg(vtp->subno, 0, 16));
00095 #endif
00096                 data->foundteletextpage = true;
00097                 memcpy(&(data->teletextpage), vtp, sizeof(vt_page));
00098             }
00099        }
00100 
00101        case EV_HEADER:
00102        case EV_XPACKET:
00103            break;
00104     }
00105 }
00106 
00107 int V4LRecorder::OpenVBIDevice(void)
00108 {
00109     int fd = -1;
00110     if (vbi_fd >= 0)
00111         return vbi_fd;
00112 
00113     struct VBIData *vbi_cb = NULL;
00114     struct vbi     *pal_tt = NULL;
00115     uint width = 0, start_line = 0, line_count = 0;
00116 
00117     QByteArray vbidev = vbidevice.toAscii();
00118     if (VBIMode::PAL_TT == vbimode)
00119     {
00120         pal_tt = vbi_open(vbidev.constData(), NULL, 99, -1);
00121         if (pal_tt)
00122         {
00123             fd = pal_tt->fd;
00124             vbi_cb = new VBIData;
00125             memset(vbi_cb, 0, sizeof(VBIData));
00126             vbi_cb->nvr = this;
00127             vbi_add_handler(pal_tt, (void*) vbi_event, vbi_cb);
00128         }
00129     }
00130     else if (VBIMode::NTSC_CC == vbimode)
00131     {
00132         fd = open(vbidev.constData(), O_RDONLY/*|O_NONBLOCK*/);
00133     }
00134     else
00135     {
00136         LOG(VB_GENERAL, LOG_ERR, LOC + "Invalid CC/Teletext mode");
00137         return -1;
00138     }
00139 
00140     if (fd < 0)
00141     {
00142         LOG(VB_GENERAL, LOG_ERR, LOC +
00143             QString("Can't open vbi device: '%1'").arg(vbidevice));
00144         return -1;
00145     }
00146 
00147     if (VBIMode::NTSC_CC == vbimode)
00148     {
00149 #ifdef USING_V4L2
00150         struct v4l2_format fmt;
00151         memset(&fmt, 0, sizeof(fmt));
00152         fmt.type = V4L2_BUF_TYPE_VBI_CAPTURE;
00153         if (0 != ioctl(fd, VIDIOC_G_FMT, &fmt))
00154         {
00155 #ifdef USING_V4L1
00156             LOG(VB_RECORD, LOG_INFO, "V4L2 VBI setup failed, trying v1 ioctl");
00157             // Try V4L v1 VBI ioctls, iff V4L v2 fails
00158             struct vbi_format old_fmt;
00159             memset(&old_fmt, 0, sizeof(vbi_format));
00160             if (ioctl(fd, VIDIOCGVBIFMT, &old_fmt) < 0)
00161             {
00162                 LOG(VB_GENERAL, LOG_ERR, LOC +
00163                     "Failed to query vbi capabilities (V4L1)");
00164                 close(fd);
00165                 return -1;
00166             }
00167             fmt.fmt.vbi.sampling_rate    = old_fmt.sampling_rate;
00168             fmt.fmt.vbi.offset           = 0;
00169             fmt.fmt.vbi.samples_per_line = old_fmt.samples_per_line;
00170             fmt.fmt.vbi.start[0]         = old_fmt.start[0];
00171             fmt.fmt.vbi.start[1]         = old_fmt.start[1];
00172             fmt.fmt.vbi.count[0]         = old_fmt.count[0];
00173             fmt.fmt.vbi.count[1]         = old_fmt.count[1];
00174             fmt.fmt.vbi.flags            = old_fmt.flags;
00175 #else // if !USING_V4L1
00176             LOG(VB_RECORD, LOG_ERR, "V4L2 VBI setup failed");
00177             close(fd);
00178             return -1;
00179 #endif // !USING_V4L1
00180         }
00181         LOG(VB_RECORD, LOG_INFO, LOC +
00182             QString("vbi_format  rate: %1"
00183                     "\n\t\t\t          offset: %2"
00184                     "\n\t\t\tsamples_per_line: %3"
00185                     "\n\t\t\t          starts: %4, %5"
00186                     "\n\t\t\t          counts: %6, %7"
00187                     "\n\t\t\t           flags: 0x%8")
00188                 .arg(fmt.fmt.vbi.sampling_rate)
00189                 .arg(fmt.fmt.vbi.offset)
00190                 .arg(fmt.fmt.vbi.samples_per_line)
00191                 .arg(fmt.fmt.vbi.start[0])
00192                 .arg(fmt.fmt.vbi.start[1])
00193                 .arg(fmt.fmt.vbi.count[0])
00194                 .arg(fmt.fmt.vbi.count[1])
00195                 .arg(fmt.fmt.vbi.flags,0,16));
00196 
00197         width      = fmt.fmt.vbi.samples_per_line;
00198         start_line = fmt.fmt.vbi.start[0];
00199         line_count = fmt.fmt.vbi.count[0];
00200         if (line_count != fmt.fmt.vbi.count[1])
00201         {
00202             LOG(VB_GENERAL, LOG_ERR, LOC +
00203                     "VBI must have the same number of "
00204                     "odd and even fields for our decoder");
00205             close(fd);
00206             return -1;
00207         }
00208         if (start_line > 21 || start_line + line_count < 22)
00209         {
00210             LOG(VB_GENERAL, LOG_ERR, LOC + "VBI does not include line 21");
00211             // TODO We could try to set the VBI format ourselves..
00212             close(fd);
00213             return -1;
00214         }
00215 #endif // USING_V4L2
00216     }
00217 
00218     if (VBIMode::PAL_TT == vbimode)
00219     {
00220         pal_vbi_cb = vbi_cb;
00221         pal_vbi_tt = pal_tt;
00222     }
00223     else if (VBIMode::NTSC_CC == vbimode)
00224     {
00225         ntsc_vbi_width      = width;
00226         ntsc_vbi_start_line = start_line;
00227         ntsc_vbi_line_count = line_count;
00228         vbi608 = new VBI608Extractor();
00229     }
00230 
00231     vbi_fd = fd;
00232 
00233     return fd;
00234 }
00235 
00236 void V4LRecorder::CloseVBIDevice(void)
00237 {
00238     if (vbi_fd < 0)
00239         return;
00240 
00241     if (pal_vbi_tt)
00242     {
00243         vbi_del_handler(pal_vbi_tt, (void*) vbi_event, pal_vbi_cb);
00244         vbi_close(pal_vbi_tt);
00245         delete pal_vbi_cb;
00246         pal_vbi_cb = NULL;
00247     }
00248     else
00249     {
00250         delete vbi608; vbi608 = NULL;
00251         close(vbi_fd);
00252     }
00253 
00254     vbi_fd = -1;
00255 }
00256 
00257 void V4LRecorder::RunVBIDevice(void)
00258 {
00259     if (vbi_fd < 0)
00260         return;
00261 
00262     unsigned char *buf = NULL, *ptr = NULL, *ptr_end = NULL;
00263     if (ntsc_vbi_width)
00264     {
00265         uint sz   = ntsc_vbi_width * ntsc_vbi_line_count * 2;
00266         buf = ptr = new unsigned char[sz];
00267         ptr_end   = buf + sz;
00268     }
00269 
00270     while (IsHelperRequested() && !IsErrored())
00271     {
00272         if (PauseAndWait())
00273             continue;
00274 
00275         if (!IsHelperRequested() || IsErrored())
00276             break;
00277 
00278         struct timeval tv;
00279         fd_set rdset;
00280 
00281         tv.tv_sec = 0;
00282         tv.tv_usec = 5000;
00283         FD_ZERO(&rdset);
00284         FD_SET(vbi_fd, &rdset);
00285 
00286         int nr = select(vbi_fd + 1, &rdset, 0, 0, &tv);
00287         if (nr < 0)
00288             LOG(VB_GENERAL, LOG_ERR, LOC + "vbi select failed" + ENO);
00289 
00290         if (nr <= 0)
00291         {
00292             if (nr==0)
00293                 LOG(VB_GENERAL, LOG_DEBUG, LOC + "vbi select timed out");
00294             continue; // either failed or timed out..
00295         }
00296         if (VBIMode::PAL_TT == vbimode)
00297         {
00298             pal_vbi_cb->foundteletextpage = false;
00299             vbi_handler(pal_vbi_tt, pal_vbi_tt->fd);
00300             if (pal_vbi_cb->foundteletextpage)
00301             {
00302                 // decode VBI as teletext subtitles
00303                 FormatTT(pal_vbi_cb);
00304             }
00305         }
00306         else if (VBIMode::NTSC_CC == vbimode)
00307         {
00308             int ret = read(vbi_fd, ptr, ptr_end - ptr);
00309             ptr = (ret > 0) ? ptr + ret : ptr;
00310             if ((ptr_end - ptr) == 0)
00311             {
00312                 unsigned char *line21_field1 =
00313                     buf + ((21 - ntsc_vbi_start_line) * ntsc_vbi_width);
00314                 unsigned char *line21_field2 =
00315                     buf + ((ntsc_vbi_line_count + 21 - ntsc_vbi_start_line)
00316                            * ntsc_vbi_width);
00317                 bool cc1 = vbi608->ExtractCC12(line21_field1, ntsc_vbi_width);
00318                 bool cc2 = vbi608->ExtractCC34(line21_field2, ntsc_vbi_width);
00319                 if (cc1 || cc2)
00320                 {
00321                     int code1 = vbi608->GetCode1();
00322                     int code2 = vbi608->GetCode2();
00323                     code1 = (0xFFFF==code1) ? -1 : code1;
00324                     code2 = (0xFFFF==code2) ? -1 : code2;
00325                     FormatCC(code1, code2);
00326                 }
00327                 ptr = buf;
00328             }
00329             else if (ret < 0)
00330             {
00331                 LOG(VB_GENERAL, LOG_ERR, LOC + "Reading VBI data" + ENO);
00332             }
00333         }
00334     }
00335 
00336     if (buf)
00337         delete [] buf;
00338 }
00339 
00340 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends