vdr-plugin-softhddevice-drm-gles 1.6.7
softhddevice.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
18#include <chrono>
19#include <mutex>
20#include <variant>
21#include <libintl.h>
22
23extern "C" {
24#include <libavcodec/avcodec.h>
25}
26
27#include <vdr/dvbspu.h>
28#include <vdr/skins.h>
29#include <vdr/status.h>
30#include <vdr/thread.h>
31
32#include "audio.h"
33#include "codec_audio.h"
34#include "config.h"
35#include "event.h"
36#include "grab.h"
37#include "hardwaredevice.h"
38#include "jittertracker.h"
39#include "logger.h"
40#include "pes.h"
41#include "pipreceiver.h"
42#include "softhddevice.h"
43#include "softhdosdprovider.h"
44#include "videorender.h"
45#include "videostream.h"
46
55 : m_pSpuDecoder(new cDvbSpuDecoder()),
56 m_pConfig(config),
57 m_pipUseAlt(m_pConfig->ConfigPipUseAlt)
58{
59// LOGDEBUG("device: %s:", __FUNCTION__);
61
62 m_channelSwitchStartTime = std::chrono::steady_clock::now();
64}
65
72{
73 LOGDEBUG("device: %s:", __FUNCTION__);
74
75 delete m_pEventHandler;
76 delete m_pHardwareDevice;
77 delete m_pSpuDecoder;
78}
79
84{
85 LOGDEBUG("device: %s:", __FUNCTION__);
86 m_pHardwareDevice = new cHardwareDevice(); // deleted in destructor
87
88 return true;
89}
90
95{
96 LOGDEBUG("device: %s", __FUNCTION__);
98
99 return true;
100}
101
106{
107 LOGDEBUG("device: %s", __FUNCTION__);
110}
111
122
129{
130 LOGDEBUG("device: %s: %d", __FUNCTION__, on);
131
132 if (on)
133 m_pOsdProvider = new cSoftOsdProvider(this); // no need to delete it, VDR does it
134
135 cDevice::MakePrimaryDevice(on);
136}
137
144void cSoftHdDevice::ChannelSwitch(const cDevice *device, int channelNum, bool liveView)
145{
146 if (device != cDevice::PrimaryDevice())
147 return;
148
149 if (!liveView)
150 return;
151
152 if (channelNum == 0)
153 m_channelSwitchStartTime = std::chrono::steady_clock::now();
154}
155
163{
164 LOGDEBUG("device: %s:", __FUNCTION__);
165 if (!IsPrimaryDevice())
166 return NULL;
167
168 return m_pSpuDecoder;
169}
170
175{
176 bool hasDecoder = !IsDetached();
177
178// LOGDEBUG("device: %s: %d", __FUNCTION__, hasDecoder);
179
180 return hasDecoder;
181}
182
187{
188 bool canReplay = !IsDetached();
189
190 LOGDEBUG("device: %s: %d", __FUNCTION__, canReplay);
191
192 return canReplay;
193}
194
206{
207 uint64_t startStateChange = cTimeMs::Now();
208 LOGDEBUG("device: STATE MACHINE received %s", EventToString(event));
209 bool needsResume = false;
210
211#ifdef USE_GLES
212 // Lock the GL thread before the state machine lock, because cmdCopyBufferToOutputFb() calls
213 // cSoftHdDevice::OsdDrawARGB(), which itself locks the state machine mutex and we can end
214 // up in a deadlock then.
215 // We can safely unlock the thread again after the state change, because cSoftHdDevice::OsdDrawARGB()
216 // always tests if we are in detached mode and this new state is probably set then.
217 bool needsOglResume = false;
220#endif
221
222 { // locked state machine context
223 std::lock_guard<std::mutex> lock(m_mutex);
224
225 if (m_state != DETACHED) {
226 m_pRender->Halt();
228 needsResume = true;
229 }
230
231 auto invalid = [this, &event]() {
232 LOGWARNING("device: Invalid event '%s' in state '%s' received", EventToString(event), StateToString(m_state));
233 };
234
235 switch (m_state) {
236 case State::DETACHED:
237 std::visit(overload{
238 [&invalid](const PlayEvent&) { invalid(); },
239 [&invalid](const PauseEvent&) { invalid(); },
240 [&invalid](const StopEvent&) { invalid(); },
241 [&invalid](const TrickSpeedEvent&) { invalid(); },
242 [&invalid](const StillPictureEvent&) { invalid(); },
243 [](const DetachEvent&) { /* ignore */ },
244 [this](const AttachEvent&) {
245 if (!m_forceDetached)
246 SetState(STOP);
247 },
248 [&invalid](const BufferUnderrunEvent&) { invalid(); },
251 [&invalid](const ResyncEvent&) { invalid(); },
252 [&invalid](const DisplayChangeEvent&) { invalid(); },
253 }, event);
254 needsResume = false;
255 break;
256 case State::STOP:
257 std::visit(overload{
258 [this](const PlayEvent&) {
260 m_pAudio->SetVolume((m_volume * 1000) / 255);
264 },
265 [&invalid](const PauseEvent&) { invalid(); },
266 [&invalid](const StopEvent&) { invalid(); },
267 [&invalid](const TrickSpeedEvent&) { invalid(); },
268 [this](const StillPictureEvent& s) {
269 HandleStillPicture(s.data, s.size);
270 },
271 [this, &needsResume](const DetachEvent&) {
273 needsResume = false;
274 },
275 [&invalid](const AttachEvent&) { invalid(); },
276 [&invalid](const BufferUnderrunEvent&) { invalid(); },
279 [&invalid](const ResyncEvent&) { invalid(); },
280 [this](const DisplayChangeEvent& d) {
282 },
283 }, event);
284 break;
285 case State::BUFFERING:
286 std::visit(overload{
287 [this](const PlayEvent&) {
288 // ignore
289 },
290 [this](const PauseEvent&) {
291 // ignore
292 },
293 [this](const StopEvent&) {
294 SetState(STOP);
295 },
296 [this](const TrickSpeedEvent& t) {
297 // abort buffering and proceed with trick speed immediately, because trick speed shall be as fast and as demanded as possible
298 SetState(PLAY);
299 m_pRender->SetTrickSpeed(t.speed, t.active, t.forward);
301 },
302 [this](const StillPictureEvent& s) {
303 HandleStillPicture(s.data, s.size);
304 },
305 [this, &needsResume](const DetachEvent&) {
307 needsResume = false;
308 },
309 [&invalid](const AttachEvent&) { invalid(); },
310 [&invalid](const BufferUnderrunEvent&) { invalid(); },
311 [this](const BufferingThresholdReachedEvent&) {
314
319 // store the first PTSes beforehand, because dropping samples/frames will change the output of GetFirst*PtsMsToPlay()
322 } else if (receivedAudio) {
323 LOGDEBUG("device: audio only detected");
326 } else if (receivedVideo) {
327 LOGDEBUG("device: video only detected");
330 } else
331 LOGFATAL("device: buffering threshold reached and no a/v available. This is a bug.");
332
333 SetState(PLAY);
334 },
335 [this](const ScheduleResyncAtPtsMsEvent& s) {
336 SetState(PLAY);
338 },
339 [&invalid](const ResyncEvent&) { invalid(); },
340 [this](const DisplayChangeEvent& d) {
342 },
343 }, event);
344 break;
345 case State::PLAY:
346 std::visit(overload{
347 [this](const PlayEvent&) {
348 // resume from pause
350 switch (m_playbackMode) {
351 case AUDIO_ONLY:
353 m_pAudio->SetPaused(false);
354 break;
355 case AUDIO_AND_VIDEO:
358 if (audioBehindVideoByMs > 0) {
360 m_pAudio->SetPaused(false);
361 } else
363
364 // fallthrough
365 case VIDEO_ONLY:
368 break;
369 case NONE:
370 LOGFATAL("device: play event in PLAY state with NONE playback mode. This is a bug.");
371 break;
372 }
373 },
374 [this](const PauseEvent&) {
377 else
379
380 m_pAudio->SetPaused(true);
382 },
383 [this](const StopEvent&) {
384 SetState(STOP);
385 },
386 [this](const TrickSpeedEvent& t) {
387 m_pRender->SetTrickSpeed(t.speed, t.active, t.forward);
389 },
390 [this](const StillPictureEvent& s) {
391 HandleStillPicture(s.data, s.size);
392 },
393 [this, &needsResume](const DetachEvent&) {
395 needsResume = false;
396 },
397 [&invalid](const AttachEvent&) { invalid(); },
398 [this](const BufferUnderrunEvent&) {
400 },
402 // ignore
403 },
404 [this](const ScheduleResyncAtPtsMsEvent& s) {
406 },
407 [this](const ResyncEvent&) {
409 },
410 [this](const DisplayChangeEvent& d) {
412 },
413 }, event);
414 break;
416 std::visit(overload{
417 [this](const PlayEvent&) {
418 SetState(PLAY);
419 },
420 [this](const PauseEvent&) {
422 m_pAudio->SetPaused(true);
424 },
425 [this](const StopEvent&) {
426 SetState(STOP);
427 },
428 [this](const TrickSpeedEvent& t) {
429 // resume from pause, or change trick speed direction/speed
430 m_pRender->SetTrickSpeed(t.speed, t.active, t.forward);
432 },
433 [this](const StillPictureEvent& s) {
434 HandleStillPicture(s.data, s.size);
435 },
436 [this, &needsResume](const DetachEvent&) {
438 needsResume = false;
439 },
440 [&invalid](const AttachEvent&) { invalid(); },
441 [this](const BufferUnderrunEvent&) {
442 // ignore during trick speed. Fast forward/reverse as fast and as demanded as possible
443 },
446 [&invalid](const ResyncEvent&) { invalid(); },
447 [this](const DisplayChangeEvent& d) {
449 },
450 }, event);
451 break;
452 }
453
454 if (needsResume) {
456 m_pRender->Resume();
457 }
458
459 } // end of locked state machine context
460#ifdef USE_GLES
463#endif
464
465 uint64_t stopStateChange = cTimeMs::Now();
466 LOGDEBUG("device: STATE MACHINE state change done in %d ms", (int)(stopStateChange - startStateChange));
467}
468
478 switch (state) {
479 case BUFFERING:
481 // nothing
482 break;
483 case PLAY:
485 m_pAudio->SetPaused(false);
486
487 if (m_playbackMode != AUDIO_ONLY) {
491 }
492 break;
493 case TRICK_SPEED:
494 // The filter thread needs to be restarted for interlaced streams to be rendered without deinterlacer in trick speed mode. It is started lazily.
499 break;
500 case STOP:
501 FlushAudio();
502
505 m_pRender->Reset();
507
516
517 break;
518 case DETACHED:
519 delete m_pPipHandler;
520 m_pPipHandler = nullptr;
521
522 // resume the previously stopped threads
524 m_pRender->Resume();
525
526 // now do the detach
528 delete m_pPipStream;
529
530#ifdef USE_GLES
531 // The opengl thread was probably locked before cmdCopyBufferToOutputFb().
532 // 1) set running to false
533 // 2) continue the thread (which will skip the waiting cmd->Execute())
534 // 3) do the real thread cancel and cleanup
535 // We need to keep this order to prevent a deadlock!
539#endif
540 m_pRender->Exit(); // render must be stopped before videostream!
542 m_pAudio->Exit(); // audio must be stopped after renderer!
543
544 delete m_pAudioDecoder; // includes a Close()
545 delete m_pVideoStream;
546 delete m_pGrab;
547 delete m_pRender;
548 delete m_pAudio;
549
550 break;
551 }
552}
553
563 switch (state) {
564 case PLAY:
567 m_pAudio->SetPaused(true);
569 break;
570 case BUFFERING:
573 break;
574 case TRICK_SPEED:
575 // The filter thread needs to be restarted for interlaced streams to be rendered with deinterlacer again. It is started lazily.
577 m_pRender->SetTrickSpeed(0, false, false);
584 break;
585 case STOP:
586 m_receivedAudio = false;
587 m_receivedVideo = false;
588 m_receivedValidAudio = false;
589 m_receivedValidVideo = false;
590 break;
591 case DETACHED:
592 m_pAudio = new cSoftHdAudio(this);
593 m_pRender = new cVideoRender(this);
597 m_pRender->Init(); // starts display thread
598 m_pVideoStream->StartDecoder(); // starts decoding thread
600 m_pPipStream->StartDecoder(); // starts decoding thread
601 m_pPipHandler = new cPipHandler(this);
602 // Audio is init lazily (includes starting thread)
603
604 break;
605 }
606}
607
614{
615 if (m_state != newState) {
616 LOGDEBUG("device: Preparing to leave state %s", StateToString(m_state));
618 LOGDEBUG("device: Changing state %s -> %s", StateToString(m_state), StateToString(newState));
621 LOGDEBUG("device: State changed to %s", StateToString(m_state));
622 }
623}
624
631{
632 LOGDEBUG("device: %s: %d", __FUNCTION__, play_mode);
633
634 // A new play mode arrived, attach first if we did detach because of an external player
638 }
639
640 switch (play_mode) {
641 case pmNone:
643 break;
644 case pmAudioVideo:
645 case pmAudioOnly:
646 case pmAudioOnlyBlack:
647 case pmVideoOnly:
649 break;
651 // External players like mpv (vdr-plugin-mpv) want to acquire DRM/ALSA
652 // so we release it here and set a flag. As soon as the next SetPlayMode arrives
653 // we then can attach again before changing to the new playmode.
657 break;
658 default:
659 LOGERROR("device: %s: playmode not supported %d", play_mode);
660 return false;
661 break;
662 }
663
664 return true;
665}
666
672{
673 if (IsDetached())
674 return AV_NOPTS_VALUE;
675
676 switch (m_playbackMode) {
677 case NONE:
678 return AV_NOPTS_VALUE;
679 case AUDIO_AND_VIDEO:
680 case VIDEO_ONLY:
681 return m_pRender->GetVideoClock();
682 case AUDIO_ONLY:
684 }
685
686 abort();
687}
688
701void cSoftHdDevice::TrickSpeed(int speed, bool forward)
702{
703 LOGDEBUG("device: %s: %d %s", __FUNCTION__, speed, forward ? "forward" : "backward");
704
705 // This normalizes the VDR frame displaying count into a factor, representing how fast/slow the playback shall be.
706 // For example, a factor of 2.0 means twice as fast as normal, a factor of 0.5 means half as fast as normal (slow-mo).
707 // This is necessary because VDR sends only I-frames during trickspeed, but the distance between I-frames depends on the encoding parameters.
708 // Therefore, we send a normalized factor for the further components, which then calculate the necessary frame displaying count by considering the distance between I-frames.
709
710 double normalizedSpeed = 1;
711 static constexpr double MAX_SPEED = 3;
712
713 // these are arbitrary values, which feel just right
714 static constexpr double FAST_TRICKSPEED_FACTOR = 5; // the higher the factor, the faster the fast forward/reverse
715 static constexpr double SLOW_FORWARD_FACTOR = 2; // the higher the factor, the slower the slow-mo
716
717 // Fastest speed in reverse slow-mo is the original speed. Slower speeds are too slow, because of the already low frame rate.
718 static constexpr double SLOW_REVERSE_FACTOR = 1;
719
720 // speed of the trickspeed (VDR's magic frame displaying count)
721 switch (speed) {
722 case 6:
723 case 8:
724 case 63:
725 normalizedSpeed = 1; // slowest (both, in fast trickspeed and slow-mo)
726 break;
727 case 3:
728 case 4:
729 case 48:
730 normalizedSpeed = 2;
731 break;
732 case 1:
733 case 2:
734 case 24:
735 normalizedSpeed = 3; // fastest (both, in fast trickspeed and slow-mo)
736 break;
737 }
738
739 // figure out if VDR demands slow-mo or fast trickspeed
740 double tmp;
741 switch (speed) {
742 case 8:
743 case 4:
744 case 2:
745 case 63:
746 case 48:
747 case 24:
748 // slow-mo
749 tmp = (MAX_SPEED + 1) - normalizedSpeed;
750
751 if (forward)
753 else
755
756 normalizedSpeed = 1 / tmp;
757 break;
758 default:
759 // fast trickspeed
761 break;
762 }
763
764 OnEventReceived(TrickSpeedEvent{normalizedSpeed, speed != 0, forward});
765}
766
775{
776 LOGDEBUG("device: %s:", __FUNCTION__);
777 cDevice::Clear();
778
779 if (IsDetached())
780 return;
781
782 m_pRender->Halt();
784
787
791
794
795 m_pRender->Reset();
796
797 m_pAudio->SetPaused(true);
798 FlushAudio();
799
801
802 m_pRender->Resume();
804}
805
812{
813 cDevice::Play();
814
816}
817
822{
823 LOGDEBUG("device: %s:", __FUNCTION__);
824 cDevice::Freeze();
825
827}
828
835void cSoftHdDevice::StillPicture(const uchar *data, int size)
836{
837 LOGDEBUG("device: %s: %s %p %d", __FUNCTION__, data[0] == 0x47 ? "ts" : "pes", data, size);
838
839 if (data[0] == 0x47) { // ts sync byte
840 cDevice::StillPicture(data, size);
841 return;
842 }
843
845}
846
854void cSoftHdDevice::HandleStillPicture(const uchar *data, int size)
855{
858
859 // skip BufferUnderrunEvent{VIDEO} in renderer
861
862 const uchar *currentPacketStart = data;
863 while (currentPacketStart < data + size) {
865
866 if (pesPacket.IsValid())
868 else {
869 LOGWARNING("device: %s: invalid PES packet", __FUNCTION__);
870 break;
871 }
872
873 currentPacketStart += pesPacket.GetPacketLength();
874 }
875
877 m_pVideoStream->ResetInputPts(); // stillpicture shouldn't trigger having video data
879}
880
894{
895// LOGDEBUG("device: %s: timeout %d", __FUNCTION__, timeout_ms);
896 if (IsDetached())
897 return true;
898
900 return true;
901
902 usleep(timeoutMs * 1000);
903
904 return false;
905}
906
913{
914 if (IsDetached())
915 return true;
916
917 LOGDEBUG("device: %s: timeout %d ms", __FUNCTION__, timeoutMs);
919 if (timeoutMs) { // let display thread work
920 usleep(timeoutMs * 1000);
921 }
923 }
924
925 return true;
926}
927
935{
936 LOGDEBUG("device: %s: %d", __FUNCTION__, videoDisplayFormat);
937
938 cDevice::SetVideoDisplayFormat(videoDisplayFormat);
939}
940
952{
953 LOGDEBUG("device: %s: %d", __FUNCTION__, videoFormat16_9);
954
955 // FIXME: 4:3 / 16:9 video format not supported.
956 SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
957}
958
971void cSoftHdDevice::GetVideoSize(int &width, int &height, double &aspectRatio)
972{
973// LOGDEBUG("device: %s: %d x %d @ %f", __FUNCTION__, *width, *height, *aspectRatio);
974
975 if (IsDetached()) { // return default values according to vdr docs
976 width = 0;
977 height = 0;
978 aspectRatio = 1.0;
979 return;
980 }
981
982 m_pVideoStream->GetVideoSize(&width, &height, &aspectRatio);
983}
984
994void cSoftHdDevice::GetOsdSize(int &width, int &height, double &aspectRatio)
995{
996 if (IsDetached()) { // hardcode to 1920x1080 in detached state
997 width = 1920;
998 height = 1080;
999 aspectRatio = (double)width / (double)height;
1000 return;
1001 }
1002
1003 std::lock_guard<std::mutex> lock(m_sizeMutex);
1004 width = m_osdWidth;
1005 height = m_osdHeight;
1006 aspectRatio = (double)width / (double)height;
1007}
1008
1015void cSoftHdDevice::SetOsdSize(int width, int height)
1016{
1017 std::lock_guard<std::mutex> lock(m_sizeMutex);
1018 m_osdWidth = width;
1019 m_osdHeight = height;
1020}
1021
1028void cSoftHdDevice::SetScreenSize(int width, int height)
1029{
1030 std::lock_guard<std::mutex> lock(m_sizeMutex);
1031 m_screenWidth = width;
1032 m_screenHeight = height;
1033}
1034
1043static void PrintStreamData(const uchar *payload)
1044{
1045 LOGDEBUG2(L_CODEC, "Stream: %02X%02X%02X | %02X | %02X%02X | %02X%02X%02X | %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
1046 payload[0],
1047 payload[1],
1048 payload[2],
1049 payload[3],
1050 payload[4],
1051 payload[5],
1052 payload[6],
1053 payload[7],
1054 payload[8],
1055 payload[9],
1056 payload[10],
1057 payload[11],
1058 payload[12],
1059 payload[13],
1060 payload[14],
1061 payload[15],
1062 payload[16],
1063 payload[17],
1064 payload[18],
1065 payload[19],
1066 payload[20],
1067 payload[21],
1068 payload[22],
1069 payload[23],
1070 payload[24]
1071 );
1072}
1073
1087int cSoftHdDevice::PlayAudio(const uchar *data, int size, uchar id)
1088{
1089// LOGDEBUG("device: %s: %p %p %d %d", __FUNCTION__, this, data, size, id);
1090 if (IsDetached())
1091 return size;
1092
1093 m_receivedAudio = true;
1094
1095 if (m_pAudio->IsBufferFull())
1096 return 0;
1097
1098 cPesAudio pesPacket((const uint8_t*)data, size);
1099
1100 if (!pesPacket.IsValid()) {
1102
1103 return size;
1104 }
1105
1107 auto now = std::chrono::steady_clock::now();
1108 auto timeUntilFirstPacketReceived = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_channelSwitchStartTime).count();
1109 LOGDEBUG("device: first valid audio packet arrives %dms after channel switch was triggered", timeUntilFirstPacketReceived);
1110
1113 }
1114 m_receivedValidAudio = true;
1115
1116 if (Transferring()) { // compensation is only necessary with live streams
1121 }
1122
1123 if (m_audioChannelID != id) {
1127 LOGDEBUG("device: %s: new channel id 0x%02X", __FUNCTION__, m_audioChannelID);
1128 }
1129
1130 m_audioReassemblyBuffer.Push(pesPacket.GetPayload(), pesPacket.GetPayloadSize(), pesPacket.GetPts());
1131
1134
1135 AVPacket *avpkt;
1136 do {
1138 break;
1139
1141 // The playback has just started
1144 }
1145
1147 AVPacket *copy = avpkt;
1149 } while (avpkt != nullptr);
1150
1151 return size;
1152}
1153
1155{
1156 //LOGDEBUG("device: %s:", __FUNCTION__);
1157}
1158
1160{
1161 //LOGDEBUG("device: %s: %s", __FUNCTION__, on ? "true" : "false");
1162}
1163
1165 int audio_channel)
1166{
1167 //LOGDEBUG("device: %s: %d", __FUNCTION__, audio_channel);
1168}
1169
1171{
1172 //LOGDEBUG("device: %s:", __FUNCTION__);
1173 return 0;
1174}
1175
1182{
1183 if (IsDetached())
1184 return;
1185
1186 LOGDEBUG("device: %s: %d", __FUNCTION__, volume);
1187 m_volume = volume;
1188 m_pAudio->SetVolume((volume * 1000) / 255);
1189}
1190
1205int cSoftHdDevice::PlayVideo(const uchar *data, int size)
1206{
1207// LOGDEBUG("device: %s: %p %d", __FUNCTION__, data, size);
1208 if (IsDetached())
1209 return size;
1210
1211 m_receivedVideo = true;
1212
1214}
1215
1226int cSoftHdDevice::PlayPipVideo(const uchar *data, int size)
1227{
1228// LOGDEBUG("device: %s: %p %d", __FUNCTION__, data, size);
1229
1230 // This is a bit hacky:
1231 // Because we do no sync with the pip stream, we simply drop data
1232 // if the input buffer is full -> this prevents us from having a buffer overflow
1233 // caused by the pip stream.
1235 return size;
1236
1237 return PlayVideoInternal(m_pPipStream, &m_pipReassemblyBuffer, data, size, false, false);
1238}
1239
1251{
1252 // LOGDEBUG("device: %s: %p %d %s", __FUNCTION__, data, size, mainStream ? "video" : "pip");
1253
1254 if (stream->IsInputBufferFull())
1255 return 0;
1256
1257 cPesVideo pesPacket((const uint8_t*)data, size);
1258
1259 if (!pesPacket.IsValid()) {
1260 buffer->Reset();
1261
1262 return size;
1263 }
1264
1265 if (mainStream) {
1267 auto now = std::chrono::steady_clock::now();
1268 auto timeUntilFirstPacketReceived = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_channelSwitchStartTime).count();
1269 LOGDEBUG("device: first valid video packet arrives %dms after channel switch was triggered", timeUntilFirstPacketReceived);
1270
1273
1274 }
1275 m_receivedValidVideo = true;
1276 }
1277
1278 if (trackJitter) {
1282 }
1283
1284 if (stream->GetCodecId() == AV_CODEC_ID_NONE) {
1285 // The playback has just started
1286 if (!pesPacket.HasPts() || !buffer->ParseCodecHeader(pesPacket.GetPayload(), pesPacket.GetPayloadSize())) {
1287 // received the middle of fragmented data, wait for the next PES packets with the start of a new frame
1288 return size;
1289 }
1290
1291 PrintStreamData(data);
1292 buffer->Push(pesPacket.GetPayload(), pesPacket.GetPayloadSize(), pesPacket.GetPts());
1293
1294 stream->Open(buffer->GetCodec());
1295 } else {
1296 int payloadOffset = 0;
1297 if (pesPacket.HasPts() && !buffer->IsEmpty()) {
1298 // received the first fragment of a new frame, finish the current reassembly buffer into an AVPacket
1299 stream->PushAvPacket(buffer->PopAvPacket());
1300
1301 // populate the cleared buffer with the next frame
1302 if (buffer->HasLeadingZero(pesPacket.GetPayload(), pesPacket.GetPayloadSize()))
1303 payloadOffset = 1; // H.264/HEVC streams may have a leading zero byte before the start code
1304 }
1305
1306 buffer->Push(pesPacket.GetPayload() + payloadOffset, pesPacket.GetPayloadSize() - payloadOffset, pesPacket.GetPts());
1307 }
1308
1309 return size;
1310}
1311
1319
1347{
1348 if (m_state != BUFFERING)
1349 return false;
1350
1354
1355 // Assume audio only or video only if no PES fragment from the other stream has been received, while the buffering threshold of the other stream is reached.
1356 // Check for buffer fill level only if at least one PES packet was reassembled and pushed to the respective decoder.
1359
1361 LOGDEBUG("device: %s: Detected audio only", __FUNCTION__);
1362 return true;
1364 LOGDEBUG("device: %s: Detected video only", __FUNCTION__);
1365 return true;
1367 return false; // Either no video or no audio received, yet. Or, video didn't make it to the output buffer, yet.
1368
1371
1372 bool reached = m_pRender->IsOutputBufferFull() && // video decoder output buffer (audio hardware output buffer is negligible)
1373 syncedVideoBufferFillLevelMs > GetBufferFillLevelThresholdMs() && // video decoder input buffer
1374 syncedAudioBufferFillLevelMs > GetBufferFillLevelThresholdMs(); // audio decoder output buffer
1375
1376 if (reached) {
1377 LOGDEBUG2(L_AV_SYNC, "First received PTS: %s (audio), %s (video) buffer fill levels: %ldms (audio) %ldms (video)",
1382 }
1383
1384 return reached;
1385}
1386
1408
1421
1431uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int width, int height)
1432{
1433 if (!width || !height) {
1434 LOGWARNING("device: %s: width or height is 0 - skip!", __FUNCTION__);
1435 return nullptr;
1436 }
1437
1438 if (IsDetached())
1439 return nullptr;
1440
1441 if (m_pGrab->IsActive()) {
1442 LOGWARNING("device: %s: wait for the last grab to be finished - skip!", __FUNCTION__);
1443 return nullptr;
1444 }
1445
1446 LOGDEBUG2(L_GRAB, "device: %s: %d, %d, %d, %dx%d", __FUNCTION__, size, jpeg, quality, width, height);
1447
1448 if (!m_pGrab->Start(jpeg, quality, width, height, m_screenWidth, m_screenHeight))
1449 return nullptr;
1450
1451 if (!m_pGrab->ProcessGrab())
1452 return nullptr;
1453
1454 size = m_pGrab->Size();
1455 uchar *result = m_pGrab->Image();
1456
1457 m_pGrab->Finish();
1458
1459 return result;
1460}
1461
1470{
1472 return rect;
1473
1474 double scaleFactor = std::min((double)m_screenWidth / m_osdWidth, (double)m_screenHeight / m_osdHeight);
1475 int width = std::lround(scaleFactor * rect.Width());
1476 int height = std::lround(scaleFactor * rect.Height());
1477 int x = std::lround(scaleFactor * rect.X());
1478 int y = std::lround(scaleFactor * rect.Y());
1479
1480 x = std::max(0, x);
1481 y = std::max(0, y);
1482 if (x + width > m_screenWidth)
1483 width = m_screenWidth - x;
1484 if (y + height > m_screenHeight)
1485 height = m_screenHeight - y;
1486
1487 if (width <= 0 || height <= 0)
1488 return cRect::Null;
1489
1490 LOGDEBUG2(L_DRM, "device: %s: scale rect %dx%d-%d|%d -> %dx%d-%d|%d", __FUNCTION__,
1491 rect.Width(), rect.Height(), rect.X(), rect.Y(), width, height, x, y);
1492
1493 return cRect(x, y, width, height);
1494}
1495
1505{
1506 if (IsDetached())
1507 return;
1508
1509 LOGDEBUG2(L_OSD, "device: %s: %dx%d%+d%+d",
1510 __FUNCTION__, rect.Width(), rect.Height(), rect.X(), rect.Y());
1511
1512 if (m_pRender)
1514}
1515
1520{
1521 if (IsDetached())
1522 return;
1523
1525}
1526
1539void cSoftHdDevice::OsdDrawARGB(int xi, int yi, int height, int width, int pitch,
1540 const uint8_t * argb, int x, int y)
1541{
1542 if (IsDetached())
1543 return;
1544
1545 m_pRender->OsdDrawARGB(xi, yi, height, width, pitch, argb, x, y);
1546}
1547
1548#ifdef USE_GLES
1556
1564
1574
1584
1585#endif
1586
1595
1604
1613
1628
1638
1643{
1644 LOGDEBUG("%s:", __FUNCTION__);
1645 m_audioChannelID = -1;
1646}
1647
1656{
1657 *duped = 0;
1658 *dropped = 0;
1659 *counter = 0;
1660 if (m_pRender) {
1662 }
1663}
1664
1665/*****************************************************************************
1666 * media player functions
1667 ****************************************************************************/
1668
1680
1692
1702{
1703 m_pAudio->LazyInit();
1704
1705 if (m_pAudio->IsBufferFull())
1706 return 0;
1707
1709 return 1;
1710}
1711
1721{
1722 m_pAudio->LazyInit();
1723
1725 return 0;
1726
1728
1729 return 1;
1730}
1731
1732/*****************************************************************************
1733 * Detach and attach functionality
1734 ****************************************************************************/
1735
1743{
1744 if (cDevice::Replaying()) {
1745 LOGDEBUG("device: %s: Device is replaying, stop replay first", __FUNCTION__);
1746 StopReplay();
1747 }
1748
1749 if (IsPrimaryDevice(false)) {
1750 m_needsMakePrimary = true;
1751 MakePrimaryDevice(false);
1752 }
1753
1756}
1757
1765{
1766 m_forceDetached = false;
1767
1768 if (m_needsMakePrimary) {
1769 MakePrimaryDevice(true);
1770 m_needsMakePrimary = false;
1771 }
1772
1774}
1775
1780{
1781 std::lock_guard<std::mutex> lock(m_mutex);
1782 return m_state == State::DETACHED;
1783}
1784
1785/*****************************************************************************
1786 * PiP functionality
1787 ****************************************************************************/
1788
1812
1817{
1818 std::lock_guard<std::mutex> lock(m_mutex);
1819 return m_pPipHandler->IsEnabled();
1820}
1821
1822/*
1823 * Wrapper functions for cVideoRender and cPipHandler
1824 */
1826{
1827 std::lock_guard<std::mutex> lock(m_mutex);
1828 m_pRender->Halt();
1830 m_pRender->Resume();
1831};
1832
1834{
1835 std::lock_guard<std::mutex> lock(m_mutex);
1836 m_pRender->Halt();
1837 m_pRender->SetPipActive(active);
1838 m_pRender->Resume();
1839};
1840
1848
1851
1858{
1860
1864 if (!mode->width || !m_pRender->CanHandleMode(mode))
1866 } else if (idx >= CONFIG_DISPLAY_MODE_MANUAL)
1868
1869 // Check, if the requested mode differs from the current one at all
1870 if (!m_pConfig->CompareCurrentMode(mode)) {
1871 LOGDEBUG("Add display mode change event to %s mode %dx%d@%.2f%s",
1872 idx == CONFIG_DISPLAY_MODE_DEFAULT ? "default" :
1873 (idx == CONFIG_DISPLAY_MODE_FOLLOW_VIDEO ? "follow video" :
1874 (idx == CONFIG_DISPLAY_MODE_FOLLOW_VIDEO_INTERLACED ? "follow video interlaced" :
1875 "fixed")),
1876 mode->width, mode->height, mode->refreshRateHz, mode->interlaced ? "i" : "");
1878 }
1879}
1880
1887{
1888 LOGDEBUG("Set display mode: %dx%d@%.2f%s",
1889 mode.width,
1890 mode.height,
1891 mode.refreshRateHz,
1892 mode.interlaced ? "i" : "");
1893
1896}
1897
1902 : cThread("event handler"),
1903 m_pDevice(device),
1904 m_pEventReceiver(device)
1905{
1906 Start();
1907}
1908
1913{
1914 Cancel(2);
1915}
1916
1921{
1922 LOGDEBUG("device: event queue handler thread started");
1923
1924 while (Running()) {
1925 std::vector<Event> local;
1926 {
1927 std::lock_guard<std::mutex> lock(m_mutex);
1928 local.swap(m_eventQueue);
1929 }
1930
1931 for (auto &event : local)
1933
1934 usleep(10000);
1935
1936 }
1937
1938 LOGDEBUG("device: event queue handler thread stopped");
1939}
1940
1945{
1946 std::lock_guard<std::mutex> lock(m_mutex);
1947 m_eventQueue.push_back(event);
1948}
Audio Interface Header File.
virtual void OnEventReceived(const Event &)=0
Audio Decoder.
Definition codec_audio.h:59
void FlushBuffers(void)
Flush the audio decoder buffers.
void Decode(const AVPacket *)
Forward an audio packet either to the decoder or passthrough.
AVCodecID GetCodecId() const
Definition codec_audio.h:68
void SetPassthroughMask(int)
Set audio pass-through mask.
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=90000 })
Open and initiate the audio decoder.
void Close(void)
Close the audio decoder.
Event handler thread.
void AddEvent(Event)
Add an event to the queue.
std::vector< Event > m_eventQueue
event fifo queue
cEventHandler(cSoftHdDevice *)
Create and start the event handler thread.
std::mutex m_mutex
queue mutex
virtual ~cEventHandler(void)
Stop and delete the event handler thread.
IEventReceiver * m_pEventReceiver
pointer to event receiver
virtual void Action(void) override
Periodically send events in the queue to the final event receiver/handler.
Hardware device.
int GetQuirks(void)
Get Hardware Quirks.
int GetShortTermMaxJitterMs(void)
int GetLongTermMaxJitterMs(void)
void PacketReceived(void)
Called each time a packet is received.
void Reset(void)
Resets the jitter tracker.
Main Video Stream.
Audio PES Packet Parser.
Definition pes.h:79
Video PES Packet Parser.
Definition pes.h:64
PiP Stream Handler.
Definition pipreceiver.h:55
void ChannelChange(int)
Change the pip channel.
void SwapPosition(void)
Swap pip between normal and alternative position.
void Toggle(void)
Toggle picture-in-picture.
void Disable(void)
Stop picture-in-picture.
void ChannelSwap(bool)
Swap the pip channel with main live channel.
bool IsEnabled(void)
Definition pipreceiver.h:68
void Enable(void)
Start picture-in-picture.
void SetSize(void)
Set size and position for the pip window.
PiP Video Stream.
AVPacket * PopAvPacket(void) override
Pop an audio AVPacket from the reassembly buffer.
Definition pes.cpp:486
Video Stream Reassembly Buffer.
Definition pes.h:145
AVPacket * PopAvPacket(void) override
Definition pes.h:148
bool HasLeadingZero(const uint8_t *, int)
Check if video data has a leading zero byte before the start code.
Definition pes.cpp:469
bool ParseCodecHeader(const uint8_t *, int)
Parse video codec header to detect codec type.
Definition pes.cpp:432
AVCodecID GetCodec(void)
Definition pes.h:128
void Reset(void)
Reset the reassembly buffer.
Definition pes.cpp:659
virtual void Push(const uint8_t *data, int size, int64_t pts)
Definition pes.h:123
bool IsEmpty(void)
Definition pes.h:125
Audio Interface.
Definition audio.h:51
void LazyInit(void)
Initialize audio output module (alsa)
Definition audio.cpp:933
void ResetHwDelayBaseline(void)
Reset the hw delay baseline.
Definition audio.cpp:1149
int64_t GetInputPtsMs(void)
Definition audio.h:71
void SetHwDelayBaseline(void)
Set the hw delay baseline.
Definition audio.cpp:1131
int64_t GetHardwareOutputPtsTimebaseUnits(void)
Get the hardware output PTS in timebase units.
Definition audio.cpp:832
void SetVolume(int)
Set mixer volume (0-1000)
Definition audio.cpp:846
void DropSamplesOlderThanPtsMs(int64_t)
Drop samples older than the given PTS.
Definition audio.cpp:421
int64_t GetOutputPtsMs(void)
Get the output PTS of the ringbuffer.
Definition audio.cpp:774
void ClockDriftCompensation(void)
Calculate clock drift compensation.
Definition audio.cpp:1179
void Exit(void)
Cleanup audio output module (alsa)
Definition audio.cpp:949
void SetPaused(bool)
Set audio playback pause state.
Definition audio.cpp:868
void SetPassthroughMask(int mask)
Definition audio.h:83
bool HasInputPts(void)
Definition audio.h:70
bool IsBufferFull(void)
Definition audio.h:62
void FlushBuffers(void)
Flush audio buffers.
Definition audio.cpp:722
Plugin Configuration.
Definition config.h:49
bool ConfigParseH264Dimensions
parse h264 stream for width and height for decoder init
Definition config.h:102
sDrmMode RequestedDrmMode
is set to the requested mode which should be changed to
Definition config.h:137
int ConfigVideoAudioDelayMs
config audio delay
Definition config.h:68
std::atomic< int > StatMaxLongTermAudioJitterMs
logged max overall audio jitter since stream start
Definition config.h:129
int ConfigMaxSizeGPUImageCache
config max gpu image cache size
Definition config.h:106
std::atomic< int > StatMaxShortTermAudioJitterMs
logged max audio jitter of the last 1000 packets
Definition config.h:128
int ConfigDecoderFallbackToSwNumPkts
maximum number of packets sent before fallback to sw decoder
Definition config.h:100
std::vector< sDrmMode > CollectedDrmModes
collected available drm modes on the current connector
Definition config.h:132
bool ConfigDisableDeint
disable deinterlacer
Definition config.h:98
int ConfigDisableOglOsd
config disable ogl osd
Definition config.h:120
int ConfigAdditionalBufferLengthMs
config size ms of a/v buffer
Definition config.h:97
bool CompareCurrentMode(sDrmMode *)
Return true, if the given mode is equal to the current display mode.
Definition config.cpp:165
std::atomic< int > StatMaxShortTermVideoJitterMs
logged max video jitter of the last 1000 packets
Definition config.h:130
bool ConfigDecoderNeedsIFrame
start h264 decoder only when an I-Frame arrives
Definition config.h:101
sDrmMode AutoDetectedDrmMode
auto detected mode on the first startup (maybe equal to UserSetMode)
Definition config.h:133
std::atomic< int > StatMaxLongTermVideoJitterMs
logged max overall video jitter since stream start
Definition config.h:131
sDrmMode CurrentVideoDrmMode
currently used video drm mode
Definition config.h:136
Output Device Implementation.
void SetState(State)
Sets the device into the given state.
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD pixmap.
cReassemblyBufferVideo m_videoReassemblyBuffer
video pes reassembly buffer
void Stop(void)
Called by VDR when the plugin is stopped.
bool m_pipUseAlt
use alternative pip position
cReassemblyBufferVideo m_pipReassemblyBuffer
pip pes reassembly buffer
void PipChannelSwap(bool)
cVideoStream * m_pPipStream
pointer to pip video stream
void FlushAudio(void)
Clear all audio data from the decoder and ringbuffer.
void PipSwapPosition(void)
static constexpr int MIN_BUFFER_FILL_LEVEL_THRESHOLD_MS
min buffering threshold in ms
int m_volume
track the volume in the device (for attach)
void SetScreenSize(int, int)
Set the screen size.
virtual void StillPicture(const uchar *, int)
Display the given I-frame as a still picture.
void PipSetSize(void)
void HandleDisplayModeChange(const sDrmMode &)
Set the display mode.
cSoftOsdProvider * m_pOsdProvider
pointer to cSoftOsdProvider object
cVideoStream * m_pVideoStream
pointer to main video stream
cReassemblyBufferAudio m_audioReassemblyBuffer
audio pes reassembly buffer
int MaxSizeGPUImageCache(void)
Get the maximum GPU image cache size.
std::atomic< bool > m_receivedAudio
flag if audio packets have been received
void SetRenderPipSize(void)
cDvbSpuDecoder * m_pSpuDecoder
pointer to spu decoder
void OnEnteringState(State)
Actions to be performed when entering a state.
int Start(void)
Called by VDR when the plugin is started.
void SetEnableOglOsd(void)
Enables OpenGL/ES Osd.
virtual void GetVideoSize(int &, int &, double &)
Get the video size.
int PlayAudioPkts(AVPacket *)
Play an audio packet.
virtual void GetOsdSize(int &, int &, double &)
Returns the width, height and aspect ratio the OSD should have.
void SetEnableHdr(bool)
Enable HDR display mode.
void SetRenderPipActive(bool)
void GetStats(int *, int *, int *)
Get statistics from the renderer.
void ResetChannelId(void)
Reset the channel ID (restarts audio)
cHardwareDevice * m_pHardwareDevice
pointer to hardware device description
virtual bool CanReplay(void) const
Return true if this device can currently start a replay session.
virtual void SetDigitalAudioDevice(bool)
std::mutex m_mutex
mutex to lock the state machine
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
virtual void Clear(void)
Clears all video and audio data from the device.
cEventHandler * m_pEventHandler
event handler thread
void OnEventReceived(const Event &)
Event handler for playback state transitions.
cPipHandler * m_pPipHandler
pointer to pip handler
void Detach(void)
Detach the device.
virtual int PlayVideo(const uchar *, int)
Play a video packet of the main videostream.
void ResetPipStream(void)
Resets pip stream and render pipeline.
std::chrono::steady_clock::time_point m_dataReceivedTime
timestamp, when the first audio or video data after a channel switch arrives in Play*()
std::atomic< State > m_state
current plugin state, normal plugin start sets detached state
void OnLeavingState(State)
Actions to be performed when leaving a state.
virtual bool SetPlayMode(ePlayMode)
Sets the device into the given play mode.
cAudioDecoder * m_pAudioDecoder
pointer to cAudioDecoder object
void SetAudioCodec(enum AVCodecID, AVCodecParameters *, AVRational)
Open an audio codec.
virtual void Play(void)
Sets the device into play mode (after a previous trick mode, or pause)
bool IsBufferingThresholdReached(void)
Check if the buffering threshold has been reached.
cVideoRender * m_pRender
pointer to cVideoRender object
virtual void SetAudioChannelDevice(int)
void SetOsdSize(int, int)
Set the OSD size.
cSoftHdGrab * m_pGrab
pointer to grabber object
int OglOsdIsDisabled(void)
Is the OpenGL/ES osd disabled?
cSoftHdDevice(cSoftHdConfig *)
Create the device.
int PlayPipVideo(const uchar *, int)
Play a video packet of the pip videostream.
bool m_needsMakePrimary
true, if device should be made a primary device after attach
virtual void ChannelSwitch(const cDevice *, int, bool)
Monitor a channel switch triggered by VDR (cStatus::ChannelSwitch())
cSoftHdAudio * m_pAudio
pointer to cSoftHdAudio object
cSoftHdConfig * m_pConfig
pointer to cSoftHdConfig object
virtual cRect CanScaleVideo(const cRect &, int taCenter)
Ask the output, if it can scale video.
virtual void SetVolumeDevice(int)
Sets the audio volume on this device (Volume = 0...255).
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles.
virtual bool Flush(int=0)
Flush the device output buffers.
bool IsDetached(void) const
Returns true, if the device is detached.
virtual void TrickSpeed(int, bool)
Sets the device into a mode where replay is done slower.
std::chrono::steady_clock::time_point m_channelSwitchStartTime
timestamp, when VDR triggered a channel switch
void SetDecoderFallbackToSw(bool)
Force the decoder to fallback to software if the hardware decoder fails after the configured amount o...
virtual int PlayAudio(const uchar *, int, uchar)
Play an audio packet.
void PipToggle(void)
bool PipIsEnabled(void)
Returns true, if pip is currently enabled.
std::mutex m_sizeMutex
mutex to lock screen size (which is accessed by different threads)
bool Initialize(void)
Initialize the device.
std::atomic< bool > m_receivedVideo
flag if video packets have been received
void SetDecoderNeedsIFrame(void)
Forces the h264 decoder to wait for an I-Frame to start.
virtual int GetAudioChannelDevice(void)
int PlayVideoPkts(AVPacket *)
Play a video packet.
std::atomic< bool > m_receivedValidAudio
flag if valid audio packets have been received
cJitterTracker m_audioJitterTracker
audio jitter tracker
std::atomic< bool > m_receivedValidVideo
flag if valid video packets have been received
int GetBufferFillLevelThresholdMs()
Returns the buffer fill level threshold in milliseconds.
void HandleStillPicture(const uchar *data, int size)
The still picture data received from VDR can contain multiple PES packets.
int PlayVideoInternal(cVideoStream *, cReassemblyBufferVideo *, const uchar *, int, bool, bool)
Play a video packet.
virtual void SetVideoDisplayFormat(eVideoDisplayFormat)
Sets the video display format.
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
void SetParseH264Dimensions(void)
Parse the h264 stream width and height before starting the decoder.
void SetDisableOglOsd(void)
Disables OpenGL/ES Osd (called from setup menu or conf)
bool m_forceDetached
start the plugin in detached state
virtual ~cSoftHdDevice(void)
Destroy the device.
int m_audioChannelID
current audio channel ID
void PipDisable(void)
virtual void SetVideoFormat(bool)
Set the video format.
virtual void MakePrimaryDevice(bool)
Informs a device that it will be the primary device.
void SetVideoCodec(enum AVCodecID, AVCodecParameters *, AVRational)
Open a video codec.
void PipEnable(void)
void SetPassthroughMask(int)
Set the passthrough mask (called from setup menu or conf)
void SetDisableDeint(void)
Disables deinterlacer (called from setup menu or conf)
virtual uchar * GrabImage(int &, bool, int, int, int)
Grabs the currently visible screen image.
virtual cSpuDecoder * GetSpuDecoder(void)
Get the device SPU decoder.
cJitterTracker m_videoJitterTracker
video jitter tracker
virtual void SetAudioTrackDevice(eTrackType)
std::atomic< PlaybackMode > m_playbackMode
current playback mode
void OsdClose(void)
Close the OSD.
int64_t GetFirstAudioPtsMsToPlay()
Calculate the first audio PTS that should be played during synchronized playback.
virtual void ScaleVideo(const cRect &=cRect::Null)
Scale the currently shown video.
int64_t GetFirstVideoPtsMsToPlay()
void SetDisplayMode(int)
Trigger a display mode change event if the mode changed.
void PipChannelChange(int)
virtual bool Poll(cPoller &, int=0)
Return true if the device itself or any of the file handles in poller is ready for further action.
void Attach(void)
Attach the device again.
bool m_externalPlayerActive
true, if we detached for an external player
Grabbing Processor.
Definition grab.h:79
bool IsActive(void)
Definition grab.h:83
bool Start(bool, int, int, int, int, int)
Start a grab in the video renderer.
Definition grab.cpp:661
uint8_t * Image(void)
Definition grab.h:85
bool ProcessGrab(void)
Start the conversion.
Definition grab.cpp:780
int Size(void)
Definition grab.h:86
void Finish(void)
Clean up.
Definition grab.cpp:695
Plugin OSD provider.
void RequestStopOpenGlThread(void)
Initiate a stop of the OpenGL thread without waiting.
void StopOpenGlThread(void)
Stop the OpenGL thread and cancel it if necessary.
void UnlockOpenGlThread(void)
Unlock the OpenGL thread.
bool LockOpenGlThread(void)
Lock the OpenGL thread.
Video Renderer.
void PushPipFrame(AVFrame *)
Push a PiP frame into the render ringbuffer.
bool IsOutputBufferFull(void)
Check, if the main render output buffer is full.
void SetEnableHdr(bool enable)
void Reset()
Reset the renderer.
void ResetBufferReuseStrategy()
void Halt(void)
void ReInitDisplayMode(void)
Re-Initialize the drm device with current display mode settings.
void OsdClear(void)
Clear the OSD (draw an empty/ transparent OSD)
void ScheduleVideoPlaybackPauseAt(int64_t ptsMs)
void ScheduleResyncAtPtsMs(int64_t ptsMs)
void ClearDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
void Init(void)
Initialize the renderer.
void ResetDecodingStrategy()
void Exit(void)
Exit and cleanup the renderer.
void EnableOglOsd(void)
void ResetPipBufferReuseStrategy()
void GetStats(int *, int *, int *)
Get some rendering statistics.
void DisplayBlackFrame(void)
Display a black video frame.
void PushMainFrame(AVFrame *)
Push a main frame into the render ringbuffer.
void SetVideoOutputPosition(const cRect &)
Set size and position of the video on the screen.
int64_t GetOutputPtsMs(void)
Get the output PTS in milliseconds.
void SetPipActive(bool on)
void ClearPipDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
cQueue< cDrmBuffer > * GetPipOutputBuffer(void)
void Resume(void)
void SetStillpicture(bool active)
void SchedulePlaybackStartAtPtsMs(int64_t ptsMs)
int64_t GetVideoClock(void)
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD ARGB image.
void SetScheduleAudioResume(bool resume)
void SetDisplayOneFrameThenPause(bool pause)
void SetPipSize(bool)
Set the size and position of the pip window.
void DisableOglOsd(void)
void SetPlaybackPaused(bool pause)
void ResetFrameCounter(void)
Send start condition to video thread.
bool CanHandleMode(sDrmMode *)
Wrapper to check, if drm can handle the display mode.
void SetTrickSpeed(double, bool, bool)
Set the trickspeed parameters.
void ResetPipDecodingStrategy()
cQueue< cDrmBuffer > * GetMainOutputBuffer(void)
Video Input Stream.
Definition videostream.h:47
void GetVideoSize(int *, int *, double *)
Get video size and aspect ratio.
void SetDecoderFallbackToSwNumPkts(int numPackets)
Definition videostream.h:90
void Flush(void)
Flushes the video stream by finalizing any pending data.
void StartDecoder()
Start the decoder.
void ClearVdrCoreToDecoderQueue(void)
Clears all video stream data, which is buffered to be decoded.
void ResetInputPts(void)
Definition videostream.h:77
void Resume(void)
Definition videostream.h:65
int GetVideoPacketMax(void)
Definition videostream.h:79
void SetStartDecodingWithIFrame(bool enable)
Definition videostream.h:88
size_t GetAvPacketsFilled(void)
Definition videostream.h:70
void DisableDeint(bool disable)
Definition videostream.h:87
void CloseDecoder(void)
Close the decoder.
void Exit(void)
Exit video stream.
void CancelFilterThread(void)
Stop filter thread.
void FlushDecoder(void)
Flush the decoder.
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=90000 })
Open a video codec.
bool PushAvPacket(AVPacket *avpkt)
Pushes a pre-assembled AVPacket directly to the processing queue.
bool IsInputBufferFull(void)
Definition videostream.h:71
void ResetFilterThreadNeededCheck()
Definition videostream.h:83
int64_t GetInputPtsMs(void)
void SetParseH264Dimensions(bool enable)
Definition videostream.h:89
void Halt(void)
Definition videostream.h:64
virtual void SetDeinterlacerDeactivated(bool deactivate)
Definition videostream.h:85
void ResetTrickSpeedFramesSentCounter(void)
Definition videostream.h:73
bool HasInputPts(void)
Definition videostream.h:74
Audio Decoder Header File.
Plugin Configuration Header File.
@ CONFIG_DISPLAY_MODE_DEFAULT
Definition config.h:38
@ CONFIG_DISPLAY_MODE_FOLLOW_VIDEO_INTERLACED
Definition config.h:40
@ CONFIG_DISPLAY_MODE_FOLLOW_VIDEO
Definition config.h:39
@ CONFIG_DISPLAY_MODE_MANUAL
Definition config.h:41
__attribute__((weak)) union gbm_bo_handle gbm_bo_get_handle_for_plane(struct gbm_bo *bo
State Machine and Event Header File.
Grabbing Interface Header File.
const char * EventToString(const Event &e)
State
const char * StateToString(State s)
static void PrintStreamData(const uchar *payload)
Print the start code, stream id, length, first three bytes (start code) of the payload,...
@ AUDIO_AND_VIDEO
@ VIDEO_ONLY
@ AUDIO_ONLY
@ NONE
@ PLAY
@ STOP
@ BUFFERING
@ TRICK_SPEED
@ DETACHED
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:47
#define LOGDEBUG
log to LOG_DEBUG
Definition logger.h:45
#define LOGERROR
log to LOG_ERR
Definition logger.h:39
#define AV_NOPTS_VALUE
Definition misc.h:74
std::variant< PlayEvent, PauseEvent, StopEvent, TrickSpeedEvent, StillPictureEvent, DetachEvent, AttachEvent, BufferUnderrunEvent, BufferingThresholdReachedEvent, ScheduleResyncAtPtsMsEvent, ResyncEvent, DisplayChangeEvent > Event
Definition event.h:73
#define LOGWARNING
log to LOG_WARN
Definition logger.h:41
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:37
static const char * Timestamp2String(int64_t ts, uint8_t divisor)
Nice time-stamp string.
Definition misc.h:127
@ L_DRM
drm logs
Definition logger.h:60
@ L_AV_SYNC
audio/video sync logs
Definition logger.h:57
@ L_OSD
osd logs
Definition logger.h:59
@ L_CODEC
codec logs
Definition logger.h:61
@ L_GRAB
grabbing logs
Definition logger.h:69
Describes a hardware device.
Jitter Tracking of Incoming Packets Header File.
Logger Header File.
PES Packet Parser Header File.
PiP (Picture-in-Picture) Interface Header File.
Output Device Header File.
OSD Provider Header File.
Holds possible display configurations.
Definition config.h:30
int width
display width
Definition config.h:31
bool interlaced
is this an interlaced mode?
Definition config.h:34
int height
display height
Definition config.h:32
double refreshRateHz
display refresh rate
Definition config.h:33
Video Renderer (Display) Header File.
Video Input Stream Header File.