You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
293 lines
11 KiB
C++
293 lines
11 KiB
C++
//----------------------------------------------------------------------------------------
|
|
#include "aviwrapper.h"
|
|
#include <cassert>
|
|
#include <common/crt/mvstring.h>
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
/*!
|
|
\class AVIWrapper
|
|
\brief Provides an easy way to create and use *.avi-files.
|
|
|
|
This class is meant to provide easy access to the AVI file functions. It can be used to generate
|
|
an AVI stream with only a few lines of code.
|
|
|
|
Three general methods are supported:
|
|
|
|
- Creation of an AVI stream using the standard Windows compression options dialog (interactively)
|
|
- Creation of an AVI stream specifying a codec handler, quality settings and image dimensions
|
|
(not interactively)
|
|
- Creation of an AVI stream from images which are already in jpeg format.
|
|
*/
|
|
|
|
unsigned int AVIWrapper::m_usageCount = 0;
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
/*!
|
|
\brief Constructs a new \b AVIWrapper object.
|
|
\param filename The filename of the AVI file to be created or \e 0 if no file shall be
|
|
created.
|
|
\param mode The access mode for this file.
|
|
|
|
Opens and creates an AVI file in the mode specified by the \e mode parameter if
|
|
a filename has been specified. See MSDN for details about the available modes.
|
|
*/
|
|
AVIWrapper::AVIWrapper( const char* pFilename /* = 0 */, UINT mode /* = OF_READ */ ) :
|
|
m_AVIStreamFrameCounter( 0 ), m_pAVIFile( 0 ), m_pAVIStream( 0 ), m_pAVIStreamCompressed( 0 ),
|
|
m_codec( CodecToFourccCode( codecNoCompression ) )
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
if( m_usageCount == 0 )
|
|
{
|
|
AVIFileInit();
|
|
}
|
|
++m_usageCount;
|
|
if( pFilename )
|
|
{
|
|
HRESULT result = AVIFileOpen( &m_pAVIFile, pFilename, mode, 0 );
|
|
if( result == AVIERR_OK )
|
|
{
|
|
result = AVIFileGetStream( m_pAVIFile, &m_pAVIStream, streamtypeVIDEO, 0 );
|
|
}
|
|
if( result != AVIERR_OK )
|
|
{
|
|
AVIFileExit();
|
|
throw AVIWrapperException( AVIErrorToString( result ).c_str() );
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
AVIWrapper::~AVIWrapper( void )
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
if( m_pAVIFile )
|
|
{
|
|
CloseStreamsAndFiles();
|
|
}
|
|
--m_usageCount;
|
|
if( m_usageCount == 0 )
|
|
{
|
|
AVIFileExit();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
/*!
|
|
\brief Closes the AVI file again.
|
|
|
|
Closes all open streams and the AVI file itself. At the moment only one stream can be opened
|
|
at the same time.
|
|
*/
|
|
void AVIWrapper::CloseAVIFile( void )
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
if( !m_pAVIFile )
|
|
{
|
|
throw AVIWrapperException( "CloseAVIFile: No file has been opened so far" );
|
|
}
|
|
CloseStreamsAndFiles();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
/*!
|
|
\brief Closes all open stream and the AVI file itself.
|
|
*/
|
|
void AVIWrapper::CloseStreamsAndFiles( void )
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
if( m_pAVIStream )
|
|
{
|
|
AVIStreamRelease( m_pAVIStream );
|
|
}
|
|
if( m_pAVIStreamCompressed )
|
|
{
|
|
AVIStreamRelease( m_pAVIStreamCompressed );
|
|
}
|
|
if( m_pAVIFile )
|
|
{
|
|
AVIFileRelease( m_pAVIFile );
|
|
}
|
|
m_pAVIStream = 0;
|
|
m_pAVIStreamCompressed = 0;
|
|
m_pAVIFile = 0;
|
|
m_AVIStreamFrameCounter = 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
/*!
|
|
\brief Creates an AVI stream from DIB images.
|
|
\param w The width of the images to be stored in the stream
|
|
\param h The height of the images to be stored in the stream
|
|
\param sampleRate The frames per second entry in the AVI header
|
|
\param quality The JPEG quality (from 0 - 10000)
|
|
\param name The name of the stream in the file
|
|
\param codec The codec to be used for the compression of the DIB data. Pass \e codecMax if
|
|
you want to select a codec from the standard Windows compression dialog or
|
|
a valid codec from the \b CODEC_T enumeration.
|
|
|
|
Use this function to create a compressed or uncompressed AVI stream from images in DIB/Bitmap
|
|
format. The images can be stored in a compressed format defined by the specified compression
|
|
handler.
|
|
|
|
If your images are already in JPEG format use the function <b>AVIWrapper::CreateAVIStreamFromJPEGs()</b>
|
|
instead.
|
|
*/
|
|
void AVIWrapper::CreateAVIStreamFromDIBs( int w, int h, int bitcount, DWORD sampleRate, DWORD quality, const char* pName /*= "default"*/, CODEC_T codec /*= codecMax*/ )
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
BITMAPINFOHEADER BmpHeader;
|
|
SetupStreamStructs( BmpHeader, w, h, bitcount, sampleRate, quality, pName, codec );
|
|
BmpHeader.biCompression = BI_RGB;
|
|
AVICOMPRESSOPTIONS* opts[1] = {&m_AVICompressionOptions};
|
|
memset( &m_AVICompressionOptions, 0, sizeof( AVICOMPRESSOPTIONS ) );
|
|
PAVISTREAM streams[1] = {m_pAVIStream};
|
|
|
|
if( codec == codecMax )
|
|
{
|
|
// show windows compression handler dialog
|
|
AVISaveOptions( 0, 0, 1, ( PAVISTREAM* )&streams, ( LPAVICOMPRESSOPTIONS* )&opts );
|
|
}
|
|
else // fill AVICOMPRESSOPTIONS with user parameters
|
|
{
|
|
m_codec = codec;
|
|
opts[0]->fccType = streamtypeVIDEO;
|
|
opts[0]->fccHandler = CodecToFourccCode( codec );
|
|
opts[0]->dwQuality = quality;
|
|
opts[0]->dwFlags = AVICOMPRESSF_VALID;
|
|
}
|
|
m_codec = opts[0]->fccHandler;
|
|
HRESULT result = AVIMakeCompressedStream( &m_pAVIStreamCompressed, m_pAVIStream, &m_AVICompressionOptions, NULL );
|
|
if( result == AVIERR_OK )
|
|
{
|
|
result = AVIStreamSetFormat( m_pAVIStreamCompressed, 0, &BmpHeader, sizeof( BITMAPINFOHEADER ) );
|
|
}
|
|
if( result != AVIERR_OK )
|
|
{
|
|
CloseStreamsAndFiles();
|
|
throw AVIWrapperException( AVIErrorToString( result ).c_str() );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
/*!
|
|
\brief Creates an AVI stream from JPEG images.
|
|
\param w The width of the images to be stored in the stream
|
|
\param h The height of the images to be stored in the stream
|
|
\param sampleRate The frames per second entry in the AVI header
|
|
\param quality The JPEG quality (from 0 - 10000)
|
|
\param name The name of the stream in the file
|
|
|
|
Use this function to create a MJPEG stream from images which are already in JPEG format.
|
|
|
|
To create an AVI stream from images in DIB format use the function
|
|
<b>AVIWrapper::CreateAVIStreamFromDIBs()</b> instead.
|
|
*/
|
|
void AVIWrapper::CreateAVIStreamFromJPEGs( int w, int h, int bitcount, DWORD sampleRate, DWORD quality, const char* pName /*= "default"*/ )
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
// no 'handler' compression! This section works for already compressed images
|
|
BITMAPINFOHEADER BmpHeader;
|
|
SetupStreamStructs( BmpHeader, w, h, bitcount, sampleRate, quality, pName, codecMorganMjpg );
|
|
BmpHeader.biCompression = CodecToFourccCode( codecMorganMjpg );
|
|
const HRESULT result = AVIStreamSetFormat( m_pAVIStream, 0, &BmpHeader, sizeof( BITMAPINFOHEADER ) );
|
|
if( result != AVIERR_OK )
|
|
{
|
|
CloseStreamsAndFiles();
|
|
throw AVIWrapperException( AVIErrorToString( result ).c_str() );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
/*!
|
|
\brief Opens an AVI file.
|
|
\param filename The name of the file to be created/opened/used.
|
|
\param mode The access mode for this file.
|
|
|
|
Opens and creates an AVI file in the mode specified by the \e mode parameter
|
|
See MSDN for details about the available modes.
|
|
*/
|
|
void AVIWrapper::OpenAVIFile( const char* pFilename, UINT mode /* = OF_READ */ )
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
if( m_pAVIFile )
|
|
{
|
|
throw AVIWrapperException( "OpenAVIFile: Another file has been opened already" );
|
|
}
|
|
if( !pFilename )
|
|
{
|
|
throw AVIWrapperException( "OpenAVIFile: No valid filename has been specified" );
|
|
}
|
|
const HRESULT result = AVIFileOpen( &m_pAVIFile, pFilename, mode, 0 );
|
|
if( result != AVIERR_OK )
|
|
{
|
|
throw AVIWrapperException( AVIErrorToString( result ).c_str() );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
/*!
|
|
\brief Stores one image in the AVI stream
|
|
\param data Pointer to the image data
|
|
\param size Size (in bytes) of the memory block pointed to by \e data
|
|
|
|
This function stores one image in the specified stream.
|
|
*/
|
|
void AVIWrapper::SaveDataToAVIStream( unsigned char* pData, int size )
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
PAVISTREAM pAVIStream = ( m_pAVIStreamCompressed ) ? m_pAVIStreamCompressed : m_pAVIStream;
|
|
if( !pAVIStream )
|
|
{
|
|
throw AVIWrapperException( "SaveDataToAVIStream: Stream pointer invalid" );
|
|
}
|
|
const HRESULT result = AVIStreamWrite( pAVIStream, m_AVIStreamFrameCounter++, 1, pData, size, AVIIF_KEYFRAME, 0, 0 );
|
|
if( result != AVIERR_OK )
|
|
{
|
|
throw AVIWrapperException( AVIErrorToString( result ).c_str() );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
void AVIWrapper::SetupStreamStructs( BITMAPINFOHEADER& BmpHeader, int w, int h, int bitcount, DWORD sampleRate, DWORD quality, const char* pName /*= "default"*/, CODEC_T codec /*= codecMax*/ )
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
if( !m_pAVIFile )
|
|
{
|
|
throw AVIWrapperException( "CreateNewAVIStream: No file has been opened so far" );
|
|
}
|
|
if( strlen( pName ) > sizeof( m_AVIStreamInfo.szName ) )
|
|
{
|
|
throw AVIWrapperException( "CreateNewAVIStream: stream name too long" );
|
|
}
|
|
if( m_pAVIStream || m_pAVIStreamCompressed )
|
|
{
|
|
throw AVIWrapperException( "CreateNewAVIStream: There is already an open stream" );
|
|
}
|
|
// setup AVISTREAMINFO structure
|
|
memset( &m_AVIStreamInfo, 0, sizeof( AVISTREAMINFO ) );
|
|
m_AVIStreamInfo.fccType = streamtypeVIDEO;
|
|
m_AVIStreamInfo.fccHandler = CodecToFourccCode( codec );
|
|
m_AVIStreamInfo.wPriority = 10;
|
|
m_AVIStreamInfo.dwScale = 1;
|
|
m_AVIStreamInfo.dwRate = sampleRate;
|
|
m_AVIStreamInfo.dwQuality = quality;
|
|
m_AVIStreamInfo.rcFrame.right = w;
|
|
m_AVIStreamInfo.rcFrame.bottom = h;
|
|
mv_strncpy_s( m_AVIStreamInfo.szName, pName, sizeof( m_AVIStreamInfo.szName ) );
|
|
|
|
const HRESULT result = AVIFileCreateStream( m_pAVIFile, &m_pAVIStream, &m_AVIStreamInfo );
|
|
if( result != AVIERR_OK )
|
|
{
|
|
throw AVIWrapperException( AVIErrorToString( result ).c_str() );
|
|
}
|
|
// setup BITMAPINFOHEADER structure
|
|
memset( &BmpHeader, 0, sizeof( BITMAPINFOHEADER ) );
|
|
BmpHeader.biSize = sizeof( BITMAPINFOHEADER );
|
|
BmpHeader.biWidth = w;
|
|
BmpHeader.biHeight = h;
|
|
BmpHeader.biPlanes = 1;
|
|
BmpHeader.biBitCount = static_cast<WORD>( bitcount );
|
|
|
|
// setup internals
|
|
m_AVIStreamFrameCounter = 0;
|
|
} |