Back to index

salome-gui  6.5.0
SVTK_Recorder.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // This library is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU Lesser General Public
00005 // License as published by the Free Software Foundation; either
00006 // version 2.1 of the License.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // Lesser General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU Lesser General Public
00014 // License along with this library; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00016 //
00017 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00018 //
00019 
00020 #include "SVTK_Recorder.h"
00021 
00022 #include "SVTK_ImageWriter.h"
00023 #include "SVTK_ImageWriterMgr.h"
00024 
00025 #include <vtkObjectFactory.h>
00026 #include <vtkObject.h>
00027 #include <vtkCallbackCommand.h>
00028 #include <vtkRenderWindow.h>
00029 #include <vtkTimerLog.h>
00030 #include <vtkWindowToImageFilter.h>
00031 #include <vtkJPEGWriter.h>
00032 #include <vtkImageData.h>
00033 
00034 #include <sstream>
00035 #include <iomanip>
00036 #include <iostream>
00037 
00038 #ifndef WIN32
00039 #include <unistd.h>
00040 #endif
00041 
00042 #include <QApplication>
00043 #include <QFileInfo>
00044 #include <QDir>
00045 
00046 //#include "utilities.h"
00047 
00048 #ifdef _DEBUG_
00049 static int MYDEBUG = 0;
00050 #else
00051 static int MYDEBUG = 0;
00052 #endif
00053 
00054 
00055 namespace
00056 {
00057   //----------------------------------------------------------------------------
00058   inline
00059   void
00060   GetNameJPEG(const std::string& thePreffix,  
00061               const int theIndex,
00062               std::string& theName)
00063   {
00064     std::ostringstream aStream;
00065     aStream<<thePreffix<<"_"<<setw(6)<<setfill('0')<<theIndex<<".jpeg";
00066     theName = aStream.str();
00067   }
00068 }
00069 
00070 //----------------------------------------------------------------------------
00071 vtkCxxRevisionMacro(SVTK_Recorder,"$Revision: 1.2.2.1.8.6.2.1 $");
00072 vtkStandardNewMacro(SVTK_Recorder);
00073 
00074 
00075 //----------------------------------------------------------------------------
00076 SVTK_Recorder
00077 ::SVTK_Recorder():
00078   myRenderWindow(NULL),
00079   myState(SVTK_Recorder_Stop),
00080   myNbFPS(5.5),
00081   myQuality(100),
00082   myProgressiveMode(true),
00083   myUseSkippedFrames(true),
00084   myErrorStatus(0),
00085   myCommand(vtkCallbackCommand::New()),
00086   myPriority(0.0),
00087   myTimeStart(0.0),
00088   myFrameIndex(0),
00089   myPaused(0),
00090   myFilter(vtkWindowToImageFilter::New()),
00091   myWriterMgr(new SVTK_ImageWriterMgr),
00092   myNbWrittenFrames(0),
00093   myNameAVIMaker("jpeg2yuv")
00094 {
00095   myCommand->SetClientData(this); 
00096   myCommand->SetCallback(SVTK_Recorder::ProcessEvents);
00097 }
00098 
00099 
00100 //----------------------------------------------------------------------------
00101 SVTK_Recorder
00102 ::~SVTK_Recorder()
00103 {
00104   myCommand->Delete();
00105   myFilter->Delete();
00106   delete myWriterMgr;
00107 }
00108 
00109 
00110 //----------------------------------------------------------------------------
00111 void
00112 SVTK_Recorder
00113 ::CheckExistAVIMaker()
00114 {
00115   myErrorStatus = 0;
00116   std::ostringstream aStream;
00117 #ifndef WIN32
00118   aStream<<"which "<<myNameAVIMaker<<" 2> /dev/null";
00119 #else
00120   aStream<<"setlocal & set P2=.;%PATH% & (for %e in (%PATHEXT%) do @for %i in ("<<myNameAVIMaker<<"%e) do @if NOT \"%~$P2:i\"==\"\" exit /b 0) & exit /b 1";
00121 #endif
00122   std::string anAVIMakeCheck = aStream.str();
00123   int iErr = system(anAVIMakeCheck.c_str());
00124   if(iErr != 0)
00125     myErrorStatus = 127;
00126 }
00127 
00128 
00129 //----------------------------------------------------------------------------
00130 void
00131 SVTK_Recorder
00132 ::SetName(const char* theName)
00133 {
00134   myName = theName;
00135 }
00136 
00137 const char* 
00138 SVTK_Recorder::Name() const
00139 {
00140   return myName.c_str();
00141 }
00142 
00143 
00144 //----------------------------------------------------------------------------
00145 void
00146 SVTK_Recorder
00147 ::SetNbFPS(const double theNbFPS)
00148 {
00149   myNbFPS = theNbFPS;
00150 }
00151 
00152 double
00153 SVTK_Recorder
00154 ::NbFPS() const
00155 {
00156   return myNbFPS;
00157 }
00158 
00159 
00160 //----------------------------------------------------------------------------
00161 void
00162 SVTK_Recorder
00163 ::SetQuality(int theQuality)
00164 {
00165   myQuality = theQuality;
00166 }
00167 
00168 int
00169 SVTK_Recorder
00170 ::GetQuality() const
00171 {
00172   return myQuality;
00173 }
00174 
00175 
00176 //----------------------------------------------------------------------------
00177 void 
00178 SVTK_Recorder
00179 ::SetRenderWindow(vtkRenderWindow* theRenderWindow)
00180 {
00181   myRenderWindow = theRenderWindow;
00182 }
00183 
00184 vtkRenderWindow* 
00185 SVTK_Recorder
00186 ::RenderWindow()
00187 {
00188   return myRenderWindow;
00189 }
00190 
00191 
00192 //----------------------------------------------------------------------------
00193 void
00194 SVTK_Recorder
00195 ::SetProgressiveMode(bool theProgressiveMode)
00196 {
00197   myProgressiveMode = theProgressiveMode;
00198 }
00199 
00200 bool
00201 SVTK_Recorder
00202 ::GetProgressiveMode() const
00203 {
00204   return myProgressiveMode;
00205 }
00206 
00207 
00208 //----------------------------------------------------------------------------
00209 void
00210 SVTK_Recorder
00211 ::SetUseSkippedFrames(bool theUseSkippedFrames)
00212 {
00213   myUseSkippedFrames = theUseSkippedFrames;
00214 }
00215 
00216 bool
00217 SVTK_Recorder
00218 ::UseSkippedFrames() const
00219 {
00220   return myUseSkippedFrames;
00221 }
00222 
00223 
00224 //----------------------------------------------------------------------------
00225 int
00226 SVTK_Recorder
00227 ::ErrorStatus() const
00228 {
00229   return myErrorStatus;
00230 }
00231 
00232 int
00233 SVTK_Recorder
00234 ::State() const
00235 {
00236   return myState;
00237 }
00238 
00239 
00240 //----------------------------------------------------------------------------
00241 void
00242 SVTK_Recorder
00243 ::ProcessEvents(vtkObject* vtkNotUsed(theObject), 
00244                 unsigned long theEvent,
00245                 void* theClientData, 
00246                 void* vtkNotUsed(theCallData))
00247 {
00248   if(vtkObject* anObj = reinterpret_cast<vtkObject*>(theClientData)){ 
00249     if(SVTK_Recorder* aSelf = dynamic_cast<SVTK_Recorder*>(anObj)){
00250       if(theEvent==vtkCommand::EndEvent){
00251         if(aSelf->State() == SVTK_Recorder::SVTK_Recorder_Record){
00252           aSelf->DoRecord();
00253         }
00254       }
00255     }
00256   }
00257 }
00258 
00259 
00260 //----------------------------------------------------------------------------
00261 void
00262 SVTK_Recorder
00263 ::Record()
00264 {
00265   if(myState == SVTK_Recorder_Stop){
00266     if(myRenderWindow){
00267       myState = SVTK_Recorder_Record;
00268       myFilter->SetInput(myRenderWindow);
00269       myFrameIndex = -1;
00270       myNbWrittenFrames = 0;
00271       myRenderWindow->RemoveObserver(myCommand);
00272       myRenderWindow->AddObserver(vtkCommand::EndEvent,
00273                                   myCommand,
00274                                   myPriority);
00275       myRenderWindow->Render();
00276     }
00277   }
00278 }
00279 
00280 
00281 //----------------------------------------------------------------------------
00282 void
00283 SVTK_Recorder
00284 ::Stop()
00285 {
00286   QApplication::setOverrideCursor( Qt::WaitCursor );
00287 
00288   if(myState == SVTK_Recorder_Record){ 
00289     if(!myPaused)
00290       DoRecord();
00291 
00292     myWriterMgr->Stop();
00293 
00294     if(myUseSkippedFrames)
00295       AddSkippedFrames();
00296 
00297     myFrameIndexes.clear();
00298 
00299     MakeFileAVI();
00300   }
00301   myState = SVTK_Recorder_Stop;
00302   myPaused = 0;
00303 
00304   QApplication::restoreOverrideCursor();
00305 }
00306 
00307 
00308 //----------------------------------------------------------------------------
00309 void
00310 SVTK_Recorder
00311 ::Pause()
00312 {
00313   myPaused = myPaused ? 0 : 1;
00314   if(myPaused && !myFrameIndexes.empty()){
00315     myFrameIndexes.back() *= -1;
00316     if(MYDEBUG) cout<<"SVTK_Recorder::Pause - myFrameIndexes.back() = "<<myFrameIndexes.back()<<endl;
00317   }
00318 }
00319 
00320 
00321 //----------------------------------------------------------------------------
00322 inline 
00323 int
00324 GetFrameIndex(double theStartTime,
00325               double theFPS)
00326 {
00327   double aTimeNow = vtkTimerLog::GetUniversalTime();
00328   double aDelta = aTimeNow - theStartTime;
00329   return int(aDelta*theFPS);
00330 }
00331 
00332 void
00333 SVTK_Recorder
00334 ::DoRecord()
00335 {
00336   if(myPaused)
00337     return;
00338 
00339   if(myFrameIndex < 0){
00340     myFrameIndex = 0;
00341     myTimeStart = vtkTimerLog::GetUniversalTime();
00342   }else{
00343     int aFrameIndex = GetFrameIndex(myTimeStart,myNbFPS);
00344     if(aFrameIndex <= myFrameIndex)
00345       return;
00346 
00347     // If there was a "pause" we correct the myTimeStart
00348     int aLastFrameIndex = myFrameIndexes.back();
00349     if(aLastFrameIndex < 0){
00350       myFrameIndexes.back() = abs(myFrameIndexes.back());
00351       double aPauseTime = fabs((double)(aFrameIndex - myFrameIndex - 1)) / myNbFPS;
00352       if(MYDEBUG) 
00353         cout<<"SVTK_Recorder::DoRecord - aFrameIndex = "<<aFrameIndex<<
00354           "; aPauseTime = "<<aPauseTime<<endl;
00355       myTimeStart += aPauseTime;
00356     }
00357 
00358     aFrameIndex = GetFrameIndex(myTimeStart,myNbFPS);
00359     if(aFrameIndex <= myFrameIndex)
00360       return;
00361 
00362     myFrameIndex = aFrameIndex;
00363   }
00364 
00365   myFrameIndexes.push_back(myFrameIndex);
00366   if(MYDEBUG) cout<<"SVTK_Recorder::DoRecord - myFrameIndex = "<<myFrameIndex<<endl;
00367 
00368   myRenderWindow->RemoveObserver(myCommand);
00369   myFilter->Modified();
00370 
00371   std::string aName;
00372   GetNameJPEG(myName,myFrameIndex,aName);
00373 
00374   PreWrite();
00375 
00376   vtkImageData *anImageData = vtkImageData::New(); 
00377   anImageData->DeepCopy(myFilter->GetOutput());
00378 
00379   myWriterMgr->StartImageWriter(anImageData,aName,myProgressiveMode,myQuality);
00380   myNbWrittenFrames++;
00381 
00382   myRenderWindow->AddObserver(vtkCommand::EndEvent,
00383                               myCommand,
00384                               myPriority);
00385 }
00386 
00387 
00388 //----------------------------------------------------------------------------
00389 void
00390 SVTK_Recorder
00391 ::PreWrite()
00392 {
00393   vtkImageData *anImageData = myFilter->GetOutput();
00394   //
00395   if(!anImageData){
00396     myErrorStatus = 20;
00397     return;
00398   }
00399   anImageData->UpdateInformation();
00400   int *anExtent = anImageData->GetWholeExtent();
00401   anImageData->SetUpdateExtent(anExtent[0], anExtent[1],
00402                                anExtent[2], anExtent[3],
00403                                0,0);
00404   anImageData->UpdateData();
00405 }
00406 
00407 
00408 //----------------------------------------------------------------------------
00409 void
00410 SVTK_Recorder
00411 ::AddSkippedFrames()
00412 {
00413   myErrorStatus = 0;
00414 
00415   if(myFrameIndexes.size() < 2)
00416     return;
00417 
00418   size_t anId = 0, anEnd = myFrameIndexes.size() - 1;
00419   for(; anId < anEnd; anId++){
00420     int aStartIndex = myFrameIndexes[anId];
00421     if(aStartIndex < 0)
00422       continue;
00423 
00424     int aFinishIndex = abs(myFrameIndexes[anId + 1]);
00425     if(aStartIndex + 1 == aFinishIndex)
00426       continue;
00427 
00428     std::string anInitialName;
00429     std::ostringstream aStream;
00430     GetNameJPEG(myName,aStartIndex,anInitialName);
00431     for(int anIndex = aStartIndex + 1; anIndex < aFinishIndex; anIndex++){
00432       myNbWrittenFrames++;
00433       std::string anCurrentName;
00434       GetNameJPEG(myName,anIndex,anCurrentName);
00435   #ifndef WIN32
00436       aStream<<"ln -s "<< anInitialName<<" "<<anCurrentName<<";";
00437   #else
00438       aStream<<"COPY /Y "<<QString::fromStdString(anInitialName).replace("/","\\\\").toStdString()<<
00439                 " "<<QString::fromStdString(anCurrentName).replace("/","\\\\").toStdString()<<" > NUL";
00440   #endif
00441       if(anIndex + 1 < aFinishIndex)
00442   #ifndef WIN32
00443         aStream<<" \\";
00444         aStream<<endl;
00445   #else
00446         aStream<<" & ";
00447   #endif
00448     }
00449     std::string aString(aStream.str());
00450     system(aString.c_str());
00451     if(MYDEBUG) cout<<"SVTK_Recorder::AddSkippedFrames - "<<aString<<endl;
00452   }
00453 }
00454 
00455 
00456 //----------------------------------------------------------------------------
00457 void
00458 SVTK_Recorder
00459 ::MakeFileAVI()
00460 {
00461   myErrorStatus = 0;
00462   std::ostringstream aStream;
00463   aStream<<myNameAVIMaker<<
00464     " -I p"<<
00465     " -v 0"<<
00466     //" -f "<<int(myNbFPS)<<" "<<
00467     " -f "<<myNbFPS<<" "<<
00468     " -n "<<myNbWrittenFrames<<" "<<
00469     " -j \""<<myName<<"_\%06d.jpeg\" "<<
00470     "| yuv2lav"<<" -o \""<<myName<<"\"";
00471 #ifdef WIN32
00472   aStream<<" -f aA";   
00473 #endif
00474   std::string aString(aStream.str());
00475   myErrorStatus = system(aString.c_str());
00476 
00477   if(MYDEBUG) cout<<"SVTK_Recorder::MakeFileAVI - "<<aString<<endl;
00478 
00479   QFileInfo aFileInfo(myName.c_str());
00480   QString aDirPath = aFileInfo.absoluteDir().path();
00481   QString aBaseName = aFileInfo.fileName();
00482   QString aCommand;
00483 #ifndef WIN32
00484   aCommand = QString("(cd ") + aDirPath + 
00485     "; ls " +
00486     " | egrep '" + aBaseName + "_[0-9]*.jpeg'" +
00487     " | xargs rm " +
00488     ")";
00489 #else
00490   QString tmpFile = QString("_") + aBaseName + "_tempfile";
00491   QString diskName = aDirPath.split("/")[0];
00492   aCommand = diskName + " && (cd " + aDirPath.replace("/","\\\\") + 
00493        " && ((dir /b | findstr " + aBaseName + "_[0-9]*.jpeg > " + tmpFile + 
00494        ") & (for /f %i in (" + tmpFile + ") do (del \"%i\")) & (del " + tmpFile + "))) > NUL";
00495 #endif
00496 
00497   if(MYDEBUG) cout<<"SVTK_Recorder::MakeFileAVI - "<<(const char*)aCommand.toLatin1()<<endl;
00498   system((const char*)aCommand.toLatin1());
00499 }