生活随笔
收集整理的這篇文章主要介紹了
mp4v2再学习 -- H264视频编码成MP4文件
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、H264視頻編碼成MP4文件
參看:H264視頻編碼成MP4文件
參看:mp4v2在VS2010下的編譯與在項目中的使用
最近做項目需要將H264文件封裝為mp4文件,從網上找到了MP4V2庫,下載下來后不知道從何下手,官方網站https://code.google.com/p/mp4v2/在windows下的編譯過程介紹的很簡短,對剛剛開始使用VS2010做大型項目的人來說,實在是有些無力。于是從網上找到了下面幾篇博客文章,親測可用,留下來以備查看。
(1)mp4v2 庫在VS2017下的編譯過程
? ? 注:此段內容參考:編譯MP4v2
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 文件夾下。
上面的內容其實就是獲取 MP4V2 源碼。上面兩個谷歌網站沒有進入,原因你懂的。可從 CSDN 下載。
下載:mp4v2最新源碼
然后在進入 vs2013 目錄下,用 vs2017 打開 mp4v2.sln 。選擇配置為 release win32,成功后,編譯 libmp4v2。
在 mp4v2-master\buildwin\lib.vs2013\Win32\Release 下會生成 4 個文件,lbmp4v2.lib、libmp4v2.dll、libmp4v2.pdb、libmp4v2.exp。這樣就完成了。
備注:
1. mp4v2 的源碼下載需要用到 SVN 客戶端 TortoiseSVN,官方網站上能下載的是 Linux 平臺下的代碼。
Linux下安裝編譯之前有講,參看:mp4v2再學習 -- mp4v2 安裝說明
2. 此過程在 VS2017 下打開沒有問題。
3. 以后在你的項目中會用到 lbmp4v2.lib、libmp4v2.dll 這兩個文件。
上面的操作有幾處需要注意的:
(1)首先選擇配置為 release win32,這個該如何配置?
配置方法:生成->配置管理器,然后將 libmp4v2 配置改為 Release?
(2)問題分析
出現 無法打開包括文件: “corecrt.h”
解決方法,參看:VS2015無法打開包括文件corecrt.h
簡單來說就是按如下圖,把里面的 10.0.15063.0 文件復制一份,重命名成 10.0.10240.0
(2)mp4v2庫在VS2010中的使用
注:此處測試代碼參考:H264視頻編碼成MP4文件,作者代碼寫的很好,贊一個。此處只是把配置過程再詳講一下。
原文如下:
最近需要將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文件。
[cpp]?view plaincopy
class?MP4Encoder????{????public:????????MP4Encoder(void);????????~MP4Encoder(void);????public:??????????????MP4FileHandle?CreateMP4File(const?char?*fileName,int?width,int?height,int?timeScale?=?90000,int?frameRate?=?25);??????????????bool?Write264Metadata(MP4FileHandle?hMp4File,LPMP4ENC_Metadata?lpMetadata);??????????????int?WriteH264Data(MP4FileHandle?hMp4File,const?unsigned?char*?pData,int?size);???????????????void?CloseMP4File(MP4FileHandle?hMp4File);????????????????????bool?WriteH264File(const?char*?pFile264,const?char*?pFileMp4);??????????????static?bool?PraseMetadata(const?unsigned?char*?pData,int?size,MP4ENC_Metadata?&metadata);????};?????客戶端調用示例代碼:
[cpp]?view plaincopy
#include?<stdio.h>????#include?"MP4Encoder.h"????????int?main(int?argc,?char**?argv)????{????????MP4Encoder?mp4Encoder;??????????????mp4Encoder.WriteH264File("test.264","test.mp4");????}????MP4Encoder的完整代碼如下:[cpp]?view plaincopy
?????????#pragma?once????#include?"mp4v2\mp4v2.h"??????????typedef?struct?_MP4ENC_NaluUnit????{????????int?type;????????int?size;????????unsigned?char?*data;????}MP4ENC_NaluUnit;????????typedef?struct?_MP4ENC_Metadata????{??????????????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:??????????????MP4FileHandle?CreateMP4File(const?char?*fileName,int?width,int?height,int?timeScale?=?90000,int?frameRate?=?25);??????????????bool?Write264Metadata(MP4FileHandle?hMp4File,LPMP4ENC_Metadata?lpMetadata);??????????????int?WriteH264Data(MP4FileHandle?hMp4File,const?unsigned?char*?pData,int?size);???????????????void?CloseMP4File(MP4FileHandle?hMp4File);????????????????????bool?WriteH264File(const?char*?pFile264,const?char*?pFileMp4);??????????????static?bool?PraseMetadata(const?unsigned?char*?pData,int?size,MP4ENC_Metadata?&metadata);????private:??????????????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[cpp]?view plaincopy
?????????#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,int?frameRate)????{????????if(pFileName?==?NULL)????????{????????????return?false;????????}??????????????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,???????????m_nHeight,??????????lpMetadata->Sps[1],???????????lpMetadata->Sps[2],???????????lpMetadata->Sps[3],???????????3);?????????????????if?(m_videoId?==?MP4_INVALID_TRACK_ID)????????{????????????printf("add?video?track?failed.\n");????????????return?false;????????}????????MP4SetVideoProfileLevel(hMp4File,?0x01);?????????????????MP4AddH264SequenceParameterSet(hMp4File,m_videoId,lpMetadata->Sps,lpMetadata->nSpsLen);??????????????????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)???????????{??????????????????????????????m_videoId?=?MP4AddH264VideoTrack????????????????????(hMp4File,?????????????????????m_nTimeScale,?????????????????????m_nTimeScale?/?m_nFrameRate,?????????????????????m_nWidth,???????????????????????m_nHeight,??????????????????????nalu.data[1],???????????????????nalu.data[2],???????????????????nalu.data[3],???????????????????3);?????????????????????????if?(m_videoId?==?MP4_INVALID_TRACK_ID)????????????????{????????????????????printf("add?video?track?failed.\n");????????????????????return?0;????????????????}????????????????MP4SetVideoProfileLevel(hMp4File,?1);???????????????????MP4AddH264SequenceParameterSet(hMp4File,m_videoId,nalu.data,nalu.size);????????????}????????????else?if(nalu.type?==?0x08)???????????{????????????????MP4AddH264PictureParameterSet(hMp4File,m_videoId,nalu.data,nalu.size);????????????}????????????else????????????{????????????????int?datalen?=?nalu.size+4;????????????????unsigned?char?*data?=?new?unsigned?char[datalen];??????????????????????????????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;????}????
其實講 ffmpeg 時就已經講了VS 開發環境搭建。參看:ffmpeg再學習 -- Windows下安裝說明
好吧,那我再講一遍。。
(1)新建項目
打開 VS;文件->新建->項目->Win32控制臺應用程序->選擇空項目,點擊完成。注意,選擇的位置最好不要有 空格或者漢字。
(2)拷貝考法文件
頭文件( *.h)拷貝至項目文件夾的 include 子文件夾下
導入庫文件( *.lib)拷貝至項目文件夾的 lib 子文件夾下
動態庫文件( *.dll) 拷貝至項目文件夾下
這三組文件具體是,mp4v2-master文件夾下的 include 文件夾 和?mp4v2-master\buildwin\lib.vs2013\Win32\Release 文件夾下的?libmp4v2.lib 和?libmp4v2.dll
點擊右鍵,選擇在資源管理器中打開文件夾,進入項目目錄。(注意,如果手動進入注意文件夾位置,我就是沒找好位置,試了半天最后才發現,將上面的這些文件拷貝到錯誤的文件夾下了)
放置完成即下圖:(3)添加代碼右擊 MP4Encoder 工程,添加->類
雙擊 C++類 進入 一般 C++類向導,類名寫為 CMP4Encoder ,然后把上面 MP4Encoder.h 和MP4Encoder.cpp 的代碼拷貝到對應的文件中。右擊工程?MP4Encoder?->添加->新建項選擇C++文件,名稱寫做 main.cpp,位置默認即可,然后將上面的“客戶端調用示例代碼”拷貝到此文件。
(4)配置開發文件打開屬性面板
解決方案資源管理器->右鍵單擊項目->屬性
頭文件配置
配置屬性->C/C++->常規->附加包含目錄,輸入“ include”(剛才拷貝頭文件的目錄)
導入庫配置
配置屬性->鏈接器->常規->附加庫目錄,輸入“ lib” (剛才拷貝庫文件的目錄)
配置屬性->鏈接器->輸入->附加依賴項,輸入?libmp4v2.lib;
動態庫不用配置
(5)測試
首先拷貝一個 H264 測試文件 (后綴為.264) 到 MP4Encoder 文件夾下。
測試文件可以從此處,下載:[開源世界]分享H.264視頻文件下載地址?
注意,需要將該264文件,重命名為 test.h264,否則生成的 MP4 文件大小為1K。
或者你更改主函數:
然后點擊本地Windows調試器,出現此項目已經過期,選擇 是。
即可生成 test.mp4 文件,可以用VLC播放器打開看看。
不過生成文件時會出現,無法查找或打開 PDB 文件。如下圖:
它對于生成文件沒有影響的。如果看著不舒服,可參看:無法查找或打開 PDB 文件解決辦法
這是我寫的工程文件:MP4Encoder 工程文件
二、工程文件(可用)
講了這么多,你發現沒有上面這個例子只是將 H264 視頻編碼成MP4文件,缺少音頻啊親。
下面這個即音視頻編碼轉MP4文件的例子,下載:MP4v2 -- h264 轉 MP4
總結
以上是生活随笔為你收集整理的mp4v2再学习 -- H264视频编码成MP4文件的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。