31#include <libavcodec/avcodec.h>
32#include <libavutil/hwcontext_drm.h>
35#include <drm_fourcc.h>
37#include <vdr/thread.h>
38#include <xf86drmMode.h>
66 : cThread(
"softhd display"),
68 m_pAudio(m_pDevice->Audio()),
69 m_pConfig(m_pDevice->Config()),
71 m_pEventReceiver(device),
73 m_enableHdr(m_pConfig->ConfigVideoEnableHDR)
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;
333 0, 0,
buf->Width(),
buf->Height());
434 0, 0,
buf->Width(),
buf->Height());
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",
559 if (!frame || !frame->opaque_ref)
562 int *
frameFlags = (
int *)frame->opaque_ref->data;
575 if (!frame->opaque_ref) {
577 if (!frame->opaque_ref) {
605 LOGERROR(
"threads: display thread: drmHandleEvent failed!");
628 LOGDEBUG(
"videorender: display thread started");
643 LOGDEBUG(
"videorender: display thread stopped");
654 LOGDEBUG(
"videorender: stopping display thread");
715 LOGDEBUG2(
L_AV_SYNC,
"videorender: resync schedule arrived at %s, current audio pts %s video pts %s",
737 pipBuf->PresentationFinished();
760 auto now = std::chrono::steady_clock::now();
873#define MIN(a, b) ((a) < (b) ? (a) : (b))
888 int width,
int height,
int pitch,
895 for (
int i = 0;
i < height; ++
i) {
930 for (
int i = 0;
i < height; ++
i) {
1020 buf->SetPresentationPending(
true);
1075 LOGDEBUG2(
L_TRICK,
"videorender: %s: set trick speed %.3f %s %s",
__FUNCTION__, speed, speed > 1.0 ?
"fast" :
"slow", forward ?
"forward" :
"backward");
1408 buf->SetDestroyAfterUse(
true);
1423 return pool->FindUninitilized();
1433 return pool->FindUninitilized();
1441 if (!
buf->IsDirty()) {
1454 for (
int i = 0;
i <
inframe->height / 2; ++
i)
1459 frame->width =
inframe->width;
1460 frame->height =
inframe->height;
1462 frame->sample_aspect_ratio =
inframe->sample_aspect_ratio;
1480 if (!
buf->IsDirty()) {
Audio and Alsa Interface Header File.
virtual void OnEventReceived(const Event &)=0
DRM Buffer: Get a Hardware Buffer to Reuse.
DRM Buffer: Get a Software Buffer to Reuse.
DRM Buffer: Get a Buffer to Use Once.
Prepare DRM Buffer for Hardware Decoding.
Prepare DRM Buffer for Software Decoding.
void SetSizeOnScreen(int x, int y, int w, int h)
AVFrame * frame
associated AVFrame
void SetDestroyAfterUse(bool val)
int ModeAtomicCommit(drmModeAtomicReqPtr req, uint32_t flags, void *user_data)
EGLDisplay EglDisplay(void)
void ModeAtomicFree(drmModeAtomicReqPtr req)
drmModeAtomicReqPtr ModeAtomicAlloc(void)
EGLSurface EglSurface(void)
uint64_t DisplayHeight(void)
uint64_t DisplayWidth(void)
uint64_t ZposPrimary(void)
struct gbm_surface * GbmSurface(void)
uint64_t ZposOverlay(void)
cDrmPlane * PipPlane(void)
cDrmPlane * OsdPlane(void)
cDrmPlane * VideoPlane(void)
uint32_t ConnectorId(void)
cDrmBuffer * GetDrmBuf(void)
void Clear(void)
Remove all elements from the queue.
T * Pop(void)
Pop an element from the back of the queue.
bool IsEmpty(void)
Check if the queue is empty.
bool IsFull(void)
Check if the queue is full.
size_t Size(void)
Get the current size of the queue.
int GetAvResyncBorderMs(void)
int ConfigDisableOglOsd
config disable ogl osd
int ConfigPipAltTopPercent
0 = aligned to top, 100 = aligned to bottom
int ConfigPipLeftPercent
0 = aligned to left, 100 = aligned to right
int ConfigPipAltLeftPercent
0 = aligned to left, 100 = aligned to right
int ConfigPipAltScalePercent
alternative scale factor of pip video
int ConfigPipTopPercent
0 = aligned to top, 100 = aligned to bottom
int ConfigPipScalePercent
scale factor of pip video
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 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)
Plugin Configuration 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
Grabbing Interface Header File.
int64_t GetHardwareOutputPtsMs(void)
Get the hardware output PTS in milliseconds.
void DropSamplesOlderThanPtsMs(int64_t)
Drop samples older than the given PTS.
int GetUsedBytes(void)
Get used bytes in audio ringbuffer.
void SetPaused(bool)
Set audio playback pause state.
int64_t GetHardwareOutputDelayMs(void)
Get the hardware delay in milliseconds.
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.
int SetVideoPlaneColorRange(drmModeAtomicReqPtr, uint32_t)
void InitEvent(void)
Init the event context.
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
#define LOGDEBUG
log to LOG_DEBUG
#define LOGERROR
log to LOG_ERR
void FreeDrmBuf(void)
Free the grabbed drm buffer.
void SetDrmBuf(cDrmBuffer *)
Set the grab buffer and the dimensions how it is presented on the screen.
#define LOGWARNING
log to LOG_WARN
#define LOGFATAL
log to LOG_ERR and abort
static const char * Timestamp2String(int64_t ts, uint8_t divisor)
Nice time-stamp string.
#define EGL_CHECK(stmt)
eglCheckError macro
@ L_PACKET
decoder packet/frame tracking logs
@ L_AV_SYNC
audio/video sync logs
@ L_OPENGL
opengl osd logs
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.
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
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)
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
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.
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
Output Device Header File.
Video Renderer (Display) Header File.
Video Input Stream Header File.