PCM 编码为AAC
来源:互联网 发布:ghostview mac 编辑:程序博客网 时间:2024/06/05 18:30
PCM 编码为AAC
简介
ffmpeg version 3.4 Copyright (c) 2003-2017 the FFmpeg developersbuilt with Apple LLVM version 7.3.0 (clang-703.0.31)configuration: --prefix=/usr/local/media/ffmpeg_34 --enable-gpl --enable-avresample --disable-x86asm --disable-encoder=aac --disable-decoder=aac --enable-libfdk_aac --enable-nonfree --extra-cflags=-I/usr/local/media/libfdkaac/include/ --extra-ldflags=-L/usr/local/media/libfdkaac/lib --extra-cflags=-I/usr/local/media/libx264/include/ --extra-ldflags=-L/usr/local/media/libx264/lib由于音频数据在采样率、format有多种参数格式, ffmpeg自带的AAC支持有限,本例采样率8000就不支持,需要用fdkaac第三方库,本例编码依赖库为libfdk_aac.
AAC
AAC 封装格式
AAC音频格式有ADIF和ADTS:ADIF:Audio Data Interchange Format 音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。ADTS:Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。简单说,ADTS可以在任意帧解码,也就是说它每一帧都有头信息。ADIF只有一个统一的头,所以必须得到所有的数据后解码。且这两种的header的格式也是不同的,目前一般编码后的和抽取出的都是ADTS格式的音频流。ADTS是帧序列,本身具备流特征,在音频流的传输与处理方面更加合适。
/** * 添加ADTS头部 * * @param packet ADTS header 的 byte[],长度为7 * @param packetLen 该帧的长度,包括header的长度 */private void addADTStoPacket(byte[] packet, int packetLen) { int profile = 2; // AAC LC int freqIdx = 3; // 48000Hz int chanCfg = 2; // 2 Channel packet[0] = (byte) 0xFF; packet[1] = (byte) 0xF9; packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2)); packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11)); packet[4] = (byte) ((packetLen & 0x7FF) >> 3); packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F); packet[6] = (byte) 0xFC;}
其中profile表示使用哪个级别的AAC,在MPEG-2 AAC中定义了3种:
AAC编解码
AAC 编解码器初始化时,nb_samples 固定为 1024。每次编码需要的样本数由av_samples_get_buffer_size计算得出,需要足够的数据,才能编码成功。
源码
#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <math.h>#include <libavcodec/avcodec.h>#include <libavutil/opt.h>#include <libavutil/channel_layout.h>#include <libavutil/common.h>#include <libavutil/imgutils.h>#include <libavutil/mathematics.h>#include <libavutil/samplefmt.h>#include <libavutil/frame.h>#include <libavformat/avformat.h>#include <libswscale/swscale.h>#include <libavutil/channel_layout.h>#include <libavutil/common.h>#include <libavutil/frame.h>#include <libavutil/samplefmt.h>static int write_aac_header(FILE* fp, AVPacket* pkt);/* check that a given sample format is supported by the encoder */static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt){ const enum AVSampleFormat *p = codec->sample_fmts; while (*p != AV_SAMPLE_FMT_NONE) { if (*p == sample_fmt) return 1; p++; } return 0;}static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *output){ int ret; /* send the frame for encoding */ ret = avcodec_send_frame(ctx, frame); if (ret < 0) { fprintf(stderr, "Error sending the frame to the encoder\n"); exit(1); } fprintf(stdout, "Sending the frame to the encoder\n"); /* read all the available output packets (in general there may be any * number of them */ while (ret >= 0) { ret = avcodec_receive_packet(ctx, pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return; else if (ret < 0) { fprintf(stderr, "Error encoding audio frame\n"); exit(1); } write_aac_header(output, pkt); fwrite(pkt->data, 1, pkt->size, output); fprintf(stdout, "write %d\n", pkt->size); av_packet_unref(pkt); } return;}//AAC有两种封装格式,分别是ADIF ADTS,多与流媒体一般使用ADTS格式。见://http://www.jianshu.com/p/839b11e0638b aac freqIdxchar aac_adts_header[7] = {0};int chanCfg = 1; //MPEG-4 Audio Channel Configuration. 1 Channel front-centerstatic int init_aac_header() { int profile = 2; //AAC LC int freqIdx = 11; //8000HZ aac_adts_header[0] = (char)0xFF; // 11111111 = syncword aac_adts_header[1] = (char)0xF1; // 1111 1 00 1 = syncword MPEG-2 Layer CRC aac_adts_header[2] = (char)(((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2)); aac_adts_header[6] = (char)0xFC; return 0;}static int write_aac_header(FILE* fp, AVPacket* pkt) { aac_adts_header[3] = (char)(((chanCfg & 3) << 6) + ((7 + pkt->size) >> 11)); aac_adts_header[4] = (char)(((7 + pkt->size) & 0x7FF) >> 3); aac_adts_header[5] = (char)((((7 + pkt->size) & 7) << 5) + 0x1F); fwrite(aac_adts_header, 7, 1, fp); return 0;}int main(int argc, char **argv){ AVFrame *frame; AVCodec *codec = NULL; AVPacket *pkt; AVCodecContext *codecContext; int readSize=0; FILE * fileIn,*fileOut; int frameCount=0; /* register all the codecs */ av_register_all(); init_aac_header(); if(argc!=3){ fprintf(stdout,"usage:./a.out xxx.pcm xxx.aac\n"); return -1; } fileIn =fopen(argv[1],"r+"); if (fileIn == NULL) { fprintf(stderr, "fopen failed %s\n", argv[1]); exit(1); } //3.读出来的数据,我们需要编码,因此需要编码器 //下面的函数找到h.264类型的编码器 /* find the mpeg1 video encoder */ codec = avcodec_find_encoder(AV_CODEC_ID_AAC); if (!codec){ fprintf(stderr, "Codec not found\n"); exit(1); } //有了编码器,我们还需要编码器的上下文环境,用来控制编码的过程 codecContext = avcodec_alloc_context3(codec);//分配AVCodecContext实例 if (!codecContext){ fprintf(stderr, "Could not allocate video codec context\n"); return -1; } /* put sample parameters */ codecContext->bit_rate = 64000; /* check that the encoder supports s16 pcm input */ codecContext->sample_fmt = AV_SAMPLE_FMT_S16; if (!check_sample_fmt(codec, codecContext->sample_fmt)) { fprintf(stderr, "Encoder does not support sample format %s", av_get_sample_fmt_name(codecContext->sample_fmt)); exit(1); } codecContext->sample_rate = 8000; codecContext->channel_layout = AV_CH_LAYOUT_MONO; codecContext->channels = av_get_channel_layout_nb_channels(codecContext->channel_layout); /* select other audio parameters supported by the encoder */ //准备好了编码器和编码器上下文环境,现在可以打开编码器了 //根据编码器上下文打开编码器 if (avcodec_open2(codecContext, codec, NULL) < 0){ fprintf(stderr, "Could not open codec\n"); return -1; } /* packet for holding encoded output */ pkt = av_packet_alloc(); if (!pkt) { fprintf(stderr, "could not allocate the packet\n"); exit(1); } //读出的一帧数据保存在AVFrame中。 frame = av_frame_alloc(); if (!frame) { fprintf(stderr, "Could not allocate audio frame\n"); exit(1); } frame->nb_samples = codecContext->frame_size;; frame->format = codecContext->sample_fmt; frame->channel_layout = codecContext->channel_layout; /* allocate the data buffers */ int ret = av_frame_get_buffer(frame, 0); if (ret < 0) { fprintf(stderr, "Could not allocate audio data buffers\n"); exit(1); } int data_size = av_samples_get_buffer_size(NULL, codecContext->channels, frame->nb_samples, frame->format, 0); //4.准备输出文件 fileOut= fopen(argv[2],"w+"); //下面开始编码 while(1){ //读一帧数据出来 //frame->pts = 1; readSize = fread(frame->data[0], 1,data_size,fileIn); if(readSize == 0){ fprintf(stdout,"end of file\n"); frameCount++; break; } encode(codecContext, frame, pkt, fileOut); } //flush encode(codecContext, NULL, pkt, fileOut); fclose(fileIn); fclose(fileOut); av_frame_free(&frame); av_packet_free(&pkt); avcodec_free_context(&codecContext); return 0;}
源码下载
GITHUB : https://github.com/jaygno/pcm_2_aac
参考资料
FFmpeg(2016)PCM编码AAC
AAC ADTS结构分析
AAC 格式简介
Android音视频处理之AAC编码
阅读全文
0 0
- PCM 编码为AAC
- 如何将裸码流pcm编码为aac文件
- ffmpeg pcm码流编码为aac
- PCM编码AAC
- 精简但精确的PCM编码为AAC解析
- 【FFmpeg学习笔记006】 PCM编码为AAC
- 【FFmpeg(2016)】PCM编码AAC
- MediaCodec编译pcm为aac
- MediaCodec编译pcm为aac
- FAAC转换PCM为AAC
- MediaCodec编译pcm为aac
- PCM音频采样数据编码为AAC的压缩编码数据
- ffmpeg实战教程(三)音频PCM采样为AAC,视频YUV编码为H264/HEVC
- 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)
- 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)
- 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)
- ffmpeg学习十:将pcm格式的音频编码为aac格式
- android 实时PCM数据编码成AAC
- 【vuejs】 模态框组件-confirm或者alert框
- Python_操作列表
- Leetcode#406 Queue Reconstruction by Height
- 磁盘分区预习
- Java笔记一——基础语法:
- PCM 编码为AAC
- 三栏布局
- javascript里this的指向问题
- 区别:innerHTML---innerText---createTextNode--document.write
- 【C语言练习】3.0
- bind视图(view)配置
- 0基础lua学习(九)数组
- 包子AI插画笔记
- 使用注解代替enum