最简单的基于FFMPEG的音频编码器(PCM编码为AAC)

最简单的基于FFMPEG的音频编码器(PCM编码为AAC)

大家好,又见面了,我是全栈君。

本文介绍一个最简单的基于FFMPEG的音频编码器。该编码器实现了PCM音频採样数据编码为AAC的压缩编码数据。编码器代码十分简单,可是每一行代码都非常重要。通过看本编码器的源码。能够了解FFMPEG音频编码的流程。

本程序使用最新版的类库(编译时间为2014.5.6)。开发平台为VC2010。全部的配置都已经做好,仅仅须要执行就能够了。

流程(2014.9.29更新)

以下附一张使用FFmpeg编码音频的流程图。

使用该流程。不仅能够编码AAC的音频,并且能够编码MP3,MP2等等各种FFmpeg支持的音频。图中蓝色背景的函数是实际输出数据的函数。

浅绿色的函数是音频编码的函数。

最简单的基于FFMPEG的音频编码器(PCM编码为AAC)

简介一下流程中各个函数的意义:

av_register_all():注冊FFmpeg全部编解码器。

avformat_alloc_output_context2():初始化输出码流的AVFormatContext。

avio_open():打开输出文件。

av_new_stream():创建输出码流的AVStream。

avcodec_find_encoder():查找编码器。

avcodec_open2():打开编码器。

avformat_write_header():写文件头(对于某些没有文件头的封装格式,不须要此函数。比方说MPEG2TS)。

avcodec_encode_audio2():编码音频。即将AVFrame(存储PCM採样数据)编码为AVPacket(存储AAC,MP3等格式的码流数据)。

av_write_frame():将编码后的视频码流写入文件。

av_write_trailer():写文件尾(对于某些没有文件头的封装格式。不须要此函数。比方说MPEG2TS)。

代码

 

/**
 *最简单的基于FFmpeg的音频编码器
 *Simplest FFmpeg Audio Encoder
 *
 *雷霄骅 Lei Xiaohua
 *leixiaohua1020@126.com
 *中国传媒大学/数字电视技术
 *Communication University of China / Digital TV Technology
 *http://blog.csdn.net/leixiaohua1020
 *
 *本程序实现了音频PCM採样数据编码为压缩码流(MP3。WMA,AAC等)。

*是最简单的FFmpeg音频编码方面的教程。 *通过学习本样例能够了解FFmpeg的编码流程。

*This software encode PCM data to AAC bitstream. *It's the simplest audio encoding software based on FFmpeg. *Suitable for beginner of FFmpeg */#include <stdio.h>#define __STDC_CONSTANT_MACROS#ifdef _WIN32//Windowsextern "C"{#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"};#else//Linux...#ifdef __cplusplusextern "C"{#endif#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#ifdef __cplusplus};#endif#endifint flush_encoder(AVFormatContext *fmt_ctx,unsigned int stream_index){ int ret; int got_frame; AVPacket enc_pkt; if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities & CODEC_CAP_DELAY)) return 0; while (1) { enc_pkt.data = NULL; enc_pkt.size = 0; av_init_packet(&enc_pkt); ret = avcodec_encode_audio2 (fmt_ctx->streams[stream_index]->codec, &enc_pkt, NULL, &got_frame); av_frame_free(NULL); if (ret < 0) break; if (!got_frame){ ret=0; break; } printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",enc_pkt.size); /* mux encoded frame */ ret = av_write_frame(fmt_ctx, &enc_pkt); if (ret < 0) break; } return ret;}int main(int argc, char* argv[]){ AVFormatContext* pFormatCtx; AVOutputFormat* fmt; AVStream* audio_st; AVCodecContext* pCodecCtx; AVCodec* pCodec; uint8_t* frame_buf; AVFrame* pFrame; AVPacket pkt; int got_frame=0; int ret=0; int size=0; FILE *in_file=NULL; //Raw PCM data int framenum=1000; //Audio frame number const char* out_file = "tdjm.aac"; //Output URL int i; in_file= fopen("tdjm.pcm", "rb"); av_register_all(); //Method 1. pFormatCtx = avformat_alloc_context(); fmt = av_guess_format(NULL, out_file, NULL); pFormatCtx->oformat = fmt; //Method 2. //avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file); //fmt = pFormatCtx->oformat; //Open output URL if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0){ printf("Failed to open output file!\n"); return -1; } audio_st = avformat_new_stream(pFormatCtx, 0); if (audio_st==NULL){ return -1; } pCodecCtx = audio_st->codec; pCodecCtx->codec_id = fmt->audio_codec; pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO; pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16; pCodecCtx->sample_rate= 44100; pCodecCtx->channel_layout=AV_CH_LAYOUT_STEREO; pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout); pCodecCtx->bit_rate = 64000; //Show some information av_dump_format(pFormatCtx, 0, out_file, 1); pCodec = avcodec_find_encoder(pCodecCtx->codec_id); if (!pCodec){ printf("Can not find encoder!\n"); return -1; } if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0){ printf("Failed to open encoder!\n"); return -1; } pFrame = av_frame_alloc(); pFrame->nb_samples= pCodecCtx->frame_size; pFrame->format= pCodecCtx->sample_fmt; size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1); frame_buf = (uint8_t *)av_malloc(size); avcodec_fill_audio_frame(pFrame, pCodecCtx->channels, pCodecCtx->sample_fmt,(const uint8_t*)frame_buf, size, 1); //Write Header avformat_write_header(pFormatCtx,NULL); av_new_packet(&pkt,size); for (i=0; i<framenum; i++){ //Read PCM if (fread(frame_buf, 1, size, in_file) <= 0){ printf("Failed to read raw data! \n"); return -1; }else if(feof(in_file)){ break; } pFrame->data[0] = frame_buf; //PCM Data pFrame->pts=i*100; got_frame=0; //Encode ret = avcodec_encode_audio2(pCodecCtx, &pkt,pFrame, &got_frame); if(ret < 0){ printf("Failed to encode!\n"); return -1; } if (got_frame==1){ printf("Succeed to encode 1 frame! \tsize:%5d\n",pkt.size); pkt.stream_index = audio_st->index; ret = av_write_frame(pFormatCtx, &pkt); av_free_packet(&pkt); } } //Flush Encoder ret = flush_encoder(pFormatCtx,0); if (ret < 0) { printf("Flushing encoder failed\n"); return -1; } //Write Trailer av_write_trailer(pFormatCtx); //Clean if (audio_st){ avcodec_close(audio_st->codec); av_free(pFrame); av_free(frame_buf); } avio_close(pFormatCtx->pb); avformat_free_context(pFormatCtx); fclose(in_file); return 0;}

结果

程序执行完毕后。会将一个PCM採样数据文件(*.pcm)编码为AAC码流文件(*.aac)。

下载

 

simplest ffmpeg audio encoder

项目主页

SourceForge:https://sourceforge.net/projects/simplestffmpegaudioencoder/

Github:https://github.com/leixiaohua1020/simplest_ffmpeg_audio_encoder

开源中国:http://git.oschina.net/leixiaohua1020/simplest_ffmpeg_audio_encoder

CSDNproject下载地址:

 http://download.csdn.net/detail/leixiaohua1020/7324091

PUDNproject下载地址:

http://www.pudn.com/downloads644/sourcecode/multimedia/detail2605236.html

更新-1.1 (2015.2.13)=========================================

这次考虑到了跨平台的要求,调整了源码。经过这次调整之后,源码能够在以下平台编译通过:

VC++:打开sln文件就可以编译,无需配置。

cl.exe:打开compile_cl.bat就可以命令行下使用cl.exe进行编译,注意可能须要依照VC的安装路径调整脚本里面的參数。编译命令例如以下。

::VS2010 Environment
call "D:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"
::include
@set INCLUDE=include;%INCLUDE%
::lib
@set LIB=lib;%LIB%
::compile and link
cl simplest_ffmpeg_audio_encoder.cpp /link avcodec.lib avformat.lib avutil.lib ^
avdevice.lib avfilter.lib postproc.lib swresample.lib swscale.lib /OPT:NOREF

MinGW:MinGW命令行下执行compile_mingw.sh就可以使用MinGW的g++进行编译。

编译命令例如以下。

g++ simplest_ffmpeg_audio_encoder.cpp -g -o simplest_ffmpeg_audio_encoder.exe \
-I /usr/local/include -L /usr/local/lib -lavformat -lavcodec -lavutil

GCC:Linux或者MacOS命令行下执行compile_gcc.sh就可以使用GCC进行编译。编译命令例如以下。

gcc simplest_ffmpeg_audio_encoder.cpp -g -o simplest_ffmpeg_audio_encoder.out \
-I /usr/local/include -L /usr/local/lib -lavformat -lavcodec -lavutil

PS:相关的编译命令已经保存到了project目录中

CSDN下载地址:http://download.csdn.net/detail/leixiaohua1020/8445209

SourceForge上已经更新。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/116024.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 经典汉罗塔问题解决方案[通俗易懂]

    经典汉罗塔问题解决方案[通俗易懂]汉罗塔问题将a的盘子移动到c针且一次只能移动一个盘,在移动过程中必须保持大盘在下,小盘在上。1、将n-1个盘子从a移动到b盘2、将a剩下的一个盘子移动到c盘3、将b的n-1个盘子移动到c盘#include<iostream>usingnamespacestd;voidmove1(chara,charc){ cout<<a<<“–>”<<c<<endl;}voidhanoi(intn,

  • idea激活码永久(已测有效)

    idea激活码永久(已测有效),https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • Nginx sendfile原理详解[通俗易懂]

    Nginx sendfile原理详解[通俗易懂]配置语法语法:sendfileon|off;默认值:sendfileoff;上下文:http,server,location,ifinlocation说明sendfile值为on,指定使用sendfile系统调用来传输文件。sendfile系统调用在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了数据在内核缓冲区和用户缓冲区之间的拷贝,操作效率很高,被…

  • visio2010密钥

    visio2010密钥GR24B-GC2XY-KRXRG-2TRJJ-4X7DCVWQ6G-37WBG-J7DJP-CY66Y-V278X2T8H8-JPW3D-CJGRK-3HTVF-VWD83HMCVF-BX8YB-JK46P-DP3KJ-9DRB222WT8-GGT7M-7MVKR-HF7Y4-MCWWDVX6BF-BHVDV-MHQ4R-KH9QD-6TQKVJ4MVP-7F4X4-V8W2C-…

  • 大数据开发和java开发有什么不同?

    大数据开发和java开发有什么不同?最近发现有些同学并不太了解大数据开发工程师这个职位,所以想简单介绍一下什么是大数据开发工程师,当前互联网公司的数据开发到底是什么样子的?和一般的Java或者PHP工程师在工作上有什么区别?什么不是大数据开发?仅使用数据库(关系型mysql,sqlserver,oracle等非关系型mongoredis等),尽管数据量达到千万级别,亿级别不是大数据开发。从业务系统的数据库中查询数据…

  • CNN算法详细分析

    CNN算法详细分析test_example_CNN.mtrain_x=double(reshape(train_x’,28,28,60000))/255;test_x=double(reshape(test_x’,28,28,10000))/255;train_y=double(train_y’);test_y=double(test_y’);将输入的数据按照规定的形式组织,并归一化。r…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号