Android framework源码MPEG4Writer.cpp学习

(frameworks/av/media/libstagefright/MPEG4Writer.cpp)

一、MPEG4Writer相关流程

MPEG4Writer是Android stagefright媒体框架下一个的封装类,录制视频调用的MediaRecorder接口类的底层封装实现通过它完成。

以视频为例,MPEG4Writer是视频录制的最后一环。

图 1 MediaRecorder调用流程

MPEG4Writer遵守 ISO 14496-12标准进行封装,MP4、3gp、ismv等我们常见的媒体封装格式都是以这种基础文件格式为基础衍生的。

Android系统录像封装流程主要有三个步骤:

1) 录制开始时,写入文件头部。

2) 录制进行时,实时写入音视频轨迹的数据块。

3) 录制结束时,写入索引信息并更新头部参数。

 

索引负责描述音视频轨迹的特征,会随着音视频轨迹的存储而变化,所以通常做法会将录像文件索引信息放在音视频轨迹流后面,在媒体流数据写完(录像结束)后才能写入。可以看到,存放音视频数据的mdat box是位于第二位的,而负责检索音视频的moov box是位于最后的,这与通常的MP4封装的排列顺序不同,当然这是为了符合录制而产生的结果。因为 moov的大小是随着 mdat 变化的,而我们录制视频的时间预先是不知道的,所以需要先将mdat 数据写入,最后再写入moov,完成封装。

现有Android系统上录像都是录制是MP4或3GP格式,底层就是使用MPEG4Writer组合器类来完成的,它将编码后的音视频轨迹按照MPEG4规范进行封装,填入各个参数,就组合成完整的MP4格式文件。MPEG4Writer的组合功能主要由两种线程完成,一种是负责音视频数据写入封装文件写线程(WriterThread,一种是音视频数据读取处理轨迹线程(TrackThread。轨迹线程一般有两个:视频轨迹数据读取线程和音频轨迹数据读取线程,而写线程只有一个,负责将轨迹线程中打包成Chunk的数据写入封装文件。

如图2所示,轨迹线程是以帧为单位获取数据帧(Sample),并将每帧中的信息及系统环境信息提取汇总存储在内存的trak表中,其中需要维持的信息有Chunk写入文件的偏移地址Stco(Chunk Offset)、Sample与Chunk的映射关系Stsc(Sample-to-Chunk)、关键帧Stss(Sync Sample)、每一帧的持续时间Stts(Time-to-Sample&

封装了开源工程, mp4v2, mpeg4ip代码, /******************************************/ /* Name:Mp4Interface.h /* Mark:mp4封装解析接口 /* author: machh /* date:2012.5.12. /******************************************/ #ifndef _MP4_INTERFACE_ #define _MP4_INTERFACE_ #include "MP4Writer.h" #include "MP4Reader.h" typedef struct _tagPACKET_HEADER_ { _tagPACKET_HEADER_() { nType = 0; nLen = 0; nTime = 0; } unsigned long nTime; // 不依赖于I帧的参考时间 int nLen; // 不包括该头结构本身大小 int nType; }PACKET_HEADER; enum FILE_OPEN_MODEL { OPEN_MODEL_W, // 写文件 OPEN_MODEL_R // 读文件 r+b }; class Mp4Interface { public: Mp4Interface(void); ~Mp4Interface(void); public: /* * @mark 打开文件 * @param[in] nModel文件打开方式,如果nModel为OPEN_MODEL_W 则创建文件 * @param[in] nMediaType 值为 MP4_VIDEOTYPE_H264/MP4_VIDEOTYPE_MPEG4 * @return 操作结果 */ int OpenFile(const char* strPath, FILE_OPEN_MODEL nModel, int nMediaType ); /* * @Name:Close * @mark: 读写操作结束之后,必须调用此函数 */ int Close(); public: //写操作 /* * @mark: 添加视频轨道 * @param[out] nTrackId 轨道ID * @param[in] nWidth,nHeight 画面宽高 * @param[out] fps 帧率 */ int AddVideoTrack (int& nTrackId, const int nWidth, const int nHeight, const double fps ); /* * @mark: 写一帧数据 * @param[in] lpData 要写入的数据 * @param[in] nSize 要写入的数据大小 * @param[in] nTimestamp 时间戳 */ BOOL WriteFrame( const int nTrackId, const uint8_t* const lpData, const int nSize, const MP4Timestamp nTimestamp, const MP4Duration nDuration = -1 ); /* * @mark: 添加音频轨道 aac * @param[out] nTrackId * @param[in] nSamplePerSec (timescale) */ int AddAudioTrack( int& nTrackId, const int nSamplePerSec, const int nSamplePerFrame = -1 ); public: //读操作 /* * @mark : 全局函数,读取整个MP4文件结构信息, * 函数内部会fopen/fclose,该函数应当在OpenFile之前调用 * @param[in] strFile 文件路径 * @param[out] lsTrackInfo 输出文件信息结构 */ bool static GetMP4FileInfo( const char* strFile, MP4_TRACKINFO_LIST& lsTrackInfo ); /* * @mark:SetReadTrackId设置轨道ID, */ int SetReadTrackId( int nTrackID ); /* * @mark:获取轨道信息,该函数必须在OpenFile(……)之后调用才有效 */ int GetTrackInfo( MP4_TRACK_INFO* pstTrackInfo ); /* * @mark: 读取一帧数据 */ int ReadFrameData( DWORD nSampleId, BYTE** ppFrame, DWORD* pnBufSize,int& nFrameType ); protected: int m_nOpenModel; int m_nMediaType; CMP4Writer * m_pMp4Writer; CMP4Reader * m_pMp4Reader; }; #endif// end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值