VLC初始加载优化:avformat_find_stream_info接口延迟降低

ffmpeg拉流rtmp音频实时数据有延时的解决方法 最近在做一个从rtmp服务器中拉流音频实时数据会延迟播放的问题,从rtmp播放端发现,是探测时间太长了,超过了5s,播放数据就延迟播放了5second, 卡在了这个函数:avformat_find_stream_info(),我通过ffplay的以下命令可以解决播放延时的问题:   ffmpeg ffplay播放延时大问题:播放延时参数设置 本文转自:h 阅读详情

在进行demux时候,采用ffmpeg进行。


转载地址:http://jiya.io/archives/vlc_optimize_1.html


0x00 前置信息

版本:ffmpeg2.2.0
文件:vlc src/module/demux/avformat/demux.c
函数:OpenDemux

0x01 研究背景

ffmpeg的两个接口avformat_open_input和avformat_find_stream_info分别用于打开一个流和分析流信息。在初始信息不足的情况下,avformat_find_stream_info接口需要在内部调用read_frame_internal接口读取流数据,然后再分析后,设置核心数据结构AVFormatContext。由于需要读取数据包,avformat_find_stream_info接口会带来很大的延迟,那么有几种方案可以降低该接口的延迟,具体如下:

  1. 通过设置AVFormatContext的probesize成员,来限制avformat_find_stream_info接口内部读取的最大数据量,代码如下:
AVFormatContext *fmt_ctx = NULL;
ret = avformat_open_input(&fmt_ctx, url, input_fmt, NULL);
fmt_ctx->probesize = 4096;
ret = avformat_find_stream_info(fmt_ctx, NULL);

这样的方法其实会带来弊端,因为预读长度设置的过小时,在avformat_find_stream_info内部至多只会读取一帧数据,有些情况时,会导致这些数据不足以分析这个流的信息。

  1. 通过设置AVFormatContext的flags成员,来设置将avformat_find_stream_info内部读取的数据包不放入AVFormatContext的缓冲区packet_buffer中,代码如下:
AVFormatContext *fmt_ctx = NULL;
ret = avformat_open_input(&fmt_ctx, url, input_fmt, NULL);
fmt_ctx->flags |= AVFMT_FLAG_NOBUFFER;
ret = avformat_find_stream_info(fmt_ctx, NULL);

深入avformat_find_stream_info接口内部就可以发现,当设置了AVFMT_FLAG_NOBUFFER选项后,数据包不入缓冲区,相当于在avformat_find_stream_info接口内部读取的每一帧数据只用于分析,不显示,摘avformat_find_stream_info接口中的一段代码即可理解:

if (ic->flags & AVFMT_FLAG_NOBUFFER) {
   pkt = &pkt1;
} else {
   pkt = add_to_pktbuf(&ic->packet_buffer, &pkt1,
                       &ic->packet_buffer_end);
   if ((ret = av_dup_packet(pkt)) < 0)
      goto find_stream_info_err;
}

当读取的数据包很多时,实际avformat_find_stream_info接口内部尝试解码以及分析的过程也是耗时的(具体没有测试),所以想到一种极端的解决方案,直接跳过avformat_find_stream_info接口,自定义初始化解码环境。

0x02 解决方法

前提条件:发送端的流信息可知。

我这里环境的流信息为:
audio: AAC 44100Hz 2 channel 16bit
video: H264 640*480 30fps
直播流

调用avformat_open_input接口后,不继续调用avformat_find_stream_info接口,具体代码如下:

AVFormatContext *fmt_ctx = NULL;
ret = avformat_open_input(&fmt_ctx, url, input_fmt, NULL);
fmt_ctx->probesize = 4096;
ret = init_decode(fmt_ctx);

init_decode为自己实现的接口:接口及详细代码如下:

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 = codec_type;
    return st;
}

static int get_video_extradata(AVFormatContext *s, int video_index)
{
   int  type, size, flags, pos, stream_type;
   int ret = -1;
   int64_t dts;
   bool got_extradata = false;

   if (!s || video_index < 0 || video_index > 2)
      return ret;

   for (;; avio_skip(s->pb, 4)) {
      pos  = avio_tell(s->pb);
      type = avio_r8(s->pb);
      size = avio_rb24(s->pb);
      dts  = avio_rb24(s->pb);
      dts |= avio_r8(s->pb) << 24;
      avio_skip(s->pb, 3);

       if (0 == size)
          break;
       if (FLV_TAG_TYPE_AUDIO == type || FLV_TAG_TYPE_META == type) {
          /*if audio or meta tags, skip them.*/
          avio_seek(s->pb, size, SEEK_CUR);
       } else if (type == FLV_TAG_TYPE_VIDEO) {
         /*if the first video tag, read the sps/pps info from it. then break.*/
          size -= 5;
          s->streams[video_index]->codec->extradata = xmalloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
          if (NULL == s->streams[video_index]->codec->extradata)
             break;
          memset(s->streams[video_index]->codec->extradata, 0, size + FF_INPUT_BUFFER_PADDING_SIZE);
          memcpy(s->streams[video_index]->codec->extradata, s->pb->buf_ptr + 5, size);
          s->streams[video_index]->codec->extradata_size = size;
          ret = 0;
          got_extradata = true;
       } else  {
          /*The type unknown,something wrong.*/
           break;
       }

       if (got_extradata)
          break;
   }

   return ret;
}

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 = 44100;
     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 = 2;
     s->streams[audio_index]->codec->channel_layout = 3;
     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 = 640;
     s->streams[video_index]->codec->height = 480;
     s->streams[video_index]->codec->ticks_per_frame = 2;
     s->streams[video_index]->codec->pix_fmt = 0;
     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 = 90;
     s->streams[video_index]->avg_frame_rate.num = 3;
   /*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 = 60;
     s->streams[video_index]->r_frame_rate.num = 2;
   /* H264 need sps/pps for decoding, so read it from the first video tag.*/
     ret = get_video_extradata(s, video_index);

     /*Update the AVFormatContext Info*/
     s->nb_streams = 2;
     /*empty the buffer.*/
     s->pb->buf_ptr = s->pb->buf_end;
    /*
     something wrong.
     TODO: find out the 'pos' means what.
     then set it.
     */
     s->pb->pos = s->pb->buf_end;

     return ret;
}

分析:
在init_decode接口执行的操作如下:

  1. 经过avformat_open_input接口的调用,AVFormatContext内部有几个流其实是无法预知的,所以需要判断,没有的流需调用create_stream接口创建,并分别设置video_index和audio_index。
  2. 根据已知信息,初始化audio和video的流信息。
  3. 因为H264解码时需要sps/pps信息,这个信息在接收到的第一个video tag中,通过get_video_extradata接口获取:
    3.1 avio_*系列接口读到的数据已经是flv格式的,所以判断读到的tag如果是audio tag或者metadata tag时,跳过这个tag数据,继续读。
    3.2 如果是video tag,读取其中的数据至s->streams[video_index]->codec->extradata中,跳出循环。
  4. 更新AVFormatContext信息。
  5. 将缓冲区置空。

如果video tag是H263编码的,在init_decode接口内部,无需调用get_video_extradata接口即可成功初始化解码环境(需将codec_id设置为AV_CODEC_ID_FLV1)。

对于大多数情况,都可以通过自定义的接口init_decode替代avformat_find_stream_info接口来降低延迟,当然会有很多限制,就看具体项目需求了。

0x03 总结

init_decode接口能够适配多种设备发出的流,当然还有很多细节没有关注到,需要在后续研究中跟进。


Unity多路RTSP流低延迟渲染实战:基于libvlc的跨平台解决方案 在实时音视频处理领域,RTSP(实时流传输协议)是网络摄像头、安防监控等场景中广泛使用的流媒体协议。其工作原理是通过建立TCP或UDP连接,传输经过编码压缩的音视频数据流。对于需要在Unity引擎中集成实时视频流的应用(如智慧城市大屏、多视角直播、虚拟仿真),实现低延迟、高并发的RTSP流渲染是一大技术挑战。传统的Unity VideoPlayer组件因依赖系统原生播放框架,对RTSP支持不佳,延迟高且稳定性差,难以满足实时交互需求。为此,引入专业的流媒体处理库成为关键。libvlc作为VLC播放器的核心库 阅读详情

相关推荐

ffmpeg学习七:avformat_find_stream_info函数源码分析

前面两篇文章分析avformat_open_input和avcodec_open2两个函数,我们所做的函数分析工作都是为了能够很好的理解前面一篇博客:ffmpeg学习四:写第一个程序-视频解码中所给的视频解码的程序。avformat_find_stream_info函数也是视频解码程序中必须要有的函数,因此这篇文章主要来分析这个函数。一、功能简介先看看avformat_find_stream_inf

阳光玻璃杯 1万+

VLC优化(1) avformat_find_stream_info接口延迟降低

VLC优化(1) avformat_find_stream_info接口延迟降低 http://jiya.io/page/1/ 0x00 前置信息 版本:ffmpeg2.2.0 文件:vlc src/module/demux/avformat/demux.c 函数:OpenDemux 0x01 研究背景 ffmpeg的两个接口avformat_

maken 2508

解决FFmpeg中avformat_find_stream_info检索时间过长问题(Java)

本文介绍了三种解决avformat_find_stream_info检索时间过长问题的方法:延迟执行avformat_find_stream_info、设置解码器参数和使用多线程。通过设置analyzeduration和probesize参数,我们可以限制解码器对音视频流的解码时间和数据量,从而减少avformat_find_stream_info函数的执行时间。通过使用多线程,我们可以将avformat_find_stream_info函数的执行与其他任务并行处理,从而提高整体的执行效率。

DevSavantX的博客 791

FFMPEG avformat_find_stream_info替换

FFMPEG avformat_find_stream_info替换前提 因为使用avformat_find_stream_info接口读取一部分视音频数据并且获得一些相关的信息。耗时太长,在网上查找了一些资料,看了雷神的讲解稍微了解了这个函数的功能,但是并没有得到如何降低耗时的问题,最后在网上找到了这篇文章 —— [ VLC优化(1) avformat_find_stream_info

leo2007608的专栏 9198

FFmpeg —— 解决avformat_find_stream_info函数阻塞时间过长问题

问题      当在做一些音频推流工作时,在打开环境上下文后需要查找格式上下文信息(avformat_find_stream_info),但执行该函数的时间过于长了(约5~10秒),可能让人觉得很烦哦。那么我们今天来解决这个问题。        avformat_find_stream_info对于网络串流来说是需要花费时间进行探测一些信息的。所以可能时间较长。   解决      AVFotmatContext对象用probesize、max_analyze_duration两个参数,可以对其进行设置达到

2857

C# VlcDotNet播放RTSP流,延迟低400ms左右

最近用Vlc.DotNet.Forms.VlcControl 写了个demo,延迟达到400ms左右,应该是极限了,下面分享下。

遇见--专栏 2791

VLC优化(1) avformat_find_stream_info接口延迟降低——已知流信息

https://jiya.io/archives/vlc_optimize_1.html 0x00 前置信息 版本:ffmpeg2.2.0 文件:vlc src/module/demux/avformat/demux.c 函数:OpenDemux 0x01 研究背景 ffmpeg的两个接口avformat_open_input和avformat_find_s

STN_LCD的专栏 1882

基于FFmpeg与Qt的RTSP网络摄像头实时显示系统开发实践

实时视频流处理是计算机视觉与多媒体应用中的基础技术,其核心在于高效、稳定地从网络协议中获取、解码并渲染视频数据。RTSP(实时流协议)作为网络摄像头、安防监控等领域的标准流媒体传输协议,其客户端开发常面临低延迟、高稳定性的挑战。FFmpeg作为业界领先的音视频处理库,提供了从协议解复用、解码到像素格式转换的完整底层控制能力,是实现高性能流媒体处理的技术基石。结合Qt框架强大的跨平台GUI开发与高效的信号槽线程通信机制,能够构建出响应迅速、界面友好的客户端应用。这种组合方案尤其适用于工业质检、安防监控、视频会

weixin_33585822的博客 302

avformat_find_stream_info接口延迟降低

0x00 前置信息 版本:ffmpeg2.2.0 文件:vlc src/module/demux/avformat/demux.c 函数:OpenDemux 0x01 研究背景 ffmpeg的两个接口avformat_open_input和avformat_find_stream_info分别用于打开一个流和分析流信息。在初始信息不足的情况下,avformat_find_stre

qpx0033的专栏 1352

【CV论文精读】【协同感知综述】Collaborative Perception for Autonomous Driving :Current Status and Future Trend

感知是自动驾驶系统的关键模块之一,近年来取得了很大进展。然而,单个车辆的有限能力导致感知性能提高的瓶颈。为了突破个体感知的局限,协作感知被提出,它使车辆能够共享信息来感知视线和视野之外的环境。本文综述了有前途的协作感知技术的相关工作,包括介绍了基本概念,概括了协作模式,总结了协作感知的关键要素和应用。最后,我们讨论了这一研究领域面临的挑战和问题,并给出了一些潜在的进一步方向。

weixin_44184852的博客 4689

从零到一:EHB-电机复合制动系统的Simulink仿真实战指南

本文详细介绍了EHB-电机复合制动系统在纯电动汽车中的Simulink仿真实战指南。通过系统概述、建模核心模块解析、控制策略开发及典型问题排查,帮助读者掌握从零到一的开发流程。重点讲解了液压子系统建模、电机再生制动模型及整车动力学集成,为开发者提供了一套完整的解决方案。

hh234的博客 1006

音画不同步的本质:时间基准与缓冲区协同控制

音画不同步并非简单卡顿,而是音视频时间轴错位引发的系统性故障。其核心在于时间基准源选择、解码渲染流水线异步性、网络抖动影响及帧率匹配失准四大原理。消费级场景下,CLOCK_MONOTONIC作为单调高精度时钟是可靠基准;而缓冲区水位动态调控可主动抑制音画偏移放大效应。该问题广泛存在于直播、点播、WebRTC等音视频开发场景,直接影响4K/HDR/杜比全景声等高阶体验。本文聚焦音视频开发中真实产线级解决方案,涵盖PTS校准、Jitter Buffer自适应、帧率锁定等关键技术路径。

weixin_33816946的博客 340

HFSS实战(三)——过孔via TDR仿真

在上一讲中,主要是通过观察S参数确定via的优化是否达到目标。但S参数只能看到一个整体的结果,并不知道via真实的阻抗是多少?想要单独确定via的阻抗,最好还是通过TDR的仿真。

luohuo9844的博客 1万+

FFmpeg avformat_find_stream_info接口优化实录

最近开发FFmpeg接收海康摄像头的推流视频,在打开视频时延时比较大,在5秒左右,下面分享一下优化的过程。 优化前后的效果比较。 avformat_find_stream_info用于分析流信息。在初始信息不足的情况下,avformat_find_stream_info接口需要在内部调用read_frame_internal接口读取流数据,然后再分析后,设置核心数据结构AVFormatContext。由于需要读取数据包,avformat_find_stream_info接口会带来很大的延迟,降低该接口的延

dongh_bfwm的博客 2363

IGS精密星历高效获取与解析指南

本文详细介绍了IGS精密星历在高精度定位中的核心作用,对比了IGS Final、IGR和IGU等不同产品的精度与时效性差异。指南提供了从武汉大学、NASA CDDIS等数据中心高效下载数据的实战方法,并深入解析了SP3文件格式,帮助用户掌握精密星历的获取、解析与自动化处理技巧,以支持厘米级定位应用。

garlic的博客 838

电感损耗 DCR/ACR/磁芯损耗 3 大来源解析:从集肤效应到磁滞回线

本文深入解析电感损耗的三大来源:DCR(直流电阻)、ACR(交流电阻)和磁芯损耗,从集肤效应到磁滞回线的微观机制。通过对比不同材料和设计策略,提供高频开关电源中电感损耗的优化方案,帮助工程师提升系统效率和可靠性。

weixin_34379433的博客 512

[FFMEPG]avformat_find_stream_info延时优化

前置信息 版本:ffmpeg 4.2.2 函数:avformat_find_stream_info 研究背景 网上关于avformat_find_stream_info延时优化的文章很少。某些极限H264片源,在初始信息不足的情况下,特别是视频SPS帧(SPS帧可以解析出视频的信息,如width, height等)特别靠后,这时avformat_find_stream_info内部一直rea...

zhoudidong的专栏 2473

别再手动写用例了!用AI Agent自动生成测试用例的保姆级实战(附Python代码)

本文详细介绍了如何利用AI Agent技术自动生成测试用例,大幅提升测试工程师的工作效率。通过Python代码实战演示,从环境搭建到核心Agent构建(需求解析、场景挖掘、用例编排),再到与企业工具链(TestRail、Jira)的深度集成,帮助团队实现测试用例的智能化生成与管理。

weixin_30897233的博客 645

FFmpeg avformat_find_stream_info函数优化

背景 一般的应用场景对实时点播速度要求不高的情况下,可以设置探测码流的延时和探测数据的大小,代码如下: pFormatContext->probesize = 500 *1024; pFormatContext->max_analyze_duration = 5 * AV_TIME_BASE;//AV_TIME...

weixin_34319999的博客 738

华南理工大学-大学物理实验-绪论作业

3.用公式测量某圆柱体铝的密度,测得直径=2.0420.003(cm),高=4.1260.004(cm),质量=36.4880.006(g)。计算铝的密度和测量的标准差,并以测量结果表达式表示之。(要求判别和剔除异常数据)(30分)(了解图解法的注意事项,大学物理实验众多实验数据处理采用这种方法,如PN结温度特性研究,光电效应与普朗克常数的测定,霍尔效应测磁场等等,注意规范作图)实验测得温度与对应的金属丝的长度的数据如下表所示。(了解异常数据的判断方法及具体判断过程,30分的题目n(*≧▽≦*)n)

mohen_777的博客 580

手把手教你学基于 Linux 的 NPU 固件开发-第 10 讲:可靠性设计(RAS)——让系统坚如磐石错误检测、纠正与上报机制(ECC、Parity)

组件推荐保护机制备注HBM/DDRScrubbing必须开启,定期巡检片上 SRAMECC(权重/激活值),Parity(指令)权衡面积与可靠性计算单元ABFT或DMR(关键路径)防止计算逻辑错误片上网络CRC重传保证数据传输完整性系统软件AER 上报CE 监控自动恢复闭环管理,杜绝 SDC运维策略预测性维护Checkpoint变被动为主动核心心法(信任硬件,但必须验证。在纳米尺度下,错误是必然发生的物理现象。

MHD0815的博客 90

FFmpeg源代码简单分析:avformat_find_stream_info()

本文简单分析FFmpeg中一个常用的函数:avformat_find_stream_info()。该函数可以读取一部分视音频数据并且获得一些相关的信息。

雷霄骅(leixiaohua1020)的专栏 7万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

ffmpeg播放rtsp流avformat_find_stream_info时间过长的问题

后来问了ai,建议用udp方式播放,速度会快一些。因为服务端防火墙只设置了tcp的转发,ffmpeg默认的传输方式是udp,所以无法播放也正常。现象也与上述问题一致,改了以下代码,使用tcp播放(或者防火墙开通udp转发也行)。起初怀疑是参数问题,网络搜索解决方案,大多是让调整probesize和max_analyze_duration,但是依然无效。使用ffmpeg对rtsp流进行解码时,avformat_find_stream_info响应太慢。又利用ffplay、vlc直接播放,结果也是无法播放。

waphj的专栏 497

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

avformat_find_stream_info函数卡住问题

问题:初始化RTSP流时,在android设备上卡住在avformat_find_stream_info函数,然后程序崩溃。 但其他URL没问题,且同样在代码在iOS上没问题,由于jni调试,也没看到ffmepg打印什么异常信息出来,而IOS上可以看到如下打印信息 avformat_open_input ret= 0 UDP timeout, retrying with TCP看到这个当时竟然

ios 5666

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

上一篇: android动画(一)Interpolator
下一篇: MPEG2-TS音视频同步原理
xb_smart
博客等级 码龄16年 124粉丝 74原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值