2025-03-06 ffmpeg提取SPS/PPS/SEI ( extradata )

一、需求

在某些情况下,可能需要直接使用H264/H265等原始数据流进行解码,比较常用的udp下的h264/h265。这时需要 av_parser_parse2 来组AVPacket,但对于视频的信息:宽高、格式等,可以根据 AVCodecParserContext 来获取,也可以直接提取sps/pps/sei这些原始数据extradata

本文讲如何从原始数据流(AVPacket)中找出 extradata 信息

二、ffmpeg5.0版本以下

在旧版本的ffmpeg中, AVCodecParserContext 内部有个 split 函数,可以直接返回 extradata 在数据流中的位置

cpp 复制代码
 AVCodecParserContext* m_parser    = nullptr;
 
 // 初始化 m_parser  
 // ........
 //
 
 // m_ctx : AVCodecContext*
 // pkt : AVPacket*
 // 其中第一个参数 m_ctx 可以不设置,直接设置为nullptr也可
 auto re = m_parser->parser->split(m_ctx, pkt->data, pkt->size);
 if (re > 0) {
    if (m_ctx->extradata_size <= 0 && m_ctx->extradata == nullptr) {
        //存放于解码器的上下文中,,在m_ctx释放的时候会自动释放
         m_ctx->extradata_size = re;
         m_ctx->extradata      = (uint8_t*) av_malloc(m_ctx->extradata_size
                                                        + AV_INPUT_BUFFER_PADDING_SIZE);
         memcpy(m_ctx->extradata, pkt->data, m_ctx->extradata_size);
         }
  }
 

三、ffmpeg5.0版本以上

ffmpeg5.0后 AVCodecParserContext 的 split 函数已删除

但可以使用 av_bsf_get_by_name("extract_extradata")

以下代码可供参考

cpp 复制代码
bool VideoStreamUdpH26X::setupExtraData(const AVCodecParserContext* parser,
AVCodecContext*             ctx,
AVPacket*                   pkt)
{
    bool need = false;
    // 检查输入参数及必要信息
    if (!parser || !pkt || !ctx)
        return need;
    if (parser->width <= 0 || parser->height <= 0)
        return need;

    // 获取 extract_extradata BSF
    const AVBitStreamFilter* bsf = av_bsf_get_by_name("extract_extradata");
    if (!bsf) {
        LOG_DEBUG() << "extract_extradata BSF not found";
        return need;
    }

    AVBSFContext* bsf_ctx = nullptr;
    auto          ret     = av_bsf_alloc(bsf, &bsf_ctx);
    if (ret < 0) {
        LOG_DEBUG() << "Failed to allocate BSF context, ret = " << ret;
        return need;
    }

    // 设置 BSF 的输入参数(使用 parser 的部分信息)
    bsf_ctx->par_in->codec_id   = (AVCodecID) parser->parser->codec_ids[0];
    bsf_ctx->par_in->codec_type = AVMEDIA_TYPE_VIDEO;
    bsf_ctx->par_in->width      = parser->width;
    bsf_ctx->par_in->height     = parser->height;

    ret = av_bsf_init(bsf_ctx);
    if (ret < 0) {
        LOG_DEBUG() << "Failed to initialize BSF context, ret = " << ret;
        av_bsf_free(&bsf_ctx);
        return need;
    }

    // 将包送入 BSF 提取 extradata
    ret = av_bsf_send_packet(bsf_ctx, pkt);
    if (ret < 0) {
        LOG_DEBUG() << "Failed to send packet to BSF, ret = " << ret << printError(ret);
        av_bsf_free(&bsf_ctx);
        return need;
    }
    // 从 BSF 中取出过滤后的包
    ret = av_bsf_receive_packet(bsf_ctx, pkt);
    if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
        LOG_DEBUG() << "Failed to receive packet from BSF, ret = " << ret << printError(ret);
        av_bsf_free(&bsf_ctx);
        return need;
    }

    size_t   extradata_size = 0;
    uint8_t* side_extradata = av_packet_get_side_data(pkt,
    AV_PKT_DATA_NEW_EXTRADATA,
    &extradata_size);
    if (side_extradata && extradata_size > 0) {
        // 更新 extradata
        if (ctx->extradata_size != extradata_size) {
            if (ctx->extradata) {
                av_freep(&ctx->extradata);
                ctx->extradata_size = 0;
            }

            ctx->extradata = (uint8_t*) av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
            if (!ctx->extradata) {
                LOG_DEBUG() << "Failed to allocate memory for extradata";
                av_bsf_free(&bsf_ctx);
                return need;
            }
            ctx->extradata_size = extradata_size;

            memcpy(ctx->extradata, side_extradata, ctx->extradata_size);
            LOG_DEBUG() << "Extracted extradata: "
                << QByteArray((char*) ctx->extradata, ctx->extradata_size).toHex();
        }

        need = true;
    }

    av_bsf_free(&bsf_ctx);
    return need;
}
相关推荐
阿里巴啦1 天前
python+yt-dlp开源项目,支持 YouTube, Bilibili, TikTok/抖音,快手 等多个平台的视频/音频/字幕下载/ai摘要等功能
python·ffmpeg·whisper·音视频·视频处理·ai摘要·音视频转录
来鸟 鸣间2 天前
linux下ffmpeg源码编译
linux·运维·ffmpeg
Echo_NGC22372 天前
【FFmpeg使用指南】Part 2:滤镜图架构与信号处理
架构·ffmpeg·音视频·信号处理
Echo_NGC22372 天前
【FFmpeg使用指南】Part 1:核心架构与媒体流处理
ffmpeg·音视频·媒体·视频
ssxueyi2 天前
用 Claude Code 从零开发自己的Direct3D 硬件加速播放器
ffmpeg·ai编程·directx·视频播放器·从零开始·claude code·csdn征文活动
Yan_uuu2 天前
ubuntu18.04 安装 x264、ffmpeg、nv-codec-hearers 支持GPU硬件加速
c++·图像处理·ubuntu·ffmpeg
runner365.git3 天前
做一个基于ffmpeg的AI Agent智能体
人工智能·ffmpeg·大模型
彷徨而立3 天前
【FFmpeg】理解 av_packet_from_data 和 av_packet_unref 接口
ffmpeg
runner365.git3 天前
ffmpeg8.0合入whisper,语音识别模型终于进入ffmpeg
ffmpeg·whisper·语音识别
小徐敲java4 天前
视频推流服务器与FFmpeg 安装配置
服务器·ffmpeg·音视频