vdr-plugin-softhddevice-drm-gles 1.6.7
videorender.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
17#include <cerrno>
18#include <chrono>
19#include <cinttypes>
20#include <cstdint>
21#include <mutex>
22#include <vector>
23
24#ifdef USE_GLES
25#include <assert.h>
26#include <gbm.h>
27#include <EGL/egl.h>
28#endif
29
30extern "C" {
31#include <libavcodec/avcodec.h>
32#include <libavutil/hwcontext_drm.h>
33}
34
35#include <drm_fourcc.h>
36#include <vdr/osd.h>
37#include <vdr/thread.h>
38#include <xf86drmMode.h>
39
40#include "audio.h"
41#include "config.h"
42#include "drmdevice.h"
43#include "drmhdr.h"
44#include "event.h"
45#include "grab.h"
46#include "logger.h"
47#include "misc.h"
48#include "queue.h"
49#include "softhddevice.h"
50#include "videorender.h"
51#include "videostream.h"
52
59 : cThread("softhd display"),
60 m_pDevice(device),
61 m_pAudio(m_pDevice->Audio()),
62 m_pConfig(m_pDevice->Config()),
63 m_grabOsd("OSD"),
64 m_grabVideo("VIDEO"),
65 m_grabPip("PIP"),
66 m_pDrmDevice(new cDrmDevice(this, m_pConfig)),
67 m_pEventReceiver(device),
68 m_pHdrMetadata(this),
69 m_enableHdr(m_pConfig->ConfigVideoEnableHDR)
70{
71#ifdef USE_GLES
73 m_bo = nullptr;
74 m_pNextBo = nullptr;
75 m_pOldBo = nullptr;
76#endif
77 m_timebase = av_make_q(1, 90000);
79}
80
85{
86 LOGDEBUG2(L_DRM, "videorender: %s", __FUNCTION__);
87
88 Stop();
89
90 delete m_pDrmDevice;
91}
92
104
115
123
136{
137 if (!frame || dispWidth == 0 || dispHeight == 0)
138 return { dispX, dispY, dispWidth, dispHeight };
139
140 double frameWidth = frame->width > 0 ? frame->width : 1.0;
141 double frameHeight = frame->height > 0 ? frame->height : 1.0;
142 double frameSar = av_q2d(frame->sample_aspect_ratio) ? av_q2d(frame->sample_aspect_ratio) : 1.0;
143 double dispAspect = static_cast<double>(dispWidth) / static_cast<double>(dispHeight);
145
146 double picWidthD = dispWidth;
147 double picHeightD = dispHeight;
148
149 if (dispAspect > frameAspect) {
150 // letterbox horizontally (frame narrower than display)
154 } else {
155 // pillarbox vertically (frame wider than display)
159 }
160
161 // round to the nearest pixel
162 uint64_t picWidth = std::llround(std::max(0.0, picWidthD));
163 uint64_t picHeight = std::llround(std::max(0.0, picHeightD));
164
165 int64_t offsetX = static_cast<int64_t>(dispWidth) - static_cast<int64_t>(picWidth);
166 int64_t offsetY = static_cast<int64_t>(dispHeight) - static_cast<int64_t>(picHeight);
167 uint64_t posX = dispX + static_cast<uint64_t>(std::max<int64_t>(0, offsetX / 2));
168 uint64_t posY = dispY + static_cast<uint64_t>(std::max<int64_t>(0, offsetY / 2));
169
170 return { posX, posY, picWidth, picHeight };
171}
172
179{
180 uint32_t blobID = 0;
181 if (m_pDrmDevice->CreateHdrBlob(&hdrData, sizeof(hdrData), &blobID)) {
182 LOGERROR("videorender: %s: HDR: Failed to create hdr property blob.", __FUNCTION__);
184 LOGERROR("videorender: %s: HDR: Failed to set hdr property", __FUNCTION__);
185 }
186
187 if (blobID)
189
190 if (!m_colorRangeStored) {
194 m_colorRangeStored = true;
195 }
196 }
197}
198
207{
210
212 LOGFATAL("videorender: %s: cannot allocate atomic request (%d): %m", __FUNCTION__, errno);
213
217
218 LOGDEBUG2(L_DRM, "videorender: %s: HDR: connector %d -> Colorspace %s", __FUNCTION__,
219 m_pDrmDevice->ConnectorId(), m_pHdrMetadata.GetColorPrimaries() == AVCOL_PRI_BT2020 ? "BT2020_RGB" : "BT709_YCC");
220
221 LOGDEBUG2(L_DRM, "videorender: %s: HDR: plane %d -> COLOR_ENCODING %s, COLOR_RANGE %s (Color %d)", __FUNCTION__,
222 m_pDrmDevice->VideoPlane()->GetId(), m_pHdrMetadata.GetColorPrimaries() == AVCOL_PRI_BT2020 ? "YCBCR_BT20202" : "YCBCR_BT709",
224
227 LOGFATAL("videorender: %s: cannot set atomic mode (%d): %m", __FUNCTION__, errno);
228 }
229
231
232 m_hasDoneHdrModeset = true;
233}
234
262
272{
273 if (!buf)
274 return 1;
275
276 AVFrame *frame = buf->frame;
277
278 if (frame && m_enableHdr) {
282
283 if (!m_pHdrMetadata.Build(&hdrData, frame->color_primaries, frame->color_trc, sd1, sd2)) {
286 }
287 }
288
289 // set display dimensions as default
292 uint64_t dispX = 0;
293 uint64_t dispY = 0;
294
296
297 // get video size and position
298 if (m_videoIsScaled) {
299 dispWidth = m_videoRect.Width();
300 dispHeight = m_videoRect.Height();
301 dispX = m_videoRect.X();
302 dispY = m_videoRect.Y();
303 }
304
305 // fit frame into display
307
308 // now set the plane parameters
309 videoPlane->SetParams(m_pDrmDevice->CrtcId(), buf->Id(),
311 0, 0, buf->Width(), buf->Height());
312
313 buf->SetSizeOnScreen(fittedRect.x, fittedRect.y, fittedRect.w, fittedRect.h); // remember for grab
314
315 return 0;
316}
317
325{
326 if (!m_pBufOsd || !m_pBufOsd->IsDirty())
327 return 1;
328
331
332 // We had draw activity on the osd buffer
333 if (m_pDrmDevice->UseZpos()) {
336 videoPlane->SetPlaneZpos(modeReq);
337 osdPlane->SetPlaneZpos(modeReq);
338
339 LOGDEBUG2(L_DRM, "videorender: %s: SetPlaneZpos: video->plane_id %d -> zpos %" PRIu64 ", osd->plane_id %d -> zpos %" PRIu64 "", __FUNCTION__,
340 videoPlane->GetId(), videoPlane->GetZpos(),
341 osdPlane->GetId(), osdPlane->GetZpos());
342 }
343
348
349 // now set the plane parameters
350 osdPlane->SetParams(m_pDrmDevice->CrtcId(), m_pBufOsd->Id(),
351 0, 0, crtcW, crtcH,
352 0, 0, srcW, srcH);
353
354 m_pBufOsd->SetSizeOnScreen(0, 0, crtcW, crtcH); // remember for grab
355
357 return 0;
358}
359
369{
370 if (!buf || !m_pipActive || m_videoIsScaled)
371 return 1;
372
373 AVFrame *frame = buf->frame;
374
375 // set display dimensions as default
378 uint64_t dispX = 0;
379 uint64_t dispY = 0;
380
382
383 // Get video size and position
384 if (m_videoIsScaled) {
385 dispWidth = m_videoRect.Width();
386 dispHeight = m_videoRect.Height();
387 dispX = m_videoRect.X();
388 dispY = m_videoRect.Y();
389 }
390
391 // fit frame into display
393
394 // compute pip window with given scaling and positioning values from menu
395 int64_t centerOffsetX = static_cast<int64_t>(dispWidth) - static_cast<int64_t>(fittedRect.w);
396 int64_t centerOffsetY = static_cast<int64_t>(dispHeight) - static_cast<int64_t>(fittedRect.h);
397 centerOffsetX = std::max<int64_t>(0, centerOffsetX / 2);
398 centerOffsetY = std::max<int64_t>(0, centerOffsetY / 2);
399
400 double crtcWD = fittedRect.w * m_pipScalePercent / 100.0;
401 double crtcHD = fittedRect.h * m_pipScalePercent / 100.0;
402 uint64_t crtcW = std::llround(crtcWD);
403 uint64_t crtcH = std::llround(crtcHD);
404
405 double spaceW = dispWidth - crtcW - centerOffsetX;
407
408 uint64_t crtcX = dispX + std::llround(spaceW * m_pipLeftPercent / 100.0 + centerOffsetX * m_pipScalePercent / 100.0);
409 uint64_t crtcY = dispY + std::llround(spaceH * m_pipTopPercent / 100.0 + centerOffsetY * m_pipScalePercent / 100.0);
410
411 // now set the plane parameters
412 pipPlane->SetParams(m_pDrmDevice->CrtcId(), buf->Id(),
414 0, 0, buf->Width(), buf->Height());
415
416 buf->SetSizeOnScreen(crtcX, crtcY, crtcW, crtcH); // remember for grab
417
418 return 0;
419}
420
430{
431 enum modeSetLevel {
432 MODESET_OSD = (1 << 0),
433 MODESET_VIDEO = (1 << 1),
434 MODESET_PIP = (1 << 2)
435 };
436
437 int modeSet = 0;
443
445 LOGERROR("videorender: %s: cannot allocate atomic request (%d): %m", __FUNCTION__, errno);
446 return -1;
447 }
448
449 // handle the video plane
450 // If no new video is available, set the old buffer again, if available.
451 // This is necessary to recognize a size-change in SetVideoBuffer().
452 // Though this is not expensive, maybe we should only call that, if size really changed.
454 videoPlane->SetPlane(modeReq);
456// LOGDEBUG2(L_DRM, "videorender: %s: SetPlane Video (fb = %" PRIu64 ")", __FUNCTION__, videoPlane->GetFbId());
457 }
458
459 // handle the pip plane
460 if (pipPlane->GetId()) {
462 pipPlane->SetPlane(modeReq);
463 else
464 pipPlane->ClearPlane(modeReq);
465
467 }
468
469 // handle the osd plane
470 if (!SetOsdBuffer(modeReq)) {
471 osdPlane->SetPlane(modeReq);
473// LOGDEBUG2(L_DRM, "videorender: %s: SetPlane OSD %d (fb = %" PRIu64 ")", __FUNCTION__, m_osdShown, osdPlane->GetFbId());
474 }
475
476 // return without an atomic commit (no video frame and osd activity)
477 if (!modeSet) {
479 return -1;
480 }
481
482 // do the atomic commit
484 if (modeSet & MODESET_OSD)
485 osdPlane->DumpParameters("osd");
487 videoPlane->DumpParameters("video");
488 if (modeSet & MODESET_PIP)
489 pipPlane->DumpParameters("pip");
490
492 LOGERROR("videorender: %s: page flip failed (%d): %m", __FUNCTION__, errno);
493 return -1;
494 }
495
497
498 return 0;
499}
500
509{
510 bool logDropDup = true;
511
516 else
517 logDropDup = false;
518
519 LOGDEBUG2(L_AV_SYNC, "%s (%d|%d|%d) Pkts %d Frames %d Rb %d bytes (%dms) PTS: in %s a %s v %s user delay %dms hw delay %dms diff %dms",
520 (logDropDup && (audioBehindVideoByMs > 0)) ? "Frame duped" : (logDropDup ? "Frame dropped" : "Frames:"),
534}
535
544{
545 if (!frame || !frame->opaque_ref)
546 return 0;
547
548 int *frameFlags = (int *)frame->opaque_ref->data;
549 return *frameFlags;
550}
551
559{
560 int *frameFlags;
561 if (!frame->opaque_ref) {
562 frame->opaque_ref = av_buffer_allocz(sizeof(*frameFlags));
563 if (!frame->opaque_ref) {
564 LOGFATAL("videorender: %s: cannot allocate private frame data", __FUNCTION__);
565 }
566 }
567
568 frameFlags = (int *)frame->opaque_ref->data;
569 *frameFlags = flags;
570}
571
580{
581 if (CommitBuffer(buf, pipBuf) < 0) {
582 // no modesetting was done
583 if (buf && buf->frame)
584 av_frame_free(&buf->frame);
585 if (pipBuf && pipBuf->frame)
586 av_frame_free(&pipBuf->frame);
587
588 return false;
589 } else {
590 if (m_pDrmDevice->HandleEvent() != 0)
591 LOGERROR("threads: display thread: drmHandleEvent failed!");
592
594
595 // now, that we had a successful commit, set the STC if we have a frame. Skip if only the OSD was updated.
596 if (buf && buf->frame) {
597 if (buf->frame->pts != AV_NOPTS_VALUE)
598 SetVideoClock(buf->frame->pts);
599
600 LOGDEBUG2(L_PACKET, "videorender: %s: ID %d: PTS %s", __FUNCTION__, buf->Id(), Timestamp2String(buf->frame->pts, 90));
601 }
602
603 return true;
604 }
605}
606
607/*****************************************************************************
608 * Thread
609 ****************************************************************************/
610
615{
616 LOGDEBUG("videorender: display thread started");
617 while(Running()) {
618 m_mutex.lock();
619
621
622 m_mutex.unlock();
623
625
627 usleep(100); // yield thread. give control also to threads with lower priority.
628 else
629 usleep(1000);
630 }
631 LOGDEBUG("videorender: display thread stopped");
632}
633
638{
639 if (!Active())
640 return;
641
642 LOGDEBUG("videorender: stopping display thread");
643 Cancel(2);
644}
645
655{
657
662
663 LOGDEBUG2(L_AV_SYNC, "videorender: resync schedule arrived at %s, current audio pts %s video pts %s",
665 m_eventQueue.push_back(ResyncEvent{});
667 }
668
669 // Pause was scheduled and we reached this pts now
671 LOGDEBUG2(L_AV_SYNC, "videorender: %s: pause was scheduled at %s)!", __FUNCTION__, Timestamp2String(videoPtsMs, 1));
674 // Resuming audio from pause was scheduled audio needs to catch up video
676 LOGDEBUG2(L_AV_SYNC, "videorender: resuming audio playback: video %s, audio %s", Timestamp2String(videoPtsMs, 1), Timestamp2String(audioPtsMs, 1));
677 m_pAudio->SetPaused(false);
679 // Duplicate frame
681 !skipSync && !m_pAudio->IsPaused()) {
683 m_framePresentationCounter++; // display the current video frame one period longer
684 // Drop frame - max every second frame. Otherwise, the buffer gets drained immediately, if multiple frames in a row are dropped.
688 m_framePresentationCounter--; // skip this pageflip
690
691 return true;
692 }
693
694// LogDroppedDuped(audioPtsMs, videoPtsMs, audioBehindVideoByMs);
695
696 // log AV diff for the first 10 frames and every 10 seconds
697// if (m_startCounter < 10 || m_startCounter % 500 == 0)
698// LOGDEBUG2(L_AV_SYNC, "drop %d, dup %d, total %d audio %s video %s Delay %dms kernel buffer delay %dms diff %dms",
699// m_framesDropped, m_framesDuped, m_startCounter,
700// Timestamp2String(audioPtsMs, 1), Timestamp2String(videoPtsMs, 1),
701// m_pDevice->GetVideoAudioDelayMs(), m_pAudio->GetHardwareOutputDelayMs(), audioBehindVideoByMs);
702
704
705 return false;
706}
707
714{
716
719
723 IsTrickSpeed() ||
724 IsStillpicture() ||
728
729 cDrmBuffer *drmBuffer = nullptr;
732
734
735 bool pageFlipDone = false;
736 if (drmBuffer) {
739 int64_t interFrameGapMs = std::abs(PtsToMs(drmBuffer->frame->pts - m_pCurrentlyDisplayed->frame->pts));
741 } else
743 }
744
746 // check if playback shall start
748 drmBuffer->PresentationFinished();
749 return true;
750 } else {
752 m_videoPlaybackPaused = false;
753 }
754 } else if (!m_displayOneFrameThenPause && !IsStillpicture()) {
755 // A/V sync
757 int64_t videoPtsMs = PtsToMs(drmBuffer->frame->pts);
759 // drop frame
760 drmBuffer->PresentationFinished();
761 if (pipBuffer)
762 pipBuffer->PresentationFinished();
763 return true;
764 }
765
768 }
769
773 }
774
776 if (m_startCounter == 1 && m_pDevice->Transferring()) {
777 auto now = std::chrono::steady_clock::now();
778 auto channelSwitchDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_pDevice->GetChannelSwitchStartTime()).count();
779 auto durationSinceFirstPacketMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_pDevice->GetChannelSwitchFirstPacketTime()).count();
781 Skins.Message(mtInfo, cString::sprintf(tr("channel switch done in %ldms (%ldms)"), channelSwitchDurationMs, durationSinceFirstPacketMs));
782 LOGDEBUG("channel switch done in %dms, %dms after first packet was received", channelSwitchDurationMs, durationSinceFirstPacketMs);
783 }
784
787
788 m_lastFrameWasDropped = false;
791 // display the current frame again in trick speed mode or for A/V syncing
793 } else if ((m_pBufOsd && m_pBufOsd->IsDirty()) || pipBuffer) {
795 }
796
797 if (pipBuffer) {
800
802 }
803
806
808
809 return pageFlipDone;
810}
811
816{
817 LOGDEBUG2(L_DRM, "videorender: %s: closing, set a black FB", __FUNCTION__);
818
820
824 m_pCurrentlyDisplayed = nullptr;
825 }
826}
827
832{
833 std::lock_guard<std::mutex> lock(m_timebaseMutex);
834
835 return pts * 1000 * av_q2d(m_timebase);
836}
837
842{
843 return m_pDrmDevice->HandleEvent();
844}
845
850{
851 return m_pDrmDevice->CanHandleHdr();
852}
853
854/*****************************************************************************
855 * OSD
856 ****************************************************************************/
857
862{
863#ifdef USE_GLES
864 if (m_disableOglOsd) {
865 memset((void *)m_pBufOsd->Plane(0), 0,
866 (size_t)(m_pBufOsd->Pitch(0) * m_pBufOsd->Height()));
867 } else {
869
873
875 if (!buf) {
876 LOGERROR("videorender: %s: Failed to get GL buffer", __FUNCTION__);
877 return;
878 }
879
880 m_pBufOsd = buf;
881
882 // release old buffer for writing again
883 if (m_bo)
885
886 // rotate bos and create and keep bo as m_pOldBo to make it free'able
887 m_pOldBo = m_bo;
888 m_bo = m_pNextBo;
889
890 LOGDEBUG2(L_OPENGL, "videorender: %s: eglSwapBuffers m_eglDisplay %p eglSurface %p (%i x %i, %i)", __FUNCTION__, m_pDrmDevice->EglDisplay(), m_pDrmDevice->EglSurface(), buf->Width(), buf->Height(), buf->Pitch(0));
891 }
892#else
893 memset((void *)m_pBufOsd->Plane(0), 0,
894 (size_t)(m_pBufOsd->Pitch(0) * m_pBufOsd->Height()));
895#endif
896
898 m_osdShown = false;
899}
900
901#define MIN(a, b) ((a) < (b) ? (a) : (b))
902
916 int width, int height, int pitch,
917 const uint8_t * argb, int x, int y)
918{
919#ifdef USE_GLES
920 if (m_disableOglOsd) {
921 LOGDEBUG2(L_OSD, "videorender: %s: width %d height %d pitch %d argb %p x %d y %d pitch buf %d xi %d yi %d", __FUNCTION__,
922 width, height, pitch, argb, x, y, m_pBufOsd->Pitch(0), xi, yi);
923 for (int i = 0; i < height; ++i) {
924 memcpy(m_pBufOsd->Plane(0) + x * 4 + (i + y) * m_pBufOsd->Pitch(0),
925 argb + i * pitch, MIN((size_t)pitch, m_pBufOsd->Pitch(0)));
926 }
927 } else {
929
933
935 if (!buf) {
936 LOGERROR("videorender: %s: Failed to get GL buffer", __FUNCTION__);
937 return;
938 }
939
940 m_pBufOsd = buf;
941
942 // release old buffer for writing again
943 if (m_bo)
945
946 // rotate bos and create and keep bo as m_pOldBo to make it free'able
947 m_pOldBo = m_bo;
948 m_bo = m_pNextBo;
949
950 LOGDEBUG2(L_OPENGL, "videorender: %s: eglSwapBuffers eglDisplay %p eglSurface %p (%i x %i, %i)", __FUNCTION__, m_pDrmDevice->EglDisplay(), m_pDrmDevice->EglSurface(), buf->Width(), buf->Height(), buf->Pitch(0));
951 }
952#else
953 // suppress unused variable warnings ...
954 (void) xi;
955 (void) yi;
956 (void) width;
957
958 for (int i = 0; i < height; ++i) {
959 memcpy(m_pBufOsd->Plane(0) + x * 4 + (i + y) * m_pBufOsd->Pitch(0),
960 argb + i * pitch, (size_t)pitch);
961 }
962#endif
964 m_osdShown = true;
965}
966
970static void ReleaseFrame( __attribute__ ((unused)) void *opaque, uint8_t *data)
971{
973
975}
976
986
994
1002
1007 AVFrame *frame,
1008 bool trickspeed,
1009 std::atomic<cBufferStrategy*> &bufferReuseStrategy,
1010 std::atomic<cDecodingStrategy*> &decodingStrategy,
1013 bool mainFrame)
1014{
1015 if (bufferReuseStrategy == nullptr) {
1016 if (trickspeed)
1018 else if (frame->format == AV_PIX_FMT_DRM_PRIME)
1020 else
1022 }
1023
1024 if (decodingStrategy == nullptr) {
1025 if (frame->format == AV_PIX_FMT_DRM_PRIME)
1027 else
1029 }
1030
1031 // Store the PTS of the first frame to be presented. The first frame might not have a valid PTS, if gone through a HW deinterlacer.
1032 //
1033 // @note: This is the only place outside of the display thread, where the video pts is set
1034 // (except setting it to AV_NOPTS_VALUE in cSofthdDevice::Clear() and SetState(STOP))
1035 // We only store here, if the stream recently started and the clock wasn't set already in the display thread
1036
1037 if (mainFrame && GetVideoClock() == AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE)
1038 SetVideoClock(frame->pts);
1039
1042
1043 if (!buf)
1044 LOGFATAL("videorender: %s: no free DRM buffer found. This is a bug.", __FUNCTION__);
1045
1046 frame = decodingStrategy.load()->PrepareDrmBuffer(buf, m_pDrmDevice->Fd(), frame);
1047
1048 buf->frame = frame;
1049 buf->SetPresentationPending(true);
1050
1051 drmBufferQueue->Push(buf);
1052}
1053
1062{
1064 return AV_NOPTS_VALUE;
1065
1066 std::lock_guard<std::mutex> lock(m_timebaseMutex);
1067
1068 return GetVideoClock() * 1000 * av_q2d(m_timebase);
1069}
1070
1075{
1076 m_startCounter = 0;
1077 LOGDEBUG("videorender: %s: reset m_startCounter %d TrickSpeed %d", __FUNCTION__, m_startCounter, IsTrickSpeed());
1078}
1079
1084{
1085 m_startCounter = 0;
1086 m_framesDuped = 0;
1087 m_framesDropped = 0;
1090 m_flipCounter = 0;
1091
1092 delete m_decodingStrategy;
1093 m_decodingStrategy = nullptr;
1094}
1095
1103void cVideoRender::SetTrickSpeed(double speed, bool active, bool forward)
1104{
1105 LOGDEBUG2(L_TRICK, "videorender: %s: set trick speed %.3f %s %s", __FUNCTION__, speed, speed > 1.0 ? "fast" : "slow", forward ? "forward" : "backward");
1107 m_trickspeedFactor = speed;
1108 m_trickspeed = active;
1109 m_forwardTrickspeed = forward;
1110}
1111
1120{
1121 if (!IsTrickSpeed())
1122 return 1;
1123
1124 // Calculate the expected number of display refreshes for this frame
1125 double interFrameGapSec = interFrameGapMs / 1000.0;
1126 double refreshPeriodSec = 1.0 / m_refreshRateHz;
1127 int displayCount = std::max(1, static_cast<int>(std::round(interFrameGapSec / refreshPeriodSec / m_trickspeedFactor)));
1128
1129 return displayCount;
1130}
1131
1132/*****************************************************************************
1133 * Grabbing
1134 ****************************************************************************/
1135
1143{
1144 int timeoutMs = 500;
1145 cMutex mutex;
1146 mutex.Lock();
1147 m_startgrab = true;
1148 int err = 0;
1149
1150 if (!m_grabCond.TimedWait(mutex, timeoutMs)) {
1151 LOGWARNING("videorender: %s: timed out after %dms", __FUNCTION__, timeoutMs);
1152 err = 1;
1153 }
1154
1155 std::lock_guard<std::mutex> lock(m_grabMutex);
1156 m_startgrab = false;
1157
1158 return err;
1159}
1160
1167{
1168 std::lock_guard<std::mutex> lock(m_grabMutex);
1169
1170 if (!m_startgrab)
1171 return;
1172
1173 if (m_pBufOsd && m_osdShown) {
1174 LOGDEBUG2(L_GRAB, "videorender: %s: Trigger osd grab arrived", __FUNCTION__);
1176 }
1177
1179 if (pbuf) {
1180 LOGDEBUG2(L_GRAB, "videorender: %s: Trigger video grab arrived", __FUNCTION__);
1182 }
1183
1185 if (pipBuf && grabPip) {
1186 LOGDEBUG2(L_GRAB, "videorender: %s: Trigger pip grab arrived", __FUNCTION__);
1188 }
1189
1190 m_grabCond.Broadcast();
1191}
1192
1197{
1198 std::lock_guard<std::mutex> lock(m_grabMutex);
1199
1200 m_grabOsd.Clear();
1202 m_grabPip.Clear();
1203}
1204
1213{
1217}
1218
1219/*****************************************************************************
1220 * Setup and initialization
1221 ****************************************************************************/
1222
1229void cVideoRender::SetOsdSize(int width, int height)
1230{
1231 m_pDevice->SetOsdSize(width, height);
1232}
1233
1242void cVideoRender::SetScreenSize(int width, int height, double refreshRateHz, bool interlaced)
1243{
1244 m_refreshRateHz = refreshRateHz;
1245 m_pDevice->SetScreenSize(width, height);
1246 m_framesPerFlipCycle = interlaced ? 2 : 1;
1247 m_flipCounter = 0;
1248}
1249
1259
1266{
1267 return m_pDrmDevice->CanHandleMode(mode);
1268}
1269
1279{
1280 // osd fb
1281#ifndef USE_GLES
1282 if (!m_pBufOsd)
1283 m_pBufOsd = new cDrmBuffer();
1284
1286#else
1287 if (m_disableOglOsd) {
1288 if (!m_pBufOsd)
1289 m_pBufOsd = new cDrmBuffer();
1290
1292 }
1293#endif
1294
1295 // black fb
1296 LOGDEBUG2(L_DRM, "videorender: %s: Try to create a black FB", __FUNCTION__);
1299}
1300
1305{
1306 if (m_pDrmDevice->ReInit())
1307 LOGFATAL("videorender: %s: Init drm device failed", __FUNCTION__);
1308
1311 uint32_t modeID = 0;
1312
1314 LOGFATAL("videorender: %s: Failed to create mode property blob.", __FUNCTION__);
1315 if (!(modeReq = m_pDrmDevice->ModeAtomicAlloc())) {
1317 LOGFATAL("videorender: %s: cannot allocate atomic request (%d): %m", __FUNCTION__, errno);
1318 }
1319
1322
1326 LOGFATAL("videorender: %s: cannot set atomic mode (%d): %m", __FUNCTION__, errno);
1327 }
1328
1331}
1332
1337{
1338 if (m_pDrmDevice->Init())
1339 LOGFATAL("videorender: %s: Init drm device failed", __FUNCTION__);
1340
1341#ifdef USE_GLES
1342 if (!m_disableOglOsd) {
1343 if (m_pDrmDevice->InitGbm())
1344 LOGFATAL("videorender: %s: Init gbm failed", __FUNCTION__);
1345
1346 if (m_pDrmDevice->InitEGL())
1347 LOGFATAL("videorender: %s: Init EGL failed", __FUNCTION__);
1348 }
1349#endif
1350
1352
1355
1356 InitBuffers();
1357
1358 // save actual modesetting
1360
1363 uint32_t modeID = 0;
1364
1366 LOGFATAL("videorender: %s: Failed to create mode property blob.", __FUNCTION__);
1367 if (!(modeReq = m_pDrmDevice->ModeAtomicAlloc())) {
1369 LOGFATAL("videorender: %s: cannot allocate atomic request (%d): %m", __FUNCTION__, errno);
1370 }
1371
1375
1376 // Osd plane
1377 // We don't have the m_pBufOsd for OpenGL yet, so we can't set anything. Set src and FbId later when osd was drawn,
1378 // but initially move the OSD behind the VIDEO
1379#ifndef USE_GLES
1380 osdPlane->SetParams(m_pDrmDevice->CrtcId(), m_pBufOsd->Id(),
1382 0, 0, m_pBufOsd->Width(), m_pBufOsd->Height());
1383
1384 osdPlane->SetPlane(modeReq);
1385#else
1386 if (m_disableOglOsd) {
1387 osdPlane->SetParams(m_pDrmDevice->CrtcId(), m_pBufOsd->Id(),
1389 0, 0, m_pBufOsd->Width(), m_pBufOsd->Height());
1390
1391 osdPlane->SetPlane(modeReq);
1392 }
1393#endif
1394 if (m_pDrmDevice->UseZpos()) {
1395 videoPlane->SetZpos(m_pDrmDevice->ZposOverlay());
1396 videoPlane->SetPlaneZpos(modeReq);
1397#ifdef USE_GLES
1398 osdPlane->SetZpos(m_pDrmDevice->ZposPrimary());
1399 osdPlane->SetPlaneZpos(modeReq);
1400#endif
1401 }
1402
1403 // Black buffer for video plane
1404 videoPlane->SetParams(m_pDrmDevice->CrtcId(), m_bufBlack.Id(),
1406 0, 0, m_bufBlack.Width(), m_bufBlack.Height());
1407
1408 videoPlane->SetPlane(modeReq);
1409
1411#ifndef USE_GLES
1412 osdPlane->DumpParameters("osd");
1413#endif
1414 videoPlane->DumpParameters("video");
1415
1418 LOGFATAL("videorender: %s: cannot set atomic mode (%d): %m", __FUNCTION__, errno);
1419 }
1420
1423
1424 m_osdShown = false;
1425
1426 // init variables page flip
1428
1429 Start();
1430}
1431
1438{
1440#ifdef USE_GLES
1441 if (m_disableOglOsd) {
1442 if (m_pBufOsd) {
1443 m_pBufOsd->Destroy();
1444 delete m_pBufOsd;
1445 }
1446 } else {
1447 if (m_pNextBo)
1449 if (m_pOldBo)
1451 }
1452#else
1453 if (m_pBufOsd) {
1454 m_pBufOsd->Destroy();
1455 delete m_pBufOsd;
1456 }
1457#endif
1458}
1459
1464{
1465 LOGDEBUG("videorender: %s", __FUNCTION__);
1466
1467 Reset();
1468 Stop();
1469
1470 // restore saved CRTC configuration
1472
1475
1478
1479 DeleteBuffers();
1480
1482}
1483
1490{
1491 m_videoRect.Set(rect.Point(), rect.Size());
1492
1493 if (m_videoRect.IsEmpty())
1494 m_videoIsScaled = false;
1495 else
1496 m_videoIsScaled = true;
1497
1498 LOGDEBUG("videorender: %s: %d %d %d %d%s", __FUNCTION__, rect.X(), rect.Y(), rect.Width(), rect.Height(), m_videoIsScaled ? ", video is scaled" : "");
1499}
1500
1505{
1506 for (Event event : m_eventQueue)
1508
1509 m_eventQueue.clear();
1510}
1511
1529
1530/*****************************************************************************
1531 * Buffer reuse strategy: use-once
1532 ****************************************************************************/
1534{
1535 cDrmBuffer *buf = pool->FindUninitilized();
1536
1537 if (buf)
1538 buf->SetDestroyAfterUse(true);
1539
1540 return buf;
1541}
1542
1543/*****************************************************************************
1544 * Buffer reuse strategy: reuse
1545 ****************************************************************************/
1547{
1548 cDrmBuffer *buf = pool->FindByDmaBufHandle(primedata->objects[0].fd);
1549
1550 if (buf)
1551 return buf;
1552 else
1553 return pool->FindUninitilized();
1554}
1555
1557{
1558 cDrmBuffer *buf = pool->FindNoPresentationPending();
1559
1560 if (buf)
1561 return buf;
1562 else
1563 return pool->FindUninitilized();
1564}
1565
1566/*****************************************************************************
1567 * Decoding strategy: software
1568 ****************************************************************************/
1570{
1571 if (!buf->IsDirty()) {
1572 buf->Setup(drmDeviceFd, inframe->width, inframe->height, DRM_FORMAT_NV12, nullptr, true);
1573
1574 int dmaBufHandle;
1576 LOGFATAL("videorender: %s: Failed to retrieve the Prime FD (%d): %m", __FUNCTION__, errno);
1577
1578 buf->SetDmaBufHandle(dmaBufHandle);
1579 }
1580
1581 for (int i = 0; i < inframe->height; ++i)
1582 memcpy(buf->Plane(0) + i * buf->Pitch(0), inframe->data[0] + i * inframe->linesize[0], inframe->linesize[0]);
1583
1584 for (int i = 0; i < inframe->height / 2; ++i)
1585 memcpy(buf->Plane(1) + i * buf->Pitch(1), inframe->data[1] + i * inframe->linesize[1], inframe->linesize[1]);
1586
1587 AVFrame *frame = av_frame_alloc();
1588 frame->pts = inframe->pts;
1589 frame->width = inframe->width;
1590 frame->height = inframe->height;
1591 frame->format = AV_PIX_FMT_DRM_PRIME;
1592 frame->sample_aspect_ratio = inframe->sample_aspect_ratio;
1593
1594 frame->format = AV_PIX_FMT_DRM_PRIME;
1596 primedata->objects[0].fd = buf->DmaBufHandle();
1597 frame->data[0] = (uint8_t *)primedata;
1599
1601
1602 return frame;
1603}
1604
1605/*****************************************************************************
1606 * Decoding strategy: hardware
1607 ****************************************************************************/
1609{
1610 if (!buf->IsDirty()) {
1612 buf->Setup(drmDeviceFd, frame->width, frame->height, 0, primedata, false);
1613 }
1614
1615 return frame;
1616}
Audio Interface Header File.
virtual void OnEventReceived(const Event &)=0
DRM Buffer: Get a Hardware Buffer to Reuse.
cDrmBuffer * GetBuffer(cDrmBufferPool *, AVDRMFrameDescriptor *) override
DRM Buffer: Get a Software Buffer to Reuse.
cDrmBuffer * GetBuffer(cDrmBufferPool *, AVDRMFrameDescriptor *) override
DRM Buffer: Get a Buffer to Use Once.
Definition videorender.h:97
cDrmBuffer * GetBuffer(cDrmBufferPool *, AVDRMFrameDescriptor *) override
Prepare DRM Buffer for Hardware Decoding.
AVFrame * PrepareDrmBuffer(cDrmBuffer *, int, AVFrame *) override
Prepare DRM Buffer for Software Decoding.
AVFrame * PrepareDrmBuffer(cDrmBuffer *, int, AVFrame *) override
DRM Buffer Pool.
Definition drmbuffer.h:145
void DestroyAllExcept(cDrmBuffer *)
Destroy all drm buffers except the given one.
DRM Buffer.
Definition drmbuffer.h:48
void MarkClean(void)
Definition drmbuffer.h:68
void SetSizeOnScreen(int x, int y, int w, int h)
Definition drmbuffer.h:102
uint32_t Pitch(int idx)
Definition drmbuffer.h:92
void Setup(int, uint32_t, uint32_t, uint32_t, AVDRMFrameDescriptor *, bool)
Setup the buffer.
uint32_t Width(void)
Definition drmbuffer.h:60
uint32_t Height(void)
Definition drmbuffer.h:62
uint8_t * Plane(int idx)
Definition drmbuffer.h:85
void MarkDirty(void)
Definition drmbuffer.h:69
void FillBlack(void)
Color the buffer black.
AVFrame * frame
associated AVFrame
Definition drmbuffer.h:99
int Id(void)
Definition drmbuffer.h:73
bool IsDirty(void)
Definition drmbuffer.h:67
void PresentationFinished(void)
The presentation of this buffer has finished.
void Destroy(void)
Clear and destroy the buffer object and its parameters.
Definition drmbuffer.cpp:90
void SetDestroyAfterUse(bool val)
Definition drmbuffer.h:100
DRM Device.
Definition drmdevice.h:83
int SetConnectorHdrOutputMetadata(drmModeAtomicReqPtr, uint32_t)
uint64_t OsdHeight(void)
Definition drmdevice.h:101
int ModeAtomicCommit(drmModeAtomicReqPtr req, uint32_t flags, void *user_data)
Definition drmdevice.h:132
int InitGbm(void)
Init gbm device and surface.
cDrmBuffer * GetBufFromBo(struct gbm_bo *)
Get a drm buffer from a gbm buffer object.
EGLDisplay EglDisplay(void)
Definition drmdevice.h:115
void ModeAtomicFree(drmModeAtomicReqPtr req)
Definition drmdevice.h:133
int SetConnectorColorspace(drmModeAtomicReqPtr, uint32_t)
int InitEGL(void)
Init EGL context.
int CreateModeBlob(uint32_t *)
drmModeAtomicReqPtr ModeAtomicAlloc(void)
Definition drmdevice.h:131
int Fd(void)
Definition drmdevice.h:92
int GetVideoPlaneColorRange(uint64_t *)
int DestroyHdrBlob(uint32_t)
int SetVideoPlaneColorEncoding(drmModeAtomicReqPtr, uint32_t)
bool HasPipPlane(void)
Definition drmdevice.h:111
EGLSurface EglSurface(void)
Definition drmdevice.h:114
int SetCrtcModeId(drmModeAtomicReqPtr, uint32_t)
uint64_t DisplayHeight(void)
Definition drmdevice.h:99
int HandleEvent(void)
Poll for a drm event.
bool CanHandleMode(sDrmMode *)
Return true, if the given mode is one of the collected ones.
int DestroyModeBlob(uint32_t)
uint64_t DisplayWidth(void)
Definition drmdevice.h:98
uint64_t ZposPrimary(void)
Definition drmdevice.h:106
int CreateHdrBlob(struct hdr_output_metadata *, size_t, uint32_t *)
struct gbm_surface * GbmSurface(void)
Definition drmdevice.h:118
uint64_t ZposOverlay(void)
Definition drmdevice.h:105
int SetConnectorHdrBlobProperty(uint32_t)
cDrmPlane * PipPlane(void)
Definition drmdevice.h:110
void SaveCrtc(void)
Save information of a CRTC.
int ReInit(void)
Re-Init the drm device with a new connector mode.
uint32_t CrtcId(void)
Definition drmdevice.h:103
void RestoreCrtc(void)
Restore information of a CRTC.
void Close(void)
Close the drm file handle.
cDrmPlane * OsdPlane(void)
Definition drmdevice.h:108
int SetConnectorCrtcId(drmModeAtomicReqPtr)
cDrmPlane * VideoPlane(void)
Definition drmdevice.h:109
uint32_t ConnectorId(void)
Definition drmdevice.h:96
int SetCrtcActive(drmModeAtomicReqPtr, uint32_t)
uint64_t OsdWidth(void)
Definition drmdevice.h:100
int Init(void)
Initiate the drm device.
bool CanHandleHdr(void)
Definition drmdevice.h:127
int SetVideoPlaneColorRange(drmModeAtomicReqPtr, uint32_t)
void InitEvent(void)
Init the event context.
int UseZpos(void)
Definition drmdevice.h:104
DRM Plane.
Definition drmplane.h:23
void FreeProperties(void)
Free the previously filled plane properties.
Definition drmplane.cpp:53
uint32_t GetId(void)
Definition drmplane.h:39
void Clear(void)
Clear the grab buffer (input and output data)
Definition grab.cpp:429
void Set(cDrmBuffer *)
Set the grab buffer and the dimensions how it is presented on the screen.
Definition grab.cpp:443
int GetColorPrimaries(void)
Definition drmhdr.h:113
int Build(struct hdr_output_metadata *, int, int, AVFrameSideData *, AVFrameSideData *)
Build an HDR static metadata blob.
Definition drmhdr.cpp:58
void Clear(void)
Remove all elements from the queue.
Definition queue.h:88
T * Pop(void)
Pop an element from the back of the queue.
Definition queue.h:57
bool IsEmpty(void)
Check if the queue is empty.
Definition queue.h:99
bool IsFull(void)
Check if the queue is full.
Definition queue.h:110
size_t Size(void)
Get the current size of the queue.
Definition queue.h:121
int64_t GetInputPtsMs(void)
Definition audio.h:71
int GetUsedRingbufferMs(void)
Get used ms in audio ringbuffer.
Definition audio.cpp:755
int64_t GetHardwareOutputPtsMs(void)
Get the hardware output PTS in milliseconds.
Definition audio.cpp:795
int GetAvResyncBorderMs(void)
Definition audio.h:73
void DropSamplesOlderThanPtsMs(int64_t)
Drop samples older than the given PTS.
Definition audio.cpp:421
void SetPaused(bool)
Set audio playback pause state.
Definition audio.cpp:868
bool IsPaused(void)
Definition audio.h:59
int64_t GetHardwareOutputDelayMs(void)
Get the hardware delay in milliseconds.
Definition audio.cpp:815
int GetUsedRingbufferBytes(void)
Get used bytes in audio ringbuffer.
Definition audio.cpp:745
int ConfigDisableOglOsd
config disable ogl osd
Definition config.h:120
int ConfigPipAltTopPercent
0 = aligned to top, 100 = aligned to bottom
Definition config.h:90
int ConfigPipLeftPercent
0 = aligned to left, 100 = aligned to right
Definition config.h:84
int ConfigPipAltLeftPercent
0 = aligned to left, 100 = aligned to right
Definition config.h:89
int ConfigPipAltScalePercent
alternative scale factor of pip video
Definition config.h:88
int ConfigShowChannelSwitchDurationMessage
let the skin show a short message about the channel switch duration
Definition config.h:108
int ConfigPipTopPercent
0 = aligned to top, 100 = aligned to bottom
Definition config.h:85
int ConfigPipScalePercent
scale factor of pip video
Definition config.h:83
int ConfigPipUseAlt
Definition config.h:86
Output Device Implementation.
void SetScreenSize(int, int)
Set the screen size.
int GetVideoAudioDelayMs(void)
void SetDrmCanDisplayPip(bool canDisplay)
bool IsBufferingThresholdReached(void)
Check if the buffering threshold has been reached.
void SetOsdSize(int, int)
Set the OSD size.
std::chrono::steady_clock::time_point GetChannelSwitchFirstPacketTime(void)
cVideoStream * VideoStream(void)
std::chrono::steady_clock::time_point GetChannelSwitchStartTime(void)
bool IsVideoOnlyPlayback(void)
void SetDisplayMode(int)
Trigger a display mode change event if the mode changed.
void PushPipFrame(AVFrame *)
Push a PiP frame into the render ringbuffer.
void SetFrameFlags(AVFrame *, int)
Set frame flags.
int m_numWrongProgressive
counter for progressive frames sent in an interlaced stream (only used for logging)
int DrmHandleEvent(void)
Wrapper for drmHandleEvent()
bool IsOutputBufferFull(void)
Check, if the main render output buffer is full.
int m_framesDuped
number of frames duplicated
void SetHdrBlob(struct hdr_output_metadata)
Create an hdr blob and set it for the connector.
void InitBuffers(void)
Init the osd and black buffer.
bool m_osdShown
set, if osd is shown currently
cCondVar m_grabCond
condition gets signalled, if renederer finished to clone the grabbed buffers
cDrmBuffer * m_pCurrentlyDisplayed
pointer to currently displayed DRM buffer
int m_pipScalePercent
scale factor for pip
struct gbm_bo * m_pOldBo
pointer to old gbm buffer object (for later free)
std::atomic< bool > m_resumeAudioScheduled
set, if audio resume is scheduled after a pause
int m_flipCounter
page flip counter
struct gbm_bo * m_bo
pointer to current gbm buffer object
void SetScreenSize(int, int, double, bool)
Wrapper to set the screen size in the device.
void Reset()
Reset the renderer.
void PushFrame(AVFrame *, bool, std::atomic< cBufferStrategy * > &, std::atomic< cDecodingStrategy * > &, cQueue< cDrmBuffer > *, cDrmBufferPool *, bool)
Push the frame into the render ringbuffer.
bool CanHandleHdr(void)
Return true, if the device can handle HDR.
void SetDisplayMode(int)
Wrapper to set the display mode.
std::atomic< bool > m_forwardTrickspeed
true, if trickspeed plays forward
std::atomic< bool > m_displayOneFrameThenPause
set, if only one frame shall be displayed and then pause playback
std::vector< Event > m_eventQueue
event queue for incoming events
std::atomic< double > m_refreshRateHz
screen refresh rate in Hz
void CreateGrabBuffers(bool)
Copy current video, osd and pip buffers to dedicated grabbing buffers.
void ReInitDisplayMode(void)
Re-Initialize the drm device with current display mode settings.
int SetVideoBuffer(cDrmBuffer *)
Modesetting for video.
cDrmBufferPool m_pipDrmBufferPool
PIP pool of drm buffers.
cGrabBuffer m_grabVideo
keeps the current grabbed video
void ProcessEvents(void)
Process queued events and forward to event receiver.
int m_framesDropped
number of frames dropped
std::mutex m_grabMutex
mutex around grabbing
void OsdClear(void)
Clear the OSD (draw an empty/ transparent OSD)
std::atomic< int > m_framePresentationCounter
number of times the current frame has to be shown (for slow-motion)
std::atomic< bool > m_enableHdr
hdr is enabled
bool FrameDropNecessary(int64_t, int64_t)
Do the AV Sync.
std::atomic< bool > m_pipActive
true, if pip should be displayed
int SetOsdBuffer(drmModeAtomicReqPtr)
Modesetting for osd.
void ClearDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
void Init(void)
Initialize the renderer.
std::atomic< bool > m_videoPlaybackPaused
set, if playback is frozen (used for pause)
void Exit(void)
Exit and cleanup the renderer.
void SetColorSpace(drmColorRange)
Set kms color space, color encoding and color range.
std::atomic< int64_t > m_scheduleResyncAtPtsMs
if set, a resync (enter state BUFFERING) will be forced at the given pts
cQueue< cDrmBuffer > m_drmBufferQueue
queue for DRM buffers to be displayed (VIDEO_SURFACES_MAX is defined in thread.h)
cGrabBuffer m_grabPip
keeps the current grabbed pip video
~cVideoRender(void)
Destroy the video renderer.
cRect m_videoRect
rect of the currently displayed video
void GetStats(int *, int *, int *)
Get some rendering statistics.
std::atomic< cDecodingStrategy * > m_pipDecodingStrategy
strategy for decoding setup
std::atomic< cBufferStrategy * > m_bufferReuseStrategy
strategy to select drm buffers
void DisplayBlackFrame(void)
Display a black video frame.
bool IsStillpicture(void)
cSoftHdAudio * m_pAudio
pointer to cSoftHdAudio
AVRational m_timebase
timebase used for pts, set by first RenderFrame()
void PushMainFrame(AVFrame *)
Push a main frame into the render ringbuffer.
std::mutex m_mutex
mutex for thread control
void SetVideoOutputPosition(const cRect &)
Set size and position of the video on the screen.
cVideoRender(cSoftHdDevice *)
Create the video renderer.
int GetFrameFlags(AVFrame *)
Get frame flags.
int m_pipTopPercent
top margin for pip
cDrmBuffer * m_pBufOsd
pointer to osd drm buffer object
cHdrMetadata m_pHdrMetadata
hdr metadata object
std::mutex m_timebaseMutex
mutex used around m_timebase
std::atomic< bool > m_startgrab
internal flag to trigger grabbing
int64_t GetOutputPtsMs(void)
Get the output PTS in milliseconds.
void RestoreColorSpace(void)
Restore color space, color encoding and color range to BT709 and the original color range.
cSoftHdDevice * m_pDevice
pointer to cSoftHdDevice
void DeleteBuffers(void)
Delete the osd and black buffer.
std::atomic< cBufferStrategy * > m_pipBufferReuseStrategy
strategy to select drm buffers
cSoftHdConfig * m_pConfig
pointer to cSoftHdConfig
void ClearPipDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
int CommitBuffer(cDrmBuffer *, cDrmBuffer *)
Commit the frame to the hardware.
static constexpr int AV_SYNC_THRESHOLD_AUDIO_AHEAD_VIDEO_MS
threshold in ms, when to drop video frames to keep audio and video in sync
int TriggerGrab(void)
Trigger a screen grab.
void SetVideoClock(int64_t pts)
IEventReceiver * m_pEventReceiver
pointer to event receiver
cQueue< cDrmBuffer > m_pipDrmBufferQueue
queue for PIP DRM buffers to be displayed (VIDEO_SURFACES_MAX is defined in thread....
int SetPipBuffer(cDrmBuffer *)
Modesetting for pip.
void ClearGrabBuffers(void)
Clear the grab drm buffers.
virtual void Action(void)
Thread loop, which tries to display frames and processes events.
void LogDroppedDuped(int64_t, int64_t, int)
Log A/V sync debug message.
bool DisplayFrame()
Display the frame (video and/or osd)
int m_framesPerFlipCycle
number of pageflips over which a single video frame should be presented 1 in progressive display mode...
bool m_disableOglOsd
set, if ogl osd is disabled
void Stop(void)
Stop the thread.
bool m_colorRangeStored
true, if the original color range was stored
bool IsTrickSpeed(void)
bool m_hasDoneHdrModeset
true, if we ever created an hdr blob and did a modesetting
cDrmBuffer * m_pCurrentlyPipDisplayed
pointer to currently displayed DRM buffer
int64_t GetVideoClock(void)
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD ARGB image.
cDrmDevice * m_pDrmDevice
pointer cDrmDevice object
cGrabBuffer m_grabOsd
keeps the current grabbed osd
std::atomic< double > m_trickspeedFactor
current trick speed
int64_t PtsToMs(int64_t)
Convert a PTS to milliseconds.
std::atomic< int64_t > m_videoPlaybackPauseScheduledAt
if set, video will be paused at the given pts
void SetOsdSize(int, int)
Wrapper to set the osd size in the device.
std::atomic< cDecodingStrategy * > m_decodingStrategy
strategy for decoding setup
std::atomic< bool > m_trickspeed
true, if trickspeed is active
bool m_lastFrameWasDropped
true, if the last frame was dropped
void SetPipSize(bool)
Set the size and position of the pip window.
bool PageFlip(cDrmBuffer *, cDrmBuffer *)
Do the pageflip.
int m_pipLeftPercent
left margin for pip
cDrmBufferPool m_drmBufferPool
pool of drm buffers
drmColorRange m_originalColorRange
initial color range
std::atomic< int64_t > m_schedulePlaybackStartAtPtsMs
if set, frames with PTS older than this will be dropped
static constexpr int AV_SYNC_THRESHOLD_AUDIO_BEHIND_VIDEO_MS
Sync Corridor.
void ResetFrameCounter(void)
Send start condition to video thread.
int m_startCounter
counter for displayed frames, indicates a video start
bool CanHandleMode(sDrmMode *)
Wrapper to check, if drm can handle the display mode.
bool m_videoIsScaled
true, if the currently displayed video is scaled
struct gbm_bo * m_pNextBo
pointer to next gbm buffer object (for later free)
int GetFramePresentationCount(int64_t)
Get the number of times the current frame shall be presented in trickspeed mode.
void SetTrickSpeed(double, bool, bool)
Set the trickspeed parameters.
cDrmBuffer m_bufBlack
black drm buffer object
size_t GetAvPacketsFilled(void)
Definition videostream.h:70
Plugin Configuration Header File.
__attribute__((weak)) union gbm_bo_handle gbm_bo_get_handle_for_plane(struct gbm_bo *bo
DRM Device Header File.
HDR (High Dynamic Range) Header File.
State Machine and Event Header File.
Grabbing Interface Header File.
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:47
#define LOGDEBUG
log to LOG_DEBUG
Definition logger.h:45
#define LOGERROR
log to LOG_ERR
Definition logger.h:39
#define AV_NOPTS_VALUE
Definition misc.h:74
std::variant< PlayEvent, PauseEvent, StopEvent, TrickSpeedEvent, StillPictureEvent, DetachEvent, AttachEvent, BufferUnderrunEvent, BufferingThresholdReachedEvent, ScheduleResyncAtPtsMsEvent, ResyncEvent, DisplayChangeEvent > Event
Definition event.h:73
#define LOGWARNING
log to LOG_WARN
Definition logger.h:41
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:37
static const char * Timestamp2String(int64_t ts, uint8_t divisor)
Nice time-stamp string.
Definition misc.h:127
#define EGL_CHECK(stmt)
eglCheckError macro
Definition misc.h:62
@ L_PACKET
decoder packet/frame tracking logs
Definition logger.h:68
@ L_DRM
drm logs
Definition logger.h:60
@ L_AV_SYNC
audio/video sync logs
Definition logger.h:57
@ L_OSD
osd logs
Definition logger.h:59
@ L_TRICK
trickspeed logs
Definition logger.h:63
@ L_OPENGL
opengl osd logs
Definition logger.h:65
@ L_GRAB
grabbing logs
Definition logger.h:69
@ VIDEO
Definition event.h:30
Logger Header File.
Misc Functions.
Thread-safe Queue.
Output Device Header File.
Holds possible display configurations.
Definition config.h:30
uint64_t y
uint64_t x
uint64_t h
uint64_t w
#define MIN(a, b)
static void ReleaseFrame(__attribute__((unused)) void *opaque, uint8_t *data)
Callback free primedata if av_buffer is unreferenced.
static sRect ComputeFittedRect(AVFrame *frame, uint64_t dispX, uint64_t dispY, uint64_t dispWidth, uint64_t dispHeight)
Fits the video frame into a given area.
Video Renderer (Display) Header File.
@ COLORSPACE_BT2020_RGB
Definition videorender.h:66
@ COLORSPACE_BT709_YCC
Definition videorender.h:65
drmColorRange
Definition videorender.h:74
@ COLORRANGE_FULL
Definition videorender.h:76
@ COLORRANGE_LIMITED
Definition videorender.h:75
@ COLORENCODING_BT2020
Definition videorender.h:71
@ COLORENCODING_BT709
Definition videorender.h:70
Video Input Stream Header File.