00001
00002
00003 #ifdef USING_V4L1
00004 #include <linux/videodev.h>
00005 #endif // USING_V4L1
00006
00007 #ifdef USING_V4L2
00008 #include <linux/videodev2.h>
00009 #endif // USING_V4L2
00010
00011 #include <sys/ioctl.h>
00012 #include <sys/time.h>
00013 #include <unistd.h>
00014 #include <fcntl.h>
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"
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);
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
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
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;
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
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