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