961da54018dc44d7d21b860346236430ff496d49
[occt.git] / src / OpenGl / OpenGl_AVIWriter.cxx
1 // Created on: 2007-04-15
2 // Created by: Alexey MORENOV & Alexander GRIGORIEV
3 // Copyright (c) 2007-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OpenGl_AVIWriter.hxx>
17
18 #if (defined(_WIN32) || defined(__WIN32__)) && defined(HAVE_VIDEOCAPTURE)
19   #ifdef _MSC_VER
20     #pragma comment (lib, "vfw32.lib")
21   #endif
22
23 OpenGl_AVIWriter* OpenGl_AVIWriter::MyAVIWriterInstance = 0L;
24
25 OpenGl_AVIWriter * OpenGl_AVIWriter::GetInstance()
26 {
27   return MyAVIWriterInstance;
28 }
29
30 //=======================================================================
31 //function : OpenGl_AVIWriter
32 //purpose  : 
33 //=======================================================================
34
35 Standard_EXPORT OpenGl_AVIWriter::OpenGl_AVIWriter
36                  (const char *     theFileName, 
37                   DWORD            dwCodec /* = mmioFOURCC('M','P','G','4') */,
38                   Standard_Integer theFrameRate /* = 25 */)
39   : myhHeap             (0L),
40     myhWindow           (0L),
41     myhAviDC            (0L),
42     mylpBits            (0L),
43     mylSample           (0L),
44     mypAviFile          (0L),
45     mypAviStream        (0L),
46     mypAviCompressedStream(0L),
47     myFileName          (0L),
48     myIsAllowRecord     (Standard_False),
49     myAppendFuncSelector(1)         //0=Dummy       1=FirstTime     2=Usual
50 {
51   ::AVIFileInit();
52   if (theFileName != 0L && theFileName[0] != '\0') {
53
54     const size_t aLen = strlen(theFileName) + 1;
55     myFileName = new char [aLen];
56     memcpy(myFileName, theFileName, aLen);
57     myErrMsg = (Standard_CString)"Method Succeeded";
58
59     pAppendFrame[0]= &OpenGl_AVIWriter::AppendDummy;
60     pAppendFrame[1]= &OpenGl_AVIWriter::AppendFrameFirstTime;
61     pAppendFrame[2]= &OpenGl_AVIWriter::AppendFrameUsual;
62
63     pAppendFrameBits[0]=&OpenGl_AVIWriter::AppendDummyBits;
64     pAppendFrameBits[1]=&OpenGl_AVIWriter::AppendFrameBitsFirstTime;
65     pAppendFrameBits[2]=&OpenGl_AVIWriter::AppendFrameBitsUsual;
66
67     MyAVIWriterInstance = this;
68
69     ZeroMemory(&myAviStreamInfo,sizeof(AVISTREAMINFO));
70     myAviStreamInfo.fccType             = streamtypeVIDEO;
71     myAviStreamInfo.fccHandler          = dwCodec;
72     myAviStreamInfo.dwScale             = 1;
73     myAviStreamInfo.dwRate              = theFrameRate; // Frames Per Second;
74     myAviStreamInfo.dwQuality           = 100;/*//-1;  // Default Quality*/
75
76     ZeroMemory(&myAviCompressOptions,sizeof(AVICOMPRESSOPTIONS));
77     myAviCompressOptions.fccType        = streamtypeVIDEO;
78     myAviCompressOptions.fccHandler     = myAviStreamInfo.fccHandler;
79     myAviCompressOptions.dwFlags        =
80       AVICOMPRESSF_KEYFRAMES|AVICOMPRESSF_VALID|AVICOMPRESSF_DATARATE;
81     myAviCompressOptions.dwKeyFrameEvery  = 1;
82     myAviCompressOptions.dwBytesPerSecond = 125000;
83     myAviCompressOptions.dwQuality      = 100;
84   }
85 }
86
87 //=======================================================================
88 //function : ~OpenGl_AVIWriter
89 //purpose  : 
90 //=======================================================================
91
92 Standard_EXPORT OpenGl_AVIWriter::~OpenGl_AVIWriter(void)
93 {
94   ReleaseMemory();
95   AVIFileExit();
96   if (myFileName)
97     delete [] myFileName;
98   MyAVIWriterInstance = 0L;
99 }
100
101 //=======================================================================
102 //function : StartRecording
103 //purpose  : 
104 //=======================================================================
105
106 void OpenGl_AVIWriter::StartRecording(const HANDLE hWin)
107 {
108   if (hWin != NULL)
109     myhWindow = hWin;
110   myIsAllowRecord = Standard_True;
111 }
112
113 //=======================================================================
114 //function : StopRecording
115 //purpose  : 
116 //=======================================================================
117
118 void OpenGl_AVIWriter::StopRecording()
119 {
120   myIsAllowRecord = Standard_False;
121 }
122
123 //=======================================================================
124 //function : ReleaseMemory
125 //purpose  : 
126 //=======================================================================
127
128 void OpenGl_AVIWriter::ReleaseMemory()
129 {
130   myAppendFuncSelector=0;      //Point to DummyFunction
131
132   if(myhAviDC)
133   {
134     DeleteDC(myhAviDC);
135     myhAviDC=NULL;
136   }
137   if(mypAviCompressedStream)
138   {
139     AVIStreamRelease(mypAviCompressedStream);
140     mypAviCompressedStream=NULL;
141   }
142   if(mypAviStream)
143   {
144     AVIStreamRelease(mypAviStream);
145     mypAviStream=NULL;
146   }
147   if(mypAviFile)
148   {
149     AVIFileRelease(mypAviFile);
150     mypAviFile=NULL;
151   }
152   if(mylpBits)
153   {
154     HeapFree(myhHeap,HEAP_NO_SERIALIZE,mylpBits);
155     mylpBits=NULL;
156   }
157   if(myhHeap)
158   {
159     HeapDestroy(myhHeap);
160     myhHeap=NULL;
161   }
162 }
163
164 //=======================================================================
165 //function : SetErrorMessage
166 //purpose  : 
167 //=======================================================================
168
169 void OpenGl_AVIWriter::SetErrorMessage(const char * theErrorMessage)
170 {
171   myErrMsg = (Standard_CString)theErrorMessage;
172 }
173
174 //=======================================================================
175 //function : InitMovieCreation
176 //purpose  : 
177 //=======================================================================
178
179 HRESULT OpenGl_AVIWriter::InitMovieCreation (int nFrameWidth,
180                                              int nFrameHeight,
181                                              int nBitsPerPixel)
182 {
183   int  nMaxWidth=GetSystemMetrics(SM_CXSCREEN),
184        nMaxHeight=GetSystemMetrics(SM_CYSCREEN);
185
186   myhAviDC = CreateCompatibleDC(NULL);
187   if(myhAviDC==NULL)
188   {
189     SetErrorMessage("Unable to Create Compatible DC");
190     return E_FAIL;
191   }
192
193   if (nFrameWidth > nMaxWidth)
194     nMaxWidth= nFrameWidth;
195   if (nFrameHeight > nMaxHeight)
196     nMaxHeight = nFrameHeight;
197
198   myhHeap=HeapCreate(HEAP_NO_SERIALIZE, nMaxWidth*nMaxHeight*4, 0);
199   if(myhHeap==NULL)
200   {
201     SetErrorMessage("Unable to Create Heap");
202     return E_FAIL;
203   }
204
205   mylpBits=HeapAlloc(myhHeap, HEAP_ZERO_MEMORY|HEAP_NO_SERIALIZE,
206                      nMaxWidth*nMaxHeight*4);
207   if(mylpBits==NULL)
208   {
209     SetErrorMessage("Unable to Allocate Memory on Heap");
210     return E_FAIL;
211   }
212
213   HRESULT hr;
214   hr = ::AVIFileOpen(&mypAviFile, myFileName, OF_CREATE|OF_WRITE, NULL);
215   if (!hr == AVIERR_OK)
216   {
217     SetErrorMessage("Unable to Create the Movie File");
218     return E_FAIL;
219   }
220   /*
221   if(FAILED(::AVIFileOpen(&mypAviFile, myszFileName, OF_CREATE|OF_WRITE, NULL)))
222   {
223     SetErrorMessage("Unable to Create the Movie File");
224     return E_FAIL;
225   }
226   */
227
228   myAviStreamInfo.dwSuggestedBufferSize = nMaxWidth * nMaxHeight * 4;
229   SetRect(&myAviStreamInfo.rcFrame, 0, 0, nFrameWidth, nFrameHeight);
230   strncpy(myAviStreamInfo.szName, "Video Stream", 64);
231
232   if(FAILED(AVIFileCreateStream(mypAviFile,&mypAviStream,&myAviStreamInfo)))
233   {
234     SetErrorMessage("Unable to Create Video Stream in the Movie File");
235     return E_FAIL;
236   }
237
238   if(FAILED(AVIMakeCompressedStream(&mypAviCompressedStream,
239                                     mypAviStream,
240                                     &myAviCompressOptions,
241                                     NULL)))
242   {
243     // One reason this error might occur is if you are using a Codec that is not
244     // available on your system. Check the mmioFOURCC() code you are using and
245     // make sure you have that codec installed properly on your machine.
246     SetErrorMessage("Unable to Create Compressed Stream: "
247                     "Check your CODEC options");
248     return E_FAIL;
249   }
250
251   BITMAPINFO bmpInfo;
252   ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
253   bmpInfo.bmiHeader.biPlanes            = 1;
254   bmpInfo.bmiHeader.biWidth             = nFrameWidth;
255   bmpInfo.bmiHeader.biHeight            = nFrameHeight;
256   bmpInfo.bmiHeader.biCompression       = BI_RGB;
257   bmpInfo.bmiHeader.biBitCount          = nBitsPerPixel;
258   bmpInfo.bmiHeader.biSize              = sizeof(BITMAPINFOHEADER);
259   bmpInfo.bmiHeader.biSizeImage         = (bmpInfo.bmiHeader.biWidth *
260                                            bmpInfo.bmiHeader.biHeight*
261                                            bmpInfo.bmiHeader.biBitCount)/8;
262
263   if(FAILED(AVIStreamSetFormat(mypAviCompressedStream,
264                                0,
265                                (LPVOID)&bmpInfo,
266                                bmpInfo.bmiHeader.biSize)))
267   {
268     // One reason this error might occur is if your bitmap does not meet
269     // the Codec requirements.
270     // For example, 
271     //   your bitmap is 32bpp while the Codec supports only 16 or 24 bpp; Or
272     //   your bitmap is 274 * 258 size, while the Codec supports only sizes
273     //   that are powers of 2; etc...
274     // Possible solution to avoid this is: make your bitmap suit the codec
275     // requirements, or Choose a codec that is suitable for your bitmap.
276     SetErrorMessage("Unable to Set Video Stream Format");
277     return E_FAIL;
278   }
279
280   return S_OK;  // Everything went Fine
281 }
282
283 //=======================================================================
284 //function : AppendFrameFirstTime
285 //purpose  : 
286 //=======================================================================
287
288 HRESULT OpenGl_AVIWriter::AppendFrameFirstTime(HBITMAP  hBitmap)
289 {
290   BITMAP Bitmap;
291   GetObject(hBitmap, sizeof(BITMAP), &Bitmap);
292
293   if(SUCCEEDED(InitMovieCreation( Bitmap.bmWidth, 
294                                   Bitmap.bmHeight, 
295                                   Bitmap.bmBitsPixel)))
296   {
297     myAppendFuncSelector = 2;      //Point to the UsualAppend Function
298     return AppendFrameUsual(hBitmap);
299   }
300
301   ReleaseMemory();
302   return E_FAIL;
303 }
304
305 //=======================================================================
306 //function : AppendFrameUsual
307 //purpose  : 
308 //=======================================================================
309
310 HRESULT OpenGl_AVIWriter::AppendFrameUsual(HBITMAP hBitmap)
311 {
312   BITMAPINFO    bmpInfo;
313
314   bmpInfo.bmiHeader.biBitCount=0;
315   bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
316
317   GetDIBits(myhAviDC,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS);
318
319   bmpInfo.bmiHeader.biCompression=BI_RGB;
320
321   GetDIBits(myhAviDC,
322             hBitmap,
323             0,
324             bmpInfo.bmiHeader.biHeight,
325             mylpBits,
326             &bmpInfo,
327             DIB_RGB_COLORS);
328
329   if(FAILED(AVIStreamWrite(mypAviCompressedStream,
330                            mylSample++,
331                            1,
332                            mylpBits,
333                            bmpInfo.bmiHeader.biSizeImage,
334                            0,
335                            NULL,
336                            NULL)))
337   {
338     SetErrorMessage("Unable to Write Video Stream to the output Movie File");
339     ReleaseMemory();
340     return E_FAIL;
341   }
342
343   return S_OK;
344 }
345
346 //=======================================================================
347 //function : AppendDummy
348 //purpose  : 
349 //=======================================================================
350
351 HRESULT OpenGl_AVIWriter::AppendDummy(HBITMAP)
352 {
353   return E_FAIL;
354 }
355
356 //=======================================================================
357 //function : AppendNewFrame
358 //purpose  : 
359 //=======================================================================
360
361 HRESULT OpenGl_AVIWriter::AppendNewFrame(HBITMAP hBitmap)
362 {
363   return (this->*pAppendFrame[myAppendFuncSelector])((HBITMAP)hBitmap);
364 }
365
366 //=======================================================================
367 //function : AppendNewFrame
368 //purpose  : 
369 //=======================================================================
370
371 HRESULT OpenGl_AVIWriter::AppendNewFrame(int nWidth,
372                                          int nHeight,
373                                          LPVOID pBits,
374                                          int nBitsPerPixel)
375 {
376   return (this->*pAppendFrameBits[myAppendFuncSelector])(nWidth,
377                                                           nHeight,
378                                                           pBits,
379                                                           nBitsPerPixel);
380 }
381
382 //=======================================================================
383 //function : AppendFrameFirstTime
384 //purpose  : 
385 //=======================================================================
386
387 HRESULT OpenGl_AVIWriter::AppendFrameBitsFirstTime(int nWidth,
388                                                    int nHeight,
389                                                    LPVOID pBits,
390                                                    int nBitsPerPixel)
391 {
392   if(SUCCEEDED(InitMovieCreation(nWidth, nHeight, nBitsPerPixel)))
393   {
394     myAppendFuncSelector=2;    //Point to the UsualAppend Function
395     return AppendFrameBitsUsual(nWidth, nHeight, pBits, nBitsPerPixel);
396   }
397   ReleaseMemory();
398
399   return E_FAIL;
400 }
401
402 //=======================================================================
403 //function : AppendFrameUsual
404 //purpose  : 
405 //=======================================================================
406
407 HRESULT OpenGl_AVIWriter::AppendFrameBitsUsual(int nWidth,
408                                                int nHeight,
409                                                LPVOID pBits,
410                                                int nBitsPerPixel)
411 {
412   DWORD dwSize=nWidth*nHeight*nBitsPerPixel/8;
413
414   if(FAILED(AVIStreamWrite(mypAviCompressedStream,
415                            mylSample++,
416                            1,
417                            pBits,
418                            dwSize,
419                            0,
420                            NULL,
421                            NULL)))
422   {
423     SetErrorMessage("Unable to Write Video Stream to the output Movie File");
424     ReleaseMemory();
425     return E_FAIL;
426   }
427
428   return S_OK;
429 }
430
431 //=======================================================================
432 //function : AppendDummy
433 //purpose  : 
434 //=======================================================================
435
436 HRESULT OpenGl_AVIWriter::AppendDummyBits(int nWidth,
437                                           int nHeight,
438                                           LPVOID pBits,
439                                           int nBitsPerPixel)
440 {
441   return E_FAIL;
442 }
443
444 //=======================================================================
445 //function : AviWriter
446 //purpose  : 
447 //=======================================================================
448
449 void OpenGl_AVIWriter_AVIWriter(void * pp,
450                                 int  nWidth,
451                                 int  nHeight,
452                                 int  nBitsPerPixel)
453 {
454   if (OpenGl_AVIWriter::GetInstance() != 0L)
455     if (OpenGl_AVIWriter::GetInstance()->IsRecording())
456     {
457
458       OpenGl_AVIWriter::GetInstance()->AppendNewFrame(nWidth,
459                                                       nHeight,
460                                                       pp,
461                                                       nBitsPerPixel);
462     }
463 }
464
465 //=======================================================================
466 //function : AllowWriting
467 //purpose  : 
468 //=======================================================================
469
470 Standard_Boolean OpenGl_AVIWriter_AllowWriting(void * hWin)
471 {
472   Standard_Boolean aResult(Standard_False);
473   const OpenGl_AVIWriter * anInst = OpenGl_AVIWriter::GetInstance();
474   if (anInst != 0L) {
475     if (hWin == NULL || anInst->HWindow() == hWin)
476       aResult = static_cast<Standard_Boolean> (anInst->IsRecording());
477   }
478   return aResult;
479 }
480
481 #endif