mp4v2在VS2010下的编译与在项目中的使用
2013-11-15 10:37
295 查看
最近做项目需要将H264文件封装为mp4文件,从网上找到了MP4V2库,下载下来后不知道从何下手,官方网站https://code.google.com/p/mp4v2/在windows下的编译过程介绍的很简短,对刚刚开始使用VS2010做大型项目的人来说,实在是有些无力。于是从网上找到了下面几篇博客文章,亲测可用,留下来以备查看。
1.mp4v2 库在VS2010下的编译过程
注:此段内容参考自http://blog.csdn.net/elinchen88/article/details/7987284
Mp4v2 一开始是与mpeg4ip这个开源项目捆绑在一起的,现在已经脱离mpeg4ip以一个单独的库存在着。Mp4v2库提供了一些API用来创建修改MP4文件。
源码在http://mp4v2.googlecode.com/svn/trunk/,首先新建一个文件夹用来导入源码,创建文件夹后右键SVN checkout(需要预先在电脑上安装TortoiseSVN
客户端),在URL of repository 中填入http://mp4v2.googlecode.com/svn/trunk/这个网址,点击ok后导入代码,再把vstudio9.0\libmp4v2\Version.rc放入src文件夹下,然后在进入vstudio9.0目录下,用vs2008打开mp4v2.sln进行编译。编译libmp4v2,选择配置为release
win32,成功后,在bin\Windows-Win32\Release下会生成4个文件,lbmp4v2.lib、libmp4v2.dll、libmp4v2.pdb、libmp4v2.exp。这样就完成了。
备注:1.mp4v2的源码下载需要用到SVN客户端TortoiseSVN,官方网站上能下载的是linux平台下的代码。
2.此过程在VS2010下打开没有问题。
3.以后在你的项目中会用到lbmp4v2.lib、libmp4v2.dll这两个文件。
2.mp4v2库在VS2010中的使用
注:此处测试代码参考自http://blog.csdn.net/firehood_/article/details/8813587,作者代码写的很好,赞一个。此处只是把配置过程再详讲一下。原文如下:
最近需要将H264视频编码成MP4格式。研究了一下,一种方法是采用ffmpeg库,可以先将H264文件解码,再编码生成MP4文件,但这种方式效率较低,10M的视频可能需要几秒钟才能完成。另一种方式根据MP4文件协议直接将H264包封装成MP4格式,由于是直接基于MP4的封装,因而效率很高。H264可以很方便的封装成FLV文件,但MP4格式格式相对比较复杂,封装起来会比较麻烦。由于没时间研究MP4协议,在Google
Code上找到一个开源的MP4编解码库Mp4v2(https://code.google.com/p/mp4v2/),通过Mp4v2可以很方便的将H264编码成MP4格式文件。为了方便使用,基于该库封装了一个MP4Encoder类,MP4Encoder封装的接口如下。目前仅支持将H264文件或数据帧编码成MP4文件。
客户端调用示例代码:
MP4Encoder的完整代码如下:
MP4Encoder.cpp
备注:说说我的将此代码与mp4v2库结合的过程。
1) 在MP4v2源代码中有一个vstudio9.0目录,用VS2010打开mp4v2.sln,然后新建一个项目,项目类型选Win32控制台应用程序,名称可以写为Test264ToMp4,解决方案选择“添加到解决方案”即可。这样在vstudio9.0目录下,就会多了一个文件夹Test264ToMp4(当然,也可以新打开一个VS2010,新建个名字叫做Test264Mp4的工程,对应的解决方案名字自动为Test264ToMp4,只要在3)中配置好include、lib、dll即可)。
2) 在VS2010中,右击Test64ToMp4工程,添加->类,类名写为 CMP4Encoder,然后把上面MP4Encoder.h和MP4Encoder.cpp的代码拷贝到对应的文件中,main函数所在的文件需要重新写一个cpp,可起名为Test.cpp。步骤为:右击工程Test264ToMp4->添加->新建项,选择C++文件,名称写做Test.cpp,位置默认即可,然后将上面的“客户端调用示例代码”拷贝到此文件。
3)关键部分来了。将MP4V2类库添加到Test264ToMp4工程。
首先添加.h目录。需要将MP4V2开源软件包里面的include目录和vstudio9.0目录下的include目录添加到“附加包含目录”项中。如图所示:
此处最好路径位置最好用相对路径来代替,由于自己对这个还不怎么熟悉,先用绝对路径吧。
![](http://img.blog.csdn.net/20131115103153468?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWJzdW4yMDEw/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
然后添加libmp4v2.lib
方法:右击Test264ToMp4->属性->配置属性->链接器->常规,在“附加库目录”里点“编辑”,把第1步中编译好的libmp4v2.lib库所在的路径加上,如图:
![](http://img.blog.csdn.net/20131115103208968?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWJzdW4yMDEw/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
然后点击链接器下的“输入”,在“附加依赖项”中点“编辑”,写上libmp4v2.lib,如图:
![](http://img.blog.csdn.net/20131115103225015?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWJzdW4yMDEw/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
最后,将libmp4v2.dll拷贝到Test264ToMp4目录下即可。
3.测试过程
首先拷贝一个H264测试文件(后缀为.264)到Test264ToMp4文件夹下,测试文件可以从此处下载(http://blog.163.com/lvan100@yeah/blog/static/68117214201381485753386/)。右击Test264ToMp4,生成,然后运行即可生成.mp4文件,可以用VLC播放器打开看看。
4.总结
当要调用开源项目的库时,最重要的三个东西分别是include目录(里面存放了所需的.h文件)、编译后的动态链接库(.dll文件)和编译后的静态链接库文件(.lib)文件,只要这三个地方配好了,一般就能用了。当VS编译时,报错如找不到.h文件之类,就得看是不是include路径没写对,当出现link错误时,就得看.lib路径是否没写对。
1.mp4v2 库在VS2010下的编译过程
注:此段内容参考自http://blog.csdn.net/elinchen88/article/details/7987284
Mp4v2 一开始是与mpeg4ip这个开源项目捆绑在一起的,现在已经脱离mpeg4ip以一个单独的库存在着。Mp4v2库提供了一些API用来创建修改MP4文件。
源码在http://mp4v2.googlecode.com/svn/trunk/,首先新建一个文件夹用来导入源码,创建文件夹后右键SVN checkout(需要预先在电脑上安装TortoiseSVN
客户端),在URL of repository 中填入http://mp4v2.googlecode.com/svn/trunk/这个网址,点击ok后导入代码,再把vstudio9.0\libmp4v2\Version.rc放入src文件夹下,然后在进入vstudio9.0目录下,用vs2008打开mp4v2.sln进行编译。编译libmp4v2,选择配置为release
win32,成功后,在bin\Windows-Win32\Release下会生成4个文件,lbmp4v2.lib、libmp4v2.dll、libmp4v2.pdb、libmp4v2.exp。这样就完成了。
备注:1.mp4v2的源码下载需要用到SVN客户端TortoiseSVN,官方网站上能下载的是linux平台下的代码。
2.此过程在VS2010下打开没有问题。
3.以后在你的项目中会用到lbmp4v2.lib、libmp4v2.dll这两个文件。
2.mp4v2库在VS2010中的使用
注:此处测试代码参考自http://blog.csdn.net/firehood_/article/details/8813587,作者代码写的很好,赞一个。此处只是把配置过程再详讲一下。原文如下:
最近需要将H264视频编码成MP4格式。研究了一下,一种方法是采用ffmpeg库,可以先将H264文件解码,再编码生成MP4文件,但这种方式效率较低,10M的视频可能需要几秒钟才能完成。另一种方式根据MP4文件协议直接将H264包封装成MP4格式,由于是直接基于MP4的封装,因而效率很高。H264可以很方便的封装成FLV文件,但MP4格式格式相对比较复杂,封装起来会比较麻烦。由于没时间研究MP4协议,在Google
Code上找到一个开源的MP4编解码库Mp4v2(https://code.google.com/p/mp4v2/),通过Mp4v2可以很方便的将H264编码成MP4格式文件。为了方便使用,基于该库封装了一个MP4Encoder类,MP4Encoder封装的接口如下。目前仅支持将H264文件或数据帧编码成MP4文件。
class MP4Encoder { public: MP4Encoder(void); ~MP4Encoder(void); public: // open or creat a mp4 file. MP4FileHandle CreateMP4File(const char *fileName,int width,int height,int timeScale = 90000,int frameRate = 25); // wirte 264 metadata in mp4 file. bool Write264Metadata(MP4FileHandle hMp4File,LPMP4ENC_Metadata lpMetadata); // wirte 264 data, data can contain multiple frame. int WriteH264Data(MP4FileHandle hMp4File,const unsigned char* pData,int size); // close mp4 file. void CloseMP4File(MP4FileHandle hMp4File); // convert H264 file to mp4 file. // no need to call CreateMP4File and CloseMP4File,it will create/close mp4 file automaticly. bool WriteH264File(const char* pFile264,const char* pFileMp4); // Prase H264 metamata from H264 data frame static bool PraseMetadata(const unsigned char* pData,int size,MP4ENC_Metadata &metadata); };
客户端调用示例代码:
#include <stdio.h> #include "MP4Encoder\MP4Encoder.h" int main(int argc, char** argv) { MP4Encoder mp4Encoder; // convert H264 file to mp4 file mp4Encoder.WriteH264File("test.264","test.mp4"); }
MP4Encoder的完整代码如下:
/******************************************************************** filename: MP4Encoder.h created: 2013-04-16 author: firehood purpose: MP4编码器,基于开源库mp4v2实现(https://code.google.com/p/mp4v2/)。 *********************************************************************/ #pragma once #include "mp4v2\mp4v2.h" // NALU单元 typedef struct _MP4ENC_NaluUnit { int type; int size; unsigned char *data; }MP4ENC_NaluUnit; typedef struct _MP4ENC_Metadata { // video, must be h264 type unsigned int nSpsLen; unsigned char Sps[1024]; unsigned int nPpsLen; unsigned char Pps[1024]; } MP4ENC_Metadata,*LPMP4ENC_Metadata; class MP4Encoder { public: MP4Encoder(void); ~MP4Encoder(void); public: // open or creat a mp4 file. MP4FileHandle CreateMP4File(const char *fileName,int width,int height,int timeScale = 90000,int frameRate = 25); // wirte 264 metadata in mp4 file. bool Write264Metadata(MP4FileHandle hMp4File,LPMP4ENC_Metadata lpMetadata); // wirte 264 data, data can contain multiple frame. int WriteH264Data(MP4FileHandle hMp4File,const unsigned char* pData,int size); // close mp4 file. void CloseMP4File(MP4FileHandle hMp4File); // convert H264 file to mp4 file. // no need to call CreateMP4File and CloseMP4File,it will create/close mp4 file automaticly. bool WriteH264File(const char* pFile264,const char* pFileMp4); // Prase H264 metamata from H264 data frame static bool PraseMetadata(const unsigned char* pData,int size,MP4ENC_Metadata &metadata); private: // read one nalu from H264 data buffer static int ReadOneNaluFromBuf(const unsigned char *buffer,unsigned int nBufferSize,unsigned int offSet,MP4ENC_NaluUnit &nalu); private: int m_nWidth; int m_nHeight; int m_nFrameRate; int m_nTimeScale; MP4TrackId m_videoId; };
MP4Encoder.cpp
/******************************************************************** filename: MP4Encoder.cpp created: 2013-04-16 author: firehood purpose: MP4编码器,基于开源库mp4v2实现(https://code.google.com/p/mp4v2/)。 *********************************************************************/ #include "MP4Encoder.h" #include <string.h> #define BUFFER_SIZE (1024*1024) MP4Encoder::MP4Encoder(void): m_videoId(NULL), m_nWidth(0), m_nHeight(0), m_nTimeScale(0), m_nFrameRate(0) { } MP4Encoder::~MP4Encoder(void) { } MP4FileHandle MP4Encoder::CreateMP4File(const char *pFileName,int width,int height,int timeScale/* = 90000*/,int frameRate/* = 25*/) { if(pFileName == NULL) { return false; } // create mp4 file MP4FileHandle hMp4file = MP4Create(pFileName); if (hMp4file == MP4_INVALID_FILE_HANDLE) { printf("ERROR:Open file fialed.\n"); return false; } m_nWidth = width; m_nHeight = height; m_nTimeScale = 90000; m_nFrameRate = 25; MP4SetTimeScale(hMp4file, m_nTimeScale); return hMp4file; } bool MP4Encoder::Write264Metadata(MP4FileHandle hMp4File,LPMP4ENC_Metadata lpMetadata) { m_videoId = MP4AddH264VideoTrack (hMp4File, m_nTimeScale, m_nTimeScale / m_nFrameRate, m_nWidth, // width m_nHeight,// height lpMetadata->Sps[1], // sps[1] AVCProfileIndication lpMetadata->Sps[2], // sps[2] profile_compat lpMetadata->Sps[3], // sps[3] AVCLevelIndication 3); // 4 bytes length before each NAL unit if (m_videoId == MP4_INVALID_TRACK_ID) { printf("add video track failed.\n"); return false; } MP4SetVideoProfileLevel(hMp4File, 0x01); // Simple Profile @ Level 3 // write sps MP4AddH264SequenceParameterSet(hMp4File,m_videoId,lpMetadata->Sps,lpMetadata->nSpsLen); // write pps MP4AddH264PictureParameterSet(hMp4File,m_videoId,lpMetadata->Pps,lpMetadata->nPpsLen); return true; } int MP4Encoder::WriteH264Data(MP4FileHandle hMp4File,const unsigned char* pData,int size) { if(hMp4File == NULL) { return -1; } if(pData == NULL) { return -1; } MP4ENC_NaluUnit nalu; int pos = 0, len = 0; while (len = ReadOneNaluFromBuf(pData,size,pos,nalu)) { if(nalu.type == 0x07) // sps { // 添加h264 track m_videoId = MP4AddH264VideoTrack (hMp4File, m_nTimeScale, m_nTimeScale / m_nFrameRate, m_nWidth, // width m_nHeight, // height nalu.data[1], // sps[1] AVCProfileIndication nalu.data[2], // sps[2] profile_compat nalu.data[3], // sps[3] AVCLevelIndication 3); // 4 bytes length before each NAL unit if (m_videoId == MP4_INVALID_TRACK_ID) { printf("add video track failed.\n"); return 0; } MP4SetVideoProfileLevel(hMp4File, 1); // Simple Profile @ Level 3 MP4AddH264SequenceParameterSet(hMp4File,m_videoId,nalu.data,nalu.size); } else if(nalu.type == 0x08) // pps { MP4AddH264PictureParameterSet(hMp4File,m_videoId,nalu.data,nalu.size); } else { int datalen = nalu.size+4; unsigned char *data = new unsigned char[datalen]; // MP4 Nalu前四个字节表示Nalu长度 data[0] = nalu.size>>24; data[1] = nalu.size>>16; data[2] = nalu.size>>8; data[3] = nalu.size&0xff; memcpy(data+4,nalu.data,nalu.size); if(!MP4WriteSample(hMp4File, m_videoId, data, datalen,MP4_INVALID_DURATION, 0, 1)) { return 0; } delete[] data; } pos += len; } return pos; } int MP4Encoder::ReadOneNaluFromBuf(const unsigned char *buffer,unsigned int nBufferSize,unsigned int offSet,MP4ENC_NaluUnit &nalu) { int i = offSet; while(i<nBufferSize) { if(buffer[i++] == 0x00 && buffer[i++] == 0x00 && buffer[i++] == 0x00 && buffer[i++] == 0x01 ) { int pos = i; while (pos<nBufferSize) { if(buffer[pos++] == 0x00 && buffer[pos++] == 0x00 && buffer[pos++] == 0x00 && buffer[pos++] == 0x01 ) { break; } } if(pos == nBufferSize) { nalu.size = pos-i; } else { nalu.size = (pos-4)-i; } nalu.type = buffer[i]&0x1f; nalu.data =(unsigned char*)&buffer[i]; return (nalu.size+i-offSet); } } return 0; } void MP4Encoder::CloseMP4File(MP4FileHandle hMp4File) { if(hMp4File) { MP4Close(hMp4File); hMp4File = NULL; } } bool MP4Encoder::WriteH264File(const char* pFile264,const char* pFileMp4) { if(pFile264 == NULL || pFileMp4 == NULL) { return false; } MP4FileHandle hMp4File = CreateMP4File(pFileMp4,352,288); if(hMp4File == NULL) { printf("ERROR:Create file failed!"); return false; } FILE *fp = fopen(pFile264, "rb"); if(!fp) { printf("ERROR:open file failed!"); return false; } fseek(fp, 0, SEEK_SET); unsigned char *buffer = new unsigned char[BUFFER_SIZE]; int pos = 0; while(1) { int readlen = fread(buffer+pos, sizeof(unsigned char), BUFFER_SIZE-pos, fp); if(readlen<=0) { break; } readlen += pos; int writelen = 0; for(int i = readlen-1; i>=0; i--) { if(buffer[i--] == 0x01 && buffer[i--] == 0x00 && buffer[i--] == 0x00 && buffer[i--] == 0x00 ) { writelen = i+5; break; } } writelen = WriteH264Data(hMp4File,buffer,writelen); if(writelen<=0) { break; } memcpy(buffer,buffer+writelen,readlen-writelen+1); pos = readlen-writelen+1; } fclose(fp); delete[] buffer; CloseMP4File(hMp4File); return true; } bool MP4Encoder:: PraseMetadata(const unsigned char* pData,int size,MP4ENC_Metadata &metadata) { if(pData == NULL || size<4) { return false; } MP4ENC_NaluUnit nalu; int pos = 0; bool bRet1 = false,bRet2 = false; while (int len = ReadOneNaluFromBuf(pData,size,pos,nalu)) { if(nalu.type == 0x07) { memcpy(metadata.Sps,nalu.data,nalu.size); metadata.nSpsLen = nalu.size; bRet1 = true; } else if((nalu.type == 0x08)) { memcpy(metadata.Pps,nalu.data,nalu.size); metadata.nPpsLen = nalu.size; bRet2 = true; } pos += len; } if(bRet1 && bRet2) { return true; } return false; }
备注:说说我的将此代码与mp4v2库结合的过程。
1) 在MP4v2源代码中有一个vstudio9.0目录,用VS2010打开mp4v2.sln,然后新建一个项目,项目类型选Win32控制台应用程序,名称可以写为Test264ToMp4,解决方案选择“添加到解决方案”即可。这样在vstudio9.0目录下,就会多了一个文件夹Test264ToMp4(当然,也可以新打开一个VS2010,新建个名字叫做Test264Mp4的工程,对应的解决方案名字自动为Test264ToMp4,只要在3)中配置好include、lib、dll即可)。
2) 在VS2010中,右击Test64ToMp4工程,添加->类,类名写为 CMP4Encoder,然后把上面MP4Encoder.h和MP4Encoder.cpp的代码拷贝到对应的文件中,main函数所在的文件需要重新写一个cpp,可起名为Test.cpp。步骤为:右击工程Test264ToMp4->添加->新建项,选择C++文件,名称写做Test.cpp,位置默认即可,然后将上面的“客户端调用示例代码”拷贝到此文件。
3)关键部分来了。将MP4V2类库添加到Test264ToMp4工程。
首先添加.h目录。需要将MP4V2开源软件包里面的include目录和vstudio9.0目录下的include目录添加到“附加包含目录”项中。如图所示:
此处最好路径位置最好用相对路径来代替,由于自己对这个还不怎么熟悉,先用绝对路径吧。
然后添加libmp4v2.lib
方法:右击Test264ToMp4->属性->配置属性->链接器->常规,在“附加库目录”里点“编辑”,把第1步中编译好的libmp4v2.lib库所在的路径加上,如图:
然后点击链接器下的“输入”,在“附加依赖项”中点“编辑”,写上libmp4v2.lib,如图:
最后,将libmp4v2.dll拷贝到Test264ToMp4目录下即可。
3.测试过程
首先拷贝一个H264测试文件(后缀为.264)到Test264ToMp4文件夹下,测试文件可以从此处下载(http://blog.163.com/lvan100@yeah/blog/static/68117214201381485753386/)。右击Test264ToMp4,生成,然后运行即可生成.mp4文件,可以用VLC播放器打开看看。
4.总结
当要调用开源项目的库时,最重要的三个东西分别是include目录(里面存放了所需的.h文件)、编译后的动态链接库(.dll文件)和编译后的静态链接库文件(.lib)文件,只要这三个地方配好了,一般就能用了。当VS编译时,报错如找不到.h文件之类,就得看是不是include路径没写对,当出现link错误时,就得看.lib路径是否没写对。
相关文章推荐
- C++箴言:避免构造或析构函数中调用虚函数
- Installshield Major upgrade
- 开发者如何提升技能水平
- 函数调用的几个概念:_stdcall,_cdecl....
- 在函数前面加上WINAPI、CALLBACK等是什么意思
- 做程序员之后才知道的 5 件惊奇事
- Am335x 之GPIO控制
- C++ 类的内建函数使用方法
- C# String.IndexOfAny 方法 (Char[])
- 最佳的 14 个免费的响应式 Web 设计测试工具
- css写三角形
- Android图片内存优化的几点心得
- 关于:问题和资料
- C# ListView的用法
- Outlook Expressh或IE不能打印
- hex,bin,axf,elf的区别
- 数据挖掘基础:相关性检验
- 汇编里面关于lea与mov的区别
- c++派生类转换为基类与public、protected、private继承的关系
- iOS 多机子测试ipa,无需越狱