MPEG 解封装


MPEG 解封装


因为工作需求,需要将MP4/MKV中的H264/H265裸流给拉出来单独保存。
网上搜索以后前人已经有了一些探索,比如:
最简单的基于FFmpeg的封装格式处理:视音频分离器简化版
从flv文件中提取h264码流(使用av_bsf_send_packet和av_bsf_receive_packet)

流程

大概流程就是拆包,拿到一帧帧的AVPacket以后转存到文件中就行,但测试发现MP4和MKV中的packet没有SPS和PPS头,所以我们就需要使用h264_mp4toannexbhevc_mp4toannexb这两个bitstream filter来对packet进行处理。

h264_mp4toannexb

@section h264_mp4toannexb

Convert an H.264 bitstream from length prefixed mode to start code
prefixed mode (as defined in the Annex B of the ITU-T H.264
specification).

This is required by some streaming formats, typically the MPEG-2
transport stream format (muxer @code{mpegts}).

For example to remux an MP4 file containing an H.264 stream to mpegts
format with @command{ffmpeg}, you can use the command:

贴上h264_mp4toannexb的相关信息,简单来说就是将bitstream从length prefixed mode 转为 start code prefixed mode,更为具体的信息可以参考H.264的附录B(annexb)

hevc_mp4toannexb

@section hevc_mp4toannexb

Convert an HEVC/H.265 bitstream from length prefixed mode to start code
prefixed mode (as defined in the Annex B of the ITU-T H.265
specification).

This is required by some streaming formats, typically the MPEG-2
transport stream format (muxer @code{mpegts}).

For example to remux an MP4 file containing an HEVC stream to mpegts
format with @command{ffmpeg}, you can use the command:

@example
ffmpeg -i INPUT.mp4 -codec copy -bsf:v hevc_mp4toannexb OUTPUT.ts
@end example

Please note that this filter is auto-inserted for MPEG-TS (muxer
@code{mpegts}) and raw HEVC/H.265 (muxer @code{h265} or
@code{hevc}) output formats.

H.265情况与H.264情况类似。

代码

主要使用av_bsf_send_packetav_bsf_receive_packet来实现。

int mp4toannexb(DEMUXER_T *demuxer, AVPacket *pkt)
{
    int ret;

    ret = av_bsf_send_packet(demuxer->bsf_ctx, pkt);
    if (ret < 0) {
        printf("bsf send packet failed, errno: %d \n", ret);
        return -1;
    }

    for(;;) {
        ret = av_bsf_receive_packet(demuxer->bsf_ctx, pkt);
        if (AVERROR_EOF == ret || AVERROR(EAGAIN) == ret) {
            return 0;
        }
        if (ret < 0) {
            printf("Could not receive packet, errno: %d \n", ret);
            return -1;
        }
    }
}

int create_filter(DEMUXER_T *demuxer) {
    int ret, codec_id = demuxer->ctx->streams[demuxer->video_index]->codecpar->codec_id;
    const AVBitStreamFilter *filter;

    switch (codec_id) {
    case AV_CODEC_ID_H264:
        filter = av_bsf_get_by_name("h264_mp4toannexb");
        break;
    case AV_CODEC_ID_HEVC:
        filter = av_bsf_get_by_name("hevc_mp4toannexb");
        break;
    default:
        printf("Unspport Codec id: %d \n", codec_id);
        return -1;
    }

    if (NULL == filter) {
        printf("Could not create filter \n");
        return -1;
    }

    ret = av_bsf_alloc(filter, &demuxer->bsf_ctx);
    if (ret < 0) {
        printf("Could not alloc bitstream filter \n");
        return -1;
    }

    // avcodec_parameters_from_context
    ret = avcodec_parameters_copy(demuxer->bsf_ctx->par_in, demuxer->ctx->streams[demuxer->video_index]->codecpar);
    if (ret < 0) {
        printf("Parameter copy filed, errno: %d \n", ret);
        goto L_ERR_PARAMETERS_COPY;
    }

    ret = av_bsf_init(demuxer->bsf_ctx);
    if (ret < 0) {
        printf("BSF init failed, errno: %d \n", ret);
        goto L_ERR_BSF_INIT;
    }

    return 0;

L_ERR_BSF_INIT:
L_ERR_PARAMETERS_COPY:
    av_bsf_free(&demuxer->bsf_ctx);
    return ret;
}

完整的代码已上传GitHub(mpeg_demuxer)。

ffmpeg命令行操作

代码写完后发现其实一条命令就能解决问题,-_-||

ffmpeg -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264

写在最后

一般来说只有H.264和hevc有裸流,其他编码格式一般没有。
比如mkv格式的vp9,我们一般将它转为ivf格式。

ffmpeg -i input.mkv -c copy stream.vp9.ivf
ffmpeg -i input.webm -c copy stream.ivf
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值