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;
}
相关推荐
问道飞鱼10 小时前
【工具介绍】Ffmpeg工具介绍与简单使用
ffmpeg·视频工具
l***775214 小时前
从MySQL5.7平滑升级到MySQL8.0的最佳实践分享
ffmpeg
ZouZou老师20 小时前
FFmpeg性能优化经典案例
性能优化·ffmpeg
aqi001 天前
FFmpeg开发笔记(九十)采用FFmpeg套壳的音视频转码百宝箱FFBox
ffmpeg·音视频·直播·流媒体
齐齐大魔王1 天前
FFmpeg
ffmpeg
你好音视频1 天前
FFmpeg RTSP拉流流程深度解析
ffmpeg
IFTICing2 天前
【环境配置】ffmpeg下载、安装、配置(Windows环境)
windows·ffmpeg
haiy20112 天前
FFmpeg 编译
ffmpeg
aqi002 天前
FFmpeg开发笔记(八十九)基于FFmpeg的直播视频录制工具StreamCap
ffmpeg·音视频·直播·流媒体
八月的雨季 最後的冰吻2 天前
FFmepg--28- 滤镜处理 YUV 视频帧:实现上下镜像效果
ffmpeg·音视频