📄 avi.cpp
字号:
#include "avi.h"#if 0#ifdef _WIN32#include <windows.h>static void debug_outs (char *szMsg, ...){ char szBuf[256]; wvsprintf (szBuf, szMsg, (LPSTR)(&szMsg + 1)); OutputDebugString (szBuf);}#else#include <stdio.h>#define debug_outs printf#endifstatic void debug_break (void){}#define ASSERT(exp) ((void)((exp)?1:(debug_outs ("ASSERT failed: line %d, file %s\n", __LINE__,__FILE__), debug_break(), 0)))#define DEBUGMSG(cond,printf_exp) ((void)((cond)?(debug_outs printf_exp),1:0))#else#define ASSERT(exp)#define DEBUGMSG(cond,printf_exp)#endif#define AVI_DEMUX_STATE_CHUNK_NAME_BYTE0 0#define AVI_DEMUX_STATE_CHUNK_NAME_BYTE1 1#define AVI_DEMUX_STATE_CHUNK_NAME_BYTE2 2#define AVI_DEMUX_STATE_CHUNK_NAME_BYTE3 3#define AVI_DEMUX_STATE_CHUNK_LENGTH_BYTE0 4#define AVI_DEMUX_STATE_CHUNK_LENGTH_BYTE1 5#define AVI_DEMUX_STATE_CHUNK_LENGTH_BYTE2 6#define AVI_DEMUX_STATE_CHUNK_LENGTH_BYTE3 7#define AVI_DEMUX_STATE_WRITE_CHUNK 8#define AVI_DEMUX_STATE_RESTORE_STATE 9#define AVI_DEMUX_STATE_INVALID 10#define AVI_MIN(X,Y) (((X)<=(Y))?(X):(Y)) // to find the min between two number.AVIDemux::AVIDemux (){ DEBUGMSG (1, ("AVIDemux::AVIDemux\n")); m_handle = 0; m_savedbuf = 0; m_savedbuflen = 0; m_savedp = 0; Init ();}AVIDemux::~AVIDemux (){ DEBUGMSG (1, ("AVIDemux::~AVIDemux\n")); if (m_handle) { ASSERT (m_CallbackTable.fclose); m_CallbackTable.fclose (m_handle, m_CallbackTable.context); }}AVI_DEMUX_ERROR AVIDemux::Init (){ DEBUGMSG (1, ("AVIDemux::Init\n")); if (m_handle) { if (m_CallbackTable.fclose) m_CallbackTable.fclose (m_handle, m_CallbackTable.context); } m_CallbackTable.fopen = 0; m_CallbackTable.fread = 0; m_CallbackTable.fseek = 0; m_CallbackTable.fclose = 0; m_CallbackTable.addref = 0; m_CallbackTable.release = 0; m_CallbackTable.info = 0; m_CallbackTable.putChunk = 0; m_handle = 0; m_nStreamHeader = 0; m_nStreamFormat = 0; m_moviOffset = 0; m_sizeOfFile = 0; m_chunkstart = 0; m_bytecounter = 0; RMint32 i; for (i=0; i<AVI_MAX_STREAMS_SUPPORTED; i++) m_vbrmp3[i] = 0; for (i=0; i<AVI_MAX_INDEX_HELPER; i++) { m_IndexHelper[i].chunkOffset = 0; m_IndexHelper[i].indexOffset = 0; m_IndexHelper[i].videoFrameCount = 0; for (RMint32 j=0; j<AVI_MAX_STREAMS_SUPPORTED; j++) m_IndexHelper[i].audioByteOrFrameCount[j] = 0; } m_avih.TotalFrames = 0; m_demuxstate = AVI_DEMUX_STATE_INVALID; m_idx1Offset = 0; m_currentFramePosition = 0; m_KeyFramesOnly = 0; m_IndexCacheValid = 0; m_IndexCacheOffset = 0; m_KeyFrameDelayInMS = 500; m_IndexIsRelativeToStartOfFile = 0; return AVI_DEMUX_ERROR_NO_ERROR;}AVI_DEMUX_ERROR AVIDemux::InitCallbackTable (AVI_CALLBACK_TABLE *pCallbackTable){ DEBUGMSG (1, ("AVIDemux::InitCallbackTable\n")); m_CallbackTable.context = pCallbackTable->context; m_CallbackTable.fopen = pCallbackTable->fopen; m_CallbackTable.fread = pCallbackTable->fread; m_CallbackTable.ftell = pCallbackTable->ftell; m_CallbackTable.fseek = pCallbackTable->fseek; m_CallbackTable.fclose = pCallbackTable->fclose; m_CallbackTable.addref = pCallbackTable->addref; m_CallbackTable.release = pCallbackTable->release; m_CallbackTable.info = pCallbackTable->info; m_CallbackTable.getbuffer = pCallbackTable->getbuffer; m_CallbackTable.putChunk = pCallbackTable->putChunk; m_CallbackTable.loading = pCallbackTable->loading; m_CallbackTable.gettimems = pCallbackTable->gettimems; return AVI_DEMUX_ERROR_NO_ERROR;}static RMint32 isChar (RMint8 character){ if(((character >= 'a') && (character <= 'z')) || ((character >= 'A') && (character <= 'Z')) || ((character >= '0') && (character <= '9')) || (character == ' ')) return 1; return 0;}AVI_DEMUX_ERROR AVIDemux::DemuxFile (RMint8 *filename){ ASSERT (m_handle == 0); ASSERT (m_CallbackTable.fopen); m_handle = m_CallbackTable.fopen (filename, m_CallbackTable.context); ASSERT (m_handle); if (m_handle == 0) { DEBUGMSG (1, ("fopen (%s) failed\n", filename)); return AVI_DEMUX_ERROR_NOT_AN_AVI_FILE; } AVI_CHUNK chunk; RMuint32 name; RMuint32 n; ASSERT (sizeof(chunk) == 8); // verify that this is a AVI RIFF file n = m_CallbackTable.fread (m_handle, &chunk, sizeof(chunk), m_CallbackTable.context); ASSERT (n == sizeof(chunk)); if (n != sizeof(chunk)) { m_CallbackTable.fclose (m_handle, m_CallbackTable.context); m_handle = 0; DEBUGMSG (1, ("not an AVI RIFF file: too short\n")); return AVI_DEMUX_ERROR_NOT_AN_AVI_FILE; } if (chunk.Name != AVI_FOURCC ('R','I','F','F')) { m_CallbackTable.fclose (m_handle, m_CallbackTable.context); m_handle = 0; DEBUGMSG (1, ("not an AVI RIFF file: no RIFF header\n")); return AVI_DEMUX_ERROR_NOT_AN_AVI_FILE; } m_RIFFlength = chunk.Length; RMuint32 rifflength = m_RIFFlength; ASSERT (sizeof(name) == 4); // next 4 bytes must be 'AVI ' n = m_CallbackTable.fread (m_handle, &name, sizeof(name), m_CallbackTable.context); ASSERT (n == sizeof(name)); if (name != AVI_FOURCC('A','V','I',' ')) { m_CallbackTable.fclose (m_handle, m_CallbackTable.context); m_handle = 0; DEBUGMSG (1, ("not an AVI RIFF file: name is not 'AVI '\n")); return AVI_DEMUX_ERROR_NOT_AN_AVI_FILE; } rifflength -= sizeof(name); ASSERT ((RMint32)rifflength > 0); RMuint32 listOffset; RMuint32 subListLength, subChunkLength, position, mainchunkLength; // actually not the length of the file, but the length of the riff // chunk m_sizeOfFile = rifflength; ASSERT (m_CallbackTable.loading); m_CallbackTable.loading (0, m_CallbackTable.context); // parse all the chunks while (rifflength > 0) { // read the next chunk rifflength -= sizeof (chunk); n = m_CallbackTable.fread (m_handle, &chunk, sizeof (chunk), m_CallbackTable.context); ASSERT (n == sizeof (chunk)); ASSERT (chunk.Length <= rifflength); if (n == 0) { DEBUGMSG (1, ("read error?\n")); if (m_moviOffset) { // ok a movi offset was found, let's do our best to play // this file - in anycase, the file is corrupted. // if an idx1 chunk has not been found, then you won't be // able to seek or do I frames rifflength = 0; continue; } // not even a m_moviOffset has been found - abort return AVI_DEMUX_ERROR_NOT_AN_AVI_FILE; } if (((isChar ((RMint8)((chunk.Name >> 24) & 0xff))) == 0) || ((isChar ((RMint8)((chunk.Name >> 16) & 0xff))) == 0) || ((isChar ((RMint8)((chunk.Name >> 8) & 0xff))) == 0) || ((isChar ((RMint8)((chunk.Name >> 0) & 0xff))) == 0)) { ASSERT (0); // invalid chunk name n = m_CallbackTable.ftell (m_handle, m_CallbackTable.context); m_CallbackTable.fseek (m_handle, n - (sizeof (chunk) - 1), m_CallbackTable.context); rifflength += (sizeof (chunk) - 1); continue; } switch (chunk.Name) { case AVI_FOURCC ('L','I','S','T'): // this is the main LIST chunk mainchunkLength = chunk.Length; DEBUGMSG (1, ("LIST chunk\n")); listOffset = m_CallbackTable.ftell (m_handle, m_CallbackTable.context); // we recognize 3 kinds of LIST chunks: 'hdrl', 'strl', amd 'movi' n = m_CallbackTable.fread (m_handle, &name, sizeof(name), m_CallbackTable.context); ASSERT (n == sizeof(name)); switch (name) { case AVI_FOURCC ('h','d','r','l'): n = m_CallbackTable.fread (m_handle, &name, sizeof(name), m_CallbackTable.context); ASSERT (n == sizeof(name)); ASSERT (name == AVI_FOURCC ('a','v','i','h')); n = m_CallbackTable.fread (m_handle, &subChunkLength, sizeof(subChunkLength), m_CallbackTable.context); ASSERT (n == sizeof(subChunkLength)); position = m_CallbackTable.ftell (m_handle, m_CallbackTable.context); ASSERT (subChunkLength >= sizeof(m_avih)); n = m_CallbackTable.fread (m_handle, &m_avih, sizeof(m_avih), m_CallbackTable.context); ASSERT (n == sizeof (m_avih)); DEBUGMSG (1, ("aviHeader:\n")); DEBUGMSG (1, (" MicroSecPerFrame: %lu\n", m_avih.MicroSecPerFrame)); DEBUGMSG (1, (" MaxBytesPerSec: %lu\n", m_avih.MaxBytesPerSec)); DEBUGMSG (1, (" Flags: %lu\n", m_avih.Flags)); DEBUGMSG (1, (" TotalFrames: %lu\n", m_avih.TotalFrames)); DEBUGMSG (1, (" InitialFrames: %lu\n", m_avih.InitialFrames)); DEBUGMSG (1, (" Streams: %lu\n", m_avih.Streams)); DEBUGMSG (1, (" SuggestedBufferSize: %lu\n", m_avih.SuggestedBufferSize)); DEBUGMSG (1, (" Width: %lu\n", m_avih.Width)); DEBUGMSG (1, (" Height: %lu\n", m_avih.Height)); DEBUGMSG (1, (" Scale: %lu\n", m_avih.Scale)); DEBUGMSG (1, (" Rate: %lu\n", m_avih.Rate)); DEBUGMSG (1, (" Start: %lu\n", m_avih.Start)); DEBUGMSG (1, (" Length: %lu\n", m_avih.Length)); ASSERT (m_CallbackTable.info); m_CallbackTable.info (AVI_DEMUX_MSG_AVIHDR, &m_avih, m_CallbackTable.context); m_CallbackTable.fseek (m_handle, position + subChunkLength, m_CallbackTable.context); mainchunkLength -= 4; // for 'hdrl' mainchunkLength -= (subChunkLength + 8); // for 'avih' // XXX to do: handle more than one sublist while ((RMint32)mainchunkLength > 0) { n = m_CallbackTable.fread (m_handle, &name, sizeof(name), m_CallbackTable.context); ASSERT (n == sizeof(name)); n = m_CallbackTable.fread (m_handle, &subChunkLength, sizeof(subListLength), m_CallbackTable.context); ASSERT (n == sizeof(subChunkLength)); mainchunkLength -= 8; // for the header of this subchunk mainchunkLength -= subChunkLength; // for this subchunk if (name == AVI_FOURCC ('L','I','S','T')) { subListLength = subChunkLength; n = m_CallbackTable.fread (m_handle, &name, sizeof(name), m_CallbackTable.context); ASSERT (n == sizeof(name)); ASSERT (subListLength >= 4); subListLength -= 4; if (name == AVI_FOURCC ('s','t','r','l')) { while ((RMint32)subListLength > 3) { n = m_CallbackTable.fread (m_handle, &name, sizeof(name), m_CallbackTable.context); subListLength -= 4; ASSERT (n == sizeof(name)); switch (name) { case AVI_FOURCC ('s','t','r','h'): n = m_CallbackTable.fread (m_handle, &subChunkLength, sizeof(subChunkLength), m_CallbackTable.context); ASSERT (n == sizeof(subChunkLength)); subListLength -= 4; position = m_CallbackTable.ftell (m_handle, m_CallbackTable.context); ASSERT (subChunkLength >= sizeof(AVI_STREAM_HEADER)); n = m_CallbackTable.fread (m_handle, &m_StreamHeaders[m_nStreamHeader], sizeof(AVI_STREAM_HEADER), m_CallbackTable.context); ASSERT (n == sizeof(AVI_STREAM_HEADER)); ASSERT (m_CallbackTable.info); DEBUGMSG (1, ("strh:\n")); DEBUGMSG (1, (" rate: %lu (0x%08lx)\n", AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamHeader], Rate), AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamHeader], Rate))); DEBUGMSG (1, (" scale: %lu (0x%08lx)\n", AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamHeader], Scale), AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamHeader], Scale))); m_CallbackTable.info (AVI_DEMUX_MSG_STREAMHDR, &m_StreamHeaders[m_nStreamHeader], m_CallbackTable.context); if (AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamHeader], fccType)) { DEBUGMSG (1, (" fccType: %c%c%c%c\n", (RMint8)(AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamHeader], fccType) >> 0), (RMint8)(AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamHeader], fccType) >> 8), (RMint8)(AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamHeader], fccType) >> 16), (RMint8)(AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamHeader], fccType) >> 24))); } else { DEBUGMSG (1, (" fccType: 0000\n")); } subListLength -= subChunkLength; m_CallbackTable.fseek (m_handle, position+subChunkLength, m_CallbackTable.context); m_nStreamHeader++; break; case AVI_FOURCC ('s','t','r','f'): if (AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamFormat], fccType) == AVI_FOURCC('v','i','d','s')) { n = m_CallbackTable.fread (m_handle, &subChunkLength, sizeof(subChunkLength), m_CallbackTable.context); ASSERT (n == sizeof(subChunkLength)); subListLength -= 4; position = m_CallbackTable.ftell (m_handle, m_CallbackTable.context); ASSERT (subChunkLength >= sizeof(AVI_BITMAPINFO)); n = m_CallbackTable.fread (m_handle, &m_StreamFormats[m_nStreamFormat], sizeof(AVI_BITMAPINFO), m_CallbackTable.context); ASSERT (n == sizeof(AVI_BITMAPINFO)); ASSERT (m_CallbackTable.info); m_CallbackTable.info (AVI_DEMUX_MSG_BITMAPINFO, &m_StreamFormats[m_nStreamFormat], m_CallbackTable.context); DEBUGMSG (1, ("vids:\n")); DEBUGMSG (1, (" width: %u\n",m_StreamFormats[m_nStreamFormat].bmi.Width)); DEBUGMSG (1, (" height: %u\n",m_StreamFormats[m_nStreamFormat].bmi.Width)); subListLength -= subChunkLength; m_CallbackTable.fseek (m_handle, position+subChunkLength, m_CallbackTable.context); } else if (AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamFormat], fccType) == AVI_FOURCC('a','u','d','s')) { n = m_CallbackTable.fread (m_handle, &subChunkLength, sizeof(subChunkLength), m_CallbackTable.context); ASSERT (n == sizeof(subChunkLength)); subListLength -= 4; position = m_CallbackTable.ftell (m_handle, m_CallbackTable.context); ASSERT (subChunkLength >= sizeof(AVI_WAVEFORMATEX)); n = m_CallbackTable.fread (m_handle, &m_StreamFormats[m_nStreamFormat], sizeof(AVI_WAVEFORMATEX), m_CallbackTable.context); ASSERT (n == sizeof(AVI_WAVEFORMATEX)); ASSERT (m_CallbackTable.info); m_CallbackTable.info (AVI_DEMUX_MSG_WAVEFORMATEX, &m_StreamFormats[m_nStreamFormat], m_CallbackTable.context); if ((AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamFormat], Scale) == 1152) || ((AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamFormat], Rate) == m_StreamFormats[m_nStreamFormat].wfx.nSamplesPerSec) && (AVI_PACKED_STRUCTURE_ACCESS (m_StreamHeaders[m_nStreamFormat], SampleSize) == 0))) { DEBUGMSG (1, ("assuming variable bitrate mp3\n")); m_vbrmp3[m_nStreamFormat] = 1; } DEBUGMSG (1, ("auds:\n")); DEBUGMSG (1, (" formattag: %u\n", m_StreamFormats[m_nStreamFormat].wfx.wFormatTag)); DEBUGMSG (1, (" channels: %u\n", m_StreamFormats[m_nStreamFormat].wfx.nChannels));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -