ffmpeg-从mp4、flv、ts文件中提取264视频流数据
main.c
#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>void proc(int need_to_annexb, char* in_file, char* out_file)
{AVFormatContext* ifmat_ctx = NULL;int videoindex = -1;AVPacket* pkt = NULL;int ret = -1;int file_end = 0;//char* in_file = "believe.mp4";//char* out_file = "out_mp4_no_annexb.h264";FILE* out_fd = fopen(out_file, "wb");printf("in_file = %s , out_file = %s\n", in_file, out_file);//创建解复用器,最后使用avformat_close_input()释放相关内存ifmat_ctx = avformat_alloc_context();if(!ifmat_ctx){printf("avformat_alloc_context faild!\n");return -1;}//根据url打开码流,会选择匹配的解复用器的ret = avformat_open_input(&ifmat_ctx, in_file, NULL, NULL);if(ret != 0){printf("avformat_open_input failed!\n");return -1;}//读取媒体文件的部分数据包可以获取码流信息ret = avformat_find_stream_info(ifmat_ctx, NULL);if(ret < 0){printf("avformat_find_stream_info faile!\n");avformat_close_input(&ifmat_ctx);return -1;}//查找出哪个码流是音频还是视频还是字幕videoindex = av_find_best_stream(ifmat_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);if(videoindex == -1){printf("av_find_best_stream failed!\n");avformat_close_input(&ifmat_ctx);return -1;}//分配packetpkt = av_packet_alloc();av_init_packet(pkt);file_end = 0;while (0 == file_end){if((ret = av_read_frame(ifmat_ctx, pkt)) < 0){file_end = 1;printf("av_read_frame end!\n");}//读出的帧判断是否是视频帧if(ret == 0 && pkt->stream_index == videoindex){//是否需要使用h264_mp4toannexb转换if(need_to_annexb){//获取比特流过滤器(h264_mp4toannexb)const AVBitStreamFilter* bsfilter = av_bsf_get_by_name("h264_mp4toannexb");AVBSFContext *bsf_ctx = NULL;//申请过滤器上下文av_bsf_alloc(bsfilter, &bsf_ctx);//从视频流中拷贝编解决码器参数avcodec_parameters_copy(bsf_ctx->par_in, ifmat_ctx->streams[videoindex]->codecpar);//初始化过滤器上下文av_bsf_init(bsf_ctx);int input_size = pkt->size;//记录下是否send 一个packet,receive 一个packet。基本都是这个情况的//有比较少情况出现会send 一个packet,receive 几个packet//(SPS、PPS、I帧在一个packet send,receive 多个packet)。int out_pkt_count = 0;if(av_bsf_send_packet(bsf_ctx, pkt) != 0){//不管是否成功,都要释放packet,因为bitstreamfilter内部还有引用这个内存空间的av_packet_unref(pkt);continue;}//不管是否成功,都要释放packet,因为bitstreamfilter内部还有引用这个内存空间的av_packet_unref(pkt);while (av_bsf_receive_packet(bsf_ctx , pkt) == 0){out_pkt_count++;size_t size = fwrite(pkt->data, 1, pkt->size, out_fd);if(size != pkt->size){printf("fwrite failed!\n");}av_packet_unref(pkt);}//send 一个packet ,receive pakcet 超过2个就输出提示信息if(out_pkt_count >= 2){printf("one send packet size = %d, receive %d packet.\n", input_size,out_pkt_count);}if(bsf_ctx)av_bsf_free(&bsf_ctx);}else{size_t size = fwrite(pkt->data, 1, pkt->size, out_fd);if(size != pkt->size){printf("fwrite failed!\n");}av_packet_unref(pkt);}}else{if(ret == 0){av_packet_unref(pkt);}}}if(out_fd)fclose(out_fd);if(pkt)av_packet_free(&pkt);if(ifmat_ctx)avformat_close_input(&ifmat_ctx);}int main()
{proc(1, "believe.flv", "out_flv_need_toannexb.h264");//使用ffplay可以播放proc(0, "believe.flv", "out_flv_no_toannexb.h264");//使用ffplay不可以proc(1, "believe.mp4", "out_mp4_need_toannexb.h264");//使用ffplay可以播放proc(0, "believe.mp4", "out_mp4_no_toannexb.h264");//使用ffplay不可以proc(1, "believe.ts", "out_ts_need_toannexb.h264");//使用ffplay可以播放proc(0, "believe.ts", "out_ts_no_toannexb.h264");//使用ffplay可以播放//注意://flv/mp4/mkv一些结构中,h264需要h264_mp4toannexb处理,添加startcode/SPS/PPS等信息//ts不用h264_mp4toannexb处理。return 0;
}
flv两个文件的对比:
mp4两个文件的对比:
ts两个文件的对比: