Skip to content
Snippets Groups Projects
Verified Commit 1e2605e9 authored by Silas Della Contrada's avatar Silas Della Contrada
Browse files

feat(codec): Implemented QSV decoder

fix(common): Changed QSV native format selector to:
  One luminance plane and one chrominance plane
fix(render): Now moving opengl context back to main thread after FallbackFrameMapper stops
parent 24db03af
No related branches found
No related tags found
1 merge request!17Draft: Resolve "Migrate frame passing to libProcessingGraph"
...@@ -80,7 +80,7 @@ namespace AVQt::common { ...@@ -80,7 +80,7 @@ namespace AVQt::common {
AVQt::common::PixelFormat::registerGPUFormat({.format = AV_PIX_FMT_MMAL, .nativeFormat = nullptr}); AVQt::common::PixelFormat::registerGPUFormat({.format = AV_PIX_FMT_MMAL, .nativeFormat = nullptr});
AVQt::common::PixelFormat::registerGPUFormat({.format = AV_PIX_FMT_MEDIACODEC, .nativeFormat = nullptr}); AVQt::common::PixelFormat::registerGPUFormat({.format = AV_PIX_FMT_MEDIACODEC, .nativeFormat = nullptr});
AVQt::common::PixelFormat::registerGPUFormat({.format = AV_PIX_FMT_QSV, .nativeFormat = &FullFormatPixelFormatOf}); AVQt::common::PixelFormat::registerGPUFormat({.format = AV_PIX_FMT_QSV, .nativeFormat = &OneInterleavedPlanePixelFormatOf});
AVQt::common::PixelFormat::registerGPUFormat({.format = AV_PIX_FMT_VDPAU, .nativeFormat = nullptr}); AVQt::common::PixelFormat::registerGPUFormat({.format = AV_PIX_FMT_VDPAU, .nativeFormat = nullptr});
AVQt::common::PixelFormat::registerGPUFormat({.format = AV_PIX_FMT_VIDEOTOOLBOX, .nativeFormat = nullptr}); AVQt::common::PixelFormat::registerGPUFormat({.format = AV_PIX_FMT_VIDEOTOOLBOX, .nativeFormat = nullptr});
......
...@@ -6,13 +6,14 @@ ...@@ -6,13 +6,14 @@
#include "private/QSVDecoderImpl_p.hpp" #include "private/QSVDecoderImpl_p.hpp"
#include "common/PixelFormat.hpp" #include "common/PixelFormat.hpp"
#include "decoder/VideoDecoderFactory.hpp"
namespace AVQt { namespace AVQt {
const api::VideoDecoderInfo &QSVDecoderImpl::info() { const api::VideoDecoderInfo &QSVDecoderImpl::info() {
static const api::VideoDecoderInfo info = { static const api::VideoDecoderInfo info = {
.metaObject = QSVDecoderImpl::staticMetaObject, .metaObject = QSVDecoderImpl::staticMetaObject,
.name = "VAAPI", .name = "QSV",
.platforms = {common::Platform::Linux_X11, common::Platform::Linux_Wayland}, .platforms = {common::Platform::Linux_X11, common::Platform::Linux_Wayland, common::Platform::Windows},
.supportedInputPixelFormats = { .supportedInputPixelFormats = {
{AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE}, {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE},
{AV_PIX_FMT_YUV420P10, AV_PIX_FMT_NONE}, {AV_PIX_FMT_YUV420P10, AV_PIX_FMT_NONE},
...@@ -102,7 +103,7 @@ namespace AVQt { ...@@ -102,7 +103,7 @@ namespace AVQt {
auto *framesContext = reinterpret_cast<AVHWFramesContext *>(framesCtxRef->data); auto *framesContext = reinterpret_cast<AVHWFramesContext *>(framesCtxRef->data);
framesContext->format = AV_PIX_FMT_QSV; framesContext->format = AV_PIX_FMT_QSV;
framesContext->sw_format = static_cast<AVPixelFormat>(d->codecParams->format); framesContext->sw_format = common::PixelFormat{static_cast<AVPixelFormat>(d->codecParams->format), AV_PIX_FMT_QSV}.toNativeFormat().getCPUFormat();
framesContext->width = d->codecParams->width; framesContext->width = d->codecParams->width;
framesContext->height = d->codecParams->height; framesContext->height = d->codecParams->height;
framesContext->initial_pool_size = 32; framesContext->initial_pool_size = 32;
...@@ -128,6 +129,13 @@ namespace AVQt { ...@@ -128,6 +129,13 @@ namespace AVQt {
goto fail; goto fail;
} }
d->frameFetcher = std::make_unique<QSVDecoderImplPrivate::FrameFetcher>(d);
d->frameFetcher->start();
if (!d->frameFetcher->isRunning()) {
qWarning() << "[AVQt::QSVDecoderImpl] Failed to start frame fetcher";
goto fail;
}
return true; return true;
} else { } else {
qWarning("[AVQt::QSVDecoderImpl] Already opened"); qWarning("[AVQt::QSVDecoderImpl] Already opened");
...@@ -135,6 +143,7 @@ namespace AVQt { ...@@ -135,6 +143,7 @@ namespace AVQt {
} }
fail: fail:
d->open = false; d->open = false;
d->frameFetcher.reset();
d->codecContext.reset(); d->codecContext.reset();
d->hwDeviceContext.reset(); d->hwDeviceContext.reset();
d->hwFramesContext.reset(); d->hwFramesContext.reset();
...@@ -146,6 +155,7 @@ namespace AVQt { ...@@ -146,6 +155,7 @@ namespace AVQt {
bool shouldBe = false; bool shouldBe = false;
if (d->open.compare_exchange_strong(shouldBe, false)) { if (d->open.compare_exchange_strong(shouldBe, false)) {
d->frameFetcher.reset();
d->codecContext.reset(); d->codecContext.reset();
d->hwDeviceContext.reset(); d->hwDeviceContext.reset();
d->hwFramesContext.reset(); d->hwFramesContext.reset();
...@@ -308,3 +318,7 @@ namespace AVQt { ...@@ -308,3 +318,7 @@ namespace AVQt {
qDebug() << "FrameFetcher stopped"; qDebug() << "FrameFetcher stopped";
} }
}// namespace AVQt }// namespace AVQt
static_block {
AVQt::VideoDecoderFactory::getInstance().registerDecoder(AVQt::QSVDecoderImpl::info());
}
...@@ -14,10 +14,11 @@ namespace AVQt { ...@@ -14,10 +14,11 @@ namespace AVQt {
class QSVDecoderImpl : public QObject, public api::IVideoDecoderImpl { class QSVDecoderImpl : public QObject, public api::IVideoDecoderImpl {
Q_OBJECT Q_OBJECT
Q_DECLARE_PRIVATE(QSVDecoderImpl) Q_DECLARE_PRIVATE(QSVDecoderImpl)
Q_INTERFACES(AVQt::api::IVideoDecoderImpl)
public: public:
static const api::VideoDecoderInfo &info(); static const api::VideoDecoderInfo &info();
explicit QSVDecoderImpl(AVCodecID codecId, QObject *parent = nullptr); Q_INVOKABLE explicit QSVDecoderImpl(AVCodecID codecId, QObject *parent = nullptr);
~QSVDecoderImpl() override; ~QSVDecoderImpl() override;
bool open(std::shared_ptr<AVCodecParameters> codecParams) override; bool open(std::shared_ptr<AVCodecParameters> codecParams) override;
void close() override; void close() override;
......
...@@ -50,6 +50,8 @@ namespace AVQt { ...@@ -50,6 +50,8 @@ namespace AVQt {
std::shared_ptr<AVBufferRef> hwFramesContext{nullptr, &destroyAVBufferRef}; std::shared_ptr<AVBufferRef> hwFramesContext{nullptr, &destroyAVBufferRef};
std::atomic_bool open{false}, firstFrame{true}; std::atomic_bool open{false}, firstFrame{true};
std::unique_ptr<FrameFetcher> frameFetcher{};
}; };
}// namespace AVQt }// namespace AVQt
......
...@@ -209,6 +209,7 @@ namespace AVQt { ...@@ -209,6 +209,7 @@ namespace AVQt {
QMutexLocker lock(&d->renderMutex); QMutexLocker lock(&d->renderMutex);
bool shouldBe = true; bool shouldBe = true;
if (d->running.compare_exchange_strong(shouldBe, false)) { if (d->running.compare_exchange_strong(shouldBe, false)) {
d->afterStopThread = QThread::currentThread();
lock.unlock(); lock.unlock();
QThread::quit(); QThread::quit();
QThread::wait(); QThread::wait();
...@@ -382,6 +383,9 @@ namespace AVQt { ...@@ -382,6 +383,9 @@ namespace AVQt {
emit frameReady(frame->pts, fbo); emit frameReady(frame->pts, fbo);
qDebug("Frame ready"); qDebug("Frame ready");
} }
if (d->afterStopThread) {
d->context->moveToThread(d->afterStopThread);
}
} }
void FallbackFrameMapperPrivate::bindResources() { void FallbackFrameMapperPrivate::bindResources() {
......
...@@ -73,6 +73,8 @@ namespace AVQt { ...@@ -73,6 +73,8 @@ namespace AVQt {
QOpenGLBuffer vbo{}; QOpenGLBuffer vbo{};
QOpenGLBuffer ibo{}; QOpenGLBuffer ibo{};
QThread *afterStopThread{nullptr};
std::unique_ptr<SwsContext, decltype(&destroySwsContext)> pSwsContext{nullptr, &destroySwsContext}; std::unique_ptr<SwsContext, decltype(&destroySwsContext)> pSwsContext{nullptr, &destroySwsContext};
std::atomic_bool paused{false}, firstFrame{true}, running{false}; std::atomic_bool paused{false}, firstFrame{true}, running{false};
......
...@@ -9,7 +9,7 @@ if (NOT QT_VERSION) ...@@ -9,7 +9,7 @@ if (NOT QT_VERSION)
endif () endif ()
set(PGRAPH_QT_VERSION "${QT_VERSION}" CACHE INTERNAL "PGRAPH_QT_VERSION") set(PGRAPH_QT_VERSION "${QT_VERSION}" CACHE INTERNAL "PGRAPH_QT_VERSION")
set(SC_QT_VERSION "${QT_VERSION}" CACHE INTERNAL "SC_QT_VERSION") set(SC_QT_VERSION "${QT_VERSION}" CACHE INTERNAL "SC_QT_VERSION")
#set(CMAKE_PREFIX_PATH "/home/silas/ffmpeg_build/" CACHE INTERNAL "CMAKE_PREFIX_PATH") set(CMAKE_PREFIX_PATH "/home/silas/ffmpeg_build/" CACHE INTERNAL "CMAKE_PREFIX_PATH")
add_subdirectory(libpgraph_network) add_subdirectory(libpgraph_network)
......
...@@ -246,8 +246,8 @@ bool OpenGLWidgetRenderer::isPaused() const { ...@@ -246,8 +246,8 @@ bool OpenGLWidgetRenderer::isPaused() const {
bool OpenGLWidgetRenderer::open() { bool OpenGLWidgetRenderer::open() {
Q_D(OpenGLWidgetRenderer); Q_D(OpenGLWidgetRenderer);
d->mapper = AVQt::OpenGLFrameMapperFactory::getInstance().create({d->params.isHWAccel ? d->params.swPixelFormat : d->params.pixelFormat, d->params.isHWAccel ? d->params.pixelFormat : AV_PIX_FMT_NONE}, d->mapper = AVQt::OpenGLFrameMapperFactory::getInstance()
QStringList() << "VAAPI"); .create({d->params.isHWAccel ? d->params.swPixelFormat : d->params.pixelFormat, d->params.isHWAccel ? d->params.pixelFormat : AV_PIX_FMT_NONE});
// clang-format off // clang-format off
// Preserve normalized form of Qt SIGNAL/SLOT macro // Preserve normalized form of Qt SIGNAL/SLOT macro
connect(std::dynamic_pointer_cast<QObject>(d->mapper).get(), SIGNAL(frameReady(qint64,std::shared_ptr<QOpenGLFramebufferObject>)), connect(std::dynamic_pointer_cast<QObject>(d->mapper).get(), SIGNAL(frameReady(qint64,std::shared_ptr<QOpenGLFramebufferObject>)),
......
...@@ -53,9 +53,9 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt ...@@ -53,9 +53,9 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt
logFile.open(QIODevice::WriteOnly); logFile.open(QIODevice::WriteOnly);
} }
//#ifndef QT_DEBUG #ifndef QT_DEBUG
if (type > QtMsgType::QtDebugMsg) if (type > QtMsgType::QtDebugMsg)
//#endif #endif
{ {
QString output; QString output;
QTextStream os(&output); QTextStream os(&output);
...@@ -144,7 +144,7 @@ int main(int argc, char *argv[]) { ...@@ -144,7 +144,7 @@ int main(int argc, char *argv[]) {
auto muxer = std::make_shared<AVQt::Muxer>(std::move(muxerConfig), registry); auto muxer = std::make_shared<AVQt::Muxer>(std::move(muxerConfig), registry);
AVQt::VideoDecoder::Config videoDecoderConfig{}; AVQt::VideoDecoder::Config videoDecoderConfig{};
videoDecoderConfig.decoderPriority << "VAAPI"; videoDecoderConfig.decoderPriority << "QSV";
auto decoder1 = std::make_shared<AVQt::VideoDecoder>(videoDecoderConfig, registry); auto decoder1 = std::make_shared<AVQt::VideoDecoder>(videoDecoderConfig, registry);
auto decoder2 = std::make_shared<AVQt::VideoDecoder>(videoDecoderConfig, registry); auto decoder2 = std::make_shared<AVQt::VideoDecoder>(videoDecoderConfig, registry);
// auto decoder3 = std::make_shared<AVQt::VideoDecoder>("VAAPI", registry); // auto decoder3 = std::make_shared<AVQt::VideoDecoder>("VAAPI", registry);
...@@ -220,9 +220,9 @@ int main(int argc, char *argv[]) { ...@@ -220,9 +220,9 @@ int main(int argc, char *argv[]) {
// encoderInPad->link(decoder1OutPad); // encoderInPad->link(decoder1OutPad);
// decoder2InPad->link(encoderOutPad); // decoder2InPad->link(encoderOutPad);
decoder1InPad->link(demuxerOutPad); decoder1InPad->link(demuxerOutPad);
// ccInPad->link(decoder1OutPad); ccInPad->link(decoder1OutPad);
encoder1InPad->link(decoder1OutPad); // encoder1InPad->link(decoder1OutPad);
encoder2InPad->link(decoder1OutPad); // encoder2InPad->link(decoder1OutPad);
// yuvrgbconverterInPad->link(decoder1OutPad); // yuvrgbconverterInPad->link(decoder1OutPad);
// renderer2InPad->link(decoder1OutPad); // renderer2InPad->link(decoder1OutPad);
renderer1InPad->link(decoder1OutPad); renderer1InPad->link(decoder1OutPad);
...@@ -231,8 +231,8 @@ int main(int argc, char *argv[]) { ...@@ -231,8 +231,8 @@ int main(int argc, char *argv[]) {
// renderer2InPad->link(decoder2OutPad); // renderer2InPad->link(decoder2OutPad);
// yuvrgbconverterOutPad->link(frameSaverInPad); // yuvrgbconverterOutPad->link(frameSaverInPad);
muxerInPad1->link(encoder1OutPad); // muxerInPad1->link(encoder1OutPad);
muxerInPad2->link(encoder2OutPad); // muxerInPad2->link(encoder2OutPad);
demuxer->open(); demuxer->open();
...@@ -241,9 +241,9 @@ int main(int argc, char *argv[]) { ...@@ -241,9 +241,9 @@ int main(int argc, char *argv[]) {
demuxer->start(); demuxer->start();
QTimer::singleShot(5000, [demuxer]() { // QTimer::singleShot(5000, [demuxer]() {
QApplication::quit(); // QApplication::quit();
}); // });
// QTimer::singleShot(4000, [demuxer]{ // QTimer::singleShot(4000, [demuxer]{
// demuxer->pause(true); // demuxer->pause(true);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment