#include "InputFrameTexture.h" #include 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>(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(frame.width), static_cast(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(frame.rowBytes / 4) : 0); const unsigned char* sourceBytes = static_cast(frame.bytes); for (unsigned destinationY = 0; destinationY < frame.height; ++destinationY) { const unsigned sourceY = frame.height - 1u - destinationY; const unsigned char* sourceRow = sourceBytes + static_cast(sourceY) * static_cast(frame.rowBytes); glTexSubImage2D( GL_TEXTURE_2D, 0, 0, static_cast(destinationY), static_cast(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); }