前言

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 公众号

linux环境C语言实现:h264与pcm封装成mp4视频格式的更多相关文章

  1. H264编码 封装成MP4格式 视频流 RTP封包

    H264编码 封装成MP4格式 视频流 RTP封包         分类:             多媒体编程              2013-02-20 21:31     3067人阅读    ...

  2. Linux环境C语言斐波拉切数列(1,1,2,3,5,8,13,.........)实现

    斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一 ...

  3. iOS 将视频流(h264)和音频流封装成PS流

    调用方法: static  CPSPackager * testObjc = NULL; static char *pszBuffer; testObjc = new CPSPackager(); p ...

  4. .NET 6 从0到1使用Docker部署至Linux环境

    前言 作为一名.Net菜鸟开发者,平时对Linux接触的并不多,项目部署这一块都是运维小哥顶着,但是作为混迹在云原生项目组的人咱也不能什么都不知道,该掌握的知识还是要懂的,所以借着这次机会,梳理一下项 ...

  5. H264视频编码成MP4文件

    firehood的专栏 Wince嵌入式开发       目录视图 摘要视图 订阅 赠书 | AI专栏(AI圣经!<深度学习>中文版)      每周荐书:Kotlin.分布式.Keras ...

  6. Linux环境下使用gcc编译,gdb反汇编C语言程序

    使用虚拟机 VMware Workstation 10 Linux环境:Ubuntu 14.04 LTS Server amd64   我把过程截图如下. 首先是hello world程序: 备注: ...

  7. Windows10下配置Linux下C语言开发环境

    今天为大家介绍如在Windows10下配置Linux下C语言开发环境,首先安装linux子系统:启用开发者模式 1.打开设置 2.点击更新和安全3.点击开发者选项 4.启用开发人员模式 5.更改系统功 ...

  8. Linux下c语言环境概述

    Linux下C语言环境概述 主要涉及编辑器.编译链接器.调试器.项目管理工具 编辑器 Linux中常用的编辑器有vi和emacs 查看vim配置文件并编辑 编译链接器 在Linux中,最常用的编译器是 ...

  9. Linux C编程之一:Linux下c语言的开发环境

    ---恢复内容开始--- 今天开始根据Linux C编程相关视频的学习所做的笔记,希望能一直坚持下去... 1.开发环境的构成 编辑器:VI: 编译器:选择GNU  C/C++编译器gcc: 调试器: ...

  10. Linux环境下C语言线程创建---简单代码

    在Linux环境下用C语言编写线程创建. //file name: pthreadtext.c #include <stdio.h> #include <pthread.h> ...

随机推荐

  1. libGDX游戏开发之Box2D(十四)

    libGDX游戏开发之Box2D(十四) libGDX系列,游戏开发有unity3D巴拉巴拉的,为啥还用java开发?因为我是Java程序员emm-国内用libgdx比较少,多数情况需要去官网和goo ...

  2. JVM学习-Class文件结构

    文章原文:https://gaoyubo.cn/blogs/844dc0e7.html 一.Class类文件的结构 任何一个Class文件都对应着唯一的一个类或接口的定义信息. 但是反过来说,类或接口 ...

  3. Java 展开或折叠PDF中的书签

    PDF中的书签功能可快速定位到指定阅读位置.对多层书签可根据阅读喜好设置层级展开或折叠.本文将通过Java程序代码介绍如何来实现PDF书签展开或折叠. 程序环境 Spire.Pdf.jar( 免费版3 ...

  4. 六步带你体验EDS交换数据全流程

    本期我们将走进XX医疗集团向某慢病院共享数据的场景,如何通过EDS完成数据交换,进而实现医疗数据的安全可控共享. 本文分享自华为云社区<[EDS从小白到专家]第1期-六步带你体验EDS交换数据全 ...

  5. 可以一学的代码优化小技巧:减少if-else冗余

    摘要:if-else 语句对于程序员来说,是非常非常熟悉的一个判断语句,我们在日常开发和学习中都经常看见它. 本文分享自华为云社区<JavaScript代码之美-代码优化,减少if-else冗余 ...

  6. 一文带你了解华为云GaussDB的五大黑科技

    摘要:在华为开发者大会2021(HDC·Cloud)中,华为云数据库多位技术专家分享了GaussDB系列数据库全新5大黑科技. 4月24-26日,华为开发者大会2021(HDC·Cloud)在深圳隆重 ...

  7. GaussDB(for Influx)与开源企业版性能对比

    摘要:相比于企业版InfluxDB,GaussDB(for Influx)能为客户提供更高的写入能力.更稳定的查询能力.更高的数据压缩率,高效满足各大时序应用场景需求. 本文分享自华为云社区<华 ...

  8. 从下个月开始,App Store 要求使用 Xcode 14 构建的 iOS 16 兼容应用程序

    Xcode 继向开发者发布第一个iOS 16.5 测试版后,苹果公司周二宣布了对开发者向 App Store 提交应用程序的新要求.从下个月开始,Apple 将要求每个应用程序都必须使用 Xcode ...

  9. No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalanc

    No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalanc ...

  10. LinkedBlockingQueue实现的生产者和消费者模型

    首先 LinkedBlockingQueue 是线程安全的阻塞队列,LinkedBlockingQueue实现的生产者和消费者模型 阻塞队列与我们平常接触的普通队列(LinkedList或ArrayL ...