Android开发Android开发经验谈Android技术知识

part05_ffmpeg实现本地音频转码pcm输出

2018-05-14  本文已影响230人  IT魔幻师

一、音频基础知识

二、本地音频转码成pcm输出到文件

    extern "C" {
    //封装格式
    #include "libavformat/avformat.h"
    //解码
    #include "libavcodec/avcodec.h"
    //缩放
    #include "libswscale/swscale.h"
    //重采样
    #include "libswresample/swresample.h"
    };
    /**
     * 将本地音频文件转码为pcm格式并保存到一个新文件上
     * input: 本地音频文件路径
     * output:转换后的硬盘存储路径
     */
    void musicPlayer(const char *input,const char *output){
        av_register_all();
        AVFormatContext *pFormatCtx = avformat_alloc_context();
        //打开音频文件
        if (avformat_open_input(&pFormatCtx, input, NULL, NULL) != 0) {
            LOGI("%s", "无法打开音频文件");
            return;
        }
        //获取输入文件信息
        if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
            LOGI("%s", "无法获取输入文件信息");
            return;
        }
        //获取音频流索引位置
        int i = 0, audio_stream_idx = -1;
        for (; i < pFormatCtx->nb_streams; i++) {
            if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
                audio_stream_idx = i;
                break;
            }
        }
        //获取解码器
        AVCodecContext *codecCtx = pFormatCtx->streams[audio_stream_idx]->codec;
        AVCodec *codec = avcodec_find_decoder(codecCtx->codec_id);
        //打开解码器
        if (avcodec_open2(codecCtx, codec, NULL) < 0) {
            LOGI("%s", "无法打开解码器");
            return;
        }
        //压缩数据
        AVPacket *packet = (AVPacket *) av_malloc(sizeof(AVPacket));
        //解压缩数据
        AVFrame *frame = av_frame_alloc();
        //frame->16bit 44100 PCM 统一音频采样格式与采样率
        SwrContext *swrContext = swr_alloc();
        //音频格式  重采样设置参数
        AVSampleFormat in_sample = codecCtx->sample_fmt;//原音频的采样位数
        //输出采样格式
        AVSampleFormat out_sample = AV_SAMPLE_FMT_S16;//16位
        int in_sample_rate = codecCtx->sample_rate;// 输入采样率
        int out_sample_rate = 44100;//输出采样
    
        //输入声道布局
        uint64_t in_ch_layout = codecCtx->channel_layout;
        //输出声道布局
        uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO;//2通道 立体声
    
        /**
         * struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
          int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
          int64_t  in_ch_layout, enum AVSampleFormat  in_sample_fmt, int  in_sample_rate,
          int log_offset, void *log_ctx);
         */
        swr_alloc_set_opts(swrContext, out_ch_layout, out_sample, out_sample_rate, in_ch_layout, in_sample,
                           in_sample_rate, 0, NULL);
        swr_init(swrContext);
        int got_frame = 0;
        int ret;
        int out_channerl_nb = av_get_channel_layout_nb_channels(out_ch_layout);
        LOGE("声道数量%d ", out_channerl_nb);
        int count = 0;
        //设置音频缓冲区间 16bit   44100  PCM数据
        uint8_t *out_buffer = (uint8_t *) av_malloc(2 * 44100);
        FILE *fp_pcm = fopen(output, "wb");//输出到文件
        while (av_read_frame(pFormatCtx, packet) >= 0) {
    
            ret = avcodec_decode_audio4(codecCtx, frame, &got_frame, packet);
            LOGE("正在解码%d", count++);
            if (ret < 0) {
                LOGE("解码完成");
            }
            //解码一帧
            if (got_frame > 0) {
                /**
                 * int swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
                                    const uint8_t **in , int in_count);
                 */
                swr_convert(swrContext, &out_buffer, 2 * 44100,
                            (const uint8_t **) frame->data, frame->nb_samples);
                /**
                 * int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,
                                   enum AVSampleFormat sample_fmt, int align);
                 */
                int out_buffer_size = av_samples_get_buffer_size(NULL, out_channerl_nb, frame->nb_samples,
                                                                 out_sample, 1);
                fwrite(out_buffer, 1, out_buffer_size, fp_pcm);//输出到文件
            }
        }
        fclose(fp_pcm);
        av_frame_free(&frame);
        av_free(out_buffer);
        swr_free(&swrContext);
        avcodec_close(codecCtx);
        avformat_close_input(&pFormatCtx);
    }
上一篇 下一篇

猜你喜欢

热点阅读