MythTV master
mythvideoout.cpp
Go to the documentation of this file.
1// std
2#include <cmath>
3#include <cstdlib>
4
5// MythTV
11
14#include "mythavutil.h"
15#include "mythplayer.h"
16#include "mythvideoout.h"
17#include "mythvideooutgpu.h"
18#include "mythvideooutnull.h"
19#include "mythvideoprofile.h"
20#include "osd.h"
21
22#define LOC QString("VideoOutput: ")
23
25{
28}
29
100 m_dbLetterboxColour(static_cast<LetterBoxColour>(gCoreContext->GetNumSetting("LetterboxColour", 0))),
101 m_clearColor(m_dbLetterboxColour == kLetterBoxColour_Gray25 ? 64 : 0)
102{
103}
104
110bool MythVideoOutput::Init(const QSize VideoDim, const QSize VideoDispDim,
111 float VideoAspect, const QRect WindowRect, MythCodecID CodecID)
112{
113 m_videoCodecID = CodecID;
114 bool wasembedding = IsEmbedding();
115 QRect oldrect;
116 if (wasembedding)
117 {
118 oldrect = GetEmbeddingRect();
119 EmbedPlayback(false, {});
120 }
121
122 bool mainSuccess = InitBounds(VideoDim, VideoDispDim, VideoAspect, WindowRect);
123
124 if (m_videoProfile)
125 m_videoProfile->SetInput(GetVideoDispDim());
126
127 if (wasembedding)
128 EmbedPlayback(true, oldrect);
129
130 VideoAspectRatioChanged(VideoAspect); // apply aspect ratio and letterbox mode
131
132 return mainSuccess;
133}
134
135void MythVideoOutput::SetVideoFrameRate(float VideoFrameRate)
136{
137 if (m_videoProfile)
138 m_videoProfile->SetOutput(VideoFrameRate);
139}
140
141void MythVideoOutput::SetDeinterlacing(bool Enable, bool DoubleRate, MythDeintType Force /*=DEINT_NONE*/)
142{
143
144
145 if (!Enable)
146 {
147 m_deinterlacing = false;
148 m_deinterlacing2X = false;
151 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Disabled all deinterlacing");
152 return;
153 }
154
155 m_deinterlacing = Enable;
156 m_deinterlacing2X = DoubleRate;
157 m_forcedDeinterlacer = Force;
158
159 MythDeintType singlerate = DEINT_NONE;
160 MythDeintType doublerate = DEINT_NONE;
161 if (DEINT_NONE != Force)
162 {
163 singlerate = Force;
164 if (DoubleRate)
165 doublerate = Force;
166 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Overriding deinterlacers");
167 }
168 else if (m_videoProfile)
169 {
170 singlerate = MythVideoFrame::ParseDeinterlacer(m_videoProfile->GetSingleRatePreferences());
171 if (DoubleRate)
172 doublerate = MythVideoFrame::ParseDeinterlacer(m_videoProfile->GetDoubleRatePreferences());
173 }
174
175 LOG(VB_GENERAL, LOG_INFO, LOC + QString("SetDeinterlacing (Doublerate %1): Single %2 Double %3")
176 .arg(QString::number(DoubleRate),
179 m_videoBuffers.SetDeinterlacing(singlerate, doublerate, m_videoCodecID);
180}
181
187bool MythVideoOutput::InputChanged(const QSize VideoDim, const QSize VideoDispDim,
188 float VideoAspect, MythCodecID CodecID,
189 bool& /*AspectOnly*/, int ReferenceFrames, bool /*ForceChange*/)
190{
191 SourceChanged(VideoDim, VideoDispDim, VideoAspect);
192 m_maxReferenceFrames = ReferenceFrames;
193 AVCodecID avCodecId = myth2av_codecid(CodecID);
194 const AVCodec* codec = avcodec_find_decoder(avCodecId);
195 QString codecName;
196 if (codec)
197 codecName = codec->name;
198 if (m_videoProfile)
199 m_videoProfile->SetInput(GetVideoDispDim(), 0 ,codecName);
200 m_videoCodecID = CodecID;
201 DiscardFrames(true, true);
202 // Update deinterlacers for any input change
204 return true;
205}
206
207void MythVideoOutput::GetOSDBounds(QRect& Total, QRect& Visible,
208 float& VisibleAspect,
209 float& FontScaling,
210 float ThemeAspect) const
211{
212 Total = GetDisplayVisibleRect();
213 Visible = GetVisibleOSDBounds(VisibleAspect, FontScaling, ThemeAspect);
214}
215
222QRect MythVideoOutput::GetVisibleOSDBounds(float& VisibleAspect,
223 float& FontScaling,
224 float ThemeAspect) const
225{
226 QRect dvr = GetDisplayVisibleRect();
227 float dispPixelAdj = 1.0F;
228 if (dvr.height() && dvr.width())
229 dispPixelAdj = (GetDisplayAspect() * dvr.height()) / dvr.width();
230
231 float ova = GetOverridenVideoAspect();
232 QRect vr = GetVideoRect();
233 float vs = vr.height() ? static_cast<float>(vr.width()) / vr.height() : 1.0F;
234 VisibleAspect = ThemeAspect * (ova > 0.0F ? vs / ova : 1.F) * dispPixelAdj;
235
236 FontScaling = 1.0F;
237 return { QPoint(0,0), dvr.size() };
238}
239
241{
243}
244
245void MythVideoOutput::SetFramesPlayed(long long FramesPlayed)
246{
247 m_framesPlayed = FramesPlayed;
248}
249
251{
252 return m_framesPlayed;
253}
254
256{
257 return m_errorState != kError_None;
258}
259
261{
262 return m_errorState;
263}
264
267{
269}
270
273{
275}
276
279{
280 return static_cast<int>(m_videoBuffers.ValidVideoFrames());
281}
282
285{
286 return static_cast<int>(m_videoBuffers.FreeVideoFrames());
287}
288
291{
293}
294
298{
300}
301
304{
306}
307
310{
311 return m_videoBuffers.GetStatus();
312}
313
317{
319}
320
322QRect MythVideoOutput::GetImageRect(const QRect Rect, QRect* DisplayRect)
323{
324 qreal hscale = 0.0;
325 QSize video_size = GetVideoDispDim();
326 int image_height = video_size.height();
327 int image_width {720};
328 if (image_height > 720)
329 image_width = 1920;
330 else if (image_height > 576)
331 image_width = 1280;
332 qreal image_aspect = static_cast<qreal>(image_width) / image_height;
333 qreal pixel_aspect = static_cast<qreal>(video_size.width()) / video_size.height();
334
335 QRect rect1 = Rect;
336 if (DisplayRect && DisplayRect->isValid())
337 {
338 QTransform m0;
339 m0.scale(static_cast<qreal>(image_width) / DisplayRect->width(),
340 static_cast<qreal>(image_height) / DisplayRect->height());
341 rect1 = m0.mapRect(rect1);
342 rect1.translate(DisplayRect->left(), DisplayRect->top());
343 }
344 QRect result = rect1;
345
346 QRect dvr_rec = GetDisplayVideoRect();
347 QRect vid_rec = GetVideoRect();
348
349 hscale = image_aspect / pixel_aspect;
350 if (hscale < 0.99 || hscale > 1.01)
351 {
352 vid_rec.setLeft(static_cast<int>(lround(static_cast<qreal>(vid_rec.left()) * hscale)));
353 vid_rec.setWidth(static_cast<int>(lround(static_cast<qreal>(vid_rec.width()) * hscale)));
354 }
355
356 qreal vscale = static_cast<qreal>(dvr_rec.width()) / image_width;
357 hscale = static_cast<qreal>(dvr_rec.height()) / image_height;
358 QTransform m1;
359 m1.translate(dvr_rec.left(), dvr_rec.top());
360 m1.scale(vscale, hscale);
361
362 vscale = static_cast<qreal>(image_width) / vid_rec.width();
363 hscale = static_cast<qreal>(image_height) / vid_rec.height();
364 QTransform m2;
365 m2.scale(vscale, hscale);
366 m2.translate(-vid_rec.left(), -vid_rec.top());
367
368 result = m2.mapRect(result);
369 result = m1.mapRect(result);
370 return result;
371}
372
380{
381 static constexpr float kSafeMargin = 0.05F;
382 float dummy = NAN;
383 QRect result = GetVisibleOSDBounds(dummy, dummy, 1.0F);
384 int safex = static_cast<int>(static_cast<float>(result.width()) * kSafeMargin);
385 int safey = static_cast<int>(static_cast<float>(result.height()) * kSafeMargin);
386 return { result.left() + safex, result.top() + safey,
387 result.width() - (2 * safex), result.height() - (2 * safey) };
388}
389
394{
396}
397
401{
403}
404
407{
409}
410
414{
416}
417
421{
423}
424
428{
430}
431
434void MythVideoOutput::DiscardFrames(bool KeyFrame, bool /*Flushed*/)
435{
437}
QRect GetEmbeddingRect(void) const
QRect GetDisplayVideoRect(void) const
bool IsEmbedding(void) const
virtual void EmbedPlayback(bool Embed, QRect Rect)
QSize GetVideoDispDim(void) const
float GetOverridenVideoAspect(void) const
QRect GetVideoRect(void) const
void SourceChanged(QSize VideoDim, QSize VideoDispDim, float Aspect)
Update for new source video dimensions and aspect ratio.
QRect GetDisplayVisibleRect(void) const
bool InitBounds(QSize VideoDim, QSize VideoDispDim, float Aspect, QRect WindowRect)
void VideoAspectRatioChanged(float Aspect)
Calls SetVideoAspectRatio(float aspect), then calls MoveResize() to apply changes.
float GetDisplayAspect(void) const
PictureAttributeSupported SupportedAttributes(void) const
static QString DeinterlacerPref(MythDeintType Deint)
Definition: mythframe.cpp:530
static MythDeintType ParseDeinterlacer(const QString &Deinterlacer)
Definition: mythframe.cpp:544
static void GetRenderOptions(RenderOptions &Options, MythRender *Render)
static void GetRenderOptions(RenderOptions &Options)
MythCodecID m_videoCodecID
Definition: mythvideoout.h:98
bool EnoughFreeFrames()
Returns true iff enough frames are available to decode onto.
VideoErrorState m_errorState
Definition: mythvideoout.h:102
long long m_framesPlayed
Definition: mythvideoout.h:103
bool EnoughDecodedFrames()
Returns true iff there are plenty of decoded frames ready for display.
virtual void ReleaseFrame(MythVideoFrame *Frame)
Releases a frame from the ready for decoding queue onto the queue of frames ready for display.
virtual void StartDisplayingFrame()
Tell GetLastShownFrame() to return the next frame from the head of the queue of frames to display.
virtual void GetOSDBounds(QRect &Total, QRect &Visible, float &VisibleAspect, float &FontScaling, float ThemeAspect) const
virtual int ValidVideoFrames() const
Returns number of frames that are fully decoded.
bool IsErrored() const
virtual void ClearAfterSeek()
Tells video output to toss decoded buffers due to a seek.
virtual MythVideoFrame * GetLastDecodedFrame()
void SetPrebuffering(bool Normal)
Sets whether to use a normal number of buffers or fewer buffers.
virtual void SetDeinterlacing(bool Enable, bool DoubleRate, MythDeintType Force=DEINT_NONE)
MythVideoColourSpace m_videoColourSpace
Definition: mythvideoout.h:94
virtual bool Init(QSize VideoDim, QSize VideoDispDim, float VideoAspect, QRect WindowRect, MythCodecID CodecID)
QRect GetImageRect(QRect Rect, QRect *DisplayRect=nullptr)
translates caption/dvd button rectangle into 'screen' space
MythVideoProfilePtr m_videoProfile
Definition: mythvideoout.h:100
virtual void SetVideoFrameRate(float VideoFrameRate)
PictureAttributeSupported GetSupportedPictureAttributes()
virtual long long GetFramesPlayed()
QRect GetSafeRect()
Returns a QRect describing an area of the screen on which it is 'safe' to render the On Screen Displa...
QString GetFrameStatus() const
Returns string with status of each frame for debugging.
MythDeintType m_forcedDeinterlacer
Definition: mythvideoout.h:109
VideoErrorState GetError() const
virtual void DeLimboFrame(MythVideoFrame *Frame)
Releases a frame for reuse if it is in limbo.
VideoBuffers m_videoBuffers
Definition: mythvideoout.h:101
virtual MythVideoFrame * GetLastShownFrame()
Returns frame from the head of the ready to be displayed queue, if StartDisplayingFrame has been call...
virtual MythVideoFrame * GetNextFreeFrame()
Blocks until it is possible to return a frame for decoding onto.
int FreeVideoFrames()
Returns number of frames available for decoding onto.
virtual void DiscardFrame(MythVideoFrame *Frame)
Releases frame from any queue onto the queue of frames ready for decoding onto.
virtual void SetFramesPlayed(long long FramesPlayed)
virtual void DiscardFrames(bool KeyFrame, bool Flushed)
Releases all frames not being actively displayed from any queue onto the queue of frames ready for de...
static void GetRenderOptions(RenderOptions &Options, MythRender *Render)
virtual void DoneDisplayingFrame(MythVideoFrame *Frame)
Releases frame returned from GetLastShownFrame() onto the queue of frames ready for decoding onto.
virtual bool InputChanged(QSize VideoDim, QSize VideoDispDim, float VideoAspect, MythCodecID CodecID, bool &AspectChanged, int ReferenceFrames, bool ForceChange)
Tells video output to discard decoded frames and wait for new ones.
QRect GetVisibleOSDBounds(float &VisibleAspect, float &FontScaling, float ThemeAspect) const
Returns visible portions of total OSD bounds.
int m_maxReferenceFrames
Definition: mythvideoout.h:99
void SetPrebuffering(bool Normal)
Sets prebuffering state to normal, or small.
MythVideoFrame * GetNextFreeFrame(BufferType EnqueueTo=kVideoBuffer_limbo)
Gets a frame from available buffers list.
bool EnoughFreeFrames(void) const
QString GetStatus(uint Num=0) const
MythVideoFrame * GetLastShownFrame(void)
MythVideoFrame * GetLastDecodedFrame(void)
void SetDeinterlacing(MythDeintType Single, MythDeintType Double, MythCodecID CodecID)
uint ValidVideoFrames(void) const
bool EnoughDecodedFrames(void) const
void DoneDisplayingFrame(MythVideoFrame *Frame)
Removes frame from used queue and adds it to the available list.
void DiscardFrames(bool NextFrameIsKeyFrame)
Mark all used frames as ready to be reused, this is for seek.
void ReleaseFrame(MythVideoFrame *Frame)
Frame is ready to be for filtering or OSD application.
void ClearAfterSeek(void)
Clear used frames after seeking.
void DiscardFrame(MythVideoFrame *Frame)
Frame is ready to be reused by decoder.
uint FreeVideoFrames(void) const
void StartDisplayingFrame(void)
Sets rpos to index of videoframe at head of used queue.
void DeLimboFrame(MythVideoFrame *Frame)
If the frame is still in the limbo state it is added to the available queue.
AVCodecID myth2av_codecid(MythCodecID codec_id)
MythCodecID
Definition: mythcodecid.h:14
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythDeintType
Definition: mythframe.h:67
@ DEINT_NONE
Definition: mythframe.h:68
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
#define LOC
VideoErrorState
@ kError_None
PictureAttributeSupported
LetterBoxColour
Definition: videoouttypes.h:87
@ kLetterBoxColour_Gray25
Definition: videoouttypes.h:90