使用FFmpeg C API修改time_base变速时视频正常音频截断如何解决
问题原因
你当前的实现存在两个核心错误,直接导致音频截断无加速效果:
- 直接修改输入流
in_stream的time_base属于非法操作:输入流的time_base是FFmpeg解封装时基于原始文件生成的参考值,修改后会导致后续时间戳换算的基准完全错误。 - 仅修改容器层面的time_base无法实现音频变速:音频播放时长由采样率 + 单帧采样数共同决定,播放器解码音频时会优先参考帧本身的采样参数计算播放长度,你仅压缩了容器层的时间戳,音频数据本身没有做任何调整,播放器到了压缩后的时间戳节点就会停止播放,自然就出现了内容截断、没有加速的效果。
修复方案
根据你是否需要变速不变调的效果,有两种实现路径:
方案1:变速不变调(推荐)
需要引入音频重采样/变速逻辑,不能只做容器层的参数修改,整体流程如下:
- 新增解码、重采样、编码流程:将读取到的音频包解码为原始帧,使用
libswresample或者libsonic库对原始音频帧做变速处理,调整帧的采样数后重新编码为AVPacket,再写入输出容器。 - 视频流可继续使用修改time_base的方式做同步,输出流的time_base要单独设置,不要修改输入流的参数,参考修改逻辑:
double speed = 2.0; // 2倍速,可自行调整 for (uint64_t i = 0; i < in_ctx->nb_streams; i++) { AVStream* in_stream = in_ctx->streams[i]; AVStream* out_stream = avformat_new_stream(out_ctx, NULL); if (!out_stream) { return fatal_error(); } // 不要修改输入流的time_base,单独设置输出流的time_base out_stream->time_base.num = in_stream->time_base.num; out_stream->time_base.den = in_stream->time_base.den * speed; avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar); // 音频流要额外修改输出编码器的采样率等参数,和变速后的音频帧匹配 }
方案2:接受变速变调,无需重采样
如果可以接受加速后音调升高、减速后音调降低的效果,可以不用引入解码编码流程,直接修改输出音频的编码参数配合时间戳调整即可:
double speed = 2.0; for (uint64_t i = 0; i < in_ctx->nb_streams; i++) { AVStream* in_stream = in_ctx->streams[i]; AVStream* out_stream = avformat_new_stream(out_ctx, NULL); if (!out_stream) { return fatal_error(); } avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar); out_stream->time_base.num = in_stream->time_base.num; out_stream->time_base.den = in_stream->time_base.den * speed; // 音频流单独修改采样率,和变速倍率匹配 if (in_stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { out_stream->codecpar->sample_rate = in_stream->codecpar->sample_rate * speed; } }
后续的时间戳rescale逻辑保持不变即可,此时播放器会按修改后的采样率播放音频,不会出现内容截断的问题。
内容的提问来源于stack exchange,提问作者JustFast
相关产品推荐
相关产品推荐

