diff options
author | Chris Xiong <chirs241097@gmail.com> | 2020-05-01 01:31:45 +0800 |
---|---|---|
committer | Chris Xiong <chirs241097@gmail.com> | 2020-05-01 01:31:45 +0800 |
commit | 893bec26cd1bc83fd85bb7dfdfd6225d9f6ee5b5 (patch) | |
tree | 3b7e7a4f772c8f8de93d61b549599b22902e83fc /visualization/renderer/qmpvisrendercore.cpp | |
parent | bd165c0254b9095bb9e5ea54def56b6404033ebe (diff) | |
download | QMidiPlayer-893bec26cd1bc83fd85bb7dfdfd6225d9f6ee5b5.tar.xz |
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.
Diffstat (limited to 'visualization/renderer/qmpvisrendercore.cpp')
-rw-r--r-- | visualization/renderer/qmpvisrendercore.cpp | 126 |
1 files changed, 100 insertions, 26 deletions
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 <dlfcn.h> #include <QProcess> +#include <QCommandLineParser> #include <QDebug> #include <QThread> 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<GetInterface_func>(dlsym(mp,"qmpPluginGetInterface")); SwitchMode_func switchmode=reinterpret_cast<SwitchMode_func>(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"<<QString("%1x%2").arg(msettings->getOptionInt("Visualization/wwidth")).arg(msettings->getOptionInt("Visualization/wheight")) + <<"-framerate"<<QString::number(msettings->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<<clp->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<const char*>(px),static_cast<qint64>(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<int,QProcess::ExitStatus>::of(&QProcess::finished), - [this](int x,QProcess::ExitStatus){qDebug("%d",x);qDebug()<<this->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;i<a.length();++i) { - inst->ffmpegproc->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); } |