【写在前面】

        前面我介绍了视频解码的流程,发现基础讲得有点少。

        因此这里附上一些额外的基础内容:理解PCM音频数据格式

        本篇主要内容:

        1、FFmpeg音频解码基本流程

        2、libswresample的基本使用方法


 【正文开始】

        实际上音频解码和视频解码的流程是一样的,因此就不花篇幅讲流程了。

        这里先简单说一下不同的地方:

//找到音频流的索引
    audioIndex = av_find_best_stream(formatContext, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);

AVMEDIA_TYPE_AUDIO 即可。

        然后从解复用到解码出 PCM,和视频解码的流程是一样的。

        视频解码见:

libswresample

libswresample 是FFmpeg提供的重采样( Resample )库,所谓的重采样也可以简单理解为:样本转换,因此 libswresample

libswresample,首先得分配一个SwrContext ,它有两种分配方式:

swr_alloc() 分配一个 SwrContext 指针,并且必须使用 av_opt_set_*() 来设置参数。

具体的参数在 FFmpeg 源码下的 libswresample / options.c

如果你下载了Qt的源码,那么其中就包含了FFmpeg的源码( 因为 Chromium 源码包含FFmpeg,而Qt包含 Chromium ),它在 qtwebengine 中。

swr_alloc_set_opts() 分配的同时设置一些参数。

SwrContext *swrContext = swr_alloc_set_opts(nullptr, int64_t(codecContext->channel_layout), AV_SAMPLE_FMT_S32, codecContext->sample_rate,
                                                int64_t(codecContext->channel_layout), codecContext->sample_fmt, codecContext->sample_rate,
                                                0, nullptr);
    swr_init(swrContext);

        我使用第二种方式分配,因为这里不需要那么多参数。

SwrContext 后,必须使用 swr_init()

avcodec_receive_frame() 获取到一帧解码的数据后,就可以进行转换了:

int size = av_samples_get_buffer_size(nullptr, frame->channels, frame->nb_samples, AV_SAMPLE_FMT_S32, 0);
    uint8_t *buf = new uint8_t[size];
    swr_convert(swrContext, &buf, frame->nb_samples, const_cast<const uint8_t**>(frame->data), frame->nb_samples);
    delete[] buf;

av_samples_get_buffer_size()

        2、new (分配) 一个缓冲区。

swr_convert()

因为FFmpeg的注释已经足够详细了,所以我从不讲参数。

buf 中了,记住别忘了 delete。 


【结语】

        本篇实在是没什么好写的,因为FFmpeg的抽象,所以解码视频和音频的流程基本差不多。

        不过,解码字幕的时候倒是有些不同,这在后面会进行讲解的。