上一篇文章,是分离ts格式里的h264码流,分离出来后是可以直接播放的。但是对于mkv/flv/mp4等格式,直接分离h264码流是不能直接播放的,因为AVPacket的data里只包含视频压缩数据,并不包含pps,sps信息,也没有0x00000001和0x000001分隔符,没有这些信息,单凭h264码流是无法解码播放的。
H.264码流的SPS和PPS信息存储在AVCodecContext结构体的extradata中。需要使用ffmpeg中名称为“h264_mp4toannexb”的bitstream filter处理。
void demux(void)
{
const char *src_filename = "/Users/zhw/Desktop/sintel.mkv";
const char *video_dst_filename = "/Users/zhw/Desktop/sintel.h264";
int video_index;
AVFormatContext *ifmt_ctx = NULL;
AVPacket pkt;
/* open input file, and allocate format context */
if (avformat_open_input(&ifmt_ctx, src_filename, NULL, NULL) < 0) {
fprintf(stderr, "Could not open source file %s\n", src_filename);
exit(1);
}
/* retrieve stream information */
if (avformat_find_stream_info(ifmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not find stream information\n");
exit(1);
}
video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (video_index < 0) {
fprintf(stderr, "Could not find %s stream\n",
av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
return;
}
FILE *out_file = fopen(video_dst_filename, "wb");
if (!out_file) {
fprintf(stderr, "open out_file error");
return;
}
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
//设置AVBitStreamFilter
int ret;
AVBSFContext *bsf_ctx;
const AVBitStreamFilter *filter = av_bsf_get_by_name("h264_mp4toannexb");
if(!filter)
{
fprintf(stderr, "Unkonw bitstream filter");
return;
}
ret = av_bsf_alloc(filter, &bsf_ctx);
if (ret < 0) {
fprintf(stderr, "alloc bsf error");
return;
}
ret = avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[video_index]->codecpar);
if (ret < 0) {
fprintf(stderr, "copy bsf error");
return;
}
av_bsf_init(bsf_ctx);
//从文件读取数据
while (av_read_frame(ifmt_ctx, &pkt) >= 0) {
if (pkt.stream_index == video_index) {
if (av_bsf_send_packet(bsf_ctx, &pkt) < 0) {
fprintf(stderr, "send_packet error");
av_packet_unref(&pkt);
continue;
}
while (av_bsf_receive_packet(bsf_ctx, &pkt) == 0) {
fwrite(pkt.data, 1, pkt.size, out_file);
av_packet_unref(&pkt);
}
}
}
//flush
if (av_bsf_send_packet(bsf_ctx, NULL) < 0) {
fprintf(stderr, "send_packet error");
return;
}
while (av_bsf_receive_packet(bsf_ctx, &pkt) == 0) {
fwrite(pkt.data, 1, pkt.size, out_file);
av_packet_unref(&pkt);
}
av_bsf_free(&bsf_ctx);
printf("finish\n");
h264_parser(video_dst_filename);
}
查看所有可用的bitstream filter,可以在下载源码后,执行以下命令:
./configure --list-bsfs
资源文件下载地址: