9#include "libmythbase/mythconfig.h"
21#include "libavutil/stereo3d.h"
24#define LOC QString("GLVid: ")
39 :
MythVideoGPU(Render, ColourSpace, Bounds, VideoProfile, Profile),
40 m_openglRender(Render)
44 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Fatal error");
58 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Chroma upsampling filter %1")
80 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Primaries conversion changed - recreating shaders");
93 m_shaders[i]->setUniformValue(
"m_colourGamma", colourgamma);
94 m_shaders[i]->setUniformValue(
"m_displayGamma", displaygamma);
110 QVector4D parameters(lineheight,
112 maxheight - lineheight,
120 m_shaders[i]->setUniformValue(
"m_frameData", parameters);
123 QVector2D size { rect ? 1.0F :
static_cast<GLfloat
>(
m_videoDim.width()),
124 rect ? 1.0F :
static_cast<GLfloat
>(
m_videoDim.height()) };
125 m_shaders[i]->setUniformValue(
"m_textureSize", size);
148 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Removing single field textures");
162 bool CreateReferences )
191 deinterlacer =
Frame->GetSingleRateOption(Filter);
193 if (!deinterlacer || other)
231 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Forcing OpenGL YV12 for basic deinterlacer");
236 std::vector<QSize> sizes;
237 sizes.emplace_back(size);
243 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Created %1 single field textures")
251 uint refstocreate = ((deinterlacer ==
DEINT_HIGH) && CreateReferences) ? 2 : 0;
253 if (totaltextures > max)
256 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"Insufficent texture units for deinterlacer '%1' (%2 < %3)")
259 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"Falling back to '%1'")
270 std::vector<QSize> sizes;
287 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Created deinterlacer '%1' (%2->%3)")
322 for (
const QString& define : std::as_const(defines))
323 glsldefines += QString(
"#define MYTHTV_%1\n").arg(define);
328 vertex = MediaCodecVertexShader;
342 static const QString glsl300(
"#version 300 es\n");
346 glsldefines.append(glsl300);
367#if CONFIG_VIDEOTOOLBOX
386 if (topfield && !basic)
387 defines <<
"TOPFIELD";
395 defines <<
"ONEFIELD";
398 case DEINT_MEDIUM: cost *= 5; defines <<
"LINEARBLEND";
break;
399 case DEINT_HIGH: cost *= 15; defines <<
"KERNEL"; kernel =
true;
break;
410 for (
int i = (kernel ? 2 : 0); (i >= 0) && count; i--)
412 QString
find = QString(
"s_texture%1").arg(i);
413 QStringList replacelist;
414 replacelist.reserve(count);
415 for (
int j = (i * count); j < ((i + 1) * count); ++j)
416 replacelist << QString(
"s_texture%1").arg(j);
417 fragment.replace(
find, replacelist.join(
", "));
423 for (
int i = 1 ; i >= 0; i--)
425 QString find1 = QString(
"sampler2D kernelTex%1").arg(i);
426 QString find2 = QString(
"kernelTex%1").arg(i);
427 QStringList replacelist1;
428 QStringList replacelist2;
429 replacelist1.reserve(count);
430 replacelist2.reserve(count);
431 for (
int j = 0; j < count; ++j)
433 replacelist1 << QString(
"sampler2D kernelTexture%1%2").arg(i).arg(j);
434 replacelist2 << QString(
"kernelTexture%1%2").arg(i).arg(j);
436 fragment.replace(find1, replacelist1.join(
", "));
437 fragment.replace(find2, replacelist2.join(
", "));
445 for (
const QString& define : std::as_const(defines))
446 glsldefines += QString(
"#define MYTHTV_%1\n").arg(define);
459 QString glslsamplers;
460 for (
int i = start; i < end; ++i)
461 glslsamplers += QString(
"uniform sampler2D s_texture%1;\n").arg(i);
464 fragment = glsldefines + extensions + glslsamplers + fragment;
477 QSize Size, GLenum TextureTarget)
479 QString texnew {
"2D" };
480 if (TextureTarget == QOpenGLTexture::TargetRectangle)
485 QString texold {
"2D" };
491 LOG(VB_GENERAL, LOG_INFO,
LOC +
492 QString(
"New frame format: %1:%2 %3x%4 (Tex: %5) -> %6:%7 %8x%9 (Tex: %10)")
500 QString::number(Size.width()),
501 QString::number(Size.height()))
518 std::vector<QSize> sizes;
519 sizes.push_back(Size);
523 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create input textures");
528 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Created %1 input textures for '%2'")
577 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Resetting input format");
586 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Invalid software frame");
593 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Frame format is not supported");
643 Frame->m_pitches[0] =
Frame->m_pitches[0] << 1;
644 Frame->m_pitches[1] =
Frame->m_pitches[1] << 1;
645 Frame->m_pitches[2] =
Frame->m_pitches[2] << 1;
649 Frame->m_offsets[0] =
Frame->m_offsets[0] + pitches[0];
650 Frame->m_offsets[1] =
Frame->m_offsets[1] + pitches[1];
651 Frame->m_offsets[2] =
Frame->m_offsets[2] + pitches[2];
653 Frame->m_pitches = pitches;
654 Frame->m_offsets = offsets;
679 bool hwframes =
false;
680 bool useframebufferimage =
false;
692 VideoResizing resize;
699 if (inputtextures.empty())
706 Frame->m_displayed =
false;
717 if (!inputtextures.empty())
720 QSize newsize = inputtextures[0]->m_size;
723 GLenum newtargettexture = inputtextures[0]->m_target;
737 m_shaders[
Default]->setUniformValue(
"u_transform", *inputtextures[0]->m_transform);
742 if (inputtextures[0]->m_allowGLSLDeint)
749 LOG(VB_PLAYBACK, LOG_DEBUG,
"Using existing framebuffer");
750 useframebufferimage =
true;
754 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"Nothing to display");
764 bool deinterlacing =
false;
765 bool basicdeinterlacing =
false;
773 deinterlacing =
true;
778 deinterlacing =
true;
784 basicdeinterlacing =
true;
791 if (deinterlacing &&
Frame)
802 if (yuvoutput && !resize)
824 if (!resize && !tiled && !basicdeinterlacing)
831 if ((totexture + blitcost) < noresizecost)
864 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Disabled resizing");
869 QOpenGLTexture::Filter filter = ((resize &
Sampling) ==
Sampling) ? QOpenGLTexture::Nearest : QOpenGLTexture::Linear;
874 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Resizing from %1x%2 to %3x%4 for %5")
883 QOpenGLTexture::Filter filter = (resize.testFlag(
Sampling)) ? QOpenGLTexture::Nearest : QOpenGLTexture::Linear;
884 if (inputtextures[0]->m_filter != filter)
896 if (useframebufferimage)
925 (fbo !=
nullptr) && (tex !=
nullptr))
940 QRect trect2 = vrect;
949 std::vector<MythGLTexture*> textures {};
959 inputtextures.clear();
960 inputtextures.push_back(nexttexture);
962 deinterlacing =
false;
988 trect = QRect(trect.left() >> 1, trect.top(), trect.width() >> 1, trect.height());
990 trect = QRect(trect.left(), trect.top() >> 1, trect.width(), trect.height() >> 1);
1000 static const QPen kNopen(Qt::NoPen);
1001 static const QBrush kRedBrush(QBrush(QColor(127, 0, 0, 255)));
1006 std::vector<MythGLTexture*> textures;
1038 texture->m_valid =
false;
1040 texture->m_valid =
false;
1042 texture->m_valid =
false;
1046 std::vector<MythGLTexture*>& Textures)
1054 size_t count = Current.size();
1058 for (
uint i = 0; i < count; ++i)
1059 Textures.push_back(
reinterpret_cast<MythGLTexture*
>(prev[i]));
1060 for (
uint i = 0; i < count; ++i)
1062 for (
uint i = 0; i < count; ++i)
1068 std::ranges::transform(Current, std::back_inserter(Textures),
1080 case FMT_YV12:
return "opengl-yv12";
1081 case FMT_NV12:
return "opengl-nv12";
1096 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create bicubic shader. Disabling");
1102 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Created bicubic sampler");
1113 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Disabling bicubic sampler");
1120#include "moc_mythopenglvideo.cpp"
bool GetBoolSetting(const QString &key, bool defaultval=false)
static std::vector< MythVideoTextureOpenGL * > Retrieve(MythRenderOpenGL *Context, MythVideoColourSpace *ColourSpace, MythVideoFrame *Frame, FrameScanType Scan)
MythVideoTextureOpenGL * GetTexture()
MythVideoTextureOpenGL * Map(std::vector< MythVideoTextureOpenGL * > &Inputs, QSize DisplaySize)
std::vector< MythVideoTextureOpenGL * > m_prevTextures
MythVideoTextureOpenGL * m_frameBufferTexture
bool SetupFrameFormat(VideoFrameType InputType, VideoFrameType OutputType, QSize Size, GLenum TextureTarget)
QOpenGLFramebufferObject * m_frameBuffer
MythOpenGLVideo(MythRenderOpenGL *Render, MythVideoColourSpace *ColourSpace, MythVideoBounds *Bounds, const MythVideoProfilePtr &VideoProfile, const QString &Profile)
~MythOpenGLVideo() override
void BindTextures(bool Deinterlacing, std::vector< MythVideoTextureOpenGL * > &Current, std::vector< MythGLTexture * > &Textures)
bool m_chromaUpsamplingFilter
std::array< int, ShaderCount > m_shaderCost
std::array< QOpenGLShaderProgram *, ShaderCount > m_shaders
static QString TypeToProfile(VideoFrameType Type)
QOpenGLFunctions::OpenGLFeatures m_features
void CleanupDeinterlacers()
MythOpenGLTonemap * m_toneMap
std::vector< MythVideoTextureOpenGL * > m_inputTextures
void ResetTextures() override
Clear reference frames after a seek as they will contain old images.
std::vector< MythVideoTextureOpenGL * > m_nextTextures
void PrepareFrame(MythVideoFrame *Frame, FrameScanType Scan=kScan_Progressive) override
Update the current input texture using the data from the given video frame.
void ColourSpaceUpdate(bool PrimariesChanged) override
MythDeintType m_fallbackDeinterlacer
void SetupBicubic(VideoResizing &Resize)
void RenderFrame(MythVideoFrame *Frame, bool TopFieldFirst, FrameScanType Scan, StereoscopicMode StereoOverride, bool DrawBorder=false) override
void UpdateShaderParameters()
bool AddDeinterlacer(const MythVideoFrame *Frame, FrameScanType Scan, MythDeintType Filter=DEINT_SHADER, bool CreateReferences=true)
MythRenderOpenGL * m_openglRender
void ResetFrameFormat() override
bool CreateVideoShader(VideoShaderType Type, MythDeintType Deint=DEINT_NONE)
Create the appropriate shader for the operation Type.
QString GetProfile() const override
void SetShaderProgramParams(QOpenGLShaderProgram *Program, const QMatrix4x4 &Value, const char *Uniform)
int GetMaxTextureUnits(void) const
void DrawBitmap(MythGLTexture *Texture, QOpenGLFramebufferObject *Target, QRect Source, QRect Destination, QOpenGLShaderProgram *Program, int Alpha=255, qreal Scale=1.0)
void SetViewPort(QRect Rect, bool ViewportOnly=false) override
void DeleteShaderProgram(QOpenGLShaderProgram *Program)
void BindFramebuffer(QOpenGLFramebufferObject *Framebuffer)
void DeleteFramebuffer(QOpenGLFramebufferObject *Framebuffer)
QOpenGLFunctions::OpenGLFeatures GetFeatures(void) const
bool EnableShaderProgram(QOpenGLShaderProgram *Program)
void logDebugMarker(const QString &Message)
QOpenGLShaderProgram * CreateShaderProgram(const QString &Vertex, const QString &Fragment)
void DeleteTexture(MythGLTexture *Texture)
void DrawRect(QOpenGLFramebufferObject *Target, QRect Area, const QBrush &FillBrush, const QPen &LinePen, int Alpha)
int GetExtraFeatures(void) const
void SetTextureFilters(MythGLTexture *Texture, QOpenGLTexture::Filter Filter, QOpenGLTexture::WrapMode Wrap=QOpenGLTexture::ClampToEdge)
MythVideoColourSpace contains a QMatrix4x4 that can convert YCbCr data to RGB.
float GetDisplayGamma(void) const
QStringList GetColourMappingDefines(void)
QMatrix4x4 GetPrimaryMatrix(void)
bool UpdateColourSpace(const MythVideoFrame *Frame)
Set the current colourspace to use.
float GetColourGamma(void) const
static bool FormatIs422(VideoFrameType Type)
static uint GetNumPlanes(VideoFrameType Type)
static QString DeinterlacerName(MythDeintType Deint, bool DoubleRate, VideoFrameType Format=FMT_NONE)
static bool FormatIsNV12(VideoFrameType Type)
static QString FormatDescription(VideoFrameType Type)
static bool FormatIs444(VideoFrameType Type)
static bool FormatIs420(VideoFrameType Type)
static bool FormatIsRGB(VideoFrameType Type)
static bool HardwareFramesFormat(VideoFrameType Type)
static bool YUVFormat(VideoFrameType Type)
static int ColorDepth(int Format)
static bool HardwareFormat(VideoFrameType Type)
VideoFrameType m_inputType
StereoscopicMode m_stereoMode
uint64_t m_discontinuityCounter
MythVideoColourSpace * m_videoColourSpace
QSize m_masterViewportSize
VideoFrameType m_outputType
void OutputChanged(QSize VideoDim, QSize VideoDispDim, float)
static QString VideoResizeToString(VideoResizing Resize)
void UpdateColourSpace(bool PrimariesChanged)
virtual void ResetFrameFormat()
MythDeintType m_deinterlacer
static void SetTextureFilters(MythRenderOpenGL *Context, const std::vector< MythVideoTextureOpenGL * > &Textures, QOpenGLTexture::Filter Filter, QOpenGLTexture::WrapMode Wrap=QOpenGLTexture::ClampToEdge)
static std::vector< MythVideoTextureOpenGL * > CreateTextures(MythRenderOpenGL *Context, VideoFrameType Type, VideoFrameType Format, std::vector< QSize > Sizes, GLenum Target=QOpenGLTexture::Target2D)
Create a set of textures suitable for the given Type and Format.
static VideoFramebuffer CreateVideoFrameBuffer(MythRenderOpenGL *Context, VideoFrameType OutputType, QSize Size, bool HighPrecision=true)
static void DeleteTextures(MythRenderOpenGL *Context, std::vector< MythVideoTextureOpenGL * > &Textures)
static void UpdateTextures(MythRenderOpenGL *Context, const MythVideoFrame *Frame, const std::vector< MythVideoTextureOpenGL * > &Textures)
Update the contents of the given Textures for data held in Frame.
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
std::array< int, 3 > FrameOffsets
std::array< int, 3 > FramePitches
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
static const QString YUVFragmentShader
static const QString DefaultVertexShader
static const QString GLSL300VertexShader
static const QString BicubicShader
static const QString YUVFragmentExtensions
static const QString GLSL300YUVFragmentShader
static const QString GLSL300YUVFragmentExtensions
static const QString RGBFragmentShader
#define GL_TEXTURE_EXTERNAL_OES
std::shared_ptr< MythVideoProfile > MythVideoProfilePtr
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
bool is_interlaced(FrameScanType Scan)
@ kStereoscopicModeTopAndBottomDiscard
@ kStereoscopicModeSideBySideDiscard