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