【Qt+FFmpeg】解码音频流程

音频解码流程和视频解码流程差不多,理解了一个另一个应该也很好掌握;

解码视频请移步【Qt+FFmpeg】FFmpeg解码本地视频流程_logani的博客-CSDN博客

一、视频播放器的实现框架

 

 解码音频流程图:

 

二、音频解码具体流程

1.注册所有组件

void video::openAudioFile(QString filename)
{
    av_register_all();

2.打开音频输入文件

    AVFormatContext *formatContentAudio=avformat_alloc_context();
    //打开输入视频文件,filename是传参进来的
    int avformat_open_result=avformat_open_input(&formatContentAudio,filename.toStdString().c_str(),nullptr,nullptr);

    if(avformat_open_result!=0)
    {
        qDebug()<<"无法打开输入音频文件";
        return;
    }

3.查找对应音频流

  • 判断是否有流媒体数据-获取视频文件信息,第二个参数结构体用 null,返回一个 int 类型的数据,
  • 然后遍历所有类型的流(音频流、视频流、字幕流),找到音频流 (信息都是在封装视频格式formatContent 里面);
  • 结构体数组 formatContent->streams, 存放着多股流,每一股流都有一个该流对应的AVCodecContext

    int avformat_find_stream_info_result=avformat_find_stream_info(formatContentAudio,nullptr);
    if(avformat_find_stream_info_result<0)
    {
        qDebug()<<"无法获取视频文件信息";
        return;
    }
    //获取音频流的索引位置
    int audio_stream_idx =-1;
    //nb_streams 代表封装格式里面的结构体信息有几个,正常就两个:一个音频信息,一个视频信息
    for (int i=0;i<formatContentAudio->nb_streams;i++)
    {
        //流的类型
        if(formatContentAudio->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)
        {
            audio_stream_idx=i;//标识类型
            break;
        }
    }
    //判断是否有音频流信息
    if(audio_stream_idx==-1)
    {
        qDebug()<<"没找到音频流";
        return;
    }

4.查找音频解码器

查找解码器-根据音频流信息中的编码器类型 id 去查找合适的解码器, 返回的是一个解码器指针

    AVCodecContext *codec=formatContentAudio->streams[audio_stream_idx]->codec;
    AVCodec *decoder=avcodec_find_decoder(codec->codec_id);
    if(decoder==nullptr)
    {
        qDebug()<<"找不到解码器";
        return;
    }

5.打开解码器

    int avcodec_open2_result=avcodec_open2(codec,decoder,nullptr);
    if(avcodec_open2_result!=0)
    {
        qDebug()<<"打开解码器失败";
        return;
    }

为准备读取帧数据做准备

 AVPacket 用于存储一帧一帧的压缩音频数据 

    //缓冲区,开辟空间
    AVPacket *pkt=(AVPacket *)malloc(sizeof(AVPacket));
    int size=codec->width*codec->height;// save picture size
    av_new_packet(pkt,size);
    //AVFrame 用于存储解码后的音频数据
    AVFrame *picture;
    //内存分配
    picture=av_frame_alloc();
    //frame->16bit 44100 PCM 统一音频采样格式与采样率
    SwrContext *swrCtx = swr_alloc();
    //重采样设置选项------start
    //输入的采样格式
    enum AVSampleFormat in_sample_fmt = codec->sample_fmt;
    //输出的采样格式 16bit PCM
    enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
    //输入的采样率
    int in_sample_rate = codec->sample_rate;
    //输出的采样率
    int out_sample_rate = 44100;
    //输入的声道布局
    uint64_t in_ch_layout = codec->channel_layout;
    //输出的声道布局
    uint64_t out_ch_layout = AV_CH_LAYOUT_MONO;
    //获取输出的声道个数
    int out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);
    swr_alloc_set_opts(swrCtx, out_ch_layout, out_sample_fmt, out_sample_rate, in_ch_layout, in_sample_fmt, in_sample_rate, 0, nullptr);
    swr_init(swrCtx);

6.循环读取压缩音频数据

    //存储 pcm 数据
    uint8_t *out_buffer = (uint8_t *) av_malloc(2 * 44100);
    FILE *fp_pcm = fopen("out.pcm", "wb+");
    FILE *fp_aac = fopen("out.aac", "wb+");

    while(av_read_frame(formatContentAudio,pkt)>=0)
    {
        //只要视频压缩数据(根据流的索引位置判断)
        if(pkt->stream_index==audio_stream_idx)
        {
            //将码流数据写入 aac 文件中
            fwrite(pkt->data,pkt->size,1,fp_aac);
            int got_picture_ptr=-1;
            //7.解码一帧压缩音频数据
            int av_decode_result=avcodec_decode_audio4(codec,picture,&got_picture_ptr,pkt);
            if (av_decode_result < 0)
            {
                qDebug()<<"解码完成";
            }
            //为 0 说明解码完成,非 0 正在解码
            if(got_picture_ptr!=0)
            {
                /*参数 1:音频重采样的上下文
                参数 2:输出的指针。传递的输出的数组
                参数 3:输出的样本数量,不是字节数。单通道的样本数量。
                参数 4:输入的数组,AVFrame 解码出来的 DATA
                参数 5:输入的单通道的样本数量。
                */
                swr_convert(swrCtx,&out_buffer,2*44100, (const uint8_t**)(picture->data), picture->nb_samples);
                //获取 sample 的 size
                int out_buffer_size = av_samples_get_buffer_size(nullptr, out_channel_nb, picture->nb_samples, out_sample_fmt, 1);
                //写入文件进行测试
                fwrite(out_buffer, 1, out_buffer_size, fp_pcm);
            }
        }
        //释放资源
        av_packet_unref(pkt);
        av_frame_unref(picture);
    }

7.关闭释放资源

    //关闭 out.pcm 文件
    fclose(fp_pcm);
    fclose(fp_aac);
    //释放 AVFrame
    av_frame_free(&picture);
    av_free(out_buffer);
    swr_free(&swrCtx);
    //关闭解码器
    avcodec_close(codec);
    //释放视频信息结构体
    avformat_free_context(formatContentAudio);

工程目录底下生成的音频数据文件

 acc文件用腾讯视频可打开,pcm可用Softe Audio Converter软件进行查看;

感谢观看!!!!

以上就是全部内容,如果对您有帮助,欢迎点赞评论,或者发现有哪里写错的,欢迎指正!

猜你喜欢

转载自blog.csdn.net/logani/article/details/127247521