Support fully-planar output in DrmRenderer

This commit is contained in:
Cameron Gutman
2023-09-12 18:08:48 -05:00
parent 47b04eee3e
commit fd41226cdd
+24 -6
View File
@@ -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;
} }
} }