Skip to content

Commit

Permalink
Fix alignment problems when uploading frames to texture memory
Browse files Browse the repository at this point in the history
  • Loading branch information
marlam committed Sep 23, 2024
1 parent f72f9d4 commit d8f97a0
Showing 1 changed file with 67 additions and 0 deletions.
67 changes: 67 additions & 0 deletions src/bino.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,19 @@ bool Bino::drawSubtitleToImage(int w, int h, const QString& string)
return true;
}

static int alignmentFromBytesPerLine(const void* data, int bpl)
{
int alignment = 1;
if (uint64_t(data) % 8 == 0 && bpl % 8 == 0)
alignment = 8;
else if (uint64_t(data) % 4 == 0 && bpl % 4 == 0)
alignment = 4;
else if (uint64_t(data) % 2 == 0 && bpl % 2 == 0)
alignment = 2;
LOG_FIREHOSE("convertFrameToTexture: alignment is %d (from data %p, bpl %d)", alignment, data, bpl);
return alignment;
}

void Bino::convertFrameToTexture(const VideoFrame& frame, unsigned int frameTex)
{
// 1. Get the frame data into plane textures
Expand All @@ -906,6 +919,9 @@ void Bino::convertFrameToTexture(const VideoFrame& frame, unsigned int frameTex)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
if (frame.storage == VideoFrame::Storage_Image) {
LOG_FIREHOSE("convertFrameToTexture: format is image");
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(frame.image.constBits(), frame.image.bytesPerLine()));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.image.bytesPerLine() / 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame.image.constBits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
Expand All @@ -923,6 +939,9 @@ void Bino::convertFrameToTexture(const VideoFrame& frame, unsigned int frameTex)
if (frame.pixelFormat == QVideoFrameFormat::Format_ARGB8888
|| frame.pixelFormat == QVideoFrameFormat::Format_ARGB8888_Premultiplied
|| frame.pixelFormat == QVideoFrameFormat::Format_XRGB8888) {
LOG_FIREHOSE("convertFrameToTexture: format argb8888");
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[0], frame.qframe.bytesPerLine(0)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(0) / 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, planeData[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ALPHA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
Expand All @@ -933,6 +952,9 @@ void Bino::convertFrameToTexture(const VideoFrame& frame, unsigned int frameTex)
} else if (frame.pixelFormat == QVideoFrameFormat::Format_BGRA8888
|| frame.pixelFormat == QVideoFrameFormat::Format_BGRA8888_Premultiplied
|| frame.pixelFormat == QVideoFrameFormat::Format_BGRX8888) {
LOG_FIREHOSE("convertFrameToTexture: format bgra8888");
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[0], frame.qframe.bytesPerLine(0)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(0) / 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, planeData[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
Expand All @@ -942,6 +964,9 @@ void Bino::convertFrameToTexture(const VideoFrame& frame, unsigned int frameTex)
planeCount = 1;
} else if (frame.pixelFormat == QVideoFrameFormat::Format_ABGR8888
|| frame.pixelFormat == QVideoFrameFormat::Format_XBGR8888) {
LOG_FIREHOSE("convertFrameToTexture: format abgr8888");
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[0], frame.qframe.bytesPerLine(0)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(0) / 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, planeData[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ALPHA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_BLUE);
Expand All @@ -951,51 +976,91 @@ void Bino::convertFrameToTexture(const VideoFrame& frame, unsigned int frameTex)
planeCount = 1;
} else if (frame.pixelFormat == QVideoFrameFormat::Format_RGBA8888
|| frame.pixelFormat == QVideoFrameFormat::Format_RGBX8888) {
LOG_FIREHOSE("convertFrameToTexture: format rgba8888");
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[0], frame.qframe.bytesPerLine(0)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(0) / 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, planeData[0]);
planeFormat = 1;
planeCount = 1;
} else if (frame.pixelFormat == QVideoFrameFormat::Format_YUV420P) {
LOG_FIREHOSE("convertFrameToTexture: format yuv420p");
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[0], frame.qframe.bytesPerLine(0)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(0));
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, planeData[0]);
glBindTexture(GL_TEXTURE_2D, _planeTexs[1]);
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[1], frame.qframe.bytesPerLine(1)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(1));
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w / 2, h / 2, 0, GL_RED, GL_UNSIGNED_BYTE, planeData[1]);
glBindTexture(GL_TEXTURE_2D, _planeTexs[2]);
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[2], frame.qframe.bytesPerLine(2)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(2));
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w / 2, h / 2, 0, GL_RED, GL_UNSIGNED_BYTE, planeData[2]);
planeFormat = 2;
planeCount = 3;
} else if (frame.pixelFormat == QVideoFrameFormat::Format_YUV422P) {
LOG_FIREHOSE("convertFrameToTexture: format yuv422p");
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[0], frame.qframe.bytesPerLine(0)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(0));
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, planeData[0]);
glBindTexture(GL_TEXTURE_2D, _planeTexs[1]);
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[1], frame.qframe.bytesPerLine(1)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(1));
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w / 2, h, 0, GL_RED, GL_UNSIGNED_BYTE, planeData[1]);
glBindTexture(GL_TEXTURE_2D, _planeTexs[2]);
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[2], frame.qframe.bytesPerLine(2)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(2));
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w / 2, h, 0, GL_RED, GL_UNSIGNED_BYTE, planeData[2]);
planeFormat = 2;
planeCount = 3;
} else if (frame.pixelFormat == QVideoFrameFormat::Format_YV12) {
LOG_FIREHOSE("convertFrameToTexture: format yv12");
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[0], frame.qframe.bytesPerLine(0)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(0));
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, planeData[0]);
glBindTexture(GL_TEXTURE_2D, _planeTexs[1]);
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[1], frame.qframe.bytesPerLine(1)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(1));
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w / 2, h / 2, 0, GL_RED, GL_UNSIGNED_BYTE, planeData[1]);
glBindTexture(GL_TEXTURE_2D, _planeTexs[2]);
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[2], frame.qframe.bytesPerLine(2)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(2));
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w / 2, h / 2, 0, GL_RED, GL_UNSIGNED_BYTE, planeData[2]);
planeFormat = 3;
planeCount = 3;
} else if (frame.pixelFormat == QVideoFrameFormat::Format_NV12) {
LOG_FIREHOSE("convertFrameToTexture: format nv12");
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[0], frame.qframe.bytesPerLine(0)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(0));
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, planeData[0]);
glBindTexture(GL_TEXTURE_2D, _planeTexs[1]);
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[1], frame.qframe.bytesPerLine(1)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(1) / 2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, w / 2, h / 2, 0, GL_RG, GL_UNSIGNED_BYTE, planeData[1]);
planeFormat = 4;
planeCount = 2;
} else if (frame.pixelFormat == QVideoFrameFormat::Format_P010
|| frame.pixelFormat == QVideoFrameFormat::Format_P016) {
LOG_FIREHOSE("convertFrameToTexture: format p010/p016");
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[0], frame.qframe.bytesPerLine(0)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(0) / 2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, w, h, 0, GL_RED, GL_UNSIGNED_SHORT, planeData[0]);
glBindTexture(GL_TEXTURE_2D, _planeTexs[1]);
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[1], frame.qframe.bytesPerLine(1)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(1) / 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16, w / 2, h / 2, 0, GL_RG, GL_UNSIGNED_SHORT, planeData[1]);
planeFormat = 4;
planeCount = 2;
} else if (frame.pixelFormat == QVideoFrameFormat::Format_Y8) {
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[0], frame.qframe.bytesPerLine(0)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(0));
LOG_FIREHOSE("convertFrameToTexture: format y8");
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, planeData[0]);
planeFormat = 5;
planeCount = 1;
} else if (frame.pixelFormat == QVideoFrameFormat::Format_Y16) {
glPixelStorei(GL_UNPACK_ALIGNMENT, alignmentFromBytesPerLine(planeData[0], frame.qframe.bytesPerLine(0)));
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.qframe.bytesPerLine(0) / 2);
LOG_FIREHOSE("convertFrameToTexture: format y16");
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, w, h, 0, GL_RED, GL_UNSIGNED_SHORT, planeData[0]);
planeFormat = 5;
planeCount = 1;
Expand All @@ -1004,6 +1069,8 @@ void Bino::convertFrameToTexture(const VideoFrame& frame, unsigned int frameTex)
std::exit(1);
}
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
// 2. Convert plane textures into linear RGB in the frame texture
glBindTexture(GL_TEXTURE_2D, frameTex);
if (IsOpenGLES)
Expand Down

0 comments on commit d8f97a0

Please sign in to comment.