From db13918cc91e5b9988095e565ec3994d924d1c2f Mon Sep 17 00:00:00 2001 From: apo Date: Tue, 11 Apr 2006 11:39:29 +0000 Subject: [PATCH] Generate AVI on animation --- src/VISUGUI/VisuGUI_TimeAnimation.cxx | 69 ++++++++++++- src/VISUGUI/VisuGUI_TimeAnimation.h | 5 + src/VISU_I/VISU_TimeAnimation.cxx | 136 ++++++++++++++++++++++++-- src/VISU_I/VISU_TimeAnimation.h | 3 + 4 files changed, 202 insertions(+), 11 deletions(-) diff --git a/src/VISUGUI/VisuGUI_TimeAnimation.cxx b/src/VISUGUI/VisuGUI_TimeAnimation.cxx index 3ac37f5f..b8afb4e9 100644 --- a/src/VISUGUI/VisuGUI_TimeAnimation.cxx +++ b/src/VISUGUI/VisuGUI_TimeAnimation.cxx @@ -1093,6 +1093,8 @@ VisuGUI_TimeAnimationDlg::VisuGUI_TimeAnimationDlg (VisuGUI* theModule, _PTR(Stu aSaveLay->setMargin( 5 ); mySaveCheck = new QCheckBox("Save pictures to directory", aSaveBox); + connect(mySaveCheck, SIGNAL( toggled(bool)), + this, SLOT( onCheckDump(bool) )); aSaveLay->addMultiCellWidget(mySaveCheck, 0, 0, 0, 2); QLabel* aFormatLbl = new QLabel("Saving format:", aSaveBox); @@ -1137,6 +1139,35 @@ VisuGUI_TimeAnimationDlg::VisuGUI_TimeAnimationDlg (VisuGUI* theModule, _PTR(Stu mySaveCheck->setChecked(false); aSaveLay->addWidget(aBrowseBtn, 2, 2); + mySaveAVICheck = new QCheckBox("Save animation to AVI file", aSaveBox); + connect(mySaveAVICheck, SIGNAL( toggled(bool)), + this, SLOT( onCheckDump(bool) )); + aSaveLay->addMultiCellWidget(mySaveAVICheck, 3, 3, 0, 2); + + QLabel* aPathAVILbl = new QLabel("Path:", aSaveBox); + aPathAVILbl->setEnabled(false); + connect(mySaveAVICheck, SIGNAL( toggled(bool)), + aPathAVILbl, SLOT( setEnabled(bool) )); + aSaveLay->addWidget(aPathAVILbl, 4, 0); + + myPathAVIEdit = new QLineEdit(aSaveBox); + myPathAVIEdit->setReadOnly(true); + myPathAVIEdit->setEnabled(false); + connect(mySaveAVICheck, SIGNAL( toggled(bool)), + myPathAVIEdit, SLOT( setEnabled(bool) )); + aSaveLay->addWidget(myPathAVIEdit, 4, 1); + + QPushButton* aBrowseAVIBtn = new QPushButton("Browse...", aSaveBox); + aBrowseAVIBtn->setEnabled(false); + connect(mySaveAVICheck, SIGNAL( toggled(bool)), + aBrowseAVIBtn, SLOT( setEnabled(bool) )); + connect(aBrowseAVIBtn, SIGNAL( clicked()), + this, SLOT( onBrowseAVI() )); + aSaveLay->addWidget(aBrowseAVIBtn, 4, 2); + + mySaveAVICheck->setChecked(false); + mySaveAVICheck->setEnabled(myAnimator->checkAVIMaker()); + TopLayout->addMultiCellWidget(aSaveBox, 7, 7, 0, 3); aMainLayout->addWidget(myPlayFrame); @@ -1245,6 +1276,9 @@ void VisuGUI_TimeAnimationDlg::onPlayPressed() QStrList aDumpFormats = QImageIO::outputFormats(); myAnimator->setDumpFormat(aDumpFormats.at(myPicsFormat->currentItem())); myAnimator->dumpTo(myPathEdit->text()); + } else if (mySaveAVICheck->isChecked()) { + myAnimator->setDumpFormat("AVI"); + myAnimator->dumpTo(myPathAVIEdit->text()); } else { myAnimator->dumpTo(""); } @@ -1369,11 +1403,44 @@ void VisuGUI_TimeAnimationDlg::onSetupDlg() //------------------------------------------------------------------------ void VisuGUI_TimeAnimationDlg::onBrowse() { - QString aPath = SUIT_FileDlg::getExistingDirectory(this, "/", "Select path"); + // QString aPath = SUIT_FileDlg::getExistingDirectory(this, "/", "Select path"); + QString aPath = SUIT_FileDlg::getExistingDirectory(this, getenv("HOME"), "Select path"); if (!aPath.isEmpty()) myPathEdit->setText(Qtx::addSlash(aPath)); } +//------------------------------------------------------------------------ +void VisuGUI_TimeAnimationDlg::onBrowseAVI() +{ + QStringList aFilter; + aFilter.append( "AVI Files (*.avi)" ); + aFilter.append( "All Files (*.*)" ); + + QString aPath = SUIT_FileDlg::getFileName(this, getenv("HOME"), aFilter, "Select file", false); + if (!aPath.isEmpty()) + myPathAVIEdit->setText(aPath); +} + +//------------------------------------------------------------------------ +void VisuGUI_TimeAnimationDlg::onCheckDump(bool) +{ + const QObject* source = sender(); + if (source == mySaveCheck) { + if (mySaveCheck->isChecked()) { + if (mySaveAVICheck->isChecked()) + mySaveAVICheck->setChecked(false); + } + mySaveAVICheck->setEnabled(!mySaveCheck->isChecked()); + } + else if (source == mySaveAVICheck) { + if (mySaveAVICheck->isChecked()) { + if (mySaveCheck->isChecked()) + mySaveCheck->setChecked(false); + } + mySaveCheck->setEnabled(!mySaveAVICheck->isChecked()); + } +} + //------------------------------------------------------------------------ void VisuGUI_TimeAnimationDlg::onStop() { diff --git a/src/VISUGUI/VisuGUI_TimeAnimation.h b/src/VISUGUI/VisuGUI_TimeAnimation.h index 3b6d6099..ec35e0d2 100644 --- a/src/VISUGUI/VisuGUI_TimeAnimation.h +++ b/src/VISUGUI/VisuGUI_TimeAnimation.h @@ -157,6 +157,8 @@ class VisuGUI_TimeAnimationDlg: public QDialog void onSpeedChange(double theSpeed); void onExecution(long theNewFrame, double theTime); void onBrowse(); + void onBrowseAVI(); + void onCheckDump(bool); void onStop(); void onHelp(); void saveToStudy(); @@ -183,6 +185,9 @@ class VisuGUI_TimeAnimationDlg: public QDialog bool isClosing; QCloseEvent* myEvent; + QCheckBox* mySaveAVICheck; + QLineEdit* myPathAVIEdit; + QPushButton* myPublishBtn; QPushButton* mySaveBtn; }; diff --git a/src/VISU_I/VISU_TimeAnimation.cxx b/src/VISU_I/VISU_TimeAnimation.cxx index ce602533..432404e0 100644 --- a/src/VISU_I/VISU_TimeAnimation.cxx +++ b/src/VISU_I/VISU_TimeAnimation.cxx @@ -47,6 +47,7 @@ #include #include #include +#include using namespace std; @@ -77,6 +78,9 @@ VISU_TimeAnimation::VISU_TimeAnimation (_PTR(Study) theStudy, myCycling = false; myAnimEntry = ""; + + myDumpPath = ""; + myAVIMaker = "jpeg2yuv"; } @@ -562,6 +566,10 @@ void VISU_TimeAnimation::run() double aOneVal = 1; if (myFieldsLst[0].myNbFrames > 2) aOneVal = myFieldsLst[0].myTiming[1] - myFieldsLst[0].myTiming[0]; + myFileIndex = 0; + int aNbFiles = 0; + QValueList anIndexList; + qApp->lock(); while (myIsActive) { emit frameChanged(myFrame, myFieldsLst[0].myTiming[myFrame]); @@ -610,15 +618,57 @@ void VISU_TimeAnimation::run() qApp->unlock(); msleep(100); qApp->lock(); - QString aFile(myDumpPath); - QString aName = QString("%1").arg(myFieldsLst[0].myTiming[myFrame]); - int aPos = -1; - while ((aPos = aName.find(".")) > -1 ) - aName.replace(aPos, 1, "_"); - aFile += aName; - aFile += "."; - aFile += myDumpFormat.lower(); - myView->dumpViewToFormat(aFile,myDumpFormat); + if (myDumpFormat.compare("AVI") != 0) { + QString aFile(myDumpPath); + QString aName = QString("%1").arg(myFieldsLst[0].myTiming[myFrame]); + int aPos = -1; + while ((aPos = aName.find(".")) > -1 ) + aName.replace(aPos, 1, "_"); + aFile += aName; + aFile += "."; + aFile += myDumpFormat.lower(); + myView->dumpViewToFormat(aFile,myDumpFormat); + } else { + QFileInfo aFileInfo(myDumpPath); + QString aDirPath = aFileInfo.dirPath(true); + QString aBaseName = aFileInfo.fileName(); + + switch (myFrame) { + case 0: + break; + case 1: + myFileIndex += 5; + break; + default: + if (myProportional) { + double p = (myFieldsLst[0].myTiming[myFrame] - + myFieldsLst[0].myTiming[myFrame-1]) / aOneVal; + myFileIndex += (long) (5*p); + } else { + myFileIndex += 5; + } + } + + QString aFile = aDirPath + QDir::separator() + aBaseName; + aFile += "_"; + aFile += QString("%1").arg(myFileIndex).rightJustify(8, '0'); + aFile += ".jpeg"; + + /* check image size is divisable 16 + myView->dumpViewToFormat(aFile,"JPEG"); + */ + SUIT_ViewWindow* aView = myView; + QImage img = aView->dumpView(); + if (!img.isNull()) { + int width = img.width(); width = (width/16)*16; + int height = img.height(); height = (height/16)*16; + QImage copy = img.copy(0, 0, width, height); + if (copy.save(aFile, "JPEG")) { + anIndexList.append(myFileIndex); + aNbFiles++; + } + } + } } if (!myIsActive) break; @@ -633,6 +683,58 @@ void VISU_TimeAnimation::run() myFrame = 0; } } + + // make AVI file if need + if (isDumping && myDumpFormat.compare("AVI") == 0) { + double aFPS = 17.3 * mySpeed; + + QFileInfo aFileInfo(myDumpPath); + QString aDirPath = aFileInfo.dirPath(true); + QString aBaseName = aFileInfo.fileName(); + + // add missing files + if (anIndexList.count() > 1) { + QString aFFile = aDirPath + QDir::separator() + aBaseName; + aFFile += QString("_%1.jpeg"); + int aStartIndex = anIndexList[0], anEndIndex; + for (int i = 1; i < anIndexList.count(); i++) { + anEndIndex = anIndexList[i]; + QString aCurFile = aFFile.arg(QString::number(aStartIndex).rightJustify(8, '0')); + QStringList aCommands; + for (int j = aStartIndex+1; j < anEndIndex; j++) { + QString aFile = aFFile.arg(QString::number(j).rightJustify(8, '0')); + aCommands.append(QString("ln -s %1 %2").arg(aCurFile).arg(aFile)); + } + system(aCommands.join(" ; \\\n").latin1()); + aStartIndex = anEndIndex; + } + } + + // make AVI file + QString aPattern = aDirPath + QDir::separator() + aBaseName; + aPattern += "_\%08d.jpeg"; + + QString aCmd = myAVIMaker; + aCmd += " -I p"; + aCmd += " -v 0"; + aCmd += QString(" -f %1").arg(aFPS); + // aCmd += QString(" -n %1").arg(aNbFiles); + aCmd += QString(" -n %1").arg(myFileIndex+1); + aCmd += QString(" -j %1").arg(aPattern); + aCmd += " | yuv2lav"; + aCmd += QString(" -o %1").arg(myDumpPath); + system(aCmd.latin1()); + + // remove temporary jpeg files + aCmd = "( "; + aCmd += QString("cd %1").arg(aDirPath); + aCmd += "; ls"; + aCmd += QString(" | egrep '%1_[0-9]*.jpeg'").arg(aBaseName); + aCmd += " | xargs rm"; + aCmd += " )"; + system(aCmd.latin1()); + } + emit stopped(); qApp->unlock(); QThread::exit(); @@ -691,7 +793,8 @@ std::string VISU_TimeAnimation::setDumpFormat(const char* theFormat) { myDumpFormat = theFormat; QStrList aDumpFormats = QImageIO::outputFormats(); - if (myDumpFormat.isEmpty() || aDumpFormats.find(theFormat) < 0) { + if (myDumpFormat.isEmpty() || + (aDumpFormats.find(theFormat) < 0 && myDumpFormat.compare("AVI") != 0)) { if (aDumpFormats.find("JPEG")) myDumpFormat = "JPEG"; else @@ -700,6 +803,19 @@ std::string VISU_TimeAnimation::setDumpFormat(const char* theFormat) return myDumpFormat.latin1(); } +//------------------------------------------------------------------------ +bool VISU_TimeAnimation::checkAVIMaker() const +{ + QStrList aDumpFormats = QImageIO::outputFormats(); + if (aDumpFormats.find("JPEG") < 0) return false; + + QString aCmd("which "); + aCmd += myAVIMaker; + aCmd += " >& /dev/null"; + int iErr = system(aCmd.latin1()); + return (iErr == 0); +} + //************************************************************************ int VISU_TimeAnimation::myNBAnimations = 0; QString VISU_TimeAnimation::GenerateName() diff --git a/src/VISU_I/VISU_TimeAnimation.h b/src/VISU_I/VISU_TimeAnimation.h index a090a1db..ea14a17a 100644 --- a/src/VISU_I/VISU_TimeAnimation.h +++ b/src/VISU_I/VISU_TimeAnimation.h @@ -103,6 +103,7 @@ class VISU_TimeAnimation: public QObject, public QThread void dumpTo(const char* thePath) { myDumpPath = thePath; } std::string setDumpFormat(const char* theFormat); + bool checkAVIMaker() const; QString getLastErrorMsg() { return myLastError; } @@ -150,6 +151,8 @@ class VISU_TimeAnimation: public QObject, public QThread double myTimeMin , myTimeMax ; //!< Range of time stams, available for animation QString myDumpPath; QString myDumpFormat; + QString myAVIMaker; + long myFileIndex; SVTK_ViewWindow* myView; QString myAnimEntry; -- 2.39.2