1 // Copyright (C) 2007-2023 CEA, EDF, 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, or (at your option) any later version.
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>
43 #include <QApplication>
47 #include "utilities.h"
52 //----------------------------------------------------------------------------
55 GetNameJPEG(const std::string& thePreffix,
59 std::ostringstream aStream;
60 aStream<<thePreffix<<"_"<<setw(6)<<setfill('0')<<theIndex<<".jpeg";
61 theName = aStream.str();
65 //----------------------------------------------------------------------------
66 vtkStandardNewMacro(SVTK_Recorder)
69 //----------------------------------------------------------------------------
72 myState(SVTK_Recorder_Stop),
81 myProgressiveMode(true),
82 myUseSkippedFrames(true),
83 myNameAVIMaker("jpeg2yuv"),
84 myCommand(vtkCallbackCommand::New()),
86 myFilter(vtkWindowToImageFilter::New()),
87 myWriterMgr(new SVTK_ImageWriterMgr)
89 myCommand->SetClientData(this);
90 myCommand->SetCallback(SVTK_Recorder::ProcessEvents);
94 //----------------------------------------------------------------------------
104 //----------------------------------------------------------------------------
107 ::CheckExistAVIMaker()
110 std::ostringstream aStream;
112 aStream<<"which "<<myNameAVIMaker<<" 2> /dev/null";
114 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";
116 std::string anAVIMakeCheck = aStream.str();
117 int iErr = system(anAVIMakeCheck.c_str());
123 //----------------------------------------------------------------------------
126 ::SetName(const char* theName)
132 SVTK_Recorder::Name() const
134 return myName.c_str();
138 //----------------------------------------------------------------------------
141 ::SetNbFPS(const double theNbFPS)
154 //----------------------------------------------------------------------------
157 ::SetQuality(int theQuality)
159 myQuality = theQuality;
170 //----------------------------------------------------------------------------
173 ::SetRenderWindow(vtkRenderWindow* theRenderWindow)
175 myRenderWindow = theRenderWindow;
182 return myRenderWindow;
186 //----------------------------------------------------------------------------
189 ::SetProgressiveMode(bool theProgressiveMode)
191 myProgressiveMode = theProgressiveMode;
196 ::GetProgressiveMode() const
198 return myProgressiveMode;
202 //----------------------------------------------------------------------------
205 ::SetUseSkippedFrames(bool theUseSkippedFrames)
207 myUseSkippedFrames = theUseSkippedFrames;
212 ::UseSkippedFrames() const
214 return myUseSkippedFrames;
218 //----------------------------------------------------------------------------
221 ::ErrorStatus() const
223 return myErrorStatus;
234 //----------------------------------------------------------------------------
237 ::ProcessEvents(vtkObject* vtkNotUsed(theObject),
238 unsigned long theEvent,
240 void* vtkNotUsed(theCallData))
242 if(vtkObject* anObj = reinterpret_cast<vtkObject*>(theClientData)){
243 if(SVTK_Recorder* aSelf = dynamic_cast<SVTK_Recorder*>(anObj)){
244 if(theEvent==vtkCommand::EndEvent){
245 if(aSelf->State() == SVTK_Recorder::SVTK_Recorder_Record){
254 //----------------------------------------------------------------------------
259 if(myState == SVTK_Recorder_Stop){
261 myState = SVTK_Recorder_Record;
262 myFilter->SetInput(myRenderWindow);
264 myNbWrittenFrames = 0;
265 myRenderWindow->RemoveObserver(myCommand);
266 myRenderWindow->AddObserver(vtkCommand::EndEvent,
269 myRenderWindow->Render();
275 //----------------------------------------------------------------------------
280 QApplication::setOverrideCursor( Qt::WaitCursor );
282 if(myState == SVTK_Recorder_Record){
288 if(myUseSkippedFrames)
291 myFrameIndexes.clear();
295 myState = SVTK_Recorder_Stop;
298 QApplication::restoreOverrideCursor();
302 //----------------------------------------------------------------------------
307 myPaused = myPaused ? 0 : 1;
308 if(myPaused && !myFrameIndexes.empty()){
309 myFrameIndexes.back() *= -1;
311 if(SALOME::VerbosityActivated())
312 cout << "SVTK_Recorder::Pause - myFrameIndexes.back() = " << myFrameIndexes.back() << endl;
317 //----------------------------------------------------------------------------
320 GetFrameIndex(double theStartTime,
323 double aTimeNow = vtkTimerLog::GetUniversalTime();
324 double aDelta = aTimeNow - theStartTime;
325 return int(aDelta*theFPS);
335 if(myFrameIndex < 0){
337 myTimeStart = vtkTimerLog::GetUniversalTime();
339 int aFrameIndex = GetFrameIndex(myTimeStart,myNbFPS);
340 if(aFrameIndex <= myFrameIndex)
343 // If there was a "pause" we correct the myTimeStart
344 int aLastFrameIndex = myFrameIndexes.back();
345 if(aLastFrameIndex < 0){
346 myFrameIndexes.back() = abs(myFrameIndexes.back());
347 double aPauseTime = fabs((double)(aFrameIndex - myFrameIndex - 1)) / myNbFPS;
349 if(SALOME::VerbosityActivated())
350 cout << "SVTK_Recorder::DoRecord - aFrameIndex = " << aFrameIndex <<
351 "; aPauseTime = " << aPauseTime << endl;
353 myTimeStart += aPauseTime;
356 aFrameIndex = GetFrameIndex(myTimeStart,myNbFPS);
357 if(aFrameIndex <= myFrameIndex)
360 myFrameIndex = aFrameIndex;
363 myFrameIndexes.push_back(myFrameIndex);
364 if(SALOME::VerbosityActivated())
365 cout << "SVTK_Recorder::DoRecord - myFrameIndex = " << myFrameIndex << endl;
367 myRenderWindow->RemoveObserver(myCommand);
368 myFilter->Modified();
371 GetNameJPEG(myName,myFrameIndex,aName);
375 vtkImageData *anImageData = vtkImageData::New();
376 anImageData->DeepCopy(myFilter->GetOutput());
378 myWriterMgr->StartImageWriter(myFilter,anImageData,aName,myProgressiveMode,myQuality);
381 myRenderWindow->AddObserver(vtkCommand::EndEvent,
387 //----------------------------------------------------------------------------
392 vtkImageData *anImageData = myFilter->GetOutput();
398 myFilter->UpdateInformation();
399 myFilter->UpdateWholeExtent();
403 //----------------------------------------------------------------------------
410 if(myFrameIndexes.size() < 2)
413 size_t anId = 0, anEnd = myFrameIndexes.size() - 1;
414 for(; anId < anEnd; anId++){
415 int aStartIndex = myFrameIndexes[anId];
419 int aFinishIndex = abs(myFrameIndexes[anId + 1]);
420 if(aStartIndex + 1 == aFinishIndex)
423 std::string anInitialName;
424 std::ostringstream aStream;
425 GetNameJPEG(myName,aStartIndex,anInitialName);
426 for(int anIndex = aStartIndex + 1; anIndex < aFinishIndex; anIndex++){
428 std::string anCurrentName;
429 GetNameJPEG(myName,anIndex,anCurrentName);
431 aStream<<"ln -s "<< anInitialName<<" "<<anCurrentName<<";";
433 aStream<<"COPY /Y "<<QString::fromStdString(anInitialName).replace("/","\\\\").toStdString()<<
434 " "<<QString::fromStdString(anCurrentName).replace("/","\\\\").toStdString()<<" > NUL";
436 if(anIndex + 1 < aFinishIndex) {
445 std::string aString(aStream.str());
446 system(aString.c_str());
447 if(SALOME::VerbosityActivated())
448 cout << "SVTK_Recorder::AddSkippedFrames - " << aString << endl;
453 //----------------------------------------------------------------------------
459 std::ostringstream aStream;
460 aStream<<myNameAVIMaker<<
463 //" -f "<<int(myNbFPS)<<" "<<
464 " -f "<<myNbFPS<<" "<<
465 " -n "<<myNbWrittenFrames<<" "<<
466 " -j \""<<myName<<"_%06d.jpeg\" "<<
467 "| yuv2lav"<<" -o \""<<myName<<"\"";
471 std::string aString(aStream.str());
472 myErrorStatus = system(aString.c_str());
474 if(SALOME::VerbosityActivated())
475 cout << "SVTK_Recorder::MakeFileAVI - " << aString << endl;
477 QFileInfo aFileInfo(myName.c_str());
478 QString aDirPath = aFileInfo.absoluteDir().path();
479 QString aBaseName = aFileInfo.fileName();
482 aCommand = QString("(cd ") + aDirPath +
484 " | egrep '" + aBaseName + "_[0-9]*.jpeg'" +
488 QString tmpFile = QString("_") + aBaseName + "_tempfile";
489 QString diskName = aDirPath.split("/")[0];
490 aCommand = diskName + " && (cd " + aDirPath.replace("/","\\\\") +
491 " && ((dir /b | findstr " + aBaseName + "_[0-9]*.jpeg > " + tmpFile +
492 ") & (for /f %i in (" + tmpFile + ") do (del \"%i\")) & (del " + tmpFile + "))) > NUL";
495 if(SALOME::VerbosityActivated())
496 cout << "SVTK_Recorder::MakeFileAVI - " << (const char*)aCommand.toUtf8() << endl;
498 system((const char*)aCommand.toUtf8());