mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-06-15 21:22:40 +00:00
Support fully-planar output in DrmRenderer
This commit is contained in:
@@ -546,6 +546,8 @@ bool DrmRenderer::isPixelFormatSupported(int videoFormat, AVPixelFormat pixelFor
|
|||||||
case AV_PIX_FMT_NV12:
|
case AV_PIX_FMT_NV12:
|
||||||
case AV_PIX_FMT_NV21:
|
case AV_PIX_FMT_NV21:
|
||||||
case AV_PIX_FMT_P010:
|
case AV_PIX_FMT_P010:
|
||||||
|
case AV_PIX_FMT_YUV420P:
|
||||||
|
case AV_PIX_FMT_YUVJ420P:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -654,7 +656,6 @@ bool DrmRenderer::mapSoftwareFrame(AVFrame *frame, AVDRMFrameDescriptor *mappedF
|
|||||||
bool ret = false;
|
bool ret = false;
|
||||||
bool freeFrame;
|
bool freeFrame;
|
||||||
auto drmFrame = &m_SwFrame[m_CurrentSwFrameIdx];
|
auto drmFrame = &m_SwFrame[m_CurrentSwFrameIdx];
|
||||||
uint32_t drmFormat;
|
|
||||||
|
|
||||||
SDL_assert(frame->format != AV_PIX_FMT_DRM_PRIME);
|
SDL_assert(frame->format != AV_PIX_FMT_DRM_PRIME);
|
||||||
SDL_assert(!m_DrmPrimeBackend);
|
SDL_assert(!m_DrmPrimeBackend);
|
||||||
@@ -673,22 +674,33 @@ bool DrmRenderer::mapSoftwareFrame(AVFrame *frame, AVDRMFrameDescriptor *mappedF
|
|||||||
freeFrame = false;
|
freeFrame = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t drmFormat;
|
||||||
|
bool fullyPlanar;
|
||||||
int bpc;
|
int bpc;
|
||||||
|
|
||||||
// NB: Keep this list updated with isPixelFormatSupported()
|
// NB: Keep this list updated with isPixelFormatSupported()
|
||||||
switch (frame->format) {
|
switch (frame->format) {
|
||||||
case AV_PIX_FMT_NV12:
|
case AV_PIX_FMT_NV12:
|
||||||
drmFormat = DRM_FORMAT_NV12;
|
drmFormat = DRM_FORMAT_NV12;
|
||||||
|
fullyPlanar = false;
|
||||||
bpc = 8;
|
bpc = 8;
|
||||||
break;
|
break;
|
||||||
case AV_PIX_FMT_NV21:
|
case AV_PIX_FMT_NV21:
|
||||||
drmFormat = DRM_FORMAT_NV21;
|
drmFormat = DRM_FORMAT_NV21;
|
||||||
|
fullyPlanar = false;
|
||||||
bpc = 8;
|
bpc = 8;
|
||||||
break;
|
break;
|
||||||
case AV_PIX_FMT_P010:
|
case AV_PIX_FMT_P010:
|
||||||
drmFormat = DRM_FORMAT_P010;
|
drmFormat = DRM_FORMAT_P010;
|
||||||
|
fullyPlanar = false;
|
||||||
bpc = 16;
|
bpc = 16;
|
||||||
break;
|
break;
|
||||||
|
case AV_PIX_FMT_YUV420P:
|
||||||
|
case AV_PIX_FMT_YUVJ420P:
|
||||||
|
drmFormat = DRM_FORMAT_YUV420;
|
||||||
|
fullyPlanar = true;
|
||||||
|
bpc = 8;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Unable to map frame with unsupported format: %d",
|
"Unable to map frame with unsupported format: %d",
|
||||||
@@ -781,13 +793,18 @@ bool DrmRenderer::mapSoftwareFrame(AVFrame *frame, AVDRMFrameDescriptor *mappedF
|
|||||||
auto &plane = layer.planes[layer.nb_planes];
|
auto &plane = layer.planes[layer.nb_planes];
|
||||||
|
|
||||||
plane.object_index = 0;
|
plane.object_index = 0;
|
||||||
plane.pitch = drmFrame->pitch;
|
|
||||||
plane.offset = i == 0 ? 0 : (layer.planes[layer.nb_planes - 1].offset + lastPlaneSize);
|
plane.offset = i == 0 ? 0 : (layer.planes[layer.nb_planes - 1].offset + lastPlaneSize);
|
||||||
|
|
||||||
int planeHeight;
|
int planeHeight;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
// Y plane is not subsampled
|
// Y plane is not subsampled
|
||||||
planeHeight = frame->height;
|
planeHeight = frame->height;
|
||||||
|
plane.pitch = drmFrame->pitch;
|
||||||
|
}
|
||||||
|
else if (fullyPlanar) {
|
||||||
|
// U/V planes are 2x2 subsampled
|
||||||
|
planeHeight = frame->height / 2;
|
||||||
|
plane.pitch = drmFrame->pitch / 2;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// UV/VU planes are 2x2 subsampled.
|
// UV/VU planes are 2x2 subsampled.
|
||||||
@@ -795,10 +812,11 @@ bool DrmRenderer::mapSoftwareFrame(AVFrame *frame, AVDRMFrameDescriptor *mappedF
|
|||||||
// NB: The pitch is the same between Y and UV/VU, because the 2x subsampling
|
// NB: The pitch is the same between Y and UV/VU, because the 2x subsampling
|
||||||
// is cancelled out by the 2x plane size of UV/VU vs U/V alone.
|
// is cancelled out by the 2x plane size of UV/VU vs U/V alone.
|
||||||
planeHeight = frame->height / 2;
|
planeHeight = frame->height / 2;
|
||||||
|
plane.pitch = drmFrame->pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the plane data into the dumb buffer
|
// Copy the plane data into the dumb buffer
|
||||||
if (frame->linesize[i] == (int)drmFrame->pitch) {
|
if (frame->linesize[i] == (int)plane.pitch) {
|
||||||
// We can do a single memcpy() if the pitch is compatible
|
// We can do a single memcpy() if the pitch is compatible
|
||||||
memcpy(drmFrame->mapping + plane.offset,
|
memcpy(drmFrame->mapping + plane.offset,
|
||||||
frame->data[i],
|
frame->data[i],
|
||||||
@@ -807,15 +825,15 @@ bool DrmRenderer::mapSoftwareFrame(AVFrame *frame, AVDRMFrameDescriptor *mappedF
|
|||||||
else {
|
else {
|
||||||
// The pitch is incompatible, so we must copy line-by-line
|
// The pitch is incompatible, so we must copy line-by-line
|
||||||
for (int j = 0; j < planeHeight; j++) {
|
for (int j = 0; j < planeHeight; j++) {
|
||||||
memcpy(drmFrame->mapping + (j * drmFrame->pitch) + plane.offset,
|
memcpy(drmFrame->mapping + (j * plane.pitch) + plane.offset,
|
||||||
frame->data[i] + (j * frame->linesize[i]),
|
frame->data[i] + (j * frame->linesize[i]),
|
||||||
qMin(frame->linesize[i], (int)drmFrame->pitch));
|
qMin(frame->linesize[i], (int)plane.pitch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
layer.nb_planes++;
|
layer.nb_planes++;
|
||||||
|
|
||||||
lastPlaneSize = drmFrame->pitch * planeHeight;
|
lastPlaneSize = plane.pitch * planeHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user