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替换相关推荐

  1. FFMpeg.AutoGen(1)讲解官方example代码:Main函数、 解码

    FFMpeg是一套C编译的开源工具集.主要用于视频处理,可以编解码视频,建立流媒体服务器等等.官方网站:http://ffmpeg.org/ FFMpeg.AutoGen封装方法以方便C#调用FFmp ...

  2. 利用第三方解码器ffmpeg让群晖DSM6.2.4版本的Video Station支持DTS视频编码和EAC3音频编码

    前言 截至2022年5月6日,此方法可用! 本文章可以解决群晖版本6.2.4-25556 Update5(Video Station版本2.5.0-1656)在播放dts.eac3音频编码的视频时提示 ...

  3. ffmpeg 修改视频封面

    千金纵买相如赋,脉脉此情谁诉. 概述 有时候我们希望使用某一张图片作为视频素材的封面 ,而不是素材中的某帧.今天使用ffmpeg批量替换视频素材封面. 环境装备 从官网下载安装 ffmpeg 准备素材 ...

  4. FFMpeg.AutoGen+D2D解码并播放视频(含音频流)

    最近在捣鼓FFMpeg这个东西,可惜网上的资料实在难找,对于c#里面的FFmpeg.AutoGen更是如此.所以走了不少弯路.(语言组织能力不太好,这篇文章的东西会很杂.涉及到d2d绘图的部分,我封装 ...

  5. [原创]JAVA FFMPEG 绿幕 设置背景 添加图标

    在JAVA中使用FFMPEG编辑绿幕视频的背景,添加图标 准备工作 使用Maven引入FFMPEG相关依赖 安装一个FFMPEG,用于调试命令 编写FFMPEG命令 替换绿幕背景 JAVA程序 准备工 ...

  6. Java转码amr_java amr格式转mp3格式(完美解决Linux下转换0K问题)

    原文:http://linjie.org/2015/08/06/amr%E6%A0%BC%E5%BC%8F%E8%BD%ACmp3%E6%A0%BC%E5%BC%8F-%E5%AE%8C%E7%BE% ...

  7. Python silk 库 支持微信语音

    GitHub 项目地址 python silk codec binding 支持微信语音编解码 pilk python silk codec binding 支持微信语音编解码 pilk: pytho ...

  8. Mencoder MPlayer 参数详解

    MPlayer(1)                        电影播放器                        MPlayer(1) D>0>        mplayer  ...

  9. mplayer全参数

    mplayer(1)                        电影播放器                        MPlayer(1) D0        mplayer  - 影视播放器 ...

最新文章

  1. Bash shell中的位置参数$#,$*,$@,$0,$1,$2...及特殊参数$?,$-等的含义
  2. Python 3.x 引入了函数注释
  3. 程序员吐槽_某程序员吐槽一程序员大佬竟然放弃百度offer,回老家进烟草公司!是不是脑子有坑?网友:你才脑子有坑!...
  4. 【Linux】基础知识
  5. Pycharm启动后总是不停的updating indices...indexing
  6. 算术溢出使用4字节值上的运算符_c语言程序设计的数据类型、运算符和表达式介绍...
  7. 杜比dss200服务器重装,杜比数字影片库 DSL200 (Dolby Show Library DSL200)
  8. 线性表的顺序存储C++代码实现
  9. ubuntu下rabbitvcs安装后无右键菜单解决办法
  10. java pv uv_使用Spark计算PV、UV
  11. Maltlab代码:四种基本的信道编码格式
  12. Ardunio程序设计基础 一
  13. 华为策略路由,实现双线选路上网
  14. 计算机找不到ac97前面板怎么办,Win7前面板没有声音的解决方法(声卡设置+前面板插线)...
  15. vue将图片保存到相册_vue 图片下载到本地,图片保存到本地
  16. 在 js 中应用 订阅发布模式(subscrib/public)
  17. Training data-efficient image transformers distillation through attention
  18. 描写计算机教室的词语,关于描写教室的词语
  19. 3、管理员添加内容的实现
  20. 无法定位程序输入点于动态链接库

热门文章

  1. C# TextBox控件,回车键实现点击按钮即自动登录的方法
  2. errorC4996: 'AVStream::codec': 被声明为已否决
  3. 国际足坛因伤退役的八大天才(四)
  4. 动态数组(Array)
  5. ironpython和.net
  6. 原来学好数据分析,你还能搞热搜、判断哪里帅哥/美女多…
  7. viewsonic(优派)按下显示屏关闭键,提示“电源按键已锁定”的解决办法。
  8. SpringBoot整合shiro-spring-boot-starter
  9. linux命令进u 盘,UNetbootin Linux操作系统装进移动硬盘
  10. linux管道符查看家目录,深入学习Linux之Linux中的管道符 | 和grep,awk,cut命令