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>
59 : cThread(
"softhd display"),
61 m_pAudio(m_pDevice->Audio()),
62 m_pConfig(m_pDevice->Config()),
68 m_enableHdr(m_pConfig->ConfigVideoEnableHDR)
139 double frameWidth = frame->width > 0 ? frame->width : 1.0;
140 double frameHeight = frame->height > 0 ? frame->height : 1.0;
141 double frameSar =
av_q2d(frame->sample_aspect_ratio) ?
av_q2d(frame->sample_aspect_ratio) : 1.0;
310 0, 0,
buf->Width(),
buf->Height());
413 0, 0,
buf->Width(),
buf->Height());
518 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",
544 if (!frame || !frame->opaque_ref)
547 int *
frameFlags = (
int *)frame->opaque_ref->data;
560 if (!frame->opaque_ref) {
562 if (!frame->opaque_ref) {
590 LOGERROR(
"threads: display thread: drmHandleEvent failed!");
615 LOGDEBUG(
"videorender: display thread started");
630 LOGDEBUG(
"videorender: display thread stopped");
641 LOGDEBUG(
"videorender: stopping display thread");
664 LOGDEBUG2(
L_AV_SYNC,
"videorender: resync schedule arrived at %s, current audio pts %s video pts %s",
780 auto now = std::chrono::steady_clock::now();
916#define MIN(a, b) ((a) < (b) ? (a) : (b))
931 int width,
int height,
int pitch,
938 for (
int i = 0;
i < height; ++
i) {
973 for (
int i = 0;
i < height; ++
i) {
1064 buf->SetPresentationPending(
true);
1120 LOGDEBUG2(
L_TRICK,
"videorender: %s: set trick speed %.3f %s %s",
__FUNCTION__, speed, speed > 1.0 ?
"fast" :
"slow", forward ?
"forward" :
"backward");
1563 buf->SetDestroyAfterUse(
true);
1578 return pool->FindUninitilized();
1588 return pool->FindUninitilized();
1596 if (!
buf->IsDirty()) {
1609 for (
int i = 0;
i <
inframe->height / 2; ++
i)
1614 frame->width =
inframe->width;
1615 frame->height =
inframe->height;
1617 frame->sample_aspect_ratio =
inframe->sample_aspect_ratio;
1635 if (!
buf->IsDirty()) {
Audio Interface Header File.
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.
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
void DestroyAllExcept(cDrmBuffer *)
Destroy all drm buffers except the given one.
void SetSizeOnScreen(int x, int y, int w, int h)
void Setup(int, uint32_t, uint32_t, uint32_t, AVDRMFrameDescriptor *, bool)
Setup the buffer.
void FillBlack(void)
Color the buffer black.
AVFrame * frame
associated AVFrame
void PresentationFinished(void)
The presentation of this buffer has finished.
void Destroy(void)
Clear and destroy the buffer object and its parameters.
void SetDestroyAfterUse(bool val)
int SetConnectorHdrOutputMetadata(drmModeAtomicReqPtr, uint32_t)
int ModeAtomicCommit(drmModeAtomicReqPtr req, uint32_t flags, void *user_data)
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)
void ModeAtomicFree(drmModeAtomicReqPtr req)
int SetConnectorColorspace(drmModeAtomicReqPtr, uint32_t)
int InitEGL(void)
Init EGL context.
int CreateModeBlob(uint32_t *)
drmModeAtomicReqPtr ModeAtomicAlloc(void)
int GetVideoPlaneColorRange(uint64_t *)
int DestroyHdrBlob(uint32_t)
int SetVideoPlaneColorEncoding(drmModeAtomicReqPtr, uint32_t)
EGLSurface EglSurface(void)
int SetCrtcModeId(drmModeAtomicReqPtr, uint32_t)
uint64_t DisplayHeight(void)
void ExitGbm(void)
Free gbm device and surface.
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)
uint64_t ZposPrimary(void)
int CreateHdrBlob(struct hdr_output_metadata *, size_t, uint32_t *)
struct gbm_surface * GbmSurface(void)
uint64_t ZposOverlay(void)
int SetConnectorHdrBlobProperty(uint32_t)
cDrmPlane * PipPlane(void)
void SaveCrtc(void)
Save information of a CRTC.
int ReInit(void)
Re-Init the drm device with a new connector mode.
void RestoreCrtc(void)
Restore information of a CRTC.
void Close(void)
Close the drm file handle.
cDrmPlane * OsdPlane(void)
int SetConnectorCrtcId(drmModeAtomicReqPtr)
cDrmPlane * VideoPlane(void)
uint32_t ConnectorId(void)
int SetCrtcActive(drmModeAtomicReqPtr, uint32_t)
int Init(void)
Initiate the drm device.
int SetVideoPlaneColorRange(drmModeAtomicReqPtr, uint32_t)
void InitEvent(void)
Init the event context.
void FreeProperties(void)
Free the previously filled plane properties.
void Clear(void)
Clear the grab buffer (input and output data)
void Set(cDrmBuffer *)
Set the grab buffer and the dimensions how it is presented on the screen.
void Clear(void)
Remove all elements from the queue.
T * Pop(void)
Pop an element from the back of the queue.
bool IsFull(void)
Check if the queue is full.
size_t Size(void)
Get the current size of the queue.
T * Peek(void)
Get a reference to the back element.
int64_t GetInputPtsMs(void)
int GetUsedRingbufferMs(void)
Get used ms in audio ringbuffer.
int64_t GetHardwareOutputPtsMs(void)
Get the hardware output PTS in milliseconds.
int GetAvResyncBorderMs(void)
void DropSamplesOlderThanPtsMs(int64_t)
Drop samples older than the given PTS.
void SetPaused(bool)
Set audio playback pause state.
int64_t GetHardwareOutputDelayMs(void)
Get the hardware delay in milliseconds.
int GetUsedRingbufferBytes(void)
Get used bytes in audio ringbuffer.
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 ConfigShowChannelSwitchDurationMessage
let the skin show a short message about the channel switch duration
int ConfigPipTopPercent
0 = aligned to top, 100 = aligned to bottom
int ConfigPipScalePercent
scale factor of pip video
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)
void TriggerEvent(const Event &)
With this wrapper function, the device can directly act as an event reveiver.
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.
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)
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 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
int Init(void)
Initialize the renderer.
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)
Plugin Configuration Header File.
__attribute__((weak)) union gbm_bo_handle gbm_bo_get_handle_for_plane(struct gbm_bo *bo
HDR (High Dynamic Range) Header File.
Grabbing Interface Header File.
std::variant< PlayEvent, PauseEvent, StopEvent, TrickSpeedEvent, StillPictureEvent, DetachEvent, AttachEvent, BufferUnderrunEvent, BufferingThresholdReachedEvent, ScheduleResyncAtPtsMsEvent, ResyncEvent, DisplayChangeEvent > Event
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
#define LOGDEBUG
log to LOG_DEBUG
#define LOGERROR
log to LOG_ERR
#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
Output Device Header File.
Device State Machine and Event Handler Header File.
Holds possible display configurations.
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.
Video Input Stream Header File.