• 音视频开发:ffplay使用sonic实现倍速播放


    前言

    现在的播放器通常都需要倍速播放功能,而且声音要求变速不变调。一般来说视频可以通过修改pts加速播放,音频如果通过修改采样率加速播放则会出现变调的现象,所以视频变速功能主要是实现音频的变速。音频要做到变速不变调,就要对音频数据进行一定的压缩或者拓展,我们可以使用一些音频处理库来达这种效果,比如谷歌的sonic。

    一、sonic的基本用法

    1. //创建对象
    2. sonicStream sncStream=sonicCreateStream(sample_rate, nb_channels);
    3. //设置倍速
    4. sonicSetSpeed(sncStream, 1.25);
    5. //写入音频裸流
    6. int ret = sonicWriteFloatToStream(sncStream,audio_buf, nb_samples);
    7. int numSamples = af->frame->nb_samples / speed;
    8. if (ret) {
    9. // 从流中读取处理好的数据
    10. int new_nb_samples = sonicReadFloatFromStream(sncStream, audio_buf, numSamples);
    11. }
    12. //销毁对象
    13. sonicDestroyStream(is->sncStream);

    二、ffplay中使用sonic

    要实现倍速有一个做法是,只对声音处理,把处理后的nb_samples更新给播放器 ,并且时钟同步到音频,这样视频也会跟踪音频一起改变速度。

    在ffplay中对音频数据进行处理,有两个地方比较适合,一个是音频重采样方法audio_decode_frame中,还一个是音频设备回调方法sdl_audio_callback中。这里我们选择在audio_decode_frame中对音频数据进行倍速处理。

    本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

    1、初始化sonicStream

    (1)、定义字段:

    可以在VideoState中添加sonicStream 字段

    sonicStream sncStream

    (2)、初始化

    初始化方法可以放在stream_component_open中伪代码如下:

    1. static int stream_component_open(VideoState* is, int stream_index)
    2. {
    3. ...ffplay源代码
    4. switch (avctx->codec_type) {
    5. case AVMEDIA_TYPE_AUDIO:
    6. ...ffplay源代码
    7. //初始化sonicStream
    8. is->sncStream = sonicCreateStream(sample_rate, nb_channels);
    9. break;
    10. }
    11. }

    2、倍速处理

    在audio_decode_frame中重采样后的音频数据回放在is->audio_buf指向的数据中,我们只需要对其处理即可。如果倍速大于1,则直接写回is->audio_buf指向的缓冲区,如果小于1则新建一个缓冲区装载数据,然后让is->audio_buf指向此缓冲区。

    (1)、定义字段

    在VideoState中定义速度参数以及数据缓冲区。

    1. double speed;
    2. char* speed_buf;
    3. int speed_buf_size;

    (2)、处理数据

    在audio_decode_frame中重采样后倍速处理,下列代码位置放在重采样后,更新时钟之前。

    1. double speed = is->speed;
    2. if (speed != 1)
    3. {
    4. //设置倍速
    5. sonicSetSpeed(is->sncStream, speed);
    6. sonicSetQuality(is->sncStream, 1);
    7. //写入音频数据
    8. int ret = sonicWriteShortToStream(is->sncStream, is->audio_buf, af->frame->nb_samples);
    9. if (ret) {
    10. //计算新的nb_samples,乘以2是为了保证sonicReadShortFromStream能一次读取全部的数据,否则可能造成累计延迟。
    11. int numSamples = 2 * af->frame->nb_samples / speed;
    12. if (speed < 1)
    13. //倍速小于1时使用自己的缓冲区
    14. {
    15. //计算缓冲区大小
    16. int size = numSamples * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
    17. if (is->speed_buf_size < size)
    18. {
    19. is->speed_buf = av_realloc(is->speed_buf, size);
    20. is->speed_buf_size = size;
    21. }
    22. is->audio_buf = is->speed_buf;
    23. }
    24. //读取处理后的数据
    25. int new_nb_samples = sonicReadShortFromStream(is->sncStream, is->audio_buf, numSamples);
    26. //重新计算数据大小
    27. resampled_data_size = new_nb_samples * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
    28. //设置新的nb_samples
    29. af->frame->nb_samples = new_nb_samples;
    30. }
    31. }

    3、释放资源

    在stream_component_close中的case AVMEDIA_TYPE_AUDIO中释放资源

    1. if (is->speed_buf)
    2. {
    3. av_free(is->speed_buf);
    4. is->speed_buf = NULL;
    5. }
    6. if (is->sncStream) {
    7. sonicDestroyStream(is->sncStream);
    8. is->sncStream=NULL;
    9. }

    如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论! 

    本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

  • 相关阅读:
    使用SqlServer客户端把Oracle数据库表导入到SqlServer
    说下 RESTful API 使用的几个方法
    Linux--ssh基本操作与配置
    腾讯云便宜服务器有哪些?腾讯云这个服务器一个月7块钱!
    基于树莓派CM4制作img系统镜像&批量制作TF卡
    Linux环境下安装JDK、Tomcat、MySQL并测试服务
    【数据仓库基础(四)】数据仓库需求:基本需求和数据需求
    Linux系统下一些配置建议整理
    计算系统概论ics第五章习题
    GaiaDB-X 获选北京国家金融科技认证中心「数据领域首批专项示范与先行单位」
  • 原文地址:https://blog.csdn.net/m0_60259116/article/details/127463414