vdr  2.2.0
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 3.3 2014/03/15 12:35:21 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 
244 void cDvbSdFfDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect)
245 {
246  if (fd_video >= 0) {
247  video_size_t vs;
248  if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
249  Width = vs.w;
250  Height = vs.h;
251  switch (vs.aspect_ratio) {
252  default:
253  case VIDEO_FORMAT_4_3: VideoAspect = 4.0 / 3.0; break;
254  case VIDEO_FORMAT_16_9: VideoAspect = 16.0 / 9.0; break;
255  case VIDEO_FORMAT_221_1: VideoAspect = 2.21; break;
256  }
257  return;
258  }
259  else
260  LOG_ERROR;
261  }
262  cDevice::GetVideoSize(Width, Height, VideoAspect);
263 }
264 
265 void cDvbSdFfDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
266 {
267  if (fd_video >= 0) {
268  video_size_t vs;
269  if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
270  Width = 720;
271  if (vs.h != 480 && vs.h != 240)
272  Height = 576; // PAL
273  else
274  Height = 480; // NTSC
275  switch (Setup.VideoFormat ? vs.aspect_ratio : VIDEO_FORMAT_4_3) {
276  default:
277  case VIDEO_FORMAT_4_3: PixelAspect = 4.0 / 3.0; break;
278  case VIDEO_FORMAT_221_1: // FF DVB cards only distinguish between 4:3 and 16:9
279  case VIDEO_FORMAT_16_9: PixelAspect = 16.0 / 9.0; break;
280  }
281  PixelAspect /= double(Width) / Height;
282  return;
283  }
284  else
285  LOG_ERROR;
286  }
287  cDevice::GetOsdSize(Width, Height, PixelAspect);
288 }
289 
291 {
293  return false;
294  return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0;
295 }
296 
297 // ptAudio ptVideo ptPcr ptTeletext ptDolby ptOther
298 static dmx_pes_type_t PesTypes[] = { DMX_PES_AUDIO, DMX_PES_VIDEO, DMX_PES_PCR, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER };
299 
300 bool cDvbSdFfDevice::SetPid(cPidHandle *Handle, int Type, bool On)
301 {
302  if (Handle->pid) {
303  dmx_pes_filter_params pesFilterParams;
304  memset(&pesFilterParams, 0, sizeof(pesFilterParams));
305  if (On) {
306  if (Handle->handle < 0) {
307  Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
308  if (Handle->handle < 0) {
309  LOG_ERROR;
310  return false;
311  }
312  }
313  pesFilterParams.pid = Handle->pid;
314  pesFilterParams.input = DMX_IN_FRONTEND;
315  pesFilterParams.output = (Type <= ptTeletext && Handle->used <= 1) ? DMX_OUT_DECODER : DMX_OUT_TS_TAP;
316  pesFilterParams.pes_type= PesTypes[Type < ptOther ? Type : ptOther];
317  pesFilterParams.flags = DMX_IMMEDIATE_START;
318  if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
319  LOG_ERROR;
320  return false;
321  }
322  }
323  else if (!Handle->used) {
324  CHECK(ioctl(Handle->handle, DMX_STOP));
325  if (Type <= ptTeletext) {
326  pesFilterParams.pid = 0x1FFF;
327  pesFilterParams.input = DMX_IN_FRONTEND;
328  pesFilterParams.output = DMX_OUT_DECODER;
329  pesFilterParams.pes_type= PesTypes[Type];
330  pesFilterParams.flags = DMX_IMMEDIATE_START;
331  CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams));
332  if (PesTypes[Type] == DMX_PES_VIDEO) // let's only do this once
333  SetPlayMode(pmNone); // necessary to switch a PID from DMX_PES_VIDEO/AUDIO to DMX_PES_OTHER
334  }
335  close(Handle->handle);
336  Handle->handle = -1;
337  }
338  }
339  return true;
340 }
341 
342 bool cDvbSdFfDevice::ProvidesSource(int Source) const
343 {
344  if (outputOnly)
345  return false;
346  else
347  return cDvbDevice::ProvidesSource(Source);
348 }
349 
351 {
352  if (outputOnly)
353  return 0;
355 }
356 
358 {
359  if (LiveView) {
360  // Avoid noise while switching:
361  CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
362  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
363  CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
364  CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
365  }
366 
367  // Turn off live PIDs:
368 
371  DetachAll(pidHandles[ptPcr].pid);
373  DelPid(pidHandles[ptAudio].pid);
374  DelPid(pidHandles[ptVideo].pid);
375  DelPid(pidHandles[ptPcr].pid, ptPcr);
377  DelPid(pidHandles[ptDolby].pid);
378 }
379 
380 bool cDvbSdFfDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
381 {
382  int apid = Channel->Apid(0);
383  int vpid = Channel->Vpid();
384  int dpid = Channel->Dpid(0);
385 
386  bool DoTune = !IsTunedToTransponder(Channel);
387 
388  bool pidHandlesVideo = vpid && pidHandles[ptVideo].pid == vpid;
389  bool pidHandlesAudio = apid && pidHandles[ptAudio].pid == apid;
390 
391  bool TurnOffLivePIDs = DoTune
392  || !IsPrimaryDevice()
393  || LiveView // for a new live view the old PIDs need to be turned off
394  || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
395  ;
396 
397  bool StartTransferMode = IsPrimaryDevice() && !DoTune
398  && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER
399  || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
400  );
402  StartTransferMode |= LiveView && IsPrimaryDevice() && Channel->Ca() >= CA_ENCRYPTED_MIN;
403 
404  bool TurnOnLivePIDs = !StartTransferMode && LiveView;
405 
406  // Turn off live PIDs if necessary:
407 
408  if (TurnOffLivePIDs)
409  TurnOffLiveMode(LiveView);
410 
411  // Set the tuner:
412 
413  if (!cDvbDevice::SetChannelDevice(Channel, LiveView))
414  return false;
415 
416  // PID settings:
417 
418  if (TurnOnLivePIDs) {
419  SetAudioBypass(false);
420  if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo) && AddPid(apid, ptAudio))) {
421  esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
422  return false;
423  }
424  if (IsPrimaryDevice())
425  AddPid(Channel->Tpid(), ptTeletext);
426  CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); // actually one would expect 'false' here, but according to Marco Schluessler <marco@lordzodiac.de> this works
427  // to avoid missing audio after replaying a DVD; with 'false' there is an audio disturbance when switching
428  // between two channels on the same transponder on DVB-S
429  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
430  }
431  else if (StartTransferMode)
432  cControl::Launch(new cTransferControl(this, Channel));
433 
434  return true;
435 }
436 
438 {
439  audio_status_t as;
440  CHECK(ioctl(fd_audio, AUDIO_GET_STATUS, &as));
441  return as.channel_select;
442 }
443 
445 {
446  CHECK(ioctl(fd_audio, AUDIO_CHANNEL_SELECT, AudioChannel));
447 }
448 
450 {
451  if (digitalAudio)
452  Volume = 0;
453  audio_mixer_t am;
454  // conversion for linear volume response:
455  am.volume_left = am.volume_right = 2 * Volume - Volume * Volume / 255;
456  CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am));
457 }
458 
460 {
461  if (digitalAudio != On) {
462  if (digitalAudio)
463  cCondWait::SleepMs(1000); // Wait until any leftover digital data has been flushed
464  digitalAudio = On;
465  SetVolumeDevice(On || IsMute() ? 0 : CurrentVolume());
466  }
467 }
468 
470 {
471  const tTrackId *TrackId = GetTrack(Type);
472  if (TrackId && TrackId->id) {
473  SetAudioBypass(false);
474  if (IS_AUDIO_TRACK(Type) || (IS_DOLBY_TRACK(Type) && SetAudioBypass(true))) {
475  if (pidHandles[ptAudio].pid && pidHandles[ptAudio].pid != TrackId->id) {
477  if (CamSlot())
478  CamSlot()->SetPid(pidHandles[ptAudio].pid, false);
479  pidHandles[ptAudio].pid = TrackId->id;
480  SetPid(&pidHandles[ptAudio], ptAudio, true);
481  if (CamSlot()) {
482  CamSlot()->SetPid(pidHandles[ptAudio].pid, true);
484  }
485  }
486  }
487  else if (IS_DOLBY_TRACK(Type)) {
489  return;
490  // Currently this works only in Transfer Mode
492  }
493  }
494 }
495 
497 {
498  return cDevice::CanReplay();
499 }
500 
502 {
503  if (PlayMode != pmExtern_THIS_SHOULD_BE_AVOIDED && fd_video < 0 && fd_audio < 0) {
504  // reopen the devices
505  fd_video = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDWR | O_NONBLOCK);
506  fd_audio = DvbOpen(DEV_DVB_AUDIO, adapter, frontend, O_RDWR | O_NONBLOCK);
508  }
509 
510  switch (PlayMode) {
511  case pmNone:
512  // special handling to return from PCM replay:
513  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
514  CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
515  CHECK(ioctl(fd_video, VIDEO_PLAY));
516 
517  CHECK(ioctl(fd_video, VIDEO_STOP, true));
518  CHECK(ioctl(fd_audio, AUDIO_STOP, true));
519  CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
520  CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
521  CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX));
522  CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX));
523  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
524  CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
525  break;
526  case pmAudioVideo:
527  case pmAudioOnlyBlack:
528  if (playMode == pmNone)
529  TurnOffLiveMode(true);
530  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
531  CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY));
532  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, PlayMode == pmAudioVideo));
533  CHECK(ioctl(fd_audio, AUDIO_PLAY));
534  CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
535  CHECK(ioctl(fd_video, VIDEO_PLAY));
536  break;
537  case pmAudioOnly:
538  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
539  CHECK(ioctl(fd_audio, AUDIO_STOP, true));
540  CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
541  CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY));
542  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
543  CHECK(ioctl(fd_audio, AUDIO_PLAY));
544  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false));
545  break;
546  case pmVideoOnly:
547  CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
548  CHECK(ioctl(fd_video, VIDEO_STOP, true));
549  CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX));
550  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
551  CHECK(ioctl(fd_audio, AUDIO_PLAY));
552  CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
553  CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
554  CHECK(ioctl(fd_video, VIDEO_PLAY));
555  break;
557  close(fd_video);
558  close(fd_audio);
559  fd_video = fd_audio = -1;
560  break;
561  default: esyslog("ERROR: unknown playmode %d", PlayMode);
562  }
563  playMode = PlayMode;
564  return true;
565 }
566 
568 {
569  if (fd_stc >= 0) {
570  struct dmx_stc stc;
571  stc.num = 0;
572  if (ioctl(fd_stc, DMX_GET_STC, &stc) == -1) {
573  esyslog("ERROR: stc %d: %m", CardIndex() + 1);
574  return -1;
575  }
576  return stc.stc / stc.base;
577  }
578  return -1;
579 }
580 
581 void cDvbSdFfDevice::TrickSpeed(int Speed, bool Forward)
582 {
583  if (fd_video >= 0)
584  CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed));
585 }
586 
588 {
589  if (fd_video >= 0)
590  CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
591  if (fd_audio >= 0)
592  CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
593  cDevice::Clear();
594 }
595 
597 {
599  if (fd_audio >= 0)
600  CHECK(ioctl(fd_audio, AUDIO_CONTINUE));
601  }
602  else {
603  if (fd_audio >= 0) {
604  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
605  CHECK(ioctl(fd_audio, AUDIO_CONTINUE));
606  }
607  if (fd_video >= 0)
608  CHECK(ioctl(fd_video, VIDEO_CONTINUE));
609  }
610  cDevice::Play();
611 }
612 
614 {
616  if (fd_audio >= 0)
617  CHECK(ioctl(fd_audio, AUDIO_PAUSE));
618  }
619  else {
620  if (fd_audio >= 0) {
621  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
622  CHECK(ioctl(fd_audio, AUDIO_PAUSE));
623  }
624  if (fd_video >= 0)
625  CHECK(ioctl(fd_video, VIDEO_FREEZE));
626  }
627  cDevice::Freeze();
628 }
629 
631 {
632  if (fd_audio >= 0) {
633  CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
634  CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
635  }
636  cDevice::Mute();
637 }
638 
639 void cDvbSdFfDevice::StillPicture(const uchar *Data, int Length)
640 {
641  if (!Data || Length < TS_SIZE)
642  return;
643  if (Data[0] == 0x47) {
644  // TS data
645  cDevice::StillPicture(Data, Length);
646  }
647  else if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01 && (Data[3] & 0xF0) == 0xE0) {
648  // PES data
649  char *buf = MALLOC(char, Length);
650  if (!buf)
651  return;
652  int i = 0;
653  int blen = 0;
654  while (i < Length - 6) {
655  if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
656  int len = Data[i + 4] * 256 + Data[i + 5];
657  if ((Data[i + 3] & 0xF0) == 0xE0) { // video packet
658  // skip PES header
659  int offs = i + 6;
660  // skip header extension
661  if ((Data[i + 6] & 0xC0) == 0x80) {
662  // MPEG-2 PES header
663  if (Data[i + 8] >= Length)
664  break;
665  offs += 3;
666  offs += Data[i + 8];
667  len -= 3;
668  len -= Data[i + 8];
669  if (len < 0 || offs + len > Length)
670  break;
671  }
672  else {
673  // MPEG-1 PES header
674  while (offs < Length && len > 0 && Data[offs] == 0xFF) {
675  offs++;
676  len--;
677  }
678  if (offs <= Length - 2 && len >= 2 && (Data[offs] & 0xC0) == 0x40) {
679  offs += 2;
680  len -= 2;
681  }
682  if (offs <= Length - 5 && len >= 5 && (Data[offs] & 0xF0) == 0x20) {
683  offs += 5;
684  len -= 5;
685  }
686  else if (offs <= Length - 10 && len >= 10 && (Data[offs] & 0xF0) == 0x30) {
687  offs += 10;
688  len -= 10;
689  }
690  else if (offs < Length && len > 0) {
691  offs++;
692  len--;
693  }
694  }
695  if (blen + len > Length) // invalid PES length field
696  break;
697  memcpy(&buf[blen], &Data[offs], len);
698  i = offs + len;
699  blen += len;
700  }
701  else if (Data[i + 3] >= 0xBD && Data[i + 3] <= 0xDF) // other PES packets
702  i += len + 6;
703  else
704  i++;
705  }
706  else
707  i++;
708  }
709  video_still_picture sp = { buf, blen };
710  CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp));
711  free(buf);
712  }
713  else {
714  // non-PES data
715  video_still_picture sp = { (char *)Data, Length };
716  CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp));
717  }
718 }
719 
720 bool cDvbSdFfDevice::Poll(cPoller &Poller, int TimeoutMs)
721 {
722  Poller.Add((playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) ? fd_audio : fd_video, true);
723  return Poller.Poll(TimeoutMs);
724 }
725 
726 bool cDvbSdFfDevice::Flush(int TimeoutMs)
727 {
728  //TODO actually this function should wait until all buffered data has been processed by the card, but how?
729  return true;
730 }
731 
732 int cDvbSdFfDevice::PlayVideo(const uchar *Data, int Length)
733 {
734  return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
735 }
736 
737 int cDvbSdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
738 {
739  return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
740 }
741 
742 int cDvbSdFfDevice::PlayTsVideo(const uchar *Data, int Length)
743 {
744  return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
745 }
746 
747 int cDvbSdFfDevice::PlayTsAudio(const uchar *Data, int Length)
748 {
749  return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
750 }
751 
752 // --- cDvbSdFfDeviceProbe ---------------------------------------------------
753 
755 {
756  outputOnly = false;
757 }
758 
760 {
761  static uint32_t SubsystemIds[] = {
762  0x110A0000, // Fujitsu Siemens DVB-C
763  0x13C20000, // Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C
764  0x13C20001, // Technotrend/Hauppauge WinTV DVB-T rev1.X
765  0x13C20002, // Technotrend/Hauppauge WinTV DVB-C rev2.X
766  0x13C20003, // Technotrend/Hauppauge WinTV Nexus-S rev2.X
767  0x13C20004, // Galaxis DVB-S rev1.3
768  0x13C20006, // Fujitsu Siemens DVB-S rev1.6
769  0x13C20008, // Technotrend/Hauppauge DVB-T
770  0x13C2000A, // Technotrend/Hauppauge WinTV Nexus-CA rev1.X
771  0x13C2000E, // Technotrend/Hauppauge WinTV Nexus-S rev2.3
772  0x13C21002, // Technotrend/Hauppauge WinTV DVB-S rev1.3 SE
773  0x00000000
774  };
775  uint32_t SubsystemId = GetSubsystemId(Adapter, Frontend);
776  for (uint32_t *sid = SubsystemIds; *sid; sid++) {
777  if (*sid == SubsystemId) {
778  dsyslog("creating cDvbSdFfDevice");
779  new cDvbSdFfDevice(Adapter, Frontend, outputOnly);
780  return true;
781  }
782  }
783  return false;
784 }
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:1526
int Vpid(void) const
Definition: channels.h:170
int Number(void) const
Definition: channels.h:197
#define dsyslog(a...)
Definition: tools.h:36
#define CA_ENCRYPTED_MIN
Definition: channels.h:49
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:1640
void DetachAll(int Pid)
Detaches all receivers from this device for this pid.
Definition: device.c:1735
#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:79
int Ca(int Index=0) const
Definition: channels.h:191
virtual void SetVolumeDevice(int Volume)
Sets the audio volume on this device (Volume = 0...255).
virtual void StartDecrypting(void)
Triggers sending all currently active CA_PMT entries to the CAM, so that it will start decrypting...
Definition: ci.c:2202
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:177
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:435
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
int Adapter(void) const
Definition: dvbdevice.h:199
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
virtual void TrickSpeed(int Speed, bool Forward)
Sets the device into a mode where replay is done slower.
bool Add(int FileHandle, bool Out)
Definition: tools.c:1424
virtual void MakePrimaryDevice(bool On)
Informs a device that it will be the primary device.
Definition: device.c:180
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:408
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
Definition: dvbdevice.c:1650
void DelPid(int Pid, ePidType PidType=ptOther)
Deletes a PID from the set of PIDs this device shall receive.
Definition: device.c:525
virtual int PlayAudio(const uchar *Data, int Length, uchar Id)
Plays the given data block as audio.
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:1139
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:442
virtual void Clear(void)
Clears all video and audio data from the device.
Definition: device.c:1132
eTrackType
Definition: device.h:70
cDvbSpuDecoder * spuDecoder
Definition: dvbsdffdevice.h:32
Definition: device.h:39
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:171
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:1443
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:1153
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
Definition: dvbsdffdevice.c:85
virtual void SetDigitalAudioDevice(bool On)
Tells the output device that the current audio track is Dolby Digital.
#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:595
int frontend
Definition: dvbdevice.h:185
bool IsPrimaryDevice(void) const
Definition: device.h:204
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:436
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
Definition: device.c:1146
int Frontend(void) const
Definition: dvbdevice.h:200
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 "delivery systems" 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:72
int Tpid(void) const
Definition: channels.h:187
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:65
#define IS_AUDIO_TRACK(t)
Definition: device.h:83
bool SetAudioBypass(bool On)
int VideoFormat
Definition: config.h:313
bool CamDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2392
cSetup Setup
Definition: config.c:373
int adapter
Definition: dvbdevice.h:185
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:208
ePlayMode
Definition: device.h:39
virtual bool Flush(int TimeoutMs=0)
Returns true if the device&#39;s output buffers are empty, i.
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:75
static dmx_pes_type_t PesTypes[]
ePlayMode playMode
Definition: dvbsdffdevice.h:87
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition: device.h:205
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:1251
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
Definition: dvbdevice.c:1615
virtual 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:2122
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
virtual int PlayVideo(const uchar *Data, int Length)
Plays the given data block as video.
static int setTransferModeForDolbyDigital
Definition: dvbdevice.h:277
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:987
int Apid(int i) const
Definition: channels.h:176
cChannelCamRelations ChannelCamRelations
Definition: ci.c:2335
#define DEV_DVB_DEMUX
Definition: dvbdevice.h:78
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:170
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
Definition: device.c:1113
#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:452
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:830
#define IS_DOLBY_TRACK(t)
Definition: device.h:84
int VideoDisplayFormat
Definition: config.h:312
virtual bool SetPlayMode(ePlayMode PlayMode)
Sets the device into the given play mode.
Definition: tools.h:357
virtual void StillPicture(const uchar *Data, int Length)
Displays the given I-frame as a still picture.
Definition: device.c:1158
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:365
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:461
#define DEV_DVB_AUDIO
Definition: dvbdevice.h:80
int SlotNumber(void)
Returns the number of this CAM slot within the whole system.
Definition: ci.h:181
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:1148
bool IsMute(void) const
Definition: device.h:583
uint16_t id
Definition: device.h:88