vdr-plugin-drmdevice 2.0.0-46418f1
device.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 "device.h"
36#include "grab.h"
37#include "hardwaredevice.h"
38#include "jittertracker.h"
39#include "logger.h"
40#include "osdprovider.h"
41#include "pes.h"
42#include "pip.h"
43#include "statemachine.h"
44#include "videorender.h"
45#include "videostream.h"
46
55 : m_pConfig(config)
56{
57 m_pStateMachine = std::make_unique<cStateMachine>(this);
58}
59
66{
67 if (!m_initialized)
68 return;
69
70 m_initialized = false; // not necessary, just for documentation
71
72 delete m_pEventHandler;
73 delete m_pHardwareDevice;
74 delete m_pSpuDecoder;
75}
76
77/*********************************************************************
78 * VDR cPlugin interface (wrapped by cPluginDrmDevice)
79 ********************************************************************/
80
85{
86 LOGDEBUG("device: %s:", __FUNCTION__);
87
88 // the following are deleted in the destructor
92
93 auto channelSwitchStartTime = std::chrono::steady_clock::now();
94 LOGGER->SetChannelSwitchStartTime(channelSwitchStartTime);
95 LOGGER->SetChannelSwitchDataReceivedTime(channelSwitchStartTime);
96
99
100 m_initialized = true;
101
102 return true;
103}
104
109{
110 LOGDEBUG("device: %s", __FUNCTION__);
112
113 return true;
114}
115
120{
121 LOGDEBUG("device: %s", __FUNCTION__);
124}
125
126/*********************************************************************
127 * VDR cDevice interface
128 ********************************************************************/
129
136{
137 LOGDEBUG("device: %s: %d", __FUNCTION__, on);
138
139 if (on)
140 m_pOsdProvider = new cDeviceOsdProvider(this); // no need to delete it, VDR does it
141
142 cDevice::MakePrimaryDevice(on);
143}
144
149{
150 bool hasDecoder = !IsDetached();
151
152// LOGDEBUG("device: %s: %d", __FUNCTION__, hasDecoder);
153
154 return hasDecoder;
155}
156
164{
165 LOGDEBUG("device: %s:", __FUNCTION__);
166 if (!IsPrimaryDevice())
167 return NULL;
168
169 return m_pSpuDecoder;
170}
171
181uchar *cOutputDevice::GrabImage(int &size, bool jpeg, int quality, int width, int height)
182{
183 if (!width || !height) {
184 LOGWARNING("device: %s: width or height is 0 - skip!", __FUNCTION__);
185 return nullptr;
186 }
187
188 if (IsDetached())
189 return nullptr;
190
191 if (m_pGrab->IsActive()) {
192 LOGWARNING("device: %s: wait for the last grab to be finished - skip!", __FUNCTION__);
193 return nullptr;
194 }
195
196 LOGDEBUG2(L_GRAB, "device: %s: %d, %d, %d, %dx%d", __FUNCTION__, size, jpeg, quality, width, height);
197
198 if (!m_pGrab->Start(jpeg, quality, width, height, m_screenWidth, m_screenHeight))
199 return nullptr;
200
201 if (!m_pGrab->ProcessGrab())
202 return nullptr;
203
204 size = m_pGrab->Size();
206
207 m_pGrab->Finish();
208
209 return result;
210}
211
219{
220 LOGDEBUG("device: %s: %d", __FUNCTION__, videoDisplayFormat);
221
222 cDevice::SetVideoDisplayFormat(videoDisplayFormat);
223}
224
236{
237 LOGDEBUG("device: %s: %d", __FUNCTION__, videoFormat16_9);
238
239 // FIXME: 4:3 / 16:9 video format not supported.
240 SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
241}
242
255void cOutputDevice::GetVideoSize(int &width, int &height, double &aspectRatio)
256{
257// LOGDEBUG("device: %s: %d x %d @ %f", __FUNCTION__, *width, *height, *aspectRatio);
258
259 if (IsDetached()) { // return default values according to vdr docs
260 width = 0;
261 height = 0;
262 aspectRatio = 1.0;
263 return;
264 }
265
266 m_pVideoStream->GetVideoSize(&width, &height, &aspectRatio);
267}
268
278void cOutputDevice::GetOsdSize(int &width, int &height, double &aspectRatio)
279{
280 if (IsDetached()) { // hardcode to 1920x1080 in detached state
281 width = 1920;
282 height = 1080;
283 aspectRatio = (double)width / (double)height;
284 return;
285 }
286
287 std::lock_guard<std::mutex> lock(m_sizeMutex);
288 width = m_osdWidth;
289 height = m_osdHeight;
290 aspectRatio = (double)width / (double)height;
291}
292
299{
300 if (IsDetached())
301 return;
302
303 LOGDEBUG("device: %s: %d", __FUNCTION__, volume);
305 m_pAudio->SetVolume((volume * 1000) / 255);
306}
307
312{
313 bool canReplay = !IsDetached();
314
315 LOGDEBUG("device: %s: %d", __FUNCTION__, canReplay);
316
317 return canReplay;
318}
319
326{
327 LOGDEBUG("device: %s: %d", __FUNCTION__, play_mode);
328
329 // A new play mode arrived, attach first if we did detach because of an external player
333 }
334
335 auto now = std::chrono::steady_clock::now();
336 auto durationSinceChannelSwitchMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - LOGGER->GetChannelSwitchStartTime()).count();
337
338 SetDrain(false);
339
340 switch (play_mode) {
341 case pmNone:
343 break;
344 case pmAudioVideo:
345 case pmAudioOnly:
346 case pmAudioOnlyBlack:
347 case pmVideoOnly:
348 m_logPlaybackStart = true;
349 LOGDEBUG2(L_AV_SYNC, "TRACE: +%5dms SetPlayMode()", durationSinceChannelSwitchMs);
351 break;
353 // External players like mpv (vdr-plugin-mpv) want to acquire DRM/ALSA
354 // so we release it here and set a flag. As soon as the next SetPlayMode arrives
355 // we then can attach again before changing to the new playmode.
359 break;
360 default:
361 LOGERROR("device: %s: playmode not supported %d", play_mode);
362 return false;
363 break;
364 }
365
366 return true;
367}
368
382int cOutputDevice::PlayAudio(const uchar *data, int size, uchar id)
383{
384// LOGDEBUG("device: %s: %p %p %d %d", __FUNCTION__, this, data, size, id);
385 if (IsDetached())
386 return size;
387
388 m_receivedAudio = true;
389
390 // Special audio-only trickspeed handling:
391 // Advance the pts and block the thread depending on the pts difference and trickspeed factor.
392 // Don't forward any data to the hardware, because audio is muted anyway.
395 cPesAudio pesPacket((const uint8_t*)data, size);
396 if (pesPacket.IsValid() && pesPacket.GetPts() != AV_NOPTS_VALUE)
398
399 return size;
400 }
401
402 if (m_pAudio->IsBufferFull())
403 return 0;
404
405 cPesAudio pesPacket((const uint8_t*)data, size);
406
407 if (!pesPacket.IsValid()) {
409
410 return size;
411 }
412
414 auto now = std::chrono::steady_clock::now();
415 auto durationSinceChannelSwitchMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - LOGGER->GetChannelSwitchStartTime()).count();
416 LOGDEBUG2(L_AV_SYNC, "TRACE: +%5dms PlayAudio() first valid audio data", durationSinceChannelSwitchMs);
417
419 LOGGER->SetChannelSwitchDataReceivedTime(now);
420
422 }
423
424 if (Transferring()) { // compensation is only necessary with live streams
429 }
430
431 if (m_audioChannelID != id) {
435 LOGDEBUG("device: %s: new channel id 0x%02X", __FUNCTION__, m_audioChannelID);
436 }
437
438 m_audioReassemblyBuffer.Push(pesPacket.GetPayload(), pesPacket.GetPayloadSize(), pesPacket.GetPts());
439
440 // fire playback start, if all buffers reached the threshold fill levels
443
444 // unpause audio, if the fast channel switch mode wants it to be started,
445 // the audio buffer reached the threshold and we are in live tv mode
447 m_pAudio->SetPaused(false);
448
450 do {
452 break;
453
455 // The playback has just started
458 }
459
463 } while (avpkt != nullptr);
464
465 return size;
466}
467
482int cOutputDevice::PlayVideo(const uchar *data, int size)
483{
484// LOGDEBUG("device: %s: %p %d", __FUNCTION__, data, size);
485 if (IsDetached())
486 return size;
487
488 m_receivedVideo = true;
489
491}
492
498{
499 if (IsDetached())
500 return AV_NOPTS_VALUE;
501
502 switch (m_playbackMode) {
503 case NONE:
504 return AV_NOPTS_VALUE;
505 case AUDIO_AND_VIDEO:
506 case VIDEO_ONLY:
507 return m_pRender->GetVideoClock();
508 case AUDIO_ONLY:
510 if (m_pStateMachine->GetState() == State::TRICK_SPEED && !slowForward)
512
514 }
515
516 abort();
517}
518
527{
529 return rect;
530
531 double scaleFactor = std::min((double)m_screenWidth / m_osdWidth, (double)m_screenHeight / m_osdHeight);
532 int width = std::lround(scaleFactor * rect.Width());
533 int height = std::lround(scaleFactor * rect.Height());
534 int x = std::lround(scaleFactor * rect.X());
535 int y = std::lround(scaleFactor * rect.Y());
536
537 x = std::max(0, x);
538 y = std::max(0, y);
539 if (x + width > m_screenWidth)
540 width = m_screenWidth - x;
541 if (y + height > m_screenHeight)
542 height = m_screenHeight - y;
543
544 if (width <= 0 || height <= 0)
545 return cRect::Null;
546
547 LOGDEBUG2(L_DRM, "device: %s: scale rect %dx%d-%d|%d -> %dx%d-%d|%d", __FUNCTION__,
548 rect.Width(), rect.Height(), rect.X(), rect.Y(), width, height, x, y);
549
550 return cRect(x, y, width, height);
551}
552
562{
563 if (IsDetached())
564 return;
565
566 LOGDEBUG2(L_OSD, "device: %s: %dx%d%+d%+d",
567 __FUNCTION__, rect.Width(), rect.Height(), rect.X(), rect.Y());
568
569 if (m_pRender)
571}
572
585void cOutputDevice::TrickSpeed(int speed, bool forward)
586{
587 LOGDEBUG("device: %s: %d %s", __FUNCTION__, speed, forward ? "forward" : "backward");
588
589 // This normalizes the VDR frame displaying count into a factor, representing how fast/slow the playback shall be.
590 // 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).
591 // This is necessary because VDR sends only I-frames during trickspeed, but the distance between I-frames depends on the encoding parameters.
592 // 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.
593
594 double normalizedSpeed = 1;
595 static constexpr double MAX_SPEED = 3;
596
597 // these are arbitrary values, which feel just right
598 static constexpr double FAST_TRICKSPEED_FACTOR = 5; // the higher the factor, the faster the fast forward/reverse
599 static constexpr double SLOW_FORWARD_FACTOR = 2; // the higher the factor, the slower the slow-mo
600
601 // Fastest speed in reverse slow-mo is the original speed. Slower speeds are too slow, because of the already low frame rate.
602 static constexpr double SLOW_REVERSE_FACTOR = 1;
603
604 // speed of the trickspeed (VDR's magic frame displaying count)
605 switch (speed) {
606 case 6:
607 case 8:
608 case 63:
609 normalizedSpeed = 1; // slowest (both, in fast trickspeed and slow-mo)
610 break;
611 case 3:
612 case 4:
613 case 48:
614 normalizedSpeed = 2;
615 break;
616 case 1:
617 case 2:
618 case 24:
619 normalizedSpeed = 3; // fastest (both, in fast trickspeed and slow-mo)
620 break;
621 }
622
623 // figure out if VDR demands slow-mo or fast trickspeed
624 double tmp;
625 switch (speed) {
626 case 8:
627 case 4:
628 case 2:
629 case 63:
630 case 48:
631 case 24:
632 // slow-mo
633 tmp = (MAX_SPEED + 1) - normalizedSpeed;
634
635 if (forward)
637 else
639
640 normalizedSpeed = 1 / tmp;
641 break;
642 default:
643 // fast trickspeed
645 break;
646 }
647
648 TriggerEvent(TrickSpeedEvent{normalizedSpeed, speed != 0, forward});
649}
650
659{
660 LOGDEBUG("device: %s:", __FUNCTION__);
661 cDevice::Clear();
662
663 if (IsDetached())
664 return;
665
666 m_pRender->Halt();
668
669 SetDrain(false);
670
673
677
680
681 m_pRender->Reset();
682
683 m_pAudio->SetPaused(true);
685 FlushAudio();
686
687 m_pStateMachine->ChangeState(BUFFERING);
688
689 m_pRender->Resume();
691}
692
699{
700 LOGDEBUG("device: %s:", __FUNCTION__);
701 cDevice::Play();
702
704}
705
710{
711 LOGDEBUG("device: %s:", __FUNCTION__);
712 cDevice::Freeze();
713
715}
716
723void cOutputDevice::StillPicture(const uchar *data, int size)
724{
725 LOGDEBUG("device: %s: %s %p %d", __FUNCTION__, data[0] == 0x47 ? "ts" : "pes", data, size);
726
727 if (data[0] == 0x47) { // ts sync byte
728 cDevice::StillPicture(data, size);
729 return;
730 }
731
732 TriggerEvent(StillPictureEvent{data, size});
733}
734
748{
749// LOGDEBUG("device: %s: timeout %d", __FUNCTION__, timeout_ms);
750 if (IsDetached())
751 return true;
752
754 return true;
755
756 usleep(timeoutMs * 1000);
757
758 return false;
759}
760
777{
778 if (IsDetached())
779 return true;
780
781// LOGDEBUG("device: %s: timeout %d ms", __FUNCTION__, timeoutMs);
782
783 const auto buffersEmpty = [&]() {
784 return m_playbackMode == AUDIO_ONLY
787 };
788
790 while (!buffersEmpty() && !timeout.TimedOut())
791 cCondWait::SleepMs(std::min(5, timeoutMs));
792
793 return buffersEmpty();
794}
795
796#if APIVERSNUM >= 30014
802bool cOutputDevice::DrainDevice(void)
803{
804 if (IsDetached())
805 return true;
806
807 // enter drain mode once
808 if (!m_draining) {
811
812 if (!m_pVideoStream->Drain())
813 return false;
814
815 SetDrain(true);
816 }
817
818 const auto buffersEmpty = [&]() {
819 return m_playbackMode == AUDIO_ONLY
822 };
823
824 if (!buffersEmpty())
825 return false;
826
827 LOGDEBUG("device: %s: drained, buffers are empty", __FUNCTION__);
828 SetDrain(false);
829
830 return true;
831}
832#endif
833
834/*********************************************************************
835 * VDR cStatus interface
836 ********************************************************************/
837
844void cOutputDevice::ChannelSwitch(const cDevice *device, int channelNum, bool liveView)
845{
846 if (device != cDevice::PrimaryDevice() || !liveView || channelNum != 0)
847 return;
848
849 auto now = std::chrono::steady_clock::now();
850 LOGGER->SetChannelSwitchStartTime(now);
851 LOGDEBUG2(L_AV_SYNC, "TRACE: channel switch");
852}
853
860 [[maybe_unused]]const char *name,
861 [[maybe_unused]]const char *filenameDevice,
862 bool on)
863{
864 if (!on)
865 return;
866
867 auto now = std::chrono::steady_clock::now();
868 LOGGER->SetChannelSwitchStartTime(now);
869 LOGDEBUG2(L_AV_SYNC, "TRACE: replay start");
870}
871
872/*********************************************************************
873 * cOutputDevice public API - playback, display, decoder control
874 ********************************************************************/
875
884
885
900
908
915{
917
921 if (!mode->width || !m_pRender->CanHandleMode(mode))
923 } else if (idx >= CONFIG_DISPLAY_MODE_MANUAL)
925
926 // Check, if the requested mode differs from the current one at all
927 if (!m_pConfig->CompareCurrentMode(mode)) {
928 LOGDEBUG("Add display mode change event to %s mode %dx%d@%.2f%s",
929 idx == CONFIG_DISPLAY_MODE_DEFAULT ? "default" :
930 (idx == CONFIG_DISPLAY_MODE_FOLLOW_VIDEO ? "follow video" :
931 (idx == CONFIG_DISPLAY_MODE_FOLLOW_VIDEO_INTERLACED ? "follow video interlaced" :
932 "fixed")),
933 mode->width, mode->height, mode->refreshRateHz, mode->interlaced ? "i" : "");
935 }
936}
937
966{
967 if (m_pStateMachine->GetState() == PLAY && m_playbackMode == AUDIO_ONLY && m_receivedVideo) {
969 return false;
970 }
971
972 if (m_pStateMachine->GetState() != BUFFERING)
973 return false;
974
978
979 // 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.
980 // Check for buffer fill level only if at least one PES packet was reassembled and pushed to the respective decoder.
983
985
987 LOGDEBUG("device: %s: Detected audio only", __FUNCTION__);
988 return true;
989 }
990
992 LOGDEBUG("device: %s: Detected video only", __FUNCTION__);
993 return true;
994 }
995
996 // In audio/video mode we need valid PTS values for both streams and a video frame must have reached the output buffer.
998 return false;
999
1003
1006
1009
1010 // used for diagnostics:
1011 // both audio and video have reached their buffering thresholds, but playback may
1012 // still be waiting for audio/video sync
1014
1015 // in CHANNEL_SWITCH_FAST_AUDIO mode audio was started already,
1016 // do not start video until audio has caught up with the video pts
1019
1021 auto now = std::chrono::steady_clock::now();
1022 auto durationSinceChannelSwitchMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - LOGGER->GetChannelSwitchStartTime()).count();
1023 LOGDEBUG2(L_AV_SYNC, "TRACE: +%5dms firing BufferingThresholdReached - PTS: %s (a), %s (v) -> diff %dms - buffer fill levels: %ldms (a) %ldms (v) render queue %d",
1031
1032 return true;
1033 }
1034
1036 auto now = std::chrono::steady_clock::now();
1037 auto durationSinceChannelSwitchMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - LOGGER->GetChannelSwitchStartTime()).count();
1038 LOGDEBUG2(L_AV_SYNC, "TRACE: +%5dms BufferingThresholdReached, video waits for audio - PTS: %s (a), %s (v) -> diff %dms - buffer fill levels: %ldms (a) %ldms (v) render queue %d",
1046 m_logPlaybackStart = false;
1047 }
1048
1049 return false;
1050}
1051
1067{
1068 if (m_pStateMachine->GetState() != BUFFERING)
1069 return false;
1070
1072 return false;
1073
1074 if (!m_pAudio->IsPaused())
1075 return false;
1076
1080
1081 // only start audio playback if the device also received and presented video already
1082 // -> video is always first
1084 return false;
1085
1087
1088 // the needed audio threshold fill level wasn't reached yet
1090 return false;
1091
1092 // drop audio data here, if the buffer fill level exceeds the threshold
1093 // - otherwise a later playback start is unneccessarily delayed when all buffers
1094 // reached their threshold but the rest of the audio data has still to be played out ...
1097
1098 // get new buffer filllevel for correct log message, because frames have been dropped in the meantime
1100
1102
1103 auto now = std::chrono::steady_clock::now();
1104 auto durationSinceChannelSwitchMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - LOGGER->GetChannelSwitchStartTime()).count();
1105 LOGDEBUG2(L_AV_SYNC, "TRACE: +%5dms firing AudioBufferingThresholdReached, threshold %dms - PTS: %s (a), %s (v) -> diff %dms - audio buffer: %ldms -> %ldms",
1113
1114 return true;
1115}
1116
1117/*********************************************************************
1118 * cOutputDevice public API - osd control
1119 ********************************************************************/
1120
1121#ifdef USE_GLES
1129
1137
1147
1157#endif
1158
1166{
1167 if (IsDetached())
1168 return;
1169
1171}
1172
1185void cOutputDevice::OsdDraw(int xi, int yi, int height, int width, int pitch,
1186 const uint8_t * argb, int x, int y)
1187{
1188 if (IsDetached())
1189 return;
1190
1191 m_pRender->OsdDraw(xi, yi, height, width, pitch, argb, x, y);
1192}
1193
1200void cOutputDevice::SetOsdSize(int width, int height)
1201{
1202 std::lock_guard<std::mutex> lock(m_sizeMutex);
1203 m_osdWidth = width;
1204 m_osdHeight = height;
1205}
1206
1213void cOutputDevice::SetScreenSize(int width, int height)
1214{
1215 std::lock_guard<std::mutex> lock(m_sizeMutex);
1216 m_screenWidth = width;
1217 m_screenHeight = height;
1218}
1219
1220/*********************************************************************
1221 * cOutputDevice public API - audio control
1222 ********************************************************************/
1223
1233
1238{
1239 LOGDEBUG("%s:", __FUNCTION__);
1240 m_audioChannelID = -1;
1241}
1242
1243/*********************************************************************
1244 * cOutputDevice public API - logging, statistics
1245 ********************************************************************/
1246
1255{
1256 *duped = 0;
1257 *dropped = 0;
1258 *counter = 0;
1259 if (m_pRender) {
1261 }
1262}
1263
1264/*********************************************************************
1265 * cOutputDevice public API - mediaplayer
1266 ********************************************************************/
1267
1279
1291
1301{
1302 if (m_pAudio->LazyInit())
1303 LOGFATAL("%s: audio init failed, abort!", __FUNCTION__);
1304
1305 if (m_pAudio->IsBufferFull())
1306 return 0;
1307
1309 return 1;
1310}
1311
1321{
1322 if (m_pAudio->LazyInit())
1323 LOGFATAL("%s: audio init failed, abort!", __FUNCTION__);
1324
1326 return 0;
1327
1329
1330 return 1;
1331}
1332
1333/*********************************************************************
1334 * cOutputDevice public API - detach/ attach
1335 ********************************************************************/
1336
1344{
1345 if (cDevice::Replaying()) {
1346 LOGDEBUG("device: %s: Device is replaying, stop replay first", __FUNCTION__);
1347 StopReplay();
1348 }
1349
1350 if (IsPrimaryDevice(false)) {
1351 m_needsMakePrimary = true;
1352 MakePrimaryDevice(false);
1353 }
1354
1357}
1358
1366{
1367 m_forceDetached = false;
1368
1369 if (m_needsMakePrimary) {
1370 MakePrimaryDevice(true);
1371 m_needsMakePrimary = false;
1372 }
1373
1375}
1376
1381{
1382 auto lock = m_pStateMachine->Lock();
1383
1384 return m_pStateMachine->GetState() == State::DETACHED;
1385}
1386
1387/*********************************************************************
1388 * cOutputDevice public API - pip
1389 ********************************************************************/
1390
1401int cOutputDevice::PlayPipVideo(const uchar *data, int size)
1402{
1403// LOGDEBUG("device: %s: %p %d", __FUNCTION__, data, size);
1404
1405 // This is a bit hacky:
1406 // Because we do no sync with the pip stream, we simply drop data
1407 // if the input buffer is full -> this prevents us from having a buffer overflow
1408 // caused by the pip stream.
1410 return size;
1411
1412 return PlayVideoInternal(m_pPipStream, &m_pipReassemblyBuffer, data, size, false, false);
1413}
1414
1438
1443{
1444 auto lock = m_pStateMachine->Lock();
1445
1446 return m_pPipHandler->IsEnabled();
1447}
1448
1456
1457/*
1458 * Wrapper functions for cVideoRender and cPipHandler
1459 */
1461{
1462 auto lock = m_pStateMachine->Lock();
1463
1464 m_pRender->Halt();
1466 m_pRender->Resume();
1467};
1468
1470{
1471 auto lock = m_pStateMachine->Lock();
1472
1473 m_pRender->Halt();
1474 m_pRender->SetPipActive(active);
1475 m_pRender->Resume();
1476};
1477
1478/*********************************************************************
1479 * cOutputDevice private functions
1480 ********************************************************************/
1481
1490static void PrintStreamData(const uchar *payload)
1491{
1492 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",
1493 payload[0],
1494 payload[1],
1495 payload[2],
1496 payload[3],
1497 payload[4],
1498 payload[5],
1499 payload[6],
1500 payload[7],
1501 payload[8],
1502 payload[9],
1503 payload[10],
1504 payload[11],
1505 payload[12],
1506 payload[13],
1507 payload[14],
1508 payload[15],
1509 payload[16],
1510 payload[17],
1511 payload[18],
1512 payload[19],
1513 payload[20],
1514 payload[21],
1515 payload[22],
1516 payload[23],
1517 payload[24]
1518 );
1519}
1520
1532{
1533 // LOGDEBUG("device: %s: %p %d %s", __FUNCTION__, data, size, mainStream ? "video" : "pip");
1534
1535 if (stream->IsInputBufferFull())
1536 return 0;
1537
1538 cPesVideo pesPacket((const uint8_t*)data, size);
1539
1540 if (!pesPacket.IsValid()) {
1541 buffer->Reset();
1542
1543 return size;
1544 }
1545
1546 if (mainStream) {
1547 if (!m_receivedValidVideo) {
1548 auto now = std::chrono::steady_clock::now();
1549 auto durationSinceChannelSwitchMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - LOGGER->GetChannelSwitchStartTime()).count();
1550 LOGDEBUG2(L_AV_SYNC, "TRACE: +%5dms PlayVideo() first valid video data", durationSinceChannelSwitchMs);
1551
1553 LOGGER->SetChannelSwitchDataReceivedTime(now);
1554
1555 m_receivedValidVideo = true;
1556 }
1557 }
1558
1559 if (trackJitter) {
1563 }
1564
1565 if (stream->GetCodecId() == AV_CODEC_ID_NONE) {
1566 // The playback has just started
1567 if (!pesPacket.HasPts() || !buffer->ParseCodecHeader(pesPacket.GetPayload(), pesPacket.GetPayloadSize())) {
1568 // received the middle of fragmented data, wait for the next PES packets with the start of a new frame
1569 return size;
1570 }
1571
1572 auto now = std::chrono::steady_clock::now();
1573 auto durationSinceChannelSwitchMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - LOGGER->GetChannelSwitchStartTime()).count();
1574 LOGDEBUG2(L_AV_SYNC, "TRACE: +%5dms PlayVideo() first decodeable video packet", durationSinceChannelSwitchMs);
1575
1576 PrintStreamData(data);
1577 buffer->Push(pesPacket.GetPayload(), pesPacket.GetPayloadSize(), pesPacket.GetPts());
1578
1579 stream->Open(buffer->GetCodec());
1580 } else {
1581 int payloadOffset = 0;
1582 if (pesPacket.HasPts() && !buffer->IsEmpty()) {
1583 // received the first fragment of a new frame, finish the current reassembly buffer into an AVPacket
1584 stream->PushAvPacket(buffer->PopAvPacket());
1585
1586 // populate the cleared buffer with the next frame
1587 if (buffer->HasLeadingZero(pesPacket.GetPayload(), pesPacket.GetPayloadSize()))
1588 payloadOffset = 1; // H.264/HEVC streams may have a leading zero byte before the start code
1589 }
1590
1591 buffer->Push(pesPacket.GetPayload() + payloadOffset, pesPacket.GetPayloadSize() - payloadOffset, pesPacket.GetPts());
1592 }
1593
1594 return size;
1595}
1596
1607
1615void cOutputDevice::HandleStillPicture(const uchar *data, int size)
1616{
1619
1620 // skip BufferUnderrunEvent{VIDEO} in renderer
1622
1623 const uchar *currentPacketStart = data;
1624 while (currentPacketStart < data + size) {
1626
1627 if (pesPacket.IsValid())
1629 else {
1630 LOGWARNING("device: %s: invalid PES packet", __FUNCTION__);
1631 break;
1632 }
1633
1634 currentPacketStart += pesPacket.GetPacketLength();
1635 }
1636
1638 m_pVideoStream->ResetInputPts(); // stillpicture shouldn't trigger having video data
1640}
1641
1648{
1649 LOGDEBUG("Set display mode: %dx%d@%.2f%s",
1650 mode.width,
1651 mode.height,
1652 mode.refreshRateHz,
1653 mode.interlaced ? "i" : "");
1654
1657}
1658
1680
1693
1701
1709{
1710 LOGDEBUG("device: %s: %s draining", __FUNCTION__, on ? "start" : "stop");
1711 m_draining = on;
1712}
1713
1714/*********************************************************************
1715 * cOutputDevice state transitioning functions
1716 ********************************************************************/
1717
1725{
1726 m_pStateMachine->OnEventReceived(event);
1727}
1728
1738{
1739 switch (state) {
1740 case PLAY:
1743 m_pAudio->SetPaused(true);
1745 break;
1746 case BUFFERING:
1749 break;
1750 case TRICK_SPEED:
1751 // The filter thread needs to be restarted for interlaced streams to be rendered with deinterlacer again. It is started lazily.
1753 m_pRender->SetTrickSpeed(0, false, false);
1754 m_pAudio->SetTrickSpeed(0, false, false);
1762 break;
1763 case STOP:
1764 m_receivedAudio = false;
1765 m_receivedVideo = false;
1766 m_receivedValidAudio = false;
1767 m_receivedValidVideo = false;
1768 break;
1769 case DETACHED:
1770 m_pAudio = new cAudioStream(this);
1771 m_pRender = new cVideoRender(this);
1772 m_pGrab = new cGrabber(m_pRender);
1775 int err = m_pRender->Init(); // starts display thread
1776 if (err < 0) { // drm init failed -> force detached mode
1777 delete m_pAudioDecoder;
1778 delete m_pVideoStream;
1779 delete m_pGrab;
1780 delete m_pRender;
1781 delete m_pAudio;
1782 LOGERROR("device: display init failed -> start in detached mode");
1783 m_forceDetached = true;
1784 break;
1785 }
1786 m_pVideoStream->StartDecoder(); // starts decoding thread
1788 m_pPipStream->StartDecoder(); // starts decoding thread
1789 m_pPipHandler = new cPipHandler(this);
1790 // Audio is init lazily (includes starting thread)
1791
1792 break;
1793 }
1794}
1795
1805{
1806 switch (state) {
1807 case BUFFERING:
1812 }
1813 break;
1814 case PLAY:
1815 // revert the video playback start release which was done in BUFFERING if we are audio-only
1819 }
1820
1822 m_pAudio->SetPaused(false);
1823
1824 if (m_playbackMode != AUDIO_ONLY) {
1826 m_pRender->SetStillpicture(false);
1828 }
1829 break;
1830 case TRICK_SPEED:
1831 // The filter thread needs to be restarted for interlaced streams
1832 // to be rendered without deinterlacer in trick speed mode.
1833 // It is started lazily.
1839 break;
1840 case STOP:
1841 if (m_forceDetached) {
1842 m_pStateMachine->SetState(DETACHED);
1843 break;
1844 }
1845
1846 FlushAudio();
1847
1850 m_pRender->Reset();
1852
1861
1862 break;
1863 case DETACHED:
1864 delete m_pPipHandler;
1865 m_pPipHandler = nullptr;
1866
1867 // resume the previously stopped threads
1869 m_pRender->Resume();
1870
1871 // now do the detach
1872 m_pPipStream->Exit();
1873 delete m_pPipStream;
1874
1875#ifdef USE_GLES
1876 // The opengl thread was probably locked before cmdCopyBufferToOutputFb().
1877 // 1) set running to false
1878 // 2) continue the thread (which will skip the waiting cmd->Execute())
1879 // 3) do the real thread cancel and cleanup
1880 // We need to keep this order to prevent a deadlock!
1884#endif
1885 m_pRender->Exit(); // render must be stopped before videostream!
1887 m_pAudio->Exit(); // audio must be stopped after renderer!
1888
1889 delete m_pAudioDecoder; // includes a Close()
1890 delete m_pVideoStream;
1891 delete m_pGrab;
1892 delete m_pRender;
1893 delete m_pAudio;
1894
1895 break;
1896 }
1897}
1898
1903{
1904 m_pRender->Halt();
1906}
1907
1916
1917#ifdef USE_GLES
1925
1934#endif
1935
1940{
1941 return m_forceDetached;
1942}
1943
1953{
1954 if (m_pAudio->LazyInit())
1955 return -1;
1956
1957 if (setVolume)
1958 m_pAudio->SetVolume((m_volume * 1000) / 255);
1959
1960 return 0;
1961}
1962
1971
1979void cOutputDevice::SetTrickSpeed(double speed, bool active, bool forward)
1980{
1981 m_pRender->SetTrickSpeed(speed, active, forward);
1982 m_pAudio->SetTrickSpeed(speed, active, forward);
1983}
1984
1995{
1998
2001 // store the first PTSes beforehand, because dropping samples/frames will change the output of GetFirst*PtsMsToPlay()
2004
2005 // don't drop old audio, if we want to wait for it in fast channel switch mode including audio playback
2008
2010 } else if (receivedAudio) {
2011 LOGDEBUG("device: audio only detected");
2014 } else if (receivedVideo) {
2015 LOGDEBUG("device: video only detected");
2018 } else {
2019 // Sometimes a DeviceClear() can jump in between signalling the ThresholdReachedEvent
2020 // and progressing it, e.g. the video thread signals the ThresholdReached, VDR sends a DeviceClear()
2021 // and OnEventReceived wants to process the ThresholdReachedEvent with empty buffers.
2022 LOGDEBUG("device: buffering threshold reached and no a/v available, keep BUFFERING state");
2023 return false;
2024 }
2025
2026 return true;
2027}
2028
2038
2045{
2046 // resume from pause
2048
2049 switch (m_playbackMode) {
2050 case AUDIO_ONLY:
2052 m_pAudio->SetPaused(false);
2053 break;
2054 case AUDIO_AND_VIDEO:
2057 if (audioBehindVideoByMs > 0) {
2059 m_pAudio->SetPaused(false);
2060 } else
2062
2063 // fallthrough
2064 case VIDEO_ONLY:
2065 m_pRender->SetStillpicture(false);
2067 break;
2068 case NONE:
2069 LOGFATAL("STATE MACHINE: play event in PLAY state with NONE playback mode. This is a bug.");
2070 break;
2071 }
2072}
2073
2090
2095{
2097}
Audio Interface Header File.
Audio Decoder.
Definition codec_audio.h:61
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:70
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=PTSTICKS })
Open and initiate the audio decoder.
void SetPassthroughMask(int)
Set audio pass-through mask.
void Close(void)
Close the audio decoder.
Audio Interface.
Definition audio.h:51
void SetHwDelayBaseline(void)
Set the hw delay baseline.
Definition audio.cpp:1226
bool IsForwardTrickSpeed(void)
Definition audio.h:80
bool IsSlowTrickSpeed(void)
Definition audio.h:81
int64_t GetTrickSpeedPtsTimebaseUnits(void)
Definition audio.h:78
void SetPassthroughMask(int mask)
Definition audio.h:91
void ResetHwDelayBaseline(void)
Reset the hw delay baseline.
Definition audio.cpp:1244
bool IsBufferEmpty(void)
Definition audio.h:63
void ClockDriftCompensation(void)
Calculate clock drift compensation.
Definition audio.cpp:1274
void ResetTrickSpeedPts(void)
Definition audio.h:79
void Exit(void)
Cleanup audio output module (alsa)
Definition audio.cpp:1035
int64_t GetOutputPtsMs(void)
Get the output PTS of the ringbuffer.
Definition audio.cpp:775
void SetPaused(bool)
Set audio playback pause state.
Definition audio.cpp:945
void SetTrickSpeed(double, bool, bool)
Set the trickspeed.
Definition audio.cpp:789
int64_t GetHardwareOutputPtsTimebaseUnits(void)
Get the hardware output PTS in timebase units.
Definition audio.cpp:909
void DropSamplesOlderThanPtsMs(int64_t)
Drop samples older than the given PTS.
Definition audio.cpp:420
bool HasInputPts(void)
Definition audio.h:71
int64_t GetInputPtsMs(void)
Definition audio.h:72
bool IsBufferFull(void)
Definition audio.h:62
int LazyInit(void)
Initialize audio output module (alsa)
Definition audio.cpp:1013
void SetVolume(int)
Set mixer volume (0-1000)
Definition audio.cpp:923
void FlushBuffers(void)
Flush audio buffers.
Definition audio.cpp:723
void AdvanceTrickSpeedPts(int64_t)
Advance the pts in trickspeed mode and delay "playback".
Definition audio.cpp:820
bool IsPaused(void)
Definition audio.h:59
Plugin Configuration.
Definition config.h:65
int ConfigPipUseAlt
Definition config.h:103
std::atomic< int > StatMaxShortTermVideoJitterMs
logged max video jitter of the last 1000 packets
Definition config.h:145
std::atomic< int > StatMaxShortTermAudioJitterMs
logged max audio jitter of the last 1000 packets
Definition config.h:143
sDrmMode CurrentVideoDrmMode
currently used video drm mode
Definition config.h:151
std::atomic< int > StatMaxLongTermAudioJitterMs
logged max overall audio jitter since stream start
Definition config.h:144
int ConfigAdditionalBufferLengthMs
config size ms of a/v buffer
Definition config.h:114
std::atomic< int > StatMaxLongTermVideoJitterMs
logged max overall video jitter since stream start
Definition config.h:146
bool ConfigDisableDeint
disable deinterlacer
Definition config.h:115
int ConfigVideoChannelSwitchMode
channel switch mode (enum ChannelSwitchMode)
Definition config.h:77
int ConfigDecoderFallbackToSwNumPkts
maximum number of packets sent before fallback to sw decoder
Definition config.h:117
int ConfigVideoAudioDelayMs
config audio delay
Definition config.h:85
int ConfigDisableOglOsd
config disable ogl osd
Definition config.h:135
sDrmMode RequestedDrmMode
is set to the requested mode which should be changed to
Definition config.h:152
bool CompareCurrentMode(sDrmMode *)
Return true, if the given mode is equal to the current display mode.
Definition config.cpp:164
sDrmMode AutoDetectedDrmMode
auto detected mode on the first startup (maybe equal to UserSetMode)
Definition config.h:148
std::vector< sDrmMode > CollectedDrmModes
collected available drm modes on the current connector
Definition config.h:147
int ConfigMaxSizeGPUImageCache
config max gpu image cache size
Definition config.h:121
Plugin OSD provider.
Definition osdprovider.h:33
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.
Event handler thread.
void AddEvent(Event)
Add an event to the queue.
Grabbing Processor.
Definition grab.h:79
void Finish(void)
Clean up.
Definition grab.cpp:700
bool ProcessGrab(void)
Start the conversion.
Definition grab.cpp:785
int Size(void)
Definition grab.h:86
uint8_t * Image(void)
Definition grab.h:85
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:666
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.
bool m_externalPlayerActive
true, if we detached for an external player
Definition device.h:285
std::mutex m_sizeMutex
mutex to lock screen size (which is accessed by different threads)
Definition device.h:269
virtual void TrickSpeed(int, bool)
Sets the device into a mode where replay is done slower.
Definition device.cpp:585
cVideoRender * m_pRender
pointer to cVideoRender object
Definition device.h:248
virtual bool CanReplay(void) const
Return true if this device can currently start a replay session.
Definition device.cpp:311
cAudioDecoder * m_pAudioDecoder
pointer to cAudioDecoder object
Definition device.h:251
bool m_initialized
true, if the plugin had a successful Initialize()
Definition device.h:242
std::unique_ptr< cStateMachine > m_pStateMachine
Definition device.h:240
void HandleStillPicture(const uchar *data, int size)
The still picture data received from VDR can contain multiple PES packets.
Definition device.cpp:1615
bool CheckAudioPlaybackStartConditions(void)
Returns true, if audio playback should start without respect to a/v-sync.
Definition device.cpp:1066
int m_audioChannelID
current audio channel ID
Definition device.h:263
void SetVideoCodec(enum AVCodecID, AVCodecParameters *, AVRational)
Open a video codec.
Definition device.cpp:1287
void HandleDisplayModeChange(const sDrmMode &)
Set the display mode.
Definition device.cpp:1647
int MaxSizeGPUImageCache(void)
Get the maximum GPU image cache size.
Definition device.cpp:1125
void SetRenderPipActive(bool)
Definition device.cpp:1469
bool m_logPlaybackStart
Definition device.h:260
void SetPassthroughMask(int)
Set the passthrough mask (called from setup menu or conf)
Definition device.cpp:1227
int PlayPipVideo(const uchar *, int)
Play a video packet of the pip videostream.
Definition device.cpp:1401
virtual int PlayAudio(const uchar *, int, uchar)
Play an audio packet.
Definition device.cpp:382
void EnterState(State)
Actions to be performed when entering a state.
Definition device.cpp:1804
void LeaveState(State)
Actions to be performed when leaving a state.
Definition device.cpp:1737
std::atomic< ChannelSwitchMode > m_channelSwitchMode
current channel switch mode
Definition device.h:259
int PlayVideoPkts(AVPacket *)
Play a video packet.
Definition device.cpp:1320
void ResumeVideoThreads(void)
Resume the rendering and decoder thread.
Definition device.cpp:1911
void TriggerEvent(const Event &)
With this wrapper function, the device can directly act as an event reveiver.
Definition device.cpp:1724
bool HaltOpenGlThread(void)
Pause the OpenGL worker thread.
Definition device.cpp:1921
void SetEnableHdr(bool)
Enable HDR display mode.
Definition device.cpp:904
int OglOsdIsDisabled(void)
Is the OpenGL/ES osd disabled?
Definition device.cpp:1133
std::atomic< bool > m_receivedAudio
flag if audio packets have been received
Definition device.h:270
std::atomic< bool > m_draining
true, if the device is in draining mode (waiting for empty buffers)
Definition device.h:243
virtual cSpuDecoder * GetSpuDecoder(void)
Get the device SPU decoder.
Definition device.cpp:163
void PipChannelChange(int)
Definition device.cpp:1452
int64_t GetFirstAudioPtsMsToPlay()
Calculate the first audio PTS that should be played during synchronized playback.
Definition device.cpp:1671
int m_osdHeight
Definition device.h:280
cDvbSpuDecoder * m_pSpuDecoder
pointer to spu decoder
Definition device.h:246
void Detach(void)
Detach the device.
Definition device.cpp:1343
void SetDecoderFallbackToSw(bool)
Force the decoder to fallback to software if the hardware decoder fails after the configured amount o...
Definition device.cpp:890
virtual bool Flush(int=0)
Return true, if the output buffers are empty, false otherwise.
Definition device.cpp:776
std::atomic< PlaybackMode > m_playbackMode
current playback mode
Definition device.h:262
void FlushAudio(void)
Clear all audio data from the decoder and ringbuffer.
Definition device.cpp:1600
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
Definition device.cpp:148
int GetBufferFillLevelThresholdMs()
Returns the buffer fill level threshold in milliseconds.
Definition device.cpp:1698
bool m_needsMakePrimary
true, if device should be made a primary device after attach
Definition device.h:245
virtual uchar * GrabImage(int &, bool, int, int, int)
Grabs the currently visible screen image.
Definition device.cpp:181
void Stop(void)
Called by VDR when the plugin is stopped.
Definition device.cpp:119
void ResetChannelId(void)
Reset the channel ID (restarts audio)
Definition device.cpp:1237
cDeviceConfig * m_pConfig
pointer to cDeviceConfig object
Definition device.h:247
void SetOsdSize(int, int)
Set the OSD size.
Definition device.cpp:1200
void PipDisable(void)
Definition device.cpp:1450
virtual ~cOutputDevice(void)
Destroy the device.
Definition device.cpp:65
void SetEnableOglOsd(void)
Enables OpenGL/ES Osd.
Definition device.cpp:1151
virtual void SetVideoDisplayFormat(eVideoDisplayFormat)
Sets the video display format.
Definition device.cpp:218
void Attach(void)
Attach the device again.
Definition device.cpp:1365
bool Initialize(void)
Initialize the device.
Definition device.cpp:84
void OsdDraw(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD pixmap.
Definition device.cpp:1185
void ResetVideoFilter(void)
Reset the video deinterlace filter.
Definition device.cpp:1966
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
Definition device.cpp:709
cAudioStream * m_pAudio
pointer to cAudioStream object
Definition device.h:250
cGrabber * m_pGrab
pointer to grabber object
Definition device.h:264
bool CheckPlaybackStartConditions(void)
Check, if all conditions are met to start the playback.
Definition device.cpp:965
void ResumePlayback(void)
Resume playback again.
Definition device.cpp:2094
cHardwareDevice * m_pHardwareDevice
pointer to hardware device description
Definition device.h:253
void PipSetSize(void)
Definition device.cpp:1455
virtual void Play(void)
Sets the device into play mode (after a previous trick mode, or pause)
Definition device.cpp:698
cEventHandler * m_pEventHandler
event handler thread
Definition device.h:254
void PipChannelSwap(bool)
Definition device.cpp:1453
void PipEnable(void)
Definition device.cpp:1449
virtual void ScaleVideo(const cRect &=cRect::Null)
Scale the currently shown video.
Definition device.cpp:561
cOutputDevice(cDeviceConfig *)
Create the device.
Definition device.cpp:54
int64_t GetFirstVideoPtsMsToPlay()
Definition device.cpp:1684
int PlayVideoInternal(cVideoStream *, cReassemblyBufferVideo *, const uchar *, int, bool, bool)
Play a video packet.
Definition device.cpp:1531
bool FastChannelSwitchInTransferMode(void)
Definition device.h:152
void SetRenderPipSize(void)
Definition device.cpp:1460
void SetDisplayMode(int)
Trigger a display mode change event if the mode changed.
Definition device.cpp:914
cReassemblyBufferAudio m_audioReassemblyBuffer
audio pes reassembly buffer
Definition device.h:256
cJitterTracker m_videoJitterTracker
video jitter tracker
Definition device.h:258
bool m_forceDetached
start the plugin in detached state
Definition device.h:284
bool PipIsEnabled(void)
Returns true, if pip is currently enabled.
Definition device.cpp:1442
bool IsDetached(void) const
Returns true, if the device is detached.
Definition device.cpp:1380
void SetDisableDeint(void)
Disables deinterlacer (called from setup menu or conf)
Definition device.cpp:879
void SetDrain(bool)
Set and log the drain state changes.
Definition device.cpp:1708
virtual void Replaying(const cControl *, const char *, const char *, bool)
Monitor a replay start or end.
Definition device.cpp:859
static constexpr int MIN_BUFFER_FILL_LEVEL_THRESHOLD_MS
min buffering threshold in ms
Definition device.h:238
cVideoStream * m_pPipStream
pointer to pip video stream
Definition device.h:266
virtual void Clear(void)
Clears all video and audio data from the device.
Definition device.cpp:658
int GetVideoAudioDelayMs(void)
Definition device.h:171
cPipHandler * m_pPipHandler
pointer to pip handler
Definition device.h:268
virtual bool SetPlayMode(ePlayMode)
Sets the device into the given play mode.
Definition device.cpp:325
void SetAudioCodec(enum AVCodecID, AVCodecParameters *, AVRational)
Open an audio codec.
Definition device.cpp:1275
int m_screenWidth
Definition device.h:281
std::atomic< bool > m_receivedValidVideo
flag if valid video packets have been received
Definition device.h:273
void HaltVideoThreads(void)
Pause the rendering and decoder thread.
Definition device.cpp:1902
int m_osdWidth
Definition device.h:279
bool IsDetachForced(void)
Returns true, the a detached plugin start was forced.
Definition device.cpp:1939
std::atomic< bool > m_receivedVideo
flag if video packets have been received
Definition device.h:271
cReassemblyBufferVideo m_pipReassemblyBuffer
pip pes reassembly buffer
Definition device.h:267
cReassemblyBufferVideo m_videoReassemblyBuffer
video pes reassembly buffer
Definition device.h:255
cJitterTracker m_audioJitterTracker
audio jitter tracker
Definition device.h:257
void OsdClose(void)
Close the OSD.
Definition device.cpp:1165
void ResetPipStream(void)
Resets pip stream and render pipeline.
Definition device.cpp:1418
virtual void SetVideoFormat(bool)
Set the video format.
Definition device.cpp:235
void SetTrickSpeed(double, bool, bool)
Set the trickspeed in the renderer.
Definition device.cpp:1979
virtual void GetVideoSize(int &, int &, double &)
Get the video size.
Definition device.cpp:255
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles.
Definition device.cpp:497
void GetStats(int *, int *, int *)
Get statistics from the renderer.
Definition device.cpp:1254
void SetScreenSize(int, int)
Set the screen size.
Definition device.cpp:1213
bool m_pipUseAlt
use alternative pip position
Definition device.h:274
void SetDisableOglOsd(void)
Disables OpenGL/ES Osd (called from setup menu or conf)
Definition device.cpp:1141
void PipToggle(void)
Definition device.cpp:1451
int InitAudio(bool)
Init the audio lazily.
Definition device.cpp:1952
virtual void SetVolumeDevice(int)
Sets the audio volume on this device (Volume = 0...255).
Definition device.cpp:298
virtual void MakePrimaryDevice(bool)
Informs a device that it will be the primary device.
Definition device.cpp:135
void ResumeOpenGlThread(void)
Resume the OpenGL worker thread.
Definition device.cpp:1929
void PausePlayback(bool)
Pause the playback.
Definition device.cpp:2080
virtual int PlayVideo(const uchar *, int)
Play a video packet of the main videostream.
Definition device.cpp:482
std::atomic< bool > m_receivedValidAudio
flag if valid audio packets have been received
Definition device.h:272
bool FastChannelSwitchAudioInTransferMode(void)
Definition device.h:151
int PlayAudioPkts(AVPacket *)
Play an audio packet.
Definition device.cpp:1300
void ScheduleResyncAtPtsMs(int64_t)
Schedule aa a/v resync in the render thread at the given pts.
Definition device.cpp:2034
cDeviceOsdProvider * m_pOsdProvider
pointer to cDeviceOsdProvider object
Definition device.h:252
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.
Definition device.cpp:747
virtual cRect CanScaleVideo(const cRect &, int taCenter)
Ask the output, if it can scale video.
Definition device.cpp:526
void PipSwapPosition(void)
Definition device.cpp:1454
bool SchedulePlaybackStart(void)
Schedules the playback start.
Definition device.cpp:1994
void ResumeFromPause(void)
Resume playback from pause state.
Definition device.cpp:2044
int Start(void)
Called by VDR when the plugin is started.
Definition device.cpp:108
int m_screenHeight
Definition device.h:282
virtual void GetOsdSize(int &, int &, double &)
Returns the width, height and aspect ratio the OSD should have.
Definition device.cpp:278
virtual void ChannelSwitch(const cDevice *, int, bool)
Monitor a channel switch triggered by VDR (cStatus::ChannelSwitch())
Definition device.cpp:844
virtual void StillPicture(const uchar *, int)
Display the given I-frame as a still picture.
Definition device.cpp:723
cVideoStream * m_pVideoStream
pointer to main video stream
Definition device.h:249
int m_volume
track the volume in the device (for attach)
Definition device.h:277
Audio PES Packet Parser.
Definition pes.h:79
Video PES Packet Parser.
Definition pes.h:64
PiP Stream Handler.
Definition pip.h:55
void ChannelChange(int)
Change the pip channel.
Definition pip.cpp:338
void SwapPosition(void)
Swap pip between normal and alternative position.
Definition pip.cpp:385
void Toggle(void)
Toggle picture-in-picture.
Definition pip.cpp:328
void Disable(void)
Stop picture-in-picture.
Definition pip.cpp:317
void ChannelSwap(bool)
Swap the pip channel with main live channel.
Definition pip.cpp:354
bool IsEnabled(void)
Definition pip.h:68
void Enable(void)
Start picture-in-picture.
Definition pip.cpp:306
void SetSize(void)
Set size and position for the pip window.
Definition pip.cpp:377
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
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.
int GetFramesFilled(void)
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)
static constexpr int GetAudioBehindVideoStartThresholdMs(void)
void OsdDraw(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD ARGB image.
void ScheduleVideoPlaybackPauseAt(int64_t ptsMs)
void ScheduleResyncAtPtsMs(int64_t ptsMs)
void ClearDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
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 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.
int Init(void)
Initialize the renderer.
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:48
void GetVideoSize(int *, int *, double *)
Get video size and aspect ratio.
bool Drain(void)
Drains the video stream by finalizing any pending data.
bool BuffersEmpty(void)
Return true, if the input AVPacket, videofilter and drm output buffer queues are empty.
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=PTSTICKS })
Open a video codec.
void SetDecoderFallbackToSwNumPkts(int numPackets)
Definition videostream.h:89
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:78
void Resume(void)
Definition videostream.h:66
int GetVideoPacketMax(void)
Definition videostream.h:80
size_t GetAvPacketsFilled(void)
Definition videostream.h:71
void DisableDeint(bool disable)
Definition videostream.h:88
void CloseDecoder(void)
Close the decoder.
void Exit(void)
Exit video stream.
void CancelFilterThread(void)
Stop filter thread.
void FlushDecoder(void)
Flush the decoder.
bool PushAvPacket(AVPacket *avpkt)
Pushes a pre-assembled AVPacket directly to the processing queue.
bool IsInputBufferFull(void)
Definition videostream.h:72
void ResetFilterThreadNeededCheck()
Definition videostream.h:84
int64_t GetInputPtsMs(void)
Definition videostream.h:77
void Halt(void)
Definition videostream.h:65
virtual void SetDeinterlacerDeactivated(bool deactivate)
Definition videostream.h:86
void ResetTrickSpeedFramesSentCounter(void)
Definition videostream.h:75
bool HasInputPts(void)
Definition videostream.h:76
Audio Decoder Header File.
Plugin Configuration Header File.
Output Device Header File.
__attribute__((weak)) union gbm_bo_handle gbm_bo_get_handle_for_plane(struct gbm_bo *bo
Grabbing Interface Header File.
std::variant< PlayEvent, PauseEvent, StopEvent, TrickSpeedEvent, StillPictureEvent, DetachEvent, AttachEvent, BufferUnderrunEvent, BufferingThresholdReachedEvent, ScheduleResyncAtPtsMsEvent, ResyncEvent, DisplayChangeEvent > Event
State
ChannelSwitchMode
Channel switch modes.
Definition config.h:54
static void PrintStreamData(const uchar *payload)
Print the start code, stream id, length, first three bytes (start code) of the payload,...
Definition device.cpp:1490
@ AUDIO_AND_VIDEO
Definition device.h:60
@ VIDEO_ONLY
Definition device.h:62
@ AUDIO_ONLY
Definition device.h:61
@ NONE
Definition device.h:59
@ PLAY
@ STOP
@ BUFFERING
@ TRICK_SPEED
@ DETACHED
@ CONFIG_DISPLAY_MODE_DEFAULT
Definition config.h:43
@ CONFIG_DISPLAY_MODE_FOLLOW_VIDEO_INTERLACED
Definition config.h:45
@ CONFIG_DISPLAY_MODE_FOLLOW_VIDEO
Definition config.h:44
@ CONFIG_DISPLAY_MODE_MANUAL
Definition config.h:46
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:48
#define LOGDEBUG
log to LOG_DEBUG
Definition logger.h:46
#define LOGERROR
log to LOG_ERR
Definition logger.h:40
#define AV_NOPTS_VALUE
Definition misc.h:76
static const char * Timestamp2StringMs(int64_t ts)
Input PTS is in ms.
Definition misc.h:151
#define LOGWARNING
log to LOG_WARN
Definition logger.h:42
#define LOGGER
shortcut to the logger
Definition logger.h:51
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:38
@ L_DRM
drm logs
Definition logger.h:64
@ L_AV_SYNC
audio/video sync logs
Definition logger.h:61
@ L_OSD
osd logs
Definition logger.h:63
@ L_CODEC
codec logs
Definition logger.h:65
@ L_GRAB
grabbing logs
Definition logger.h:73
Describes a hardware device.
Jitter Tracking of Incoming Packets Header File.
Logger Header File.
OSD Provider Header File.
PES Packet Parser Header File.
PiP (Picture-in-Picture) Interface Header File.
Device State Machine and Event Handler 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.