1 // Copyright (C) 2007-2022 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, 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"
50 static int MYDEBUG = 0;
52 static int MYDEBUG = 0;
58 //----------------------------------------------------------------------------
61 GetNameJPEG(const std::string& thePreffix,
65 std::ostringstream aStream;
66 aStream<<thePreffix<<"_"<<setw(6)<<setfill('0')<<theIndex<<".jpeg";
67 theName = aStream.str();
71 //----------------------------------------------------------------------------
72 vtkStandardNewMacro(SVTK_Recorder)
75 //----------------------------------------------------------------------------
78 myState(SVTK_Recorder_Stop),
87 myProgressiveMode(true),
88 myUseSkippedFrames(true),
89 myNameAVIMaker("jpeg2yuv"),
90 myCommand(vtkCallbackCommand::New()),
92 myFilter(vtkWindowToImageFilter::New()),
93 myWriterMgr(new SVTK_ImageWriterMgr)
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(myFilter,anImageData,aName,myProgressiveMode,myQuality);
382 myRenderWindow->AddObserver(vtkCommand::EndEvent,
388 //----------------------------------------------------------------------------
393 vtkImageData *anImageData = myFilter->GetOutput();
399 myFilter->UpdateInformation();
400 myFilter->UpdateWholeExtent();
404 //----------------------------------------------------------------------------
411 if(myFrameIndexes.size() < 2)
414 size_t anId = 0, anEnd = myFrameIndexes.size() - 1;
415 for(; anId < anEnd; anId++){
416 int aStartIndex = myFrameIndexes[anId];
420 int aFinishIndex = abs(myFrameIndexes[anId + 1]);
421 if(aStartIndex + 1 == aFinishIndex)
424 std::string anInitialName;
425 std::ostringstream aStream;
426 GetNameJPEG(myName,aStartIndex,anInitialName);
427 for(int anIndex = aStartIndex + 1; anIndex < aFinishIndex; anIndex++){
429 std::string anCurrentName;
430 GetNameJPEG(myName,anIndex,anCurrentName);
432 aStream<<"ln -s "<< anInitialName<<" "<<anCurrentName<<";";
434 aStream<<"COPY /Y "<<QString::fromStdString(anInitialName).replace("/","\\\\").toStdString()<<
435 " "<<QString::fromStdString(anCurrentName).replace("/","\\\\").toStdString()<<" > NUL";
437 if(anIndex + 1 < aFinishIndex) {
446 std::string aString(aStream.str());
447 system(aString.c_str());
448 if(MYDEBUG) 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(MYDEBUG) cout<<"SVTK_Recorder::MakeFileAVI - "<<aString<<endl;
476 QFileInfo aFileInfo(myName.c_str());
477 QString aDirPath = aFileInfo.absoluteDir().path();
478 QString aBaseName = aFileInfo.fileName();
481 aCommand = QString("(cd ") + aDirPath +
483 " | egrep '" + aBaseName + "_[0-9]*.jpeg'" +
487 QString tmpFile = QString("_") + aBaseName + "_tempfile";
488 QString diskName = aDirPath.split("/")[0];
489 aCommand = diskName + " && (cd " + aDirPath.replace("/","\\\\") +
490 " && ((dir /b | findstr " + aBaseName + "_[0-9]*.jpeg > " + tmpFile +
491 ") & (for /f %i in (" + tmpFile + ") do (del \"%i\")) & (del " + tmpFile + "))) > NUL";
494 if(MYDEBUG) cout<<"SVTK_Recorder::MakeFileAVI - "<<(const char*)aCommand.toUtf8()<<endl;
495 system((const char*)aCommand.toUtf8());