Skip to content

Commit

Permalink
VideoPlayback: Handle chroma sampling location (left or center only)
Browse files Browse the repository at this point in the history
- a minor improvement to playback quality, only really noticeable for
upscaled SD content.
- only left (or center) sampling is handled. Otherwise I can only find
422 samples that use top left - but they 'look' better with just left...
  • Loading branch information
mark-kendall committed Jun 18, 2020
1 parent a2f6544 commit aaf6829
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 38 deletions.
70 changes: 33 additions & 37 deletions mythtv/libs/libmythtv/opengl/mythopenglvideoshaders.h
Expand Up @@ -70,55 +70,51 @@ static const QString YUVFragmentShader =
"}\n"
"#endif\n"

// Chrom upsampling error filter
// Chroma for lines 1 and 3 comes from line 1-2
// Chroma for lines 2 and 4 comes from line 3-4
// This is a simple resample that ensures temporal consistency. A more advanced
// multitap filter would smooth the chroma - but at significant cost and potentially
// undesirable loss in detail.
"#ifdef MYTHTV_CUE\n"

"highp vec2 chromaLocation(highp vec2 xy)\n"
"{\n"
"#ifdef MYTHTV_CUE\n"
" highp float temp = xy.y * FIELDSIZE;\n"
" highp float onetwo = min((floor(temp / 2.0) / (FIELDSIZE / 2.0)) + LINEHEIGHT, MAXHEIGHT);\n"
"#ifdef MYTHTV_CHROMALEFT\n"
" return vec2(xy.x + (0.5 / COLUMN), mix(onetwo, min(onetwo + (2.0 * LINEHEIGHT), MAXHEIGHT), step(0.5, fract(temp))));\n"
"#else\n"
" return vec2(xy.x, mix(onetwo, min(onetwo + (2.0 * LINEHEIGHT), MAXHEIGHT), step(0.5, fract(temp))));\n"
"}\n"
"#endif\n"
"#else\n"
"#ifdef MYTHTV_CHROMALEFT\n"
" return vec2(xy.x + (0.5 / COLUMN), xy.y);\n"
"#else\n"
" return xy;\n"
"#endif\n"
"#endif\n"
"}\n"

"#ifdef MYTHTV_NV12\n"
"highp vec4 sampleYUV(in sampler2D texture1, in sampler2D texture2, highp vec2 texcoord)\n"
"{\n"
"#ifdef MYTHTV_CUE\n"
"#ifdef MYTHTV_RECTS\n"
// TODO this needs checking
" return vec4(texture2D(texture1, texcoord).r, texture2D(texture2, chromaLocation(texcoord) * vec2(0.5, 0.5)).rg, 1.0);\n"
"#else\n"
" return vec4(texture2D(texture1, texcoord).r, texture2D(texture2, chromaLocation(texcoord)).rg, 1.0);\n"
"#endif\n"
"#else\n"
"#ifdef MYTHTV_RECTS\n"
" return vec4(texture2D(texture1, texcoord).r, texture2D(texture2, texcoord * vec2(0.5, 0.5)).rg, 1.0);\n"
"#else\n"
" return vec4(texture2D(texture1, texcoord).r, texture2D(texture2, texcoord).rg, 1.0);\n"
"#endif\n"
"#endif\n"
"}\n"
"#endif\n"

"#ifdef MYTHTV_YV12\n"
"highp vec4 sampleYUV(in sampler2D texture1, in sampler2D texture2, in sampler2D texture3, highp vec2 texcoord)\n"
"{\n"
"#ifdef MYTHTV_CUE\n"
" highp vec2 field = chromaLocation(texcoord);\n"
" return vec4(texture2D(texture1, texcoord).r,\n"
" texture2D(texture2, field).r,\n"
" texture2D(texture3, field).r,\n"
" 1.0);\n"
"#else\n"
" highp vec2 chroma = chromaLocation(texcoord);\n"
" return vec4(texture2D(texture1, texcoord).r,\n"
" texture2D(texture2, texcoord).r,\n"
" texture2D(texture3, texcoord).r,\n"
" texture2D(texture2, chroma).r,\n"
" texture2D(texture3, chroma).r,\n"
" 1.0);\n"
"#endif\n"
"}\n"
"#endif\n"

Expand Down Expand Up @@ -286,41 +282,41 @@ static const QString GLSL300YUVFragmentShader =
// This is a simple resample that ensures temporal consistency. A more advanced
// multitap filter would smooth the chroma - but at significant cost and potentially
// undesirable loss in detail.
"#ifdef MYTHTV_CUE\n"

"highp vec2 chromaLocation(highp vec2 xy)\n"
"{\n"
"#ifdef MYTHTV_CUE\n"
" highp float temp = xy.y * FIELDSIZE;\n"
" highp float onetwo = min((floor(temp / 2.0) / (FIELDSIZE / 2.0)) + LINEHEIGHT, MAXHEIGHT);\n"
"#ifdef MYTHTV_CHROMALEFT\n"
" return vec2(xy.x + (0.5 / COLUMN), mix(onetwo, min(onetwo + (2.0 * LINEHEIGHT), MAXHEIGHT), step(0.5, fract(temp))));\n"
"#else\n"
" return vec2(xy.x, mix(onetwo, min(onetwo + (2.0 * LINEHEIGHT), MAXHEIGHT), step(0.5, fract(temp))));\n"
"}\n"
"#endif\n"
"#else\n"
"#ifdef MYTHTV_CHROMALEFT\n"
" return vec2(xy.x + (0.5 / COLUMN), xy.y);\n"
"#else\n"
" return xy;\n"
"#endif\n"
"#endif\n"
"}\n"

"#ifdef MYTHTV_NV12\n"
"highp uvec4 sampleYUV(in sampler2D texture1, in sampler2D texture2, highp vec2 texcoord)\n"
"{\n"
"#ifdef MYTHTV_CUE\n"
" return uvec4(texture(texture1, texcoord).r, texture(texture2, chromaLocation(texcoord)).rg, 1.0);\n"
"#else\n"
" return uvec4(texture(texture1, texcoord).r, texture(texture2, texcoord).rg, 1.0);\n"
"#endif\n"
"}\n"
"#endif\n"

"#ifdef MYTHTV_YV12\n"
"highp uvec4 sampleYUV(in sampler2D texture1, in sampler2D texture2, in sampler2D texture3, highp vec2 texcoord)\n"
"{\n"
"#ifdef MYTHTV_CUE\n"
" highp vec2 field = chromaLocation(texcoord);\n"
" highp vec2 chroma = chromaLocation(texcoord);\n"
" return uvec4(texture(texture1, texcoord).r,\n"
" texture(texture2, field).r,\n"
" texture(texture3, field).r,\n"
" texture(texture2, chroma).r,\n"
" texture(texture3, chroma).r,\n"
" 1.0);\n"
"#else\n"
" return uvec4(texture(texture1, texcoord).r,\n"
" texture(texture2, texcoord).r,\n"
" texture(texture3, texcoord).r,\n"
" 1.0);\n"
"#endif\n"
"}\n"
"#endif\n"

Expand Down
21 changes: 20 additions & 1 deletion mythtv/libs/libmythtv/videocolourspace.cpp
Expand Up @@ -337,7 +337,9 @@ bool VideoColourSpace::UpdateColourSpace(const VideoFrame *Frame)
int csp = Frame->colorspace;
int primary = Frame->colorprimaries;
int transfer = Frame->colortransfer;
int chroma = Frame->chromalocation;
int raw = csp;
int rawchroma = chroma;
VideoFrameType frametype = Frame->codec;
VideoFrameType softwaretype = PixelFormatToFrameType(static_cast<AVPixelFormat>(Frame->sw_pix_fmt));

Expand All @@ -360,9 +362,12 @@ bool VideoColourSpace::UpdateColourSpace(const VideoFrame *Frame)
primary = (Frame->width < 1280) ? AVCOL_PRI_BT470BG : AVCOL_PRI_BT709;
if (transfer == AVCOL_TRC_UNSPECIFIED)
transfer = (Frame->width < 1280) ? AVCOL_TRC_GAMMA28 : AVCOL_TRC_BT709;
if (chroma == AVCHROMA_LOC_UNSPECIFIED)
chroma = AVCHROMA_LOC_LEFT;

if ((csp == m_colourSpace) && (m_colourSpaceDepth == depth) &&
(m_range == range) && (m_colourShifted == Frame->colorshifted) &&
(primary == m_colourPrimaries))
(primary == m_colourPrimaries) && (chroma == m_chromaLocation))
{
return false;
}
Expand All @@ -373,6 +378,7 @@ bool VideoColourSpace::UpdateColourSpace(const VideoFrame *Frame)
m_colourShifted = Frame->colorshifted;
m_colourPrimaries = primary;
m_colourTransfer = transfer;
m_chromaLocation = chroma;

if (forced)
LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Forcing inconsistent colourspace - frame format %1")
Expand All @@ -391,6 +397,9 @@ bool VideoColourSpace::UpdateColourSpace(const VideoFrame *Frame)
.arg(m_fullRange ? "Full" : "Limited")
.arg(m_customDisplayPrimaries ? "Custom (screen)" :
av_color_primaries_name(static_cast<AVColorPrimaries>(m_displayPrimaries))));
LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Chroma location: %1 %2")
.arg(av_chroma_location_name(static_cast<AVChromaLocation>(m_chromaLocation)))
.arg(rawchroma == m_chromaLocation ? "(Detected)" : "(Guessed)"));

Update();

Expand Down Expand Up @@ -443,6 +452,16 @@ void VideoColourSpace::SetAlpha(int Value)
QStringList VideoColourSpace::GetColourMappingDefines(void)
{
QStringList result;

// TODO extend this to handle all non-co-sited chroma locations. Left is the
// most common by far - otherwise topleft seems to be used by some 422 content (but
// subjectively looks better without adjusting vertically!)
if (m_chromaLocation == AVCHROMA_LOC_LEFT || m_chromaLocation == AVCHROMA_LOC_TOPLEFT ||
m_chromaLocation == AVCHROMA_LOC_BOTTOMLEFT)
{
result << "CHROMALEFT";
}

if (m_primaryMatrix.isIdentity())
return result;

Expand Down
1 change: 1 addition & 0 deletions mythtv/libs/libmythtv/videocolourspace.h
Expand Up @@ -90,6 +90,7 @@ class VideoColourSpace : public QObject, public QMatrix4x4, public ReferenceCoun
PrimariesMode m_primariesMode { PrimariesRelaxed };
int m_colourPrimaries { AVCOL_PRI_BT709 };
int m_displayPrimaries { AVCOL_PRI_BT709 };
int m_chromaLocation { AVCHROMA_LOC_LEFT };
float m_colourGamma { 2.2F };
float m_displayGamma { 2.2F };
QMatrix4x4 m_primaryMatrix { };
Expand Down

0 comments on commit aaf6829

Please sign in to comment.