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


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 5s用不了4g网络怎么办 红米手机返回键没了怎么办 小米手机进水了开不了机怎么办 手机返回键和菜单键失灵怎么办 苹果5s指纹按键坏了怎么办 小米手机安卓系统耗电量大怎么办? 苹果5s充不进去电怎么办 苹果手机6s返回键失灵怎么办 本人被骗同时被利用骗了别人怎么办 京东取消订单后货到了该怎么办 京东电信日租卡流量顶置了怎么办 苹果6s进水后闪光灯不亮怎么办 华为手机情景义停车事项过期怎么办 拼多多付款后商品下架了怎么办 淘宝上买化妆品买到假货了怎么办 找苹果官网解id发票丢了怎么办 客人已交订金但要取消宴席怎么办 京东买的小米电视碎屏了怎么办 京东购买的电视碎屏了怎么办 淘宝上买手机不能用不给退怎么办 天猫申请退货退款卖家不处理怎么办 在淘宝买到货到付款的假苹果怎么办 跟朋友买手机买到假货怎么办 在淘宝网上买到不合格的产品怎么办 淘宝打假师打了我的店铺怎么办 收藏品公司关门跑路员工怎么办 客户快递签收后说货物短缺怎么办 京东商城买东西商家不换货怎么办 在商场买东西过几天就降价了怎么办 天猫买东西不退货不退款怎么办 买买8p美版的怎么办 京东金条银行卡被冻结还不了怎么办 在瑞士刚买的浪琴手表不走了怎么办 刚买的手表表镜有划痕 怎么办 唯品会上买的手表有质量问题怎么办 我买的对方材料没开票给我怎么办 给对方修完车车主不给发票怎么办 买苹果手机花呗额度不够怎么办 苹果手机用别人的手机卡激活怎么办 小米商城花呗分期额度不够怎么办 淘宝已经形成订单商家不发货怎么办