首页 > 系统相关 >linux环境C语言实现:h264与pcm封装成mp4视频格式

linux环境C语言实现:h264与pcm封装成mp4视频格式

时间:2023-04-20 19:46:30浏览次数:41  
标签:aac h264 pConfiguration PCM C语言 int MP4 linux stPara

前言

H.264是压缩过的数据,PCM是原始数据,MP4是一种视频封装格式。实际H.264与PCM不能直接合成MP4格式,因为音频格式不对。这里需要中间对音频做一次压缩处理。基本流程为:将PCM音频数据压缩成AAC格式音频数据,再将AAC与H.264合成MP4视频格式。

(一)PCM压缩为AAC格式

直接上代码,接口函数的实现如下:

#include <stdio.h>
#include "faac.h"
#include "pcm2acc.h" 

int Hst_PCM_To_AAC(PCM_TO_MP4_PARA_S stPara)
{
	// 定义别名
	typedef unsigned char   BYTE;
	unsigned long	nSampleRate = 8000;
	unsigned int	nChannels = 1;
	unsigned int	nPCMBitSize = 16;
	unsigned long	nInputSamples = 0;
	unsigned long	nMaxOutputBytes = 0;
	faacEncHandle	hEncoder = {0};
 
	//nSampleRate = stPara.u64SampleRate;
	//nChannels   = stPara.u32Channels;
	//nPCMBitSize = stPara.u32PCMBitSize;


	FILE* fpIn = fopen(stPara.arrs8PCMFilename, "rb");
	FILE* fpOut = fopen(stPara.arrs8AACFilename, "wb");
	//FILE* fpIn = fopen("./ExportChannel0Audio.cpm", "rb");
	//FILE* fpOut = fopen("./test.aac", "wb");
 
	if(fpIn==NULL || fpOut==NULL)
	{
		printf("File Open error \n");
		return -1;
	}
 
	// 打开faac编码器引擎
	hEncoder = faacEncOpen(nSampleRate, nChannels, &nInputSamples, &nMaxOutputBytes);
	if(hEncoder == NULL)
	{
		printf("open faac encoder error !\n");
		return -1;
	}
 
	// 分配内存信息
	int		nPCMBufferSize = nInputSamples*nPCMBitSize/8;
	BYTE*	pbPCMBuffer = new BYTE[nPCMBufferSize];
	BYTE*	pbAACBuffer = new BYTE[nMaxOutputBytes];
 
	// 获取当前编码器信息
	faacEncConfigurationPtr pConfiguration = {0};
	pConfiguration = faacEncGetCurrentConfiguration(hEncoder);
 
	// 设置编码配置信息
	/*
		PCM Sample Input Format
		0	FAAC_INPUT_NULL			invalid, signifies a misconfigured config
		1	FAAC_INPUT_16BIT		native endian 16bit
		2	FAAC_INPUT_24BIT		native endian 24bit in 24 bits		(not implemented)
		3	FAAC_INPUT_32BIT		native endian 24bit in 32 bits		(DEFAULT)
		4	FAAC_INPUT_FLOAT		32bit floating point
    */
	pConfiguration->inputFormat = FAAC_INPUT_16BIT;
 
	// 0 = Raw; 1 = ADTS
	pConfiguration->outputFormat = 1;
 
	// AAC object types 
	//#define MAIN 1
	//#define LOW  2
	//#define SSR  3
	//#define LTP  4
	pConfiguration->aacObjectType = LOW;
	pConfiguration->allowMidside = 0;
	pConfiguration->useLfe = 0;
	pConfiguration->bitRate = 48000;
	pConfiguration->bandWidth = 32000;
 
	// 其他的参数不知道怎么配置,毕竟对音频不熟
	// 不过当前的设置可以实现转换,不过声音好像有一丢丢怪异
	// 这一块的配置信息很重要,错了会导致转码失败,然后你以为代码其他地方错了
 
	// 重置编码器的配置信息
	faacEncSetConfiguration(hEncoder, pConfiguration);
 
	size_t nRet = 0;
 
	printf("start data convert : \n");
	int i = 0;
	while( (nRet = fread(pbPCMBuffer, 1, nPCMBufferSize, fpIn)) > 0)
	{
		printf("\b\b\b\b\b\b\b\b%-8d", ++i);
		nInputSamples = nRet / (nPCMBitSize/8);
 
		// 编码
		nRet = faacEncEncode(hEncoder, (int*) pbPCMBuffer, nInputSamples, pbAACBuffer, nMaxOutputBytes);
 
		// 写入转码后的数据
		fwrite(pbAACBuffer, 1, nRet, fpOut);
	}
 
	// 扫尾工作
	faacEncClose(hEncoder);
	fclose(fpOut);
	fclose(fpIn);
 
	delete[] pbAACBuffer;
	delete[] pbPCMBuffer;
	
	return 0;
}


int main(void)
{
	PCM_TO_MP4_PARA_S l_stPara;
	
	Hst_PCM_To_AAC(l_stPara);
}

整个工程如下:

.
├── faac-1.29.9.2_ARM.tar.gz
├── faaccfg.h
├── faac.h
├── lib
│   ├── libfaac.a
│   ├── libfaac.la
│   ├── libfaac.so
│   ├── libfaac.so.0
│   └── libwisdom_aac.so
├── pcm2acc.cpp
├── pcm2acc.h
└── test.c

注意:我这些库是使用了海思的交叉编译,并不能直接在PC机上运行。如果需要在PC机上运行,需要自己重新编译库文件,这里只提供一种方法。完整工程下载路径:PCM音频转AAC格式

(二)H264与PCM合成MP4

这套代码是在网上下载的,初步使用并没发现其他的什么异常。他原来是用来做AVI转MP4和MP4转AVI的,中间的音频转换他们没有提供,于是我在这基础上做了一些修改,直接将h264与AAC合成MP4格式。主要代码如下:

int H264AacToMp4(H264_AAC_PARA stPara,char* mp4FilePath)
{
	int VIDEO_BUF_LEN = 327680;
	int AUDIO_BUF_LEN = 100000;
	CAviFmtInterface aviFormatInsatance;
	CMp4FmtInterface mp4FormatInsatance;
	int framew = stPara.u32VideoFrameW;
	int frameh = stPara.u32VideoFrameH;
	long framerate = stPara.u32VideoFrameRate;

	char * vidbuf = (char*)malloc(VIDEO_BUF_LEN);
    char * audbuf = (char*)malloc(AUDIO_BUF_LEN);
	if(vidbuf==NULL || audbuf==NULL)
	{
		return -1;
	}

	mp4FormatInsatance.OpenFile(mp4FilePath,OPEN_MODEL_W);
	mp4FormatInsatance.SetMp4Param((u_int16_t)framew,(u_int16_t)frameh,framerate);

	FILE *in_aac = NULL;
	FILE *in_h264 = NULL;

	in_aac = fopen(stPara.arrs8AACFileName,"rb");
	if(in_aac == NULL)
	{
		printf("Can't open the aac file\n");
		return -1;
	}
	
	in_h264 = fopen(stPara.arrs8H264FileName,"rb") ;
	if(in_h264== NULL)
	{
		printf("Can't open the h264 file\n");
		return -1;
	}

	//音频
	fseek(in_aac,0,SEEK_END);
	file_aac_length = ftell(in_aac);
	fseek(in_aac,0,SEEK_SET);
	if(file_aac_length == 0)
	{
		return -1;
	}

	//音频
	AACBUFFER aacbuffer;
	init_aac_buf(&aacbuffer);
	fread(aacbuffer.buf,1,AACBUFSIZE,in_aac);
	ADTS_HEADER adts_header;


	int idx = 0;
	int idxAudio = 0;

	while (1)//read and write avi per fream
	{
		init_adts_header(&adts_header);

		long readLen = 0;
		readLen = aviFormatInsatance.GetAnnexbNALU(in_h264, vidbuf);
		if(readLen<=0)
		{
			break;
		};
		
		if(!mp4FormatInsatance.WriteVideoFrameData((unsigned char*)vidbuf,readLen))
		{
			printf("Write video frame data fail. The frame index is:%05d.\n",idx);
		}
		idx++;	
	}
	
	idx = 0;
	while(1)
	{
		if(read_aac_frame(&aacbuffer,&adts_header))
		{
			if(!mp4FormatInsatance.WriteAudioFrameData((const unsigned char*)(adts_header.aac_frame_start-7),adts_header.aac_frame_length+7))//此接口需要的数据信息,需要包含7个字节的头信息
			{
				printf("error!\n");
				break;
			}
			idx++;
		}
		else
		{
			printf("Reach to the end of aac file!\n");
			break;
		}
	}

	mp4FormatInsatance.Close(); 
	
	if(NULL!=in_h264)
	{
		fclose(in_h264);
		in_h264 = NULL;
	}

	if(NULL!=in_aac)
	{
		fclose(in_aac);
		in_h264 = NULL;
	}

	free(vidbuf);
	free(audbuf);
	return 0;
}

代码结构如下:

.
├── avilib
├── AviToMp4.h
├── include
├── libwisdom_hi3520_avi2mp4.so
├── Makefile
├── mediaconvert
├── mp4file
├── mp4lib
├── Mp4ToAvi.h
├── obj
├── test.cpp
└── type.h

​在 liwen01 公众号中回复 音视频 获取工程代码,本章代码工程名为:MP4格式合成.zip

---------------------------End---------------------------
长按识别二维码
关注 liwen01 公众号
    

标签:aac,h264,pConfiguration,PCM,C语言,int,MP4,linux,stPara
From: https://www.cnblogs.com/liwen01/p/17338000.html

相关文章

  • linux环境C语言实现:h264与pcm封装成AVI格式
    ​前言拖了很久的AVI音视频封装实例,花了一天时间终于调完了,兼容性不是太好,但作为参考学习使用应该没有问题。RIFF和AVI以及WAV格式,可以参考前面的一些文章。这里详细介绍将一个H264视频流和一个2通道PCM音频流封装成一个AVI格式的视频文件。测试过可以在暴风,迅雷和VLC播放器上......
  • linux环境C语言实现:h265与pcm封装成AVI格式
    ​前言不知道是处于版权收费问题还是什么原因,H265现在也并没有非常广泛的被普及。将h265数据合成AVI的资料现在在网上也基本上没有。使用格式化工厂工具将h265数据封装成AVI格式,发现它在封装的时候其实是对数据进行了一个装换,转成了FMP4格式。正文因为是在嵌入式设备中使用,所......
  • linux设备树-设备树常用OF操作函数
    ----------------------------------------------------------------------------------------------------------------------------内核版本:linux5.2.8根文件系统:busybox1.25.0u-boot:2016.05-------------------------------------------------------------------------------......
  • Linux设备节点创建方式的演变历史
    引子  遵从"Everythingisafile"的思想,在Linux下想要操作设备的话,是需要通过一类叫做设备节点(devicenode)的特殊文件。设备节点通常位于/dev这个目录下,但是位于其它目录也是可以的。只要翻开一本介绍Linux驱动的书,或者在网上搜索相关的文章,很大概率上会教你在写好驱动代码后......
  • Linux入门二
    目录一、磁盘管理二、文件挂载1.挂载方法2.挂载示例(1)挂载光盘镜像文件(2)挂载移动硬盘(3)挂载U盘(4)挂载Windows文件共享(5)挂载UNIX系统NFS文件共享(6)补充3.卸载已挂载的设备三、软硬链接四、nfs服务1.什么是NFS2.服务端配置NFS(1)配置(2)共享目录的权限(3)启动nfs服务3.客户端挂载NFS五、......
  • 4/20 C语言判断字符串是否为回文,字符串中可以包含中文和英文
    //已知中文字符占用两个字节#include<stdio.h>#include<string.h>booljudge(char*a,int&i,int&k);intmain(){inti,k;chara[100];while(scanf("%s",a)!=EOF){i=0;k=strlen(a)-1;while......
  • linux 新建服务器基线
    linux新建服务器基线yum-yinstallntpvimnet-toolslsofnctelnetbind-utilspython3python3-develpython3-setuptoolspython3-pippython3-rpm-generatorspython3-libspython3-rpm-macroswgetNTP时钟服务器centos/etc/ntp.conf#注释driftfile/var/lib/ntp/dri......
  • linux下查看服务器的型号
    评:如何看到服务器的型号呢?#dmidecode|grep"Product"ProductName:IBMSystemx3650-[7979R01]-ProductName:SystemPlanarProductName:PowerSuppyBackplaneProductName:PCI-ExpressRiserCard,Slots1&2solaris可以直接用uname-a就能看到服......
  • linux IPtable防火墙 禁止和开放端口
    评:1、关闭所有的INPUTFORWARDOUTPUT只对某些端口开放。下面是命令实现:iptables-PINPUTDROPiptables-PFORWARDDROPiptables-POUTPUTDROP再用命令iptables-L-n查看是否设置好,好看到全部DROP了这样的设置好了,我们只是临时的,重启服务器还是会恢复......
  • linux下安装mysql
    1、查看是否已经安装Mysqlrpm-qa|grepmysql2、上传mysql的安装包到linux下,(.tar.gz版本的)3、解压安装包tar-zxvfmysql-5.7.35-linux-glibc2.12-x86_64.tar.gz4、先检查是否有mysql用户组和mysql用户,没有就添加有就忽略:检查是否有mysql用户组:groupsmysql添加......