分析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. 字符串正则匹配(递归/DP)

    Wildcard-Matching &  Regular Expression Matching Wildcard-Matching中?匹配任意一个字符,*匹配任意长度字符串包括空字符串 方法 ...

  2. RAID磁盘阵列及CentOS7系统启动流程

    磁盘阵列(Redundant Arrays of Independent Disks,RAID),有“独立磁盘构成的具有冗余能力的阵列”之意,,数据读取无影响.将数据切割成许多区段,分别存放在各个硬盘 ...

  3. get_k_data 接口文档 全新的免费行情数据接口

    get_k_data 接口文档 全新的免费行情数据接口 原创: Jimmy 挖地兔 2016-11-06 前言在tushareAPI里,曾经被用户喜欢和作为典范使用的API get_hist_data ...

  4. ubuntu16.04之mongodb自动备份

    cron服务是Linux的内置服务,但它不会开机自动启动.可以用以下命令启动和停止服务: service cron start service cron stop service cron resta ...

  5. 三大家族(offset、scroll、client)

    offset.scroll.client三大家族 offset家族 offsetWidth 与 offsetHeight offset 偏移 用于获取元素自身的位置和大小 offsetWidth和of ...

  6. Anconda 3.7安装以及使用详细教程

    Anconda 3.7安装以及使用详细教程 2019-04-17    22:42:03 一.下载anconda 3.7 链接地址:官方地址 二.安装 双击下载好的Anaconda3-2019.03- ...

  7. 使用JumpServer管理你的服务器

    本文介绍CentOS 7从安装jumpserver到简单使用jumpserver管理服务器. 1.Jumpserver介绍 Jumpserver是一款开源的开源的堡垒机,如下图是官网介绍. 官网地址: ...

  8. 修改 bug 总结

    对于 elementui table 组件的排序 要求对每列数据进行排序 数据是 金额之类 数字的没问题 但是 针对 标题中有数字,字母,文字的时候 会排序错误 :sort-method=" ...

  9. Vue.js的安装及简单使用

    一.Vue简介 二.Vue.js的安装 2.1.npm安装 2.1.1.node.js介绍及安装 简介: 简单的说 Node.js 就是运行在服务端的 JavaScript. Node.js 是一个基 ...

  10. 我的 FPGA 学习历程(09)—— 时序逻辑入门

    讲到这篇时,组合逻辑就告一段落了,下面是一些总结: 描述组合逻辑时,always 语句中的敏感信号列表中需要列出全部的可能影响输出的变量 描述组合逻辑时,always 语句中的赋值总是使用阻塞赋值符号 ...