From 893bec26cd1bc83fd85bb7dfdfd6225d9f6ee5b5 Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Fri, 1 May 2020 01:31:45 +0800 Subject: Visualization renderer now understands command line arguments. Fixed wrong tick calculation in render mode. Fixed most of the hangs and crashes associated with the renderer. Do not write pixel data in the visualization thread. --- visualization/renderer/qmpvisrendercore.cpp | 126 ++++++++++++++++++++++------ 1 file changed, 100 insertions(+), 26 deletions(-) (limited to 'visualization/renderer/qmpvisrendercore.cpp') diff --git a/visualization/renderer/qmpvisrendercore.cpp b/visualization/renderer/qmpvisrendercore.cpp index fb1a7ef..a2733a7 100644 --- a/visualization/renderer/qmpvisrendercore.cpp +++ b/visualization/renderer/qmpvisrendercore.cpp @@ -8,11 +8,12 @@ #include #include +#include #include #include qmpVisRenderCore *qmpVisRenderCore::inst=nullptr; -qmpVisRenderCore::qmpVisRenderCore():QObject(nullptr) +qmpVisRenderCore::qmpVisRenderCore(QCommandLineParser *_clp):QObject(nullptr),clp(_clp) { inst=this; player=new CMidiPlayer(); @@ -21,17 +22,21 @@ qmpVisRenderCore::qmpVisRenderCore():QObject(nullptr) msettings->registerOptionEnumInt("MIDI","Text encoding","Midi/TextEncoding",{"Unicode","Big5","Big5-HKSCS","CP949","EUC-JP","EUC-KR","GB18030","KOI8-R","KOI8-U","Macintosh","Shift-JIS"},0); } -void qmpVisRenderCore::loadVisualizationLibrary() +bool qmpVisRenderCore::loadVisualizationLibrary() { mp=dlopen("libvisualization.so",RTLD_LAZY); - if(!mp)fprintf(stderr,"failed to load visualization module!\n"); + if(!mp) + { + fprintf(stderr,"failed to load the visualization module!\n"); + return false; + } GetInterface_func getintf=reinterpret_cast(dlsym(mp,"qmpPluginGetInterface")); SwitchMode_func switchmode=reinterpret_cast(dlsym(mp,"switchToRenderMode")); vf=nullptr; vp=getintf(api); - switchmode(&qmpVisRenderCore::framefunc,false); + switchmode(&qmpVisRenderCore::framefunc,!clp->isSet("show-window")); vp->init(); - msettings->load("/home/chrisoft/.config/qmprc"); + return true; } void qmpVisRenderCore::unloadVisualizationLibrary() @@ -40,6 +45,21 @@ void qmpVisRenderCore::unloadVisualizationLibrary() dlclose(mp); } +void qmpVisRenderCore::loadSettings() +{ + if(clp->isSet("config")) + msettings->load(clp->value("config").toStdString().c_str()); + for(auto &o:clp->values("option")) + { + int sp=o.indexOf('='); + if(!~sp) + qDebug("invalid option pair: %s",o.toStdString().c_str()); + QString key=o.left(sp); + QString value=o.mid(sp+1); + msettings->setopt(key.toStdString(),value.toStdString()); + } +} + void qmpVisRenderCore::setMIDIFile(const char *url) { player->playerLoadFile(url); @@ -51,38 +71,92 @@ void qmpVisRenderCore::startRender() ffmpegproc=new QProcess(); ffmpegproc->setProgram("ffmpeg"); QStringList arguments; + arguments.append(split_arguments(clp->value("ffmpeg-pre-args"))); arguments <<"-f"<<"rawvideo" <<"-pixel_format"<<"rgba" - <<"-video_size"<<"1600x900" - <<"-framerate"<<"60" + <<"-video_size"<getOptionInt("Visualization/wwidth")).arg(msettings->getOptionInt("Visualization/wheight")) + <<"-framerate"<getOptionInt("Visualization/tfps")) <<"-i"<<"pipe:"; - arguments - <<"-vf"<<"vflip" - <<"-pix_fmt"<<"yuv420p" - <<"-c:v"<<"libx264" - <<"-preset"<<"fast" - <<"-crf"<<"22"; - arguments<<"output.mp4"; + arguments.append(split_arguments(clp->value("ffmpeg-args"))); + arguments<value("output-file"); ffmpegproc->setArguments(arguments); - ffmpegproc->start(); + QMetaObject::Connection frameconn=connect(this,&qmpVisRenderCore::frameRendered,this, + [this,&frameconn](void* px,size_t sz,uint32_t c,uint32_t t) + { + if(sz) + { + if(!ffmpegproc->isOpen())return; + ffmpegproc->write(static_cast(px),static_cast(sz)); + while(ffmpegproc->bytesToWrite()>1<<26) + ffmpegproc->waitForBytesWritten(); + } + fprintf(stderr,"Rendered tick %u of %u, %.2f%% done.\r",c,t,100.*c/t); + if(c>t) + { + this->ffmpegproc->closeWriteChannel(); + disconnect(frameconn); + qApp->exit(0); + } + },Qt::ConnectionType::BlockingQueuedConnection); connect(ffmpegproc,QOverload::of(&QProcess::finished), - [this](int x,QProcess::ExitStatus){qDebug("%d",x);qDebug()<ffmpegproc->readAllStandardError();}); - vf->show(); - startcb(nullptr,nullptr); + [this,&frameconn](int x,QProcess::ExitStatus st){ + qDebug("%s",this->ffmpegproc->readAllStandardError().data()); + disconnect(frameconn); + if(x||st==QProcess::ExitStatus::CrashExit) + qApp->exit(1); + else + qApp->exit(0); + }); + QMetaObject::invokeMethod(this,[this](){ + ffmpegproc->start(); + vf->show(); + startcb(nullptr,nullptr); + },Qt::ConnectionType::QueuedConnection); } -void qmpVisRenderCore::framefunc(void *px, size_t sz) +QStringList qmpVisRenderCore::split_arguments(QString a) { - if(sz) + QStringList ret; + QString buf; + bool escaped=false; + for(int i=0;iffmpegproc->write((const char*)px,sz); - while(inst->ffmpegproc->bytesToWrite()>1<<26) + if(a[i]=='\\') + { + if(escaped) + { + buf+='\\'; + escaped=false; + } + else escaped=true; + } + else if(a[i]==' ') { - inst->ffmpegproc->waitForBytesWritten(); - QThread::yieldCurrentThread(); + if(escaped)buf+=' '; + else + { + ret.append(buf); + buf.clear(); + } + escaped=false; + } + else + { + if(escaped) + { + buf+='\\'; + escaped=false; + } + buf+=a[i]; } } - else - inst->ffmpegproc->closeWriteChannel(); + if(buf.length()) + ret.append(buf); + return ret; +} + +void qmpVisRenderCore::framefunc(void *px, size_t sz,uint32_t curf,uint32_t totf) +{ + emit inst->frameRendered(px,sz,curf,totf); } -- cgit v1.2.3