音频转aac格式

//
// Created by bytedance on 2022/1/20.
//

#include "main.h"
#include <iostream>
#include <unistd.h>

using namespace std;

extern  "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/log.h>
#include <libswresample/swresample.h>
}

#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "swresample.lib")


int main(){
    int ret =0;
    // 样本格式 sample_size  AV_SAMPLE_FMT_S16(16位字节存储) AV_SAMPLE_FMT_FLTP(浮点数存储 4个字节32位存储)
    // 样本类型 planar AV_SAMPLE_FMT_S16 在内存中的格式为c1/c2/c1/c2
    // 样本类型 planar AV_SAMPLE_FMT_S16P 在内存中的格式为c1/c1/c1/...c2/c2/c2
    av_register_all();        // 注册所有的解码器
    avcodec_register_all();    // 注册所有的编解码

    // 输入和输出都是字符数组
    char inputFile[] = "../audio.pcm";
    char outFile[] = "../audio.aac";

    // 1、找到指定的编码器
    AVCodec * codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!codec) {
        cout<<"avcodec_find_encoder failed"<<endl;
        return -1;
    }
    // 2、根据编码器拿到编码器的上下文(输入的上下文)
    AVCodecContext* avCodecContext = avcodec_alloc_context3(codec);
    if (!avCodecContext) {
        cout<<"avcodec_alloc_context3 failed"<<endl;
        return -1;
    }
    // 3、将音频的参数设置到编辑器的上下文中
    avCodecContext->sample_rate = 44100;
    avCodecContext->channels = 2;
    // 声道类型是立体声
    avCodecContext->channel_layout =AV_CH_LAYOUT_STEREO;
    // 设置样本格式
    avCodecContext->sample_fmt = AV_SAMPLE_FMT_FLTP;
    avCodecContext->bit_rate = 64000;
    // 设置文件头部
    avCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    // 4、打开音频编码器
    ret =avcodec_open2(avCodecContext, codec, NULL);
    if(ret < 0) {
        return -1;
    }
    // 5、创建一个输出的结构体
    AVFormatContext * oc =NULL;
    avformat_alloc_output_context2(&oc, NULL, NULL, outFile);
    if(!oc) {
        return -1;
    }

    // 6、 创建音频流
    AVStream * st = avformat_new_stream(oc, NULL);
    st->codecpar->codec_tag = 0;
    // 拷贝音频输入设置的那些参数
    avcodec_parameters_from_context(st->codecpar, avCodecContext);

    // 打印设置的信息
    av_dump_format(oc, 0, outFile, 1);

    // 7、打开音频文件
    ret = avio_open(&oc->pb, outFile, AVIO_FLAG_READ_WRITE);
    if (ret < 0) {
        return -1;
    }
    avformat_write_header(oc, NULL);  // 生成一个aac的文件
    // 8、设置重采样
    SwrContext * ctx = NULL;
    ctx = swr_alloc_set_opts(ctx, avCodecContext->channel_layout,avCodecContext->sample_fmt, avCodecContext-> sample_rate, // 输出的音频参数
    AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, 44100, // 输入的音频参数
    0,0);
    if(!ctx){
        cout<<"swr_alloc_set_opts failed"<<endl;
        return -1;
    }
    ret = swr_init(ctx);   // 重采样的初始化
    if (ret <0) {
        cout<<"swr_init failed"<<endl;
        return -1;
    }

    // 一帧一帧的读取PCM数据,进行重采样,然后写入到aac文件
    // 9、创建接收帧数据的结构体
    AVFrame *frame = av_frame_alloc();
    frame->format = AV_SAMPLE_FMT_FLTP;
    frame->channels =2;
    frame->channel_layout = AV_CH_LAYOUT_STEREO;
    frame->nb_samples = 1024;   //一帧音频的采样数量

    ret = av_frame_get_buffer(frame, 0);
    if(ret < 0)
    {
        cout<<"av_frame_get_buffer failed"<<endl;
        return -1;
    }

    // 10、创建缓存空间
    int readSize = frame->nb_samples*2*2; // 16位 代表两个字节
    char *pcms = new char[readSize];
    // 11、打开输入的音频文件


    FILE *flp = fopen(inputFile, "rb");
    if (flp == nullptr)
    {
        cout<<"fopen failed"<<endl;
        return -1;
    }
    for(;;)
    {
        int len = fread(pcms, 1, readSize, flp);
        if(len<= 0)
        {
            break;
        }
        // 重采样之前的数据
        const uint8_t * data[1];
        data[0] = (uint8_t*)pcms;


        len = swr_convert(ctx, frame->data, frame->nb_samples, data, frame->nb_samples);   //重采样之后的数据
        if(len <= 0)
        {
            break;
        }
        // 12、重载样之后的数据重新编码后写入aac文件
        AVPacket pkt;
        av_init_packet(&pkt);   // avpacket 一般作为需要重新编码的数据容器
        // 将数据发送给编码线程
        ret = avcodec_send_frame(avCodecContext, frame);
        if(ret != 0)
        {
            continue;
        }

        ret = avcodec_receive_packet(avCodecContext, &pkt);
        if(ret != 0)
        {
            continue;
        }

        // 0标识音频流
        pkt.stream_index = 0;
        pkt.dts = 0; //重置解码时间
        pkt.pts = 0; //重置播放时间

        // 将文件写入到输出文件
        av_interleaved_write_frame(oc, &pkt);
        cout<<len+"单词读取的样本个数"<<endl;


    }
    delete pcms;
    pcms = NULL;


    // 写入视频的索引
    av_write_trailer(oc);





    // 、关闭文件流、编码器
    avio_close(oc->pb);
    // 关闭编码器
    avcodec_close(avCodecContext);
    // 清理设置的编码器参数
    avcodec_free_context(&avCodecContext);
    // 清理结构体上下文
    avformat_free_context(oc);
    std::cout<<"main.cpp"<<endl;
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值