1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "SVTK_Recorder.h"
22 #include "SVTK_ImageWriter.h"
23 #include "SVTK_ImageWriterMgr.h"
25 #include <vtkObjectFactory.h>
26 #include <vtkObject.h>
27 #include <vtkCallbackCommand.h>
28 #include <vtkRenderWindow.h>
29 #include <vtkTimerLog.h>
30 #include <vtkWindowToImageFilter.h>
31 #include <vtkJPEGWriter.h>
32 #include <vtkImageData.h>
42 #include <QApplication>
46 //#include "utilities.h"
49 static int MYDEBUG = 0;
51 static int MYDEBUG = 0;
57 //----------------------------------------------------------------------------
60 GetNameJPEG(const std::string& thePreffix,
64 std::ostringstream aStream;
65 aStream<<thePreffix<<"_"<<setw(6)<<setfill('0')<<theIndex<<".jpeg";
66 theName = aStream.str();
70 //----------------------------------------------------------------------------
71 vtkCxxRevisionMacro(SVTK_Recorder,"$Revision$");
72 vtkStandardNewMacro(SVTK_Recorder);
75 //----------------------------------------------------------------------------
79 myState(SVTK_Recorder_Stop),
82 myProgressiveMode(true),
83 myUseSkippedFrames(true),
85 myCommand(vtkCallbackCommand::New()),
90 myFilter(vtkWindowToImageFilter::New()),
91 myWriterMgr(new SVTK_ImageWriterMgr),
93 myNameAVIMaker("jpeg2yuv")
95 myCommand->SetClientData(this);
96 myCommand->SetCallback(SVTK_Recorder::ProcessEvents);
100 //----------------------------------------------------------------------------
110 //----------------------------------------------------------------------------
113 ::CheckExistAVIMaker()
116 std::ostringstream aStream;
118 aStream<<"which "<<myNameAVIMaker<<" 2> /dev/null";
120 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";
122 std::string anAVIMakeCheck = aStream.str();
123 int iErr = system(anAVIMakeCheck.c_str());
129 //----------------------------------------------------------------------------
132 ::SetName(const char* theName)
138 SVTK_Recorder::Name() const
140 return myName.c_str();
144 //----------------------------------------------------------------------------
147 ::SetNbFPS(const double theNbFPS)
160 //----------------------------------------------------------------------------
163 ::SetQuality(int theQuality)
165 myQuality = theQuality;
176 //----------------------------------------------------------------------------
179 ::SetRenderWindow(vtkRenderWindow* theRenderWindow)
181 myRenderWindow = theRenderWindow;
188 return myRenderWindow;
192 //----------------------------------------------------------------------------
195 ::SetProgressiveMode(bool theProgressiveMode)
197 myProgressiveMode = theProgressiveMode;
202 ::GetProgressiveMode() const
204 return myProgressiveMode;
208 //----------------------------------------------------------------------------
211 ::SetUseSkippedFrames(bool theUseSkippedFrames)
213 myUseSkippedFrames = theUseSkippedFrames;
218 ::UseSkippedFrames() const
220 return myUseSkippedFrames;
224 //----------------------------------------------------------------------------
227 ::ErrorStatus() const
229 return myErrorStatus;
240 //----------------------------------------------------------------------------
243 ::ProcessEvents(vtkObject* vtkNotUsed(theObject),
244 unsigned long theEvent,
246 void* vtkNotUsed(theCallData))
248 if(vtkObject* anObj = reinterpret_cast<vtkObject*>(theClientData)){
249 if(SVTK_Recorder* aSelf = dynamic_cast<SVTK_Recorder*>(anObj)){
250 if(theEvent==vtkCommand::EndEvent){
251 if(aSelf->State() == SVTK_Recorder::SVTK_Recorder_Record){
260 //----------------------------------------------------------------------------
265 if(myState == SVTK_Recorder_Stop){
267 myState = SVTK_Recorder_Record;
268 myFilter->SetInput(myRenderWindow);
270 myNbWrittenFrames = 0;
271 myRenderWindow->RemoveObserver(myCommand);
272 myRenderWindow->AddObserver(vtkCommand::EndEvent,
275 myRenderWindow->Render();
281 //----------------------------------------------------------------------------
286 QApplication::setOverrideCursor( Qt::WaitCursor );
288 if(myState == SVTK_Recorder_Record){
294 if(myUseSkippedFrames)
297 myFrameIndexes.clear();
301 myState = SVTK_Recorder_Stop;
304 QApplication::restoreOverrideCursor();
308 //----------------------------------------------------------------------------
313 myPaused = myPaused ? 0 : 1;
314 if(myPaused && !myFrameIndexes.empty()){
315 myFrameIndexes.back() *= -1;
316 if(MYDEBUG) cout<<"SVTK_Recorder::Pause - myFrameIndexes.back() = "<<myFrameIndexes.back()<<endl;
321 //----------------------------------------------------------------------------
324 GetFrameIndex(double theStartTime,
327 double aTimeNow = vtkTimerLog::GetUniversalTime();
328 double aDelta = aTimeNow - theStartTime;
329 return int(aDelta*theFPS);
339 if(myFrameIndex < 0){
341 myTimeStart = vtkTimerLog::GetUniversalTime();
343 int aFrameIndex = GetFrameIndex(myTimeStart,myNbFPS);
344 if(aFrameIndex <= myFrameIndex)
347 // If there was a "pause" we correct the myTimeStart
348 int aLastFrameIndex = myFrameIndexes.back();
349 if(aLastFrameIndex < 0){
350 myFrameIndexes.back() = abs(myFrameIndexes.back());
351 double aPauseTime = fabs((double)(aFrameIndex - myFrameIndex - 1)) / myNbFPS;
353 cout<<"SVTK_Recorder::DoRecord - aFrameIndex = "<<aFrameIndex<<
354 "; aPauseTime = "<<aPauseTime<<endl;
355 myTimeStart += aPauseTime;
358 aFrameIndex = GetFrameIndex(myTimeStart,myNbFPS);
359 if(aFrameIndex <= myFrameIndex)
362 myFrameIndex = aFrameIndex;
365 myFrameIndexes.push_back(myFrameIndex);
366 if(MYDEBUG) cout<<"SVTK_Recorder::DoRecord - myFrameIndex = "<<myFrameIndex<<endl;
368 myRenderWindow->RemoveObserver(myCommand);
369 myFilter->Modified();
372 GetNameJPEG(myName,myFrameIndex,aName);
376 vtkImageData *anImageData = vtkImageData::New();
377 anImageData->DeepCopy(myFilter->GetOutput());
379 myWriterMgr->StartImageWriter(anImageData,aName,myProgressiveMode,myQuality);
382 myRenderWindow->AddObserver(vtkCommand::EndEvent,
388 //----------------------------------------------------------------------------
393 vtkImageData *anImageData = myFilter->GetOutput();
399 anImageData->UpdateInformation();
400 int *anExtent = anImageData->GetWholeExtent();
401 anImageData->SetUpdateExtent(anExtent[0], anExtent[1],
402 anExtent[2], anExtent[3],
404 anImageData->UpdateData();
408 //----------------------------------------------------------------------------
415 if(myFrameIndexes.size() < 2)
418 size_t anId = 0, anEnd = myFrameIndexes.size() - 1;
419 for(; anId < anEnd; anId++){
420 int aStartIndex = myFrameIndexes[anId];
424 int aFinishIndex = abs(myFrameIndexes[anId + 1]);
425 if(aStartIndex + 1 == aFinishIndex)
428 std::string anInitialName;
429 std::ostringstream aStream;
430 GetNameJPEG(myName,aStartIndex,anInitialName);
431 for(int anIndex = aStartIndex + 1; anIndex < aFinishIndex; anIndex++){
433 std::string anCurrentName;
434 GetNameJPEG(myName,anIndex,anCurrentName);
436 aStream<<"ln -s "<< anInitialName<<" "<<anCurrentName<<";";
438 aStream<<"COPY /Y "<<QString::fromStdString(anInitialName).replace("/","\\\\").toStdString()<<
439 " "<<QString::fromStdString(anCurrentName).replace("/","\\\\").toStdString()<<" > NUL";
441 if(anIndex + 1 < aFinishIndex)
449 std::string aString(aStream.str());
450 system(aString.c_str());
451 if(MYDEBUG) cout<<"SVTK_Recorder::AddSkippedFrames - "<<aString<<endl;
456 //----------------------------------------------------------------------------
462 std::ostringstream aStream;
463 aStream<<myNameAVIMaker<<
466 //" -f "<<int(myNbFPS)<<" "<<
467 " -f "<<myNbFPS<<" "<<
468 " -n "<<myNbWrittenFrames<<" "<<
469 " -j \""<<myName<<"_\%06d.jpeg\" "<<
470 "| yuv2lav"<<" -o \""<<myName<<"\"";
474 std::string aString(aStream.str());
475 myErrorStatus = system(aString.c_str());
477 if(MYDEBUG) cout<<"SVTK_Recorder::MakeFileAVI - "<<aString<<endl;
479 QFileInfo aFileInfo(myName.c_str());
480 QString aDirPath = aFileInfo.absoluteDir().path();
481 QString aBaseName = aFileInfo.fileName();
484 aCommand = QString("(cd ") + aDirPath +
486 " | egrep '" + aBaseName + "_[0-9]*.jpeg'" +
490 QString tmpFile = QString("_") + aBaseName + "_tempfile";
491 QString diskName = aDirPath.split("/")[0];
492 aCommand = diskName + " && (cd " + aDirPath.replace("/","\\\\") +
493 " && ((dir /b | findstr " + aBaseName + "_[0-9]*.jpeg > " + tmpFile +
494 ") & (for /f %i in (" + tmpFile + ") do (del \"%i\")) & (del " + tmpFile + "))) > NUL";
497 if(MYDEBUG) cout<<"SVTK_Recorder::MakeFileAVI - "<<(const char*)aCommand.toLatin1()<<endl;
498 system((const char*)aCommand.toLatin1());