109 lines
2.8 KiB
C++
109 lines
2.8 KiB
C++
#include "InputFrameTexture.h"
|
|
|
|
#include <chrono>
|
|
|
|
InputFrameTexture::~InputFrameTexture()
|
|
{
|
|
ShutdownGl();
|
|
}
|
|
|
|
GLuint InputFrameTexture::PollAndUpload(InputFrameMailbox* mailbox)
|
|
{
|
|
if (mailbox == nullptr)
|
|
return mTexture;
|
|
|
|
InputFrame frame;
|
|
if (!mailbox->TryAcquireLatest(frame))
|
|
{
|
|
++mUploadMisses;
|
|
mLastUploadMilliseconds = 0.0;
|
|
return mTexture;
|
|
}
|
|
|
|
if (frame.bytes != nullptr && frame.pixelFormat == VideoIOPixelFormat::Bgra8 && EnsureTexture(frame))
|
|
{
|
|
mLastFrameFormatSupported = true;
|
|
const auto uploadStart = std::chrono::steady_clock::now();
|
|
UploadBgra8FrameFlippedVertically(frame);
|
|
const auto uploadEnd = std::chrono::steady_clock::now();
|
|
mLastUploadMilliseconds = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(uploadEnd - uploadStart).count();
|
|
++mUploadedFrames;
|
|
}
|
|
else
|
|
{
|
|
mLastFrameFormatSupported = frame.pixelFormat == VideoIOPixelFormat::Bgra8;
|
|
mLastUploadMilliseconds = 0.0;
|
|
}
|
|
|
|
mailbox->Release(frame);
|
|
return mTexture;
|
|
}
|
|
|
|
void InputFrameTexture::ShutdownGl()
|
|
{
|
|
if (mTexture != 0)
|
|
glDeleteTextures(1, &mTexture);
|
|
mTexture = 0;
|
|
mWidth = 0;
|
|
mHeight = 0;
|
|
}
|
|
|
|
bool InputFrameTexture::EnsureTexture(const InputFrame& frame)
|
|
{
|
|
if (frame.width == 0 || frame.height == 0)
|
|
return false;
|
|
|
|
if (mTexture != 0 && mWidth == frame.width && mHeight == frame.height)
|
|
return true;
|
|
|
|
ShutdownGl();
|
|
glGenTextures(1, &mTexture);
|
|
glBindTexture(GL_TEXTURE_2D, mTexture);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexImage2D(
|
|
GL_TEXTURE_2D,
|
|
0,
|
|
GL_RGBA8,
|
|
static_cast<GLsizei>(frame.width),
|
|
static_cast<GLsizei>(frame.height),
|
|
0,
|
|
GL_BGRA,
|
|
GL_UNSIGNED_INT_8_8_8_8_REV,
|
|
nullptr);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
mWidth = frame.width;
|
|
mHeight = frame.height;
|
|
return mTexture != 0;
|
|
}
|
|
|
|
void InputFrameTexture::UploadBgra8FrameFlippedVertically(const InputFrame& frame)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, mTexture);
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.rowBytes > 0 ? static_cast<GLint>(frame.rowBytes / 4) : 0);
|
|
|
|
const unsigned char* sourceBytes = static_cast<const unsigned char*>(frame.bytes);
|
|
for (unsigned destinationY = 0; destinationY < frame.height; ++destinationY)
|
|
{
|
|
const unsigned sourceY = frame.height - 1u - destinationY;
|
|
const unsigned char* sourceRow = sourceBytes + static_cast<std::size_t>(sourceY) * static_cast<std::size_t>(frame.rowBytes);
|
|
glTexSubImage2D(
|
|
GL_TEXTURE_2D,
|
|
0,
|
|
0,
|
|
static_cast<GLint>(destinationY),
|
|
static_cast<GLsizei>(frame.width),
|
|
1,
|
|
GL_BGRA,
|
|
GL_UNSIGNED_INT_8_8_8_8_REV,
|
|
sourceRow);
|
|
}
|
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|