FFMPEG avformat_find_stream_info替换
来源:互联网 发布:淘宝手机版店招制作 编辑:程序博客网 时间:2024/06/04 19:38
FFMPEG avformat_find_stream_info替换
前提
因为使用avformat_find_stream_info接口读取一部分视音频数据并且获得一些相关的信息。耗时太长,在网上查找了一些资料,看了雷神的讲解稍微了解了这个函数的功能,但是并没有得到如何降低耗时的问题,最后在网上找到了这篇文章 —— [ VLC优化(1) avformat_find_stream_info接口延迟降低 ]
这篇文章详细的说明了如何使用一些参数来降低avformat_find_stream_info接口的耗时,并提出了一种极端的解决方案,在已知发送端的流信息的情况下,跳过avformat_find_stream_info接口,自定义初始化解码环境。
我的音视频播放用的是雷神的 [ Simplest FFmpeg Player 2 ]中的SU(SDL Update)版。
过程
我稍微修改了读取数据的方式为rmpt,然后使用,但是我使用了他的方案后发现无法读取到一帧的数据,然后我反复对比avformat_find_stream_info接口和init_decode接口后的fmt_ctx参数的不同。
增加了一些codec信息,比如:
s->streams[audio_index]->codec->codec_type = AVMEDIA_TYPE_AUDIO;s->streams[audio_index]->codec->bit_rate = 16000;s->streams[audio_index]->codec->refs = 1;s->streams[audio_index]->codec->sample_fmt = AV_SAMPLE_FMT_FLTP;s->streams[audio_index]->codec->profile = 1;s->streams[audio_index]->codec->level = -99;s->streams[video_index]->codec->pix_fmt = AV_PIX_FMT_YUV420P;s->streams[video_index]->codec->sample_fmt = AV_SAMPLE_FMT_NONE;s->streams[video_index]->codec->codec_type = AVMEDIA_TYPE_VIDEO;
最后发现还是不行,在对比av_dump_format打印出来的音视频信息的不同,增加了一些配置:
char option_key[] = "encoder";char option_value[] = "Lavf57.0.100";ret = av_dict_set(&(s->metadata), option_key, option_value, 0);// AVDictionaryEntry *tag = NULL;// tag = av_dict_get((s->metadata), "", tag, AV_DICT_IGNORE_SUFFIX);s->duration = 0;s->start_time = 0;s->bit_rate = 0;s->iformat->flags = 0;s->duration_estimation_method = AVFMT_DURATION_FROM_STREAM;
发现av_dump_format打印出来的音视频消息都对了,但是还是无法读取视频数据。
继续找不同,发现s->packet_buffer里面没有数据,查找资料发现This buffer is only needed when packets were already buffered but not decoded, for example to get the codec parameters in MPEG streams. 看样子是里面要有数据啊,从av_dump_format源代码中搜索packet_buffer找到相关的代码:
ret = read_frame_internal(ic, &pkt1); if (ret == AVERROR(EAGAIN)) continue; if (ret < 0) { /* EOF or error*/ break; } if (ic->flags & AVFMT_FLAG_NOBUFFER) free_packet_buffer(&ic->packet_buffer, &ic->packet_buffer_end); { pkt = add_to_pktbuf(&ic->packet_buffer, &pkt1, &ic->packet_buffer_end); if (!pkt) { ret = AVERROR(ENOMEM); goto find_stream_info_err; } if ((ret = av_dup_packet(pkt)) < 0) goto find_stream_info_err; }
看样子是通过调用read_frame_internal读取一帧的数据放入packet_buffer,所以拷贝出相关代码read_frame_internal这个不能调用,但是有个av_read_frame这个函数对read_frame_internal进行了封装,可以调用这个函数
AVPacket packet; av_init_packet(&packet); int ret = av_read_frame(s, &packet); add_to_pktbuf(&(s->packet_buffer), &packet, &(s->packet_buffer_end));
还是不成功,断点查看,发现没有得到packet数据,在看看avformat_find_stream_info源代码:
ret = read_frame_internal(ic, &pkt1); if (ret == AVERROR(EAGAIN)) continue;
再改:
AVPacket packet;av_init_packet(&packet);while (true){ int ret1 = av_read_frame(s, &packet); if (packet.size > 0) { break; }}add_to_pktbuf(&(s->packet_buffer), &packet, &(s->packet_buffer_end));
终于得到了packet_buff的数据了,可是还是不行,在对比avformat_find_stream_info接口和init_decode接口后的fmt_ctx参数的不同,发现avformat_find_stream_info执行完后,avio_tell(s->pb), s->pb->seek_count两个的数据是相同的,而init_decode执行完avio_tell(s->pb), s->pb->seek_count两个的数据不同,查看init_decode中有关的代码get_video_extradata(),只知道这里面有对s->pb的操作,看不懂就先注释了,先看看效果,如果不行在自己修改s->streams[video_index]->codec->extradata和s->streams[video_index]->codec->extradata_size的数据,结果竟然可以了!!!完全没想到,怀疑avio_*** 这类函数可能有问题。放代码吧:
enum { FLV_TAG_TYPE_AUDIO = 0x08, FLV_TAG_TYPE_VIDEO = 0x09, FLV_TAG_TYPE_META = 0x12,};static AVStream *create_stream(AVFormatContext *s, int codec_type){ AVStream *st = avformat_new_stream(s, NULL); if (!st) return NULL; st->codec->codec_type = (AVMediaType)codec_type; return st;}static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, AVPacketList **plast_pktl){ AVPacketList *pktl = (AVPacketList *)av_mallocz(sizeof(AVPacketList)); if (!pktl) return NULL; if (*packet_buffer) (*plast_pktl)->next = pktl; else *packet_buffer = pktl; /* Add the packet in the buffered packet list. */ *plast_pktl = pktl; pktl->pkt = *pkt; return &pktl->pkt;}static int init_decode(AVFormatContext *s){ int video_index = -1; int audio_index = -1; int ret = -1; if (!s) return ret; /* Get video stream index, if no video stream then create it. And audio so on. */ if (0 == s->nb_streams) { create_stream(s, AVMEDIA_TYPE_VIDEO); create_stream(s, AVMEDIA_TYPE_AUDIO); video_index = 0; audio_index = 1; } else if (1 == s->nb_streams) { if (AVMEDIA_TYPE_VIDEO == s->streams[0]->codec->codec_type) { create_stream(s, AVMEDIA_TYPE_AUDIO); video_index = 0; audio_index = 1; } else if (AVMEDIA_TYPE_AUDIO == s->streams[0]->codec->codec_type) { create_stream(s, AVMEDIA_TYPE_VIDEO); video_index = 1; audio_index = 0; } } else if (2 == s->nb_streams) { if (AVMEDIA_TYPE_VIDEO == s->streams[0]->codec->codec_type) { video_index = 0; audio_index = 1; } else if (AVMEDIA_TYPE_VIDEO == s->streams[1]->codec->codec_type) { video_index = 1; audio_index = 0; } } /*Error. I can't find video stream.*/ if (video_index != 0 && video_index != 1) return ret; //Init the audio codec(AAC). s->streams[audio_index]->codec->codec_id = AV_CODEC_ID_AAC; s->streams[audio_index]->codec->sample_rate = 8000; s->streams[audio_index]->codec->time_base.den = 44100; s->streams[audio_index]->codec->time_base.num = 1; s->streams[audio_index]->codec->bits_per_coded_sample = 16; // s->streams[audio_index]->codec->channels = 1; s->streams[audio_index]->codec->channel_layout = 4; s->streams[audio_index]->codec->codec_type = AVMEDIA_TYPE_AUDIO; s->streams[audio_index]->codec->bit_rate = 16000; s->streams[audio_index]->codec->refs = 1; s->streams[audio_index]->codec->sample_fmt = AV_SAMPLE_FMT_FLTP; s->streams[audio_index]->codec->profile = 1; s->streams[audio_index]->codec->level = -99; s->streams[audio_index]->pts_wrap_bits = 32; s->streams[audio_index]->time_base.den = 1000; s->streams[audio_index]->time_base.num = 1; //Init the video codec(H264). s->streams[video_index]->codec->codec_id = AV_CODEC_ID_H264; s->streams[video_index]->codec->width = 1280; s->streams[video_index]->codec->height = 720; s->streams[video_index]->codec->ticks_per_frame = 2; s->streams[video_index]->codec->pix_fmt = AV_PIX_FMT_YUV420P; s->streams[video_index]->codec->time_base.den = 2000; s->streams[video_index]->codec->time_base.num = 1; s->streams[video_index]->codec->sample_fmt = AV_SAMPLE_FMT_NONE; s->streams[video_index]->codec->frame_size = 0; s->streams[video_index]->codec->frame_number = 7; s->streams[video_index]->codec->has_b_frames = 0; s->streams[video_index]->codec->codec_type = AVMEDIA_TYPE_VIDEO; s->streams[video_index]->codec->codec_tag = 0; s->streams[video_index]->codec->bit_rate = 0; s->streams[video_index]->codec->refs = 1; s->streams[video_index]->codec->sample_rate = 0; s->streams[video_index]->codec->channels = 0; s->streams[video_index]->codec->profile = 66; s->streams[video_index]->codec->level = 31; s->streams[video_index]->pts_wrap_bits = 32; s->streams[video_index]->time_base.den = 1000; s->streams[video_index]->time_base.num = 1; s->streams[video_index]->avg_frame_rate.den = 1; s->streams[video_index]->avg_frame_rate.num = 25; char option_key[] = "encoder"; char option_value[] = "Lavf57.0.100"; ret = av_dict_set(&(s->metadata), option_key, option_value, 0); AVDictionaryEntry *tag = NULL; tag = av_dict_get((s->metadata), "", tag, AV_DICT_IGNORE_SUFFIX); s->duration = 0; s->start_time = 0; s->bit_rate = 0; s->iformat->flags = 0; s->duration_estimation_method = AVFMT_DURATION_FROM_STREAM; AVPacket packet; av_init_packet(&packet); while (true) { int ret1 = av_read_frame(s, &packet); if (packet.flags & AV_PKT_FLAG_KEY) { break; } } add_to_pktbuf(&(s->packet_buffer), &packet, &(s->packet_buffer_end)); /*Need to change, different condition has different frame_rate. 'r_frame_rate' is new in ffmepg2.3.3*/ s->streams[video_index]->r_frame_rate.den = 1; s->streams[video_index]->r_frame_rate.num = 25; /*Update the AVFormatContext Info*/ s->nb_streams = 2; /* something wrong. TODO: find out the 'pos' means what. then set it. */ s->pb->pos = (int64_t)s->pb->buf_end; return ret;}if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){ printf("Couldn't open input stream.\n"); return -1;}init_decode(pFormatCtx);
相关参数按照自己的要求修改哈
参考:
[1]https://jiya.io/archives/vlc_optimize_1.html
[2]http://blog.csdn.net/leixiaohua1020/article/details/44084321
[3]http://blog.csdn.net/leixiaohua1020/article/details/12678577
- FFMPEG avformat_find_stream_info替换
- FFmpeg源代码简单分析:avformat_find_stream_info()
- FFmpeg函数简单分析:avformat_find_stream_info()
- avformat_find_stream_info
- 解决 ffmpeg 在avformat_find_stream_info执行时间太长
- ffmpeg源码跟踪笔记之avformat_find_stream_info
- 解决 ffmpeg 在avformat_find_stream_info执行时间太长
- ffmpeg学习七:avformat_find_stream_info函数源码分析
- 针对ffmpeg做rtsp客户端时,avformat_find_stream_info长时间等待问题
- 图解FFMPEG打开媒体的函数avformat_open_input&avformat_find_stream_info
- ffmpeg源码分析--8.avformat_find_stream_info及一些参数的确定
- ffmpeg源码简析(七)解码-avformat_open_input,avformat_find_stream_info()
- avformat_find_stream_info 崩溃
- avformat_find_stream_info分析
- avformat_find_stream_info函数卡住问题
- avformat_find_stream_info接口延迟降低
- FFMEPG函数avformat_find_stream_info作用
- 【zz】ffmpeg中av_strlcpy替换了pstrcpy
- 关于void*与void**的区别
- 斯科特.杨《如何高效学习》
- mac 安装 composer
- static关键字学习笔记
- HDUOJ1195 OpenLock简单遍历
- FFMPEG avformat_find_stream_info替换
- 每日一题(15): poj2533
- ebtables/iptables interaction on a Linux-based bridge
- NumPy之二:数组形状操作
- 图像处理与计算机视觉基础,经典以及最近发展
- Linux I2C驱动个人理解(二)
- spring cloud微服务框架 第四天
- 移动端input上传调用相机
- 数据结构—链表(三)