加载中…
个人资料
南冠彤
南冠彤
  • 博客等级:
  • 博客积分:0
  • 博客访问:411,581
  • 关注人气:59
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

[转载]ffdemux_mpegts中时间戳的处理问题

(2014-03-27 15:47:01)
标签:

转载

分类: 音视频
ffdemux_mpegts是gstreamer的demux plugin,基于ffmpeg,在使用的时候发现处理实时流存在问题。

先来描述一下问题,采用gst-launch命令启动转码,命令如下:

gst-launch-0.10 udpsrc multicast-group=239.1.80.80 port=49500 ! queue ! ffdemux_mpegts name=demuxer ! queue ! ffdec_mp3 ! queue ! ffenc_mp2 ! queue ! ffmux_mpegts name=muxer preload=10000 maxdelay=500000 muxrate=3600000 ! udpsink host=239.100.100.100 port=12345 demuxer. ! queue ! queue ! mpeg2dec ! queue ! mpeg2enc format=3 bitrate=2900 closed-gop=true sequence-header-every-gop=true ! muxer. --gst-debug-level=2 > udp188-log.txt 2>&1 &

采用了ffdemux_mpegts来解复用mpegts流。采用udpsrc作为ts流的源,来自实时的数字电视。运行过程中会结束转码,而不是持续的运行。把debug的level设置为5,发现如下内容:

ffmpeg gstffmpegdemux.c:1378:gst_ffmpegdemux_loop:<demuxer> pkt pts:26:30:43.583444444
ffmpeg gstffmpegdemux.c:1378:gst_ffmpegdemux_loop:<demuxer> pkt pts:0:00:00.025755556
ffmpeg gstffmpegdemux.c:1548:gst_ffmpegdemux_loop:<demuxer> dropping buffer out of segment, stream eos
ffmpeg gstffmpegdemux.c:407:gst_ffmpegdemux_is_eos: stream 0 0xb561e6c8 eos:0

其中有pts:26:30:43.583444444,也就是pts已经达到了其最大值,因为是33位的,且按照90kHZ计时,刚好是26小时30分钟多一点。接下来就从0开始计数,这让ffdemux_mpegts以为流已经结束,因此发出了eos的events。由于音频和视频分别有自己的pts,另外由于pts并不是单调递增的,所以当音频和视频都满足了eos的条件就造成转码“结束”。

以上描述的是一个问题,还有另外一个问题,就是gstream采用64位的时间戳,且单位为纳秒,而pts只有33位,且单位是按照90kHZ来算的,因此简单的让gstreamer的时间戳等于pts是不可行的,以下是在gstffmpegutils.h中定义的函数:

static inline guint64
gst_ffmpeg_time_ff_to_gst (gint64 pts, AVRational base)
{
  guint64 out;

  if (pts == AV_NOPTS_VALUE){
    out = GST_CLOCK_TIME_NONE;
  } else {
    AVRational bq = { 1, GST_SECOND };
    out = av_rescale_q (pts, base, bq);
  }

  return out;
}

上面的函数在gstffmpegdemux.c中的loop函数里被调用,用于gstreamer的时间戳的计算。

由于gstreamer的时间戳是64为的,而pts是33位的,且pts并不是严格单调递增的,因此转换就更复杂一点。

[转载]ffdemux_mpegts中时间戳的处理问题

如上面所示表示PTS按取值被分成两个区域,其中1区域占据平分成3个部分的两边,2区域占据当中。

  • region1_right = 5秒,region1_left=95438(95443-5)秒。
  • region2_left = 10秒,region2_right=15433(95443-10)秒。
  • 当状态为1区域,如果pts_timestamp的值落在region2_left和region2_right之间,则变为2区域状态,并且gst_last_timestamp = max_pts*循环次数。
  • 当状态为2区域,如果遇上pts_timestamp的值落在region1_left和region1_right之间,则变为1区域状态。
  • 如果是1区域状态:
    • 如果pts_timestamp值在1.1区域则gst_timestamp = gst_last_timestamp + max_pts + pts_timestamp。
    • 如果pts_timestamp值在1.2区域则gst_timestamp = gst_last_timestamp + pts_timestamp。
  • 如果是2区域状态,则gst_timestamp = gst_last_timestamp + pts_timestamp。
64位无符号数,单位是纳秒,能表示约5,6百年(我自己计算的,如果不准请提示),因此起始时间设置为0,可以放心使用。

为了避免累积误差,gst_last_timestamp的计算采用pts_max*循环次数,然后再转换,而不是gst_last_timestamp += pts_max的转换。这就需要一个变量记载pts循环的次数,pts循环一次指的是pts达到最大值从零开始。

如下是ubuntu10.10 server版本源代码的修改:

60a61,65
>
  gint region;
  guint64 pts_region1_left, pts_region1_right;
  guint64 pts_region2_left, pts_region2_right;
  guint64 gst_last_timestamp, pts_accumulate;
979a985,991
  stream->pts_accumulate = 0llu;
  //stream->gst_last_timestamp = (8589934591llu * 100000llu) / 9llu;//0llu;
  stream->gst_last_timestamp = 0llu;
  stream->pts_region1_right = 5000000000llu; //5s
  stream->pts_region1_left = 95438000000000llu; //95438s, 95443-5
  stream->pts_region2_left = 10000000000llu; //10s
  stream->pts_region2_right = 95433000000000llu; //max pts is about 95443s
1029a1042,1047
    if (tmp < stream->pts_region1_right || tmp > stream->pts_region1_left) {
      stream->region = 1;
    } else {
      stream->region = 2;
    }
>
1364a1383,1404
    if (stream->region == 1) {
      if (timestamp > stream->pts_region2_left && timestamp < stream->pts_region2_right) {
        GST_DEBUG_OBJECT (demux, "enter region 2");
        stream->pts_accumulate += 1;
        stream->gst_last_timestamp = (stream->pts_accumulate * 8589934591llu * 100000llu) / 9llu;
        stream->region = 2;
      }
    } else if (stream->region == 2) {
      if (timestamp < stream->pts_region1_right || timestamp > stream->pts_region1_left) {
        GST_DEBUG_OBJECT (demux, "enter region 1");
        stream->region = 1;
      }
    }
    if (stream->region == 1) {
      if (timestamp < stream->pts_region2_left) {
        timestamp += (stream->gst_last_timestamp + (8589934591llu * 100000llu) / 9llu);
      } else if (timestamp > stream->pts_region2_right) {
        timestamp += stream->gst_last_timestamp;
      }
    } else if (stream->region == 2) {
        timestamp += stream->gst_last_timestamp;
    }
1381,1382c1421,1422
  if (demux->start_time != -1 && demux->start_time > timestamp)
    goto drop;
---
  //if (demux->start_time != -1 && demux->start_time > timestamp)
  //  goto drop;
1388,1389c1428,1429
  if (demux->segment.stop != -1 && timestamp > demux->segment.stop)
    goto drop;
---
  //if (demux->segment.stop != -1 && timestamp > demux->segment.stop)
  //  goto drop;

0

  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有