vdr 2.6.9
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 4.0 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
26cDvbSdFfDevice::cDvbSdFfDevice(int Adapter, int Frontend, bool OutputOnly)
27:cDvbDevice(Adapter, Frontend)
28{
29 spuDecoder = NULL;
30 digitalAudio = false;
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)
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
84
86{
87 return true;
88}
89
91{
92 return true;
93}
94
101
102uchar *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
238void 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
244void 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
265void 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
298static dmx_pes_type_t PesTypes[] = { DMX_PES_AUDIO, DMX_PES_VIDEO, DMX_PES_PCR, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER };
299
300bool 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
342bool 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
378}
379
380bool 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;
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
581void 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));
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 }
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 }
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 }
637}
638
639void 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
720bool cDvbSdFfDevice::Poll(cPoller &Poller, int TimeoutMs)
721{
723 return Poller.Poll(TimeoutMs);
724}
725
726bool 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
732int cDvbSdFfDevice::PlayVideo(const uchar *Data, int Length)
733{
734 return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
735}
736
737int cDvbSdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
738{
739 return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
740}
741
742int cDvbSdFfDevice::PlayTsVideo(const uchar *Data, int Length)
743{
744 return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
745}
746
747int cDvbSdFfDevice::PlayTsAudio(const uchar *Data, int Length)
748{
749 return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
750}
751
752// --- cDvbSdFfDeviceProbe ---------------------------------------------------
753
758
759bool cDvbSdFfDeviceProbe::Probe(int Adapter, int Frontend)
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}
#define CA_ENCRYPTED_MIN
Definition channels.h:44
cChannelCamRelations ChannelCamRelations
Definition ci.c:2947
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:2697
virtual void StartDecrypting(void)
Sends all CA_PMT entries to the CAM that have been modified since the last call to this function.
Definition ci.c:2776
int SlotNumber(void)
Returns the number of this CAM slot within the whole system.
Definition ci.h:344
bool CamDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition ci.c:3004
int Tpid(void) const
Definition channels.h:171
int Vpid(void) const
Definition channels.h:154
int Number(void) const
Definition channels.h:179
int Dpid(int i) const
Definition channels.h:161
int Apid(int i) const
Definition channels.h:160
tChannelID GetChannelID(void) const
Definition channels.h:191
int Ppid(void) const
Definition channels.h:155
int Ca(int Index=0) const
Definition channels.h:173
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition thread.c:72
static void Launch(cControl *Control)
Definition player.c:87
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:533
@ ptTeletext
Definition device.h:416
@ ptPcr
Definition device.h:416
@ ptOther
Definition device.h:416
@ ptDolby
Definition device.h:416
@ ptAudio
Definition device.h:416
@ ptVideo
Definition device.h:416
bool HasPid(int Pid) const
Returns true if this device is currently receiving the given PID.
Definition device.c:550
void DelPid(int Pid, ePidType PidType=ptOther)
Deletes a PID from the set of PIDs this device shall receive.
Definition device.c:625
bool IsPrimaryDevice(bool CheckDecoder=true) const
Definition device.h:223
virtual void MakePrimaryDevice(bool On)
Informs a device that it will be the primary device.
Definition device.c:186
void DetachAll(int Pid)
Detaches all receivers from this device for this pid.
Definition device.c:1899
bool IsMute(void) const
Definition device.h:640
virtual void Play(void)
Sets the device into play mode (after a previous trick mode).
Definition device.c:1295
cPidHandle pidHandles[MAXPIDHANDLES]
Definition device.h:425
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:1143
virtual void Mute(void)
Turns off audio while replaying.
Definition device.c:1309
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
Definition device.c:1302
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:506
static int CurrentVolume(void)
Definition device.h:652
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
Definition device.c:1269
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:540
virtual void Clear(void)
Clears all video and audio data from the device.
Definition device.c:1288
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition device.h:224
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:499
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:560
void ForceTransferMode(void)
Forces the device into transfermode for the current channel.
Definition device.c:972
virtual void StillPicture(const uchar *Data, int Length)
Displays the given I-frame as a still picture.
Definition device.c:1314
static uint32_t GetSubsystemId(int Adapter, int Frontend)
Definition dvbdevice.c:2432
The cDvbDevice implements a DVB device which can be accessed through the Linux DVB driver API.
Definition dvbdevice.h:168
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
Definition dvbdevice.c:2333
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
Definition dvbdevice.c:2303
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
Definition dvbdevice.c:2348
static int setTransferModeForDolbyDigital
Definition dvbdevice.h:272
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition dvbdevice.c:2225
virtual bool Probe(int Adapter, int Frontend)
Probes for a DVB device at the given Adapter and creates the appropriate object derived from cDvbDevi...
The cDvbSdFfDevice implements a DVB device which can be accessed through the Linux DVB driver API.
virtual void SetVolumeDevice(int Volume)
Sets the audio volume on this device (Volume = 0...255).
void TurnOffLiveMode(bool LiveView)
virtual void SetDigitalAudioDevice(bool On)
Tells the output device that the current audio track is Dolby Digital.
virtual void Clear(void)
Clears all video and audio data from the device.
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
virtual void Play(void)
Sets the device into play mode (after a previous trick mode).
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 GetVideoSize(int &Width, int &Height, double &VideoAspect)
Returns the Width, Height and VideoAspect ratio of the currently displayed video material.
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles.
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
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).
virtual int PlayTsAudio(const uchar *Data, int Length)
Plays the given data block as audio.
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
virtual void SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
Sets the video display format to the given one (only useful if this device has an MPEG decoder).
ePlayMode playMode
virtual cSpuDecoder * GetSpuDecoder(void)
Returns a pointer to the device's SPU decoder (or NULL, if this device doesn't have an SPU decoder).
virtual void MakePrimaryDevice(bool On)
Informs a device that it will be the primary device.
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
virtual bool SetPid(cPidHandle *Handle, int Type, bool On)
Does the actual PID setting on this device.
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.
virtual void SetAudioTrackDevice(eTrackType Type)
Sets the current audio track to the given value.
cDvbSpuDecoder * spuDecoder
virtual void Mute(void)
Turns off audio while replaying.
virtual void TrickSpeed(int Speed, bool Forward)
Sets the device into a mode where replay is done slower.
virtual bool AvoidRecording(void) const
Returns true if this device should only be used for recording if no other device is available.
virtual void StillPicture(const uchar *Data, int Length)
Displays the given I-frame as a still picture.
virtual int GetAudioChannelDevice(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
virtual int PlayTsVideo(const uchar *Data, int Length)
Plays the given data block as video.
virtual int PlayAudio(const uchar *Data, int Length, uchar Id)
Plays the given data block as audio.
virtual ~cDvbSdFfDevice()
virtual bool SetPlayMode(ePlayMode PlayMode)
Sets the device into the given play mode.
bool SetAudioBypass(bool On)
virtual bool Flush(int TimeoutMs=0)
Returns true if the device's output buffers are empty, i.
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
static int devVideoOffset
virtual void SetAudioChannelDevice(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
virtual int PlayVideo(const uchar *Data, int Length)
Plays the given data block as video.
cDvbSdFfDevice(int Adapter, int Frontend, bool OutputOnly)
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
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 ...
bool Add(int FileHandle, bool Out)
Definition tools.c:1538
bool Poll(int TimeoutMs=0)
Definition tools.c:1570
int VideoDisplayFormat
Definition config.h:325
int VideoFormat
Definition config.h:326
cSetup Setup
Definition config.c:372
eVideoDisplayFormat
Definition device.h:58
@ vdfLetterBox
Definition device.h:59
@ vdfCenterCutOut
Definition device.h:60
@ vdfPanAndScan
Definition device.h:58
ePlayMode
Definition device.h:39
@ pmAudioOnlyBlack
Definition device.h:42
@ pmNone
Definition device.h:39
@ pmVideoOnly
Definition device.h:43
@ pmAudioOnly
Definition device.h:41
@ pmAudioVideo
Definition device.h:40
@ pmExtern_THIS_SHOULD_BE_AVOIDED
Definition device.h:44
#define IS_AUDIO_TRACK(t)
Definition device.h:76
eTrackType
Definition device.h:63
#define IS_DOLBY_TRACK(t)
Definition device.h:77
int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError)
Definition dvbdevice.c:1921
#define DEV_DVB_DEMUX
Definition dvbdevice.h:76
#define DEV_DVB_AUDIO
Definition dvbdevice.h:78
#define DEV_DVB_VIDEO
Definition dvbdevice.h:77
#define DEV_VIDEO
Definition dvbdevice.h:70
#define DEV_DVB_OSD
Definition dvbdevice.h:73
static dmx_pes_type_t PesTypes[]
#define TS_SIZE
Definition remux.h:34
uint16_t id
Definition device.h:81
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:1351
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
#define LOG_ERROR_STR(s)
Definition tools.h:40
unsigned char uchar
Definition tools.h:31
#define CHECK(s)
Definition tools.h:51
#define dsyslog(a...)
Definition tools.h:37
#define MALLOC(type, size)
Definition tools.h:47
#define esyslog(a...)
Definition tools.h:35
#define LOG_ERROR
Definition tools.h:39