aviwriter.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * Copyright 2011-2013 Branimir Karadzic. All rights reserved.
  3. * License: http://www.opensource.org/licenses/BSD-2-Clause
  4. */
  5. #ifndef __AVIWRITER_H__
  6. #define __AVIWRITER_H__
  7. #include <bx/readerwriter.h>
  8. // Simple AVI writer. VideoLAN and VirtualDub can decode it.
  9. // Needs some bits to get jiggled to work with other players. But it's good
  10. // enough for an example.
  11. struct AviWriter
  12. {
  13. AviWriter()
  14. : m_frame(NULL)
  15. , m_frameSize(0)
  16. , m_numFrames(0)
  17. , m_width(0)
  18. , m_height(0)
  19. , m_yflip(false)
  20. {
  21. }
  22. bool open(const char* _filePath, uint32_t _width, uint32_t _height, uint32_t _fps, bool _yflip)
  23. {
  24. if (0 != m_writer.open(_filePath) )
  25. {
  26. return false;
  27. }
  28. m_frameSize = _width * _height * 3;
  29. m_frame = new uint8_t[m_frameSize + 8];
  30. m_numFrames = 0;
  31. m_width = _width;
  32. m_height = _height;
  33. // Bgfx returns _yflip true for OpenGL since bottom left corner is 0, 0. In D3D top left corner
  34. // is 0, 0. DIB expect OpenGL style coordinates, so this is inverted logic for AVI writer.
  35. m_yflip = !_yflip;
  36. bx::StaticMemoryBlockWriter mem(m_frame, 8);
  37. // Stream Data (LIST 'movi' Chunk) http://msdn.microsoft.com/en-us/library/ms899496.aspx
  38. bx::write(&mem, BX_MAKEFOURCC('0', '0', 'd', 'b') );
  39. bx::write(&mem, m_frameSize);
  40. bx::write(&m_writer, BX_MAKEFOURCC('R', 'I', 'F', 'F') );
  41. m_riffSizeOffset = m_writer.seek();
  42. bx::write(&m_writer, UINT32_C(0) );
  43. bx::write(&m_writer, BX_MAKEFOURCC('A', 'V', 'I', ' ') );
  44. // AVI RIFF Form http://msdn.microsoft.com/en-us/library/ms899422.aspx
  45. bx::write(&m_writer, BX_MAKEFOURCC('L', 'I', 'S', 'T') );
  46. bx::write(&m_writer, UINT32_C(192) );
  47. bx::write(&m_writer, BX_MAKEFOURCC('h', 'd', 'r', 'l') );
  48. // AVI Main Header http://msdn.microsoft.com/en-us/library/ms779632.aspx
  49. bx::write(&m_writer, BX_MAKEFOURCC('a', 'v', 'i', 'h') );
  50. bx::write(&m_writer, UINT32_C(56) );
  51. bx::write(&m_writer, UINT32_C(0) ); // dwMicroSecPerFrame
  52. bx::write(&m_writer, UINT32_C(0) ); // dwMaxBytesPerSec
  53. bx::write(&m_writer, UINT32_C(0) ); // dwPaddingGranularity
  54. bx::write(&m_writer, UINT32_C(0x101) ); // dwFlags
  55. m_totalFramesOffset = m_writer.seek();
  56. bx::write(&m_writer, UINT32_C(0) ); // dwTotalFrames
  57. bx::write(&m_writer, UINT32_C(0) ); // dwInitialFrames
  58. bx::write(&m_writer, UINT32_C(1) ); // dwStreams
  59. bx::write(&m_writer, UINT32_C(0) ); // dwSuggestedBufferSize
  60. bx::write(&m_writer, _width); // dwWidth
  61. bx::write(&m_writer, _height); // dwHeight
  62. bx::write(&m_writer, UINT32_C(0) ); // dwReserved0
  63. bx::write(&m_writer, UINT32_C(0) ); // dwReserved1
  64. bx::write(&m_writer, UINT32_C(0) ); // dwReserved2
  65. bx::write(&m_writer, UINT32_C(0) ); // dwReserved3
  66. bx::write(&m_writer, BX_MAKEFOURCC('L', 'I', 'S', 'T') );
  67. bx::write(&m_writer, UINT32_C(116) );
  68. bx::write(&m_writer, BX_MAKEFOURCC('s', 't', 'r', 'l') );
  69. // AVISTREAMHEADER Structure http://msdn.microsoft.com/en-us/library/ms779638.aspx
  70. bx::write(&m_writer, BX_MAKEFOURCC('s', 't', 'r', 'h') );
  71. bx::write(&m_writer, UINT32_C(56) );
  72. // AVI Stream Headers http://msdn.microsoft.com/en-us/library/ms899423.aspx
  73. bx::write(&m_writer, BX_MAKEFOURCC('v', 'i', 'd', 's') ); // fccType
  74. bx::write(&m_writer, BX_MAKEFOURCC('D', 'I', 'B', ' ') ); // fccHandler
  75. bx::write(&m_writer, UINT32_C(0) ); // dwFlags
  76. bx::write(&m_writer, UINT16_C(0) ); // wPriority
  77. bx::write(&m_writer, UINT16_C(0) ); // wLanguage
  78. bx::write(&m_writer, UINT32_C(0) ); // dwInitialFrames
  79. bx::write(&m_writer, UINT32_C(1) ); // dwScale
  80. bx::write(&m_writer, _fps); // dwRate
  81. bx::write(&m_writer, UINT32_C(0) ); // dwStart
  82. m_lengthOffset = m_writer.seek();
  83. bx::write(&m_writer, UINT32_C(0) ); // dwLength
  84. bx::write(&m_writer, m_frameSize); // dwSuggestedBufferSize
  85. bx::write(&m_writer, UINT32_MAX); // dwQuality
  86. bx::write(&m_writer, UINT32_C(0) ); // dwSampleSize
  87. bx::write(&m_writer, INT16_C(0) ); // rcFrame.left
  88. bx::write(&m_writer, INT16_C(0) ); // rcFrame.top
  89. bx::write(&m_writer, uint16_t(_width) ); // rcFrame.right
  90. bx::write(&m_writer, uint16_t(_height) );// rcFrame.bottom
  91. bx::write(&m_writer, BX_MAKEFOURCC('s', 't', 'r', 'f') );
  92. bx::write(&m_writer, UINT32_C(40) );
  93. // BITMAPINFOHEADER structure http://msdn.microsoft.com/en-us/library/windows/desktop/dd318229%28v=vs.85%29.aspx
  94. bx::write(&m_writer, UINT32_C(40) ); // biSize
  95. bx::write(&m_writer, _width); // biWidth
  96. bx::write(&m_writer, _height); // biHeight
  97. bx::write(&m_writer, UINT16_C(1) ); // biPlanes
  98. bx::write(&m_writer, UINT16_C(24) ); // biBitCount
  99. bx::write(&m_writer, UINT32_C(0) ); // biCompression
  100. bx::write(&m_writer, m_frameSize); // biSizeImage
  101. bx::write(&m_writer, UINT32_C(0) ); // biXPelsPerMeter
  102. bx::write(&m_writer, UINT32_C(0) ); // biYPelsPerMeter
  103. bx::write(&m_writer, UINT32_C(0) ); // biClrUsed
  104. bx::write(&m_writer, UINT32_C(0) ); // biClrImportant
  105. bx::write(&m_writer, BX_MAKEFOURCC('L', 'I', 'S', 'T') );
  106. m_moviListOffset = m_writer.seek();
  107. bx::write(&m_writer, UINT32_C(0) );
  108. bx::write(&m_writer, BX_MAKEFOURCC('m', 'o', 'v', 'i') );
  109. return true;
  110. }
  111. void close()
  112. {
  113. if (NULL != m_frame)
  114. {
  115. int64_t pos = m_writer.seek();
  116. m_writer.seek(m_moviListOffset, bx::Whence::Begin);
  117. bx::write(&m_writer, uint32_t(pos-m_moviListOffset-4) );
  118. m_writer.seek(pos, bx::Whence::Begin);
  119. bx::write(&m_writer, BX_MAKEFOURCC('i', 'd', 'x', '1') );
  120. bx::write(&m_writer, m_numFrames*16);
  121. for (uint32_t ii = 0, offset = 4; ii < m_numFrames; ++ii)
  122. {
  123. bx::write(&m_writer, BX_MAKEFOURCC('0', '0', 'd', 'b') );
  124. bx::write(&m_writer, UINT32_C(16) );
  125. bx::write(&m_writer, offset);
  126. bx::write(&m_writer, m_frameSize);
  127. offset += m_frameSize + 8;
  128. }
  129. pos = m_writer.seek();
  130. m_writer.seek(m_riffSizeOffset, bx::Whence::Begin);
  131. bx::write(&m_writer, uint32_t(pos-m_riffSizeOffset-4) );
  132. m_writer.seek(m_totalFramesOffset, bx::Whence::Begin);
  133. bx::write(&m_writer, m_numFrames);
  134. m_writer.seek(m_lengthOffset, bx::Whence::Begin);
  135. bx::write(&m_writer, m_numFrames);
  136. m_writer.close();
  137. delete [] m_frame;
  138. m_frame = NULL;
  139. m_frameSize = 0;
  140. }
  141. }
  142. void frame(const void* _data)
  143. {
  144. if (NULL != m_frame)
  145. {
  146. ++m_numFrames;
  147. uint32_t width = m_width;
  148. uint32_t height = m_height;
  149. uint8_t* bgr = &m_frame[8];
  150. if (m_yflip)
  151. {
  152. for (uint32_t yy = 0; yy < height; ++yy)
  153. {
  154. const uint8_t* bgra = (const uint8_t*)_data + (height-1-yy)*width*4;
  155. for (uint32_t ii = 0; ii < width; ++ii)
  156. {
  157. bgr[0] = bgra[0];
  158. bgr[1] = bgra[1];
  159. bgr[2] = bgra[2];
  160. bgr += 3;
  161. bgra += 4;
  162. }
  163. }
  164. }
  165. else
  166. {
  167. const uint8_t* bgra = (const uint8_t*)_data;
  168. for (uint32_t ii = 0, num = m_frameSize/3; ii < num; ++ii)
  169. {
  170. bgr[0] = bgra[0];
  171. bgr[1] = bgra[1];
  172. bgr[2] = bgra[2];
  173. bgr += 3;
  174. bgra += 4;
  175. }
  176. }
  177. bx::write(&m_writer, m_frame, m_frameSize+8);
  178. }
  179. }
  180. bx::CrtFileWriter m_writer;
  181. int64_t m_riffSizeOffset;
  182. int64_t m_totalFramesOffset;
  183. int64_t m_lengthOffset;
  184. int64_t m_moviListOffset;
  185. uint8_t* m_frame;
  186. uint32_t m_frameSize;
  187. uint32_t m_numFrames;
  188. uint32_t m_width;
  189. uint32_t m_height;
  190. bool m_yflip;
  191. };
  192. #endif // __AVIWRITER_H__