使用mp4v2封装mp4

编译环境:Ubuntu16.04 64位
交叉编译工具:arm-hisiv500-linux-gcc

1. 交叉编译mp4v2

下载合适版本的mp2v2源码,我下载的是2.0.0的bz包mp4v2_2.0.0~dfsg0.orig.tar.bz2

tar jxf mp4v2_2.0.0~dfsg0.orig.tar.bz2
cd mp4v2-2.0.0;./configure --host=arm-hisiv500-linux CC=arm-hisiv500-linux-gcc CXX=arm-hisiv500-linux-g++ --disable-debug
make

生成的libmp4v2.a在目录.libs
头文件位于include/mp4v2目录,头文件需要拷贝完全,代码中仅需要包含mp4v2.h

#include "mp4v2/mp4v2.h"

注意:移植后,链接libmp4v2.a需要加上-lstdc++选项。

2. sample代码

注意:代码基于hi3519平台。

2.1 创建文件

MP4FileHandle hMP4File = MP4CreateEx(fileName, 0, 1, 1, 0, 0, 0, 0);
MP4SetTimeScale(hMP4File, 90000);

2.2 关闭文件

MP4Close(hMP4File, 0);

2.3 写数据

typedef struct _MP4ENC_NaluUnit
{
	int type;
 	int size;
 	unsigned char *data;
}MP4ENC_NaluUnit;

typedef struct _MP4ENC_INFO
{
 	unsigned int u32FrameRate;
	unsigned int u32Width;
 	unsigned int u32Height;
 	unsigned int u32Profile;
}MP4ENC_INFO;

static HI_S32 Sample_MP4_ReadNalu(HI_U8 *pPack, HI_U32 nPackLen, unsigned int offSet, MP4ENC_NaluUnit *pNaluUnit)
{
	int i = offSet;
	while (i < nPackLen)
	{
		if (pPack[i++] == 0x00 && pPack[i++] == 0x00 && pPack[i++] == 0x00 && pPack[i++] == 0x01)// 开始码
		{
			int pos = i;
			while (pos < nPackLen)
			{
				if (pPack[pos++] == 0x00 && pPack[pos++] == 0x00 && pPack[pos++] == 0x00 && pPack[pos++] == 0x01)
					break;
			}
			if (pos == nPackLen)
				pNaluUnit->size = pos - i;
			else
				pNaluUnit->size = (pos - 4) - i;
				
			pNaluUnit->type = pPack[i] & 0x1f;
			pNaluUnit->data = (unsigned char *)&pPack[i];
			return (pNaluUnit->size + i - offSet);
		}
	}
	return 0;
}

static HI_S32 Sample_MP4_WRITE(MP4FileHandle hFile, MP4TrackId *pTrackId,VENC_STREAM_S *pstStream, MP4ENC_INFO *stMp4Info)
{
	int i = 0;
	for (i = 0; i < pstStream->u32PackCount; i++)
	{
		HI_U8 *pPack = pstStream->pstPack[i].pu8Addr + pstStream->pstPack[i].u32Offset;
		HI_U32 nPackLen = pstStream->pstPack[i].u32Len - pstStream->pstPack[i].u32Offset;

		MP4ENC_NaluUnit stNaluUnit;
		memset(&stNaluUnit, 0, sizeof(stNaluUnit));
		int nPos = 0, nLen = 0;
		while ((nLen = Sample_MP4_ReadNalu(pPack, nPackLen, nPos, &stNaluUnit)) != 0)
		{
			switch (stNaluUnit.type)
			{
			case H264E_NALU_SPS:
			if (*pTrackId == MP4_INVALID_TRACK_ID)
     			{
      				*pTrackId = MP4AddH264VideoTrack(hFile, 90000, 90000 / stMp4Info->u32FrameRate, stMp4Info->u32Width, stMp4Info->u32Height, stNaluUnit.data[1], stNaluUnit.data[2], stNaluUnit.data[3], 3);
      				if (*pTrackId == MP4_INVALID_TRACK_ID)
     				{
       					return HI_FAILURE;
     				}
      				MP4SetVideoProfileLevel(hFile, stMp4Info->u32Profile);
      				MP4AddH264SequenceParameterSet(hFile,*pTrackId,stNaluUnit.data,stNaluUnit.size);
     			}
     			break;
			case H264E_NALU_PPS:
    			if (*pTrackId == MP4_INVALID_TRACK_ID)
     			{
      				break;
     			}
			MP4AddH264PictureParameterSet(hFile,*pTrackId,stNaluUnit.data,stNaluUnit.size);
			break;
			case H264E_NALU_IDRSLICE:
			case H264E_NALU_PSLICE:
			{
			if (*pTrackId == MP4_INVALID_TRACK_ID)
      			{
       				break;
      			}
			int nDataLen = stNaluUnit.size + 4;
      			unsigned char *data = (unsigned char *)malloc(nDataLen);
      			data[0] = stNaluUnit.size >> 24;
      			data[1] = stNaluUnit.size >> 16;
      			data[2] = stNaluUnit.size >> 8;
      			data[3] = stNaluUnit.size & 0xff;
      			memcpy(data + 4, stNaluUnit.data, stNaluUnit.size);
			if (!MP4WriteSample(hFile, *pTrackId, data, nDataLen, MP4_INVALID_DURATION, 0, 1))
      			{
       				free(data);
       				return HI_FAILURE;
      			}
			free(data);
			}
			break;
			default :
			break;
		}
		nPos += nLen;
		}
	}
	return HI_SUCCESS;
}

以上代码没有封装音频,可以稍作修改,用作其他平台。

mp4v2貌似不支持h265,后续将使用其他的开源库做封装,详见我的另一篇博客《使用gpac封装mp4》

转载请注明出处,如有错漏之处,敬请指正。

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值