MythTV  master
v4lrecorder.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 #ifdef USING_V4L1
4 #include <linux/videodev.h> // for vbi_format
5 #endif // USING_V4L1
6 
7 #ifdef USING_V4L2
8 #include <linux/videodev2.h>
9 #endif // USING_V4L2
10 
11 #include <sys/ioctl.h> // for ioctl
12 #include <sys/time.h> // for gettimeofday
13 #include <unistd.h> // for IO_NONBLOCK
14 #include <fcntl.h> // for IO_NONBLOCK
15 
16 #include "vbi608extractor.h"
17 #include "mythcontext.h"
18 #include "mythlogging.h"
19 #include "v4lrecorder.h"
20 #include "vbitext/vbi.h"
21 #include "tv_rec.h"
22 #include "tv.h" // for VBIMode
23 
24 #define TVREC_CARDNUM \
25  ((tvrec != nullptr) ? QString::number(tvrec->GetInputId()) : "NULL")
26 
27 #define LOC QString("V4LRec[%1](%2): ") \
28  .arg(TVREC_CARDNUM).arg(videodevice)
29 
31  DTVRecorder(tv), vbimode(VBIMode::None),
32  pal_vbi_cb(nullptr), pal_vbi_tt(nullptr),
33  ntsc_vbi_width(0), ntsc_vbi_start_line(0),
34  ntsc_vbi_line_count(0),
35  vbi608(nullptr),
36  vbi_thread(nullptr), vbi_fd(-1),
37  request_helper(false)
38 {
39 }
40 
42 {
43  {
44  QMutexLocker locker(&pauseLock);
45  request_helper = false;
46  unpauseWait.wakeAll();
47  }
48 
49  if (vbi_thread)
50  {
51  vbi_thread->wait();
52  delete vbi_thread;
53  vbi_thread = nullptr;
55  }
56 }
57 
59 {
61  while (vbi_thread && vbi_thread->isRunning())
62  vbi_thread->wait();
63 }
64 
66 {
67  QMutexLocker locker(&pauseLock);
69 }
70 
71 void V4LRecorder::SetOption(const QString &name, const QString &value)
72 {
73  if (name == "audiodevice")
74  audiodevice = value;
75  else if (name == "vbidevice")
76  vbidevice = value;
77  else if (name == "vbiformat")
78  vbimode = VBIMode::Parse(value);
79  else
81 }
82 
83 static void vbi_event(struct VBIData *data, struct vt_event *ev)
84 {
85  switch (ev->type)
86  {
87  case EV_PAGE:
88  {
89  struct vt_page *vtp = (struct vt_page *) ev->p1;
90  if (vtp->flags & PG_SUBTITLE)
91  {
92 #if 0
93  LOG(VB_GENERAL, LOG_DEBUG, QString("subtitle page %1.%2")
94  .arg(vtp->pgno, 0, 16) .arg(vtp->subno, 0, 16));
95 #endif
96  data->foundteletextpage = true;
97  memcpy(&(data->teletextpage), vtp, sizeof(vt_page));
98  }
99  }
100  break;
101 
102  case EV_HEADER:
103  case EV_XPACKET:
104  break;
105  }
106 }
107 
109 {
110  int fd = -1;
111  if (vbi_fd >= 0)
112  return vbi_fd;
113 
114  struct VBIData *vbi_cb = nullptr;
115  struct vbi *pal_tt = nullptr;
116  uint width = 0, start_line = 0, line_count = 0;
117 
118  QByteArray vbidev = vbidevice.toLatin1();
119  if (VBIMode::PAL_TT == vbimode)
120  {
121  pal_tt = vbi_open(vbidev.constData(), nullptr, 99, -1);
122  if (pal_tt)
123  {
124  fd = pal_tt->fd;
125  vbi_cb = new VBIData;
126  memset(vbi_cb, 0, sizeof(VBIData));
127  vbi_cb->nvr = this;
128  vbi_add_handler(pal_tt, (void*) vbi_event, vbi_cb);
129  }
130  }
131  else if (VBIMode::NTSC_CC == vbimode)
132  {
133  fd = open(vbidev.constData(), O_RDONLY/*|O_NONBLOCK*/);
134  }
135  else
136  {
137  LOG(VB_GENERAL, LOG_ERR, LOC + "Invalid CC/Teletext mode");
138  return -1;
139  }
140 
141  if (fd < 0)
142  {
143  LOG(VB_GENERAL, LOG_ERR, LOC +
144  QString("Can't open vbi device: '%1'").arg(vbidevice));
145  return -1;
146  }
147 
148  if (VBIMode::NTSC_CC == vbimode)
149  {
150 #ifdef USING_V4L2
151  struct v4l2_format fmt;
152  memset(&fmt, 0, sizeof(fmt));
153  fmt.type = V4L2_BUF_TYPE_VBI_CAPTURE;
154  if (0 != ioctl(fd, VIDIOC_G_FMT, &fmt))
155  {
156 #ifdef USING_V4L1
157  LOG(VB_RECORD, LOG_INFO, "V4L2 VBI setup failed, trying v1 ioctl");
158  // Try V4L v1 VBI ioctls, iff V4L v2 fails
159  struct vbi_format old_fmt;
160  memset(&old_fmt, 0, sizeof(vbi_format));
161  if (ioctl(fd, VIDIOCGVBIFMT, &old_fmt) < 0)
162  {
163  LOG(VB_GENERAL, LOG_ERR, LOC +
164  "Failed to query vbi capabilities (V4L1)");
165  close(fd);
166  return -1;
167  }
168  fmt.fmt.vbi.sampling_rate = old_fmt.sampling_rate;
169  fmt.fmt.vbi.offset = 0;
170  fmt.fmt.vbi.samples_per_line = old_fmt.samples_per_line;
171  fmt.fmt.vbi.start[0] = old_fmt.start[0];
172  fmt.fmt.vbi.start[1] = old_fmt.start[1];
173  fmt.fmt.vbi.count[0] = old_fmt.count[0];
174  fmt.fmt.vbi.count[1] = old_fmt.count[1];
175  fmt.fmt.vbi.flags = old_fmt.flags;
176 #else // if !USING_V4L1
177  LOG(VB_RECORD, LOG_ERR, "V4L2 VBI setup failed");
178  close(fd);
179  return -1;
180 #endif // !USING_V4L1
181  }
182  LOG(VB_RECORD, LOG_INFO, LOC +
183  QString("vbi_format rate: %1"
184  "\n\t\t\t offset: %2"
185  "\n\t\t\tsamples_per_line: %3"
186  "\n\t\t\t starts: %4, %5"
187  "\n\t\t\t counts: %6, %7"
188  "\n\t\t\t flags: 0x%8")
189  .arg(fmt.fmt.vbi.sampling_rate)
190  .arg(fmt.fmt.vbi.offset)
191  .arg(fmt.fmt.vbi.samples_per_line)
192  .arg(fmt.fmt.vbi.start[0])
193  .arg(fmt.fmt.vbi.start[1])
194  .arg(fmt.fmt.vbi.count[0])
195  .arg(fmt.fmt.vbi.count[1])
196  .arg(fmt.fmt.vbi.flags,0,16));
197 
198  width = fmt.fmt.vbi.samples_per_line;
199  start_line = fmt.fmt.vbi.start[0];
200  line_count = fmt.fmt.vbi.count[0];
201  if (line_count != fmt.fmt.vbi.count[1])
202  {
203  LOG(VB_GENERAL, LOG_ERR, LOC +
204  "VBI must have the same number of "
205  "odd and even fields for our decoder");
206  close(fd);
207  return -1;
208  }
209  if (start_line > 21 || start_line + line_count < 22)
210  {
211  LOG(VB_GENERAL, LOG_ERR, LOC + "VBI does not include line 21");
212  // TODO We could try to set the VBI format ourselves..
213  close(fd);
214  return -1;
215  }
216 #endif // USING_V4L2
217  }
218 
219  if (VBIMode::PAL_TT == vbimode)
220  {
221  pal_vbi_cb = vbi_cb;
222  pal_vbi_tt = pal_tt;
223  }
224  else if (VBIMode::NTSC_CC == vbimode)
225  {
226  ntsc_vbi_width = width;
227  ntsc_vbi_start_line = start_line;
228  ntsc_vbi_line_count = line_count;
229  vbi608 = new VBI608Extractor();
230  }
231 
232  vbi_fd = fd;
233 
234  return fd;
235 }
236 
238 {
239  if (vbi_fd < 0)
240  return;
241 
242  if (pal_vbi_tt)
243  {
246  delete pal_vbi_cb;
247  pal_vbi_cb = nullptr;
248  }
249  else
250  {
251  delete vbi608; vbi608 = nullptr;
252  close(vbi_fd);
253  }
254 
255  vbi_fd = -1;
256 }
257 
259 {
260  if (vbi_fd < 0)
261  return;
262 
263  unsigned char *buf = nullptr, *ptr = nullptr, *ptr_end = nullptr;
264  if (ntsc_vbi_width)
265  {
267  buf = ptr = new unsigned char[sz];
268  ptr_end = buf + sz;
269  }
270 
271  while (IsHelperRequested() && !IsErrored())
272  {
273  if (PauseAndWait())
274  continue;
275 
276  if (!IsHelperRequested() || IsErrored())
277  break;
278 
279  struct timeval tv;
280  fd_set rdset;
281 
282  tv.tv_sec = 0;
283  tv.tv_usec = 5000;
284  FD_ZERO(&rdset);
285  FD_SET(vbi_fd, &rdset);
286 
287  int nr = select(vbi_fd + 1, &rdset, nullptr, nullptr, &tv);
288  if (nr < 0)
289  LOG(VB_GENERAL, LOG_ERR, LOC + "vbi select failed" + ENO);
290 
291  if (nr <= 0)
292  {
293  if (nr==0)
294  LOG(VB_GENERAL, LOG_DEBUG, LOC + "vbi select timed out");
295  continue; // either failed or timed out..
296  }
297  if (VBIMode::PAL_TT == vbimode)
298  {
299  pal_vbi_cb->foundteletextpage = false;
302  {
303  // decode VBI as teletext subtitles
305  }
306  }
307  else if (VBIMode::NTSC_CC == vbimode)
308  {
309  int ret = read(vbi_fd, ptr, ptr_end - ptr);
310  ptr = (ret > 0) ? ptr + ret : ptr;
311  if ((ptr_end - ptr) == 0)
312  {
313  unsigned char *line21_field1 =
314  buf + ((21 - ntsc_vbi_start_line) * ntsc_vbi_width);
315  unsigned char *line21_field2 =
317  * ntsc_vbi_width);
318  bool cc1 = vbi608->ExtractCC12(line21_field1, ntsc_vbi_width);
319  bool cc2 = vbi608->ExtractCC34(line21_field2, ntsc_vbi_width);
320  if (cc1 || cc2)
321  {
322  int code1 = vbi608->GetCode1();
323  int code2 = vbi608->GetCode2();
324  code1 = (0xFFFF==code1) ? -1 : code1;
325  code2 = (0xFFFF==code2) ? -1 : code2;
326  FormatCC(code1, code2);
327  }
328  ptr = buf;
329  }
330  else if (ret < 0)
331  {
332  LOG(VB_GENERAL, LOG_ERR, LOC + "Reading VBI data" + ENO);
333  }
334  }
335  }
336 
337  if (buf)
338  delete [] buf;
339 }
340 
341 /* vim: set expandtab tabstop=4 shiftwidth=4: */
void RunVBIDevice(void)
This is a specialization of RecorderBase used to handle MPEG-2, MPEG-4, MPEG-4 AVC,...
Definition: dtvrecorder.h:28
QWaitCondition unpauseWait
Definition: recorderbase.h:323
void SetOption(const QString &name, const QString &value) override
Set an specific option.
Definition: v4lrecorder.cpp:71
int pgno
Definition: vt.h:38
volatile bool request_helper
Definition: v4lrecorder.h:57
QMutex pauseLock
Definition: recorderbase.h:319
#define EV_PAGE
Definition: vt.h:20
vbimode
Definition: vbilut.h:20
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:312
#define EV_HEADER
Definition: vt.h:21
uint ntsc_vbi_start_line
Definition: v4lrecorder.h:51
struct vbi * vbi_open(const char *vbi_name, struct cache *ca, int fine_tune, int big_buf)
Definition: vbi.c:607
void CloseVBIDevice(void)
unsigned int uint
Definition: compat.h:140
bool IsErrored(void) override
Tells us whether an unrecoverable error has been encountered.
Definition: dtvrecorder.h:48
virtual bool PauseAndWait(int timeout=100)
If request_pause is true, sets pause and blocks up to timeout milliseconds or until unpaused,...
uint ntsc_vbi_width
Definition: v4lrecorder.h:50
QString vbidevice
Definition: v4lrecorder.h:46
virtual ~V4LRecorder()
Definition: v4lrecorder.cpp:41
Definition: tv.h:6
struct VBIData * pal_vbi_cb
Definition: v4lrecorder.h:48
virtual bool IsHelperRequested(void) const
Definition: v4lrecorder.cpp:65
struct vbi * pal_vbi_tt
Definition: v4lrecorder.h:49
uint16_t GetCode1(void) const
def read(device=None, features=[])
Definition: disc.py:35
Definition: vt.h:36
uint ntsc_vbi_line_count
Definition: v4lrecorder.h:52
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
int OpenVBIDevice(void)
RecorderBase * nvr
Definition: v4lrecorder.h:17
#define close
Definition: compat.h:16
int flags
Definition: vt.h:40
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:150
bool request_recording
True if API call has requested a recording be [re]started.
Definition: recorderbase.h:325
QString audiodevice
Definition: v4lrecorder.h:45
void SetOption(const QString &opt, const QString &value) override
Set an specific option.
bool isRunning(void) const
Definition: mthread.cpp:275
const char * name
Definition: ParseText.cpp:339
Definition: vt.h:8
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:99
virtual void FormatTT(struct VBIData *)
Definition: v4lrecorder.h:41
unsigned char data[VT_HEIGHT][VT_WIDTH]
Definition: vt.h:43
void StopRecording(void) override
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
Definition: v4lrecorder.cpp:58
#define LOC
Definition: v4lrecorder.cpp:27
V4LRecorder(TVRec *rec)
Definition: v4lrecorder.cpp:30
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void vbi_handler(struct vbi *vbi, int fd)
Definition: vbi.c:400
bool foundteletextpage
Definition: v4lrecorder.h:19
bool ExtractCC12(const unsigned char *buf, uint width)
#define EV_XPACKET
Definition: vt.h:22
uint16_t GetCode2(void) const
Definition: vbi.h:21
virtual void StopRecording(void)
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
int subno
Definition: vt.h:38
VBIThread * vbi_thread
Definition: v4lrecorder.h:54
bool ExtractCC34(const unsigned char *buf, uint width)
int vbi_add_handler(struct vbi *vbi, void *handler, void *data)
Definition: vbi.c:443
int type
Definition: vt.h:10
#define PG_SUBTITLE
Definition: vt.h:58
static uint Parse(QString vbiformat)
Definition: tv.h:16
VBI608Extractor * vbi608
Definition: v4lrecorder.h:53
int fd
Definition: vbi.h:23
void vbi_del_handler(struct vbi *vbi, void *handler, void *data)
Definition: vbi.c:461
void * p1
Definition: vt.h:13
void vbi_close(struct vbi *vbi)
Definition: vbi.c:658
static void vbi_event(struct VBIData *data, struct vt_event *ev)
Definition: v4lrecorder.cpp:83
virtual void FormatCC(uint, uint)
Definition: v4lrecorder.h:42