最近在学习音视频开发,需要开发一个从flv文件中提取h264码流的demo。
具体的原理,在雷神的文章中写的很清楚了:
https://blog.csdn.net/leixiaohua1020/article/details/39767055
https://blog.csdn.net/leixiaohua1020/article/details/39802819
在这里致敬一下雷神,给我们这些小白入门音视频铺平了道路!
但是雷神在Demo中使用的API是旧版本的API,比如bitstream_filter相关的:
av_bitstream_filter_init()
av_bitstream_filter_filter()
等,这些API即将被弃用,我们需要使用新版本的API。
但是网上并没有找到相关的实现,根据上面链接的方法也并不能正确解析出h264码流。
在分析bitstream_filter.c源码后我们发现,在调用av_bsf_init()前需要调用avcodec_parameters_from_context(),增加解码必要的一些参数。
修改后的demo如下,大家可以用来参考。因为我也是刚入门,所以欢迎大家批评指正~:
#include <stdio.h>
#include <libavformat/avformat.h>
#define FFMPEG_NEW
int main() {
AVFormatContext *ifmt_ctx = NULL;
AVPacket pkt;
int ret, i;
int videoindex = -1, audioindex = -1;
const char *in_filename = "demo.flv";
const char *out_filename_v = "ffmpeg_demo.h264";
const char *out_filename_a = "ffmpeg_demo.mp3";
//av_register_all(); 已废弃
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
printf("Could not open input file.");
goto ERROR;
}
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
printf("Failed to retrieve input stream information");
goto ERROR;
}
videoindex = -1;
for (i=0; i<ifmt_ctx->nb_streams; i++) { //nb_streams:视音频流的个数
if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
videoindex = i;
else if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
audioindex = i;
}
printf("\nInput Video===========================\n");
av_dump_format(ifmt_ctx, 0, in_filename, 0); // 打印信息
printf("\n======================================\n");
FILE *fp_audio=fopen(out_filename_a,"wb+");
FILE *fp_video=fopen(out_filename_v,"wb+");
#ifdef FFMPEG_NEW
AVBSFContext *bsf_ctx = NULL;
const AVBitStreamFilter *pfilter = av_bsf_get_by_name("h264_mp4toannexb");
if (pfilter == NULL) {
printf("Get bsf failed!\n");
goto ERROR;
}
#else
AVBitStreamFilterContext* h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
#endif
while (av_read_frame(ifmt_ctx, &pkt) >= 0) {
if (pkt.stream_index == videoindex) {
#ifdef FFMPEG_NEW
if ((ret = av_bsf_alloc(pfilter, &bsf_ctx)) != 0) {
printf("Alloc bsf failed!\n");
goto ERROR;
}
ret = avcodec_parameters_from_context(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->codec);
if (ret < 0) {
printf("Set Codec failed!\n");
goto ERROR;
}
ret = av_bsf_init(bsf_ctx);
if (ret < 0) {
printf("Init bsf failed!\n");
goto ERROR;
}
av_bsf_send_packet(bsf_ctx, &pkt);
ret = av_bsf_receive_packet(bsf_ctx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0) {
printf("Receive Pkt failed!\n");
goto ERROR;
}
#else
av_bitstream_filter_filter(h264bsfc, ifmt_ctx->streams[videoindex]->codec, NULL, &pkt.data, &pkt.size, pkt.data, pkt.size, 0);
#endif
printf("Write Video Packet. size:%d\tpts:%lld\n",pkt.size,pkt.pts);
fwrite(pkt.data, 1, pkt.size, fp_video);
}
else if (pkt.stream_index == audioindex) {
printf("Write Audio Packet. size:%d\tpts:%lld\n",pkt.size,pkt.pts);
fwrite(pkt.data, 1, pkt.size, fp_audio);
}
av_packet_unref(&pkt);
}
#ifdef FFMPEG_NEW
av_bsf_free(&bsf_ctx);
#else
av_bitstream_filter_close(h264bsfc);
#endif
fclose(fp_video);
fclose(fp_audio);
avformat_close_input(&ifmt_ctx);
return 0;
ERROR:
if (ifmt_ctx)
avformat_close_input(&ifmt_ctx);
if (fp_audio)
fclose(fp_audio);
if (fp_video)
fclose(fp_video);
if (bsf_ctx)
av_bsf_free(&bsf_ctx);
return -1;
}