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;
}
相关推荐
智能直播8 小时前
网络RTMP拉流不卡顿、声音不同步,一文讲透缓冲区、时间戳
开发语言·ffmpeg·php·音视频·视频编解码
八月的雨季 最後的冰吻18 小时前
FFmepg-- 42-ffplay.c 线程安全机制深度分析
c语言·安全·ffmpeg
开开心心就好2 天前
把手机变成电脑麦克风,WiFi连接就能用
智能手机·ffmpeg·计算机外设·电脑·word·音视频
@嵌入式扫地僧2 天前
FFmpeg 解码 H.264 流提取 SEI 用户数据实战
ffmpeg·h.264·流媒体开发·sei 解析·自定义 sei
VimorphTech2 天前
ffmpeg.wasm 实战:浏览器提取视频音频,如何处理进度、取消和资源释放?
ffmpeg
小小龙学IT2 天前
FFmpeg 开源多媒体处理框架深度解析:从命令行到 libav* 全家桶
c语言·ffmpeg·开源
ofoxcoding3 天前
Gemini TTS 与 ElevenLabs 语音合成实测:同一段视频旁白效果对比
ai·ffmpeg·音视频
_大峰_4 天前
索尼 A7M4 误删视频恢复实战:基于原始卡镜像重建 MP4 数据
ffmpeg·数据恢复·音视频·mp4·exfat
Anhty4 天前
3 款手机音频剪辑 APP 横评,短视频配音后期,免费工具怎么选?
功能测试·ffmpeg·音视频
VidDown5 天前
自动给视频挑一张能看的封面:帧评分、构图与批量生成
python·ffmpeg·音视频·视频