FFMPEG音频编码

一.编码过程

创建编码器->创建上下文->打开编码器->运送数据给编码器->编码->释放资源

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编码位深还没解决

 

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值