【写在前面】
前面我介绍了视频解码的流程,发现基础讲得有点少。
因此这里附上一些额外的基础内容:理解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的抽象,所以解码视频和音频的流程基本差不多。
不过,解码字幕的时候倒是有些不同,这在后面会进行讲解的。