diff options
-rw-r--r-- | tools/qmlviewer/main.cpp | 18 | ||||
-rw-r--r-- | tools/qmlviewer/qmlviewer.cpp | 138 | ||||
-rw-r--r-- | tools/qmlviewer/qmlviewer.h | 3 |
3 files changed, 114 insertions, 45 deletions
diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp index c5676ab..26ff213 100644 --- a/tools/qmlviewer/main.cpp +++ b/tools/qmlviewer/main.cpp @@ -27,11 +27,15 @@ void usage() qWarning(" -v, -version ............................. display version"); qWarning(" -frameless ............................... run with no window frame"); qWarning(" -skin <qvfbskindir> ...................... run with a skin window frame"); - qWarning(" -recorddither ordered|threshold|floyd .... set dither mode used for recording"); + qWarning(" -recordfile <output> ..................... set output file"); + qWarning(" - ImageMagick 'convert' for GIF)"); + qWarning(" - png file for raw frames"); + qWarning(" - 'ffmpeg' for other formats"); + qWarning(" -recorddither ordered|threshold|floyd .... set GIF dither recording mode"); qWarning(" -recordperiod <milliseconds> ............. set time between recording frames"); - qWarning(" -autorecord [from-]<tomilliseconds> ...... set recording to start and stop automatically"); + qWarning(" -autorecord [from-]<tomilliseconds> ...... set recording to start and stop"); qWarning(" -devicekeys .............................. use numeric keys (see F1)"); - qWarning(" -cache ................................... enable a disk cache of remote content"); + qWarning(" -cache ................................... disk cache remote content"); qWarning(" -recordtest <directory> .................. record an autotest"); qWarning(" -runtest <directory> ..................... run a previously recorded test"); qWarning(" "); @@ -66,7 +70,8 @@ int main(int argc, char ** argv) int period = 0; int autorecord_from = 0; int autorecord_to = 0; - QString dither = "threshold"; + QString dither = "none"; + QString recordfile = "animation.gif"; QString skin; bool devkeys = false; bool cache = false; @@ -83,6 +88,10 @@ int main(int argc, char ** argv) cache = true; } else if (arg == "-recordperiod") { period = QString(argv[++i]).toInt(); + } else if (arg == "-recordfile") { + recordfile = QString(argv[++i]); + } else if (arg == "-recorddither") { + dither = QString(argv[++i]); } else if (arg == "-autorecord") { QString range = QString(argv[++i]); int dash = range.indexOf('-'); @@ -119,6 +128,7 @@ int main(int argc, char ** argv) QmlViewer viewer(testMode, testDir, 0, frameless ? Qt::FramelessWindowHint : Qt::Widget); viewer.setCacheEnabled(cache); viewer.openQml(fileName); + viewer.setRecordFile(recordfile); if (period>0) viewer.setRecordPeriod(period); if (autorecord_to) diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 00cb7f1..094d779 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -35,7 +35,7 @@ #include <QMenu> QmlViewer::QmlViewer(QFxTestEngine::TestMode testMode, const QString &testDir, QWidget *parent, Qt::WindowFlags flags) - : QWidget(parent, flags) + : QWidget(parent, flags), frame_stream(0) { testEngine = 0; devicemode = false; @@ -218,6 +218,11 @@ void QmlViewer::setAutoRecord(int from, int to) } } +void QmlViewer::setRecordFile(const QString& f) +{ + record_file = f; +} + void QmlViewer::setRecordPeriod(int ms) { record_period = ms; @@ -246,7 +251,7 @@ void QmlViewer::keyPressEvent(QKeyEvent *event) exit(0); else if (event->key() == Qt::Key_F1 || (event->key() == Qt::Key_1 && devicemode)) { qDebug() << "F1 - help\n" - << "F2 - toggle GIF recording\n" + << "F2 - toggle video recording\n" << "F3 - take PNG snapshot\n" << "F4 - show items and state\n" << "F5 - reload QML\n" @@ -288,49 +293,95 @@ void QmlViewer::setRecording(bool on) if (on) { recordTimer.start(record_period,this); + QString fmt = record_file.right(4).toLower(); + if (fmt != ".png" && fmt != ".gif") { + // Stream video to ffmpeg + + QProcess *proc = new QProcess(this); + frame_stream = proc; + + QStringList args; + args << "-sameq"; // ie. high + args << "-y"; + args << "-r" << QString::number(1000/record_period); + args << "-f" << "rawvideo"; + args << "-pix_fmt" << "rgb32"; + args << "-s" << QString("%1x%2").arg(canvas->width()).arg(canvas->height()); + args << "-i" << "-"; + args << record_file; + proc->start("ffmpeg",args,QIODevice::WriteOnly); + } else { + // Store frames, save to GIF/PNG + frame_stream = 0; + } } else { recordTimer.stop(); - int frame=0; - QStringList inputs; - qDebug() << "Saving frames..."; - - foreach (QImage* img, frames) { - QString name; - name.sprintf("tmp-frame%04d.png",frame++); - if (record_dither=="ordered") - img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::OrderedDither).save(name); - else if (record_dither=="threshold") - img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::ThresholdDither).save(name); - else if (record_dither=="floyd") - img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither).save(name); - else - img->convertToFormat(QImage::Format_Indexed8).save(name); - inputs << name; - delete img; - } - QString output="animation.gif"; - - QStringList args; - - args << "-delay" << QString::number(record_period/10); - args << inputs; - args << output; - qDebug() << "Converting..." << output; - if (0!=QProcess::execute("convert", args)) { - qWarning() << "Cannot run ImageMagick 'convert' - not converted to gif"; - inputs.clear(); // don't remove them - qDebug() << "Wrote frames tmp-frame*.png"; + if (frame_stream) { + qDebug() << "Saving video..."; + frame_stream->close(); + qDebug() << "Wrote" << record_file; } else { - qDebug() << "Compressing..." << output; - if (0!=QProcess::execute("gifsicle", QStringList() << "-O2" << "-o" << output << output)) - qWarning() << "Cannot run 'gifsicle' - not compressed"; - qDebug() << "Wrote" << output; - } + int frame=0; + QStringList inputs; + qDebug() << "Saving frames..."; + + QString framename; + bool png_output = false; + if (record_file.right(4).toLower()==".png") { + if (record_file.contains('%')) + framename = record_file; + else + framename = record_file.left(record_file.length()-4)+"%04d"+record_file.right(4); + png_output = true; + } else { + framename = "tmp-frame%04d.png"; + png_output = false; + } + foreach (QImage* img, frames) { + QString name; + name.sprintf(framename.toLocal8Bit(),frame++); + if (record_dither=="ordered") + img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::OrderedDither).save(name); + else if (record_dither=="threshold") + img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::ThresholdDither).save(name); + else if (record_dither=="floyd") + img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither).save(name); + else + img->save(name); + inputs << name; + delete img; + } + + if (png_output) { + framename.replace(QRegExp("%\\d*."),"*"); + qDebug() << "Wrote frames" << framename; + inputs.clear(); // don't remove them + } else { + // ImageMagick and gifsicle for GIF encoding + QStringList args; + args << "-delay" << QString::number(record_period/10); + args << inputs; + args << record_file; + qDebug() << "Converting..." << record_file; + if (0!=QProcess::execute("convert", args)) { + qWarning() << "Cannot run ImageMagick 'convert' - recorded frames not converted"; + inputs.clear(); // don't remove them + qDebug() << "Wrote frames tmp-frame*.png"; + } else { + if (record_file.right(4).toLower() == ".gif") { + qDebug() << "Compressing..." << record_file; + if (0!=QProcess::execute("gifsicle", QStringList() << "-O2" << "-o" << record_file << record_file)) + qWarning() << "Cannot run 'gifsicle' - not compressed"; + } + qDebug() << "Wrote" << record_file; + } + } - foreach (QString name, inputs) - QFile::remove(name); + foreach (QString name, inputs) + QFile::remove(name); - frames.clear(); + frames.clear(); + } } qDebug() << "Recording: " << (recordTimer.isActive()?"ON":"OFF"); } @@ -338,7 +389,12 @@ void QmlViewer::setRecording(bool on) void QmlViewer::timerEvent(QTimerEvent *event) { if (event->timerId() == recordTimer.timerId()) { - frames.append(new QImage(canvas->asImage())); + if (frame_stream) { + QImage frame(canvas->asImage()); + frame_stream->write((char*)frame.bits(),frame.numBytes()); + } else { + frames.append(new QImage(canvas->asImage())); + } if (record_autotime && autoTimer.elapsed() >= record_autotime) setRecording(false); } else if (event->timerId() == autoStartTimer.timerId()) { diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h index 0fa879d..fc65ebf 100644 --- a/tools/qmlviewer/qmlviewer.h +++ b/tools/qmlviewer/qmlviewer.h @@ -33,6 +33,7 @@ public: void setRecordDither(const QString& s) { record_dither = s; } void setRecordPeriod(int ms); + void setRecordFile(const QString&); int recordPeriod() const { return record_period; } void setRecording(bool on); bool isRecording() const { return recordTimer.isActive(); } @@ -59,9 +60,11 @@ private: void init(QFxTestEngine::TestMode, const QString &, const QString& fileName); QBasicTimer recordTimer; QList<QImage*> frames; + QIODevice* frame_stream; QBasicTimer autoStartTimer; QTime autoTimer; QString record_dither; + QString record_file; int record_period; int record_autotime; bool devicemode; |