]> SALOME platform Git repositories - modules/visu.git/blob - src/VVTK/VVTK_Recorder.cxx
Salome HOME
Join modifications from BR_Dev_For_4_0 tag V4_1_1.
[modules/visu.git] / src / VVTK / VVTK_Recorder.cxx
1 //  SALOME VTKViewer : build VTK viewer into Salome desktop
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
6 //  This library is free software; you can redistribute it and/or 
7 //  modify it under the terms of the GNU Lesser General Public 
8 //  License as published by the Free Software Foundation; either 
9 //  version 2.1 of the License. 
10 // 
11 //  This library is distributed in the hope that it will be useful, 
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
14 //  Lesser General Public License for more details. 
15 // 
16 //  You should have received a copy of the GNU Lesser General Public 
17 //  License along with this library; if not, write to the Free Software 
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
19 // 
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //
23 //
24 //  File   :
25 //  Author :
26 //  Module :
27 //  $Header$
28
29 #include "VVTK_Recorder.h"
30
31 #include "VVTK_ImageWriter.h"
32 #include "VVTK_ImageWriterMgr.h"
33
34 #include <vtkObjectFactory.h>
35 #include <vtkObject.h>
36 #include <vtkCallbackCommand.h>
37 #include <vtkRenderWindow.h>
38 #include <vtkTimerLog.h>
39 #include <vtkWindowToImageFilter.h>
40 #include <vtkJPEGWriter.h>
41 #include <vtkImageData.h>
42
43 #include <sstream>
44 #include <iomanip>
45 #include <iostream>
46
47 #ifndef WIN32
48 #include <unistd.h>
49 #endif
50
51 #include <qapplication.h>
52 #include <qfileinfo.h>
53
54 #include "utilities.h"
55
56 #ifdef _DEBUG_
57 static int MYDEBUG = 0;
58 #else
59 static int MYDEBUG = 0;
60 #endif
61
62
63 namespace
64 {
65   //----------------------------------------------------------------------------
66   inline
67   void
68   GetNameJPEG(const std::string& thePreffix,  
69               const int theIndex,
70               std::string& theName)
71   {
72     using namespace std;
73     ostringstream aStream;
74     aStream<<thePreffix<<"_"<<setw(6)<<setfill('0')<<theIndex<<".jpeg";
75     theName = aStream.str();
76   }
77 }
78
79 //----------------------------------------------------------------------------
80 vtkCxxRevisionMacro(VVTK_Recorder,"$Revision$");
81 vtkStandardNewMacro(VVTK_Recorder);
82
83
84 //----------------------------------------------------------------------------
85 VVTK_Recorder
86 ::VVTK_Recorder():
87   myRenderWindow(NULL),
88   myState(VVTK_Recorder_Stop),
89   myNbFPS(5.5),
90   myQuality(100),
91   myProgressiveMode(true),
92   myUseSkippedFrames(true),
93   myErrorStatus(0),
94   myCommand(vtkCallbackCommand::New()),
95   myPriority(0.0),
96   myTimeStart(0.0),
97   myFrameIndex(0),
98   myPaused(0),
99   myFilter(vtkWindowToImageFilter::New()),
100   myWriterMgr(new VVTK_ImageWriterMgr),
101   myNbWrittenFrames(0),
102   myNameAVIMaker("jpeg2yuv")
103 {
104   myCommand->SetClientData(this); 
105   myCommand->SetCallback(VVTK_Recorder::ProcessEvents);
106 }
107
108
109 //----------------------------------------------------------------------------
110 VVTK_Recorder
111 ::~VVTK_Recorder()
112 {
113   myCommand->Delete();
114   myFilter->Delete();
115   delete myWriterMgr;
116 }
117
118
119 //----------------------------------------------------------------------------
120 void
121 VVTK_Recorder
122 ::CheckExistAVIMaker()
123 {
124   myErrorStatus = 0;
125   using namespace std;
126   ostringstream aStream;
127   aStream<<"which "<<myNameAVIMaker<<" >& /dev/null";
128   std::string anAVIMakeCheck = aStream.str();
129   int iErr = system(anAVIMakeCheck.c_str());
130   if(iErr != 0)
131     myErrorStatus = 127;
132 }
133
134
135 //----------------------------------------------------------------------------
136 void
137 VVTK_Recorder
138 ::SetName(const char* theName)
139 {
140   myName = theName;
141 }
142
143 const char* 
144 VVTK_Recorder::Name() const
145 {
146   return myName.c_str();
147 }
148
149
150 //----------------------------------------------------------------------------
151 void
152 VVTK_Recorder
153 ::SetNbFPS(const double theNbFPS)
154 {
155   myNbFPS = theNbFPS;
156 }
157
158 double
159 VVTK_Recorder
160 ::NbFPS() const
161 {
162   return myNbFPS;
163 }
164
165
166 //----------------------------------------------------------------------------
167 void
168 VVTK_Recorder
169 ::SetQuality(int theQuality)
170 {
171   myQuality = theQuality;
172 }
173
174 int
175 VVTK_Recorder
176 ::GetQuality() const
177 {
178   return myQuality;
179 }
180
181
182 //----------------------------------------------------------------------------
183 void 
184 VVTK_Recorder
185 ::SetRenderWindow(vtkRenderWindow* theRenderWindow)
186 {
187   myRenderWindow = theRenderWindow;
188 }
189
190 vtkRenderWindow* 
191 VVTK_Recorder
192 ::RenderWindow()
193 {
194   return myRenderWindow;
195 }
196
197
198 //----------------------------------------------------------------------------
199 void
200 VVTK_Recorder
201 ::SetProgressiveMode(bool theProgressiveMode)
202 {
203   myProgressiveMode = theProgressiveMode;
204 }
205
206 bool
207 VVTK_Recorder
208 ::GetProgressiveMode() const
209 {
210   return myProgressiveMode;
211 }
212
213
214 //----------------------------------------------------------------------------
215 void
216 VVTK_Recorder
217 ::SetUseSkippedFrames(bool theUseSkippedFrames)
218 {
219   myUseSkippedFrames = theUseSkippedFrames;
220 }
221
222 bool
223 VVTK_Recorder
224 ::UseSkippedFrames() const
225 {
226   return myUseSkippedFrames;
227 }
228
229
230 //----------------------------------------------------------------------------
231 int
232 VVTK_Recorder
233 ::ErrorStatus() const
234 {
235   return myErrorStatus;
236 }
237
238 int
239 VVTK_Recorder
240 ::State() const
241 {
242   return myState;
243 }
244
245
246 //----------------------------------------------------------------------------
247 void
248 VVTK_Recorder
249 ::ProcessEvents(vtkObject* vtkNotUsed(theObject), 
250                 unsigned long theEvent,
251                 void* theClientData, 
252                 void* vtkNotUsed(theCallData))
253 {
254   if(vtkObject* anObj = reinterpret_cast<vtkObject*>(theClientData)){ 
255     if(VVTK_Recorder* aSelf = dynamic_cast<VVTK_Recorder*>(anObj)){
256       if(theEvent==vtkCommand::EndEvent){
257         if(aSelf->State() == VVTK_Recorder::VVTK_Recorder_Record){
258           aSelf->DoRecord();
259         }
260       }
261     }
262   }
263 }
264
265
266 //----------------------------------------------------------------------------
267 void
268 VVTK_Recorder
269 ::Record()
270 {
271   if(myState == VVTK_Recorder_Stop){
272     if(myRenderWindow){
273       myState = VVTK_Recorder_Record;
274       myFilter->SetInput(myRenderWindow);
275       myFrameIndex = -1;
276       myNbWrittenFrames = 0;
277       myRenderWindow->RemoveObserver(myCommand);
278       myRenderWindow->AddObserver(vtkCommand::EndEvent,
279                                   myCommand,
280                                   myPriority);
281       myRenderWindow->Render();
282     }
283   }
284 }
285
286
287 //----------------------------------------------------------------------------
288 void
289 VVTK_Recorder
290 ::Stop()
291 {
292   QApplication::setOverrideCursor( Qt::waitCursor );
293
294   if(myState == VVTK_Recorder_Record){ 
295     if(!myPaused)
296       DoRecord();
297
298     myWriterMgr->Stop();
299
300     if(myUseSkippedFrames)
301       AddSkippedFrames();
302
303     myFrameIndexes.clear();
304
305     MakeFileAVI();
306   }
307   myState = VVTK_Recorder_Stop;
308   myPaused = 0;
309
310   QApplication::restoreOverrideCursor();
311 }
312
313
314 //----------------------------------------------------------------------------
315 void
316 VVTK_Recorder
317 ::Pause()
318 {
319   myPaused = myPaused ? 0 : 1;
320   if(myPaused && !myFrameIndexes.empty()){
321     myFrameIndexes.back() *= -1;
322     if(MYDEBUG) cout<<"VVTK_Recorder::Pause - myFrameIndexes.back() = "<<myFrameIndexes.back()<<endl;
323   }
324 }
325
326
327 //----------------------------------------------------------------------------
328 inline 
329 int
330 GetFrameIndex(double theStartTime,
331               double theFPS)
332 {
333   double aTimeNow = vtkTimerLog::GetCurrentTime();
334   double aDelta = aTimeNow - theStartTime;
335   return int(aDelta*theFPS);
336 }
337
338 void
339 VVTK_Recorder
340 ::DoRecord()
341 {
342   if(myPaused)
343     return;
344
345   if(myFrameIndex < 0){
346     myFrameIndex = 0;
347     myTimeStart = vtkTimerLog::GetCurrentTime();
348   }else{
349     int aFrameIndex = GetFrameIndex(myTimeStart,myNbFPS);
350     if(aFrameIndex <= myFrameIndex)
351       return;
352
353     // If there was a "pause" we correct the myTimeStart
354     int aLastFrameIndex = myFrameIndexes.back();
355     if(aLastFrameIndex < 0){
356       myFrameIndexes.back() = abs(myFrameIndexes.back());
357       double aPauseTime = fabs((double)(aFrameIndex - myFrameIndex - 1)) / myNbFPS;
358       if(MYDEBUG) 
359         cout<<"VVTK_Recorder::DoRecord - aFrameIndex = "<<aFrameIndex<<
360           "; aPauseTime = "<<aPauseTime<<endl;
361       myTimeStart += aPauseTime;
362     }
363
364     aFrameIndex = GetFrameIndex(myTimeStart,myNbFPS);
365     if(aFrameIndex <= myFrameIndex)
366       return;
367
368     myFrameIndex = aFrameIndex;
369   }
370
371   myFrameIndexes.push_back(myFrameIndex);
372   if(MYDEBUG) cout<<"VVTK_Recorder::DoRecord - myFrameIndex = "<<myFrameIndex<<endl;
373
374   myRenderWindow->RemoveObserver(myCommand);
375   myFilter->Modified();
376
377   std::string aName;
378   GetNameJPEG(myName,myFrameIndex,aName);
379
380   PreWrite();
381
382   vtkImageData *anImageData = vtkImageData::New(); 
383   anImageData->DeepCopy(myFilter->GetOutput());
384
385   myWriterMgr->StartImageWriter(anImageData,aName,myProgressiveMode,myQuality);
386   myNbWrittenFrames++;
387
388   myRenderWindow->AddObserver(vtkCommand::EndEvent,
389                               myCommand,
390                               myPriority);
391 }
392
393
394 //----------------------------------------------------------------------------
395 void
396 VVTK_Recorder
397 ::PreWrite()
398 {
399   vtkImageData *anImageData = myFilter->GetOutput();
400   //
401   if(!anImageData){
402     myErrorStatus = 20;
403     return;
404   }
405   anImageData->UpdateInformation();
406   int *anExtent = anImageData->GetWholeExtent();
407   anImageData->SetUpdateExtent(anExtent[0], anExtent[1],
408                                anExtent[2], anExtent[3],
409                                0,0);
410   anImageData->UpdateData();
411 }
412
413
414 //----------------------------------------------------------------------------
415 void
416 VVTK_Recorder
417 ::AddSkippedFrames()
418 {
419   myErrorStatus = 0;
420
421   if(myFrameIndexes.size() < 2)
422     return;
423
424   size_t anId = 0, anEnd = myFrameIndexes.size() - 1;
425   for(; anId < anEnd; anId++){
426     int aStartIndex = myFrameIndexes[anId];
427     if(aStartIndex < 0)
428       continue;
429
430     int aFinishIndex = abs(myFrameIndexes[anId + 1]);
431     if(aStartIndex + 1 == aFinishIndex)
432       continue;
433
434     std::string anInitialName;
435     std::ostringstream aStream;
436     GetNameJPEG(myName,aStartIndex,anInitialName);
437     for(int anIndex = aStartIndex + 1; anIndex < aFinishIndex; anIndex++){
438       myNbWrittenFrames++;
439       std::string anCurrentName;
440       GetNameJPEG(myName,anIndex,anCurrentName);
441       aStream<<"ln -s "<< anInitialName<<" "<<anCurrentName<<";";
442       if(anIndex + 1 < aFinishIndex)
443         aStream<<" \\";
444       aStream<<endl;
445     }
446     std::string aString(aStream.str());
447     system(aString.c_str());
448     if(MYDEBUG) cout<<"VVTK_Recorder::AddSkippedFrames - "<<aString<<endl;
449   }
450 }
451
452
453 //----------------------------------------------------------------------------
454 void
455 VVTK_Recorder
456 ::MakeFileAVI()
457 {
458   myErrorStatus = 0;
459   std::ostringstream aStream;
460   aStream<<myNameAVIMaker<<
461     " -I p"<<
462     " -v 0"<<
463     //" -f "<<int(myNbFPS)<<" "<<
464     " -f "<<myNbFPS<<" "<<
465     " -n "<<myNbWrittenFrames<<" "<<
466     " -j "<<myName<<"_\%06d.jpeg "<<
467     "| yuv2lav"<<
468     " -o "<<myName;
469    
470   std::string aString(aStream.str());
471   myErrorStatus = system(aString.c_str());
472
473   if(MYDEBUG) cout<<"VVTK_Recorder::MakeFileAVI - "<<aString<<endl;
474
475   QFileInfo aFileInfo(myName.c_str());
476   QString aDirPath = aFileInfo.dirPath(TRUE);
477   QString aBaseName = aFileInfo.fileName();
478   QString aCommand = 
479     QString("(cd ") + aDirPath + 
480     "; ls " +
481     " | egrep '" + aBaseName + "_[0-9]*.jpeg'" +
482     " | xargs rm " +
483     ")";
484
485   aCommand = 
486     QString("rm ") + aDirPath + "/" + aBaseName + "*.jpeg";
487
488   if(MYDEBUG) cout<<"VVTK_Recorder::MakeFileAVI - "<<aCommand.latin1()<<endl;
489   system(aCommand.latin1());
490 }