#include "qmpvisrendercore.hpp" #include "qmppluginapistub.hpp" #include "qmpsettingsro.hpp" #include "qmpmidiplay.hpp" #include "qmpcorepublic.hpp" #include #include #include #include #include #include qmpVisRenderCore *qmpVisRenderCore::inst=nullptr; qmpVisRenderCore::qmpVisRenderCore(QCommandLineParser *_clp):QObject(nullptr),clp(_clp) { inst=this; player=new CMidiPlayer(); api=new qmpPluginAPIStub(this); msettings=new qmpSettingsRO(); 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); } bool qmpVisRenderCore::loadVisualizationLibrary() { mp=dlopen("libvisualization.so",RTLD_LAZY); 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,!clp->isSet("show-window")); vp->init(); resetcb(nullptr,nullptr); return true; } void qmpVisRenderCore::unloadVisualizationLibrary() { vp->deinit(); 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()); continue; } 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); } void qmpVisRenderCore::startRender() { assert(vf); 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"<getOptionInt("Visualization/wwidth")).arg(msettings->getOptionInt("Visualization/wheight")) <<"-framerate"<getOptionInt("Visualization/tfps")) <<"-i"<<"pipe:"; arguments.append(split_arguments(clp->value("ffmpeg-args"))); arguments<value("output-file"); ffmpegproc->setArguments(arguments); 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,&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); } QStringList qmpVisRenderCore::split_arguments(QString a) { QStringList ret; QString buf; bool escaped=false; for(int i=0;iframeRendered(px,sz,curf,totf); }