|
MythTV
0.26-pre
|
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: */
1.7.6.1