aviwriter.h 7.3 KB

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