vdr-plugin-softhddevice-drm-gles 1.6.2
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
66 : cThread("softhd display"),
67 m_pDevice(device),
68 m_pAudio(m_pDevice->Audio()),
69 m_pConfig(m_pDevice->Config()),
70 m_pDrmDevice(new cDrmDevice(this, m_pConfig->ConfigDisplayResolution)),
71 m_pEventReceiver(device),
72 m_pHdrMetadata(this),
73 m_enableHdr(m_pConfig->ConfigVideoEnableHDR)
74{
75#ifdef USE_GLES
77 m_bo = nullptr;
78 m_pNextBo = nullptr;
79 m_pOldBo = nullptr;
80#endif
81 m_timebase = av_make_q(1, 90000);
83}
84
89{
90 LOGDEBUG2(L_DRM, "videorender: %s", __FUNCTION__);
91
92 Stop();
93
94 delete m_pDrmDevice;
95}
96
108
119
126
139{
140 if (!frame || dispWidth == 0 || dispHeight == 0)
141 return { dispX, dispY, dispWidth, dispHeight };
142
143 double frameWidth = frame->width > 0 ? frame->width : 1.0;
144 double frameHeight = frame->height > 0 ? frame->height : 1.0;
145 double frameSar = av_q2d(frame->sample_aspect_ratio) ? av_q2d(frame->sample_aspect_ratio) : 1.0;
146 double dispAspect = static_cast<double>(dispWidth) / static_cast<double>(dispHeight);
148
149 double picWidthD = dispWidth;
150 double picHeightD = dispHeight;
151
152 if (dispAspect > frameAspect) {
153 // letterbox horizontally (frame narrower than display)
157 } else {
158 // pillarbox vertically (frame wider than display)
162 }
163
164 // round to the nearest pixel
165 uint64_t picWidth = std::llround(std::max(0.0, picWidthD));
166 uint64_t picHeight = std::llround(std::max(0.0, picHeightD));
167
168 int64_t offsetX = static_cast<int64_t>(dispWidth) - static_cast<int64_t>(picWidth);
169 int64_t offsetY = static_cast<int64_t>(dispHeight) - static_cast<int64_t>(picHeight);
170 uint64_t posX = dispX + static_cast<uint64_t>(std::max<int64_t>(0, offsetX / 2));
171 uint64_t posY = dispY + static_cast<uint64_t>(std::max<int64_t>(0, offsetY / 2));
172
173 return { posX, posY, picWidth, picHeight };
174}
175
182{
183 uint32_t blobID = 0;
184 if (m_pDrmDevice->CreateHdrBlob(&hdrData, sizeof(hdrData), &blobID)) {
185 LOGERROR("videorender: %s: HDR: Failed to create hdr property blob.", __FUNCTION__);
187 LOGERROR("videorender: %s: HDR: Failed to set hdr property", __FUNCTION__);
188 }
189
190 if (blobID)
192
193 if (!m_colorRangeStored) {
197 m_colorRangeStored = true;
198 }
199 }
200}
201
210{
213 uint32_t modeID = 0;
214
216 LOGFATAL("videorender: %s: Failed to create mode property blob.", __FUNCTION__);
218 LOGFATAL("videorender: %s: cannot allocate atomic request (%d): %m", __FUNCTION__, errno);
219
222 LOGFATAL("videorender: %s: cannot set atomic mode (%d): %m", __FUNCTION__, errno);
226
230
231 LOGDEBUG2(L_DRM, "videorender: %s: HDR: connector %d -> Colorspace %s", __FUNCTION__,
232 m_pDrmDevice->ConnectorId(), m_pHdrMetadata.GetColorPrimaries() == AVCOL_PRI_BT2020 ? "BT2020_RGB" : "BT709_YCC");
233
234 LOGDEBUG2(L_DRM, "videorender: %s: HDR: plane %d -> COLOR_ENCODING %s, COLOR_RANGE %s (Color %d)", __FUNCTION__,
235 m_pDrmDevice->VideoPlane()->GetId(), m_pHdrMetadata.GetColorPrimaries() == AVCOL_PRI_BT2020 ? "YCBCR_BT20202" : "YCBCR_BT709",
237
239 LOGFATAL("videorender: %s: cannot set atomic mode (%d): %m", __FUNCTION__, errno);
240
243
244 m_hasDoneHdrModeset = true;
245}
246
252{
255 uint32_t modeID = 0;
256
258 LOGFATAL("videorender: %s: Failed to create mode property blob.", __FUNCTION__);
260 LOGFATAL("videorender: %s: cannot allocate atomic request (%d): %m", __FUNCTION__, errno);
261
263
265 LOGFATAL("videorender: %s: cannot set atomic mode (%d): %m", __FUNCTION__, errno);
266
274
276 LOGFATAL("videorender: %s: cannot set atomic mode (%d): %m", __FUNCTION__, errno);
277
280
281 m_hasDoneHdrModeset = false;
282 m_colorRangeStored = false;
283}
284
294{
295 if (!buf)
296 return 1;
297
298 AVFrame *frame = buf->frame;
299
300 if (frame && m_enableHdr) {
304
305 if (!m_pHdrMetadata.Build(&hdrData, frame->color_primaries, frame->color_trc, sd1, sd2)) {
308 }
309 }
310
311 // set display dimensions as default
314 uint64_t dispX = 0;
315 uint64_t dispY = 0;
316
318
319 // get video size and position
320 if (m_videoIsScaled) {
321 dispWidth = m_videoRect.Width();
322 dispHeight = m_videoRect.Height();
323 dispX = m_videoRect.X();
324 dispY = m_videoRect.Y();
325 }
326
327 // fit frame into display
329
330 // now set the plane parameters
331 videoPlane->SetParams(m_pDrmDevice->CrtcId(), buf->Id(),
333 0, 0, buf->Width(), buf->Height());
334
335 buf->SetSizeOnScreen(fittedRect.x, fittedRect.y, fittedRect.w, fittedRect.h); // remember for grab
336
337 return 0;
338}
339
347{
348 if (!m_pBufOsd || !m_pBufOsd->IsDirty())
349 return 1;
350
353
354 // We had draw activity on the osd buffer
355 if (m_pDrmDevice->UseZpos()) {
358 videoPlane->SetPlaneZpos(modeReq);
359 osdPlane->SetPlaneZpos(modeReq);
360
361 LOGDEBUG2(L_DRM, "videorender: %s: SetPlaneZpos: video->plane_id %d -> zpos %" PRIu64 ", osd->plane_id %d -> zpos %" PRIu64 "", __FUNCTION__,
362 videoPlane->GetId(), videoPlane->GetZpos(),
363 osdPlane->GetId(), osdPlane->GetZpos());
364 }
365
368
369 // now set the plane parameters
370 osdPlane->SetParams(m_pDrmDevice->CrtcId(), m_pBufOsd->Id(),
371 0, 0, crtcW, crtcH,
372 0, 0, crtcW, crtcH);
373
374 m_pBufOsd->SetSizeOnScreen(0, 0, crtcW, crtcH); // remember for grab
375
377 return 0;
378}
379
389{
390 if (!buf || !m_pipActive || m_videoIsScaled)
391 return 1;
392
393 AVFrame *frame = buf->frame;
394
395 // set display dimensions as default
398 uint64_t dispX = 0;
399 uint64_t dispY = 0;
400
402
403 // Get video size and position
404 if (m_videoIsScaled) {
405 dispWidth = m_videoRect.Width();
406 dispHeight = m_videoRect.Height();
407 dispX = m_videoRect.X();
408 dispY = m_videoRect.Y();
409 }
410
411 // fit frame into display
413
414 // compute pip window with given scaling and positioning values from menu
415 int64_t centerOffsetX = static_cast<int64_t>(dispWidth) - static_cast<int64_t>(fittedRect.w);
416 int64_t centerOffsetY = static_cast<int64_t>(dispHeight) - static_cast<int64_t>(fittedRect.h);
417 centerOffsetX = std::max<int64_t>(0, centerOffsetX / 2);
418 centerOffsetY = std::max<int64_t>(0, centerOffsetY / 2);
419
420 double crtcWD = fittedRect.w * m_pipScalePercent / 100.0;
421 double crtcHD = fittedRect.h * m_pipScalePercent / 100.0;
422 uint64_t crtcW = std::llround(crtcWD);
423 uint64_t crtcH = std::llround(crtcHD);
424
425 double spaceW = dispWidth - crtcW - centerOffsetX;
427
428 uint64_t crtcX = dispX + std::llround(spaceW * m_pipLeftPercent / 100.0 + centerOffsetX * m_pipScalePercent / 100.0);
429 uint64_t crtcY = dispY + std::llround(spaceH * m_pipTopPercent / 100.0 + centerOffsetY * m_pipScalePercent / 100.0);
430
431 // now set the plane parameters
432 pipPlane->SetParams(m_pDrmDevice->CrtcId(), buf->Id(),
434 0, 0, buf->Width(), buf->Height());
435
436 buf->SetSizeOnScreen(crtcX, crtcY, crtcW, crtcH); // remember for grab
437
438 return 0;
439}
440
450{
451 enum modeSetLevel {
452 MODESET_OSD = (1 << 0),
453 MODESET_VIDEO = (1 << 1),
454 MODESET_PIP = (1 << 2)
455 };
456
457 int modeSet = 0;
463
465 LOGERROR("videorender: %s: cannot allocate atomic request (%d): %m", __FUNCTION__, errno);
466 return -1;
467 }
468
469 // handle the video plane
470 // If no new video is available, set the old buffer again, if available.
471 // This is necessary to recognize a size-change in SetVideoBuffer().
472 // Though this is not expensive, maybe we should only call that, if size really changed.
474 videoPlane->SetPlane(modeReq);
476// LOGDEBUG2(L_DRM, "videorender: %s: SetPlane Video (fb = %" PRIu64 ")", __FUNCTION__, videoPlane->GetFbId());
477 }
478
479 // handle the pip plane
480 if (pipPlane->GetId()) {
482 pipPlane->SetPlane(modeReq);
483 else
484 pipPlane->ClearPlane(modeReq);
485
487 }
488
489 // handle the osd plane
490 if (!SetOsdBuffer(modeReq)) {
491 osdPlane->SetPlane(modeReq);
493 LOGDEBUG2(L_DRM, "videorender: %s: SetPlane OSD %d (fb = %" PRIu64 ")", __FUNCTION__, m_osdShown, osdPlane->GetFbId());
494 }
495
496 // return without an atomic commit (no video frame and osd activity)
497 if (!modeSet) {
499 return -1;
500 }
501
502 // do the atomic commit
504 if (modeSet & MODESET_OSD)
505 osdPlane->DumpParameters("osd");
507 videoPlane->DumpParameters("video");
508 if (modeSet & MODESET_PIP)
509 pipPlane->DumpParameters("pip");
510
512 LOGERROR("videorender: %s: page flip failed (%d): %m", __FUNCTION__, errno);
513 return -1;
514 }
515
517
518 return 0;
519}
520
529{
530 LOGDEBUG2(L_AV_SYNC, "Frame %s (drop %d, dup %d) Pkts %d Frames %d UsedBytes %d audio %s video %s Delay %dms kernel buffer delay %dms diff %dms",
531 audioBehindVideoByMs > 0 ? "duped" : "dropped",
542
543 if (audioBehindVideoByMs > 0)
545 else
547
548}
549
558{
559 if (!frame || !frame->opaque_ref)
560 return 0;
561
562 int *frameFlags = (int *)frame->opaque_ref->data;
563 return *frameFlags;
564}
565
573{
574 int *frameFlags;
575 if (!frame->opaque_ref) {
576 frame->opaque_ref = av_buffer_allocz(sizeof(*frameFlags));
577 if (!frame->opaque_ref) {
578 LOGFATAL("videorender: %s: cannot allocate private frame data", __FUNCTION__);
579 }
580 }
581
582 frameFlags = (int *)frame->opaque_ref->data;
583 *frameFlags = flags;
584}
585
594{
595 if (CommitBuffer(buf, pipBuf) < 0) {
596 // no modesetting was done
597 if (buf && buf->frame)
598 av_frame_free(&buf->frame);
599 if (pipBuf && pipBuf->frame)
600 av_frame_free(&pipBuf->frame);
601
602 return false;
603 } else {
604 if (m_pDrmDevice->HandleEvent() != 0)
605 LOGERROR("threads: display thread: drmHandleEvent failed!");
606
607 // now, that we had a successful commit, set the STC if we have a frame. Skip if only the OSD was updated.
608 if (buf && buf->frame) {
609 if (buf->frame->pts != AV_NOPTS_VALUE)
610 SetVideoClock(buf->frame->pts);
611
612 LOGDEBUG2(L_PACKET, "videorender: %s: ID %d: PTS %s", __FUNCTION__, buf->Id(), Timestamp2String(buf->frame->pts, 90));
613 }
614
615 return true;
616 }
617}
618
619/*****************************************************************************
620 * Thread
621 ****************************************************************************/
622
627{
628 LOGDEBUG("videorender: display thread started");
629 while(Running()) {
630 m_mutex.lock();
631
633
634 m_mutex.unlock();
635
637
639 usleep(100); // yield thread. give control also to threads with lower priority.
640 else
641 usleep(1000);
642 }
643 LOGDEBUG("videorender: display thread stopped");
644}
645
650{
651 if (!Active())
652 return;
653
654 LOGDEBUG("videorender: stopping display thread");
655 Cancel(2);
656}
657
664{
667
671 IsTrickSpeed() ||
672 IsStillpicture() ||
676
677 cDrmBuffer *drmBuffer = nullptr;
680
682
683 bool pageFlipDone = false;
684 if (drmBuffer) {
687 int64_t interFrameGapMs = std::abs(PtsToMs(drmBuffer->frame->pts - m_pCurrentlyDisplayed->frame->pts));
689 } else
691 }
692
694 // check if playback shall start
696 drmBuffer->PresentationFinished();
697 return true;
698 } else {
700 m_videoPlaybackPaused = false;
701 }
702 } else if (!m_displayOneFrameThenPause && !IsStillpicture()) {
703 // A/V sync
705 int64_t videoPtsMs = PtsToMs(drmBuffer->frame->pts);
706
707 if (audioPtsMs != AV_NOPTS_VALUE) {
709
714
715 LOGDEBUG2(L_AV_SYNC, "videorender: resync schedule arrived at %s, current audio pts %s video pts %s",
717 m_eventQueue.push_back(ResyncEvent{});
719 }
720
722 LOGDEBUG2(L_AV_SYNC, "videorender: %s: pause was scheduled at %s)!", __FUNCTION__, Timestamp2String(videoPtsMs, 1));
725 } else if (m_resumeAudioScheduled && audioBehindVideoByMs >= 0 && !skipSync) { // resume audio from pause
726 LOGDEBUG2(L_AV_SYNC, "videorender: resuming audio playback: video %s, audio %s", Timestamp2String(videoPtsMs, 1), Timestamp2String(audioPtsMs, 1));
727 m_pAudio->SetPaused(false);
731 m_framePresentationCounter++; // display the current video frame one period longer
733 // Drop max every second frame. Otherwise, the buffer gets drained immediately, if multiple frames in a row are dropped.
735
736 if (pipBuf)
737 pipBuf->PresentationFinished();
738
739 drmBuffer->PresentationFinished();
740 m_framePresentationCounter--; // skip this pageflip
742
743 return true;
744 }
745
747 }
748
751 }
752
756 }
757
759 if (m_startCounter == 1 && m_pDevice->Transferring()) {
760 auto now = std::chrono::steady_clock::now();
761 auto channelSwitchDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_pDevice->GetChannelSwitchStartTime()).count();
762 auto durationSinceFirstPacketMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_pDevice->GetChannelSwitchFirstPacketTime()).count();
763 LOGDEBUG("channel switch done in %dms, %dms after first packet was received", channelSwitchDurationMs, durationSinceFirstPacketMs);
764 }
765
768
769 m_lastFrameWasDropped = false;
772 // display the current frame again in trick speed mode or for A/V syncing
774 } else if ((m_pBufOsd && m_pBufOsd->IsDirty()) || pipBuf) {
776 }
777
778 if (pipBuf) {
781
783 }
784
787
789
790 return pageFlipDone;
791}
792
794{
795 LOGDEBUG2(L_DRM, "videorender: %s: closing, set a black FB", __FUNCTION__);
796
798
802 m_pCurrentlyDisplayed = nullptr;
803 }
804}
805
807{
808 std::lock_guard<std::mutex> lock(m_timebaseMutex);
809
810 return pts * 1000 * av_q2d(m_timebase);
811}
812
817{
818 return m_pDrmDevice->HandleEvent();
819}
820
822{
823 return m_pDrmDevice->CanHandleHdr();
824}
825
826/*****************************************************************************
827 * OSD
828 ****************************************************************************/
829
834{
835#ifdef USE_GLES
836 if (m_disableOglOsd) {
837 memset((void *)m_pBufOsd->Plane(0), 0,
838 (size_t)(m_pBufOsd->Pitch(0) * m_pBufOsd->Height()));
839 } else {
841
845
847 if (!buf) {
848 LOGERROR("videorender: %s: Failed to get GL buffer", __FUNCTION__);
849 return;
850 }
851
852 m_pBufOsd = buf;
853
854 // release old buffer for writing again
855 if (m_bo)
857
858 // rotate bos and create and keep bo as m_pOldBo to make it free'able
859 m_pOldBo = m_bo;
860 m_bo = m_pNextBo;
861
862 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));
863 }
864#else
865 memset((void *)m_pBufOsd->Plane(0), 0,
866 (size_t)(m_pBufOsd->Pitch(0) * m_pBufOsd->Height()));
867#endif
868
870 m_osdShown = false;
871}
872
873#define MIN(a, b) ((a) < (b) ? (a) : (b))
874
888 int width, int height, int pitch,
889 const uint8_t * argb, int x, int y)
890{
891#ifdef USE_GLES
892 if (m_disableOglOsd) {
893 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__,
894 width, height, pitch, argb, x, y, m_pBufOsd->Pitch(0), xi, yi);
895 for (int i = 0; i < height; ++i) {
896 memcpy(m_pBufOsd->Plane(0) + x * 4 + (i + y) * m_pBufOsd->Pitch(0),
897 argb + i * pitch, MIN((size_t)pitch, m_pBufOsd->Pitch(0)));
898 }
899 } else {
901
905
907 if (!buf) {
908 LOGERROR("videorender: %s: Failed to get GL buffer", __FUNCTION__);
909 return;
910 }
911
912 m_pBufOsd = buf;
913
914 // release old buffer for writing again
915 if (m_bo)
917
918 // rotate bos and create and keep bo as m_pOldBo to make it free'able
919 m_pOldBo = m_bo;
920 m_bo = m_pNextBo;
921
922 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));
923 }
924#else
925 // suppress unused variable warnings ...
926 (void) xi;
927 (void) yi;
928 (void) width;
929
930 for (int i = 0; i < height; ++i) {
931 memcpy(m_pBufOsd->Plane(0) + x * 4 + (i + y) * m_pBufOsd->Pitch(0),
932 argb + i * pitch, (size_t)pitch);
933 }
934#endif
936 m_osdShown = true;
937}
938
942static void ReleaseFrame( __attribute__ ((unused)) void *opaque, uint8_t *data)
943{
945
947}
948
958
966
974
979 AVFrame *frame,
980 bool trickspeed,
981 std::atomic<cBufferStrategy*> &bufferReuseStrategy,
982 std::atomic<cDecodingStrategy*> &decodingStrategy,
985{
986 if (bufferReuseStrategy == nullptr) {
987 if (trickspeed)
989 else if (frame->format == AV_PIX_FMT_DRM_PRIME)
991 else
993 }
994
995 if (decodingStrategy == nullptr) {
996 if (frame->format == AV_PIX_FMT_DRM_PRIME)
998 else
1000 }
1001
1002 // 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.
1003 //
1004 // @note: This is the only place outside of the display thread, where the video pts is set
1005 // (except setting it to AV_NOPTS_VALUE in cSofthdDevice::Clear() and SetState(STOP))
1006 // We only store here, if the stream recently started and the clock wasn't set already in the display thread
1007
1008 if (GetVideoClock() == AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE)
1009 SetVideoClock(frame->pts);
1010
1013
1014 if (!buf)
1015 LOGFATAL("videorender: %s: no free DRM buffer found. This is a bug.", __FUNCTION__);
1016
1017 frame = decodingStrategy.load()->PrepareDrmBuffer(buf, m_pDrmDevice->Fd(), frame);
1018
1019 buf->frame = frame;
1020 buf->SetPresentationPending(true);
1021
1022 drmBufferQueue->Push(buf);
1023}
1024
1033{
1035 return AV_NOPTS_VALUE;
1036
1037 std::lock_guard<std::mutex> lock(m_timebaseMutex);
1038
1039 return GetVideoClock() * 1000 * av_q2d(m_timebase);
1040}
1041
1046{
1047 m_startCounter = 0;
1048 LOGDEBUG("videorender: %s: reset m_startCounter %d TrickSpeed %d", __FUNCTION__, m_startCounter, IsTrickSpeed());
1049}
1050
1055{
1056 m_startCounter = 0;
1057 m_framesDuped = 0;
1058 m_framesDropped = 0;
1061
1062 delete m_decodingStrategy;
1063 m_decodingStrategy = nullptr;
1064}
1065
1073void cVideoRender::SetTrickSpeed(double speed, bool active, bool forward)
1074{
1075 LOGDEBUG2(L_TRICK, "videorender: %s: set trick speed %.3f %s %s", __FUNCTION__, speed, speed > 1.0 ? "fast" : "slow", forward ? "forward" : "backward");
1077 m_trickspeedFactor = speed;
1078 m_trickspeed = active;
1079 m_forwardTrickspeed = forward;
1080}
1081
1090{
1091 if (!IsTrickSpeed())
1092 return 1;
1093
1094 // Calculate the expected number of display refreshes for this frame
1095 double interFrameGapSec = interFrameGapMs / 1000.0;
1096 double refreshPeriodSec = 1.0 / m_refreshRateHz;
1097 int displayCount = std::max(1, static_cast<int>(std::round(interFrameGapSec / refreshPeriodSec / m_trickspeedFactor)));
1098
1099 return displayCount;
1100}
1101
1102/*****************************************************************************
1103 * Grabbing
1104 ****************************************************************************/
1105
1113{
1114 int timeoutMs = 50;
1115 cMutex mutex;
1116 mutex.Lock();
1117 m_startgrab = true;
1118 int err = 0;
1119
1120 if (!m_grabCond.TimedWait(mutex, timeoutMs)) {
1121 LOGWARNING("videorender: %s: timed out after %dms", __FUNCTION__, timeoutMs);
1122 err = 1;
1123 }
1124
1125 m_startgrab = false;
1126 return err;
1127}
1128
1135{
1136 if (!m_startgrab)
1137 return;
1138
1139 if (m_pBufOsd && m_osdShown) {
1140 LOGDEBUG2(L_GRAB, "videorender: %s: Trigger osd grab arrived", __FUNCTION__);
1143 }
1144
1146 if (pbuf) {
1147 LOGDEBUG2(L_GRAB, "videorender: %s: Trigger video grab arrived", __FUNCTION__);
1150 }
1151
1153 if (pipBuf && grabPip) {
1154 LOGDEBUG2(L_GRAB, "videorender: %s: Trigger pip grab arrived", __FUNCTION__);
1157 }
1158
1159 m_grabCond.Broadcast();
1160}
1161
1174
1183{
1187}
1188
1189/*****************************************************************************
1190 * Setup and initialization
1191 ****************************************************************************/
1192
1200void cVideoRender::SetScreenSize(int width, int height, double refreshRateHz)
1201{
1203 m_pDevice->SetScreenSize(width, height, refreshRateHz);
1204}
1205
1210{
1211 if (m_pDrmDevice->Init())
1212 LOGFATAL("videorender: %s: failed", __FUNCTION__);
1213
1215
1218
1219 // osd FB
1220#ifndef USE_GLES
1221 if (!m_pBufOsd)
1222 m_pBufOsd = new cDrmBuffer();
1223
1225#else
1226 if (m_disableOglOsd) {
1227 if (!m_pBufOsd)
1228 m_pBufOsd = new cDrmBuffer();
1229
1231 }
1232#endif
1233
1234 // black fb
1235 LOGDEBUG2(L_DRM, "videorender: %s: Try to create a black FB", __FUNCTION__);
1238
1239 // save actual modesetting
1241
1244 uint32_t modeID = 0;
1245
1247 LOGFATAL("videorender: %s: Failed to create mode property blob.", __FUNCTION__);
1249 LOGFATAL("videorender: %s: cannot allocate atomic request (%d): %m", __FUNCTION__, errno);
1250
1254
1255 // Osd plane
1256 // 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,
1257 // but initially move the OSD behind the VIDEO
1258#ifndef USE_GLES
1259 osdPlane->SetParams(m_pDrmDevice->CrtcId(), m_pBufOsd->Id(),
1261 0, 0, m_pBufOsd->Width(), m_pBufOsd->Height());
1262
1263 osdPlane->SetPlane(modeReq);
1264#else
1265 if (m_disableOglOsd) {
1266 osdPlane->SetParams(m_pDrmDevice->CrtcId(), m_pBufOsd->Id(),
1268 0, 0, m_pBufOsd->Width(), m_pBufOsd->Height());
1269
1270 osdPlane->SetPlane(modeReq);
1271 }
1272#endif
1273 if (m_pDrmDevice->UseZpos()) {
1274 videoPlane->SetZpos(m_pDrmDevice->ZposOverlay());
1275 videoPlane->SetPlaneZpos(modeReq);
1276#ifdef USE_GLES
1277 osdPlane->SetZpos(m_pDrmDevice->ZposPrimary());
1278 osdPlane->SetPlaneZpos(modeReq);
1279#endif
1280 }
1281
1282 // Black buffer for video plane
1283 videoPlane->SetParams(m_pDrmDevice->CrtcId(), m_bufBlack.Id(),
1285 0, 0, m_bufBlack.Width(), m_bufBlack.Height());
1286
1287 videoPlane->SetPlane(modeReq);
1288
1290#ifndef USE_GLES
1291 osdPlane->DumpParameters("osd");
1292#endif
1293 videoPlane->DumpParameters("video");
1294
1296 LOGFATAL("videorender: %s: cannot set atomic mode (%d): %m", __FUNCTION__, errno);
1297 }
1298
1300
1301 m_osdShown = false;
1302
1303 // init variables page flip
1305
1306 Start();
1307}
1308
1313{
1314 LOGDEBUG("videorender: %s", __FUNCTION__);
1315
1318
1319 Reset();
1320 Stop();
1321
1322 // restore saved CRTC configuration
1324
1327
1328 videoPlane->FreeProperties();
1329 osdPlane->FreeProperties();
1330
1332#ifdef USE_GLES
1333 if (m_disableOglOsd) {
1334 if (m_pBufOsd) {
1335 m_pBufOsd->Destroy();
1336 delete m_pBufOsd;
1337 }
1338 } else {
1339 if (m_pNextBo)
1341 if (m_pOldBo)
1343 }
1344#else
1345 if (m_pBufOsd) {
1346 m_pBufOsd->Destroy();
1347 delete m_pBufOsd;
1348 }
1349#endif
1350
1352}
1353
1360{
1361 m_videoRect.Set(rect.Point(), rect.Size());
1362
1363 if (m_videoRect.IsEmpty())
1364 m_videoIsScaled = false;
1365 else
1366 m_videoIsScaled = true;
1367
1368 LOGDEBUG("videorender: %s: %d %d %d %d%s", __FUNCTION__, rect.X(), rect.Y(), rect.Width(), rect.Height(), m_videoIsScaled ? ", video is scaled" : "");
1369}
1370
1375{
1376 for (Event event : m_eventQueue)
1378
1379 m_eventQueue.clear();
1380}
1381
1399
1400/*****************************************************************************
1401 * Buffer reuse strategy: use-once
1402 ****************************************************************************/
1404{
1405 cDrmBuffer *buf = pool->FindUninitilized();
1406
1407 if (buf)
1408 buf->SetDestroyAfterUse(true);
1409
1410 return buf;
1411}
1412
1413/*****************************************************************************
1414 * Buffer reuse strategy: reuse
1415 ****************************************************************************/
1417{
1418 cDrmBuffer *buf = pool->FindByDmaBufHandle(primedata->objects[0].fd);
1419
1420 if (buf)
1421 return buf;
1422 else
1423 return pool->FindUninitilized();
1424}
1425
1427{
1428 cDrmBuffer *buf = pool->FindNoPresentationPending();
1429
1430 if (buf)
1431 return buf;
1432 else
1433 return pool->FindUninitilized();
1434}
1435
1436/*****************************************************************************
1437 * Decoding strategy: software
1438 ****************************************************************************/
1440{
1441 if (!buf->IsDirty()) {
1442 buf->Setup(drmDeviceFd, inframe->width, inframe->height, DRM_FORMAT_NV12, nullptr, true);
1443
1444 int dmaBufHandle;
1446 LOGFATAL("videorender: %s: Failed to retrieve the Prime FD (%d): %m", __FUNCTION__, errno);
1447
1448 buf->SetDmaBufHandle(dmaBufHandle);
1449 }
1450
1451 for (int i = 0; i < inframe->height; ++i)
1452 memcpy(buf->Plane(0) + i * buf->Pitch(0), inframe->data[0] + i * inframe->linesize[0], inframe->linesize[0]);
1453
1454 for (int i = 0; i < inframe->height / 2; ++i)
1455 memcpy(buf->Plane(1) + i * buf->Pitch(1), inframe->data[1] + i * inframe->linesize[1], inframe->linesize[1]);
1456
1457 AVFrame *frame = av_frame_alloc();
1458 frame->pts = inframe->pts;
1459 frame->width = inframe->width;
1460 frame->height = inframe->height;
1461 frame->format = AV_PIX_FMT_DRM_PRIME;
1462 frame->sample_aspect_ratio = inframe->sample_aspect_ratio;
1463
1464 frame->format = AV_PIX_FMT_DRM_PRIME;
1466 primedata->objects[0].fd = buf->DmaBufHandle();
1467 frame->data[0] = (uint8_t *)primedata;
1469
1471
1472 return frame;
1473}
1474
1475/*****************************************************************************
1476 * Decoding strategy: hardware
1477 ****************************************************************************/
1479{
1480 if (!buf->IsDirty()) {
1482 buf->Setup(drmDeviceFd, frame->width, frame->height, 0, primedata, false);
1483 }
1484
1485 return frame;
1486}
1487
Audio and Alsa Interface Header File.
virtual void OnEventReceived(const Event &)=0
DRM Buffer: Get a Hardware Buffer to Reuse.
Definition videorender.h:97
DRM Buffer: Get a Software Buffer to Reuse.
DRM Buffer: Get a Buffer to Use Once.
Definition videorender.h:89
Prepare DRM Buffer for Hardware Decoding.
Prepare DRM Buffer for Software Decoding.
DRM Buffer Pool.
Definition drmbuffer.h:138
DRM Buffer.
Definition drmbuffer.h:47
void MarkClean(void)
Definition drmbuffer.h:68
void SetSizeOnScreen(int x, int y, int w, int h)
Definition drmbuffer.h:98
uint32_t Pitch(int idx)
Definition drmbuffer.h:89
uint32_t Width(void)
Definition drmbuffer.h:60
uint32_t Height(void)
Definition drmbuffer.h:62
uint8_t * Plane(int idx)
Definition drmbuffer.h:82
void MarkDirty(void)
Definition drmbuffer.h:69
AVFrame * frame
associated AVFrame
Definition drmbuffer.h:95
int Id(void)
Definition drmbuffer.h:73
bool IsDirty(void)
Definition drmbuffer.h:67
void SetDestroyAfterUse(bool val)
Definition drmbuffer.h:96
DRM Device.
Definition drmdevice.h:41
int ModeAtomicCommit(drmModeAtomicReqPtr req, uint32_t flags, void *user_data)
Definition drmdevice.h:84
EGLDisplay EglDisplay(void)
Definition drmdevice.h:68
void ModeAtomicFree(drmModeAtomicReqPtr req)
Definition drmdevice.h:85
drmModeAtomicReqPtr ModeAtomicAlloc(void)
Definition drmdevice.h:83
int Fd(void)
Definition drmdevice.h:47
bool HasPipPlane(void)
Definition drmdevice.h:64
EGLSurface EglSurface(void)
Definition drmdevice.h:67
uint64_t DisplayHeight(void)
Definition drmdevice.h:54
uint64_t DisplayWidth(void)
Definition drmdevice.h:53
uint64_t ZposPrimary(void)
Definition drmdevice.h:59
struct gbm_surface * GbmSurface(void)
Definition drmdevice.h:71
uint64_t ZposOverlay(void)
Definition drmdevice.h:58
cDrmPlane * PipPlane(void)
Definition drmdevice.h:63
uint32_t CrtcId(void)
Definition drmdevice.h:56
cDrmPlane * OsdPlane(void)
Definition drmdevice.h:61
cDrmPlane * VideoPlane(void)
Definition drmdevice.h:62
uint32_t ConnectorId(void)
Definition drmdevice.h:51
bool CanHandleHdr(void)
Definition drmdevice.h:80
int UseZpos(void)
Definition drmdevice.h:57
DRM Plane.
Definition drmplane.h:26
uint32_t GetId(void)
Definition drmplane.h:42
cDrmBuffer * GetDrmBuf(void)
Definition grab.h:66
int GetColorPrimaries(void)
Definition drmhdr.h:109
void Clear(void)
Remove all elements from the queue.
Definition queue.h:91
T * Pop(void)
Pop an element from the back of the queue.
Definition queue.h:60
bool IsEmpty(void)
Check if the queue is empty.
Definition queue.h:102
bool IsFull(void)
Check if the queue is full.
Definition queue.h:113
size_t Size(void)
Get the current size of the queue.
Definition queue.h:124
int GetAvResyncBorderMs(void)
Definition audio.h:68
bool IsPaused(void)
Definition audio.h:54
int ConfigDisableOglOsd
config disable ogl osd
Definition config.h:38
int ConfigPipAltTopPercent
0 = aligned to top, 100 = aligned to bottom
Definition config.h:78
int ConfigPipLeftPercent
0 = aligned to left, 100 = aligned to right
Definition config.h:71
int ConfigPipAltLeftPercent
0 = aligned to left, 100 = aligned to right
Definition config.h:77
int ConfigPipAltScalePercent
alternative scale factor of pip video
Definition config.h:76
int ConfigPipTopPercent
0 = aligned to top, 100 = aligned to bottom
Definition config.h:72
int ConfigPipScalePercent
scale factor of pip video
Definition config.h:70
int ConfigPipUseAlt
Definition config.h:74
Output Device Implementation.
int GetVideoAudioDelayMs(void)
void SetDrmCanDisplayPip(bool canDisplay)
std::chrono::steady_clock::time_point GetChannelSwitchFirstPacketTime(void)
cVideoStream * VideoStream(void)
std::chrono::steady_clock::time_point GetChannelSwitchStartTime(void)
bool IsVideoOnlyPlayback(void)
int m_numWrongProgressive
counter for progressive frames sent in an interlaced stream (only used for logging)
int m_framesDuped
number of frames duplicated
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
struct gbm_bo * m_bo
pointer to current gbm buffer object
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
cDrmBufferPool m_pipDrmBufferPool
PIP pool of drm buffers.
cGrabBuffer m_grabVideo
keeps the current grabbed video
int m_framesDropped
number of frames dropped
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
double m_refreshRateHz
screen refresh rate in Hz
std::atomic< bool > m_pipActive
true, if pip should be displayed
std::atomic< bool > m_videoPlaybackPaused
set, if playback is frozen (used for pause)
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
cRect m_videoRect
rect of the currently displayed video
bool m_startgrab
internal flag to trigger grabbing
std::atomic< cDecodingStrategy * > m_pipDecodingStrategy
strategy for decoding setup
std::atomic< cBufferStrategy * > m_bufferReuseStrategy
strategy to select drm buffers
bool IsStillpicture(void)
cSoftHdAudio * m_pAudio
pointer to cSoftHdAudio
AVRational m_timebase
timebase used for pts, set by first RenderFrame()
std::mutex m_mutex
mutex for thread control
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
cSoftHdDevice * m_pDevice
pointer to cSoftHdDevice
std::atomic< cBufferStrategy * > m_pipBufferReuseStrategy
strategy to select drm buffers
cSoftHdConfig * m_pConfig
pointer to cSoftHdConfig
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....
bool m_disableOglOsd
set, if ogl osd is disabled
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)
cDrmDevice * m_pDrmDevice
pointer cDrmDevice object
cGrabBuffer m_grabOsd
keeps the current grabbed osd
std::atomic< double > m_trickspeedFactor
current trick speed
std::atomic< int64_t > m_videoPlaybackPauseScheduledAt
if set, video will be paused at the given pts
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
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
int m_startCounter
counter for displayed frames, indicates a video start
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)
cDrmBuffer m_bufBlack
black drm buffer object
size_t GetAvPacketsFilled(void)
Definition videostream.h:80
Plugin Configuration Header File.
DRM Device Header File.
HDR (High Dynamic Range) Header File.
State Machine and Event Header File.
std::variant< PlayEvent, PauseEvent, StopEvent, TrickSpeedEvent, StillPictureEvent, DetachEvent, AttachEvent, BufferUnderrunEvent, BufferingThresholdReachedEvent, PipEvent, ScheduleResyncAtPtsMsEvent, ResyncEvent > Event
Definition event.h:80
@ VIDEO
Definition event.h:26
Grabbing Interface Header File.
int64_t GetHardwareOutputPtsMs(void)
Get the hardware output PTS in milliseconds.
Definition audio.cpp:923
void DropSamplesOlderThanPtsMs(int64_t)
Drop samples older than the given PTS.
Definition audio.cpp:576
int GetUsedBytes(void)
Get used bytes in audio ringbuffer.
Definition audio.cpp:884
void SetPaused(bool)
Set audio playback pause state.
Definition audio.cpp:1001
int64_t GetHardwareOutputDelayMs(void)
Get the hardware delay in milliseconds.
Definition audio.cpp:945
bool IsBufferingThresholdReached(void)
Check if the buffering threshold has been reached.
void SetScreenSize(int, int, double)
Set the screen size.
int SetConnectorHdrOutputMetadata(drmModeAtomicReqPtr, uint32_t)
cDrmBuffer * GetBufFromBo(struct gbm_bo *)
Get a drm buffer from a gbm buffer object.
void Setup(int, uint32_t, uint32_t, uint32_t, AVDRMFrameDescriptor *, bool)
Setup the buffer.
int SetConnectorColorspace(drmModeAtomicReqPtr, uint32_t)
int CreateModeBlob(uint32_t *)
int GetVideoPlaneColorRange(uint64_t *)
int DestroyHdrBlob(uint32_t)
int SetVideoPlaneColorEncoding(drmModeAtomicReqPtr, uint32_t)
int SetCrtcModeId(drmModeAtomicReqPtr, uint32_t)
int HandleEvent(void)
Poll for a drm event.
int DestroyModeBlob(uint32_t)
int CreateHdrBlob(struct hdr_output_metadata *, size_t, uint32_t *)
void FillBlack(void)
Color the buffer black.
int SetConnectorHdrBlobProperty(uint32_t)
void SaveCrtc(void)
Save information of a CRTC.
void RestoreCrtc(void)
Restore information of a CRTC.
void Close(void)
Close the drm file handle.
int SetConnectorCrtcId(drmModeAtomicReqPtr)
void DestroyAllExcept(cDrmBuffer *)
Destroy all drm buffers except the given one.
int SetCrtcActive(drmModeAtomicReqPtr, uint32_t)
int Init(void)
Initiate the drm device.
void PresentationFinished(void)
The presentation of this buffer has finished.
__attribute__((weak)) union gbm_bo_handle gbm_bo_get_handle_for_plane(struct gbm_bo *bo
void Destroy(void)
Clear and destroy the buffer object and its parameters.
int Build(struct hdr_output_metadata *, int, int, AVFrameSideData *, AVFrameSideData *)
Build an HDR static metadata blob.
Definition drmhdr.cpp:60
int SetVideoPlaneColorRange(drmModeAtomicReqPtr, uint32_t)
void InitEvent(void)
Init the event context.
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:42
#define LOGDEBUG
log to LOG_DEBUG
Definition logger.h:40
#define LOGERROR
log to LOG_ERR
Definition logger.h:34
#define AV_NOPTS_VALUE
Definition misc.h:74
void FreeDrmBuf(void)
Free the grabbed drm buffer.
Definition grab.cpp:290
void SetDrmBuf(cDrmBuffer *)
Set the grab buffer and the dimensions how it is presented on the screen.
Definition grab.cpp:309
#define LOGWARNING
log to LOG_WARN
Definition logger.h:36
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:32
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:63
@ L_DRM
drm logs
Definition logger.h:55
@ L_AV_SYNC
audio/video sync logs
Definition logger.h:52
@ L_OSD
osd logs
Definition logger.h:54
@ L_TRICK
trickspeed logs
Definition logger.h:58
@ L_OPENGL
opengl osd logs
Definition logger.h:60
@ L_GRAB
grabbing logs
Definition logger.h:64
void PushPipFrame(AVFrame *)
Push a PiP frame into the render ringbuffer.
void SetFrameFlags(AVFrame *, int)
Set frame flags.
int DrmHandleEvent(void)
Wrapper for drmHandleEvent()
bool IsOutputBufferFull(void)
Check, if the main render output buffer is full.
void SetHdrBlob(struct hdr_output_metadata)
Create an hdr blob and set it for the connector.
void Reset()
Reset the renderer.
bool CanHandleHdr(void)
void CreateGrabBuffers(bool)
Copy current video, osd and pip buffers to dedicated grabbing buffers.
int SetVideoBuffer(cDrmBuffer *)
Modesetting for video.
void ProcessEvents(void)
Process queued events and forward to event receiver.
void OsdClear(void)
Clear the OSD (draw an empty/ transparent OSD)
AVFrame * PrepareDrmBuffer(cDrmBuffer *, int, AVFrame *) override
#define MIN(a, b)
cDrmBuffer * GetBuffer(cDrmBufferPool *, AVDRMFrameDescriptor *) override
int SetOsdBuffer(drmModeAtomicReqPtr)
Modesetting for osd.
void ClearDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
void Init(void)
Initialize the renderer.
void PushFrame(AVFrame *, bool, std::atomic< cBufferStrategy * > &, std::atomic< cDecodingStrategy * > &, cQueue< cDrmBuffer > *, cDrmBufferPool *)
Push the frame into the render ringbuffer.
void Exit(void)
Exit and cleanup the renderer.
AVFrame * PrepareDrmBuffer(cDrmBuffer *, int, AVFrame *) override
void SetColorSpace(drmColorRange)
Set kms color space, color encoding and color range.
~cVideoRender(void)
Destroy the video renderer.
void GetStats(int *, int *, int *)
Get some rendering statistics.
void DisplayBlackFrame(void)
drmColorRange
Definition videorender.h:72
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.
cVideoRender(cSoftHdDevice *)
Create the video renderer.
int GetFrameFlags(AVFrame *)
Get frame flags.
int64_t GetOutputPtsMs(void)
Get the output PTS in milliseconds.
void ClearPipDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
static void ReleaseFrame(__attribute__((unused)) void *opaque, uint8_t *data)
Callback free primedata if av_buffer is unreferenced.
#define AV_SYNC_THRESHOLD_AUDIO_BEHIND_VIDEO_MS
threshold in ms, when to duplicate video frames to keep audio and video in sync
Definition videorender.h:59
int CommitBuffer(cDrmBuffer *, cDrmBuffer *)
Commit the frame to the hardware.
int TriggerGrab(void)
Trigger a screen grab.
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)
void Stop(void)
Stop the thread.
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.
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD ARGB image.
cDrmBuffer * GetBuffer(cDrmBufferPool *, AVDRMFrameDescriptor *) override
void SetScreenSize(int, int, double)
Wrapper to set the screen size in the device.
int64_t PtsToMs(int64_t)
cDrmBuffer * GetBuffer(cDrmBufferPool *, AVDRMFrameDescriptor *) override
void SetPipSize(bool)
Set the size and position of the pip window.
bool PageFlip(cDrmBuffer *, cDrmBuffer *)
Do the pageflip.
void RestoreColorSpace()
Restore color space, color encoding and color range to BT709 and the original color range.
void ResetFrameCounter(void)
Send start condition to video thread.
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.
#define AV_SYNC_THRESHOLD_AUDIO_AHEAD_VIDEO_MS
threshold in ms, when to drop video frames to keep audio and video in sync
Definition videorender.h:60
@ COLORSPACE_BT2020_RGB
Definition videorender.h:64
@ COLORSPACE_BT709_YCC
Definition videorender.h:63
@ COLORRANGE_FULL
Definition videorender.h:74
@ COLORRANGE_LIMITED
Definition videorender.h:73
@ COLORENCODING_BT2020
Definition videorender.h:69
@ COLORENCODING_BT709
Definition videorender.h:68
Logger Header File.
Misc Functions.
Thread-safe Queue.
Output Device Header File.
uint64_t y
uint64_t x
uint64_t h
uint64_t w
Video Renderer (Display) Header File.
Video Input Stream Header File.