分析ffmpeg源码

分析问题

mpegtsenc.c

找到发送PAT、PMT的函数

/* send SDT, PAT and PMT tables regularly */
static void retransmit_si_info(AVFormatContext *s, int force_pat, int64_t dts)
{
MpegTSWrite *ts = s->priv_data;
int i; if (++ts->sdt_packet_count == ts->sdt_packet_period ||
(dts != AV_NOPTS_VALUE && ts->last_sdt_ts == AV_NOPTS_VALUE) ||
(dts != AV_NOPTS_VALUE && dts - ts->last_sdt_ts >= ts->sdt_period*90000.0)
) {
ts->sdt_packet_count = 0;
if (dts != AV_NOPTS_VALUE)
ts->last_sdt_ts = FFMAX(dts, ts->last_sdt_ts);
mpegts_write_sdt(s);
}
if (++ts->pat_packet_count == ts->pat_packet_period ||
(dts != AV_NOPTS_VALUE && ts->last_pat_ts == AV_NOPTS_VALUE) ||
(dts != AV_NOPTS_VALUE && dts - ts->last_pat_ts >= ts->pat_period*90000.0) ||
force_pat) {
ts->pat_packet_count = 0;
if (dts != AV_NOPTS_VALUE)
ts->last_pat_ts = FFMAX(dts, ts->last_pat_ts);
mpegts_write_pat(s);
for (i = 0; i < ts->nb_services; i++)
mpegts_write_pmt(s, ts->services[i]);
}
}

从源码分析,可以知道PAT、PMT的发送条件

if (++ts->pat_packet_count == ts->pat_packet_period ||
(dts != AV_NOPTS_VALUE && ts->last_pat_ts == AV_NOPTS_VALUE) ||
(dts != AV_NOPTS_VALUE && dts - ts->last_pat_ts >= ts->pat_period*90000.0) ||
force_pat)

dts != AV_NOPTS_VALUE && ts->last_pat_ts == AV_NOPTS_VALUE:第一次发送PAT、PMT用到的是这个条件。

++ts->pat_packet_count == ts->pat_packet_period:这个条件是定时100ms发送PAT、PMT;ts->pat_packet_period 这个字段在函数mpegts_init里面有定义。

ts->last_pat_ts >= ts->pat_period*90000.0: 这个条件用户自定义发表间隔时会生效,ts->pat_period 这个字段默认值是INT_MAX。

ts->pat_period:这个字段可以通过如下接口进行用户自定义设置:

av_opt_set(ofmt_ctx->priv_data, "pat_period",   "0.01",      0);

:ffmpeg 巧妙的地方时,你用户自定义后,定时100ms发送的条件就会失效。

force_pat: 强制发送PAT、PMT,这个参数是函数入参,故需要查看函数retransmit_si_info被谁调用。

搜索代码可知,只有mpegts_write_pes调用此函数。

static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
const uint8_t *payload, int payload_size,
int64_t pts, int64_t dts, int key, int stream_id)
{
MpegTSWriteStream *ts_st = st->priv_data;
MpegTSWrite *ts = s->priv_data;
uint8_t buf[TS_PACKET_SIZE];
uint8_t *q;
int val, is_start, len, header_len, write_pcr, is_dvb_subtitle, is_dvb_teletext, flags;
int afc_len, stuffing_len;
int64_t pcr = -1; /* avoid warning */
int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE);
int force_pat = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && key && !ts_st->prev_payload_key; av_assert0(ts_st->payload != buf || st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO);
if (ts->flags & MPEGTS_FLAG_PAT_PMT_AT_FRAMES && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
force_pat = 1;
} is_start = 1;
while (payload_size > 0) {
retransmit_si_info(s, force_pat, dts);
force_pat = 0; write_pcr = 0;

分析源码可知,force_pat遇到视频关键帧时,会被赋值为1。

由此分析可知,当定时发送完PAT、PMT后,25ms内来了一帧关键帧,也会发送PAT、PMT,导致出现PAT、PMT间隔小于25ms这个错误。

修改源码解决问题

修改函数retransmit_si_info:将发送PAT、PMT条件中的force_pat去掉即可

/* send SDT, PAT and PMT tables regularly */
static void retransmit_si_info(AVFormatContext *s, int force_pat, int64_t dts)
{
MpegTSWrite *ts = s->priv_data;
int i; if (++ts->sdt_packet_count == ts->sdt_packet_period ||
(dts != AV_NOPTS_VALUE && ts->last_sdt_ts == AV_NOPTS_VALUE) ||
(dts != AV_NOPTS_VALUE && dts - ts->last_sdt_ts >= ts->sdt_period*90000.0)
) {
ts->sdt_packet_count = 0;
if (dts != AV_NOPTS_VALUE)
ts->last_sdt_ts = FFMAX(dts, ts->last_sdt_ts);
mpegts_write_sdt(s);
} #if 0
if (++ts->pat_packet_count == ts->pat_packet_period ||
(dts != AV_NOPTS_VALUE && ts->last_pat_ts == AV_NOPTS_VALUE) ||
(dts != AV_NOPTS_VALUE && dts - ts->last_pat_ts >= ts->pat_period*90000.0) ||
force_pat)
#endif
if (++ts->pat_packet_count == ts->pat_packet_period ||
(dts != AV_NOPTS_VALUE && ts->last_pat_ts == AV_NOPTS_VALUE) ||
(dts != AV_NOPTS_VALUE && dts - ts->last_pat_ts >= ts->pat_period*90000.0))
{
ts->pat_packet_count = 0;
if (dts != AV_NOPTS_VALUE)
ts->last_pat_ts = FFMAX(dts, ts->last_pat_ts);
mpegts_write_pat(s);
for (i = 0; i < ts->nb_services; i++)
mpegts_write_pmt(s, ts->services[i]);
}
}

修复FFMPEG 复用 PAT、PMT发送间隔小于25ms的错误的更多相关文章

  1. TS流PAT/PMT详解

    一 从TS流开始 从MPEG-2到DVB,看着看着突然就出现了一大堆表格,什么PAT.PMT.CAT……如此多的表该怎样深入了解呢? 我们知道,数字电视机顶盒接收到的是一段段的码流,我们称之为TS(T ...

  2. ffmpeg 复用

    aa 将mkv中的音视频复用成ts流: ffmpeg -i 32_mkv_h264_718x480_ac3.mkv  -codec copy -bsf:v h264_mp4toannexb  -f m ...

  3. 关于SetTimer间隔小于OmTimer执行时间的问题

    如果SetTimer的时间间隔为t,其响应事件OnTimer代码执行一遍的时间为T,且T>t.这样,一次未执行完毕,下一次定时到,这时候程序会如何执行? 可能的情况:1.丢弃还未执行的代码,开始 ...

  4. 邮件发送,无尽的501错误。TCP发送邮件解决方案

    先贴上错误信息,便于搜索引擎采集,也送给遇到此问题的技术朋友们. smtp 501 Syntax error (no parameters allowed) (#5.5.4) 背景描述: 使用TCP发 ...

  5. SpringMVC客户端发送json数据时报400错误

    当测试客户端发送json数据给服务器时,找不到响应路径? 原来是参数类型不符,即使是json也要考虑参数的个数和类型 解决:将age请求参数由"udf"改为"3" ...

  6. duilib 修复padding属性导致其他控件自动计算宽高度错误的bug和导致自己宽高度错误的bug

    转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42950733          BUG 一:padding导致其他控件宽 ...

  7. vs2012 MinGW编译ffmpeg 出现libavdevice/avdevice.c(38) : error C2059: 语法错误:“.”

    利用vs2012编译ffmpeg出现以下错误: libavdevice/avdevice.c(38) : error C2059: 语法错误:“.” libavdevice/avdevice.c(40 ...

  8. IE 浏览器在地址栏输入中文字符,发送get请求报400错误的问题

    因为学校有JavaWeb的课程,所以才接触这方面.最近遇到了个小问题. 先看一段很简单的jsp代码例子 <%@ page language="java" import=&qu ...

  9. nRF24L01基于FIFO TX队列的发送性能优化

    RF24项目代码分析 头文件 https://github.com/nRF24/RF24/blob/master/RF24.h 源文件 https://github.com/nRF24/RF24/bl ...

随机推荐

  1. UML示例图 zt

    UML示例图   在Visio里,包和类的关系是包含关系,将类拖入包的文件夹之后,关系就建立了,二元关联符号可以设置为:聚合.合成.接口:空心圆+直线(唐老鸭类实现了'讲人话’):依赖:虚线+箭头(动 ...

  2. [原创]Xilinx Vivado 2017.4/2018.3/2016.4/2015.4/ISE14.7下载及其安装

    最新版本Vivado 2018.3下载地址 链接:https://pan.baidu.com/s/17aE-vICRQYN27bD2sXCLxg提取码:ilg5 由于工程需要,下载VIVADO2018 ...

  3. keepalived介绍及工作原理

    keepalived介绍keepalived观察其名可知,保持存活,在网络里面就是保持在线了,也就是所谓的高可用或热备,它集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防 ...

  4. RESTful-2一分钟理解什么是REST和RESTful

    从事web开发工作有一小段时间,REST风格的接口,这样的词汇总是出现在耳边,然后又没有完全的理解,您是不是有和我相同的疑问呢?那我们一起来一探究竟吧! 就是用URL定位资源,用HTTP描述操作. 知 ...

  5. Android进阶:三、这一次,我们用最详细的方式解析Android消息机制的源码

    决定再写一次有关Handler的源码 Handler源码解析 一.创建Handler对象 使用handler最简单的方式:直接new一个Handler的对象 Handler handler = new ...

  6. G - Surf Gym - 100819S -逆向背包DP

    G - Surf Gym - 100819S 思路 :有点类似 逆向背包DP , 因为这些事件发生后是对后面的时间有影响. 所以,我们 进行逆向DP,具体 见代码实现. #include<bit ...

  7. web-storage-cache 使用JS数据缓存

    https://github.com/WQTeam/web-storage-cache 使用WebStorageCache,只要在页面上引入下面代码即可. <script src="s ...

  8. Ubuntu server 16.04安装,无网卡驱动解决

    因为使用一个软件必须要在ubuntu server 16.04上安装,因此先在裸机上安装ubuntu server 16.04,具体信息: 镜像版本:ubuntu-16.04.6-server-amd ...

  9. centos查看apache用的是哪个httpd.conf

    httpd -V得到类似如下结果: -D HTTPD_ROOT="/etc/httpd" -D SERVER_CONFIG_FILE="conf/httpd.conf&q ...

  10. 【转】Android studio安装与配置

    Android studio安装与配置 1.首先下载Android studio安装包,可以从http://www.android-studio.org/下载最新版本,这里采用3.0版本进行演示,对应 ...