Input GPU decoding
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
#include "DeckLinkVideoIOFormat.h"
|
||||
#include "../logging/Logger.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <new>
|
||||
|
||||
@@ -24,28 +23,6 @@ bool FindInputDisplayMode(IDeckLinkInput* input, BMDDisplayMode targetMode, IDec
|
||||
return FindDeckLinkDisplayMode(iterator, targetMode, foundMode);
|
||||
}
|
||||
|
||||
unsigned char ClampToByte(double value)
|
||||
{
|
||||
if (value <= 0.0)
|
||||
return 0;
|
||||
if (value >= 255.0)
|
||||
return 255;
|
||||
return static_cast<unsigned char>(value + 0.5);
|
||||
}
|
||||
|
||||
void StoreRec709UyvyAsBgra(unsigned char yByte, unsigned char uByte, unsigned char vByte, unsigned char* destination)
|
||||
{
|
||||
const double y = (static_cast<double>(yByte) - 16.0) / 219.0;
|
||||
const double cb = (static_cast<double>(uByte) - 16.0) / 224.0 - 0.5;
|
||||
const double cr = (static_cast<double>(vByte) - 16.0) / 224.0 - 0.5;
|
||||
const double red = y + 1.5748 * cr;
|
||||
const double green = y - 0.1873 * cb - 0.4681 * cr;
|
||||
const double blue = y + 1.8556 * cb;
|
||||
destination[0] = ClampToByte(blue * 255.0);
|
||||
destination[1] = ClampToByte(green * 255.0);
|
||||
destination[2] = ClampToByte(red * 255.0);
|
||||
destination[3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
DeckLinkInputCallback::DeckLinkInputCallback(DeckLinkInput& owner) :
|
||||
@@ -122,7 +99,7 @@ bool DeckLinkInput::Initialize(const DeckLinkInputConfig& config, std::string& e
|
||||
}
|
||||
Log(
|
||||
"decklink-input",
|
||||
std::string("DeckLink input enabled in ") + (mCapturePixelFormat == bmdFormat8BitBGRA ? "BGRA8" : "UYVY8-to-BGRA8 conversion") + " mode.");
|
||||
std::string("DeckLink input enabled in ") + (mCapturePixelFormat == bmdFormat8BitBGRA ? "BGRA8" : "UYVY8 raw capture") + " mode.");
|
||||
|
||||
mCallback.Attach(new (std::nothrow) DeckLinkInputCallback(*this));
|
||||
if (mCallback == nullptr)
|
||||
@@ -197,6 +174,11 @@ DeckLinkInputMetrics DeckLinkInput::Metrics() const
|
||||
return metrics;
|
||||
}
|
||||
|
||||
VideoIOPixelFormat DeckLinkInput::CapturePixelFormat() const
|
||||
{
|
||||
return mCapturePixelFormat == bmdFormat8BitYUV ? VideoIOPixelFormat::Uyvy8 : VideoIOPixelFormat::Bgra8;
|
||||
}
|
||||
|
||||
void DeckLinkInput::HandleFrameArrived(IDeckLinkVideoInputFrame* inputFrame)
|
||||
{
|
||||
if (inputFrame == nullptr)
|
||||
@@ -263,7 +245,7 @@ void DeckLinkInput::HandleFrameArrived(IDeckLinkVideoInputFrame* inputFrame)
|
||||
{
|
||||
Log(
|
||||
"decklink-input",
|
||||
std::string("First DeckLink ") + (mCapturePixelFormat == bmdFormat8BitBGRA ? "BGRA8" : "UYVY8 converted BGRA8") + " input frame submitted to InputFrameMailbox.");
|
||||
std::string("First DeckLink ") + (mCapturePixelFormat == bmdFormat8BitBGRA ? "BGRA8" : "UYVY8 raw") + " input frame submitted to InputFrameMailbox.");
|
||||
}
|
||||
|
||||
inputFrameBuffer->EndAccess(bmdBufferAccessRead);
|
||||
@@ -305,7 +287,7 @@ bool DeckLinkInput::DiscoverInput(const DeckLinkInputConfig& config, std::string
|
||||
{
|
||||
mInput = candidateInput;
|
||||
mCapturePixelFormat = bmdFormat8BitYUV;
|
||||
Log("decklink-input", "DeckLink input device selected for UYVY8 capture with CPU BGRA8 conversion.");
|
||||
Log("decklink-input", "DeckLink input device selected for UYVY8 raw capture with render-thread GPU decode.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -360,34 +342,10 @@ bool DeckLinkInput::SubmitUyvy8Frame(IDeckLinkVideoInputFrame* inputFrame, const
|
||||
if (width == 0 || height == 0 || sourceRowBytes < static_cast<long>(width * 2u))
|
||||
return false;
|
||||
|
||||
const unsigned destinationRowBytes = VideoIORowBytes(VideoIOPixelFormat::Bgra8, width);
|
||||
const auto convertStart = std::chrono::steady_clock::now();
|
||||
mConversionBuffer.resize(static_cast<std::size_t>(destinationRowBytes) * static_cast<std::size_t>(height));
|
||||
const unsigned char* sourceBytes = static_cast<const unsigned char*>(bytes);
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
const unsigned char* sourceRow = sourceBytes + static_cast<std::size_t>(y) * static_cast<std::size_t>(sourceRowBytes);
|
||||
unsigned char* destinationRow = mConversionBuffer.data() + static_cast<std::size_t>(y) * static_cast<std::size_t>(destinationRowBytes);
|
||||
for (unsigned x = 0; x < width; x += 2)
|
||||
{
|
||||
const unsigned pairOffset = x * 2u;
|
||||
const unsigned char u = sourceRow[pairOffset + 0];
|
||||
const unsigned char y0 = sourceRow[pairOffset + 1];
|
||||
const unsigned char v = sourceRow[pairOffset + 2];
|
||||
const unsigned char y1 = sourceRow[pairOffset + 3];
|
||||
StoreRec709UyvyAsBgra(y0, u, v, destinationRow + static_cast<std::size_t>(x) * 4u);
|
||||
if (x + 1u < width)
|
||||
StoreRec709UyvyAsBgra(y1, u, v, destinationRow + static_cast<std::size_t>(x + 1u) * 4u);
|
||||
}
|
||||
}
|
||||
const auto convertEnd = std::chrono::steady_clock::now();
|
||||
mConvertMilliseconds.store(
|
||||
std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(convertEnd - convertStart).count(),
|
||||
std::memory_order_relaxed);
|
||||
|
||||
mConvertMilliseconds.store(0.0, std::memory_order_relaxed);
|
||||
const uint64_t frameIndex = mCapturedFrames.load(std::memory_order_relaxed);
|
||||
const auto submitStart = std::chrono::steady_clock::now();
|
||||
const bool submitted = mMailbox.SubmitFrame(mConversionBuffer.data(), destinationRowBytes, frameIndex);
|
||||
const bool submitted = mMailbox.SubmitFrame(bytes, static_cast<unsigned>(sourceRowBytes), frameIndex);
|
||||
const auto submitEnd = std::chrono::steady_clock::now();
|
||||
mSubmitMilliseconds.store(
|
||||
std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(submitEnd - submitStart).count(),
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
|
||||
bool IsInitialized() const { return mInput != nullptr; }
|
||||
bool IsRunning() const { return mRunning.load(std::memory_order_acquire); }
|
||||
VideoIOPixelFormat CapturePixelFormat() const;
|
||||
DeckLinkInputMetrics Metrics() const;
|
||||
|
||||
void HandleFrameArrived(IDeckLinkVideoInputFrame* inputFrame);
|
||||
@@ -80,7 +81,6 @@ private:
|
||||
BMDPixelFormat mCapturePixelFormat = bmdFormat8BitBGRA;
|
||||
CComPtr<IDeckLinkInput> mInput;
|
||||
CComPtr<DeckLinkInputCallback> mCallback;
|
||||
std::vector<unsigned char> mConversionBuffer;
|
||||
std::atomic<bool> mRunning{ false };
|
||||
std::atomic<uint64_t> mCapturedFrames{ 0 };
|
||||
std::atomic<uint64_t> mNoInputSourceFrames{ 0 };
|
||||
|
||||
Reference in New Issue
Block a user