大家好
我剛接觸流媒體不久, 現在遇到一個非常奇怪的問題,向各位大俠請假,請你們指點。
問題是這樣的 用一個 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。 |