vdr-plugin-softhddevice-drm-gles 1.6.2
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
31#include "audio.h"
32#include "codec_audio.h"
33#include "config.h"
34#include "event.h"
35#include "grab.h"
36#include "jittertracker.h"
37#include "logger.h"
38#include "pes.h"
39#include "pipreceiver.h"
40#include "softhddevice.h"
41#include "softhdosdprovider.h"
42#include "videorender.h"
43#include "videostream.h"
44
60 : m_pSpuDecoder(new cDvbSpuDecoder()),
61 m_pConfig(config),
62 m_pipUseAlt(m_pConfig->ConfigPipUseAlt)
63{
64// LOGDEBUG("device: %s:", __FUNCTION__);
65
66 m_channelSwitchStartTime = std::chrono::steady_clock::now();
68}
69
76{
77 LOGDEBUG("device: %s:", __FUNCTION__);
78 delete m_pSpuDecoder;
79}
80
85{
86 LOGDEBUG("device: %s", __FUNCTION__);
88
89 return true;
90}
91
96{
97 LOGDEBUG("device: %s", __FUNCTION__);
99}
100
111
118{
119 LOGDEBUG("device: %s: %d", __FUNCTION__, on);
120
121 if (on)
122 m_pOsdProvider = new cSoftOsdProvider(this); // no need to delete it, VDR does it
123
124 cDevice::MakePrimaryDevice(on);
125}
126
133void cSoftHdDevice::ChannelSwitch(const cDevice *device, int channelNum, bool liveView)
134{
135 if (device != cDevice::PrimaryDevice())
136 return;
137
138 if (!liveView)
139 return;
140
141 if (channelNum == 0)
142 m_channelSwitchStartTime = std::chrono::steady_clock::now();
143}
144
152{
153 LOGDEBUG("device: %s:", __FUNCTION__);
154 if (!IsPrimaryDevice())
155 return NULL;
156
157 return m_pSpuDecoder;
158}
159
164{
165 bool hasDecoder = !IsDetached();
166
167// LOGDEBUG("device: %s: %d", __FUNCTION__, hasDecoder);
168
169 return hasDecoder;
170}
171
176{
177 bool canReplay = !IsDetached();
178
179 LOGDEBUG("device: %s: %d", __FUNCTION__, canReplay);
180
181 return canReplay;
182}
183
195{
196 uint64_t startStateChange = cTimeMs::Now();
197 LOGDEBUG("device: STATE MACHINE received %s", EventToString(event));
198 bool needsResume = false;
199
200#ifdef USE_GLES
201 // Lock the GL thread before the state machine lock, because cmdCopyBufferToOutputFb() calls
202 // cSoftHdDevice::OsdDrawARGB(), which itself locks the state machine mutex and we can end
203 // up in a deadlock then.
204 // We can safely unlock the thread again after the state change, because cSoftHdDevice::OsdDrawARGB()
205 // always tests if we are in detached mode and this new state is probably set then.
206 bool needsOglResume = false;
209#endif
210
211 { // locked state machine context
212 std::lock_guard<std::mutex> lock(m_mutex);
213
214 if (m_state != DETACHED) {
215 m_pRender->Halt();
217 needsResume = true;
218 }
219
220 auto invalid = [this, &event]() {
221 LOGWARNING("device: Invalid event '%s' in state '%s' received", EventToString(event), StateToString(m_state));
222 };
223
224 switch (m_state) {
225 case State::DETACHED:
226 std::visit(overload{
227 [&invalid](const PlayEvent&) { invalid(); },
228 [&invalid](const PauseEvent&) { invalid(); },
229 [&invalid](const StopEvent&) { invalid(); },
230 [&invalid](const TrickSpeedEvent&) { invalid(); },
231 [&invalid](const StillPictureEvent&) { invalid(); },
232 [](const DetachEvent&) { /* ignore */ },
233 [this](const AttachEvent&) {
234 if (!m_forceDetached)
235 SetState(STOP);
236 },
237 [&invalid](const BufferUnderrunEvent&) { invalid(); },
239 [&invalid](const PipEvent&) { invalid(); },
241 [&invalid](const ResyncEvent&) { invalid(); },
242 }, event);
243 needsResume = false;
244 break;
245 case State::STOP:
246 std::visit(overload{
247 [this](const PlayEvent&) {
249 m_pAudio->SetVolume((m_volume * 1000) / 255);
253 },
254 [&invalid](const PauseEvent&) { invalid(); },
255 [&invalid](const StopEvent&) { invalid(); },
256 [&invalid](const TrickSpeedEvent&) { invalid(); },
257 [this](const StillPictureEvent& s) {
258 HandleStillPicture(s.data, s.size);
259 },
260 [this, &needsResume](const DetachEvent&) {
263 needsResume = false;
264 },
265 [&invalid](const AttachEvent&) { invalid(); },
266 [&invalid](const BufferUnderrunEvent&) { invalid(); },
268 [this](const PipEvent& p) {
270 },
272 [&invalid](const ResyncEvent&) { invalid(); },
273 }, event);
274 break;
275 case State::BUFFERING:
276 std::visit(overload{
277 [this](const PlayEvent&) {
278 // ignore
279 },
280 [this](const PauseEvent&) {
281 // ignore
282 },
283 [this](const StopEvent&) {
284 SetState(STOP);
285 },
286 [this](const TrickSpeedEvent& t) {
287 // abort buffering and proceed with trick speed immediately, because trick speed shall be as fast and as demanded as possible
288 SetState(PLAY);
289 m_pRender->SetTrickSpeed(t.speed, t.active, t.forward);
291 },
292 [this](const StillPictureEvent& s) {
293 HandleStillPicture(s.data, s.size);
294 },
295 [this, &needsResume](const DetachEvent&) {
297 needsResume = false;
298 },
299 [&invalid](const AttachEvent&) { invalid(); },
300 [&invalid](const BufferUnderrunEvent&) { invalid(); },
301 [this](const BufferingThresholdReachedEvent&) {
304
309 // store the first PTSes beforehand, because dropping samples/frames will change the output of GetFirst*PtsMsToPlay()
312 } else if (receivedAudio) {
313 LOGDEBUG("device: audio only detected");
316 } else if (receivedVideo) {
317 LOGDEBUG("device: video only detected");
320 } else
321 LOGFATAL("device: buffering threshold reached and no a/v available. This is a bug.");
322
323 SetState(PLAY);
324 },
325 [this](const PipEvent& p) {
327 },
328 [this](const ScheduleResyncAtPtsMsEvent& s) {
329 SetState(PLAY);
331 },
332 [&invalid](const ResyncEvent&) { invalid(); },
333 }, event);
334 break;
335 case State::PLAY:
336 std::visit(overload{
337 [this](const PlayEvent&) {
338 // resume from pause
340 switch (m_playbackMode) {
341 case AUDIO_ONLY:
343 m_pAudio->SetPaused(false);
344 break;
345 case AUDIO_AND_VIDEO:
348 if (audioBehindVideoByMs > 0) {
350 m_pAudio->SetPaused(false);
351 } else
353
354 // fallthrough
355 case VIDEO_ONLY:
358 break;
359 case NONE:
360 LOGFATAL("device: play event in PLAY state with NONE playback mode. This is a bug.");
361 break;
362 }
363 },
364 [this](const PauseEvent&) {
367 else
369
370 m_pAudio->SetPaused(true);
372 },
373 [this](const StopEvent&) {
374 SetState(STOP);
375 },
376 [this](const TrickSpeedEvent& t) {
377 m_pRender->SetTrickSpeed(t.speed, t.active, t.forward);
379 },
380 [this](const StillPictureEvent& s) {
381 HandleStillPicture(s.data, s.size);
382 },
383 [this, &needsResume](const DetachEvent&) {
386 needsResume = false;
387 },
388 [&invalid](const AttachEvent&) { invalid(); },
389 [this](const BufferUnderrunEvent&) {
391 },
393 // ignore
394 },
395 [this](const PipEvent& p) {
397 },
398 [this](const ScheduleResyncAtPtsMsEvent& s) {
400 },
401 [this](const ResyncEvent&) {
403 },
404 }, event);
405 break;
407 std::visit(overload{
408 [this](const PlayEvent&) {
409 SetState(PLAY);
410 },
411 [this](const PauseEvent&) {
413 m_pAudio->SetPaused(true);
415 },
416 [this](const StopEvent&) {
417 SetState(STOP);
418 },
419 [this](const TrickSpeedEvent& t) {
420 // resume from pause, or change trick speed direction/speed
421 m_pRender->SetTrickSpeed(t.speed, t.active, t.forward);
423 },
424 [this](const StillPictureEvent& s) {
425 HandleStillPicture(s.data, s.size);
426 },
427 [this, &needsResume](const DetachEvent&) {
430 needsResume = false;
431 },
432 [&invalid](const AttachEvent&) { invalid(); },
433 [this](const BufferUnderrunEvent&) {
434 // ignore during trick speed. Fast forward/reverse as fast and as demanded as possible
435 },
437 [this](const PipEvent& p) {
439 },
441 [&invalid](const ResyncEvent&) { invalid(); },
442 }, event);
443 break;
444 }
445
446 if (needsResume) {
448 m_pRender->Resume();
449 }
450
451 } // end of locked state machine context
452#ifdef USE_GLES
455#endif
456
457 uint64_t stopStateChange = cTimeMs::Now();
458 LOGDEBUG("device: STATE MACHINE state change done in %d ms", (int)(stopStateChange - startStateChange));
459}
460
470 switch (state) {
471 case BUFFERING:
473 // nothing
474 break;
475 case PLAY:
477 m_pAudio->SetPaused(false);
478
479 if (m_playbackMode != AUDIO_ONLY) {
483 }
484 break;
485 case TRICK_SPEED:
486 // The filter thread needs to be restarted for interlaced streams to be rendered without deinterlacer in trick speed mode. It is started lazily.
491 break;
492 case STOP:
493 FlushAudio();
494
497 m_pRender->Reset();
499
508
509 break;
510 case DETACHED:
511 delete m_pPipHandler;
512 m_pPipHandler = nullptr;
513
514 // resume the previously stopped threads
516 m_pRender->Resume();
517
518 // now do the detach
520 delete m_pPipStream;
521
522#ifdef USE_GLES
523 // The opengl thread was probably locked before cmdCopyBufferToOutputFb().
524 // 1) set running to false
525 // 2) continue the thread (which will skip the waiting cmd->Execute())
526 // 3) do the real thread cancel and cleanup
527 // We need to keep this order to prevent a deadlock!
531#endif
532 m_pRender->Exit(); // render must be stopped before videostream!
534 m_pAudio->Exit(); // audio must be stopped after renderer!
535
536 delete m_pAudioDecoder; // includes a Close()
537 delete m_pVideoStream;
538 delete m_pGrab;
539 delete m_pRender;
540 delete m_pAudio;
541
542 break;
543 }
544}
545
555 switch (state) {
556 case PLAY:
559 m_pAudio->SetPaused(true);
561 break;
562 case BUFFERING:
565 break;
566 case TRICK_SPEED:
567 // The filter thread needs to be restarted for interlaced streams to be rendered with deinterlacer again. It is started lazily.
569 m_pRender->SetTrickSpeed(0, false, false);
576 break;
577 case STOP:
578 m_receivedAudio = false;
579 m_receivedVideo = false;
580 break;
581 case DETACHED:
582 m_pAudio = new cSoftHdAudio(this);
583 m_pRender = new cVideoRender(this);
587 m_pRender->Init(); // starts display thread
588 m_pVideoStream->StartDecoder(); // starts decoding thread
590 m_pPipStream->StartDecoder(); // starts decoding thread
591 m_pPipHandler = new cPipHandler(this);
592 // Audio is init lazily (includes starting thread)
593
594 break;
595 }
596}
597
604{
605 if (m_state != newState) {
606 LOGDEBUG("device: Preparing to leave state %s", StateToString(m_state));
608 LOGDEBUG("device: Changing state %s -> %s", StateToString(m_state), StateToString(newState));
611 LOGDEBUG("device: State changed to %s", StateToString(m_state));
612 }
613}
614
621{
622 LOGDEBUG("device: %s: %d", __FUNCTION__, play_mode);
623
624 switch (play_mode) {
625 case pmNone:
627 break;
628 case pmAudioVideo:
629 case pmAudioOnly:
630 case pmAudioOnlyBlack:
631 case pmVideoOnly:
633 break;
634 default:
635 LOGERROR("device: %s: playmode not supported %d", play_mode);
636 return 0;
637 break;
638 }
639
640 return 1;
641}
642
648{
649 if (IsDetached())
650 return AV_NOPTS_VALUE;
651
652 switch (m_playbackMode) {
653 case NONE:
654 return AV_NOPTS_VALUE;
655 case AUDIO_AND_VIDEO:
656 case VIDEO_ONLY:
657 return m_pRender->GetVideoClock();
658 case AUDIO_ONLY:
660 }
661
662 abort();
663}
664
677void cSoftHdDevice::TrickSpeed(int speed, bool forward)
678{
679 LOGDEBUG("device: %s: %d %s", __FUNCTION__, speed, forward ? "forward" : "backward");
680
681 // This normalizes the VDR frame displaying count into a factor, representing how fast/slow the playback shall be.
682 // 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).
683 // This is necessary because VDR sends only I-frames during trickspeed, but the distance between I-frames depends on the encoding parameters.
684 // 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.
685
686 double normalizedSpeed = 1;
687 static constexpr double MAX_SPEED = 3;
688
689 // these are arbitrary values, which feel just right
690 static constexpr double FAST_TRICKSPEED_FACTOR = 5; // the higher the factor, the faster the fast forward/reverse
691 static constexpr double SLOW_FORWARD_FACTOR = 2; // the higher the factor, the slower the slow-mo
692
693 // Fastest speed in reverse slow-mo is the original speed. Slower speeds are too slow, because of the already low frame rate.
694 static constexpr double SLOW_REVERSE_FACTOR = 1;
695
696 // speed of the trickspeed (VDR's magic frame displaying count)
697 switch (speed) {
698 case 6:
699 case 8:
700 case 63:
701 normalizedSpeed = 1; // slowest (both, in fast trickspeed and slow-mo)
702 break;
703 case 3:
704 case 4:
705 case 48:
706 normalizedSpeed = 2;
707 break;
708 case 1:
709 case 2:
710 case 24:
711 normalizedSpeed = 3; // fastest (both, in fast trickspeed and slow-mo)
712 break;
713 }
714
715 // figure out if VDR demands slow-mo or fast trickspeed
716 double tmp;
717 switch (speed) {
718 case 8:
719 case 4:
720 case 2:
721 case 63:
722 case 48:
723 case 24:
724 // slow-mo
725 tmp = (MAX_SPEED + 1) - normalizedSpeed;
726
727 if (forward)
729 else
731
732 normalizedSpeed = 1 / tmp;
733 break;
734 default:
735 // fast trickspeed
737 break;
738 }
739
740 OnEventReceived(TrickSpeedEvent{normalizedSpeed, speed != 0, forward});
741}
742
751{
752 LOGDEBUG("device: %s:", __FUNCTION__);
753 cDevice::Clear();
754
755 if (IsDetached())
756 return;
757
758 m_pRender->Halt();
760
763
767
770
771 m_pRender->Reset();
772
773 m_pAudio->SetPaused(true);
774 FlushAudio();
775
777
778 m_pRender->Resume();
780}
781
788{
789 cDevice::Play();
790
792}
793
798{
799 LOGDEBUG("device: %s:", __FUNCTION__);
800 cDevice::Freeze();
801
803}
804
811void cSoftHdDevice::StillPicture(const uchar *data, int size)
812{
813 LOGDEBUG("device: %s: %s %p %d", __FUNCTION__, data[0] == 0x47 ? "ts" : "pes", data, size);
814
815 if (data[0] == 0x47) { // ts sync byte
816 cDevice::StillPicture(data, size);
817 return;
818 }
819
821}
822
830void cSoftHdDevice::HandleStillPicture(const uchar *data, int size)
831{
834
835 // skip BufferUnderrunEvent{VIDEO} in renderer
837
838 const uchar *currentPacketStart = data;
839 while (currentPacketStart < data + size) {
841
842 if (pesPacket.IsValid())
844 else {
845 LOGWARNING("device: %s: invalid PES packet", __FUNCTION__);
846 break;
847 }
848
849 currentPacketStart += pesPacket.GetPacketLength();
850 }
851
853 m_pVideoStream->ResetInputPts(); // stillpicture shouldn't trigger having video data
855}
856
870{
871// LOGDEBUG("device: %s: timeout %d", __FUNCTION__, timeout_ms);
872 if (IsDetached())
873 return true;
874
876 return true;
877
878 usleep(timeoutMs * 1000);
879
880 return false;
881}
882
889{
890 if (IsDetached())
891 return true;
892
893 LOGDEBUG("device: %s: timeout %d ms", __FUNCTION__, timeoutMs);
895 if (timeoutMs) { // let display thread work
896 usleep(timeoutMs * 1000);
897 }
899 }
900
901 return true;
902}
903
911{
912 LOGDEBUG("device: %s: %d", __FUNCTION__, videoDisplayFormat);
913
914 cDevice::SetVideoDisplayFormat(videoDisplayFormat);
915}
916
928{
929 LOGDEBUG("device: %s: %d", __FUNCTION__, videoFormat16_9);
930
931 // FIXME: 4:3 / 16:9 video format not supported.
932 SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
933}
934
947void cSoftHdDevice::GetVideoSize(int &width, int &height, double &aspectRatio)
948{
949// LOGDEBUG("device: %s: %d x %d @ %f", __FUNCTION__, *width, *height, *aspectRatio);
950
951 if (IsDetached()) { // return default values according to vdr docs
952 width = 0;
953 height = 0;
954 aspectRatio = 1.0;
955 return;
956 }
957
958 m_pVideoStream->GetVideoSize(&width, &height, &aspectRatio);
959}
960
970void cSoftHdDevice::GetOsdSize(int &width, int &height, double &aspectRatio)
971{
972 if (IsDetached()) { // hardcode to 1920x1080 in detached state
973 width = 1920;
974 height = 1080;
975 aspectRatio = (double)width / (double)height;
976 return;
977 }
978
979 std::lock_guard<std::mutex> lock(m_sizeMutex);
980 width = m_screenWidth;
981 height = m_screenHeight;
982 aspectRatio = (double)width / (double)height;
983}
984
992void cSoftHdDevice::SetScreenSize(int width, int height, double refreshRateHz)
993{
994 std::lock_guard<std::mutex> lock(m_sizeMutex);
995 m_screenWidth = width;
996 m_screenHeight = height;
998}
999
1006static void PrintStreamData(const uchar *payload)
1007{
1008 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",
1009 payload[0],
1010 payload[1],
1011 payload[2],
1012 payload[3],
1013 payload[4],
1014 payload[5],
1015 payload[6],
1016 payload[7],
1017 payload[8],
1018 payload[9],
1019 payload[10],
1020 payload[11],
1021 payload[12],
1022 payload[13],
1023 payload[14],
1024 payload[15],
1025 payload[16],
1026 payload[17],
1027 payload[18],
1028 payload[19],
1029 payload[20],
1030 payload[21],
1031 payload[22],
1032 payload[23],
1033 payload[24]
1034 );
1035}
1036
1050int cSoftHdDevice::PlayAudio(const uchar *data, int size, uchar id)
1051{
1052// LOGDEBUG("device: %s: %p %p %d %d", __FUNCTION__, this, data, size, id);
1053 if (IsDetached())
1054 return size;
1055
1056 if (!m_receivedAudio && Transferring()) {
1057 auto now = std::chrono::steady_clock::now();
1058 auto timeUntilFirstPacketReceived = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_channelSwitchStartTime).count();
1059 LOGDEBUG("device: first audio packet arrives %dms after channel switch was triggered", timeUntilFirstPacketReceived);
1060
1061 if (!m_receivedVideo)
1063 }
1064
1065 m_receivedAudio = true;
1066
1067 if (m_pAudio->IsBufferFull())
1068 return 0;
1069
1070 cPesAudio pesPacket((const uint8_t*)data, size);
1071
1072 if (!pesPacket.IsValid()) {
1074
1075 return size;
1076 }
1077
1078 if (Transferring()) { // compensation is only necessary with live streams
1083 }
1084
1085 if (m_audioChannelID != id) {
1089 LOGDEBUG("device: %s: new channel id 0x%02X", __FUNCTION__, m_audioChannelID);
1090 }
1091
1092 m_audioReassemblyBuffer.Push(pesPacket.GetPayload(), pesPacket.GetPayloadSize(), pesPacket.GetPts());
1093
1096
1097 AVPacket *avpkt;
1098 do {
1100
1101 if (avpkt) {
1103 // The playback has just started
1106 }
1107
1109 AVPacket *copy = avpkt;
1111 }
1112 } while (avpkt != nullptr);
1113
1114 return size;
1115}
1116
1118{
1119 //LOGDEBUG("device: %s:", __FUNCTION__);
1120}
1121
1123{
1124 //LOGDEBUG("device: %s: %s", __FUNCTION__, on ? "true" : "false");
1125}
1126
1128 int audio_channel)
1129{
1130 //LOGDEBUG("device: %s: %d", __FUNCTION__, audio_channel);
1131}
1132
1134{
1135 //LOGDEBUG("device: %s:", __FUNCTION__);
1136 return 0;
1137}
1138
1145{
1146 if (IsDetached())
1147 return;
1148
1149 LOGDEBUG("device: %s: %d", __FUNCTION__, volume);
1150 m_volume = volume;
1151 m_pAudio->SetVolume((volume * 1000) / 255);
1152}
1153
1168int cSoftHdDevice::PlayVideo(const uchar *data, int size)
1169{
1170// LOGDEBUG("device: %s: %p %d", __FUNCTION__, data, size);
1171 if (IsDetached())
1172 return size;
1173
1174 if (!m_receivedVideo && Transferring()) {
1175 auto now = std::chrono::steady_clock::now();
1176 auto timeUntilFirstPacketReceived = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_channelSwitchStartTime).count();
1177 LOGDEBUG("device: first video packet arrives %dms after channel switch was triggered", timeUntilFirstPacketReceived);
1178
1179 if (!m_receivedAudio)
1181 }
1182
1183 m_receivedVideo = true;
1184
1186}
1187
1198int cSoftHdDevice::PlayPipVideo(const uchar *data, int size)
1199{
1200// LOGDEBUG("device: %s: %p %d", __FUNCTION__, data, size);
1201
1202 // This is a bit hacky:
1203 // Because we do no sync with the pip stream, we simply drop data
1204 // if the input buffer is full -> this prevents us from having a buffer overflow
1205 // caused by the pip stream.
1207 return size;
1208
1209 return PlayVideoInternal(m_pPipStream, &m_pipReassemblyBuffer, data, size, false);
1210}
1211
1222{
1223 // LOGDEBUG("device: %s: %p %d", __FUNCTION__, data, size);
1224
1225 if (stream->IsInputBufferFull())
1226 return 0;
1227
1228 cPesVideo pesPacket((const uint8_t*)data, size);
1229
1230 if (!pesPacket.IsValid()) {
1231 buffer->Reset();
1232
1233 return size;
1234 }
1235
1236 if (trackJitter) {
1240 }
1241
1242 if (stream->GetCodecId() == AV_CODEC_ID_NONE) {
1243 // The playback has just started
1244 if (!pesPacket.HasPts() || !buffer->ParseCodecHeader(pesPacket.GetPayload(), pesPacket.GetPayloadSize())) {
1245 // received the middle of fragmented data, wait for the next PES packets with the start of a new frame
1246 return size;
1247 }
1248
1249 PrintStreamData(data);
1250 buffer->Push(pesPacket.GetPayload(), pesPacket.GetPayloadSize(), pesPacket.GetPts());
1251
1252 stream->Open(buffer->GetCodec());
1253 } else {
1254 int payloadOffset = 0;
1255 if (pesPacket.HasPts() && !buffer->IsEmpty()) {
1256 // received the first fragment of a new frame, finish the current reassembly buffer into an AVPacket
1257 stream->PushAvPacket(buffer->PopAvPacket());
1258
1259 // populate the cleared buffer with the next frame
1260 if (buffer->HasLeadingZero(pesPacket.GetPayload(), pesPacket.GetPayloadSize()))
1261 payloadOffset = 1; // H.264/HEVC streams may have a leading zero byte before the start code
1262 }
1263
1264 buffer->Push(pesPacket.GetPayload() + payloadOffset, pesPacket.GetPayloadSize() - payloadOffset, pesPacket.GetPts());
1265 }
1266
1267 return size;
1268}
1269
1277
1305{
1306 if (m_state != BUFFERING)
1307 return false;
1308
1312
1313 // 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.
1314 // Check for buffer fill level only if at least one PES packet was reassembled and pushed to the respective decoder.
1317
1319 LOGDEBUG("device: %s: Detected audio only", __FUNCTION__);
1320 return true;
1322 LOGDEBUG("device: %s: Detected video only", __FUNCTION__);
1323 return true;
1325 return false; // Either no video or no audio received, yet. Or, video didn't make it to the output buffer, yet.
1326
1329
1330 bool reached = m_pRender->IsOutputBufferFull() && // video decoder output buffer (audio hardware output buffer is negligible)
1331 syncedVideoBufferFillLevelMs > GetBufferFillLevelThresholdMs() && // video decoder input buffer
1332 syncedAudioBufferFillLevelMs > GetBufferFillLevelThresholdMs(); // audio decoder output buffer
1333
1334 if (reached) {
1335 LOGDEBUG2(L_AV_SYNC, "First received PTS: %s (audio), %s (video) buffer fill levels: %ldms (audio) %ldms (video)",
1340 }
1341
1342 return reached;
1343}
1344
1366
1379
1389uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int width, int height)
1390{
1391 if (IsDetached())
1392 return NULL;
1393
1394 if (m_pGrab->Active()) {
1395 LOGWARNING("device: %s: wait for the last grab to be finished - skip!", __FUNCTION__);
1396 return NULL;
1397 }
1398
1399 LOGDEBUG2(L_GRAB, "device: %s: %d, %d, %d, %dx%d", __FUNCTION__, size, jpeg, quality, width, height);
1400
1401 int screenWidth = 0;
1402 int screenHeight = 0;
1403 double aspectRatio = 0.0f;
1405
1406 if (!m_pGrab->Start(jpeg, quality, width, height, screenWidth, screenHeight))
1407 return NULL;
1408
1409 size = m_pGrab->Size();
1410
1411 return m_pGrab->Image();
1412}
1413
1425
1435{
1436 if (IsDetached())
1437 return;
1438
1439 LOGDEBUG2(L_OSD, "device: %s: %dx%d%+d%+d",
1440 __FUNCTION__, rect.Width(), rect.Height(), rect.X(), rect.Y());
1441
1442 if (m_pRender)
1444}
1445
1450{
1451 return " -a device\taudio device (fe. alsa: hw:0,0)\n"
1452 " -p device\taudio device for pass-through (hw:0,1)\n"
1453 " -c channel\taudio mixer channel name (fe. PCM)\n"
1454 " -d resolution\tdisplay resolution (fe. 1920x1080@50)\n"
1455 " -D start in detached state\n"
1456 " -w workaround\tenable/disable workarounds\n"
1457#ifdef USE_GLES
1458 "\tdisable-ogl-osd disable openGL osd\n"
1459#endif
1460 "\tdisable-pip disable picture-in-picture\n"
1461 "\n";
1462}
1463
1471{
1472 //
1473 // Parse arguments.
1474 //
1475
1476 for (;;) {
1477#ifdef USE_GLES
1478 switch (getopt(argc, argv, "-a:c:p:d:Dw:")) {
1479#else
1480 switch (getopt(argc, argv, "-a:c:p:d:D")) {
1481#endif
1482 case 'a': // audio device for pcm
1484 continue;
1485 case 'c': // channel of audio mixer
1487 continue;
1488 case 'p': // pass-through audio device
1490 continue;
1491 case 'd': // set display output
1493 continue;
1494 case 'D': // start plugin in detached state
1495 m_forceDetached = true;
1496 continue;
1497 case 'w': // workarounds
1498 if (!strcasecmp("disable-pip", optarg)) {
1499 m_disablePip = true;
1500#ifdef USE_GLES
1501 } else if (!strcasecmp("disable-ogl-osd", optarg)) {
1503#endif
1504 } else {
1505 fprintf(stderr, gettext("Workaround '%s' unsupported\n"),
1506 optarg);
1507 return 0;
1508 }
1509 continue;
1510 case EOF:
1511 break;
1512 case '-':
1513 fprintf(stderr, gettext("We need no long options\n"));
1514 return 0;
1515 case ':':
1516 fprintf(stderr, gettext("Missing argument for option '%c'\n"), optopt);
1517 return 0;
1518 default:
1519 fprintf(stderr, gettext("Unknown option '%c'\n"), optopt);
1520 return 0;
1521 }
1522 break;
1523 }
1524
1525 while (optind < argc) {
1526 fprintf(stderr, gettext("Unhandled argument '%s'\n"), argv[optind++]);
1527 }
1528
1529 return 1;
1530}
1531
1536{
1537 if (IsDetached())
1538 return;
1539
1541}
1542
1555void cSoftHdDevice::OsdDrawARGB(int xi, int yi, int height, int width, int pitch,
1556 const uint8_t * argb, int x, int y)
1557{
1558 if (IsDetached())
1559 return;
1560
1561 m_pRender->OsdDrawARGB(xi, yi, height, width, pitch, argb, x, y);
1562}
1563
1564#ifdef USE_GLES
1572
1580
1590
1600
1601#endif
1602
1611
1620
1629
1644
1654
1659{
1660 LOGDEBUG("%s:", __FUNCTION__);
1661 m_audioChannelID = -1;
1662}
1663
1672{
1673 *duped = 0;
1674 *dropped = 0;
1675 *counter = 0;
1676 if (m_pRender) {
1678 }
1679}
1680
1681/*****************************************************************************
1682 * media player functions
1683 ****************************************************************************/
1684
1696
1708
1718{
1719 m_pAudio->LazyInit();
1720
1721 if (m_pAudio->IsBufferFull())
1722 return 0;
1723
1725 return 1;
1726}
1727
1737{
1738 m_pAudio->LazyInit();
1739
1741 return 0;
1742
1744
1745 return 1;
1746}
1747
1748/*****************************************************************************
1749 * Detach and attach functionality
1750 ****************************************************************************/
1751
1759{
1760 if (cDevice::Replaying()) {
1761 LOGDEBUG("device: %s: Device is replaying, stop replay first", __FUNCTION__);
1762 StopReplay();
1763 }
1764
1765 if (IsPrimaryDevice(false)) {
1766 m_needsMakePrimary = true;
1767 MakePrimaryDevice(false);
1768 }
1769
1771}
1772
1780{
1781 m_forceDetached = false;
1782
1783 if (m_needsMakePrimary) {
1784 MakePrimaryDevice(true);
1785 m_needsMakePrimary = false;
1786 }
1787
1789}
1790
1795{
1796 std::lock_guard<std::mutex> lock(m_mutex);
1797 return m_state == State::DETACHED;
1798}
1799
1800/*****************************************************************************
1801 * PiP functionality
1802 ****************************************************************************/
1803
1821
1826{
1827 std::lock_guard<std::mutex> lock(m_mutex);
1828 return m_pPipHandler->IsEnabled();
1829}
1830
1843
1846
Audio and Alsa Interface Header File.
Audio Decoder.
Definition codec_audio.h:81
AVCodecID GetCodecId() const
Definition codec_audio.h:90
int GetShortTermMaxJitterMs(void)
int GetLongTermMaxJitterMs(void)
Main Video Stream.
Audio PES Packet Parser.
Definition pes.h:77
Video PES Packet Parser.
Definition pes.h:64
PiP Stream Handler.
Definition pipreceiver.h:51
bool IsEnabled(void)
Definition pipreceiver.h:56
PiP Video Stream.
Video Stream Reassembly Buffer.
Definition pes.h:137
AVPacket * PopAvPacket(void) override
Definition pes.h:140
AVCodecID GetCodec(void)
Definition pes.h:122
virtual void Push(const uint8_t *data, int size, int64_t pts)
Definition pes.h:117
bool IsEmpty(void)
Definition pes.h:119
Audio Interface.
Definition audio.h:46
int64_t GetInputPtsMs(void)
Definition audio.h:66
bool HasInputPts(void)
Definition audio.h:65
bool IsBufferFull(void)
Definition audio.h:57
Plugin Configuration.
Definition config.h:29
bool ConfigParseH264Dimensions
parse h264 stream for width and height for decoder init
Definition config.h:63
int ConfigVideoAudioDelayMs
config audio delay
Definition config.h:43
const char * ConfigDisplayResolution
display resolution (syntax: "1920x1080@50")
Definition config.h:84
std::atomic< int > StatMaxLongTermAudioJitterMs
logged max overall audio jitter since stream start
Definition config.h:91
int ConfigMaxSizeGPUImageCache
config max gpu image cache size
Definition config.h:37
std::atomic< int > StatMaxShortTermAudioJitterMs
logged max audio jitter of the last 1000 packets
Definition config.h:90
int ConfigDecoderFallbackToSwNumPkts
maximum number of packets sent before fallback to sw decoder
Definition config.h:65
const char * ConfigAudioPCMDevice
audio PCM device
Definition config.h:81
bool ConfigDisableDeint
disable deinterlacer
Definition config.h:61
int ConfigDisableOglOsd
config disable ogl osd
Definition config.h:38
int ConfigAdditionalBufferLengthMs
config size ms of a/v buffer
Definition config.h:42
const char * ConfigAudioMixerChannel
audio mixer channel name
Definition config.h:83
std::atomic< int > StatMaxShortTermVideoJitterMs
logged max video jitter of the last 1000 packets
Definition config.h:92
bool ConfigDecoderNeedsIFrame
start h264 decoder only when an I-Frame arrives
Definition config.h:62
std::atomic< int > StatMaxLongTermVideoJitterMs
logged max overall video jitter since stream start
Definition config.h:93
const char * ConfigAudioPassthroughDevice
audio passthrough device
Definition config.h:82
cReassemblyBufferVideo m_videoReassemblyBuffer
video pes reassembly buffer
bool m_pipUseAlt
use alternative pip position
cReassemblyBufferVideo m_pipReassemblyBuffer
pip pes reassembly buffer
cVideoStream * m_pPipStream
pointer to pip video stream
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)
cSoftOsdProvider * m_pOsdProvider
pointer to cSoftOsdProvider object
cVideoStream * m_pVideoStream
pointer to main video stream
cReassemblyBufferAudio m_audioReassemblyBuffer
audio pes reassembly buffer
std::atomic< bool > m_receivedAudio
flag if audio packets have been received
cDvbSpuDecoder * m_pSpuDecoder
pointer to spu decoder
std::mutex m_mutex
mutex to lock the state machine
cPipHandler * m_pPipHandler
pointer to pip handler
double m_screenRefreshRateHz
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
cAudioDecoder * m_pAudioDecoder
pointer to cAudioDecoder object
cVideoRender * m_pRender
pointer to cVideoRender object
cSoftHdGrab * m_pGrab
pointer to grabber object
bool m_needsMakePrimary
cSoftHdAudio * m_pAudio
pointer to cSoftHdAudio object
cSoftHdConfig * m_pConfig
pointer to cSoftHdConfig object
bool m_disablePip
true, if pip was disabled by the user
std::chrono::steady_clock::time_point m_channelSwitchStartTime
timestamp, when VDR triggered a channel switch
std::mutex m_sizeMutex
mutex to lock screen size (which is accessed by different threads)
std::atomic< bool > m_receivedVideo
flag if video packets have been received
cJitterTracker m_audioJitterTracker
audio jitter tracker
bool m_forceDetached
start the plugin in detached state
int m_audioChannelID
current audio channel ID
cJitterTracker m_videoJitterTracker
video jitter tracker
std::atomic< PlaybackMode > m_playbackMode
current playback mode
Grabbing Processor.
Definition grab.h:79
uint8_t * Image(void)
Definition grab.h:85
bool Active(void)
Definition grab.h:83
int Size(void)
Definition grab.h:86
Plugin OSD provider.
Video Renderer.
void SetEnableHdr(bool enable)
void ResetBufferReuseStrategy()
void Halt(void)
void ScheduleVideoPlaybackPauseAt(int64_t ptsMs)
void ScheduleResyncAtPtsMs(int64_t ptsMs)
void ResetDecodingStrategy()
void EnableOglOsd(void)
void ResetPipBufferReuseStrategy()
void SetPipActive(bool on)
cQueue< cDrmBuffer > * GetPipOutputBuffer(void)
void Resume(void)
void SetStillpicture(bool active)
void SchedulePlaybackStartAtPtsMs(int64_t ptsMs)
int64_t GetVideoClock(void)
void SetScheduleAudioResume(bool resume)
void SetDisplayOneFrameThenPause(bool pause)
void DisableOglOsd(void)
void SetPlaybackPaused(bool pause)
void ResetPipDecodingStrategy()
cQueue< cDrmBuffer > * GetMainOutputBuffer(void)
Video Input Stream.
Definition videostream.h:57
void SetDecoderFallbackToSwNumPkts(int numPackets)
void ResetInputPts(void)
Definition videostream.h:87
void Resume(void)
Definition videostream.h:75
int GetVideoPacketMax(void)
Definition videostream.h:89
void SetStartDecodingWithIFrame(bool enable)
Definition videostream.h:99
size_t GetAvPacketsFilled(void)
Definition videostream.h:80
void DisableDeint(bool disable)
Definition videostream.h:98
bool IsInputBufferFull(void)
Definition videostream.h:81
void ResetFilterThreadNeededCheck()
Definition videostream.h:93
void SetParseH264Dimensions(bool enable)
void Halt(void)
Definition videostream.h:74
virtual void SetDeinterlacerDeactivated(bool deactivate)
Definition videostream.h:95
void ResetTrickSpeedFramesSentCounter(void)
Definition videostream.h:83
bool HasInputPts(void)
Definition videostream.h:84
Audio Decoder Header File.
Plugin Configuration Header File.
State Machine and Event Header File.
@ PIPSTOP
Definition event.h:32
std::variant< PlayEvent, PauseEvent, StopEvent, TrickSpeedEvent, StillPictureEvent, DetachEvent, AttachEvent, BufferUnderrunEvent, BufferingThresholdReachedEvent, PipEvent, ScheduleResyncAtPtsMsEvent, ResyncEvent > Event
Definition event.h:80
Grabbing Interface Header File.
void LazyInit(void)
Initialize audio output module (alsa)
Definition audio.cpp:1075
void ResetHwDelayBaseline(void)
Reset the hw delay baseline.
Definition audio.cpp:1412
void SetPassthroughMask(int)
Set audio passthrough mask.
Definition audio.cpp:1056
void SetHwDelayBaseline(void)
Set the hw delay baseline.
Definition audio.cpp:1392
int64_t GetHardwareOutputPtsTimebaseUnits(void)
Get the hardware output PTS in timebase units.
Definition audio.cpp:964
void SetVolume(int)
Set mixer volume (0-1000)
Definition audio.cpp:978
void DropSamplesOlderThanPtsMs(int64_t)
Drop samples older than the given PTS.
Definition audio.cpp:576
int64_t GetOutputPtsMs(void)
Get the output PTS of the ringbuffer.
Definition audio.cpp:902
void ClockDriftCompensation(void)
Calculate clock drift compensation.
Definition audio.cpp:1837
void Exit(void)
Cleanup audio output module (alsa)
Definition audio.cpp:1090
void SetPaused(bool)
Set audio playback pause state.
Definition audio.cpp:1001
void FlushBuffers(void)
Flush audio buffers.
Definition audio.cpp:861
void FlushBuffers(void)
Flush the audio decoder buffers.
void Decode(const AVPacket *)
Decode an audio packet.
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.
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.
void Stop(void)
Called by VDR when the plugin is stopped.
void PipChannelSwap(bool)
void FlushAudio(void)
Clear all audio data from the decoder and ringbuffer.
void PipSwapPosition(void)
virtual void StillPicture(const uchar *, int)
Display the given I-frame as a still picture.
void PipSetSize(void)
int MaxSizeGPUImageCache(void)
Get the maximum GPU image cache size.
void SetRenderPipSize(void)
Wrapper functions for cVideoRender and cPipHandler.
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.
const char * EventToString(const Event &e)
int PlayAudioPkts(AVPacket *)
Play an audio packet.
virtual void GetOsdSize(int &, int &, double &)
Returns the width, height and aspect ratio the OSD.
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)
virtual bool CanReplay(void) const
Return true if this device can currently start a replay session.
virtual void SetDigitalAudioDevice(bool)
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.
void OnEventReceived(const Event &)
Event handler for playback state transitions.
void Detach(void)
Detach the device.
State
virtual int PlayVideo(const uchar *, int)
Play a video packet of the main videostream.
void ResetPipStream(void)
Resets pip stream and render pipeline.
void OnLeavingState(State)
Actions to be performed when leaving a state.
virtual bool SetPlayMode(ePlayMode)
Sets the device into the given play mode.
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.
virtual void SetAudioChannelDevice(int)
const char * CommandLineHelp(void)
Return command line help string.
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.
virtual void ChannelSwitch(const cDevice *, int, bool)
Monitor a channel switch triggered by VDR (cStatus::ChannelSwitch())
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.
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.
void SetDecoderNeedsIFrame(void)
Forces the h264 decoder to wait for an I-Frame to start.
int PlayVideoInternal(cVideoStream *, cReassemblyBufferVideo *, const uchar *, int, bool)
Play a video packet.
virtual int GetAudioChannelDevice(void)
int PlayVideoPkts(AVPacket *)
Play a video packet.
void SetScreenSize(int, int, double)
Set the screen size.
const char * StateToString(State s)
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.
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)
virtual ~cSoftHdDevice(void)
Destroy the device.
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.
virtual void SetAudioTrackDevice(eTrackType)
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()
int ProcessArgs(int, char *[])
Process the command line arguments.
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.
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
__attribute__((weak)) union gbm_bo_handle gbm_bo_get_handle_for_plane(struct gbm_bo *bo
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:42
#define LOGDEBUG
log to LOG_DEBUG
Definition logger.h:40
#define LOGERROR
log to LOG_ERR
Definition logger.h:34
#define AV_NOPTS_VALUE
Definition misc.h:74
void Reset(void)
Reset the reassembly buffer.
Definition pes.cpp:624
bool Start(bool, int, int, int, int, int)
Start a grab in the video renderer.
Definition grab.cpp:329
bool HasLeadingZero(const uint8_t *, int)
Check if video data has a leading zero byte before the start code.
Definition pes.cpp:438
#define LOGWARNING
log to LOG_WARN
Definition logger.h:36
void PacketReceived(void)
Called each time a packet is received.
void Reset(void)
Resets the jitter tracker.
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:32
AVPacket * PopAvPacket(void) override
Pop an audio AVPacket from the reassembly buffer.
Definition pes.cpp:455
bool ParseCodecHeader(const uint8_t *, int)
Parse video codec header to detect codec type.
Definition pes.cpp:404
static const char * Timestamp2String(int64_t ts, uint8_t divisor)
Nice time-stamp string.
Definition misc.h:127
@ L_AV_SYNC
audio/video sync logs
Definition logger.h:52
@ L_OSD
osd logs
Definition logger.h:54
@ L_CODEC
codec logs
Definition logger.h:56
@ L_GRAB
grabbing logs
Definition logger.h:64
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.
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 HandleEvent(enum PipState)
Handle a pip event.
void Disable(void)
Stop picture-in-picture.
void ChannelSwap(bool)
Swap the pip channel with main live channel.
void Enable(void)
Start picture-in-picture.
void SetSize(void)
Set size and position for the pip window.
void PushPipFrame(AVFrame *)
Push a PiP frame into the render ringbuffer.
bool IsOutputBufferFull(void)
Check, if the main render output buffer is full.
void Reset()
Reset the renderer.
void OsdClear(void)
Clear the OSD (draw an empty/ transparent OSD)
void ClearDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
void Init(void)
Initialize the renderer.
void Exit(void)
Exit and cleanup the renderer.
void GetStats(int *, int *, int *)
Get some rendering statistics.
void DisplayBlackFrame(void)
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 ClearPipDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD ARGB image.
void SetPipSize(bool)
Set the size and position of the pip window.
void ResetFrameCounter(void)
Send start condition to video thread.
void SetTrickSpeed(double, bool, bool)
Set the trickspeed parameters.
void GetVideoSize(int *, int *, double *)
Get video size and aspect ratio.
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 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.
int64_t GetInputPtsMs(void)
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.
Video Renderer (Display) Header File.
Video Input Stream Header File.