diff --git a/examples/07-callback/callback.cpp b/examples/07-callback/callback.cpp index 8bba8353..fd793a0e 100644 --- a/examples/07-callback/callback.cpp +++ b/examples/07-callback/callback.cpp @@ -10,6 +10,7 @@ #include #include "../common/dbg.h" #include "../common/math.h" +#include "../common/aviwriter.h" #include #include @@ -146,181 +147,6 @@ void saveTga(const char* _filePath, uint32_t _width, uint32_t _height, uint32_t } } -// Simple AVI writer. VideoLAN and VirtualDub can decode it. -// Needs some bits to get jiggled to work with other players. But it's good -// enough for an example. -struct AviWriter -{ - AviWriter() - : m_frame(NULL) - , m_frameSize(0) - , m_width(0) - , m_height(0) - , m_yflip(false) - { - } - - bool open(const char* _filePath, uint32_t _width, uint32_t _height, uint32_t _fps, bool _yflip) - { - if (0 != m_writer.open(_filePath) ) - { - return false; - } - - m_frameSize = _width * _height * 3; - m_frame = new uint8_t[m_frameSize + 8]; - m_width = _width; - m_height = _height; - - // Bgfx returns _yflip true for OpenGL since bottom left corner is 0, 0. In D3D top left corner - // is 0, 0. DIB expect OpenGL style coordinates, so this is inverted logic for AVI writer. - m_yflip = !_yflip; - - bx::StaticMemoryBlockWriter mem(m_frame, 8); - // Stream Data (LIST 'movi' Chunk) http://msdn.microsoft.com/en-us/library/ms899496.aspx - bx::write(&mem, BX_MAKEFOURCC('0', '0', 'd', 'b') ); - bx::write(&mem, m_frameSize); - - bx::write(&m_writer, BX_MAKEFOURCC('R', 'I', 'F', 'F') ); - bx::write(&m_writer, UINT32_C(0) ); - - bx::write(&m_writer, BX_MAKEFOURCC('A', 'V', 'I', ' ') ); - - // AVI RIFF Form http://msdn.microsoft.com/en-us/library/ms899422.aspx - bx::write(&m_writer, BX_MAKEFOURCC('L', 'I', 'S', 'T') ); - bx::write(&m_writer, UINT32_C(196) ); - bx::write(&m_writer, BX_MAKEFOURCC('h', 'd', 'r', 'l') ); - - // AVI Main Header http://msdn.microsoft.com/en-us/library/ms779632.aspx - bx::write(&m_writer, BX_MAKEFOURCC('a', 'v', 'i', 'h') ); - bx::write(&m_writer, UINT32_C(56) ); - bx::write(&m_writer, UINT32_C(0) ); // dwMicroSecPerFrame - bx::write(&m_writer, UINT32_C(0) ); // dwMaxBytesPerSec - bx::write(&m_writer, UINT32_C(0) ); // dwPaddingGranularity - bx::write(&m_writer, UINT32_C(0) ); // dwFlags - bx::write(&m_writer, UINT32_C(0) ); // dwTotalFrames - bx::write(&m_writer, UINT32_C(0) ); // dwInitialFrames - bx::write(&m_writer, UINT32_C(1) ); // dwStreams - bx::write(&m_writer, UINT32_C(0) ); // dwSuggestedBufferSize - bx::write(&m_writer, _width); // dwWidth - bx::write(&m_writer, _height); // dwHeight - bx::write(&m_writer, UINT32_C(0) ); // dwReserved0 - bx::write(&m_writer, UINT32_C(0) ); // dwReserved1 - bx::write(&m_writer, UINT32_C(0) ); // dwReserved2 - bx::write(&m_writer, UINT32_C(0) ); // dwReserved3 - - bx::write(&m_writer, BX_MAKEFOURCC('L', 'I', 'S', 'T') ); - bx::write(&m_writer, UINT32_C(120) ); - bx::write(&m_writer, BX_MAKEFOURCC('s', 't', 'r', 'l') ); - - // AVISTREAMHEADER Structure http://msdn.microsoft.com/en-us/library/ms779638.aspx - bx::write(&m_writer, BX_MAKEFOURCC('s', 't', 'r', 'h') ); - bx::write(&m_writer, UINT32_C(56) ); - // AVI Stream Headers http://msdn.microsoft.com/en-us/library/ms899423.aspx - bx::write(&m_writer, BX_MAKEFOURCC('v', 'i', 'd', 's') ); // fccType - bx::write(&m_writer, BX_MAKEFOURCC('D', 'I', 'B', ' ') ); // fccHandler - bx::write(&m_writer, UINT32_C(0) ); // dwFlags - bx::write(&m_writer, UINT16_C(0) ); // wPriority - bx::write(&m_writer, UINT16_C(0) ); // wLanguage - bx::write(&m_writer, UINT32_C(0) ); // dwInitialFrames - bx::write(&m_writer, UINT32_C(1000) ); // dwScale - bx::write(&m_writer, 1000*_fps); // dwRate - bx::write(&m_writer, UINT32_C(0) ); // dwStart - bx::write(&m_writer, UINT32_C(0) ); // dwLength - bx::write(&m_writer, UINT32_C(0) ); // dwSuggestedBufferSize - bx::write(&m_writer, UINT32_C(0) ); // dwQuality - bx::write(&m_writer, UINT32_C(0) ); // dwSampleSize - bx::write(&m_writer, INT16_C(0) ); // rcFrame.left - bx::write(&m_writer, INT16_C(0) ); // rcFrame.top - bx::write(&m_writer, INT16_C(0) ); // rcFrame.right - bx::write(&m_writer, INT16_C(0) ); // rcFrame.bottom - - bx::write(&m_writer, BX_MAKEFOURCC('s', 't', 'r', 'f') ); - bx::write(&m_writer, UINT32_C(44) ); - - // BITMAPINFOHEADER structure http://msdn.microsoft.com/en-us/library/windows/desktop/dd318229%28v=vs.85%29.aspx - bx::write(&m_writer, UINT32_C(40) ); // biSize - bx::write(&m_writer, _width); // biWidth - bx::write(&m_writer, _height); // biHeight - bx::write(&m_writer, UINT16_C(1) ); // biPlanes - bx::write(&m_writer, UINT16_C(24) ); // biBitCount - bx::write(&m_writer, UINT32_C(0) ); // biCompression - bx::write(&m_writer, UINT32_C(0) ); // biSizeImage - bx::write(&m_writer, UINT32_C(0) ); // biXPelsPerMeter - bx::write(&m_writer, UINT32_C(0) ); // biYPelsPerMeter - bx::write(&m_writer, UINT32_C(0) ); // biClrUsed - bx::write(&m_writer, UINT32_C(0) ); // biClrImportant - bx::write(&m_writer, UINT32_C(0) ); - - bx::write(&m_writer, BX_MAKEFOURCC('L', 'I', 'S', 'T') ); - bx::write(&m_writer, UINT32_C(0) ); - bx::write(&m_writer, BX_MAKEFOURCC('m', 'o', 'v', 'i') ); - - return true; - } - - void close() - { - if (NULL != m_frame) - { - m_writer.close(); - - delete [] m_frame; - m_frame = NULL; - m_frameSize = 0; - } - } - - void frame(const void* _data) - { - if (NULL != m_frame) - { - uint32_t width = m_width; - uint32_t height = m_height; - - uint8_t* bgr = &m_frame[8]; - - if (m_yflip) - { - for (uint32_t yy = 0; yy < height; ++yy) - { - const uint8_t* bgra = (const uint8_t*)_data + (height-1-yy)*width*4; - - for (uint32_t ii = 0; ii < width; ++ii) - { - bgr[0] = bgra[0]; - bgr[1] = bgra[1]; - bgr[2] = bgra[2]; - bgr += 3; - bgra += 4; - } - } - } - else - { - const uint8_t* bgra = (const uint8_t*)_data; - for (uint32_t ii = 0, num = m_frameSize/3; ii < num; ++ii) - { - bgr[0] = bgra[0]; - bgr[1] = bgra[1]; - bgr[2] = bgra[2]; - bgr += 3; - bgra += 4; - } - } - - bx::write(&m_writer, m_frame, m_frameSize+8); - } - } - - bx::CrtFileWriter m_writer; - uint8_t* m_frame; - uint32_t m_frameSize; - uint32_t m_width; - uint32_t m_height; - bool m_yflip; -}; - struct BgfxCallback : public bgfx::CallbackI { virtual ~BgfxCallback() diff --git a/examples/common/aviwriter.h b/examples/common/aviwriter.h new file mode 100644 index 00000000..a19d8af2 --- /dev/null +++ b/examples/common/aviwriter.h @@ -0,0 +1,186 @@ +/* + * Copyright 2011-2012 Branimir Karadzic. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#ifndef __AVIWRITER_H__ +#define __AVIWRITER_H__ + +#include + +// Simple AVI writer. VideoLAN and VirtualDub can decode it. +// Needs some bits to get jiggled to work with other players. But it's good +// enough for an example. +struct AviWriter +{ + AviWriter() + : m_frame(NULL) + , m_frameSize(0) + , m_width(0) + , m_height(0) + , m_yflip(false) + { + } + + bool open(const char* _filePath, uint32_t _width, uint32_t _height, uint32_t _fps, bool _yflip) + { + if (0 != m_writer.open(_filePath) ) + { + return false; + } + + m_frameSize = _width * _height * 3; + m_frame = new uint8_t[m_frameSize + 8]; + m_width = _width; + m_height = _height; + + // Bgfx returns _yflip true for OpenGL since bottom left corner is 0, 0. In D3D top left corner + // is 0, 0. DIB expect OpenGL style coordinates, so this is inverted logic for AVI writer. + m_yflip = !_yflip; + + bx::StaticMemoryBlockWriter mem(m_frame, 8); + // Stream Data (LIST 'movi' Chunk) http://msdn.microsoft.com/en-us/library/ms899496.aspx + bx::write(&mem, BX_MAKEFOURCC('0', '0', 'd', 'b') ); + bx::write(&mem, m_frameSize); + + bx::write(&m_writer, BX_MAKEFOURCC('R', 'I', 'F', 'F') ); + bx::write(&m_writer, UINT32_C(0) ); + + bx::write(&m_writer, BX_MAKEFOURCC('A', 'V', 'I', ' ') ); + + // AVI RIFF Form http://msdn.microsoft.com/en-us/library/ms899422.aspx + bx::write(&m_writer, BX_MAKEFOURCC('L', 'I', 'S', 'T') ); + bx::write(&m_writer, UINT32_C(196) ); + bx::write(&m_writer, BX_MAKEFOURCC('h', 'd', 'r', 'l') ); + + // AVI Main Header http://msdn.microsoft.com/en-us/library/ms779632.aspx + bx::write(&m_writer, BX_MAKEFOURCC('a', 'v', 'i', 'h') ); + bx::write(&m_writer, UINT32_C(56) ); + bx::write(&m_writer, UINT32_C(0) ); // dwMicroSecPerFrame + bx::write(&m_writer, UINT32_C(0) ); // dwMaxBytesPerSec + bx::write(&m_writer, UINT32_C(0) ); // dwPaddingGranularity + bx::write(&m_writer, UINT32_C(0) ); // dwFlags + bx::write(&m_writer, UINT32_C(0) ); // dwTotalFrames + bx::write(&m_writer, UINT32_C(0) ); // dwInitialFrames + bx::write(&m_writer, UINT32_C(1) ); // dwStreams + bx::write(&m_writer, UINT32_C(0) ); // dwSuggestedBufferSize + bx::write(&m_writer, _width); // dwWidth + bx::write(&m_writer, _height); // dwHeight + bx::write(&m_writer, UINT32_C(0) ); // dwReserved0 + bx::write(&m_writer, UINT32_C(0) ); // dwReserved1 + bx::write(&m_writer, UINT32_C(0) ); // dwReserved2 + bx::write(&m_writer, UINT32_C(0) ); // dwReserved3 + + bx::write(&m_writer, BX_MAKEFOURCC('L', 'I', 'S', 'T') ); + bx::write(&m_writer, UINT32_C(120) ); + bx::write(&m_writer, BX_MAKEFOURCC('s', 't', 'r', 'l') ); + + // AVISTREAMHEADER Structure http://msdn.microsoft.com/en-us/library/ms779638.aspx + bx::write(&m_writer, BX_MAKEFOURCC('s', 't', 'r', 'h') ); + bx::write(&m_writer, UINT32_C(56) ); + // AVI Stream Headers http://msdn.microsoft.com/en-us/library/ms899423.aspx + bx::write(&m_writer, BX_MAKEFOURCC('v', 'i', 'd', 's') ); // fccType + bx::write(&m_writer, BX_MAKEFOURCC('D', 'I', 'B', ' ') ); // fccHandler + bx::write(&m_writer, UINT32_C(0) ); // dwFlags + bx::write(&m_writer, UINT16_C(0) ); // wPriority + bx::write(&m_writer, UINT16_C(0) ); // wLanguage + bx::write(&m_writer, UINT32_C(0) ); // dwInitialFrames + bx::write(&m_writer, UINT32_C(1000) ); // dwScale + bx::write(&m_writer, 1000*_fps); // dwRate + bx::write(&m_writer, UINT32_C(0) ); // dwStart + bx::write(&m_writer, UINT32_C(0) ); // dwLength + bx::write(&m_writer, UINT32_C(0) ); // dwSuggestedBufferSize + bx::write(&m_writer, UINT32_C(0) ); // dwQuality + bx::write(&m_writer, UINT32_C(0) ); // dwSampleSize + bx::write(&m_writer, INT16_C(0) ); // rcFrame.left + bx::write(&m_writer, INT16_C(0) ); // rcFrame.top + bx::write(&m_writer, INT16_C(0) ); // rcFrame.right + bx::write(&m_writer, INT16_C(0) ); // rcFrame.bottom + + bx::write(&m_writer, BX_MAKEFOURCC('s', 't', 'r', 'f') ); + bx::write(&m_writer, UINT32_C(44) ); + + // BITMAPINFOHEADER structure http://msdn.microsoft.com/en-us/library/windows/desktop/dd318229%28v=vs.85%29.aspx + bx::write(&m_writer, UINT32_C(40) ); // biSize + bx::write(&m_writer, _width); // biWidth + bx::write(&m_writer, _height); // biHeight + bx::write(&m_writer, UINT16_C(1) ); // biPlanes + bx::write(&m_writer, UINT16_C(24) ); // biBitCount + bx::write(&m_writer, UINT32_C(0) ); // biCompression + bx::write(&m_writer, UINT32_C(0) ); // biSizeImage + bx::write(&m_writer, UINT32_C(0) ); // biXPelsPerMeter + bx::write(&m_writer, UINT32_C(0) ); // biYPelsPerMeter + bx::write(&m_writer, UINT32_C(0) ); // biClrUsed + bx::write(&m_writer, UINT32_C(0) ); // biClrImportant + bx::write(&m_writer, UINT32_C(0) ); + + bx::write(&m_writer, BX_MAKEFOURCC('L', 'I', 'S', 'T') ); + bx::write(&m_writer, UINT32_C(0) ); + bx::write(&m_writer, BX_MAKEFOURCC('m', 'o', 'v', 'i') ); + + return true; + } + + void close() + { + if (NULL != m_frame) + { + m_writer.close(); + + delete [] m_frame; + m_frame = NULL; + m_frameSize = 0; + } + } + + void frame(const void* _data) + { + if (NULL != m_frame) + { + uint32_t width = m_width; + uint32_t height = m_height; + + uint8_t* bgr = &m_frame[8]; + + if (m_yflip) + { + for (uint32_t yy = 0; yy < height; ++yy) + { + const uint8_t* bgra = (const uint8_t*)_data + (height-1-yy)*width*4; + + for (uint32_t ii = 0; ii < width; ++ii) + { + bgr[0] = bgra[0]; + bgr[1] = bgra[1]; + bgr[2] = bgra[2]; + bgr += 3; + bgra += 4; + } + } + } + else + { + const uint8_t* bgra = (const uint8_t*)_data; + for (uint32_t ii = 0, num = m_frameSize/3; ii < num; ++ii) + { + bgr[0] = bgra[0]; + bgr[1] = bgra[1]; + bgr[2] = bgra[2]; + bgr += 3; + bgra += 4; + } + } + + bx::write(&m_writer, m_frame, m_frameSize+8); + } + } + + bx::CrtFileWriter m_writer; + uint8_t* m_frame; + uint32_t m_frameSize; + uint32_t m_width; + uint32_t m_height; + bool m_yflip; +}; + +#endif // __AVIWRITER_H__