解决REAL VIDEO的视频平滑问题 (转)

存在问题:当前的播放器产品上,播放REAL VIDEO时,虽然文件是25fps的,并且在DEOCDER和RENDER都没有丢帧,但是视频看起来就是一顿一顿的,不流畅,但是并没有延迟。

1、检查后,发现问题出在时间戳上。当前在DECODE之后,frame的timestamp根据demux出来的pFrame->ulTimestamp拿的,DECODER输出时,时间戳如下(单位微秒)

Rv output buffer pts = 323000, dur = 1000, Current = 48534, Skew = 274466
Rv output buffer pts = 480000, dur = 157000, Current = 59978, Skew = 420022
Rv output buffer pts = 481000, dur = 1000, Current = 67589, Skew = 413411
Rv output buffer pts = 482000, dur = 1000, Current = 74178, Skew = 407822
Rv output buffer pts = 483000, dur = 1000, Current = 80045, Skew = 402955
Rv output buffer pts = 640000, dur = 157000, Current = 86134, Skew = 553866
Rv output buffer pts = 641000, dur = 1000, Current = 91322, Skew = 549678
Rv output buffer pts = 642000, dur = 1000, Current = 108634, Skew = 533366
Rv output buffer pts = 643000, dur = 1000, Current = 113267, Skew = 529733
Rv output buffer pts = 800000, dur = 157000, Current = 118922, Skew = 681078
Rv output buffer pts = 801000, dur = 1000, Current = 124000, Skew = 677000
Rv output buffer pts = 802000, dur = 1000, Current = 128767, Skew = 673233
Rv output buffer pts = 803000, dur = 1000, Current = 133456, Skew = 669544
Rv output buffer pts = 960000, dur = 157000, Current = 138845, Skew = 821155
Rv output buffer pts = 961000, dur = 1000, Current = 144111, Skew = 816889
Rv output buffer pts = 962000, dur = 1000, Current = 148734, Skew = 813266
Rv output buffer pts = 963000, dur = 1000, Current = 153478, Skew = 809522
Rv output buffer pts = 1200000, dur = 237000, Current = 159911, Skew = 1040089
Rv output buffer pts = 1201000, dur = 1000, Current = 165689, Skew = 1035311
Rv output buffer pts = 1202000, dur = 1000, Current = 170911, Skew = 1031089
Rv output buffer pts = 1203000, dur = 1000, Current = 176211, Skew = 1026789
Rv output buffer pts = 1360000, dur = 157000, Current = 183034, Skew = 1176966
Rv output buffer pts = 1361000, dur = 1000, Current = 188367, Skew = 1172633
Rv output buffer pts = 1362000, dur = 1000, Current = 193211, Skew = 1168789
Rv output buffer pts = 1363000, dur = 1000, Current = 198289, Skew = 1164711
Rv output buffer pts = 1520000, dur = 157000, Current = 204034, Skew = 1315966
Rv output buffer pts = 1521000, dur = 1000, Current = 216122, Skew = 1304878
Rv output buffer pts = 1522000, dur = 1000, Current = 221100, Skew = 1300900
Rv output buffer pts = 1523000, dur = 1000, Current = 226122, Skew = 1296878

两个FRAME之间间隔可能是150MS以上,也可能是1MS,在经过Video Compositor和OSD合成后,间隔时间一毫秒的FRAME全部被compositor丢弃,到了compositor输出时,帧间隔都是150MS左右的了,每秒帧率的确不到10帧。所以需要修改时间戳的计算方法

2、一段时间以来,我一直认为REAL文件的帧率不是固定的,因为无法在DEMUX中按照协议取得REAL文件的帧率;并且帧率不固定、存在漂移这点也被Doctor.Li赞同。今天静下心来查了一下,发现根本原因并不是帧率漂移造成的,而是部分RV ENCODER并不是按照REAL协议来封装RM文件的。在rv_depacki_unpack_format_info函数中,ufFramesPerSecond应该是32bit的数据,但实际上相当大的一部分REAL文件在这里只用了16bit,所以读出来的帧率是几万几万的。这个地方需要稍微修改一下来容错
if( FramesPerSecond > 0xFFFF)
{
        FramesPerSecond = FramesPerSecond >> 16;
}
这样就能得到固定的帧率了。不过很奇怪为什么桌面的REALONE PLAYER它就能读到帧率,而SDK里却存在容错性的问题。

3、得到帧率后,修正时间戳算法
在rv_frame_struct结构体中,我们可以看到
typedef struct rv_frame_struct
{
    UINT32             ulDataLen;
    BYTE*              pData;
    UINT32             ulTimestamp;
    UINT16             usSequenceNum;
    UINT16             usFlags;
    HXBOOL          bLastPacket;
    UINT32             ulNumSegments;
    rv_segment* pSegment;
} rv_frame;

我本来打算用  usSequenceNum * FrameDuration 来做时间戳,结果发现即使时间戳和AUDIO同步了,播放时演员的嘴型还是对不上。这说明RV FRAME在时间并就不是均匀的,这也再次证实了前面提到的REAL格式帧率不固定、存在轻微漂移的观点。我只好将计就计,对时间戳进行造假了。下面伪代码中的时间单位都是毫秒(mili seconds), 与时间间隔不是一毫秒的帧我们称为"有效帧", 否则称为"无效帧". 暂时这么叫把, 最后不论有效帧无效帧都应该发送出去的.

/* set timestamp of real video frame */
{
        声明 静态变量 前一帧的原始时间戳;
        声明 静态变量  最后一个有效帧的时间戳;
        声明 静态变量 最后一个有效帧的序号;  //上面rv_frame_struct结构体中的usSequenceNum
        声明 临时变量 当前帧与前一帧的原始时间间隔;  //未伪造过的时间戳之差

        当前帧与上一帧的原始时间间隔 = 当前帧德原始时间戳 - 前一帧的原始时间戳;
        如果(  当前帧与上一帧的原始时间间隔 >  (根据帧率算出的两帧之间平均时长 / 2 ) )  //把当前帧算作有效帧
        {
                最后一个有效帧的时间戳 = 当前帧的原始时间戳;
                最后一格有效帧的序号 = 当前帧的序号;
                设置当前帧的伪造时间戳 = 当前帧的原始时间戳;
        }
        否则  //无效帧
        {
                伪造当前帧的时间戳 = (当前帧 的序号 - 最后一个有效帧的序号) * 根据帧率算出的两帧之间平均时长 + 最后一个有效帧的时间戳;
        }
       
        前一帧原始时间戳 = 当前帧的原始时间戳;  
}

伪造完成,效果让人满意,视频输出平滑。但是对于码率太低的RV文件,比如视频只有200KBPS却有VGA的分辨率,由于帧率实在太低,所以看起来是一卡一卡的,没有办法咯,实际上并没有丢帧,把码率提高就OK了。

另一方面,在输出时丢帧判断条件是: 当前帧的时间戳 < 系统当前时间 + 两帧的平均间隔时间。 由于我们伪造了时间戳,比如在25fps下两帧间隔应该是40ms, 但REAL VIDEO在某些时候两帧间隔会达到80ms,而我们伪造出来仍然只有间隔40ms,所以在RENDER位置上的丢帧处理应该更"宽容"些,改为:当前帧的时间戳 < 系统当前时间 + 两帧的平均间隔时间*2  毕竟汇聚劳动人民血汗好不容易解出来的一个帧,终于跑到播放器的终点,却因为伪造的时间戳慢了那么一点点儿丢弃,实在是浪费。

 

 

 

转自

www.Walzer.cn - 技术与管理博客

原文地址 http://www.cnblogs.com/walzer/archive/2007/05/01/733871.html

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值