linux下avi文件解析(附源码)
来源:互联网 发布:免费skycc软件怎么样 编辑:程序博客网 时间:2024/04/27 16:48
前段时间由于项目需要,要解avi文件,当时我第一时间想到用ffmpeg来处理,但想想觉得太大了,又是放到arm上跑的,感觉没必要。然后,搜索引擎上稍微搜了一下,没找到有用的示例,大部分都是利用windows的api进行读写,很明显linux下用不了。结果花了2-3天时间研究并写了一个avi文件的解封装代码,但是后来因某些原因没有去使用AVI了,所以代码也没进行后续的完善优化。这里贴出来供记录以及需要的人作参考。
头文件:
/*!@brief avi文件分析提取器@author jwybobo2007@file avifileparser.h@note 代码在使用时,请标明作者,保留出处:http://blog.csdn.net/jwybobo2007*/#include <stdio.h>#include <stdlib.h>#include <string>#include <vector>#include <map>//////////////////////////////////////////////////////////////////////////#define AVIIF_KEYFRAME0x00000010L// 索引里面的关键帧标志#define AVIIF_LIST0x00000001L// Flags for dwFlags|AVI头中的标志位#define AVIFILEINFO_HASINDEX0x00000010// 是否有索引#define AVIFILEINFO_MUSTUSEINDEX0x00000020#define AVIFILEINFO_ISINTERLEAVED0x00000100#define AVIFILEINFO_WASCAPTUREFILE0x00010000#define AVIFILEINFO_COPYRIGHTED0x00020000// 最大允许的AVI头大小#define MAX_ALLOWED_AVI_HEADER_SIZE 131072// 打不开文件#define ERROR_OPEN_AVI0// 不是有效AVI#define ERROR_INVALID_AVI1// 由于编译器c,c++标准过低,没有包含stdint.h头文件,并且现在也没有使用boost库,因此定义一些类型,来兼容以前的代码#ifdef NO_STDINTtypedef char int8_t;typedef unsigned char uint8_t;typedef short int16_t;typedef unsigned short uint16_t;typedef int int32_t;typedef unsigned int uint32_t;typedef long long int64_t;typedef unsigned long long uint64_t;#endif// 双字typedef uint32_t DWORD;// 单字typedef uint16_t WORD;// 定义长整型typedef DWORD LONG;// 字节typedef uint8_t BYTE;// 定义four cc;typedef DWORD FourCC;// 定义fourcc对应的整数值,avi文件中保存的是小端const DWORD FOURCC_RIFF = 0x46464952;const DWORD FOURCC_AVI = 0x20495641;const DWORD FOURCC_LIST = 0x5453494C;const DWORD FOURCC_hdrl = 0x6C726468;const DWORD FOURCC_avih = 0x68697661;const DWORD FOURCC_strl = 0x6C727473;const DWORD FOURCC_strh = 0x68727473;const DWORD FOURCC_strf = 0x66727473;const DWORD FOURCC_STRD = 0x64727473;const DWORD FOURCC_vids = 0x73646976;const DWORD FOURCC_auds = 0x73647561;const DWORD FOURCC_INFO = 0x4F464E49;const DWORD FOURCC_ISFT = 0x54465349;const DWORD FOURCC_idx1 = 0x31786469;const DWORD FOURCC_movi = 0x69766F6D;const DWORD FOURCC_JUNK = 0x4B4E554A;const DWORD FOURCC_vprp = 0x70727076;const DWORD FOURCC_PAD = 0x20444150;const DWORD FOURCC_DIV3 = 861292868;const DWORD FOURCC_DIVX = 1482049860;const DWORD FOURCC_XVID = 1145656920;const DWORD FOURCC_DX50 = 808802372;const DWORD FOURCC_fmt = 0x20746D66;// for WAVE filesconst DWORD FOURCC_data = 0x61746164;// for WAVE filesconst DWORD FOURCC_WAVE = 0x45564157;// for WAVE files// 调色板typedef struct{BYTE rgbBlue;// 蓝BYTE rgbGreen;// 绿BYTE rgbRed;// 红BYTE rgbReserved;// 保留} RGBQUAD;// AVI主头部typedef struct{FourCC fcc;// 必须为 avihDWORD cb;// 本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)DWORD dwMicroSecPerFrame;// 视频帧间隔时间(以毫秒为单位)DWORD dwMaxBytesPerSec;// 这个AVI文件的最大数据率DWORD dwPaddingGranularity;// 数据填充的粒度DWORD dwFlags;// AVI文件的全局标记,比如是否含有索引块等DWORD dwTotalFrames;// 总帧数DWORD dwInitialFrames;// 为交互格式指定初始帧数(非交互格式应该指定为0)DWORD dwStreams;// 本文件包含的流的个数DWORD dwSuggestedBufferSize;// 建议读取本文件的缓存大小(应能容纳最大的块)DWORD dwWidth;// 视频图像的宽(以像素为单位)DWORD dwHeight;// 视频图像的高(以像素为单位)DWORD dwReserved[4];// 保留} AVIMainHeader;// 定义矩形区域typedef struct{short int left;// 总边距short int top;// 顶边距short int right;// 右边距short int bottom;// 底边距}RECT;// AVI流头部typedef struct{FourCC fcc;// 必须为 strhDWORD cb;// 本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)FourCC fccType;// 流的类型: auds(音频流) vids(视频流) mids(MIDI流) txts(文字流)FourCC fccHandler;// 指定流的处理者,对于音视频来说就是解码器DWORD dwFlags;// 标记:是否允许这个流输出?调色板是否变化?WORD wPriority;// 流的优先级(当有多个相同类型的流时优先级最高的为默认流)WORD wLanguage;// 语言DWORD dwInitialFrames;// 为交互格式指定初始帧数DWORD dwScale;// 每帧视频大小或者音频采样大小DWORD dwRate;// dwScale/dwRate,每秒采样率DWORD dwStart;// 流的开始时间DWORD dwLength;// 流的长度(单位与dwScale和dwRate的定义有关)DWORD dwSuggestedBufferSize;// 读取这个流数据建议使用的缓存大小DWORD dwQuality;// 流数据的质量指标(0 ~ 10,000)DWORD dwSampleSize;// Sample的大小RECT rcFrame;// 指定这个流(视频流或文字流)在视频主窗口中的显示位置,视频主窗口由AVIMAINHEADER结构中的dwWidth和dwHeight决定} AVIStreamHeader;// 位图头typedef struct{DWORD biSize;LONG biWidth;LONG biHeight;WORD biPlanes;WORD biBitCount;DWORD biCompression;DWORD biSizeImage;LONG biXPelsPerMeter;LONG biYPelsPerMeter;DWORD biClrUsed;DWORD biClrImportant;} BitmapInfoHeader;// 位图信息typedef struct{BitmapInfoHeader bmiHeader;// 位图头RGBQUAD bmiColors[1];// 调色板} BitmapInfo;// 音频波形信息typedef struct{WORD wFormatTag;WORD nChannels;// 声道数DWORD nSamplesPerSec;// 采样率DWORD nAvgBytesPerSec;// 每秒的数据量WORD nBlockAlign;// 数据块对齐标志WORD wBitsPerSample;// 每次采样的数据量WORD cbSize;// 大小} WaveFormatEx;// 索引节点信息typedef struct{DWORD dwChunkId;// 本数据块的四字符码(00dc 01wb)DWORD dwFlags;// 说明本数据块是不是关键帧、是不是‘rec ’列表等信息DWORD dwOffset;// 本数据块在文件中的偏移量DWORD dwSize;// 本数据块的大小} AVIIndexEntry;// 索引信息typedef struct{FourCC fcc;// 必须为‘idx1’DWORD cb;// 本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)uint32_t position;// 数据起始位置偏移std::map<uint32_t, std::vector<AVIIndexEntry> > videoIndexMap;// 视频索引表,00dc等转换成整形表示std::map<uint32_t, std::vector<AVIIndexEntry> > audioIndexMap;// 音频索引表,00wb等转换成整形表示} AVIIndex;/*!@brief avi文件分析提取器*/class AVIFileParser{public:AVIFileParser();AVIFileParser(const char* file);~AVIFileParser(void);public:/*!@brief 打开AVI文件*/void openAVI(const char* file);/*!@brief 是否是有效avi*/bool isValid(){return _isValid;}/*!@brief 是否有音频*/bool hasAudio(){return _hasAudio;}/*!@brief 是否有视频*/bool hasVideo(){return _hasVideo;}/*!@brief 返回avi头*/const AVIMainHeader* aviMainHeader(){return &_aviMainHeader;}/*!@brief 返回avi视频流头*/const AVIStreamHeader* aviVideoStreamHeader(){return &_aviVideoStreamHeader;}/*!@brief 返回avi音频流头*/const AVIStreamHeader* aviAudioStreamHeader(){return &_aviAudioStreamHeader;}/*!@brief 返回位图信息*/const BitmapInfo* bitmapInfo(){return &_bitmapInfo;}/*!@brief 返回音频信息*/const WaveFormatEx* waveFormatEx(){return &_waveInfo;}/*!@brief 最大视频帧大小*/uint32_t maxFrameSize(){return _maxFrameSize;}/*!@brief 获取视频帧@param buf 视频帧存储缓冲@param index 帧索引,默认-1,表示从当前的索引继续往下读取@return 视频帧大小*/int32_t getVideoFrame(char* buf, int32_t index = -1);/*!@brief 偏移视频帧从指定位置开始@param index 指定索引*/bool seekVideoFrame(int32_t index);/*!@brief 获取音频帧*/private:/// 解析AVIvoid _parseFile();/// 从文件读指定长度的数据,出错自动抛出异常bool readFile(char* buf, uint32_t len);/// 从文件读12个字节并分析bool readFileTagSize(DWORD& fourcc, uint32_t& size, DWORD& fourcc2);/// 从文件读4字节uint32_t readFileDW();/// 从文件读2字节uint16_t readFileW();//////////////////////////////////////////////////////////////////////////// 重载/// 从文件读4字节bool readFileDW(uint32_t& dw);/// 从文件读2字节bool readFileW(uint16_t& w);private:// 文件句柄FILE* _aviFd;// 是否有音频bool _hasAudio;// 是否有视频bool _hasVideo;// 是否有效bool _isValid;// 文件长度uint32_t _fLen;// avi主头AVIMainHeader _aviMainHeader;// avi视频流头部AVIStreamHeader _aviVideoStreamHeader;// avi音频流头部AVIStreamHeader _aviAudioStreamHeader;// 位图信息BitmapInfo _bitmapInfo;// 音频信息WaveFormatEx _waveInfo;// 编码程序std::string _soft;// 索引信息AVIIndex _aviIndex;// movi的开始位置偏移uint32_t _moviOff;// 最大帧大小uint32_t _maxFrameSize;// 当前视频位置索引(数组中的位置,下标)int32_t _currVideoIndex;};
源文件:
#include <assert.h>#include <errno.h>#include "avifileparser.h"#include "byte_write.h"AVIFileParser::AVIFileParser(void):_aviFd(NULL),_hasAudio(false),_hasVideo(false),_isValid(false),_fLen(0),_moviOff(0),_maxFrameSize(0),_currVideoIndex(0){}AVIFileParser::AVIFileParser( const char* file ):_hasAudio(false),_hasVideo(false),_isValid(false),_fLen(0),_moviOff(0),_maxFrameSize(0),_currVideoIndex(0){openAVI(file);}AVIFileParser::~AVIFileParser(void){if (_aviFd != NULL)fclose(_aviFd);}void AVIFileParser::openAVI( const char* file ){_aviFd = fopen(file, "rb");if (_aviFd == NULL){#ifndef NPRINTprintf("open avi error: %d [%s]\n", errno, strerror(errno));#endif// 抛出错误号throw ERROR_OPEN_AVI;}// 开始解析_parseFile();_isValid = true;}void AVIFileParser::_parseFile(){// 第一次读12个字节DWORD fourcc = 0;DWORD fourcc2 = 0;bool flag = true;bool hasIndex = false;readFileTagSize(fourcc, _fLen, fourcc2);if (fourcc != FOURCC_RIFF || fourcc2 != FOURCC_AVI)throw ERROR_INVALID_AVI;while (flag){uint32_t size = 0;bool isEof = readFileDW(fourcc);if (isEof)return;isEof = readFileDW(size);if (isEof)return;if (fourcc == FOURCC_LIST){fourcc2 = readFileDW();switch (fourcc2){case FOURCC_hdrl:{if (size > MAX_ALLOWED_AVI_HEADER_SIZE)throw ERROR_INVALID_AVI;// 跳过hdrluint32_t off = 4;while (off < size){fourcc = readFileDW();switch (fourcc){case FOURCC_avih:{_aviMainHeader.fcc = FOURCC_avih;_aviMainHeader.cb = readFileDW();_aviMainHeader.dwMicroSecPerFrame = readFileDW();_aviMainHeader.dwMaxBytesPerSec = readFileDW();_aviMainHeader.dwPaddingGranularity = readFileDW();_aviMainHeader.dwFlags = readFileDW();_aviMainHeader.dwTotalFrames = readFileDW();_aviMainHeader.dwInitialFrames = readFileDW();_aviMainHeader.dwStreams = readFileDW();_aviMainHeader.dwSuggestedBufferSize = readFileDW();_aviMainHeader.dwWidth = readFileDW();_aviMainHeader.dwHeight = readFileDW();if ((AVIFILEINFO_HASINDEX & _aviMainHeader.dwFlags) == AVIFILEINFO_HASINDEX)hasIndex = true;// 跳过保留字段fseek(_aviFd, 16, SEEK_CUR);// 跳过avih以及长度各四个字节off += _aviMainHeader.cb + 8;}break;case FOURCC_LIST:{int avListLen = readFileDW();if (readFileDW() != FOURCC_strl)throw ERROR_INVALID_AVI;// 跳过strlint tmpOff = 4;AVIStreamHeader aviStreamHeader = {0};while (tmpOff < avListLen){fourcc = readFileDW();tmpOff += 4;if (fourcc == FOURCC_strh){aviStreamHeader.fcc = FOURCC_strh;aviStreamHeader.cb = readFileDW();aviStreamHeader.fccType = readFileDW();aviStreamHeader.fccHandler = readFileDW();aviStreamHeader.dwFlags = readFileDW();aviStreamHeader.wPriority = readFileW();aviStreamHeader.wLanguage = readFileW();aviStreamHeader.dwInitialFrames = readFileDW();aviStreamHeader.dwScale = readFileDW();aviStreamHeader.dwRate = readFileDW();aviStreamHeader.dwStart = readFileDW();aviStreamHeader.dwLength = readFileDW();aviStreamHeader.dwSuggestedBufferSize = readFileDW();aviStreamHeader.dwQuality = readFileDW();aviStreamHeader.dwSampleSize = readFileDW();aviStreamHeader.rcFrame.left = readFileW();aviStreamHeader.rcFrame.top = readFileW();aviStreamHeader.rcFrame.right = readFileW();aviStreamHeader.rcFrame.bottom = readFileW();// 跳过长度tmpOff += 4;tmpOff += aviStreamHeader.cb;}else if (fourcc == FOURCC_strf){int tmpLen = readFileDW();if (aviStreamHeader.fccType == FOURCC_vids){_hasVideo = true;_aviVideoStreamHeader = aviStreamHeader;_bitmapInfo.bmiHeader.biSize = readFileDW();_bitmapInfo.bmiHeader.biWidth = readFileDW();_bitmapInfo.bmiHeader.biHeight = readFileDW();_bitmapInfo.bmiHeader.biPlanes = readFileW();_bitmapInfo.bmiHeader.biBitCount = readFileW();_bitmapInfo.bmiHeader.biCompression = readFileDW();_bitmapInfo.bmiHeader.biSizeImage = readFileDW();_bitmapInfo.bmiHeader.biXPelsPerMeter = readFileDW();_bitmapInfo.bmiHeader.biYPelsPerMeter = readFileDW();_bitmapInfo.bmiHeader.biClrUsed = readFileDW();_bitmapInfo.bmiHeader.biClrImportant = readFileDW();if (tmpLen > _bitmapInfo.bmiHeader.biSize)fseek(_aviFd, tmpLen - _bitmapInfo.bmiHeader.biSize, SEEK_CUR);}else if (aviStreamHeader.fccType == FOURCC_auds){_hasAudio = true;_aviAudioStreamHeader = aviStreamHeader;_waveInfo.wFormatTag = readFileW();_waveInfo.nChannels = readFileW();_waveInfo.nSamplesPerSec = readFileDW();_waveInfo.nAvgBytesPerSec = readFileDW();_waveInfo.nBlockAlign = readFileW();_waveInfo.wBitsPerSample = readFileW();_waveInfo.cbSize = readFileW();fseek(_aviFd, _waveInfo.cbSize, SEEK_CUR);/*#include <mmreg.h>WAVE_FORMAT_PCMWAVE_FORMAT_ALAW*/}// 跳过长度tmpOff += 4;tmpOff += tmpLen;}else if (fourcc == FOURCC_JUNK){int tmpLen = readFileDW();fseek(_aviFd, tmpLen, SEEK_CUR);// 跳过长度tmpOff += 4;tmpOff += tmpLen;}else if (fourcc == FOURCC_vprp){int tmpLen = readFileDW();fseek(_aviFd, tmpLen, SEEK_CUR);// 跳过长度tmpOff += 4;tmpOff += tmpLen;}}off += avListLen + 8;}break;case FOURCC_JUNK:{// 跳过JUNKoff += 4;int tmpLen = readFileDW();fseek(_aviFd, tmpLen, SEEK_CUR);// 跳过长度off += 4;off += tmpLen;}break;}}}break;case FOURCC_INFO:{fourcc = readFileDW();if (fourcc == FOURCC_ISFT){int tmpLen = readFileDW();_soft.resize(tmpLen);readFile(&_soft[0], tmpLen);}}break;case FOURCC_movi:{_moviOff = ftell(_aviFd);if (hasIndex){// 跳过movi,直接到idx处fseek(_aviFd, size - 4, SEEK_CUR);}}break;}}else if (fourcc == FOURCC_idx1){_aviIndex.fcc = FOURCC_idx1;_aviIndex.cb = size;int tmpOff = 0;while (tmpOff < _aviIndex.cb){char tmpBuf[4] = {0};readFile(tmpBuf, 4);int index = read_le_dw(tmpBuf);AVIIndexEntry tmpEntry;tmpEntry.dwFlags = readFileDW();tmpEntry.dwOffset = readFileDW();tmpEntry.dwSize = readFileDW();if (tmpEntry.dwSize > _maxFrameSize)_maxFrameSize = tmpEntry.dwSize;// 视频数据if (tmpBuf[2] == 'd'){_aviIndex.videoIndexMap[index].push_back(tmpEntry);}else if (tmpBuf[2] == 'w'){_aviIndex.audioIndexMap[index].push_back(tmpEntry);}// 一个索引信息的长度tmpOff += 16;}}else if (fourcc == FOURCC_JUNK){// 跳过fseek(_aviFd, size, SEEK_CUR);}}}bool AVIFileParser::readFile( char* buf, uint32_t len ){uint32_t ret = fread(buf, 1, len, _aviFd);if (ret != len){if (feof(_aviFd) != 0)return true;#ifndef NPRINTprintf("fread avi error: %d [%s]\n", errno, strerror(errno));#endifthrow ERROR_INVALID_AVI;}return false;}bool AVIFileParser::readFileTagSize( DWORD& fourcc, uint32_t& size, DWORD& fourcc2 ){char tmpBuf[12] = {0};bool ret = readFile(tmpBuf, 12);fourcc = read_le_dw(tmpBuf);size = read_le_dw(tmpBuf + 4);fourcc2 = read_le_dw(tmpBuf + 8);return ret;}uint32_t AVIFileParser::readFileDW(){char tmpBuf[4] = {0};readFile(tmpBuf, 4);return read_le_dw(tmpBuf);}bool AVIFileParser::readFileDW( uint32_t& dw ){char tmpBuf[4] = {0};bool ret = readFile(tmpBuf, 4);dw = read_le_dw(tmpBuf);return ret;}uint16_t AVIFileParser::readFileW(){char tmpBuf[2] = {0};readFile(tmpBuf, 2);return read_le_w(tmpBuf);}bool AVIFileParser::readFileW( uint16_t& w ){char tmpBuf[2] = {0};bool ret = readFile(tmpBuf, 2);w = read_le_w(tmpBuf);return ret;}int32_t AVIFileParser::getVideoFrame( char* buf, int32_t index /*= -1*/ ){if (!_hasVideo)return -1;// 只取第一个std::vector<AVIIndexEntry>& videoVec = _aviIndex.videoIndexMap.begin()->second;int32_t tmpIndex = 0;if (index == -1){if (_currVideoIndex < videoVec.size())tmpIndex = _currVideoIndex++;elsereturn 0;}elsetmpIndex = index;AVIIndexEntry& videoEntry = videoVec[tmpIndex];// 从movi结尾加上偏移后是dc db的数据,然后再跳过4字节的一个长度值fseek(_aviFd, _moviOff + videoEntry.dwOffset + 4, SEEK_SET);int32_t ret = fread(buf, 1, videoEntry.dwSize, _aviFd);assert(ret == videoEntry.dwSize);return ret;}bool AVIFileParser::seekVideoFrame( int32_t index ){std::vector<AVIIndexEntry>& videoVec = _aviIndex.videoIndexMap.begin()->second;if (index < videoVec.size()){_currVideoIndex = index;return true;}return false;}
转载请标明出处:http://blog.csdn.net/jwybobo2007/article/details/7662653
- linux下avi文件解析(附源码)
- linux下avi文件解析(附源码)
- linux下avi文件解析(附源码)
- linux下avi文件解析(附源码)
- linux下avi文件解析
- AVI文件格式解析+AVI文件解析工具
- AVI文件格式解析+AVI文件解析工具
- avi文件解析
- riff,avi文件解析
- AVI文件解析
- AVI文件分析解析
- AVI 文件解析
- AVI文件详细解析
- AVI文件在opencore框架下的解析
- AVI文件在opencore框架下的解析
- linux下用/proc/stat文件来计算cpu的利用率(附源码)
- linux下用/proc/stat文件来计算cpu的利用率(附源码)
- linux下用/proc/stat文件来计算cpu的利用率(附源码)
- 安装httpd服务器提示APR not found的解决办法
- 验证手机号
- linux work with win
- 内联汇编优化的TAlpha::Mask 部分汇编
- std::string 与 std::wstring 转换方法的效率比较
- linux下avi文件解析(附源码)
- Vim修改键盘映射
- string 与 LPTSTR 转换
- Pinterest:物的关系网
- 灵活运用ReentrantLock及volatile构造线程安全的CopyOnWriteArrayList
- Buffer busy wiats系列 --详细
- 创建Java线程池
- Objective-C语法之static关键字的那些事儿(六)
- ext store 过滤方法