一.编码过程
创建编码器->创建上下文->打开编码器->运送数据给编码器->编码->释放资源
1.1创建并打开编码器(编码器在一开始就是注册好的 对于ffmpeg来说是查找编码器)
创建编码器 avcodec_find_encder
创建上下文 avcodec_alloc_context3
打开编码器avcode_open2
avcode_open2 打开失败
我遇到的情况是
codec_context->sample_fmt = AV_SAMPLE_FMT_S16;
codec_context->sample_fmt = AV_SAMPLE_FMT_FLTP;
把AV_SAMPLE_FMT_S16 改成AV_SAMPLE_FMT_FLTP 就可以了
(解决:avcodec_open2(c, codec, NULL) 打开失败 的问题-CSDN博客) 转载
打开编码器
/// 创建编码上下文 打开编码器
AVCodecContext *open_coder() {
const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
// const AVCodec *codec = avcodec_find_encoder_by_name("libfdk_aac");
AVCodecContext *codec_context = avcodec_alloc_context3(codec);
///位深AV_SAMPLE_FMT_S16
codec_context->sample_fmt = AV_SAMPLE_FMT_FLTP;
AVChannelLayout layout = {0};
layout.nb_channels = 2;
layout.order = AV_CHANNEL_ORDER_NATIVE;
layout.u.mask = AV_CH_LAYOUT_STEREO;
codec_context->ch_layout = layout;
// //通道布局
// codec_context->channel_layout = AV_CH_LAYOUT_STEREO;
// //通道数
// codec_context->channels = 2;
///采样率
codec_context->sample_rate = 44100;
/// 码流
codec_context->bit_rate = 0;//AAC_LC: 128K AAC HE 64K AAC HE V2 32K
/// profile设置了就不要设置码流了 设置码流为0
codec_context->profile = FF_PROFILE_AAC_HE_V2;
int result = avcodec_open2(codec_context, codec, NULL);
if (result < 0) {
char errors[1024] = {0,};
av_strerror(result, &errors, 1024);
av_log(NULL,AV_LOG_INFO,"Failed to open audio device %s\n\n", errors);
return NULL;
}
return codec_context;
}
二:AAC 编码过程中的输入和输出数据
avcode_send_frame
avcode_receive_packet
输入输出数据
AVFrame
AVPacket
#include "test.h"
#include <time.h>
#include <unistd.h>
#include <string.h>
static int record_status = 0;
#define ms_sleep 5
void mssleep(unsigned long ms);
void setRecordStatus(int status) {
record_status = status;
}
void startRecord(void) {
printf("开始录制");
av_log_set_level(AV_LOG_DEBUG);
initDevice();
}
void encode_audio(AVCodecContext *codec_ctx,
AVFrame *av_frame,
AVPacket *newPkt,
FILE *file
) {
int result = 0;
///将数据送编码器
result = avcodec_send_frame(codec_ctx, av_frame);
///如果ret>=0说明数据设置成功
while (result >= 0) {
///获取编码后的音频数据如果成功需要重复获取,至到失败为止。
result = avcodec_receive_packet(codec_ctx, newPkt);
if (result == AVERROR(EAGAIN) || result == AVERROR_EOF) {
break;
} else if (result < 0) {
printf("Error encoding audio frame\n");
exit(-1);
}
av_log(NULL,AV_LOG_INFO,"pkt size is %d data is %p\n", newPkt->size,newPkt->data);
/// 写文件
fwrite(newPkt->data, 1, newPkt->size, file);
fflush(file);
}
}
/// 创建编码上下文 打开编码器
AVCodecContext *open_coder() {
const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
// const AVCodec *codec = avcodec_find_encoder_by_name("libfdk_aac");
AVCodecContext *codec_context = avcodec_alloc_context3(codec);
codec_context->sample_fmt = AV_SAMPLE_FMT_S16;
// codec_context->channel_layout = AV_CH_LAYOUT_STEREO;
///位深AV_SAMPLE_FMT_S16
// codec_context->sample_fmt = AV_SAMPLE_FMT_FLTP;
// codec_context->channel_layout = AV_CH_LAYOUT_STEREO;
AVChannelLayout layout = {0};
layout.nb_channels = 2;
layout.order = AV_CHANNEL_ORDER_NATIVE;
layout.u.mask = AV_CH_LAYOUT_STEREO;
codec_context->ch_layout = layout;
// //通道布局
// codec_context->channel_layout = AV_CH_LAYOUT_STEREO;
// //通道数
// codec_context->channels = 2;
///采样率
codec_context->sample_rate = 44100;
/// 码流
codec_context->bit_rate = 0;//AAC_LC: 128K AAC HE 64K AAC HE V2 32K
/// profile设置了就不要设置码流了 设置码流为0
codec_context->profile = FF_PROFILE_AAC_HE_V2;
int result = avcodec_open2(codec_context, codec, NULL);
if (result < 0) {
char errors[1024] = {0,};
av_strerror(result, &errors, 1024);
av_log(NULL,AV_LOG_INFO,"Failed to open audio device %s\n\n", errors);
return NULL;
}
return codec_context;
}
/// 重采样上下文
SwrContext *init_swr() {
SwrContext *swr_ctx = NULL;
// swr_ctx = swr_alloc_set_opts2(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, 44100, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_FLT, 44100, 0, NULL);
swr_ctx = swr_alloc_set_opts(NULL, // ctx
AV_CH_LAYOUT_STEREO, //输出channel布局
AV_SAMPLE_FMT_S16, //输出采样格式
44100,//采样率
AV_CH_LAYOUT_STEREO,//输入channel布局
AV_SAMPLE_FMT_FLT, //输入采样格式
44100, //输入采样率
0,
NULL);
if (!swr_ctx) {
}
if (swr_init(swr_ctx) < 0) {
}
return swr_ctx;
}
/*@brief open audio device
*@param
*return
*/
AVFormatContext* open_device() {
int ret = 0;
size_t errbuf_size = 1024;
char errors[1024] = {0,};
AVFormatContext *fmt_ctx = NULL;
AVDictionary *options = NULL;
//[[video device]:[audio device]]
char *deviceName = ":0";
// getformat
const AVInputFormat *iformat = av_find_input_format("avfoundation");
// open device
if ((ret = avformat_open_input(&fmt_ctx, deviceName, iformat, &options)) < 0) {
av_strerror(ret, &errors, errbuf_size);
printf(stderr,"Failed to open audio device,[%d] %s\n",ret,errors);
avformat_close_input(&fmt_ctx);
return NULL;
}
return fmt_ctx;
}
AVFrame* create_frame() {
AVFrame *av_frame = NULL;
av_frame = av_frame_alloc();/// 分配编码前的数据空间
if(!av_frame) {
printf("no memory");
goto __ERROR;
}
av_frame->nb_samples = 512;/// 单通道一个音频帧的采样大小
av_frame->format = AV_SAMPLE_FMT_S16;/// 每个采样大小
// av_frame->channel_layout = AV_CH_LAYOUT_STEREO;//channel 布局
// av_frame->format = AV_SAMPLE_FMT_FLTP;/// 每个采样大小
AVChannelLayout layout = {0};
layout.nb_channels = 2;
layout.order = AV_CHANNEL_ORDER_NATIVE;
layout.u.mask = AV_CH_LAYOUT_STEREO;
av_frame->ch_layout = layout;
av_frame_get_buffer(av_frame, 0);
if (!av_frame->buf[0]) {
printf("Error Failed to alloc buf in frame");
goto __ERROR;
}
return av_frame;
__ERROR:
if (av_frame) {
av_frame_free(&av_frame);
}
return NULL;
}
void alloc_data_4_resample(uint8_t ***src_data, int *src_linesize, uint8_t **dts_data, int *dst_linesize ){
//4096/4/2
//创建输入缓冲区
av_samples_alloc_array_and_samples(src_data, //输入缓冲区地址
src_linesize,//缓冲区中的大小
2, //通道数
512, //单通道采样个数
AV_SAMPLE_FMT_FLT,//采样格式
0);
//4096/4/2
//创建输出缓冲区
av_samples_alloc_array_and_samples(dts_data, //输出缓冲区地址
dst_linesize,//缓冲区中的大小
2, //通道数
512, //单通道采样个数
AV_SAMPLE_FMT_S16,//采样格式
0);
}
void free_data_4_resampe(uint8_t **src_data, uint8_t **dts_data) {
if (src_data) {
av_freep(&src_data[0]);
}
av_freep(&src_data);
if (dts_data) {
av_freep(&dts_data[0]);
}
av_freep(&dts_data);
}
void read_data_and_encode(AVFormatContext *fmt_ctx,
SwrContext* swr_context,
AVCodecContext *codec_ctx,
FILE *outFile) {
int ret = 0;
AVPacket pkt;
AVFrame *av_frame = NULL;
AVPacket *newpkt = NULL;
/// 重采样缓冲区
uint8_t **src_data = NULL;
int src_linesize = 0;
uint8_t **dts_data = NULL;
int dst_linesize = 0;
av_init_packet(&pkt);
av_frame = create_frame();
if(!av_frame) {
goto __ERROR;
}
newpkt = av_packet_alloc();/// 分配编码后的数据空间
///
if(!newpkt) {
goto __ERROR;
}
/// 重采样输入输出缓冲区
alloc_data_4_resample(&src_data,&src_linesize,&dts_data,&dst_linesize);
//read data from device
while (((ret = av_read_frame(fmt_ctx, &pkt)) == 0 || ret == -35) && record_status) {
if (ret == -35) {
mssleep(ms_sleep);
continue;
}
memcpy((void *)src_data[0], (void *)pkt.data, pkt.size);
/// 重采样
swr_convert(swr_context, //重采样的上下文
dts_data, // 输出结果缓冲区
512, //每个通道的采样数
(const uint8_t**) src_data,//输入缓冲区
512);//输入单个通道的采样数
/// 将重采样的数据写入fram中
memcpy((void *)av_frame->data[0], dts_data[0], dst_linesize);
/// 编码
encode_audio(codec_ctx, av_frame, newpkt, outFile);
av_packet_unref(&pkt);
}
/// 强制将编码器缓冲区中的音频进行编码输出
encode_audio(codec_ctx, NULL, newpkt, outFile);
__ERROR:
if (av_frame) {
av_frame_free(&av_frame);
}
if (newpkt) {
av_packet_free(&newpkt);
}
free_data_4_resampe(src_data, dts_data);
}
void initDevice() {
AVFormatContext *fmt_ctx = NULL;
AVCodecContext *codec_ctx = NULL;
/// 重采样上下文
SwrContext *context = NULL;
/// 注册音视频设备
avdevice_register_all();
record_status = 1;
/// 打开一个文件
FILE *outFile = fopen("/Users/king/Desktop/ffmpeg/audio/o1.aac", "wb+");
if (outFile == NULL) {
printf("文件创建失败");
goto __ERROR;
}
/// 打开设备AVInputFormat
fmt_ctx = open_device();
if (!fmt_ctx) {
printf("fmt_ctx error");
goto __ERROR;
}
//打开编码器
codec_ctx = open_coder();
if (!codec_ctx) {
printf("codec_ctx error");
goto __ERROR;
}
/// 初始化重采样上下文
context = init_swr();
if (!context) {
goto __ERROR;
}
read_data_and_encode(fmt_ctx, context, codec_ctx, outFile);
__ERROR:
// 释放重采样上下文
if (context) {
swr_free(&context);
}
if (codec_ctx) {
avcodec_free_context(&codec_ctx);
}
if (fmt_ctx) {
avformat_close_input(&fmt_ctx);
}
if (outFile) {
fclose(outFile);
}
av_log(NULL,AV_LOG_DEBUG,"record finish");
}
这个上边的代码aac编码位深还没解决