vdr 2.8.4
device.c
Go to the documentation of this file.
1/*
2 * device.c: The basic device interface
3 *
4 * See the main source file 'vdr.c' for copyright information and
5 * how to reach the author.
6 *
7 * $Id: device.c 5.29 2026/10/19 18:40:13 kls Exp $
8 */
9
10#define MUTE_DEPRECATED_FLUSH
11#include "device.h"
12#include <errno.h>
13#include <math.h>
14#include <sys/ioctl.h>
15#include <sys/mman.h>
16#include "audio.h"
17#include "channels.h"
18#include "i18n.h"
19#include "player.h"
20#include "receiver.h"
21#include "status.h"
22#include "transfer.h"
23
24// --- cLiveSubtitle ---------------------------------------------------------
25
26class cLiveSubtitle : public cReceiver {
27protected:
28 virtual void Receive(const uchar *Data, int Length) override;
29public:
30 cLiveSubtitle(int SPid);
31 virtual ~cLiveSubtitle() override;
32 };
33
35{
36 AddPid(SPid);
37}
38
43
44void cLiveSubtitle::Receive(const uchar *Data, int Length)
45{
47 cDevice::PrimaryDevice()->PlayTs(Data, Length);
48}
49
50// --- cDeviceHook -----------------------------------------------------------
51
56
57bool cDeviceHook::DeviceProvidesTransponder(const cDevice *Device, const cChannel *Channel) const
58{
59 return true;
60}
61
62bool cDeviceHook::DeviceProvidesEIT(const cDevice *Device) const
63{
64 return true;
65}
66
67// --- cDevice ---------------------------------------------------------------
68
69// The minimum number of unknown PS1 packets to consider this a "pre 1.3.19 private stream":
70#define MIN_PRE_1_3_19_PRIVATESTREAM 10
71
73int cDevice::useDevice = 0;
75std::atomic<int> cDevice::currentChannel(1);
79
81:patPmtParser(true)
82{
84 dsyslog("new device number %d (card index %d)", numDevices + 1, CardIndex() + 1);
85
86 SetDescription("device %d receiver", numDevices + 1);
87
88 mute = false;
90
91 sectionHandler = NULL;
92 eitFilter = NULL;
93 patFilter = NULL;
94 sdtFilter = NULL;
95 nitFilter = NULL;
96
97 camSlot = NULL;
98
99 occupiedFrom = 0;
100 occupiedTimeout = 0;
102
103 player = NULL;
104 isPlayingVideo = false;
105 keepTracks = false; // used in ClrAvailableTracks()!
110 liveSubtitle = NULL;
113
114 for (int i = 0; i < MAXRECEIVERS; i++)
115 receiver[i] = NULL;
116
118 device[numDevices++] = this;
119 else
120 esyslog("ERROR: too many devices!");
121}
122
124{
125 Detach(player);
127 delete liveSubtitle;
129 if (this == primaryDevice)
130 primaryDevice = NULL;
131 Cancel(3);
132}
133
135{
136 for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) {
137 bool ready = true;
138 for (int i = 0; i < numDevices; i++) {
139 if (device[i] && !device[i]->Ready()) {
140 ready = false;
142 }
143 }
144 if (ready)
145 return true;
146 }
147 return false;
148}
149
151{
152 if (n < MAXDEVICES)
153 useDevice |= (1 << n);
154}
155
157{
158 if (n > 0) {
159 nextCardIndex += n;
161 esyslog("ERROR: nextCardIndex too big (%d)", nextCardIndex);
162 }
163 else if (n < 0)
164 esyslog("ERROR: invalid value in nextCardIndex(%d)", n);
165 return nextCardIndex;
166}
167
169{
170 for (int i = 0; i < numDevices; i++) {
171 if (device[i] == this)
172 return i;
173 }
174 return -1;
175}
176
178{
179 return "";
180}
181
183{
184 return "";
185}
186
188{
189 if (!On) {
190 cLiveSubtitle *ls;
191 {
193 ls = liveSubtitle; // deleted outside the mutex, see SetCurrentSubtitleTrack()
194 liveSubtitle = NULL;
196 }
197 delete ls;
198 }
199}
200
202{
203 n--;
204 if (0 <= n && n < numDevices && device[n]) {
205 isyslog("setting primary device to %d", n + 1);
206 if (primaryDevice)
212 Setup.PrimaryDVB = n + 1;
213 return true;
214 }
215 esyslog("ERROR: invalid primary device number: %d", n + 1);
216 return false;
217}
218
219bool cDevice::HasDecoder(void) const
220{
221 return false;
222}
223
225{
226 return NULL;
227}
228
230{
232 if (!d)
233 d = PrimaryDevice();
234 return d;
235}
236
238{
239 return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
240}
241
242static int GetClippedNumProvidedSystems(int AvailableBits, cDevice *Device)
243{
244 int MaxNumProvidedSystems = (1 << AvailableBits) - 1;
245 int NumProvidedSystems = Device->NumProvidedSystems();
246 if (NumProvidedSystems > MaxNumProvidedSystems) {
247 esyslog("ERROR: device %d supports %d modulation systems but cDevice::GetDevice() currently only supports %d delivery systems which should be fixed", Device->DeviceNumber() + 1, NumProvidedSystems, MaxNumProvidedSystems);
248 NumProvidedSystems = MaxNumProvidedSystems;
249 }
250 else if (NumProvidedSystems <= 0) {
251 esyslog("ERROR: device %d reported an invalid number (%d) of supported delivery systems - assuming 1", Device->DeviceNumber() + 1, NumProvidedSystems);
252 NumProvidedSystems = 1;
253 }
254 return NumProvidedSystems;
255}
256
257cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView, bool Query)
258{
259 // Collect the current priorities of all CAM slots that can decrypt the channel:
260 int NumCamSlots = CamSlots.Count();
261 int SlotPriority[NumCamSlots + 1]; // +1 to avoid a zero sized array in case there are no CAM slots
262 int NumUsableSlots = 0;
263 bool InternalCamNeeded = false;
264 if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
266 SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used
267 if (CamSlot->ModuleStatus() == msReady) {
268 if (CamSlot->ProvidesCa(Channel->Caids())) {
270 SlotPriority[CamSlot->Index()] = CamSlot->MtdActive() ? IDLEPRIORITY : CamSlot->Priority(); // we don't need to take the priority into account here for MTD CAM slots, because they can be used with several devices in parallel
271 NumUsableSlots++;
272 }
273 }
274 }
275 }
276 if (!NumUsableSlots)
277 InternalCamNeeded = true; // no CAM is able to decrypt this channel
278 }
279
280 bool NeedsDetachReceivers = false;
281 cDevice *d = NULL;
282 cCamSlot *s = NULL;
283
284 uint32_t Impact = 0xFFFFFFFF; // we're looking for a device with the least impact
285 for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) {
286 if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY)
287 continue; // there is no CAM available in this slot
288 for (int i = 0; i < numDevices; i++) {
289 if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device[i]->DeviceNumber() + 1)
290 continue; // a specific card was requested, but not this one
292 if (InternalCamNeeded && !HasInternalCam)
293 continue; // no CAM is able to decrypt this channel and the device uses vdr handled CAMs
294 if (NumUsableSlots && !HasInternalCam && !CamSlots.Get(j)->Assign(device[i], true))
295 continue; // CAM slot can't be used with this device
296 bool ndr = false;
297 bool TunedToTransponder = device[i]->IsTunedToTransponder(Channel);
298 if (TunedToTransponder || device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basically able to do the job
299 bool OccupiedOtherTransponder = !TunedToTransponder && device[i]->Occupied();
300 if (OccupiedOtherTransponder)
301 ndr = true;
302 if (NumUsableSlots && !HasInternalCam) {
303 if (cCamSlot *csi = device[i]->CamSlot()) {
304 cCamSlot *csj = CamSlots.Get(j);
305 if ((csj->MtdActive() ? csi->MasterSlot() : csi) != csj)
306 ndr = true; // using a different CAM slot requires detaching receivers
307 }
308 }
309 // Put together an integer number that reflects the "impact" using
310 // this device would have on the overall system. Each condition is represented
311 // by one bit in the number (or several bits, if the condition is actually
312 // a numeric value). The sequence in which the conditions are listed corresponds
313 // to their individual severity, where the one listed first will make the most
314 // difference, because it results in the most significant bit of the result.
315 uint32_t imp = 0;
316 imp <<= 1; imp |= (LiveView && NumUsableSlots && !HasInternalCam) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlots.Get(j)->MasterSlotNumber()) || ndr : 0; // prefer CAMs that are known to decrypt this channel for live viewing, if we don't need to detach existing receivers
317 imp <<= 1; imp |= LiveView ? !device[i]->IsPrimaryDevice() || ndr : 0; // prefer the primary device for live viewing if we don't need to detach existing receivers
318 imp <<= 1; imp |= !device[i]->Receiving() && (device[i] != cTransferControl::ReceiverDevice() || device[i]->IsPrimaryDevice()) || ndr; // use receiving devices if we don't need to detach existing receivers, but avoid primary device in local transfer mode
319 imp <<= 1; imp |= device[i]->Receiving() || OccupiedOtherTransponder; // avoid devices that are receiving
320 imp <<= 5; imp |= GetClippedNumProvidedSystems(5, device[i]) - 1; // avoid cards which support multiple delivery systems
321 imp <<= 8; imp |= device[i]->Priority() - IDLEPRIORITY; // use the device with the lowest priority (- IDLEPRIORITY to assure that values -100..99 can be used)
322 imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
323 imp <<= 8; imp |= ((NumUsableSlots && !HasInternalCam) ? SlotPriority[j] : IDLEPRIORITY) - IDLEPRIORITY;// use the CAM slot with the lowest priority (- IDLEPRIORITY to assure that values -100..99 can be used)
324 imp <<= 1; imp |= ndr; // avoid devices if we need to detach existing receivers
325 imp <<= 1; imp |= (NumUsableSlots || InternalCamNeeded) ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
326 imp <<= 1; imp |= device[i]->AvoidRecording(); // avoid SD full featured cards
327 imp <<= 1; imp |= (NumUsableSlots && !HasInternalCam) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlots.Get(j)->MasterSlotNumber()) : 0; // prefer CAMs that are known to decrypt this channel
328 imp <<= 1; imp |= device[i]->IsPrimaryDevice(); // avoid the primary device
329 if (imp < Impact) {
330 // This device has less impact than any previous one, so we take it.
331 Impact = imp;
332 d = device[i];
333 NeedsDetachReceivers = ndr;
334 if (NumUsableSlots && !HasInternalCam)
335 s = CamSlots.Get(j);
336 }
337 //dsyslog("device %d provides channel %d prio %d ndr %d imp %.8X", device[i]->DeviceNumber() + 1, Channel->Number(), Priority, ndr, imp);
338 }
339 }
340 if (!NumUsableSlots)
341 break; // no CAM necessary, so just one loop over the devices
342 }
343 if (d) {
344 if (!Query && NeedsDetachReceivers)
346 if (s) {
347 // Some of the following statements could probably be combined, but let's keep them
348 // explicit so we can clearly see every single aspect of the decisions made here.
349 if (d->CamSlot()) {
350 if (s->MtdActive()) {
351 if (s == d->CamSlot()->MasterSlot()) {
352 // device d already has a proper CAM slot, so nothing to do here
353 }
354 else {
355 // device d has a CAM slot, but it's not the right one
356 if (!Query) {
357 d->CamSlot()->Assign(NULL);
358 s = s->MtdSpawn();
359 s->Assign(d);
360 }
361 }
362 }
363 else {
364 if (s->Device()) {
365 if (s->Device() != d) {
366 // CAM slot s is currently assigned to a different device than d
367 if (Priority > s->Priority()) {
368 if (!Query) {
369 d->CamSlot()->Assign(NULL);
370 s->Assign(d);
371 }
372 }
373 else {
374 d = NULL;
375 s = NULL;
376 }
377 }
378 else {
379 // device d already has a proper CAM slot, so nothing to do here
380 }
381 }
382 else {
383 if (s != d->CamSlot()) {
384 // device d has a CAM slot, but it's not the right one
385 if (!Query) {
386 d->CamSlot()->Assign(NULL);
387 s->Assign(d);
388 }
389 }
390 else {
391 // device d already has a proper CAM slot, so nothing to do here
392 }
393 }
394 }
395 }
396 else {
397 // device d has no CAM slot, ...
398 if (s->MtdActive()) {
399 // ... so we assign s with MTD support
400 if (!Query) {
401 s = s->MtdSpawn();
402 s->Assign(d);
403 }
404 }
405 else {
406 // CAM slot s has no MTD support ...
407 if (s->Device()) {
408 // ... but it is assigned to a different device, so we reassign it to d
409 if (Priority > s->Priority()) {
410 if (!Query) {
412 s->Assign(d);
413 }
414 }
415 else {
416 d = NULL;
417 s = NULL;
418 }
419 }
420 else {
421 // ... and is not assigned to any device, so we just assign it to d
422 if (!Query)
423 s->Assign(d);
424 }
425 }
426 }
427 }
428 else if (d->CamSlot() && !d->CamSlot()->IsDecrypting())
429 d->CamSlot()->Assign(NULL);
430 }
431 return d;
432}
433
435{
436 cDevice *Device = NULL;
437 for (int i = 0; i < cDevice::NumDevices(); i++) {
438 if (cDevice *d = cDevice::GetDevice(i)) {
439 if (d->IsTunedToTransponder(Channel))
440 return d; // if any device is tuned to the transponder, we're done
441 if (d->ProvidesTransponder(Channel)) {
442 if (d->MaySwitchTransponder(Channel))
443 return d; // this device may switch to the transponder without disturbing any receiver or live view
444 else if (!d->Occupied(Priority) && !d->IsBonded() && d->Priority(true) < LIVEPRIORITY) { // MaySwitchTransponder() implicitly calls Occupied()
445 // we select only devices with priority < LIVEPRIORITY, so device can be switched without impact on recordings or live viewing
446 if (d->Priority() < Priority && (!Device || d->Priority() < Device->Priority()))
447 Device = d; // use this one only if no other with less impact can be found
448 }
449 }
450 }
451 }
452 return Device;
453}
454
456{
457 if (cCamSlot *cs = camSlot) {
458 if (!cs->IsDecrypting() && !cs->IsActivating())
459 cs->Assign(NULL);
460 }
461}
462
464{
465 return false;
466}
467
473
475{
477 for (int i = 0; i < numDevices; i++) {
478 delete device[i];
479 device[i] = NULL;
480 }
481}
482
483uchar *cDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
484{
485 return NULL;
486}
487
488bool cDevice::GrabImageFile(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
489{
490 int result = 0;
491 int fd = open(FileName, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC, DEFFILEMODE);
492 if (fd >= 0) {
493 int ImageSize;
494 uchar *Image = GrabImage(ImageSize, Jpeg, Quality, SizeX, SizeY);
495 if (Image) {
496 if (safe_write(fd, Image, ImageSize) == ImageSize)
497 isyslog("grabbed image to %s", FileName);
498 else {
499 LOG_ERROR_STR(FileName);
500 result |= 1;
501 }
502 free(Image);
503 }
504 else
505 result |= 1;
506 close(fd);
507 }
508 else {
509 LOG_ERROR_STR(FileName);
510 result |= 1;
511 }
512 return result == 0;
513}
514
516{
517 cSpuDecoder *spuDecoder = GetSpuDecoder();
518 if (spuDecoder) {
519 if (Setup.VideoFormat)
521 else {
522 switch (VideoDisplayFormat) {
523 case vdfPanAndScan:
525 break;
526 case vdfLetterBox:
528 break;
529 case vdfCenterCutOut:
531 break;
532 default: esyslog("ERROR: invalid value for VideoDisplayFormat '%d'", VideoDisplayFormat);
533 }
534 }
535 }
536}
537
538void cDevice::SetVideoFormat(bool VideoFormat16_9)
539{
540}
541
542void cDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect)
543{
544 Width = 0;
545 Height = 0;
546 VideoAspect = 1.0;
547}
548
549void cDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
550{
551 Width = 720;
552 Height = 480;
553 PixelAspect = 1.0;
554}
555
556//#define PRINTPIDS(s) { char b[500]; char *q = b; q += sprintf(q, "%d %s ", DeviceNumber() + 1, s); for (int i = 0; i < MAXPIDHANDLES; i++) q += sprintf(q, " %s%4d %d", i == ptOther ? "* " : "", pidHandles[i].pid, pidHandles[i].used); dsyslog("%s", b); }
557#define PRINTPIDS(s)
558
559bool cDevice::HasPid(int Pid) const
560{
561 cMutexLock MutexLock(&mutexPids);
562 for (int i = 0; i < MAXPIDHANDLES; i++) {
563 if (pidHandles[i].pid == Pid)
564 return true;
565 }
566 return false;
567}
568
569bool cDevice::AddPid(int Pid, ePidType PidType, int StreamType)
570{
571 // cCamSlot::SetPid() and DetachAll() are called after releasing mutexPids.
572 // The locks they take are held while calling AddPid() elsewhere (the CAM
573 // slot's and cCaPidReceiver's mutexes when adding ECM/EMM PIDs, mutexReceiver
574 // in AttachReceiver()):
575 cCamSlot *NotifyCamSlot = NULL;
576 bool Failed = false;
577 {
578 cMutexLock MutexLock(&mutexPids);
579 if (Pid || PidType == ptPcr) {
580 int n = -1;
581 int a = -1;
582 if (PidType != ptPcr) { // PPID always has to be explicit
583 for (int i = 0; i < MAXPIDHANDLES; i++) {
584 if (i != ptPcr) {
585 if (pidHandles[i].pid == Pid)
586 n = i;
587 else if (a < 0 && i >= ptOther && !pidHandles[i].used)
588 a = i;
589 }
590 }
591 }
592 if (n >= 0) {
593 // The Pid is already in use
594 if (++pidHandles[n].used == 2 && n <= ptTeletext) {
595 // It's a special PID that may have to be switched into "tap" mode
596 PRINTPIDS("A");
597 if (!SetPid(&pidHandles[n], n, true)) {
598 esyslog("ERROR: can't set PID %d on device %d", Pid, DeviceNumber() + 1);
599 Failed = true;
600 }
601 else
602 NotifyCamSlot = camSlot;
603 }
604 PRINTPIDS("a");
605 }
606 else {
607 if (PidType < ptOther) {
608 // The Pid is not yet in use and it is a special one
609 n = PidType;
610 }
611 else if (a >= 0) {
612 // The Pid is not yet in use and we have a free slot
613 n = a;
614 }
615 else {
616 esyslog("ERROR: no free slot for PID %d on device %d", Pid, DeviceNumber() + 1);
617 return false;
618 }
619 pidHandles[n].pid = Pid;
620 pidHandles[n].streamType = StreamType;
621 pidHandles[n].used = 1;
622 PRINTPIDS("C");
623 if (!SetPid(&pidHandles[n], n, true)) {
624 esyslog("ERROR: can't set PID %d on device %d", Pid, DeviceNumber() + 1);
625 Failed = true;
626 }
627 else
628 NotifyCamSlot = camSlot;
629 }
630 }
631 }
632 if (Failed) {
633 if (PidType <= ptTeletext)
634 DetachAll(Pid);
635 DelPid(Pid, PidType);
636 return false;
637 }
638 if (NotifyCamSlot)
639 NotifyCamSlot->SetPid(Pid, true);
640 return true;
641}
642
643void cDevice::DelPid(int Pid, ePidType PidType)
644{
645 cCamSlot *NotifyCamSlot = NULL; // notified after releasing mutexPids, see AddPid()
646 {
647 cMutexLock MutexLock(&mutexPids);
648 if (Pid || PidType == ptPcr) {
649 int n = -1;
650 if (PidType == ptPcr)
651 n = PidType; // PPID always has to be explicit
652 else {
653 for (int i = 0; i < MAXPIDHANDLES; i++) {
654 if (pidHandles[i].pid == Pid) {
655 n = i;
656 break;
657 }
658 }
659 }
660 if (n >= 0 && pidHandles[n].used) {
661 PRINTPIDS("D");
662 if (--pidHandles[n].used < 2) {
663 SetPid(&pidHandles[n], n, false);
664 if (pidHandles[n].used == 0) {
665 pidHandles[n].handle = -1;
666 pidHandles[n].pid = 0;
667 NotifyCamSlot = camSlot;
668 }
669 }
670 PRINTPIDS("E");
671 }
672 }
673 }
674 if (NotifyCamSlot)
675 NotifyCamSlot->SetPid(Pid, false);
676}
677
678bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
679{
680 return false;
681}
682
684{
685 cMutexLock MutexLock(&mutexPids);
686 for (int i = ptAudio; i < ptOther; i++) {
687 if (pidHandles[i].pid)
688 DelPid(pidHandles[i].pid, ePidType(i));
689 }
690}
691
702
704{
705 if (sectionHandler) {
706 delete sectionHandler; // automatically detaches filters
707 delete nitFilter;
708 delete sdtFilter;
709 delete patFilter;
710 delete eitFilter;
711 nitFilter = NULL;
712 sdtFilter = NULL;
713 patFilter = NULL;
714 eitFilter = NULL;
715 sectionHandler = NULL;
716 }
717}
718
719int cDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
720{
721 return -1;
722}
723
724int cDevice::ReadFilter(int Handle, void *Buffer, size_t Length)
725{
726 return safe_read(Handle, Buffer, Length);
727}
728
729void cDevice::CloseFilter(int Handle)
730{
731 close(Handle);
732}
733
735{
736 if (sectionHandler)
737 sectionHandler->Attach(Filter);
738}
739
741{
742 if (sectionHandler)
743 sectionHandler->Detach(Filter);
744}
745
746bool cDevice::ProvidesSource(int Source) const
747{
748 return false;
749}
750
752{
753 cDeviceHook *Hook = deviceHooks.First();
754 while (Hook) {
755 if (!Hook->DeviceProvidesTransponder(this, Channel))
756 return false;
757 Hook = deviceHooks.Next(Hook);
758 }
759 return true;
760}
761
763{
764 cDeviceHook *Hook = deviceHooks.First();
765 while (Hook) {
766 if (!Hook->DeviceProvidesEIT(this))
767 return false;
768 Hook = deviceHooks.Next(Hook);
769 }
770 return true;
771}
772
773bool cDevice::ProvidesTransponder(const cChannel *Channel) const
774{
775 return false;
776}
777
779{
780 for (int i = 0; i < numDevices; i++) {
781 if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel))
782 return false;
783 }
784 return true;
785}
786
787bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
788{
789 return false;
790}
791
792bool cDevice::ProvidesEIT(void) const
793{
794 return false;
795}
796
798{
799 return 0;
800}
801
803{
804 return NULL;
805}
806
807bool cDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
808{
809 return false;
810}
811
813{
814 return -1;
815}
816
818{
819 return -1;
820}
821
823{
824 return NULL;
825}
826
827bool cDevice::IsTunedToTransponder(const cChannel *Channel) const
828{
829 return false;
830}
831
832bool cDevice::MaySwitchTransponder(const cChannel *Channel) const
833{
835}
836
838{
839}
840
842{
843 if (!Occupied() && !Receiving() && !(pidHandles[ptAudio].pid || pidHandles[ptVideo].pid || pidHandles[ptDolby].pid))
844 SetPowerSaveMode(true);
845}
846
847bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView)
848{
849 if (LiveView) {
850 isyslog("switching to channel %d %s (%s)", Channel->Number(), *Channel->GetChannelID().ToString(), Channel->Name());
851 cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
852 // and, if decrypted, this removes the now superfluous PIDs from the CAM, too
853 }
854 for (int i = 3; i--;) {
855 switch (SetChannel(Channel, LiveView)) {
856 case scrOk: return true;
857 case scrNotAvailable: Skins.QueueMessage(mtInfo, tr("Channel not available!"));
858 return false;
859 case scrNoTransfer: Skins.QueueMessage(mtError, tr("Can't start Transfer Mode!"));
860 return false;
861 case scrFailed: break; // loop will retry
862 default: esyslog("ERROR: invalid return value from SetChannel");
863 }
864 esyslog("retrying");
865 }
866 return false;
867}
868
869bool cDevice::SwitchChannel(int Direction)
870{
871 bool result = false;
872 Direction = sgn(Direction);
873 if (Direction) {
874 cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
875 // and, if decrypted, this removes the now superfluous PIDs from the CAM, too
876 int n = CurrentChannel() + Direction;
877 int first = n;
879 const cChannel *Channel;
880 while ((Channel = Channels->GetByNumber(n, Direction)) != NULL) {
881 // try only channels which are currently available
882 if (GetDevice(Channel, LIVEPRIORITY, true, true))
883 break;
884 n = Channel->Number() + Direction;
885 }
886 if (Channel) {
887 int d = n - first;
888 if (abs(d) == 1)
889 dsyslog("skipped channel %d", first);
890 else if (d)
891 dsyslog("skipped channels %d..%d", first, n - sgn(d));
892 if (PrimaryDevice()->SwitchChannel(Channel, true))
893 result = true;
894 }
895 else if (n != first)
896 Skins.QueueMessage(mtError, tr("Channel not available!"));
897 }
898 return result;
899}
900
901eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
902{
903 cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN and HasProgramme()
904 cStatus::MsgChannelSwitch(this, 0, LiveView);
905
906 if (LiveView) {
907 if (IsPrimaryDevice() && !Replaying() && !Transferring()) { // this is only for FF DVB cards!
909 if (const cChannel *ch = Channels->GetByNumber(currentChannel)) {
910 if (patFilter)
911 patFilter->Release(ch->Sid());
912 }
913 }
914 StopReplay();
915 cLiveSubtitle *ls;
916 {
918 ls = liveSubtitle; // deleted outside the mutex, see SetCurrentSubtitleTrack()
919 liveSubtitle = NULL;
921 }
922 delete ls;
923 }
924
925 cDevice *Device = (LiveView && IsPrimaryDevice(false)) ? GetDevice(Channel, LIVEPRIORITY, true) : this;
926
927 bool NeedsTransferMode = LiveView && Device != PrimaryDevice();
928 // If the CAM slot wants the TS data, we need to switch to Transfer Mode:
929 cCamSlot *PrimaryCamSlot = CamSlot();
930 if (!NeedsTransferMode && LiveView && IsPrimaryDevice() && PrimaryCamSlot && PrimaryCamSlot->WantsTsData())
931 NeedsTransferMode = true;
932
933 eSetChannelResult Result = scrOk;
934
935 // If this DVB card can't receive this channel, let's see if we can
936 // use the card that actually can receive it and transfer data from there:
937
938 if (NeedsTransferMode) {
939 if (Device && PrimaryDevice()->CanReplay()) {
940 if (Device->SetChannel(Channel, false) != scrOk) // calling SetChannel() directly, not SwitchChannel()!
941 Result = scrNoTransfer;
942 }
943 else
944 Result = scrNotAvailable;
945 }
946 else {
947 // Stop section handling:
948 if (sectionHandler) {
951 }
952 // Tell the camSlot about the channel switch and add all PIDs of this
953 // channel to it, for possible later decryption:
954 if (cCamSlot *cs = camSlot)
955 cs->AddChannel(Channel);
956 SetPowerSaveMode(false);
957 if (SetChannelDevice(Channel, LiveView)) {
958 // Start section handling:
959 if (sectionHandler) {
960 sectionHandler->SetChannel(Channel);
962 }
963 // Start decrypting any PIDs that might have been set in SetChannelDevice():
964 if (cCamSlot *cs = camSlot)
965 cs->StartDecrypting();
966 }
967 else
968 Result = scrFailed;
969 }
970
971 if (Result == scrOk) {
972 if (LiveView) {
973 if (IsPrimaryDevice(false))
974 currentChannel = Channel->Number();
975 if (IsPrimaryDevice()) {
976 if (patFilter) // this is only for FF DVB cards!
977 patFilter->Request(Channel->Sid());
978 // Set the available audio tracks:
980 for (int i = 0; i < MAXAPIDS; i++)
981 SetAvailableTrack(ttAudio, i, Channel->Apid(i), Channel->Alang(i));
982 for (int i = 0; i < MAXDPIDS; i++)
983 SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i));
984 for (int i = 0; i < MAXSPIDS; i++)
985 SetAvailableTrack(ttSubtitle, i, Channel->Spid(i), Channel->Slang(i));
986 if (!NeedsTransferMode)
987 EnsureAudioTrack(true);
989 }
990 }
991 // Launch the transfer control only after the channel switch is complete.
992 // Launch() makes the control visible to the main loop, which attaches it and
993 // starts feeding TS data into the primary device - if that happens while this
994 // function is still setting up the track state above, the two threads race
995 // on availableTracks et al. (SwitchChannel() may run in the SVDRP thread).
996 // Attach it right here instead of waiting for the main loop: until then
997 // cTransfer drops all TS data, and HasProgramme() reports no programme, which
998 // can make the main loop switch to the channel a second time:
999 if (NeedsTransferMode) {
1000 cControl::Launch(new cTransferControl(Device, Channel));
1002 }
1003 cStatus::MsgChannelSwitch(this, Channel->Number(), LiveView); // only report status if channel switch successful
1004 }
1005
1006 return Result;
1007}
1008
1010{
1013 if (const cChannel *Channel = Channels->GetByNumber(CurrentChannel())) {
1014 SetPowerSaveMode(false);
1015 SetChannelDevice(Channel, false); // this implicitly starts Transfer Mode
1016 }
1017 }
1018}
1019
1021{
1023 return 0;
1024 int Seconds = occupiedTimeout - time(NULL);
1025 return Seconds > 0 ? Seconds : 0;
1026}
1027
1028void cDevice::SetOccupied(int Seconds, int Priority, time_t From)
1029{
1030 if (Seconds < 0)
1031 return;
1032 if (From == 0)
1033 From = time(NULL);
1034 if (From == occupiedFrom)
1036 else {
1038 occupiedFrom = From;
1039 }
1040 occupiedTimeout = From + min(Seconds, MAXOCCUPIEDTIMEOUT);
1041}
1042
1043bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
1044{
1045 return false;
1046}
1047
1048bool cDevice::HasLock(int TimeoutMs) const
1049{
1050 return true;
1051}
1052
1054{
1055 cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN and HasProgramme()
1057}
1058
1060{
1061 return 0;
1062}
1063
1065{
1066}
1067
1069{
1070}
1071
1073{
1074}
1075
1079
1083
1085{
1086 int OldVolume = volume;
1087 mute = !mute;
1088 //XXX why is it necessary to use different sequences???
1089 if (mute) {
1090 SetVolume(0, true);
1091 Audios.MuteAudio(mute); // Mute external audio after analog audio
1092 }
1093 else {
1094 Audios.MuteAudio(mute); // Enable external audio before analog audio
1095 SetVolume(OldVolume, true);
1096 }
1097 volume = OldVolume;
1098 return mute;
1099}
1100
1102{
1103 int c = GetAudioChannelDevice();
1104 return (0 <= c && c <= 2) ? c : 0;
1105}
1106
1107void cDevice::SetAudioChannel(int AudioChannel)
1108{
1109 if (0 <= AudioChannel && AudioChannel <= 2)
1110 SetAudioChannelDevice(AudioChannel);
1111}
1112
1113void cDevice::SetVolume(int Volume, bool Absolute)
1114{
1115 int OldVolume = volume;
1116 double VolumeDelta = double(MAXVOLUME) / Setup.VolumeSteps;
1117 double VolumeLinearize = (Setup.VolumeLinearize >= 0) ? (Setup.VolumeLinearize / 10.0 + 1.0) : (1.0 / ((-Setup.VolumeLinearize / 10.0) + 1.0));
1118 volume = constrain(int(floor((Absolute ? Volume : volume + Volume) / VolumeDelta + 0.5) * VolumeDelta), 0, MAXVOLUME);
1119 SetVolumeDevice(MAXVOLUME - int(pow(1.0 - pow(double(volume) / MAXVOLUME, VolumeLinearize), 1.0 / VolumeLinearize) * MAXVOLUME));
1120 Absolute |= mute;
1121 cStatus::MsgSetVolume(Absolute ? volume.load() : volume - OldVolume, Absolute);
1122 if (volume > 0) {
1123 mute = false;
1125 }
1126}
1127
1128void cDevice::ClrAvailableTracks(bool DescriptionsOnly, bool IdsOnly)
1129{
1130 if (keepTracks)
1131 return;
1133 if (DescriptionsOnly) {
1134 for (int i = ttNone; i < ttMaxTrackTypes; i++)
1136 }
1137 else {
1138 if (IdsOnly) {
1139 for (int i = ttNone; i < ttMaxTrackTypes; i++)
1140 availableTracks[i].id = 0;
1141 }
1142 else
1143 memset(availableTracks, 0, sizeof(availableTracks));
1145 SetAudioChannel(0); // fall back to stereo
1149 }
1150}
1151
1152bool cDevice::SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language, const char *Description)
1153{
1155 eTrackType t = eTrackType(Type + Index);
1156 if (Type == ttAudio && IS_AUDIO_TRACK(t) ||
1157 Type == ttDolby && IS_DOLBY_TRACK(t) ||
1158 Type == ttSubtitle && IS_SUBTITLE_TRACK(t)) {
1159 if (Language)
1160 strn0cpy(availableTracks[t].language, Language, sizeof(availableTracks[t].language));
1161 if (Description)
1163 if (Id) {
1164 availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking
1165 if (Type == ttAudio || Type == ttDolby) {
1166 int numAudioTracks = NumAudioTracks();
1167 if (!availableTracks[currentAudioTrack].id && numAudioTracks && currentAudioTrackMissingCount++ > numAudioTracks * 10)
1169 else if (t == currentAudioTrack)
1171 }
1174 }
1175 return true;
1176 }
1177 else
1178 esyslog("ERROR: SetAvailableTrack called with invalid Type/Index (%d/%d)", Type, Index);
1179 return false;
1180}
1181
1183{
1184 return (ttNone < Type && Type < ttMaxTrackTypes) ? &availableTracks[Type] : NULL;
1185}
1186
1188{
1190 if (const tTrackId *Track = GetTrack(Type)) {
1191 TrackId = *Track;
1192 return true;
1193 }
1194 return false;
1195}
1196
1197int cDevice::NumTracks(eTrackType FirstTrack, eTrackType LastTrack) const
1198{
1200 int n = 0;
1201 for (int i = FirstTrack; i <= LastTrack; i++) {
1202 if (availableTracks[i].id)
1203 n++;
1204 }
1205 return n;
1206}
1207
1209{
1211}
1212
1214{
1216}
1217
1219{
1220 if (ttNone < Type && Type <= ttDolbyLast) {
1221 cPlayer *p;
1222 {
1224 if (IS_DOLBY_TRACK(Type))
1226 currentAudioTrack = Type;
1227 p = player;
1228 if (!p)
1230 }
1231 // Not under the mutex - the player resyncs under its thread lock, which its thread holds
1232 // while PlayTs() -> ParsePmt() -> ClrAvailableTracks() waits for the mutex:
1233 if (p)
1234 p->SetAudioTrack(Type, GetTrack(Type));
1235 if (IS_AUDIO_TRACK(Type))
1236 SetDigitalAudioDevice(false);
1237 return true;
1238 }
1239 return false;
1240}
1241
1243{
1244 if (Type == ttNone || IS_SUBTITLE_TRACK(Type)) {
1245 currentSubtitleTrack = Type;
1247 cLiveSubtitle *ls;
1248 {
1249 // mutexCurrentSubtitleTrack guards dvbSubtitleConverter and liveSubtitle
1250 // against the play/receiver thread and other control paths. liveSubtitle
1251 // is only unlinked under the mutex and deleted after releasing it:
1252 // ~cLiveSubtitle() detaches the receiver, which takes mutexReceiver - and
1253 // the receiver thread holds mutexReceiver while it delivers data through
1254 // cLiveSubtitle::Receive() -> PlayTs() -> PlayTsSubtitle(), where it
1255 // waits for mutexCurrentSubtitleTrack. Deleting under the mutex would
1256 // deadlock the two:
1260 if (Type == ttNone) {
1263 else
1265 }
1266 else if (Replaying() && !Transferring() && Setup.DisplaySubtitles == SUBTITLES_REWIND && Manual)
1268 }
1269 ls = liveSubtitle;
1270 liveSubtitle = NULL;
1271 }
1272 delete ls;
1273 if (cPlayer *p = player)
1274 p->SetSubtitleTrack(currentSubtitleTrack, GetTrack(currentSubtitleTrack));
1275 else
1278 const tTrackId *TrackId = GetTrack(currentSubtitleTrack);
1279 if (TrackId && TrackId->id) {
1280 liveSubtitle = new cLiveSubtitle(TrackId->id);
1282 }
1283 }
1284 return true;
1285 }
1286 return false;
1287}
1288
1295
1297{
1298 if (keepTracks)
1299 return;
1300 if (Force || !availableTracks[currentAudioTrack].id) {
1301 eTrackType PreferredTrack = ttAudioFirst;
1302 int PreferredAudioChannel = 0;
1303 int LanguagePreference = -1;
1304 int StartCheck = Setup.CurrentDolby ? ttDolbyFirst : ttAudioFirst;
1305 int EndCheck = ttDolbyLast;
1306 for (int i = StartCheck; i <= EndCheck; i++) {
1307 const tTrackId *TrackId = GetTrack(eTrackType(i));
1308 int pos = 0;
1309 if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.AudioLanguages, TrackId->language, LanguagePreference, &pos)) {
1310 PreferredTrack = eTrackType(i);
1311 PreferredAudioChannel = pos;
1312 }
1313 if (Setup.CurrentDolby && i == ttDolbyLast) {
1314 i = ttAudioFirst - 1;
1315 EndCheck = ttAudioLast;
1316 }
1317 }
1318 // Make sure we're set to an available audio track:
1319 const tTrackId *Track = GetTrack(GetCurrentAudioTrack());
1320 if (Force || !Track || !Track->id || PreferredTrack != GetCurrentAudioTrack()) {
1321 if (!Force) // only log this for automatic changes
1322 dsyslog("setting audio track to %d (%d)", PreferredTrack, PreferredAudioChannel);
1323 SetCurrentAudioTrack(PreferredTrack);
1324 SetAudioChannel(PreferredAudioChannel);
1325 }
1326 }
1327}
1328
1330{
1331 if (keepTracks)
1332 return;
1334 eTrackType PreferredTrack = ttNone;
1335 int LanguagePreference = INT_MAX; // higher than the maximum possible value
1336 for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) {
1337 const tTrackId *TrackId = GetTrack(eTrackType(i));
1338 if (TrackId && TrackId->id && (I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference) ||
1339 (i == ttSubtitleFirst + 8 && !*TrackId->language && LanguagePreference == INT_MAX))) // compatibility mode for old subtitles plugin
1340 PreferredTrack = eTrackType(i);
1341 }
1342 // Make sure we're set to an available subtitle track:
1343 const tTrackId *Track = GetTrack(GetCurrentSubtitleTrack());
1344 if (!Track || !Track->id || PreferredTrack != GetCurrentSubtitleTrack())
1345 SetCurrentSubtitleTrack(PreferredTrack);
1346 }
1347 else
1349}
1350
1351bool cDevice::CanReplay(void) const
1352{
1353 return HasDecoder();
1354}
1355
1357{
1358 return false;
1359}
1360
1361int64_t cDevice::GetSTC(void)
1362{
1363 return -1;
1364}
1365
1366void cDevice::TrickSpeed(int Speed, bool Forward)
1367{
1368}
1369
1377
1379{
1384}
1385
1387{
1388 Audios.MuteAudio(true);
1392}
1393
1395{
1396 Audios.MuteAudio(true);
1397}
1398
1399void cDevice::StillPicture(const uchar *Data, int Length)
1400{
1401 if (Data[0] == 0x47) {
1402 // TS data
1403 cTsToPes TsToPes;
1404 uchar *buf = NULL;
1405 int Size = 0;
1406 while (Length >= TS_SIZE) {
1407 int Pid = TsPid(Data);
1408 if (Pid == PATPID)
1410 else if (patPmtParser.IsPmtPid(Pid))
1412 else if (Pid == patPmtParser.Vpid()) {
1413 if (TsPayloadStart(Data)) {
1414 int l;
1415 while (const uchar *p = TsToPes.GetPes(l)) {
1416 int Offset = Size;
1417 int NewSize = Size + l;
1418 if (uchar *NewBuffer = (uchar *)realloc(buf, NewSize)) {
1419 Size = NewSize;
1420 buf = NewBuffer;
1421 memcpy(buf + Offset, p, l);
1422 }
1423 else {
1424 LOG_ERROR_STR("out of memory");
1425 free(buf);
1426 return;
1427 }
1428 }
1429 TsToPes.Reset();
1430 }
1431 TsToPes.PutTs(Data, TS_SIZE);
1432 }
1433 Length -= TS_SIZE;
1434 Data += TS_SIZE;
1435 }
1436 int l;
1437 while (const uchar *p = TsToPes.GetPes(l)) {
1438 int Offset = Size;
1439 int NewSize = Size + l;
1440 if (uchar *NewBuffer = (uchar *)realloc(buf, NewSize)) {
1441 Size = NewSize;
1442 buf = NewBuffer;
1443 memcpy(buf + Offset, p, l);
1444 }
1445 else {
1446 esyslog("ERROR: out of memory");
1447 free(buf);
1448 return;
1449 }
1450 }
1451 if (buf) {
1452 StillPicture(buf, Size);
1453 free(buf);
1454 }
1455 }
1456}
1457
1458bool cDevice::Replaying(void) const
1459{
1460 return player != NULL;
1461}
1462
1464{
1465 return cTransferControl::ReceiverDevice() != NULL;
1466}
1467
1469{
1470 if (CanReplay()) {
1471 if (player)
1472 Detach(player);
1473 cLiveSubtitle *ls;
1474 {
1476 ls = liveSubtitle; // deleted outside the mutex, see SetCurrentSubtitleTrack()
1477 liveSubtitle = NULL;
1479 }
1480 delete ls;
1482 player = Player;
1483 if (!Transferring())
1484 ClrAvailableTracks(false, true);
1485 SetPlayMode(Player->playMode);
1486 Player->device = this;
1487 Player->Activate(true);
1488 return true;
1489 }
1490 return false;
1491}
1492
1494{
1495 if (Player && player == Player) {
1496 cPlayer *p = player;
1497 player = NULL; // avoids recursive calls to Detach()
1498 p->Activate(false);
1499 p->device = NULL;
1504 PlayTs(NULL, 0);
1507 isPlayingVideo = false;
1508 }
1509}
1510
1512{
1513 if (player) {
1514 Detach(player);
1515 if (IsPrimaryDevice())
1517 }
1518}
1519
1520bool cDevice::Poll(cPoller &Poller, int TimeoutMs)
1521{
1522 return false;
1523}
1524
1525bool cDevice::Flush(int TimeoutMs)
1526{
1527 return false;
1528}
1529
1531{
1532 // At the end of a stream no further TS packet comes that could complete the
1533 // PES packets the converters still hold, so they are played out here. The
1534 // cDevice implementations are called explicitly, because a device that
1535 // overrides them buffers on its own and plays that data out in DrainDevice():
1536 if (cDevice::PlayTsVideo(NULL, 0) <= 0 || cDevice::PlayTsAudio(NULL, 0) <= 0 || cDevice::PlayTsSubtitle(NULL, 0) <= 0)
1537 return false; // backpressure, the player will call again
1538 return DrainDevice();
1539}
1540
1542{
1543 return Flush(10);
1544}
1545
1546int cDevice::PlayVideo(const uchar *Data, int Length)
1547{
1548 return -1;
1549}
1550
1551int cDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
1552{
1553 return -1;
1554}
1555
1566
1567int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
1568{
1569 bool FirstLoop = true;
1570 uchar c = Data[3];
1571 const uchar *Start = Data;
1572 const uchar *End = Start + Length;
1573 while (Start < End) {
1574 int d = End - Start;
1575 int w = d;
1576 switch (c) {
1577 case 0xBE: // padding stream, needed for MPEG1
1578 case 0xE0 ... 0xEF: // video
1579 isPlayingVideo = true;
1580 w = PlayVideo(Start, d);
1581 break;
1582 case 0xC0 ... 0xDF: // audio
1583 SetAvailableTrack(ttAudio, c - 0xC0, c);
1584 if ((!VideoOnly || HasIBPTrickSpeed()) && c == availableTracks[currentAudioTrack].id) {
1585 w = PlayAudio(Start, d, c);
1586 if (FirstLoop)
1587 Audios.PlayAudio(Data, Length, c);
1588 }
1589 break;
1590 case 0xBD: { // private stream 1
1591 int PayloadOffset = Data[8] + 9;
1592
1593 // Compatibility mode for old subtitles plugin:
1594 if ((Data[7] & 0x01) && (Data[PayloadOffset - 3] & 0x81) == 0x01 && Data[PayloadOffset - 2] == 0x81)
1595 PayloadOffset--;
1596
1597 uchar SubStreamId = Data[PayloadOffset];
1598 uchar SubStreamType = SubStreamId & 0xF0;
1599 uchar SubStreamIndex = SubStreamId & 0x1F;
1600
1601 // Compatibility mode for old VDR recordings, where 0xBD was only AC3:
1602pre_1_3_19_PrivateStreamDetected:
1604 SubStreamId = c;
1605 SubStreamType = 0x80;
1606 SubStreamIndex = 0;
1607 }
1608 else if (pre_1_3_19_PrivateStream)
1609 pre_1_3_19_PrivateStream--; // every known PS1 packet counts down towards 0 to recover from glitches...
1610 switch (SubStreamType) {
1611 case 0x20: // SPU
1612 case 0x30: // SPU
1613 SetAvailableTrack(ttSubtitle, SubStreamIndex, SubStreamId);
1614 if ((!VideoOnly || HasIBPTrickSpeed()) && currentSubtitleTrack != ttNone && SubStreamId == availableTracks[currentSubtitleTrack].id)
1615 w = PlaySubtitle(Start, d);
1616 break;
1617 case 0x80: // AC3 & DTS
1618 SetAvailableTrack(ttDolby, SubStreamIndex, SubStreamId);
1619 if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) {
1620 w = PlayAudio(Start, d, SubStreamId);
1621 if (FirstLoop)
1622 Audios.PlayAudio(Data, Length, SubStreamId);
1623 }
1624 break;
1625 case 0xA0: // LPCM
1626 SetAvailableTrack(ttAudio, SubStreamIndex, SubStreamId);
1627 if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) {
1628 w = PlayAudio(Start, d, SubStreamId);
1629 if (FirstLoop)
1630 Audios.PlayAudio(Data, Length, SubStreamId);
1631 }
1632 break;
1633 default:
1634 // Compatibility mode for old VDR recordings, where 0xBD was only AC3:
1636 dsyslog("unknown PS1 packet, substream id = %02X (counter is at %d)", SubStreamId, pre_1_3_19_PrivateStream);
1637 pre_1_3_19_PrivateStream += 2; // ...and every unknown PS1 packet counts up (the very first one counts twice, but that's ok)
1639 dsyslog("switching to pre 1.3.19 Dolby Digital compatibility mode - substream id = %02X", SubStreamId);
1642 goto pre_1_3_19_PrivateStreamDetected;
1643 }
1644 }
1645 }
1646 }
1647 break;
1648 default:
1649 ;//esyslog("ERROR: unexpected packet id %02X", c);
1650 }
1651 if (w > 0)
1652 Start += w;
1653 else {
1654 if (Start != Data)
1655 esyslog("ERROR: incomplete PES packet write!");
1656 return Start == Data ? w : Start - Data;
1657 }
1658 FirstLoop = false;
1659 }
1660 return Length;
1661}
1662
1663int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly)
1664{
1665 if (!Data) {
1669 return 0;
1670 }
1671 int i = 0;
1672 while (i <= Length - 6) {
1673 if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
1674 int l = PesLength(Data + i);
1675 if (i + l > Length) {
1676 esyslog("ERROR: incomplete PES packet!");
1677 return Length;
1678 }
1679 int w = PlayPesPacket(Data + i, l, VideoOnly);
1680 if (w > 0)
1681 i += l;
1682 else
1683 return i == 0 ? w : i;
1684 }
1685 else
1686 i++;
1687 }
1688 if (i < Length)
1689 esyslog("ERROR: leftover PES data!");
1690 return Length;
1691}
1692
1693int cDevice::PlayTsVideo(const uchar *Data, int Length)
1694{
1695 // Video PES has no explicit length, so we can only determine the end of
1696 // a PES packet when the next TS packet that starts a payload comes in
1697 // (Data == NULL means that no such packet will come any more):
1698 if (!Data || TsPayloadStart(Data)) {
1699 int l;
1700 while (const uchar *p = tsToPesVideo.GetPes(l)) {
1701 int w = PlayVideo(p, l);
1702 if (w <= 0) {
1704 return w;
1705 }
1706 }
1708 }
1709 if (!Data)
1710 return 1; // nothing taken, but the converter is empty now
1711 tsToPesVideo.PutTs(Data, Length);
1712 return Length;
1713}
1714
1715int cDevice::PlayTsAudio(const uchar *Data, int Length)
1716{
1717 // Audio PES always has an explicit length and consists of single packets:
1718 int l;
1719 if (const uchar *p = tsToPesAudio.GetPes(l)) {
1720 int w = PlayAudio(p, l, p[3]);
1721 if (w <= 0) {
1723 return w;
1724 }
1726 }
1727 if (!Data)
1728 return 1; // nothing taken, but the converter is empty now
1729 tsToPesAudio.PutTs(Data, Length);
1730 return Length;
1731}
1732
1733int cDevice::PlayTsSubtitle(const uchar *Data, int Length)
1734{
1735 // The converter is created here in the play/receiver thread but reset and
1736 // deleted from control paths in other threads; mutexCurrentSubtitleTrack
1737 // (which already guarded two of the delete sites) now guards all access:
1739 if (!Data && !dvbSubtitleConverter)
1740 return 1; // no subtitles have been played, so there is nothing to play out
1741 if (!dvbSubtitleConverter) {
1743 if (Replaying() && !Transferring())
1745 }
1746 if (Data)
1747 tsToPesSubtitle.PutTs(Data, Length);
1748 int l;
1749 if (const uchar *p = tsToPesSubtitle.GetPes(l)) {
1752 }
1753 return Data ? Length : 1; // nothing taken if Data is NULL, but the converter is empty now
1754}
1755
1756int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
1757{
1758 int Played = 0;
1759 if (!Data) {
1763 }
1764 else if (Length < TS_SIZE) {
1765 esyslog("ERROR: skipped %d bytes of TS fragment", Length);
1766 return Length;
1767 }
1768 else {
1769 while (Length >= TS_SIZE) {
1770 if (int Skipped = TS_SYNC(Data, Length))
1771 return Played + Skipped;
1772 int Pid = TsPid(Data);
1773 if (TsHasPayload(Data)) { // silently ignore TS packets w/o payload
1774 int PayloadOffset = TsPayloadOffset(Data);
1775 if (PayloadOffset < TS_SIZE) {
1776 if (Pid == PATPID)
1778 else if (patPmtParser.IsPmtPid(Pid))
1780 else if (Pid == patPmtParser.Vpid()) {
1781 isPlayingVideo = true;
1782 int w = PlayTsVideo(Data, TS_SIZE);
1783 if (w < 0)
1784 return Played ? Played : w;
1785 if (w == 0)
1786 break;
1787 }
1788 else if (Pid == availableTracks[currentAudioTrack].id) {
1789 if (!VideoOnly || HasIBPTrickSpeed()) {
1790 int w = PlayTsAudio(Data, TS_SIZE);
1791 if (w < 0)
1792 return Played ? Played : w;
1793 if (w == 0)
1794 break;
1795 Audios.PlayTsAudio(Data, TS_SIZE);
1796 }
1797 }
1798 else if (Pid == availableTracks[currentSubtitleTrack].id) {
1799 if (!VideoOnly || HasIBPTrickSpeed())
1800 PlayTsSubtitle(Data, TS_SIZE);
1801 }
1802 }
1803 }
1804 else if (Pid == patPmtParser.Ppid()) {
1805 int w = PlayTsVideo(Data, TS_SIZE);
1806 if (w < 0)
1807 return Played ? Played : w;
1808 if (w == 0)
1809 break;
1810 }
1811 Played += TS_SIZE;
1812 Length -= TS_SIZE;
1813 Data += TS_SIZE;
1814 }
1815 }
1816 return Played;
1817}
1818
1819int cDevice::Priority(bool IgnoreOccupied) const
1820{
1821 int priority = IDLEPRIORITY;
1822 if (IsPrimaryDevice() && !Replaying() && HasProgramme())
1823 priority = TRANSFERPRIORITY; // we use the same value here, no matter whether it's actual Transfer Mode or real live viewing
1824 if (!IgnoreOccupied && time(NULL) <= occupiedTimeout && occupiedPriority > priority)
1825 priority = occupiedPriority - 1; // so timers with occupiedPriority can start
1826 cMutexLock MutexLock(&mutexReceiver);
1827 for (int i = 0; i < MAXRECEIVERS; i++) {
1828 if (receiver[i])
1829 priority = max(receiver[i]->priority, priority);
1830 }
1831 return priority;
1832}
1833
1835{
1836 return true;
1837}
1838
1839bool cDevice::Receiving(bool Dummy) const
1840{
1841 cMutexLock MutexLock(&mutexReceiver);
1842 for (int i = 0; i < MAXRECEIVERS; i++) {
1843 if (receiver[i])
1844 return true;
1845 }
1846 return false;
1847}
1848
1849#define TS_SCRAMBLING_TIMEOUT 3 // seconds to wait until a TS becomes unscrambled
1850#define TS_SCRAMBLING_TIME_OK 3 // seconds before a Channel/CAM combination is marked as known to decrypt
1851#define EIT_INJECTION_TIME 10 // seconds for which to inject EIT event
1852
1854{
1855 if (Running() && OpenDvr()) {
1856 while (Running()) {
1857 // Read data from the DVR device:
1858 uchar *b = NULL;
1859 if (GetTSPacket(b)) {
1860 if (b) {
1861 // Distribute the packet to all attached receivers:
1862 Lock();
1863 cCamSlot *cs = CamSlot();
1864 if (cs)
1865 cs->TsPostProcess(b);
1866 int Pid = TsPid(b);
1867 bool IsScrambled = TsIsScrambled(b);
1868 cMutexLock MutexLock(&mutexReceiver);
1869 for (int i = 0; i < MAXRECEIVERS; i++) {
1870 cReceiver *Receiver = receiver[i];
1871 if (Receiver && Receiver->WantsPid(Pid)) {
1872 Receiver->Receive(b, TS_SIZE);
1873 // Check whether the TS packet is scrambled:
1874 if (Receiver->startScrambleDetection) {
1875 if (cs) {
1876 int CamSlotNumber = cs->MasterSlotNumber();
1877 if (Receiver->lastScrambledPacket < Receiver->startScrambleDetection)
1878 Receiver->lastScrambledPacket = Receiver->startScrambleDetection;
1879 time_t Now = time(NULL);
1880 if (IsScrambled) {
1881 Receiver->lastScrambledPacket = Now;
1882 if (Now - Receiver->startScrambleDetection > Receiver->scramblingTimeout) {
1883 if (!cs->IsActivating() || Receiver->Priority() >= LIVEPRIORITY) {
1884 if (Receiver->ChannelID().Valid()) {
1885 dsyslog("CAM %d: won't decrypt channel %s, detaching receiver", CamSlotNumber, *Receiver->ChannelID().ToString());
1886 ChannelCamRelations.SetChecked(Receiver->ChannelID(), CamSlotNumber);
1887 }
1888 Detach(Receiver);
1889 }
1890 }
1891 }
1892 else if (Now - Receiver->lastScrambledPacket > TS_SCRAMBLING_TIME_OK) {
1893 if (Receiver->ChannelID().Valid()) {
1894 dsyslog("CAM %d: decrypts channel %s", CamSlotNumber, *Receiver->ChannelID().ToString());
1895 ChannelCamRelations.SetDecrypt(Receiver->ChannelID(), CamSlotNumber);
1896 }
1897 Receiver->startScrambleDetection = 0;
1898 }
1899 }
1900 }
1901 // Inject EIT event to avoid the CAMs parental rating prompt:
1902 if (Receiver->startEitInjection) {
1903 time_t Now = time(NULL);
1904 if (cCamSlot *cs = CamSlot()) {
1905 if (Now != Receiver->lastEitInjection) { // once per second
1906 cs->InjectEit(Receiver->ChannelID().Sid());
1907 Receiver->lastEitInjection = Now;
1908 }
1909 }
1910 if (Now - Receiver->startEitInjection > EIT_INJECTION_TIME)
1911 Receiver->startEitInjection = 0;
1912 }
1913 }
1914 }
1915 Unlock();
1916 }
1917 }
1918 else
1919 break;
1920 }
1921 CloseDvr();
1922 }
1923}
1924
1926{
1927 return false;
1928}
1929
1931{
1932}
1933
1935{
1936 return false;
1937}
1938
1940{
1941 if (!Receiver)
1942 return false;
1943 if (Receiver->device == this)
1944 return true;
1945// activate the following line if you need it - actually the driver should be fixed!
1946//#define WAIT_FOR_TUNER_LOCK
1947#ifdef WAIT_FOR_TUNER_LOCK
1948#define TUNER_LOCK_TIMEOUT 5000 // ms
1949 if (!HasLock(TUNER_LOCK_TIMEOUT)) {
1950 esyslog("ERROR: device %d has no lock, can't attach receiver!", DeviceNumber() + 1);
1951 return false;
1952 }
1953#endif
1954 cMutexLock MutexLock(&mutexReceiver);
1955 for (int i = 0; i < MAXRECEIVERS; i++) {
1956 if (!receiver[i]) {
1957 for (int n = 0; n < Receiver->numPids; n++) {
1958 if (!AddPid(Receiver->pids[n])) {
1959 for ( ; n-- > 0; )
1960 DelPid(Receiver->pids[n]);
1961 return false;
1962 }
1963 }
1964 Receiver->Activate(true);
1965 Receiver->device = this;
1966 receiver[i] = Receiver;
1967 cCamSlot *cs = camSlot;
1968 if (cs && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
1969 cs->StartDecrypting();
1970 if (cs->WantsTsData()) {
1971 Receiver->lastEitInjection = 0;
1972 Receiver->startEitInjection = time(NULL);
1973 }
1974 if (CamSlots.NumReadyMasterSlots() > 1) { // don't try different CAMs if there is only one
1975 Receiver->startScrambleDetection = time(NULL);
1977 bool KnownToDecrypt = ChannelCamRelations.CamDecrypt(Receiver->ChannelID(), cs->MasterSlotNumber());
1978 if (KnownToDecrypt)
1979 Receiver->scramblingTimeout *= 9; // give it time to receive ECM/EMM (must be less than MAXBROKENTIMEOUT in recorder.c!)
1980 if (Receiver->ChannelID().Valid())
1981 dsyslog("CAM %d: %sknown to decrypt channel %s (scramblingTimeout = %ds)", cs->MasterSlotNumber(), KnownToDecrypt ? "" : "not ", *Receiver->ChannelID().ToString(), Receiver->scramblingTimeout);
1982 }
1983 }
1984 if (patFilter && Receiver->ChannelID().Valid())
1985 patFilter->Request(Receiver->ChannelID().Sid());
1986 Start();
1987 return true;
1988 }
1989 }
1990 esyslog("ERROR: no free receiver slot!");
1991 return false;
1992}
1993
1994void cDevice::Detach(cReceiver *Receiver, bool ReleaseCam)
1995{
1996 if (!Receiver || Receiver->device != this)
1997 return;
1998 bool receiversLeft = false;
2000 for (int i = 0; i < MAXRECEIVERS; i++) {
2001 if (receiver[i] == Receiver)
2002 receiver[i] = NULL;
2003 else if (receiver[i])
2004 receiversLeft = true;
2005 }
2006 if (patFilter && Receiver->ChannelID().Valid())
2007 patFilter->Release(Receiver->ChannelID().Sid());
2009 Receiver->device = NULL;
2010 Receiver->Activate(false);
2011 for (int n = 0; n < Receiver->numPids; n++)
2012 DelPid(Receiver->pids[n]);
2013 if (cCamSlot *cs = camSlot) {
2014 if (Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
2015 cs->StartDecrypting();
2016 if (ReleaseCam)
2018 }
2019 }
2020 if (!receiversLeft)
2021 Cancel(-1);
2022}
2023
2025{
2026 if (Pid) {
2027 {
2028 cMutexLock MutexLock(&mutexReceiver);
2029 for (int i = 0; i < MAXRECEIVERS; i++) {
2030 cReceiver *Receiver = receiver[i];
2031 if (Receiver && Receiver->WantsPid(Pid))
2032 Detach(Receiver, false);
2033 }
2034 }
2035 // Outside of mutexReceiver - see DetachAllReceivers():
2037 }
2038}
2039
2041{
2042 {
2043 cMutexLock MutexLock(&mutexReceiver);
2044 for (int i = 0; i < MAXRECEIVERS; i++)
2045 Detach(receiver[i], false);
2046 }
2047 // Outside of mutexReceiver: ReleaseCamSlot() -> cCamSlot::Assign() takes the
2048 // CAM assign mutex, under which Assign() calls AttachReceiver() and
2049 // SetCamSlot() (mutexReceiver, thread lock) - holding mutexReceiver here
2050 // inverts that order:
2052}
2053
2054// --- cTSBuffer -------------------------------------------------------------
2055
2056cTSBuffer::cTSBuffer(int File, int Size, int DeviceNumber)
2057{
2058 SetDescription("device %d TS buffer", DeviceNumber);
2059 f = File;
2060 deviceNumber = DeviceNumber;
2061 delivered = 0;
2062 ringBuffer = new cRingBufferLinear(Size, TS_SIZE, true, "TS");
2063 ringBuffer->SetTimeouts(100, 10);
2065 Start();
2066}
2067
2069{
2070 Cancel(3);
2071 delete ringBuffer;
2072}
2073
2075{
2076 if (ringBuffer) {
2077 bool firstRead = true;
2078 cPoller Poller(f);
2079 while (Running()) {
2080 if (firstRead || Poller.Poll(100)) {
2081 firstRead = false;
2082 int r = ringBuffer->Read(f);
2083 if (r < 0 && FATALERRNO) {
2084 if (errno == EOVERFLOW)
2085 esyslog("ERROR: driver buffer overflow on device %d", deviceNumber);
2086 else {
2087 LOG_ERROR;
2088 break;
2089 }
2090 }
2091 cCondWait::SleepMs(10); // avoids small chunks of data, which cause high CPU usage, esp. on ARM CPUs
2092 }
2093 }
2094 }
2095}
2096
2097uchar *cTSBuffer::Get(int *Available, bool CheckAvailable)
2098{
2099 int Count = 0;
2100 if (delivered) {
2102 delivered = 0;
2103 }
2104 if (CheckAvailable && ringBuffer->Available() < TS_SIZE)
2105 return NULL;
2106 uchar *p = ringBuffer->Get(Count);
2107 if (p && Count >= TS_SIZE) {
2108 if (*p != TS_SYNC_BYTE) {
2109 for (int i = 1; i < Count; i++) {
2110 if (p[i] == TS_SYNC_BYTE) {
2111 Count = i;
2112 break;
2113 }
2114 }
2115 ringBuffer->Del(Count);
2116 esyslog("ERROR: skipped %d bytes to sync on TS packet on device %d", Count, deviceNumber);
2117 return NULL;
2118 }
2120 if (Available)
2121 *Available = Count;
2122 return p;
2123 }
2124 return NULL;
2125}
2126
2127void cTSBuffer::Skip(int Count)
2128{
2129 delivered = Count;
2130}
cAudios Audios
Definition audio.c:27
#define CA_ENCRYPTED_MIN
Definition channels.h:44
#define MAXDPIDS
Definition channels.h:32
#define MAXAPIDS
Definition channels.h:31
#define MAXSPIDS
Definition channels.h:33
#define CA_DVB_MAX
Definition channels.h:41
#define LOCK_CHANNELS_READ
Definition channels.h:278
cChannelCamRelations ChannelCamRelations
Definition ci.c:2947
cCamSlots CamSlots
Definition ci.c:2838
@ msReady
Definition ci.h:170
void PlayAudio(const uchar *Data, int Length, uchar Id)
Definition audio.c:29
void PlayTsAudio(const uchar *Data, int Length)
Definition audio.c:35
void ClearAudio(void)
Definition audio.c:47
void MuteAudio(bool On)
Definition audio.c:41
Definition ci.h:232
bool MtdActive(void)
Returns true if MTD is currently active.
Definition ci.h:288
virtual bool IsDecrypting(void)
Returns true if the CAM in this slot is currently used for decrypting.
Definition ci.c:2795
virtual void InjectEit(int Sid)
Injects a generated EIT with a "present event" for the given Sid into the TS data stream sent to the ...
Definition ci.c:2830
int Priority(void)
Returns the priority of the device this slot is currently assigned to, or IDLEPRIORITY if it is not a...
Definition ci.c:2656
cCamSlot * MasterSlot(void)
Returns this CAM slot's master slot, or a pointer to itself if it is a master slot.
Definition ci.h:309
int MasterSlotNumber(void)
Returns the number of this CAM's master slot within the whole system.
Definition ci.h:347
virtual eModuleStatus ModuleStatus(void)
Returns the status of the CAM in this slot.
Definition ci.c:2431
bool WantsTsData(void) const
Returns true if this CAM slot wants to receive the TS data through its Decrypt() function.
Definition ci.h:338
virtual bool Assign(cDevice *Device, bool Query=false)
Assigns this CAM slot to the given Device, if this is possible.
Definition ci.c:2221
cDevice * Device(void)
Returns the device this CAM slot is currently assigned to.
Definition ci.h:332
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
virtual bool IsActivating(void)
Returns true if this CAM slot is currently activating a smart card.
Definition ci.c:2424
virtual bool TsPostProcess(uchar *Data)
If there is a cCiSession that needs to do additional processing on TS packets (after the CAM has done...
Definition ci.c:2820
cCamSlot * MtdSpawn(void)
If this CAM slot can do MTD ("Multi Transponder Decryption"), a call to this function returns a cMtdC...
Definition ci.c:2213
virtual bool ProvidesCa(const int *CaSystemIds)
Returns true if the CAM in this slot provides one of the given CaSystemIds.
Definition ci.c:2664
int NumReadyMasterSlots(void)
Returns the number of master CAM slots in the system that are ready to decrypt.
Definition ci.c:2840
void SetChecked(tChannelID ChannelID, int CamSlotNumber)
Definition ci.c:3011
bool CamDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition ci.c:3004
bool CamChecked(tChannelID ChannelID, int CamSlotNumber)
Definition ci.c:2997
void SetDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition ci.c:3019
const char * Slang(int i) const
Definition channels.h:169
int Number(void) const
Definition channels.h:188
const char * Name(void) const
Definition channels.c:119
int Dpid(int i) const
Definition channels.h:162
int Apid(int i) const
Definition channels.h:161
tChannelID GetChannelID(void) const
Definition channels.h:200
int Ca(int Index=0) const
Definition channels.h:182
const char * Dlang(int i) const
Definition channels.h:168
const int * Caids(void) const
Definition channels.h:181
int Spid(int i) const
Definition channels.h:163
const char * Alang(int i) const
Definition channels.h:167
int Sid(void) const
Definition channels.h:185
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition thread.c:73
static void Shutdown(void)
Definition player.c:108
static void Attach(void)
Definition player.c:95
static void Launch(cControl *Control)
Definition player.c:88
virtual bool DeviceProvidesEIT(const cDevice *Device) const
Returns true if the given Device can provide EIT data.
Definition device.c:62
cDeviceHook(void)
Creates a new device hook object.
Definition device.c:52
virtual bool DeviceProvidesTransponder(const cDevice *Device, const cChannel *Channel) const
Returns true if the given Device can provide the given Channel's transponder.
Definition device.c:57
friend class cReceiver
Definition device.h:123
friend class cDeviceHook
Definition device.h:122
std::atomic< eTrackType > currentAudioTrack
Definition device.h:557
static int NextCardIndex(int n=0)
Calculates the next card index.
Definition device.c:156
int Occupied(int Priority=MINPRIORITY) const
Returns the number of seconds this device is still occupied for with a priority >= Priority.
Definition device.c:1020
virtual cString DeviceName(void) const
Returns a string identifying the name of this device.
Definition device.c:182
static cList< cDeviceHook > deviceHooks
Definition device.h:247
bool Replaying(void) const
Returns true if we are currently replaying.
Definition device.c:1458
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.
Definition device.c:1520
int currentAudioTrackMissingCount
Definition device.h:561
void StopSectionHandler(void)
A device that has called StartSectionHandler() must call this function (typically in its destructor) ...
Definition device.c:703
int Priority(bool IgnoreOccupied=false) const
Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY),...
Definition device.c:1819
virtual bool SignalStats(int &Valid, double *Strength=NULL, double *Cnr=NULL, double *BerPre=NULL, double *BerPost=NULL, double *Per=NULL, int *Status=NULL) const
Returns statistics about the currently received signal (if available).
Definition device.c:807
virtual void SetSubtitleTrackDevice(eTrackType Type)
Sets the current subtitle track to the given value.
Definition device.c:1080
virtual int GetAudioChannelDevice(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition device.c:1059
virtual int PlayVideo(const uchar *Data, int Length)
Plays the given data block as video.
Definition device.c:1546
cSectionHandler * sectionHandler
Definition device.h:442
std::atomic< bool > mute
Definition device.h:629
bool SetCurrentSubtitleTrack(eTrackType Type, bool Manual=false)
Sets the current subtitle track to the given Type.
Definition device.c:1242
virtual bool HasInternalCam(void)
Returns true if this device handles encrypted channels itself without VDR assistance.
Definition device.h:486
virtual uchar * GrabImage(int &Size, bool Jpeg=true, int Quality=-1, int SizeX=-1, int SizeY=-1)
Grabs the currently visible screen image.
Definition device.c:483
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:542
bool GrabImageFile(const char *FileName, bool Jpeg=true, int Quality=-1, int SizeX=-1, int SizeY=-1)
Calls GrabImage() and stores the resulting image in a file with the given name.
Definition device.c:488
eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (general setup).
Definition device.c:901
virtual bool HasLock(int TimeoutMs=0) const
Returns true if the device has a lock on the requested transponder.
Definition device.c:1048
void StartSectionHandler(void)
A derived device that provides section data must call this function (typically in its constructor) to...
Definition device.c:692
@ ptTeletext
Definition device.h:411
@ ptPcr
Definition device.h:411
@ ptOther
Definition device.h:411
@ ptDolby
Definition device.h:411
@ ptAudio
Definition device.h:411
@ ptVideo
Definition device.h:411
cMutex mutexCurrentAudioTrack
Definition device.h:559
virtual const cPositioner * Positioner(void) const
Returns a pointer to the positioner (if any) this device has used to move the satellite dish to the r...
Definition device.c:802
bool GetTrackId(eTrackType Type, tTrackId &TrackId)
Copies the given track id into TrackId and returns true, or returns false if Type is not a valid trac...
Definition device.c:1187
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
Definition device.c:797
int NumSubtitleTracks(void) const
Returns the number of subtitle tracks that are currently available.
Definition device.c:1213
bool keepTracks
Definition device.h:563
virtual int PlayPes(const uchar *Data, int Length, bool VideoOnly=false)
Plays all valid PES packets in Data with the given Length.
Definition device.c:1663
cMutex mutexReceiver
Definition device.h:885
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition device.c:746
void ReleaseCamSlot(void)
Releases the CAM slot if it is currently not used.
Definition device.c:455
static int useDevice
Definition device.h:126
virtual void Action(void) override
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition device.c:1853
cDvbSubtitleConverter * dvbSubtitleConverter
Definition device.h:256
bool HasPid(int Pid) const
Returns true if this device is currently receiving the given PID.
Definition device.c:559
virtual void SetAudioTrackDevice(eTrackType Type)
Sets the current audio track to the given value.
Definition device.c:1076
std::atomic< bool > autoSelectPreferredSubtitleLanguage
Definition device.h:562
virtual bool SetPid(cPidHandle *Handle, int Type, bool On)
Does the actual PID setting on this device.
Definition device.c:678
static int nextCardIndex
Definition device.h:189
cTsToPes tsToPesAudio
Definition device.h:664
cNitFilter * nitFilter
Definition device.h:446
static bool WaitForAllDevicesReady(int Timeout=0)
Waits until all devices have become ready, or the given Timeout (seconds) has expired.
Definition device.c:134
void SetCamSlot(cCamSlot *CamSlot)
Sets the given CamSlot to be used with this device.
Definition device.c:468
static cDevice * ActualDevice(void)
Returns the actual receiving device in case of Transfer Mode, or the primary device otherwise.
Definition device.c:229
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition device.h:149
static void SetUseDevice(int n)
Sets the 'useDevice' flag of the given device.
Definition device.c:150
virtual bool MaySwitchTransponder(const cChannel *Channel) const
Returns true if it is ok to switch to the Channel's transponder on this device, without disturbing an...
Definition device.c:832
eTrackType GetCurrentSubtitleTrack(void) const
Definition device.h:604
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition device.c:237
static void Shutdown(void)
Closes down all devices.
Definition device.c:474
cPatFilter * patFilter
Definition device.h:444
eTrackType GetCurrentAudioTrack(void) const
Definition device.h:600
cDevice(void)
Definition device.c:80
bool DeviceHooksProvidesEIT(void) const
Definition device.c:762
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition device.c:847
virtual int PlayTsVideo(const uchar *Data, int Length)
Plays the given data block as video.
Definition device.c:1693
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition device.c:168
virtual void SetPowerSaveMode(bool On)
Puts the device into power save mode, if applicable.
Definition device.c:837
virtual bool DrainDevice(void)
Tells the device to play out all data it still holds in its buffers and decoders (data may be held ba...
Definition device.c:1541
cEitFilter * eitFilter
Definition device.h:443
virtual bool ProvidesEIT(void) const
Returns true if this device provides EIT data and thus wants to be tuned to the channels it can recei...
Definition device.c:792
virtual void SetAudioChannelDevice(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
Definition device.c:1064
cReceiver * receiver[MAXRECEIVERS]
Definition device.h:886
void DelPid(int Pid, ePidType PidType=ptOther)
Deletes a PID from the set of PIDs this device shall receive.
Definition device.c:643
bool AttachReceiver(cReceiver *Receiver)
Attaches the given receiver to this device.
Definition device.c:1939
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition device.h:372
bool IsPrimaryDevice(bool CheckDecoder=true) const
Definition device.h:224
virtual bool AvoidRecording(void) const
Returns true if this device should only be used for recording if no other device is available.
Definition device.h:240
static cDevice * primaryDevice
Definition device.h:128
static bool SetPrimaryDevice(int n)
Sets the primary device to 'n'.
Definition device.c:201
bool Receiving(bool Dummy=false) const
Returns true if we are currently receiving. The parameter has no meaning (for backwards compatibility...
Definition device.c:1839
bool Transferring(void) const
Returns true if we are currently in Transfer Mode.
Definition device.c:1463
virtual int PlayTsAudio(const uchar *Data, int Length)
Plays the given data block as audio.
Definition device.c:1715
time_t occupiedTimeout
Definition device.h:267
void StopReplay(void)
Stops the current replay session (if any).
Definition device.c:1511
virtual void MakePrimaryDevice(bool On)
Informs a device that it will be the primary device.
Definition device.c:187
virtual bool ProvidesTransponderExclusively(const cChannel *Channel) const
Returns true if this is the only device that is able to provide the given channel's transponder.
Definition device.c:778
void DetachAll(int Pid)
Detaches all receivers from this device for this pid.
Definition device.c:2024
virtual bool ProvidesChannel(const cChannel *Channel, int Priority=IDLEPRIORITY, bool *NeedsDetachReceivers=NULL) const
Returns true if this device can provide the given channel.
Definition device.c:787
int cardIndex
Definition device.h:190
virtual int SignalQuality(void) const
Returns the "quality" of the currently received signal.
Definition device.c:817
virtual int SignalStrength(void) const
Returns the "strength" of the currently received signal.
Definition device.c:812
virtual void Play(void)
Sets the device into play mode (after a previous trick mode).
Definition device.c:1378
int GetAudioChannel(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition device.c:1101
cPidHandle pidHandles[MAXPIDHANDLES]
Definition device.h:420
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition device.c:1296
void Detach(cFilter *Filter)
Detaches the given filter from this device.
Definition device.c:740
cTsToPes tsToPesVideo
Definition device.h:663
virtual bool SetPlayMode(ePlayMode PlayMode)
Sets the device into the given play mode.
Definition device.c:1356
virtual bool OpenDvr(void)
Opens the DVR of this device and prepares it to deliver a Transport Stream for use in a cReceiver.
Definition device.c:1925
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:1182
void SetVolume(int Volume, bool Absolute=false)
Sets the volume to the given value, either absolutely or relative to the current volume.
Definition device.c:1113
virtual void TrickSpeed(int Speed, bool Forward)
Sets the device into a mode where replay is done slower.
Definition device.c:1366
cLiveSubtitle * liveSubtitle
Definition device.h:255
virtual void Mute(void)
Turns off audio while replaying.
Definition device.c:1394
virtual bool HasCi(void)
Returns true if this device has a Common Interface.
Definition device.c:463
virtual cString DeviceType(void) const
Returns a string identifying the type of this device (like "DVB-S").
Definition device.c:177
virtual const cChannel * GetCurrentlyTunedTransponder(void) const
Returns a pointer to the currently tuned transponder.
Definition device.c:822
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
Definition device.c:1386
void SetAudioChannel(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
Definition device.c:1107
static int NumDevices(void)
Returns the total number of devices.
Definition device.h:130
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles.
Definition device.c:1361
time_t occupiedFrom
Definition device.h:266
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:515
bool isPlayingVideo
Definition device.h:666
virtual bool Flush(int TimeoutMs=0)
Definition device.c:1525
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
Definition device.c:219
virtual int PlayTsSubtitle(const uchar *Data, int Length)
Plays the given data block as a subtitle.
Definition device.c:1733
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).
Definition device.c:538
virtual void CloseDvr(void)
Shuts down the DVR.
Definition device.c:1930
virtual void CloseFilter(int Handle)
Closes a file handle that has previously been opened by OpenFilter().
Definition device.c:729
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
Definition device.c:1043
bool AttachPlayer(cPlayer *Player)
Attaches the given player to this device.
Definition device.c:1468
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition device.c:1128
virtual bool HasProgramme(void) const
Returns true if the device is currently showing any programme to the user, either through replaying o...
Definition device.c:1053
friend class cLiveSubtitle
Definition device.h:121
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition device.c:1329
virtual void DetachAllReceivers(void)
Detaches all receivers from this device.
Definition device.c:2040
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
Definition device.c:827
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
Definition device.c:1351
int NumTracks(eTrackType FirstTrack, eTrackType LastTrack) const
Returns the number of tracks in the given range that are currently available.
Definition device.c:1197
void AttachFilter(cFilter *Filter)
Attaches the given filter to this device.
Definition device.c:734
std::atomic< cPlayer * > player
Definition device.h:661
virtual cSpuDecoder * GetSpuDecoder(void)
Returns a pointer to the device's SPU decoder (or NULL, if this device doesn't have an SPU decoder).
Definition device.c:224
virtual bool HasIBPTrickSpeed(void)
Returns true if this device can handle all frames in 'fast forward' trick speeds.
Definition device.h:795
virtual bool Ready(void)
Returns true if this device is ready.
Definition device.c:1834
cMutex mutexChannel
Definition device.h:265
static cDevice * GetDeviceForTransponder(const cChannel *Channel, int Priority)
Returns a device that is not currently "occupied" and can be tuned to the transponder of the given Ch...
Definition device.c:434
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:549
tTrackId availableTracks[ttMaxTrackTypes]
Definition device.h:555
virtual bool GetTSPacket(uchar *&Data)
Gets exactly one TS packet from the DVR of this device and returns a pointer to it in Data.
Definition device.c:1934
virtual void Clear(void)
Clears all video and audio data from the device.
Definition device.c:1370
cTsToPes tsToPesSubtitle
Definition device.h:665
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition device.h:225
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:494
bool SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language=NULL, const char *Description=NULL)
Sets the track of the given Type and Index to the given values.
Definition device.c:1152
void SetOccupied(int Seconds, int Priority=MINPRIORITY, time_t From=0)
Sets the occupied timeout for this device to the given number of Seconds, This can be used to tune a ...
Definition device.c:1028
std::atomic< eTrackType > currentSubtitleTrack
Definition device.h:558
static int numDevices
Definition device.h:125
bool Drain(void)
Tells the device that the last data of the current stream has been delivered and no more will follow,...
Definition device.c:1530
int NumAudioTracks(void) const
Returns the number of audio tracks that are currently available.
Definition device.c:1208
virtual int PlayPesPacket(const uchar *Data, int Length, bool VideoOnly=false)
Plays the single PES packet in Data with the given Length.
Definition device.c:1567
bool ToggleMute(void)
Turns the volume off or on and returns the new mute state.
Definition device.c:1084
void SetPowerSaveIfUnused(void)
Sets this device into a power save mode if it is not currently used and has implemented SetPowerSaveM...
Definition device.c:841
void DelLivePids(void)
Deletes the live viewing PIDs.
Definition device.c:683
virtual int PlayTs(const uchar *Data, int Length, bool VideoOnly=false)
Plays the given TS packet.
Definition device.c:1756
cPatPmtParser patPmtParser
Definition device.h:662
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:569
virtual ~cDevice() override
Definition device.c:123
cMutex mutexCurrentSubtitleTrack
Definition device.h:560
std::atomic< int > volume
Definition device.h:630
int pre_1_3_19_PrivateStream
Definition device.h:564
bool DeviceHooksProvidesTransponder(const cChannel *Channel) const
Definition device.c:751
virtual int ReadFilter(int Handle, void *Buffer, size_t Length)
Reads data from a handle for the given filter.
Definition device.c:724
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask)
Opens a file handle for the given filter data.
Definition device.c:719
cSdtFilter * sdtFilter
Definition device.h:445
static cDevice * device[MAXDEVICES]
Definition device.h:76
int occupiedPriority
Definition device.h:268
std::atomic< cCamSlot * > camSlot
Definition device.h:480
void ForceTransferMode(void)
Forces the device into transfermode for the current channel.
Definition device.c:1009
virtual int PlayAudio(const uchar *Data, int Length, uchar Id)
Plays the given data block as audio.
Definition device.c:1551
cMutex mutexPids
Definition device.h:408
bool SetCurrentAudioTrack(eTrackType Type)
Sets the current audio track to the given Type.
Definition device.c:1218
void SetTempSubtitles(void)
Temporarily turn on subtitles after a fast rewind during reply.
Definition device.c:1289
virtual bool ProvidesTransponder(const cChannel *Channel) const
Returns true if this device can provide the transponder of the given Channel (which implies that it c...
Definition device.c:773
virtual void SetDigitalAudioDevice(bool On)
Tells the output device that the current audio track is Dolby Digital.
Definition device.c:1072
static std::atomic< int > currentChannel
Definition device.h:270
virtual void StillPicture(const uchar *Data, int Length)
Displays the given I-frame as a still picture.
Definition device.c:1399
virtual int PlaySubtitle(const uchar *Data, int Length)
Plays the given data block as a subtitle.
Definition device.c:1556
virtual void SetVolumeDevice(int Volume)
Sets the audio volume on this device (Volume = 0...255).
Definition device.c:1068
int Convert(const uchar *Data, int Length)
void Freeze(bool Status)
Definition dvbsubtitle.h:60
void SetVisible(bool Visible)
int ConvertFragments(const uchar *Data, int Length)
virtual void Clear(void)
Definition tools.c:2305
int Count(void) const
Definition tools.h:646
void Add(cListObject *Object, cListObject *After=NULL)
Definition tools.c:2228
int Index(void) const
Definition tools.c:2148
Definition tools.h:650
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition tools.h:662
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition tools.h:669
const T * Get(int Index) const
Returns the list element at the given Index, or NULL if no such element exists.
Definition tools.h:659
virtual ~cLiveSubtitle() override
Definition device.c:39
cLiveSubtitle(int SPid)
Definition device.c:34
virtual void Receive(const uchar *Data, int Length) override
This function is called from the cDevice we are attached to, and delivers one TS packet from the set ...
Definition device.c:44
bool Lock(int TimeoutMs=0, bool *TimedOut=NULL)
Returns true if the mutex was successfully locked.
Definition thread.c:228
void Unlock(void)
Definition thread.c:252
cNitFilter(cSdtFilter *SdtFilter)
Definition nit.c:29
void Request(int Sid)
Definition pat.c:408
void Release(int Sid)
Definition pat.c:431
void Reset(void)
Resets the parser.
Definition remux.c:638
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
Definition remux.c:648
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
Definition remux.c:680
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
Definition remux.h:404
int Ppid(void) const
Returns the PCR pid as defined by the current PMT, or 0 if no PCR pid has been detected,...
Definition remux.h:410
int Vpid(void) const
Returns the video pid as defined by the current PMT, or 0 if no video pid has been detected,...
Definition remux.h:407
std::atomic< cDevice * > device
Definition player.h:19
virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId)
Definition player.h:75
ePlayMode playMode
Definition player.h:20
virtual void Activate(bool On)
Definition player.h:42
bool Poll(int TimeoutMs=0)
Definition tools.c:1632
A steerable satellite dish generally points to the south on the northern hemisphere,...
Definition positioner.h:31
time_t lastEitInjection
Definition receiver.h:30
int Priority(void)
Definition receiver.h:58
bool WantsPid(int Pid)
Definition receiver.c:114
std::atomic< int > pids[MAXRECEIVEPIDS]
Definition receiver.h:24
time_t startEitInjection
Definition receiver.h:29
tChannelID ChannelID(void)
Definition receiver.h:81
std::atomic< cDevice * > device
Definition receiver.h:20
void Detach(void)
Definition receiver.c:125
int priority
Definition receiver.h:22
virtual void Receive(const uchar *Data, int Length)=0
This function is called from the cDevice we are attached to, and delivers one TS packet from the set ...
bool AddPid(int Pid)
Adds the given Pid to the list of PIDs of this receiver.
Definition receiver.c:42
std::atomic< int > numPids
Definition receiver.h:25
time_t startScrambleDetection
Definition receiver.h:27
time_t lastScrambledPacket
Definition receiver.h:26
int scramblingTimeout
Definition receiver.h:28
cReceiver(const cChannel *Channel=NULL, int Priority=MINPRIORITY)
Creates a new receiver for the given Channel with the given Priority.
Definition receiver.c:14
virtual void Activate(bool On)
This function is called just before the cReceiver gets attached to (On == true) and right after it ge...
Definition receiver.h:35
cRingBufferLinear(int Size, int Margin=0, bool Statistics=false, const char *Description=NULL)
Creates a linear ring buffer.
Definition ringbuffer.c:170
void Del(int Count)
Deletes at most Count bytes from the ring buffer.
Definition ringbuffer.c:371
uchar * Get(int &Count)
Gets data from the ring buffer.
Definition ringbuffer.c:346
int Read(int FileHandle, int Max=0)
Reads at most Max bytes from FileHandle and stores them in the ring buffer.
Definition ringbuffer.c:230
virtual int Available(void) override
Definition ringbuffer.c:211
void SetTimeouts(int PutTimeout, int GetTimeout)
Definition ringbuffer.c:89
void SetIoThrottle(void)
Definition ringbuffer.c:95
cSdtFilter(cPatFilter *PatFilter)
Definition sdt.c:23
void SetChannel(const cChannel *Channel)
Definition sections.c:140
cSectionHandler(cDevice *Device)
Definition sections.c:42
void SetStatus(bool On)
Definition sections.c:147
void Attach(cFilter *Filter)
Definition sections.c:119
void Detach(cFilter *Filter)
Definition sections.c:130
int VolumeSteps
Definition config.h:377
int VideoDisplayFormat
Definition config.h:331
int CurrentVolume
Definition config.h:376
int SubtitleLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:299
int DisplaySubtitles
Definition config.h:298
int VolumeLinearize
Definition config.h:378
int AudioLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:297
int VideoFormat
Definition config.h:332
int PrimaryDVB
Definition config.h:273
int CurrentDolby
Definition config.h:379
int QueueMessage(eMessageType Type, const char *s, int Seconds=0, int Timeout=0)
Like Message(), but this function may be called from a background thread.
Definition skins.c:334
@ eSpuPanAndScan
Definition spu.h:21
@ eSpuNormal
Definition spu.h:21
@ eSpuLetterBox
Definition spu.h:21
virtual void setScaleMode(cSpuDecoder::eScaleMode ScaleMode)=0
static void MsgSetVolume(int Volume, bool Absolute)
Definition status.c:89
static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber, bool LiveView)
Definition status.c:65
cTSBuffer(int File, int Size, int DeviceNumber)
Definition device.c:2056
int delivered
Definition device.h:933
uchar * Get(int *Available=NULL, bool CheckAvailable=false)
Returns a pointer to the first TS packet in the buffer.
Definition device.c:2097
virtual ~cTSBuffer() override
Definition device.c:2068
cRingBufferLinear * ringBuffer
Definition device.h:934
void Skip(int Count)
If after a call to Get() more or less than TS_SIZE of the available data has been processed,...
Definition device.c:2127
int deviceNumber
Definition device.h:932
int f
Definition device.h:931
virtual void Action(void) override
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition device.c:2074
void Unlock(void)
Definition thread.h:104
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
Definition thread.c:330
void SetDescription(const char *Description,...) __attribute__((format(printf
Definition thread.c:293
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
Definition thread.h:110
void Lock(void)
Definition thread.h:103
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting 'running' to false, so that the Action() loop can finish in an or...
Definition thread.c:381
char * description
Definition thread.h:96
static cDevice * ReceiverDevice(void)
Definition transfer.h:39
cTransferControl(cDevice *ReceiverDevice, const cChannel *Channel)
Definition transfer.c:80
void PutTs(const uchar *Data, int Length)
Puts the payload data of the single TS packet at Data into the converter.
Definition remux.c:1067
void SetRepeatLast(void)
Makes the next call to GetPes() return exactly the same data as the last one (provided there was no c...
Definition remux.c:1144
const uchar * GetPes(int &Length)
Gets a pointer to the complete PES packet, or NULL if the packet is not complete yet.
Definition remux.c:1096
void Reset(void)
Resets the converter.
Definition remux.c:1149
cSetup Setup
Definition config.c:373
#define MINPRIORITY
Definition config.h:42
#define TRANSFERPRIORITY
Definition config.h:44
#define MAXPRIORITY
Definition config.h:41
#define SUBTITLES_ALWAYS
Definition config.h:83
#define IDLEPRIORITY
Definition config.h:45
#define SUBTITLES_REWIND
Definition config.h:84
#define LIVEPRIORITY
Definition config.h:43
#define EIT_INJECTION_TIME
Definition device.c:1851
static int GetClippedNumProvidedSystems(int AvailableBits, cDevice *Device)
Definition device.c:242
#define PRINTPIDS(s)
Definition device.c:557
#define TS_SCRAMBLING_TIMEOUT
Definition device.c:1849
#define MIN_PRE_1_3_19_PRIVATESTREAM
Definition device.c:70
#define TS_SCRAMBLING_TIME_OK
Definition device.c:1850
#define MAXVOLUME
Definition device.h:33
#define MAXPIDHANDLES
Definition device.h:31
eVideoDisplayFormat
Definition device.h:59
@ vdfLetterBox
Definition device.h:60
@ vdfCenterCutOut
Definition device.h:61
@ vdfPanAndScan
Definition device.h:59
ePlayMode
Definition device.h:40
@ pmNone
Definition device.h:40
#define MAXDEVICES
Definition device.h:30
#define MAXOCCUPIEDTIMEOUT
Definition device.h:35
#define IS_AUDIO_TRACK(t)
Definition device.h:77
eTrackType
Definition device.h:64
@ ttSubtitle
Definition device.h:71
@ ttMaxTrackTypes
Definition device.h:74
@ ttDolbyLast
Definition device.h:70
@ ttAudioLast
Definition device.h:67
@ ttDolby
Definition device.h:68
@ ttAudioFirst
Definition device.h:66
@ ttSubtitleLast
Definition device.h:73
@ ttDolbyFirst
Definition device.h:69
@ ttSubtitleFirst
Definition device.h:72
@ ttAudio
Definition device.h:65
@ ttNone
Definition device.h:64
#define MAXRECEIVERS
Definition device.h:32
#define IS_SUBTITLE_TRACK(t)
Definition device.h:79
#define IS_DOLBY_TRACK(t)
Definition device.h:78
eSetChannelResult
Definition device.h:37
@ scrOk
Definition device.h:37
@ scrNotAvailable
Definition device.h:37
@ scrFailed
Definition device.h:37
@ scrNoTransfer
Definition device.h:37
bool I18nIsPreferredLanguage(int *PreferredLanguages, const char *LanguageCode, int &OldPreference, int *Position)
Checks the given LanguageCode (which may be something like "eng" or "eng+deu") against the PreferredL...
Definition i18n.c:331
#define tr(s)
Definition i18n.h:85
int TsPid(const uchar *p)
Definition remux.h:82
bool TsHasPayload(const uchar *p)
Definition remux.h:62
#define PATPID
Definition remux.h:52
bool TsIsScrambled(const uchar *p)
Definition remux.h:93
#define TS_SIZE
Definition remux.h:34
bool TsPayloadStart(const uchar *p)
Definition remux.h:72
#define TS_SYNC(Data, Length)
Definition remux.h:149
int TsPayloadOffset(const uchar *p)
Definition remux.h:108
#define TS_SYNC_BYTE
Definition remux.h:33
int PesLength(const uchar *p)
Definition remux.h:173
cSkins Skins
Definition skins.c:257
@ mtInfo
Definition skins.h:37
@ mtError
Definition skins.h:37
int Sid(void) const
Definition channels.h:64
bool Valid(void) const
Definition channels.h:58
cString ToString(void) const
Definition channels.c:38
char language[MAXLANGCODE2]
Definition device.h:83
uint16_t id
Definition device.h:82
#define LOCK_THREAD
Definition thread.h:181
char * Utf8Strn0Cpy(char *Dest, const char *Src, int n)
Copies at most n character bytes from Src to Dest, making sure that the resulting copy ends with a co...
Definition tools.c:962
ssize_t safe_read(int filedes, void *buffer, size_t size)
Definition tools.c:50
ssize_t safe_write(int filedes, const void *buffer, size_t size)
Definition tools.c:62
char * strn0cpy(char *dest, const char *src, size_t n)
Definition tools.c:128
#define FATALERRNO
Definition tools.h:52
T constrain(T v, T l, T h)
Definition tools.h:70
#define LOG_ERROR_STR(s)
Definition tools.h:40
unsigned char uchar
Definition tools.h:31
#define dsyslog(a...)
Definition tools.h:37
int sgn(T a)
Definition tools.h:68
void DELETENULL(T *&p)
Definition tools.h:49
T min(T a, T b)
Definition tools.h:63
T max(T a, T b)
Definition tools.h:64
#define esyslog(a...)
Definition tools.h:35
#define LOG_ERROR
Definition tools.h:39
#define isyslog(a...)
Definition tools.h:36