FFmpeg开发笔记(十四)FFmpeg音频重采样的缓存

简介: FFmpeg在视频流重编码和音频重采样中使用缓存机制。在音频文件格式转换时,特别是对于帧长度不固定的格式如ogg、amr、wma,需处理重采样缓存。通过调用`swr_convert`,传入空输入和0大小来清空缓存。在`swrmp3.c`中,修改帧样本数处理,并在循环结束后添加代码以冲刷缓存。编译并运行程序,将ogg文件重采样为MP3,日志显示操作成功,播放转换后的文件确认功能正常。

​FFmpeg在很多地方都运用了缓存机制,比如《FFmpeg开发实战:从零基础到短视频上线》一书的“3.3.2 对视频流重新编码”介绍了编解码的数据缓存,不单是视频编码过程和视频解码过程有缓存,甚至连音频重采样都用到了缓存。

也就是说,重采样函数swr_convert一次只会输出指定长度的音频数据,超出这个长度的数据被留在重采样的缓存当中。那么在对一个音频文件转换格式之时,有可能所有音频帧都遍历完了,重采样缓存里面还保存着剩余未取走的音频数据。此时要像对待视频编码缓存那样,想办法把剩下的音频数据冲出来。
具体到代码实现上,在调用swr_convert函数之时,倒数第二个参数填NULL,表示输入的数据内容为空;倒数第一个参数填0,表示输入的数据大小为0。这便告诉采样器,已经没有要转换的音频了,请把缓存中剩余的数据冲出来吧。那么swr_convert函数的返回值就是本次冲走的输出数据大小,当返回值为0时,表示重采样缓存已经冲光了,再也没有剩余的数据了,此时才能结束音频的格式转换操作。
当然,对于常见的mp3和aac格式,它们每帧的长度是固定的,正常情况调用一次swr_convert函数即可输出完整的音频数据,无需另外处理重采样缓存。只有ogg、amr、wma等格式的每帧音频长度不固定,才需要额外处理音频的重采样缓存,于是对《FFmpeg开发实战:从零基础到短视频上线》一书第五章的重采样代码改动如下。
打开chapter05/swrmp3.c,把下面这行

swr_frame->nb_samples = audio_decode_ctx->frame_size;

改为下面几行(因为ogg、amr和wma的frame_size为0,所以需要另外赋值):

swr_frame->nb_samples = audio_decode_ctx->frame_size;
if (swr_frame->nb_samples <= 0) {
    swr_frame->nb_samples = 512;
}

另外在轮询数据包的循环结束之后,补充下面的重采样缓存冲刷代码,这样新生成的音频文件才是完整的:

while (1) { // 冲走重采样的缓存(兼容对ogg、amr等格式的重采样)
    // 重采样。也就是把输入的音频数据根据指定的采样规格转换为新的音频数据输出
    ret = swr_convert(swr_ctx, // 音频采样器的实例
                    // 输出的数据内容和数据大小
                    swr_frame->data, swr_frame->nb_samples,
                    // 输入内容填NULL、输入大小填0表示冲走缓存
                    NULL, 0);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "swr_convert frame occur error %d.\n", ret);
        return -1;
    } else if (ret == 0) { // 到末尾了
        break;
    }
    save_mp3_file(fp_out, swr_frame); // 把音频帧保存到MP3文件
}

接着执行下面的编译命令。

gcc swrmp3.c -o swrmp3 -I/usr/local/ffmpeg/include -L/usr/local/ffmpeg/lib -lavformat -lavdevice -lavfilter -lavcodec -lavutil -lswscale -lswresample -lpostproc -lm

编译完成后执行以下命令启动测试程序,期望把ring.ogg重采样后保存为MP3文件。

./swrmp3 ../ring.ogg

程序运行完毕,发现控制台输出以下的日志信息,说明完成了对ogg文件重采样mp3音频的操作。

Success open input_file ring.ogg.
audio_decode_ctx frame_size=0, sample_fmt=8, sample_rate=11025, nb_channels=1
audio_encode_ctx frame_size=1152, sample_fmt=6, sample_rate=44100, nb_channels=1
target audio file is output_swrmp3.mp3
Success resample audio frame as mp3 file.

然后打开影音播放器可以正常播放output_swrmp3.mp3,表示上述代码正确实现了将ogg音频数据重采样再转存MP3文件的功能。

目录
相关文章
|
2天前
|
编解码 Linux 5G
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
AVS3,中国制定的第三代音视频标准,是首个针对8K和5G的视频编码标准,相比AVS2和HEVC性能提升约30%。uavs3d是AVS3的解码器,支持8K/60P实时解码,且在各平台有优秀表现。要为FFmpeg集成AVS3解码器libuavs3d,需从GitHub下载最新源码,解压后配置、编译和安装。之后,重新配置FFmpeg,启用libuavs3d并编译安装,通过`ffmpeg -version`确认成功集成。
12 0
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
|
3天前
|
存储 缓存 调度
FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频
《FFmpeg开发实战》第10章示例playsync.c在处理音频流和视频流交错的文件时能实现同步播放,但对于分开存储的格式,会出现先播放全部声音再快速播放视频的问题。为解决此问题,需改造程序,增加音频处理线程和队列,以及相关锁,先将音视频帧读入缓存,再按时间戳播放。改造包括声明新变量、初始化线程和锁、修改数据包处理方式等。代码修改后在playsync2.c中,编译运行成功,控制台显示日志,SDL窗口播放视频并同步音频,证明改造有效。
11 0
FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频
|
6天前
FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
《FFmpeg开发实战》一书中,第10章示例程序playaudio.c原本仅支持mp3和aac音频播放。为支持ogg、amr、wma等非固定帧率音频,需进行三处修改:1)当frame_size为0时,将输出采样数量设为512;2)遍历音频帧时,计算实际采样位数以确定播放数据大小;3)在SDL音频回调函数中,确保每次发送len字节数据。改进后的代码在chapter10/playaudio2.c,可编译运行播放ring.ogg测试,成功则显示日志并播放铃声。
16 1
FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
|
6天前
|
算法 Linux Windows
FFmpeg开发笔记(十七)Windows环境给FFmpeg集成字幕库libass
在Windows环境下为FFmpeg集成字幕渲染库libass涉及多个步骤,包括安装freetype、libxml2、gperf、fontconfig、fribidi、harfbuzz和libass。每个库的安装都需要下载源码、配置、编译和安装,并更新PKG_CONFIG_PATH环境变量。最后,重新配置并编译FFmpeg以启用libass及相关依赖。完成上述步骤后,通过`ffmpeg -version`确认libass已成功集成。
23 1
FFmpeg开发笔记(十七)Windows环境给FFmpeg集成字幕库libass
|
6天前
|
消息中间件 缓存 NoSQL
Redis经典问题:缓存雪崩
本文介绍了Redis缓存雪崩问题及其解决方案。缓存雪崩是指大量缓存同一时间失效,导致请求涌入数据库,可能造成系统崩溃。解决方法包括:1) 使用Redis主从复制和哨兵机制提高高可用性;2) 结合本地ehcache缓存和Hystrix限流降级策略;3) 设置随机过期时间避免同一时刻大量缓存失效;4) 使用缓存标记策略,在标记失效时更新数据缓存;5) 实施多级缓存策略,如一级缓存失效时由二级缓存更新;6) 通过第三方插件如RocketMQ自动更新缓存。这些策略有助于保障系统的稳定运行。
291 1
|
6天前
|
存储 消息中间件 缓存
Redis缓存技术详解
【5月更文挑战第6天】Redis是一款高性能内存数据结构存储系统,常用于缓存、消息队列、分布式锁等场景。其特点包括速度快(全内存存储)、丰富数据类型、持久化、发布/订阅、主从复制和分布式锁。优化策略包括选择合适数据类型、设置过期时间、使用Pipeline、开启持久化、监控调优及使用集群。通过这些手段,Redis能为系统提供高效稳定的服务。
|
2天前
|
NoSQL Redis 缓存
【后端面经】【缓存】36|Redis 单线程:为什么 Redis 用单线程而 Memcached 用多线程?
【5月更文挑战第17天】Redis常被称为单线程,但实际上其在处理命令时采用单线程,但在6.0后IO变为多线程。持久化和数据同步等任务由额外线程处理,因此严格来说Redis是多线程的。面试时需理解Redis的IO模型,如epoll和Reactor模式,以及其内存操作带来的高性能。Redis使用epoll进行高效文件描述符管理,实现高性能的网络IO。在讨论Redis与Memcached的线程模型差异时,应强调Redis的单线程模型如何通过内存操作和高效IO实现高性能。
28 7
【后端面经】【缓存】36|Redis 单线程:为什么 Redis 用单线程而 Memcached 用多线程?
|
6天前
|
缓存 NoSQL 关系型数据库
【Redis】Redis 缓存重点解析
【Redis】Redis 缓存重点解析
15 0
|
6天前
|
缓存 NoSQL 关系型数据库
【Redis】Redis作为缓存
【Redis】Redis作为缓存
8 0
|
6天前
|
存储 缓存 监控
利用Redis构建高性能的缓存系统
在现今高负载、高并发的互联网应用中,缓存系统的重要性不言而喻。Redis,作为一款开源的、内存中的数据结构存储系统,它可以用作数据库、缓存和消息代理。本文将深入探讨Redis的核心特性,以及如何利用Redis构建高性能的缓存系统,并通过实际案例展示Redis在提升系统性能方面的巨大潜力。