分离某些封装格式(例如MP4/FLV/MKV等)中的H.264的时候,需要首先写入SPS和PPS,否则会导致分离出来的数据没有SPS、PPS而无法播放。H.264码流的SPS和PPS信息存储在AVCodecContext结构体的extradata中。需要使用ffmpeg中名称为“h264_mp4toannexb”的bitstream filter处理。
原有的API已被弃用,新的API如下:
// Query
const AVBitStreamFilter *av_bsf_next(void **opaque);
const AVBitStreamFilter *av_bsf_get_by_name(const char *name);
// Setup
int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **ctx);
int av_bsf_init(AVBSFContext *ctx);
// Usage
int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt);
int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt);
// Cleanup
void av_bsf_free(AVBSFContext **ctx);
Query
You can enumerate the available filters
void *state = NULL;
const AVBitStreamFilter *bsf;
while ((bsf = av_bsf_next(&state)) {
av_log(NULL, AV_LOG_INFO, "%s\n", bsf->name);
}
or directly pick the one you need by name:
const AVBitStreamFilter *bsf = av_bsf_get_by_name("hevc_mp4toannexb");
Setup
A bsf may use some codec parameters and time_base and provide updated ones.
AVBSFContext *ctx;
ret = av_bsf_alloc(bsf, &ctx);
if (ret < 0)
return ret;
ret = avcodec_parameters_copy(ctx->par_in, in->codecpar);
if (ret < 0)
goto fail;
ctx->time_base_in = in->time_base;
ret = av_bsf_init(ctx);
if (ret < 0)
goto fail;
ret = avcodec_parameters_copy(out->codecpar, ctx->par_out);
if (ret < 0)
goto fail;
out->time_base = ctx->time_base_out;
Usage
Multiple AVPackets may be consumed before an AVPacket is emitted or multiple AVPackets may be produced out of a single input one.
AVPacket *pkt;
while (got_new_packet(&pkt)) {
ret = av_bsf_send_packet(ctx, pkt);
if (ret < 0)
goto fail;
while ((ret = av_bsf_receive_packet(ctx, pkt)) == 0) {
yield_packet(pkt);
}
if (ret == AVERROR(EAGAIN)
continue;
IF (ret == AVERROR_EOF)
goto end;
if (ret < 0)
goto fail;
}
// Flush
ret = av_bsf_send_packet(ctx, NULL);
if (ret < 0)
goto fail;
while ((ret = av_bsf_receive_packet(ctx, pkt)) == 0) {
yield_packet(pkt);
}
if (ret != AVERROR_EOF)
goto fail;
In order to signal the end of stream a NULL pkt should be fed to send_packet.
Cleanup
The cleanup function matches the av_freep signature so it takes the address of the AVBSFContext pointer.
av_bsf_free(&ctx);
All the memory is freed and the ctx pointer is set to NULL.
ps: FFmpeg给出的例子中并未while循环调用av_bsf_receive_packet,也未对其flush。
https://blogs.gentoo.org/lu_zero/2016/03/21/bitstream-filtering/
网友评论