Android音视频开发 ->FFmpeg音频编码本地PCM文件转AAC

编码流程

  1. 注册所有组件 av_register_all()
  2. 创建封装格式上下文 avformat_alloc_context() 返回一个AVFormatContext
  3. 初始化输入输出上下文(打开输出文件) avio_open(),可以输出到本地或者网络地址等等
  4. 创建媒体流 avformat_new_stream()
  5. 初始化编码器上下文以及设置参数 AVCodecContext
  6. 查找编码器 avcodec_find_encoder_by_name()
  7. 打开编码器 avcodec_open2()
  8. 写入头文件 avformat_write_header();
  9. 打开本地需要转换的文件 fopen(inFile, “rb”)
  10. 初始化 AVFrame,AVPacket
  11. 开始转换 avcodec_send_frame() avcodec_receive_packet()
  12. 开始写入本地 av_write_frame()
  13. 写入文件尾 av_write_trailer()

公共变量

AVCodec *avAudioCodec; //编码器对象

AVCodecContext *avAudioContext; //编码器上下文

AVFrame *audioFrame; //储存原始PCM数据AVFrame

AVPacket *audioPacket; //储存编码后AAC数据AVPacket

AVStream *audioStream; //流通道对象

int audioPts = 0; //pts

AVFormatContext *formatContext; //封装格式上下文对象

int audioBufferSize; //缓冲区大小

uint8_t *outBuffer; //缓冲区buffer

FILE *in_file; //本地音频文件

初始化

int AudioVideoEncode::audioEncoderInit(JNIEnv *env) {
	//输出文件(AAC)路径
    const char *outFile = "/sdcard/aaa/gjk.aac";
    //原始文件(PCM)路径
    const char *inFile = "/sdcard/aaa/PCM/pcm.pcm";
    //注册组件
    av_register_all();
    //初始化封装格式上下文
    formatContext = avformat_alloc_context();
    //指定封装类型
    formatContext->oformat = av_guess_format(NULL, outFile, NULL);//得到输出格式
    //打开输出文件
    if (avio_open(&formatContext->pb, outFile, AVIO_FLAG_READ_WRITE) < 0) return -1;
    //创建媒体流
    audioStream = avformat_new_stream(formatContext, 0);
    if (audioStream == NULL) return -1;
    //获取编码器上下文
    avAudioContext = audioStream->codec;
    //设置编码器上下文参数
    avAudioContext->codec_id = formatContext->oformat->audio_codec;//设置id
    avAudioContext->codec_type = AVMEDIA_TYPE_AUDIO;//设置类型为音频
    avAudioContext->sample_fmt = AV_SAMPLE_FMT_S16;//设置格式为16bit
    avAudioContext->sample_rate = 8000;//设置采样率
    avAudioContext->channel_layout = AV_CH_LAYOUT_MONO;//设置通道类型和下面通道数量对应
    avAudioContext->channels = 1;//单通道
    avAudioContext->bit_rate = 128000;//码率
    //查找编码器
    avAudioCodec = avcodec_find_encoder_by_name("libfdk_aac");
    if (avAudioCodec == NULL) return -1;
    //打开编码器
    int ret = avcodec_open2(avAudioContext, avAudioCodec, NULL);
    if (ret < 0) return -1;
    //写入头文件
    avformat_write_header(formatContext, NULL);
    //初始化编码前(原始数据)数据储存结构体,也就是创建数据缓冲区
    audioFrame = av_frame_alloc();
    //设置参数
    audioFrame->nb_samples = avAudioContext->frame_size;
    audioFrame->format = avAudioContext->sample_fmt;
    //打开音频输入文件
    in_file = fopen(inFile, "rb");
    if (in_file == NULL) return -1;
    //获取缓冲区大小
    audioBufferSize = av_samples_get_buffer_size(NULL,
                                                 avAudioContext->channels,
                                                 avAudioContext->frame_size,
                                                 avAudioContext->sample_fmt,
                                                 1);
    //创建缓冲区
    outBuffer = (uint8_t *) av_malloc(audioBufferSize);
    avcodec_fill_audio_frame(audioFrame,
                             avAudioContext->channels,
                             avAudioContext->sample_fmt,
                             (const uint8_t *) outBuffer,
                             audioBufferSize,
                             1);
    //初始化编码后数据储存结构体
    audioPacket = (AVPacket *) av_malloc(audioBufferSize);
    audioPts = 0;//pts
    return 0;
}

开始编码

void AudioVideoEncode::audioEncoder(JNIEnv *env, jobject obj, jbyte *byte, int byteLength) {
    int ret;
    while (true) {
        // 1、读取一帧音频采样数据
        if (fread(outBuffer, 1, audioBufferSize, in_file) <= 0) {
            __android_log_print(ANDROID_LOG_INFO, "main", "读取数据失败");
            break;
        } else if (feof(in_file)) {
            break;
        }
        audioFrame->data[0] = outBuffer;
        audioFrame->pts = audioPts;
        audioPts++;
        ret = avcodec_send_frame(avAudioContext, audioFrame);
        if (ret != 0) {
            __android_log_print(ANDROID_LOG_INFO, "main", "发送数据失败");
        }

        // 3.2 编码一帧音频采样数据
        ret = avcodec_receive_packet(avAudioContext, audioPacket);

        if (ret == 0) {
            /**第十一步:将编码后的音频码流写入文件*/
            audioPts++;
            audioPacket->stream_index = audioStream->index;
            ret = av_write_frame(formatContext, audioPacket);
            if (ret < 0) {
                __android_log_print(ANDROID_LOG_INFO, "main", "写入失败");
                return;
            }
        } else {
            __android_log_print(ANDROID_LOG_INFO, "main", "无采样数据编码");
            return;
        }
    }
    // 写文件尾(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)
    av_write_trailer(formatContext);
    //释放资源
    videoEncoderClose();
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值