vdr  2.0.4
dvbsdffdevice.c
Go to the documentation of this file.
1 /*
2  * dvbsdffdevice.h: The DVB SD Full Featured device interface
3  *
4  * See the README file for copyright information and how to reach the author.
5  *
6  * $Id: dvbsdffdevice.c 2.35 2013/02/17 13:16:18 kls Exp $
7  */
8 
9 #include "dvbsdffdevice.h"
10 #include <errno.h>
11 #include <limits.h>
12 #include <linux/videodev2.h>
13 #include <linux/dvb/audio.h>
14 #include <linux/dvb/dmx.h>
15 #include <linux/dvb/video.h>
16 #include <sys/ioctl.h>
17 #include <sys/mman.h>
18 #include <vdr/eitscan.h>
19 #include <vdr/transfer.h>
20 #include "dvbsdffosd.h"
21 
22 // --- cDvbSdFfDevice --------------------------------------------------------
23 
25 
26 cDvbSdFfDevice::cDvbSdFfDevice(int Adapter, int Frontend, bool OutputOnly)
27 :cDvbDevice(Adapter, Frontend)
28 {
29  spuDecoder = NULL;
30  digitalAudio = false;
31  playMode = pmNone;
32  outputOnly = OutputOnly;
33 
34  // Devices that are only present on cards with decoders:
35 
37  fd_video = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDWR | O_NONBLOCK);
38  fd_audio = DvbOpen(DEV_DVB_AUDIO, adapter, frontend, O_RDWR | O_NONBLOCK);
40 
41  // The offset of the /dev/video devices:
42 
43  if (devVideoOffset < 0) { // the first one checks this
44  FILE *f = NULL;
45  char buffer[PATH_MAX];
46  for (int ofs = 0; ofs < 100; ofs++) {
47  snprintf(buffer, sizeof(buffer), "/proc/video/dev/video%d", ofs);
48  if ((f = fopen(buffer, "r")) != NULL) {
49  if (fgets(buffer, sizeof(buffer), f)) {
50  if (strstr(buffer, "DVB Board")) { // found the _first_ DVB card
51  devVideoOffset = ofs;
52  dsyslog("video device offset is %d", devVideoOffset);
53  break;
54  }
55  }
56  else
57  break;
58  fclose(f);
59  }
60  else
61  break;
62  }
63  if (devVideoOffset < 0)
64  devVideoOffset = 0;
65  if (f)
66  fclose(f);
67  }
69 }
70 
72 {
73  delete spuDecoder;
74  // We're not explicitly closing any device files here, since this sometimes
75  // caused segfaults. Besides, the program is about to terminate anyway...
76 }
77 
79 {
80  if (On)
83 }
84 
86 {
87  return true;
88 }
89 
91 {
92  return true;
93 }
94 
96 {
97  if (!spuDecoder && IsPrimaryDevice())
98  spuDecoder = new cDvbSpuDecoder();
99  return spuDecoder;
100 }
101 
102 uchar *cDvbSdFfDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
103 {
104  if (devVideoIndex < 0)
105  return NULL;
106  char buffer[PATH_MAX];
107  snprintf(buffer, sizeof(buffer), "%s%d", DEV_VIDEO, devVideoIndex);
108  int videoDev = open(buffer, O_RDWR);
109  if (videoDev >= 0) {
110  uchar *result = NULL;
111  // set up the size and RGB
112  v4l2_format fmt;
113  memset(&fmt, 0, sizeof(fmt));
114  fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
115  fmt.fmt.pix.width = SizeX;
116  fmt.fmt.pix.height = SizeY;
117  fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
118  fmt.fmt.pix.field = V4L2_FIELD_ANY;
119  if (ioctl(videoDev, VIDIOC_S_FMT, &fmt) == 0) {
120  v4l2_requestbuffers reqBuf;
121  memset(&reqBuf, 0, sizeof(reqBuf));
122  reqBuf.count = 2;
123  reqBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
124  reqBuf.memory = V4L2_MEMORY_MMAP;
125  if (ioctl(videoDev, VIDIOC_REQBUFS, &reqBuf) >= 0) {
126  v4l2_buffer mbuf;
127  memset(&mbuf, 0, sizeof(mbuf));
128  mbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
129  mbuf.memory = V4L2_MEMORY_MMAP;
130  if (ioctl(videoDev, VIDIOC_QUERYBUF, &mbuf) == 0) {
131  int msize = mbuf.length;
132  unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0);
133  if (mem && mem != (unsigned char *)-1) {
134  v4l2_buffer buf;
135  memset(&buf, 0, sizeof(buf));
136  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
137  buf.memory = V4L2_MEMORY_MMAP;
138  buf.index = 0;
139  if (ioctl(videoDev, VIDIOC_QBUF, &buf) == 0) {
140  v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
141  if (ioctl (videoDev, VIDIOC_STREAMON, &type) == 0) {
142  memset(&buf, 0, sizeof(buf));
143  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
144  buf.memory = V4L2_MEMORY_MMAP;
145  buf.index = 0;
146  if (ioctl(videoDev, VIDIOC_DQBUF, &buf) == 0) {
147  if (ioctl(videoDev, VIDIOC_STREAMOFF, &type) == 0) {
148  // make RGB out of BGR:
149  int memsize = fmt.fmt.pix.width * fmt.fmt.pix.height;
150  unsigned char *mem1 = mem;
151  for (int i = 0; i < memsize; i++) {
152  unsigned char tmp = mem1[2];
153  mem1[2] = mem1[0];
154  mem1[0] = tmp;
155  mem1 += 3;
156  }
157 
158  if (Quality < 0)
159  Quality = 100;
160 
161  dsyslog("grabbing to %s %d %d %d", Jpeg ? "JPEG" : "PNM", Quality, fmt.fmt.pix.width, fmt.fmt.pix.height);
162  if (Jpeg) {
163  // convert to JPEG:
164  result = RgbToJpeg(mem, fmt.fmt.pix.width, fmt.fmt.pix.height, Size, Quality);
165  if (!result)
166  esyslog("ERROR: failed to convert image to JPEG");
167  }
168  else {
169  // convert to PNM:
170  char buf[32];
171  snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
172  int l = strlen(buf);
173  int bytes = memsize * 3;
174  Size = l + bytes;
175  result = MALLOC(uchar, Size);
176  if (result) {
177  memcpy(result, buf, l);
178  memcpy(result + l, mem, bytes);
179  }
180  else
181  esyslog("ERROR: failed to convert image to PNM");
182  }
183  }
184  else
185  esyslog("ERROR: video device VIDIOC_STREAMOFF failed");
186  }
187  else
188  esyslog("ERROR: video device VIDIOC_DQBUF failed");
189  }
190  else
191  esyslog("ERROR: video device VIDIOC_STREAMON failed");
192  }
193  else
194  esyslog("ERROR: video device VIDIOC_QBUF failed");
195  munmap(mem, msize);
196  }
197  else
198  esyslog("ERROR: failed to memmap video device");
199  }
200  else
201  esyslog("ERROR: video device VIDIOC_QUERYBUF failed");
202  }
203  else
204  esyslog("ERROR: video device VIDIOC_REQBUFS failed");
205  }
206  else
207  esyslog("ERROR: video device VIDIOC_S_FMT failed");
208  close(videoDev);
209  return result;
210  }
211  else
212  LOG_ERROR_STR(buffer);
213  return NULL;
214 }
215 
217 {
218  cDevice::SetVideoDisplayFormat(VideoDisplayFormat);
219  if (Setup.VideoFormat) {
220  CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_LETTER_BOX));
221  }
222  else {
223  switch (VideoDisplayFormat) {
224  case vdfPanAndScan:
225  CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_PAN_SCAN));
226  break;
227  case vdfLetterBox:
228  CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_LETTER_BOX));
229  break;
230  case vdfCenterCutOut:
231  CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_CENTER_CUT_OUT));
232  break;
233  default: esyslog("ERROR: unknown video display format %d", VideoDisplayFormat);
234  }
235  }
236 }
237 
238 void cDvbSdFfDevice::SetVideoFormat(bool VideoFormat16_9)
239 {
240  CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, VideoFormat16_9 ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3));
242 }
243 
245 {
246  eVideoSystem VideoSystem = vsPAL;
247  if (fd_video >= 0) {
248  video_size_t vs;
249  if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
250  if (vs.h == 480 || vs.h == 240)
251  VideoSystem = vsNTSC;
252  }
253  else
254  LOG_ERROR;
255  }
256  return VideoSystem;
257 }
258 
259 void cDvbSdFfDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect)
260 {
261  if (fd_video >= 0) {
262  video_size_t vs;
263  if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
264  Width = vs.w;
265  Height = vs.h;
266  switch (vs.aspect_ratio) {
267  default:
268  case VIDEO_FORMAT_4_3: VideoAspect = 4.0 / 3.0; break;
269  case VIDEO_FORMAT_16_9: VideoAspect = 16.0 / 9.0; break;
270  case VIDEO_FORMAT_221_1: VideoAspect = 2.21; break;
271  }
272  return;
273  }
274  else
275  LOG_ERROR;
276  }
277  cDevice::GetVideoSize(Width, Height, VideoAspect);
278 }
279 
280 void cDvbSdFfDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
281 {
282  if (fd_video >= 0) {
283  video_size_t vs;
284  if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
285  Width = 720;
286  if (vs.h != 480 && vs.h != 240)
287  Height = 576; // PAL
288  else
289  Height = 480; // NTSC
290  switch (Setup.VideoFormat ? vs.aspect_ratio : VIDEO_FORMAT_4_3) {
291  default:
292  case VIDEO_FORMAT_4_3: PixelAspect = 4.0 / 3.0; break;
293  case VIDEO_FORMAT_221_1: // FF DVB cards only distinguish between 4:3 and 16:9
294  case VIDEO_FORMAT_16_9: PixelAspect = 16.0 / 9.0; break;
295  }
296  PixelAspect /= double(Width) / Height;
297  return;
298  }
299  else
300  LOG_ERROR;
301  }
302  cDevice::GetOsdSize(Width, Height, PixelAspect);
303 }
304 
306 {
308  return false;
309  return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0;
310 }
311 
312 // ptAudio ptVideo ptPcr ptTeletext ptDolby ptOther
313 static dmx_pes_type_t PesTypes[] = { DMX_PES_AUDIO, DMX_PES_VIDEO, DMX_PES_PCR, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER };
314 
315 bool cDvbSdFfDevice::SetPid(cPidHandle *Handle, int Type, bool On)
316 {
317  if (Handle->pid) {
318  dmx_pes_filter_params pesFilterParams;
319  memset(&pesFilterParams, 0, sizeof(pesFilterParams));
320  if (On) {
321  if (Handle->handle < 0) {
322  Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
323  if (Handle->handle < 0) {
324  LOG_ERROR;
325  return false;
326  }
327  }
328  pesFilterParams.pid = Handle->pid;
329  pesFilterParams.input = DMX_IN_FRONTEND;
330  pesFilterParams.output = (Type <= ptTeletext && Handle->used <= 1) ? DMX_OUT_DECODER : DMX_OUT_TS_TAP;
331  pesFilterParams.pes_type= PesTypes[Type < ptOther ? Type : ptOther];
332  pesFilterParams.flags = DMX_IMMEDIATE_START;
333  if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
334  LOG_ERROR;
335  return false;
336  }
337  }
338  else if (!Handle->used) {
339  CHECK(ioctl(Handle->handle, DMX_STOP));
340  if (Type <= ptTeletext) {
341  pesFilterParams.pid = 0x1FFF;
342  pesFilterParams.input = DMX_IN_FRONTEND;
343  pesFilterParams.output = DMX_OUT_DECODER;
344  pesFilterParams.pes_type= PesTypes[Type];
345  pesFilterParams.flags = DMX_IMMEDIATE_START;
346  CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams));
347  if (PesTypes[Type] == DMX_PES_VIDEO) // let's only do this once
348  SetPlayMode(pmNone); // necessary to switch a PID from DMX_PES_VIDEO/AUDIO to DMX_PES_OTHER
349  }
350  close(Handle->handle);
351  Handle->handle = -1;
352  }
353  }
354  return true;
355 }
356 
357 bool cDvbSdFfDevice::ProvidesSource(int Source) const
358 {
359  if (outputOnly)
360  return false;
361  else
362  return cDvbDevice::ProvidesSource(Source);
363 }
364 
366 {
367  if (outputOnly)
368  return 0;
370 }
371 
373 {
374  if (LiveView) {
375  // Avoid noise while switching:
376  CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
377  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
378  CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
379  CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
380  }
381 
382  // Turn off live PIDs:
383 
386  DetachAll(pidHandles[ptPcr].pid);
388  DelPid(pidHandles[ptAudio].pid);
389  DelPid(pidHandles[ptVideo].pid);
390  DelPid(pidHandles[ptPcr].pid, ptPcr);
392  DelPid(pidHandles[ptDolby].pid);
393 }
394 
395 bool cDvbSdFfDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
396 {
397  int apid = Channel->Apid(0);
398  int vpid = Channel->Vpid();
399  int dpid = Channel->Dpid(0);
400 
401  bool DoTune = !IsTunedToTransponder(Channel);
402 
403  bool pidHandlesVideo = pidHandles[ptVideo].pid == vpid;
404  bool pidHandlesAudio = pidHandles[ptAudio].pid == apid;
405 
406  bool TurnOffLivePIDs = DoTune
407  || !IsPrimaryDevice()
408  || LiveView // for a new live view the old PIDs need to be turned off
409  || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
410  ;
411 
412  bool StartTransferMode = IsPrimaryDevice() && !DoTune
413  && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER
414  || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
415  );
417  StartTransferMode |= LiveView && IsPrimaryDevice() && Channel->Ca() >= CA_ENCRYPTED_MIN;
418 
419  bool TurnOnLivePIDs = !StartTransferMode && LiveView;
420 
421  // Turn off live PIDs if necessary:
422 
423  if (TurnOffLivePIDs)
424  TurnOffLiveMode(LiveView);
425 
426  // Set the tuner:
427 
428  if (!cDvbDevice::SetChannelDevice(Channel, LiveView))
429  return false;
430 
431  // PID settings:
432 
433  if (TurnOnLivePIDs) {
434  SetAudioBypass(false);
435  if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo) && AddPid(apid, ptAudio))) {
436  esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
437  return false;
438  }
439  if (IsPrimaryDevice())
440  AddPid(Channel->Tpid(), ptTeletext);
441  CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); // actually one would expect 'false' here, but according to Marco Schluessler <marco@lordzodiac.de> this works
442  // to avoid missing audio after replaying a DVD; with 'false' there is an audio disturbance when switching
443  // between two channels on the same transponder on DVB-S
444  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
445  }
446  else if (StartTransferMode)
447  cControl::Launch(new cTransferControl(this, Channel));
448 
449  return true;
450 }
451 
453 {
454  audio_status_t as;
455  CHECK(ioctl(fd_audio, AUDIO_GET_STATUS, &as));
456  return as.channel_select;
457 }
458 
460 {
461  CHECK(ioctl(fd_audio, AUDIO_CHANNEL_SELECT, AudioChannel));
462 }
463 
465 {
466  if (digitalAudio)
467  Volume = 0;
468  audio_mixer_t am;
469  // conversion for linear volume response:
470  am.volume_left = am.volume_right = 2 * Volume - Volume * Volume / 255;
471  CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am));
472 }
473 
475 {
476  if (digitalAudio != On) {
477  if (digitalAudio)
478  cCondWait::SleepMs(1000); // Wait until any leftover digital data has been flushed
479  digitalAudio = On;
480  SetVolumeDevice(On || IsMute() ? 0 : CurrentVolume());
481  }
482 }
483 
485 {
486  const tTrackId *TrackId = GetTrack(Type);
487  if (TrackId && TrackId->id) {
488  SetAudioBypass(false);
489  if (IS_AUDIO_TRACK(Type) || (IS_DOLBY_TRACK(Type) && SetAudioBypass(true))) {
490  if (pidHandles[ptAudio].pid && pidHandles[ptAudio].pid != TrackId->id) {
492  if (CamSlot())
493  CamSlot()->SetPid(pidHandles[ptAudio].pid, false);
494  pidHandles[ptAudio].pid = TrackId->id;
495  SetPid(&pidHandles[ptAudio], ptAudio, true);
496  if (CamSlot()) {
497  CamSlot()->SetPid(pidHandles[ptAudio].pid, true);
499  }
500  }
501  }
502  else if (IS_DOLBY_TRACK(Type)) {
504  return;
505  // Currently this works only in Transfer Mode
507  }
508  }
509 }
510 
512 {
513  return cDevice::CanReplay();
514 }
515 
517 {
518  if (PlayMode != pmExtern_THIS_SHOULD_BE_AVOIDED && fd_video < 0 && fd_audio < 0) {
519  // reopen the devices
520  fd_video = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDWR | O_NONBLOCK);
521  fd_audio = DvbOpen(DEV_DVB_AUDIO, adapter, frontend, O_RDWR | O_NONBLOCK);
523  }
524 
525  switch (PlayMode) {
526  case pmNone:
527  // special handling to return from PCM replay:
528  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
529  CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
530  CHECK(ioctl(fd_video, VIDEO_PLAY));
531 
532  CHECK(ioctl(fd_video, VIDEO_STOP, true));
533  CHECK(ioctl(fd_audio, AUDIO_STOP, true));
534  CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
535  CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
536  CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX));
537  CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX));
538  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
539  CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
540  break;
541  case pmAudioVideo:
542  case pmAudioOnlyBlack:
543  if (playMode == pmNone)
544  TurnOffLiveMode(true);
545  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
546  CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY));
547  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, PlayMode == pmAudioVideo));
548  CHECK(ioctl(fd_audio, AUDIO_PLAY));
549  CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
550  CHECK(ioctl(fd_video, VIDEO_PLAY));
551  break;
552  case pmAudioOnly:
553  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
554  CHECK(ioctl(fd_audio, AUDIO_STOP, true));
555  CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
556  CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY));
557  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
558  CHECK(ioctl(fd_audio, AUDIO_PLAY));
559  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false));
560  break;
561  case pmVideoOnly:
562  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
563  CHECK(ioctl(fd_video, VIDEO_STOP, true));
564  CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX));
565  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
566  CHECK(ioctl(fd_audio, AUDIO_PLAY));
567  CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
568  CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
569  CHECK(ioctl(fd_video, VIDEO_PLAY));
570  break;
572  close(fd_video);
573  close(fd_audio);
574  fd_video = fd_audio = -1;
575  break;
576  default: esyslog("ERROR: unknown playmode %d", PlayMode);
577  }
578  playMode = PlayMode;
579  return true;
580 }
581 
583 {
584  if (fd_stc >= 0) {
585  struct dmx_stc stc;
586  stc.num = 0;
587  if (ioctl(fd_stc, DMX_GET_STC, &stc) == -1) {
588  esyslog("ERROR: stc %d: %m", CardIndex() + 1);
589  return -1;
590  }
591  return stc.stc / stc.base;
592  }
593  return -1;
594 }
595 
597 {
598  if (fd_video >= 0)
599  CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed));
600 }
601 
603 {
604  if (fd_video >= 0)
605  CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
606  if (fd_audio >= 0)
607  CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
608  cDevice::Clear();
609 }
610 
612 {
614  if (fd_audio >= 0)
615  CHECK(ioctl(fd_audio, AUDIO_CONTINUE));
616  }
617  else {
618  if (fd_audio >= 0) {
619  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
620  CHECK(ioctl(fd_audio, AUDIO_CONTINUE));
621  }
622  if (fd_video >= 0)
623  CHECK(ioctl(fd_video, VIDEO_CONTINUE));
624  }
625  cDevice::Play();
626 }
627 
629 {
631  if (fd_audio >= 0)
632  CHECK(ioctl(fd_audio, AUDIO_PAUSE));
633  }
634  else {
635  if (fd_audio >= 0) {
636  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
637  CHECK(ioctl(fd_audio, AUDIO_PAUSE));
638  }
639  if (fd_video >= 0)
640  CHECK(ioctl(fd_video, VIDEO_FREEZE));
641  }
642  cDevice::Freeze();
643 }
644 
646 {
647  if (fd_audio >= 0) {
648  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
649  CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
650  }
651  cDevice::Mute();
652 }
653 
654 void cDvbSdFfDevice::StillPicture(const uchar *Data, int Length)
655 {
656  if (!Data || Length < TS_SIZE)
657  return;
658  if (Data[0] == 0x47) {
659  // TS data
660  cDevice::StillPicture(Data, Length);
661  }
662  else if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01 && (Data[3] & 0xF0) == 0xE0) {
663  // PES data
664  char *buf = MALLOC(char, Length);
665  if (!buf)
666  return;
667  int i = 0;
668  int blen = 0;
669  while (i < Length - 6) {
670  if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
671  int len = Data[i + 4] * 256 + Data[i + 5];
672  if ((Data[i + 3] & 0xF0) == 0xE0) { // video packet
673  // skip PES header
674  int offs = i + 6;
675  // skip header extension
676  if ((Data[i + 6] & 0xC0) == 0x80) {
677  // MPEG-2 PES header
678  if (Data[i + 8] >= Length)
679  break;
680  offs += 3;
681  offs += Data[i + 8];
682  len -= 3;
683  len -= Data[i + 8];
684  if (len < 0 || offs + len > Length)
685  break;
686  }
687  else {
688  // MPEG-1 PES header
689  while (offs < Length && len > 0 && Data[offs] == 0xFF) {
690  offs++;
691  len--;
692  }
693  if (offs <= Length - 2 && len >= 2 && (Data[offs] & 0xC0) == 0x40) {
694  offs += 2;
695  len -= 2;
696  }
697  if (offs <= Length - 5 && len >= 5 && (Data[offs] & 0xF0) == 0x20) {
698  offs += 5;
699  len -= 5;
700  }
701  else if (offs <= Length - 10 && len >= 10 && (Data[offs] & 0xF0) == 0x30) {
702  offs += 10;
703  len -= 10;
704  }
705  else if (offs < Length && len > 0) {
706  offs++;
707  len--;
708  }
709  }
710  if (blen + len > Length) // invalid PES length field
711  break;
712  memcpy(&buf[blen], &Data[offs], len);
713  i = offs + len;
714  blen += len;
715  }
716  else if (Data[i + 3] >= 0xBD && Data[i + 3] <= 0xDF) // other PES packets
717  i += len + 6;
718  else
719  i++;
720  }
721  else
722  i++;
723  }
724  video_still_picture sp = { buf, blen };
725  CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp));
726  free(buf);
727  }
728  else {
729  // non-PES data
730  video_still_picture sp = { (char *)Data, Length };
731  CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp));
732  }
733 }
734 
735 bool cDvbSdFfDevice::Poll(cPoller &Poller, int TimeoutMs)
736 {
737  Poller.Add((playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) ? fd_audio : fd_video, true);
738  return Poller.Poll(TimeoutMs);
739 }
740 
741 bool cDvbSdFfDevice::Flush(int TimeoutMs)
742 {
743  //TODO actually this function should wait until all buffered data has been processed by the card, but how?
744  return true;
745 }
746 
747 int cDvbSdFfDevice::PlayVideo(const uchar *Data, int Length)
748 {
749  return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
750 }
751 
752 int cDvbSdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
753 {
754  return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
755 }
756 
757 int cDvbSdFfDevice::PlayTsVideo(const uchar *Data, int Length)
758 {
759  return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
760 }
761 
762 int cDvbSdFfDevice::PlayTsAudio(const uchar *Data, int Length)
763 {
764  return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
765 }
766 
767 // --- cDvbSdFfDeviceProbe ---------------------------------------------------
768 
770 {
771  outputOnly = false;
772 }
773 
775 {
776  static uint32_t SubsystemIds[] = {
777  0x110A0000, // Fujitsu Siemens DVB-C
778  0x13C20000, // Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C
779  0x13C20001, // Technotrend/Hauppauge WinTV DVB-T rev1.X
780  0x13C20002, // Technotrend/Hauppauge WinTV DVB-C rev2.X
781  0x13C20003, // Technotrend/Hauppauge WinTV Nexus-S rev2.X
782  0x13C20004, // Galaxis DVB-S rev1.3
783  0x13C20006, // Fujitsu Siemens DVB-S rev1.6
784  0x13C20008, // Technotrend/Hauppauge DVB-T
785  0x13C2000A, // Technotrend/Hauppauge WinTV Nexus-CA rev1.X
786  0x13C2000E, // Technotrend/Hauppauge WinTV Nexus-S rev2.3
787  0x13C21002, // Technotrend/Hauppauge WinTV DVB-S rev1.3 SE
788  0x00000000
789  };
790  uint32_t SubsystemId = GetSubsystemId(Adapter, Frontend);
791  for (uint32_t *sid = SubsystemIds; *sid; sid++) {
792  if (*sid == SubsystemId) {
793  dsyslog("creating cDvbSdFfDevice");
794  new cDvbSdFfDevice(Adapter, Frontend, outputOnly);
795  return true;
796  }
797  }
798  return false;
799 }
unsigned char uchar
Definition: tools.h:30
virtual void Clear(void)
Clears all video and audio data from the device.
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition: dvbdevice.c:1448
int Vpid(void) const
Definition: channels.h:165
int Number(void) const
Definition: channels.h:191
#define dsyslog(a...)
Definition: tools.h:36
#define CA_ENCRYPTED_MIN
Definition: channels.h:48
virtual eVideoSystem GetVideoSystem(void)
Returns the video system of the currently displayed material (default is PAL).
virtual void SetAudioTrackDevice(eTrackType Type)
Sets the current audio track to the given value.
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel&#39;s transponder.
Definition: dvbdevice.c:1557
void DetachAll(int Pid)
Detaches all receivers from this device for this pid.
Definition: device.c:1721
#define LOG_ERROR
Definition: tools.h:38
virtual int PlayTsAudio(const uchar *Data, int Length)
Plays the given data block as audio.
#define DEV_DVB_VIDEO
Definition: dvbdevice.h:80
int Ca(int Index=0) const
Definition: channels.h:186
virtual void SetVolumeDevice(int Volume)
Sets the audio volume on this device (Volume = 0...255).
void StartDecrypting(void)
Triggers sending all currently active CA_PMT entries to the CAM, so that it will start decrypting...
Definition: ci.c:1961
virtual void SetVideoFormat(bool VideoFormat16_9)
Sets the output video format to either 16:9 or 4:3 (only useful if this device has an MPEG decoder)...
int Dpid(int i) const
Definition: channels.h:172
virtual int PlayTsVideo(const uchar *Data, int Length)
Plays the given data block as video.
virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect)
Returns the Width, Height and VideoAspect ratio of the currently displayed video material.
Definition: device.c:438
virtual void Freeze(void)
Puts the device into &quot;freeze frame&quot; mode.
int Adapter(void) const
Definition: dvbdevice.h:187
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
bool Add(int FileHandle, bool Out)
Definition: tools.c:1355
virtual void MakePrimaryDevice(bool On)
Informs a device that it will be the primary device.
Definition: device.c:179
virtual ~cDvbSdFfDevice()
Definition: dvbsdffdevice.c:71
#define esyslog(a...)
Definition: tools.h:34
virtual void SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
Sets the video display format to the given one (only useful if this device has an MPEG decoder)...
Definition: device.c:406
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
Definition: dvbdevice.c:1567
void DelPid(int Pid, ePidType PidType=ptOther)
Deletes a PID from the set of PIDs this device shall receive.
Definition: device.c:528
virtual int PlayAudio(const uchar *Data, int Length, uchar Id)
Plays the given data block as audio.
virtual void TrickSpeed(int Speed)
Sets the device into a mode where replay is done slower.
virtual void Mute(void)
Turns off audio while replaying.
#define LOG_ERROR_STR(s)
Definition: tools.h:39
virtual void Play(void)
Sets the device into play mode (after a previous trick mode).
Definition: device.c:1131
virtual bool AvoidRecording(void) const
Returns true if this device should only be used for recording if no other device is available...
Definition: dvbsdffdevice.c:90
virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect)
Returns the Width, Height and PixelAspect ratio the OSD should use to best fit the resolution of the ...
Definition: device.c:445
virtual void Clear(void)
Clears all video and audio data from the device.
Definition: device.c:1124
eTrackType
Definition: device.h:65
cDvbSpuDecoder * spuDecoder
Definition: dvbsdffdevice.h:32
Definition: device.h:37
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles...
int Ppid(void) const
Definition: channels.h:166
virtual void MakePrimaryDevice(bool On)
Informs a device that it will be the primary device.
Definition: dvbsdffdevice.c:78
bool Poll(int TimeoutMs=0)
Definition: tools.c:1374
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect)
Returns the Width, Height and PixelAspect ratio the OSD should use to best fit the resolution of the ...
virtual void Play(void)
Sets the device into play mode (after a previous trick mode).
virtual void Mute(void)
Turns off audio while replaying.
Definition: device.c:1145
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
Definition: dvbsdffdevice.c:85
virtual void SetDigitalAudioDevice(bool On)
Tells the actual device that digital audio output shall be switched on or off.
#define MALLOC(type, size)
Definition: tools.h:46
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
virtual void SetAudioChannelDevice(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
static int CurrentVolume(void)
Definition: device.h:577
int frontend
Definition: dvbdevice.h:173
bool IsPrimaryDevice(void) const
Definition: device.h:199
cCamSlot * CamSlot(void) const
Returns the CAM slot that is currently used with this device, or NULL if no CAM slot is in use...
Definition: device.h:426
virtual void Freeze(void)
Puts the device into &quot;freeze frame&quot; mode.
Definition: device.c:1138
int Frontend(void) const
Definition: dvbdevice.h:188
virtual bool Poll(cPoller &Poller, int TimeoutMs=0)
Returns true if the device itself or any of the file handles in Poller is ready for further action...
#define CHECK(s)
Definition: tools.h:50
virtual int NumProvidedSystems(void) const
Returns the number of individual &quot;delivery systems&quot; this device provides.
virtual bool Probe(int Adapter, int Frontend)
Probes for a DVB device at the given Adapter and creates the appropriate object derived from cDvbDevi...
#define DEV_VIDEO
Definition: dvbdevice.h:73
int Tpid(void) const
Definition: channels.h:182
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition: thread.c:57
virtual void StillPicture(const uchar *Data, int Length)
Displays the given I-frame as a still picture.
eVideoDisplayFormat
Definition: device.h:60
#define IS_AUDIO_TRACK(t)
Definition: device.h:78
bool SetAudioBypass(bool On)
int VideoFormat
Definition: config.h:306
bool CamDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2125
cSetup Setup
Definition: config.c:373
int adapter
Definition: dvbdevice.h:173
virtual cSpuDecoder * GetSpuDecoder(void)
Returns a pointer to the device&#39;s SPU decoder (or NULL, if this device doesn&#39;t have an SPU decoder)...
Definition: dvbsdffdevice.c:95
tChannelID GetChannelID(void) const
Definition: channels.h:202
ePlayMode
Definition: device.h:37
virtual bool Flush(int TimeoutMs=0)
Returns true if the device&#39;s output buffers are empty, i.
eVideoSystem
Definition: device.h:56
static void Launch(cControl *Control)
Definition: player.c:79
cDvbSdFfDevice(int Adapter, int Frontend, bool OutputOnly)
Definition: dvbsdffdevice.c:26
#define DEV_DVB_OSD
Definition: dvbdevice.h:76
static dmx_pes_type_t PesTypes[]
ePlayMode playMode
Definition: dvbsdffdevice.h:88
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition: device.h:200
uchar * RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality)
Converts the given Memory to a JPEG image and returns a pointer to the resulting image.
Definition: tools.c:1182
virtual int NumProvidedSystems(void) const
Returns the number of individual &quot;delivery systems&quot; this device provides.
Definition: dvbdevice.c:1537
void SetPid(int Pid, bool Active)
Sets the given Pid (which has previously been added through a call to AddPid()) to Active...
Definition: ci.c:1881
int WriteAllOrNothing(int fd, const uchar *Data, int Length, int TimeoutMs, int RetryMs)
Writes either all Data to the given file descriptor, or nothing at all.
Definition: tools.c:90
Definition: device.h:56
virtual int PlayVideo(const uchar *Data, int Length)
Plays the given data block as video.
static int setTransferModeForDolbyDigital
Definition: dvbdevice.h:265
void TurnOffLiveMode(bool LiveView)
const tTrackId * GetTrack(eTrackType Type)
Returns a pointer to the given track id, or NULL if Type is not less than ttMaxTrackTypes.
Definition: device.c:979
int Apid(int i) const
Definition: channels.h:171
cChannelCamRelations ChannelCamRelations
Definition: ci.c:2068
#define DEV_DVB_DEMUX
Definition: dvbdevice.h:79
virtual uchar * GrabImage(int &Size, bool Jpeg=true, int Quality=-1, int SizeX=-1, int SizeY=-1)
Grabs the currently visible screen image.
virtual void SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
Sets the video display format to the given one (only useful if this device has an MPEG decoder)...
The cDvbDevice implements a DVB device which can be accessed through the Linux DVB driver API...
Definition: dvbdevice.h:158
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
Definition: device.c:1105
#define TS_SIZE
Definition: remux.h:34
static int devVideoOffset
Definition: dvbsdffdevice.h:56
bool HasPid(int Pid) const
Returns true if this device is currently receiving the given PID.
Definition: device.c:455
virtual bool SetPid(cPidHandle *Handle, int Type, bool On)
Does the actual PID setting on this device.
void ForceTransferMode(void)
Forces the device into transfermode for the current channel.
Definition: device.c:824
#define IS_DOLBY_TRACK(t)
Definition: device.h:79
int VideoDisplayFormat
Definition: config.h:305
virtual bool SetPlayMode(ePlayMode PlayMode)
Sets the device into the given play mode.
Definition: tools.h:347
virtual void StillPicture(const uchar *Data, int Length)
Displays the given I-frame as a still picture.
Definition: device.c:1150
Definition: device.h:57
virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect)
Returns the Width, Height and VideoAspect ratio of the currently displayed video material.
cPidHandle pidHandles[MAXPIDHANDLES]
Definition: device.h:355
bool AddPid(int Pid, ePidType PidType=ptOther, int StreamType=0)
Adds a PID to the set of PIDs this device shall receive.
Definition: device.c:464
#define DEV_DVB_AUDIO
Definition: dvbdevice.h:81
int SlotNumber(void)
Returns the number of this CAM slot within the whole system.
Definition: ci.h:169
virtual int GetAudioChannelDevice(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
static int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError=false)
Definition: dvbdevice.c:1066
bool IsMute(void) const
Definition: device.h:565
uint16_t id
Definition: device.h:83