H264视频编码成MP4文件
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;
- }
- 顶
- 7
- 踩
- 0
- 上一篇H264视频通过RTMP直播
- 下一篇Apache用户名和密码验证
- • H264视频编码成MP4文件
- • Android 的视频编码 H263 MP4V H264
- • 文章【Android 的视频编码 H263 MP4V H264】的代码实现
- • 视频编码与封装方式详解
- • mp4v2再学习 -- H264视频编码成MP4文件(转)
- • H264编码 封装成MP4格式 视频流 RTP封包
- • 各种音视频编解码学习详解 h264 ,mpeg4 ,aac 等所有音视频格式
- • 音视频编解码 文件格式 协议内容详解
- • h264视频编码的MP4格式视频无法在网页中的adobe flash player中播放
- • Mp4v2实现h264+aac打包成Mp4视频文件
- 猜你在找
- 机器学习之概率与统计推断
- 机器学习之数学基础
- 机器学习之凸优化
- 机器学习之矩阵
- 响应式布局全新探索
- 探究Linux的总线、设备、驱动模型
- 深度学习基础与TensorFlow实践
- 深度学习之神经网络原理与实战技巧
- 前端开发在线峰会
- TensorFlow实战进阶:手把手教你做图像识别应用
- 8楼 qq_35409547 2016-06-28 15:23发表 [回复]
-
你好,我想将WriteH264Data中的指针pData里的内容写出来,请问怎么写,在哪儿添加语句?
- Re: linux_day 2017-04-20 11:47发表 [回复]
- 回复qq_35409547: 你搞好了吗,能读到一个单元的码流吗
- 7楼 独钓_寒江雪 2016-05-12 11:29发表 [回复]
- lz,我转换的MP4文件没有图像显示,问下怎么解决,新手
- 6楼 tanjibao 2016-04-27 17:35发表 [回复]
- 楼主,不知道你做过live555MediaServer的流媒体服务中添加MP4格式的转发没?希望求教
- 5楼 请叫我小清新 2014-10-11 11:26发表 [回复]
-
为何我调用后使用播放器播放只有两秒就没了?
- Re: linux_day 2017-04-20 13:19发表 [回复]
- 回复请叫我小清新:代码能用吗,H264的流都写不进去
- Re: hmge 2016-01-23 11:29发表 [回复]
- 同问啊 我也出现这样问题
- 4楼 qq529633582 2014-07-15 20:35发表 [回复]
- ffmpeg加上-vcodec copy -acodec copy取消编解码过程可以秒转的
- 3楼 weiwei22844 2014-02-26 10:43发表 [回复]
- 不错,很好的入门介绍,我已在自己的工程中用上!
- 2楼 Renuvb 2013-12-02 15:35发表 [回复]
-
版主你好,我用这个代码进行格式转换时,提示 mp4v2::impl::MP4File::FindTrakAtomIndex: Track id 0 doesn't exist
这个是什么原因呢?- Re: ybsun2010 2013-12-05 09:38发表 [回复]
-
回复Renuvb:你好。我也遇到了这个问题。我找到的原因是用x264编码后的h264文件开始有一段x264的版权声明,你用记事本打开该h264文件就能看到了。用其他方式编码的h264就没有版权声明,可以直接转换成功
- Re: 齐达内的神话 2014-05-14 22:23发表 [回复]
-
回复ybsun2010:请问你是如何解决的呢?我也碰到了这个问题,谢谢。
- Re: lcyw 2015-09-28 12:18发表 [回复]
- 回复齐达内的神话:x264_sei_version_write() 注释掉这个函数
- Re: ybsun2010 2014-05-16 08:41发表 [回复]
- 回复齐达内的神话:首先,重新编译一下x264库,设置里面的一个参数,就是不要生产版权声明,具体的参数你搜下,我忘了;这样生成的h264文件里面最前面是00 00 00 01 06,紧跟着是sps,你在WriteH264File函数中把 fseek(fp, 0, SEEK_SET); 改为fseek(fp, 5, SEEK_SET);就行了。这样就是从sps开始读了
- 1楼 ybsun2010 2013-11-14 21:05发表 [回复]
- 你好,我正在做将h264转换为mp4的项目。请问在vs2010下编译完了mp4v2后怎么加入到你的这个工程中呢?谢谢了
H264视频编码成MP4文件相关推荐
- mp4v2再学习 -- H264视频编码成MP4文件
一.H264视频编码成MP4文件 参看:H264视频编码成MP4文件 参看:mp4v2在VS2010下的编译与在项目中的使用 最近做项目需要将H264文件封装为mp4文件,从网上找到了MP4V2库,下 ...
- 使用mp4v2将aac音频h264视频数据封装成mp4开发心得
这阵子在捣鼓一个将游戏视频打包成本地可播放文件的模块.开始使用avi作为容器,弄了半天无奈avi对aac的支持实在有限,在播放时音视频时无法完美同步. 关于这点avi文档中有提到: For AAC, ...
- 工具---《.264视频 转成 MP4视频》
<.264视频 转成 MP4视频> 安装了"爱奇艺万能播放器"可以打开.264视频,但是opencv却不能直接读取.264视频,还是需要想办法".264视频 ...
- 【Python网络爬虫实战篇】使用selenium+requests爬取下载高清源视频:关于爬取m3u8文件链接解析为ts视频合并成mp4视频的分析实战
这两天博主在摸鱼时,偶然间接触到了流媒体的概念,一时间来了兴致.再加上之前博主有着七.八年的视频制作经验,深知视频素材获取的不易.因此,打算利用自己所学的python网络爬虫的知识,通过编写代码实现获 ...
- 怎么把video文件改成mp4_如何把视频转换成mp4格式?
要想把视频转换成mp4格式,这就看你原视频是什么格式了.这里推荐一个视频格式转换类型比较齐全的一款. 烁光视频转换器烁光视频转换器www.ivideotools.com 专业视频格式转换器,支持视频 ...
- 怎么把video文件改成mp4_腾讯视频文件怎么转换格式_如何把腾讯视频转换成mp4格式-win7之家...
视频软件不一样,视频的格式也会不一样,比如qlv视频格式是腾讯视频的独有格式,想要观看qlv格式的视频文件,就只能下载腾讯视频播放器,但是这样显得有点麻烦,其实我们也可以对腾讯视频文件转换格式,比如转 ...
- mov格式的视频转换成mp4,教你3种快速方法来处理
怎么把mov格式的视频转换成mp4?有这样疑问的朋友,我相信不在少数.为什么这么说呢?因为现在是短视频时代,人们接触视频的机会非常多,当然也会遇到mov格式.MOV格式:可以用QuickTime,包括 ...
- b站电脑客户端_如何将B站的flv格式的视频转换成mp4格式
经常看到B站有精彩的视频片段,于是想把这些视频下载保存到电脑,但是发现没有下载按钮,是不是很悲催.有些时候想从优酷.土豆网这些视频网站下载视频,结果却提示要先下载视频客户端才能继续下载视频,运气差的话 ...
- 如何快速不借用转换工具将FLV格式视频转换成MP4
FLV流媒体格式是一种新的视频格式,全称为Flash Video.它的出现有效地解决了视频文件导入Flash后,使导出的SWF文件体积庞大,所以就引出了FLV格式,主要特点就是体积小 适合作为流媒体在 ...
最新文章
- 报错android.view.InflateException: Binary XML file line #11: Attempt to invoke virtual method 'boolean
- java子类对象不能调用父类protected方法和域的原因。
- C++ Primer 5th笔记(chap 15 OOP)继承中的类作用域
- 从Q3财报看百度营销成长
- win7 64 iis7+access ADODB.Connection 错误 '800a0e7a'
- win和linux创建共享文件夹,在Windows和Linux下(Debian、Ubuntu)创建共享文件夹
- python计算n到n+100之间所有奇数的和_Python基本操作题
- 《VMware vSphere设计(原书第2版)》——1.1 什么是设计
- okhttp3 请求html页面,OkHttp3源码详解(二) 整体流程
- LeetCode 673. 最长递增子序列的个数(DP)
- 轨迹相似性度量方法总结
- 沉痛哀悼在汶川特大地震中的遇难者!!!!!
- 月薪20k的web前端开发程序员,他们都会的这6招
- Facebook的秘密服务器,竟藏着互联网的军事根源?
- Arcgis server——arcgis server manager忘记密码
- 一个类似京东商城那种多条件筛选效果
- 联想Y9000P安装Ubuntu20.04记录
- Web前端的优点有哪些?为什么Web前端可以如此火爆?
- 压力测试软件 loadr,初学abench压力测试 - 玄大冰 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
- python连乘函数_(Python3) 连加 连乘 代码