Hi Cameron,
thanks for information.
I write a appliction which should display a camera input (detected with Ultra Studio Recorder) in a GUI. For this I use Qt. I use the Qt event loop with signal and slots for the frame transfer. The "architcture" of the event loop is "inspired" by the QuadPreview example from the SDK but instead of emit I use QMetaObject::invokeMethod and the QThreading module.
Actually the constrcutor of the class (which initiaizes the ScreenHelperPreview and manages OpenGL, the GUI-Class (which handles starting the video when a button is clicked) and the slot function, that calles SetFrame() runs in the same thread. So, I think there should no problem. But when I start the video I get a black screen. When I debug the program I see that the event loop runs.
I will be very thankful if you, or someone else, have an idea why this did not work.
- Code: Select all
/**
* Videoscreen.cpp
*/
VideoScreen::VideoScreen(QWidget* parent) :
m_previewHelper(nullptr)
{
qDebug() << "VideoScreen constructor was called.";
//Registering the type name of type CComPtr<IDeckLinkVideoFrame>, requires include<QMetaType>
//Create and destroy objects of the type dyamically at runtime after registration
qRegisterMetaType<CComPtr<IDeckLinkVideoFrame>>("CComPtr<IDeckLinkVideoFrame>");
//Initializing Screen Preview Helper
ScreenPreviewHelperInstance(m_previewHelper);
m_vsThread = new QThread();
m_drawFrame = new VideoScreenHelper(parent);
m_drawFrame->moveToThread(m_vsThread);
//QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)
QObject::connect(m_drawFrame, &VideoScreenHelper::FrameChanged, this, &VideoScreen::HandleFrame, Qt::QueuedConnection);
QObject::connect(m_vsThread, &QThread::finished, m_drawFrame, &QObject::deleteLater); //Deletes VideoScreenHelper object
QObject::connect(m_vsThread, &QThread::finished, m_vsThread, &QObject::deleteLater); //Deletes QThread object
m_vsThread->start();
qDebug() << "VideoScreen Ctor: Thread-ID is " << QThread::currentThreadId();
}
/**
* Function that inializes a ScreenPreviewHelper instance. Function is called in the constructor.
*/
CComPtr<IDeckLinkGLScreenPreviewHelper> VideoScreen::ScreenPreviewHelperInstance(CComPtr<IDeckLinkGLScreenPreviewHelper> previewHelper) {
HRESULT result = CoCreateInstance(CLSID_CDeckLinkGLScreenPreviewHelper, NULL, CLSCTX_ALL, IID_IDeckLinkGLScreenPreviewHelper, (void**)&m_previewHelper);
if (result == S_OK) {
qDebug() << "ScreenPreviewHelper installed.";
}
return m_previewHelper;
}
/**
* Getter function
*/
IDeckLinkScreenPreviewCallback* VideoScreen::GetScreenPreviewCallback() {
qDebug() << "VideoScreen: GetScreenPeviewCallback was called.";
return m_drawFrame;
}
/**
* Slot function - Sets up the frame
*/
void VideoScreen::HandleFrame(CComPtr<IDeckLinkVideoFrame> frame) {
if (m_previewHelper != nullptr) {
m_previewHelper->SetFrame(frame);
qDebug() << "VideoScreen: HandleFrame method is called. Thread-ID: " << QThread::currentThreadId();
}
}
//QOpenGLWidget Interface functions
/**
*
*/
void VideoScreen::initializeGL() {
if (m_previewHelper != nullptr) {
m_previewHelper->InitializeGL();
qDebug() << "VideoScreen: initalizeGL works.";
}
}
void VideoScreen::paintGL() {
if (m_previewHelper != nullptr) {
m_previewHelper->PaintGL();
qDebug() << "VideoScreen: paintGL was called.";
}
}
void VideoScreen::resizeGL(int w, int h) {
QOpenGLFunctions* m_gLFuncs = QOpenGLContext::currentContext()->functions();
m_gLFuncs->glViewport(0, 0, w, h);
}
- Code: Select all
/**
* VideoScreenHelper.cpp
*/
VideoScreenHelper::VideoScreenHelper(QObject* parent)
: m_referenceCounter(1)
{}
/**
* Dtor
*/
VideoScreenHelper::~VideoScreenHelper()
{}
/**
* The method is called on every incoming frame and is derived from the IDeckLinkScreenPreviewCallback
*/
HRESULT VideoScreenHelper::DrawFrame(IDeckLinkVideoFrame* frame) {
QMetaObject::invokeMethod(this, "FrameChanged", Qt::QueuedConnection, Q_ARG(CComPtr<IDeckLinkVideoFrame>, frame));
qDebug() << "VideoScreenHelper: DrawFrame is called. Thread-ID is " << QThread::currentThreadId();
return S_OK;
}
- Code: Select all
/**
* QVideoMeter
*/
QVideoMeter::QVideoMeter(QWidget* parent)
: QWidget(parent)
{
//initializes ControlVideo with a decklink instance
m_control = std::make_unique<ControlVideo>(m_init->CreateDeckLinkInstance());
m_videoScreen = new VideoScreen(parent);
ui.setupUi(this);
//Observer pattern in Qt style. If the start button is released, the video stream starts
QObject::connect(ui.startBtn, &QPushButton::clicked, this, &QVideoMeter::QStartVideo);
QObject::connect(ui.stopBtn, &QPushButton::released, this, &QVideoMeter::QStopVideo);
qDebug() << "QVideoMeter CTOR" << QThread::currentThreadId();
}
/**
* Dtor
*/
QVideoMeter::~QVideoMeter() {
//delete ui;
}
/**
* Button interaction. If the start button is pressed the StartVideo function is called
*/
void QVideoMeter::QStartVideo() {
HRESULT inputVideoData = m_control->StartVideo(bmdModeHD1080p25, bmdFormat8BitYUV, bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2, false, m_videoScreen->GetScreenPreviewCallback());
if (inputVideoData == S_OK) {
ui.startBtn->setText("Running");
qDebug() << "QVideoMeter: StartButton clicked. Stream is running.";
}
else {
QMessageBox::information(this, "Kein Input", "Es wurde kein Eingangssignal erkannt.");
}
}