時間戳問題彙總

原文地址:http://hi.baidu.com/ilovejoy/blog/item/3da717eca51d7b302797917a.html/cmtid/a50c1c1837ec330935fa419b

大家好
   我剛接觸流媒體不久, 現在遇到一個非常奇怪的問題,向各位大俠請假,請你們指點。
   問題是這樣的 用一個 VLC(流媒體客戶端) 去請求流媒體服務器上的數據, 但是獲得的數據播放速度明顯快於1倍速,大概是 timestamp 不對, 不知道是服務器的錯誤,還是客戶端解碼時出錯, 總感覺服務器那邊有問題, 由於服務器端是客戶端提供的,客戶說是我們的問題, 我還不知道如何證明是誰的錯。

A:RFC3984 規定採用 90000 Hz 的時鐘,因此如果編碼幀頻是 30,那麼時間戳間隔就該是 90000 / 30 = 3000,根據抓包來看,似乎時間戳間隔的確是 3000。

時間戳的 間隔不固定,比如有的時間戳間隔是 2990 有的是 3002,會導致解析出來的視頻快播的效果麼

Q:各位大俠好:
我現在正在開發視頻實時流播放,簡單的過程如下:
採集視頻流 -> 視頻流轉換爲Sorenson H.263編碼格式   -> 把編碼的實時流通過RTMP協議發送 -> flash客戶端進行播放。
現在我的時間戳顆粒是這樣生成的:
第一幀的時間戳爲0;
第二幀的時間戳的算法爲:第一個字符編碼的當前時間 - 上一幀第一個字符編碼的當前時間
根據這個時間顆粒的算法,我在flash客戶端播放就會產生延時。
請問各位大俠有什麼好的建議或是文檔之類的,以前firstime管管建議我看RFC4629文檔,但是效果不太明顯?
謝謝!

A;時間戳順序累加就行了,每次加1

Q:最近做了一個捕捉攝像頭並保存FLV的小東西,發現轉換完畢後的FLV文件,用播放器播放的時候,速度特別快,大概是正常速度的4倍。請問這是怎麼回事?網上搜了一下,說是時間戳的問題,可是PTS我跟了,AVPacket的PTS是每幀增長40,time_base爲: 25/s.。DTS是個無效值。PTS的計算是根據ffmpeg的例子寫的。
pkt.pts= av_rescale_q(oAcc->coded_frame->pts, oAcc->time_base, audio_st->time_base);

1. dts到底需不需要自己計算?
2. 還有播放速度過快的可能原因? 
3. 還有PTS和DTS的具體含義?
int64_t pts;                         ///< presentation time stamp in time_base units
int64_t dts;                         ///< decompression time stamp in time_base units

上面的意思是不是說,播放器根據PTS進行播放。然後DTS是在編碼的時候自己設置?

剛用ffmpeg,好些東西不懂,還請大俠多多指教------剛纔又試了一下,把time_base降爲10幀每秒。播放速度和正常速度接近。但是不知道FLV文件的幀率該設置多少合適。有沒有一個權威的說法。

A:我也做攝像頭捕捉,跟你出現一樣的問題,我自己分析的話,應該是捕捉攝像頭的圖像的速度只有10幀每秒,但是保存成視頻25幀每秒的話播放看起來就非常快,但是我攝像頭捕捉設定的是25幀每秒,難道是速度達不到?
反正我還沒解決,LZ解決了的話告訴下,

謝謝。暫時認爲是攝像頭捕捉速率問題。換了一個高清無驅攝像頭就好了

Q:在每個音視頻數據包中都含有PTS和DTS,一個數據包中應該含有多個數據幀以及音頻數據,那麼這裏的PTS和DTS它是如何來標識數據幀的?PTS和DTS的單位是什麼?視頻的最小單位是幀,可通過PTS來指定它何時播放,那音頻的最小單位是什麼?這裏的PTS對音頻而言它標識的是什麼?是這個時間點採樣點嗎?

在網上找了很久關於音視頻編解碼的資料,都沒有合適的

A:

audio_timebase = av_q2d(fmtctx->streams[audio_index]->time_base);
video_timebase = av_q2d(fmtctx->streams[video_index]->time_base);

last_video_pts = pts * video_timebase;
last_audio_pts = pts * audio_timebase;

timebase就是單位

以audio爲基準同步video。只要設置好了 ao 的參數,如sample rate, channels, sample size等, audio驅動就能以正確的速度播放,所以只要程序裏write不出大問題的話,這種同步是非常有效的。

在video out裏如下做:

pre_time = av_gettime();
gl_vo->vo_display(pic);
after_time = av_gettime();
rest_time = 1000*1000/fps - (after_time - pre_time);

av_diff = last_audio_pts - last_video_pts;

if ( av_diff > 0.2 )
{
            if( av_diff < 0.5 ) rest_time -= rest_time / 4;
            else rest_time -= rest_time / 2;
}
else if ( av_diff < -0.2)
{
            if( av_diff > -0.5 ) rest_time += rest_time / 4;
            else rest_time += rest_time / 2;
}

if ( rest_time > 0 )
    usleep(rest_time);

Q:謝謝kf701的回覆,看後明白了不少
這種同步是音頻抽樣一次就與一幀圖像去同步的嗎?

A:上面的代碼是每display一個picture,就與audio的PTS比較一下,
如果沒有audio,只有video,那麼video就會以fps顯示靠的就是那個 usleep(rest_time)

Q:如何利用AVPacket包裏的pts,dts實現音視頻同步?聲頻播放是隻管自己播放,視頻有一個初始化播放幀率,如何根據AVPacket裏的pts,dts還實現兩者的同步?
現在我的視頻播放一直按原始播放幀率播放,聲音有點卡!哪位知道,儘快告知小弟!

A:DTS:decoding time stamp 
PTS:presentation time stamp

Generally the PTS and DTS will only differ when the stream we are playing has B frames in it.

Q:關於b幀和時間戳的問題

我從mpeg2視頻中用av_read_frame()讀取視頻幀並解碼,順序是IPBBPBB...
它們的pts順序是1423756...現在我要把這個視頻再用mpeg2編碼,最大b幀數還是2.那麼我在編碼時是否要將視頻數據調整爲按顯示時間先後的順序,再交給avcodec_encode_video()編碼?即把第2幀放在3、4幀之後,第7幀放在5、6幀之後?

A:你不能這麼做,編碼器會給你這麼做的。如果你有B幀,那麼所有的B幀都會被放在緩衝區裏直到下一個I/P幀到來

例如:你的輸入序列是IBBPBBPBBI

那麼輸出的序列是

輸入I,編碼I,輸出I

輸入B

輸入B

輸入P,編碼P,輸出P

編碼B,輸出B

編碼B,輸出B

輸入P,編碼P,輸出P

。。。。。。

在解碼端所有的P幀都會被放在緩衝力直到下一個I/P真的到來

如:解碼I,輸出I

解碼P,放入緩衝P

解碼B,輸出B

解碼B,輸出B

解碼P,輸出上一次P幀

Q:解碼出來的圖片的時間戳問題 MPEG一個包中包含有時間戳, 而可能幾個包才能解碼出一張圖象, 也可能一個包能解碼出幾張圖, 請問包中的時間戳與解碼出來的圖象如何對應上?

A:在ffmpeg中通過parser部件把從avformat部件取下來的原始包重新“合成”爲有僅包含一個完整幀的包。從MPEG2部份的代碼中看出,如果“幾個包才能解碼出一張圖象”的話,會取第一個包的PTS和DTS,如果“也可能一個包能解碼出幾張圖”,則會跟據這個包的PTS和DTS通過幀頻推算出其它幀的DTS。

Q: ffmpeg的avcodec_decode_video 函數解碼時間戳問題?在   VLC 中調用   avcodec_decode_video() 函數進行解碼時,AVFrame->pts 時間戳不對,導致我的圖像不能夠顯示? 請問有誰知道它的解碼原理,這個 PTS 怎麼得出的嗎?還是外部傳入的?

A:      /* NOTE: ipts is the PTS of the _first_ picture beginning in
           this packet, if any */
        is->video_st->codec->reordered_opaque= pkt->pts;
        len1 = avcodec_decode_video(is->video_st->codec,
                                    frame, &got_picture,
                                    pkt->data, pkt->size);

        if(   (decoder_reorder_pts || pkt->dts == AV_NOPTS_VALUE)
           && frame->reordered_opaque != AV_NOPTS_VALUE)
            pts= frame->reordered_opaque;
        else if(pkt->dts != AV_NOPTS_VALUE)
            pts= pkt->dts;
        else
            pts= 0;
        pts *= av_q2d(is->video_st->time_base);

Q:我貼下   VLC 的代碼,(vlc-0.9.8a/modules/codec/avcodec/video.c 文件中)

       i_used = avcodec_decode_video( p_sys->p_context, p_sys->p_ff_pic,
                                    &b_gotpicture,
                                    p_sys->i_buffer <= 0 && p_sys->b_flush ? NULL : (uint8_t*)p_sys->p_buffer, p_sys-    >i_buffer );

      中間省略

取得   PTS ,
       if( p_sys->p_ff_pic->pts )
       {
         printf(" p_sys->p_ff_pic->pts   = %Lx\n",   p_sys->p_ff_pic->pts);
         p_sys->i_pts = p_sys->p_ff_pic->pts;
       }
從   AVFrame 結構中取得   這個 PTS ,但是這個   AVFrame 結構中取得   這個 PTS 從哪裏取得的呢?

A:時間戳一般是在編碼的時候加入到媒體文件中的,所以在解碼時可以從中分析出PTS。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章