You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FFmpeg C Demo出现时间戳更新失败警告的原因及解决方法

关于FFmpeg解码时出现"Could not update timestamps for skipped samples"警告的问题

问题现象

  • 测试WebM格式视频时,Opus解码器抛出如下警告:

[opus @ 0x5ec0fc1b4580] Could not update timestamps for skipped samples.
[opus @ 0x5ec0fc1b4580] Could not update timestamps for discarded samples.

  • 测试MP4格式视频时,AAC解码器也会出现类似警告:

[aac @ 0x61326fb83700] Could not update timestamps for skipped samples.

疑问

  1. 该警告是否确实由FFmpeg跳过数据包导致?若判断有误,请指出真实原因。
  2. 为何会出现样本跳过的情况?如何解决该问题?

测试Demo代码

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

int main()
{
    int ret = 0;

    const AVCodec* codec;
    AVFormatContext* fmt_ctx = avformat_alloc_context();

    const char* file2 = "/home/aabiji/Videos/sync-test.webm";
    if ((ret = avformat_open_input(&fmt_ctx, file2, NULL, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Couldn't open input file\n");
        return -1;
    }

    ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Couldn't find a media stream\n");
        return -1;
    }

    int stream_index = ret;
    AVStream* media = fmt_ctx->streams[stream_index];

    AVCodecContext* codec_context = avcodec_alloc_context3(codec);
    if (avcodec_parameters_to_context(codec_context, media->codecpar) < 0) {
        return -1;
    }

    if ((ret = avcodec_open2(codec_context, codec, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Couldn't open media decoder\n");
        return -1;
    }

    AVPacket* packet = av_packet_alloc();
    AVFrame* frame = av_frame_alloc();

    while ((ret = av_read_frame(fmt_ctx, packet)) >= 0) {
        if (packet->stream_index != stream_index) {
            continue;
        }

        ret = avcodec_send_packet(codec_context, packet);
        if (ret < 0) {
            break; // Error
        }

        while (ret >= 0) {
            ret = avcodec_receive_frame(codec_context, frame);
            if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
                break;
            } else if (ret < 0) {
                fprintf(stderr, "Error during decoding\n");
                break;
            }
            av_frame_unref(frame);
        }

        av_packet_unref(packet);
    }

    avcodec_flush_buffers(codec_context);

    av_packet_unref(packet);
    av_frame_free(&frame);
    av_packet_free(&packet);
    avcodec_free_context(&codec_context);
    avformat_close_input(&fmt_ctx);
    return 0;
}

原因分析

该警告并非由跳过数据包导致,本质是解码器处理音频帧时,遇到无效/冗余样本需要丢弃,但无法正确更新时间戳映射引发的。常见触发场景:

  • 音频帧存在损坏、不完整的样本数据,解码器主动丢弃无效样本
  • 音频流时间戳存在不连续、偏移,解码器同步时需丢弃部分样本对齐时间线
  • Demo代码未正确处理解码器的时间戳同步逻辑,也未处理avcodec_send_packet返回的非致命错误(如部分数据无效但可继续解码的情况)

解决方案

1. 正确处理avcodec_send_packet的非致命错误

原代码中avcodec_send_packet返回<0就直接终止解码,这会中断后续正常数据包的处理。对于AVERROR_INVALIDDATA这类非致命错误,仅需打印警告并继续处理下一个数据包:

ret = avcodec_send_packet(codec_context, packet);
if (ret < 0) {
    if (ret == AVERROR_INVALIDDATA) {
        av_log(codec_context, AV_LOG_WARNING, "Invalid data in packet: %s\n", av_err2str(ret));
        av_packet_unref(packet);
        continue;
    } else {
        av_log(codec_context, AV_LOG_ERROR, "Failed to send packet: %s\n", av_err2str(ret));
        break;
    }
}

2. 配置解码器时间基准

在打开解码器前,将解码器的数据包时间基准设置为对应音频流的时间基准,帮助解码器正确处理时间戳:

// 在avcodec_open2调用前添加
codec_context->pkt_timebase = media->time_base;

3. 正确处理解码器剩余帧

原代码中avcodec_flush_buffers的使用时机错误,应在av_read_frame循环结束后,发送NULL数据包触发解码器输出剩余帧:

// 替换原代码中的avcodec_flush_buffers调用
// 发送NULL表示输入结束,获取解码器缓存的剩余帧
ret = avcodec_send_packet(codec_context, NULL);
while (ret >= 0) {
    ret = avcodec_receive_frame(codec_context, frame);
    if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
        break;
    } else if (ret < 0) {
        fprintf(stderr, "Error flushing decoder: %s\n", av_err2str(ret));
        break;
    }
    av_frame_unref(frame);
}

4. 可选:屏蔽非致命警告

若确认这些警告不影响实际解码结果,可通过设置日志级别屏蔽:

// 在main函数开头添加
av_log_set_level(AV_LOG_ERROR);

内容的提问来源于stack exchange,提问作者aabiji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 23:23:10