修复FFMPEG 复用 PAT、PMT发送间隔小于25ms的错误

分析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]);
    }
}

原文地址:https://www.cnblogs.com/standardzero/p/10687943.html

时间: 2024-08-30 01:59:38

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

mpeg2 ts流PAT,PMT,SDT的定义

转自: http://blog.sina.com.cn/s/blog_5ea0192f0100vo15.html 更具体准确的信息请参考iso13818-1,都在里面定义的 PAT的定义:Table_id:为8bit字段,该字段标识节目关联分段,对于PAT,置为0x00. Section_syntax_indicator:1bit字段,对于PAT,置为0x01. Reserved:2bit保留字段,用于将来扩展,置为11. Section_length:12bit字段,指示当前section的长

ffmpeg 复用

aa 将mkv中的音视频复用成ts流: ffmpeg -i 32_mkv_h264_718x480_ac3.mkv  -codec copy -bsf:v h264_mp4toannexb  -f mpegts xx.ts 7 %a mpegtsenc.c /home/yingc/gcyin/test/thirdparty/ffmpeg/ffmpeg-2.2.4/libavformat 第 1374 行 14 # mux.c /home/yingc/gcyin/test/thirdparty/f

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

如果SetTimer的时间间隔为t,其响应事件OnTimer代码执行一遍的时间为T,且T>t.这样,一次未执行完毕,下一次定时到,这时候程序会如何执行? 可能的情况:1.丢弃还未执行的代码,开始新的执行:2.不丢弃,Timer消息进入消息队列排队,等到原来的代码执行完毕后,马上开始新的执行:3.重入,就是原来的还继续执行,同时又开始一个新的执行: 答案:第二个,或者,第一个丢弃.不过丢弃的情况是, 消息队列满了, 第二次的消息没进去. void COnTimer1Dlg::OnTimer(UIN

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

先贴上错误信息,便于搜索引擎采集,也送给遇到此问题的技术朋友们. smtp 501 Syntax error (no parameters allowed) (#5.5.4) 背景描述: 使用TCP发送邮件,在使用新浪邮箱进行smtp发送邮件时报出该错误(其他邮箱可能也存着该问题),QQ邮箱无该问题. ======================================================== 发送邮件其实很简单,对于像鄙人这种极限追求精简的人来说,肯定不乐意使用第三方邮件插

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

利用vs2012编译ffmpeg出现以下错误: libavdevice/avdevice.c(38) : error C2059: 语法错误:"." libavdevice/avdevice.c(40) : error C2059: 语法错误:"," libavdevice/avdevice.c(42) : error C2059: 语法错误:"," libavdevice/avdevice.c(44) : error C2059: 语法错误:&

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

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

SGA_MAX_SIZE参数值小于MEMORY_TARGET参数值错误解决

C:\windows\system32>net start oracleserviceorclOracleServiceORCL 服务正在启动 ......OracleServiceORCL 服务已经启动成功. C:\windows\system32>sqlplus / as sysdba SQL*Plus: Release 11.2.0.1.0 Production on 星期三 6月 23 15:08:47 2010 Copyright (c) 1982, 2010, Oracle.  A

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

因为学校有JavaWeb的课程,所以才接触这方面.最近遇到了个小问题. 先看一段很简单的jsp代码例子 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %> <html> <head> <title>Hello.jsp</title> </head> <body> Welcome

PAT:1080. Graduate Admission (30) 部分错误(录取以学校为导向而不是考生志愿为导向导致的错误)

#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int want[106]; //各学校招生人数 struct Student { int GE,GI,sum,rank,ID; int prefer[6]; bool R; //代表该生录取情况 }STU[40066]; bool cmp(Student a,Student b) { if(a.sum!=b.sum