前言

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. 文心一言 VS 讯飞星火 VS chatgpt (169)-- 算法导论13.2 2题

    二.用go语言,证明:在任何一棵有 n 个结点的二叉搜索树中,恰有 n-1种可能的旋转. 文心一言: 要证明在任何一棵有 n 个结点的二叉搜索树中,恰有 n-1 种可能的旋转,我们可以按照以下步骤逐步 ...

  2. node node-sass sass-loader版本兼容问题

    相关概念 sass Sass是一种预处理器脚本语言,可以解释或编译成层叠样式表(CSS). Sass包含两种语法:较旧的语法使用缩进将代码块和换行符分隔为单独的规则:较新的语法SCSS使用像CSS这样 ...

  3. .NET开源、强大的Web报表统计系统

    前言 今天分享一个.NET开源.强大的Web报表统计系统:CellReport. 项目官方介绍 CellReport 诞生的初衷是为了解决日常快速制作统计报表的需要. CellReport 是一个为复 ...

  4. 2024-01-13:用go语言,现在有一个打怪类型的游戏,这个游戏是这样的,你有n个技能, 每一个技能会有一个伤害, 同时若怪物小于等于一定的血量,则该技能可能造成双倍伤害, 每一个技能最多只能释放

    2024-01-13:用go语言,现在有一个打怪类型的游戏,这个游戏是这样的,你有n个技能, 每一个技能会有一个伤害, 同时若怪物小于等于一定的血量,则该技能可能造成双倍伤害, 每一个技能最多只能释放 ...

  5. GitHub OAuth2的授权指南

    一.OAuth2简介 OAuth 2.0(开放授权 2.0)是一种用于授权的开放标准,旨在允许用户在不提供他们的用户名和密码的情况下,授权第三方应用访问其在另一网站上的信息.它是在网络服务之间安全地共 ...

  6. Cesium中用到的图形技术——Computing the horizon occlusion point

    译者注:本文翻译自Cesium官方博文<Computing the horizon occlusion point>,by KEVIN RING. 你厌倦了地平线剔除吗? 太好了,我也没有 ...

  7. 中断操作:AbortController学习笔记

    前端面试一般喜欢问: 请手写一个带取消功能的延迟函数,axios 取消功能的原理是什么? 如何中断请求fetch的原理分析和应用? 在看来<使用 AbortController 终止 fetch ...

  8. 2023开发者必备iOS开发工具

    ​ 2023开发者必备iOS开发工具 工欲善其事,必先利其器.进行开发工作时,利用并熟练使用恰当的工具可以让工作效率得到大幅度提高.下边会介绍一些在进行iOS开发工作时常用的一些工具,本文并不对其进行 ...

  9. Flutter加固原理及加密处理

    ​ 引言 为了保护Flutter应用免受潜在的漏洞和攻击威胁,加固是必不可少的措施之一.Flutter加固原理主要包括代码混淆.数据加密.安全存储.反调试与反分析.动态加载和安全通信等多个方面.通过综 ...

  10. 火山引擎ByteHouse:4000字总结,Serverless在OLAP领域应用的五点思考

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 作为云计算的下一个迭代,Serverless可以使开发者更专注于构建产品中的应用,而无需考虑底层堆栈问题.伴随着近 ...