Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkMovieGeneratorWin32.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
18 #include <GL/gl.h>
19 
21 {
22 }
23 
24 void mitk::MovieGeneratorWin32::SetFileName(const char *fileName)
25 {
26  m_sFile = _T(fileName);
27  if (_tcsstr((char *)m_sFile, _T("avi")) == NULL)
28  m_sFile += _T( ".avi" );
29 }
30 
32 {
33  m_width = m_renderer->GetRenderWindow()->GetSize()[0]; // changed from glGetIntegerv( GL_VIEWPORT, viewport );
34  m_height = m_renderer->GetRenderWindow()->GetSize()[1]; // due to sometimes strange dimensions
35 
36  m_width -= 10; // remove colored boarders around renderwindows
37  m_height -= 10;
38 
39  m_width -= m_width % 4; // some video codecs have prerequisites to the image dimensions
40  m_height -= m_height % 4;
41 
42  BITMAPINFOHEADER bih;
43  bih.biSize = sizeof(BITMAPINFOHEADER);
44  bih.biWidth = m_width;
45  bih.biHeight = m_height;
46  bih.biPlanes = 1;
47  int imgSize = 3 /* BRG*/ * bih.biWidth * bih.biHeight;
48  bih.biBitCount = 24;
49  bih.biCompression = BI_RGB;
50  bih.biSizeImage = imgSize;
51  bih.biClrUsed = 0;
52  bih.biClrImportant = 0;
53 
54  // ASSERT(bih.biWidth%4==0);
55  // ASSERT(bih.biHeight%4==0);
56 
57  // copying bitmap info structure.
58  memcpy(&m_bih, &bih, sizeof(BITMAPINFOHEADER));
59 }
60 
62 {
63  InitBitmapHeader();
64 
65  AVISTREAMINFO strHdr; // information for a single stream
66  AVICOMPRESSOPTIONS opts;
67  AVICOMPRESSOPTIONS FAR *aopts[1] = {&opts};
68 
69  TCHAR szBuffer[1024];
70  HRESULT hr;
71 
72  m_sError = _T("Ok");
73 
74  // Step 0 : Let's make sure we are running on 1.1
75  DWORD wVer = HIWORD(VideoForWindowsVersion());
76  if (wVer < 0x010a)
77  {
78  // oops, we are too old, blow out of here
79  m_sError = _T("Version of Video for Windows too old. Come on, join the 21th century!");
80  return false;
81  }
82 
83  // Step 1 : initialize AVI engine
84  AVIFileInit();
85 
86  // Step 2 : Open the movie file for writing....
87  hr = AVIFileOpen(&m_pAVIFile, // Address to contain the new file interface pointer
88  (LPCTSTR)m_sFile, // Null-terminated string containing the name of the file to open
89  OF_WRITE | OF_CREATE, // Access mode to use when opening the file.
90  NULL); // use handler determined from file extension.
91  // Name your file .avi -> very important
92 
93  if (hr != AVIERR_OK)
94  {
95  _tprintf(szBuffer, _T("AVI Engine failed to initialize. Check filename %s."), m_sFile);
96  m_sError = szBuffer;
97  // Check it succeded.
98  switch (hr)
99  {
100  case AVIERR_BADFORMAT:
101  m_sError += _T("The file couldn't be read, indicating a corrupt file or an unrecognized format.");
102  break;
103  case AVIERR_MEMORY:
104  m_sError += _T("The file could not be opened because of insufficient memory.");
105  break;
106  case AVIERR_FILEREAD:
107  m_sError += _T("A disk error occurred while reading the file.");
108  break;
109  case AVIERR_FILEOPEN:
110  m_sError += _T("A disk error occurred while opening the file.");
111  break;
112  case REGDB_E_CLASSNOTREG:
113  m_sError += _T("According to the registry, the type of file specified in AVIFileOpen does not have a handler ")
114  _T("to process it");
115  break;
116  }
117 
118  return false;
119  }
120 
121  // Fill in the header for the video stream....
122  memset(&strHdr, 0, sizeof(strHdr));
123  strHdr.fccType = streamtypeVIDEO; // video stream type
124  strHdr.fccHandler = 0;
125  strHdr.dwScale = 1; // should be one for video
126  strHdr.dwRate = static_cast<DWORD>(m_FrameRate); // fps
127  strHdr.dwSuggestedBufferSize = m_bih.biSizeImage; // Recommended buffer size, in bytes, for the stream.
128  SetRect(&strHdr.rcFrame,
129  0,
130  0, // rectangle for stream
131  (int)m_bih.biWidth,
132  (int)m_bih.biHeight);
133 
134  // Step 3 : Create the stream;
135  hr = AVIFileCreateStream(m_pAVIFile, // file pointer
136  &m_pStream, // returned stream pointer
137  &strHdr); // stream header
138 
139  // Check it succeded.
140  if (hr != AVIERR_OK)
141  {
142  m_sError = _T("AVI Stream creation failed. Check Bitmap info.");
143  if (hr == AVIERR_READONLY)
144  {
145  m_sError += _T(" Read only file.");
146  }
147  return false;
148  }
149 
150  // Step 4: Get codec and infos about codec
151  memset(&opts, 0, sizeof(opts));
152 
153  // predefine MS-CRAM as standard codec
154  opts.fccType = streamtypeVIDEO;
155  // creates a video with minor quality! Use different codec (must be installed on local machine) to generate movies
156  // with higher quality
157  opts.fccHandler = mmioFOURCC('M', 'S', 'V', 'C');
158  opts.dwQuality = 90000; // means 90% quality; dwQuality goes from [0...10000]
159 
160 // Poping codec dialog
161 // GUI Codec selection does not work in a vs 2005 compiled mitk, since we do not pass a hwnd as first parameter
162 // of AVISaveOptions
163 #if !(_MSC_VER >= 1400)
164 
165  if (!AVISaveOptions(NULL, 0, 1, &m_pStream, (LPAVICOMPRESSOPTIONS FAR *)&aopts))
166  {
167  AVISaveOptionsFree(1, (LPAVICOMPRESSOPTIONS FAR *)&aopts);
168  // return false;
169  }
170 
171 #endif
172 
173  // Step 5: Create a compressed stream using codec options.
174  hr = AVIMakeCompressedStream(&m_pStreamCompressed, m_pStream, &opts, NULL);
175 
176  if (hr != AVIERR_OK)
177  {
178  m_sError = _T("AVI Compressed Stream creation failed.");
179 
180  switch (hr)
181  {
182  case AVIERR_NOCOMPRESSOR:
183  m_sError += _T(" A suitable compressor cannot be found.");
184  break;
185  case AVIERR_MEMORY:
186  m_sError += _T(" There is not enough memory to complete the operation.");
187  break;
188  case AVIERR_UNSUPPORTED:
189  m_sError += _T("Compression is not supported for this type of data. This error might be returned if you try ")
190  _T("to compress data that is not audio or video.");
191  break;
192  }
193 
194  return false;
195  }
196 
197  // releasing memory allocated by AVISaveOptionFree
198  hr = AVISaveOptionsFree(1, (LPAVICOMPRESSOPTIONS FAR *)&aopts);
199  if (hr != AVIERR_OK)
200  {
201  m_sError = _T("Error releasing memory");
202  return false;
203  }
204 
205  // Step 6 : sets the format of a stream at the specified position
206  hr = AVIStreamSetFormat(m_pStreamCompressed,
207  0, // position
208  &m_bih, // stream format
209  m_bih.biSize + // format size
210  m_bih.biClrUsed * sizeof(RGBQUAD));
211 
212  if (hr != AVIERR_OK)
213  {
214  m_sError = _T("AVI Compressed Stream format setting failed.");
215  return false;
216  }
217 
218  // Step 6 : Initialize step counter
219  m_lFrame = 0;
220 
221  return true;
222 }
223 
225 {
226  HRESULT hr = AVIStreamWrite(m_pStreamCompressed, // stream pointer
227  m_lFrame, // time of this frame
228  1, // number to write
229  (BYTE *)data, // image buffer
230  m_bih.biSizeImage, // size of this frame
231  AVIIF_KEYFRAME, // flags....
232  NULL,
233  NULL);
234  // updating frame counter
235  m_lFrame++;
236 
237  if (hr == AVIERR_OK)
238  return true;
239  else
240  return false;
241 }
242 
244 {
245  if (m_pStream)
246  {
247  AVIStreamRelease(m_pStream);
248  m_pStream = NULL;
249  }
250  if (m_pStreamCompressed)
251  {
252  AVIStreamRelease(m_pStreamCompressed);
253  m_pStreamCompressed = NULL;
254  }
255  if (m_pAVIFile)
256  {
257  AVIFileRelease(m_pAVIFile);
258  m_pAVIFile = NULL;
259  }
260  // Close engine
261  AVIFileExit();
262  return true;
263 }
virtual void SetFileName(const char *fileName)
filename under which movie is saved
virtual bool TerminateGenerator()
called after the last frame is added
void InitBitmapHeader()
reads out size of current OpenGL context and stores it
virtual bool AddFrame(void *data)
used to add a frame
virtual bool InitGenerator()
called directly before the first frame is added