2016-07-25 127 views
0

我使用的ffmpeg記錄從GDI(Windows屏幕錄像機)視頻輸入,查看它以後使用VLC(通過ActiveX插件)+的ffmpeg解碼它。libvlc ffmpeg的:沒有在MPEGTS h264碼流尋求

眼下尋求在視頻VLC通過插件不工作(這是關鍵)。 VLC播放器本身提供尋找,但它更像是字節位置尋找(在I幀比其他幀更大時,它在水平滾動上做出更大的步驟並且也沒有時間戳)。

編碼器打開旁邊的默認值:

avformat_alloc_output_context2(&outputContext, NULL, "mpegts", "test.mpg"); 
outputFormat = outputContext->oformat; 
encoder = avcodec_find_encoder(AV_CODEC_ID_H264); 
outputStream = avformat_new_stream(outputContext, encoder); 
outputStream->id = outputContext->nb_streams - 1; 
encoderContext = outputStream->codec; 
encoderContext->bit_rate = bitrate; // 800000 by default 
encoderContext->rc_max_rate = bitrate; 
encoderContext->width = imageWidth; // 1920 
encoderContext->height = imageHeight; // 1080 
encoderContext->time_base.num = 1; 
encoderContext->time_base.den = fps; // 25 by default 
encoderContext->gop_size = fps; 
encoderContext->keyint_min = fps; 
encoderContext->max_b_frames = 0; 
encoderContext->pix_fmt = AV_PIX_FMT_YUV420P; 
outputStream->time_base = encoderContext->time_base; 
avcodec_open2(encoderContext, encoder, NULL); 

完成錄音後是這樣的:

// my impl of GDI recorder, returning AVFrame with only data and linesize filled. 
AVFrame* tmp_frame = impl_->recorder->acquireFrame(); 

// converting RGB -> YUV420 
sws_scale(impl_->scaleContext, tmp_frame->data, tmp_frame->linesize, 0, impl_->frame->height, impl_->frame->data, impl_->frame->linesize); 

// pts variable is calculated by using QueryPerformanceCounter form WinAPI. It is strictly increasing 
impl_->frame->pts = pts; 

avcodec_encode_video2(impl_->encoderContext, impl_->packet, impl_->frame, &out_size); 

if (out_size) { 
    impl_->packet->pts = pts; 
    impl_->packet->dts = pts; 
    impl_->packet->duration = 1; // here it is! It is set but has no effect 
    av_packet_rescale_ts(impl_->packet, impl_->encoderContext->time_base, impl_->outputStream->time_base); 
    // here pts = 3600*pts, dts = 3600*pts, duration = 3600 what I consider to be legit in terms of milliseconds 
    impl_->packet->stream_index = impl_->outputStream->index; 
    av_interleaved_write_frame(impl_->outputContext, impl_->packet); 
    av_packet_unref(impl_->packet); 
    out_size = 0; 
} 

ffprobe所提供的有關框架下一個信息:

[FRAME] 
media_type=video 
stream_index=0 
key_frame=1 
pkt_pts=3600 
pkt_pts_time=0:00:00.040000 
pkt_dts=3600 
pkt_dts_time=0:00:00.040000 
best_effort_timestamp=3600 
best_effort_timestamp_time=0:00:00.040000 
pkt_duration=N/A 
pkt_duration_time=N/A 
pkt_pos=564 
pkt_size=97.018555 Kibyte 
width=1920 
height=1080 
pix_fmt=yuv420p 
sample_aspect_ratio=N/A 
pict_type=I 
coded_picture_number=0 
display_picture_number=0 
interlaced_frame=0 
top_field_first=0 
repeat_pict=0 
[/FRAME] 

我相信問題在pkt_duration變量,雖然它已設置。 我在做什麼錄製錯誤,所以我不能在視頻中尋找?

P.S.在其他視頻(也h264)尋求工作在ActiveX VLC插件。

回答

0

什麼肯定是不對的,是:

impl_->packet->pts = pts; 
impl_->packet->dts = pts; 

PTS和DTS是不相等的!他們可能是,如果你只有I幀,這不是這裏的情況。此外,您的評論說:點變量使用QueryPerformanceCounter形式WinAPI的計算。如果你的幀速率是恆定的,而且我相信它,那麼你不需要QueryPerformanceCounter API。 PTS通常爲90kHz單位。 1幀的在90KHz的表達的持續時間的計算是這樣的:

90000 X分母/分子

如果FPS是25則分子是25和分母是1。29.97分子是30000分母是1001.每個新幀的PTS應增加該量(除非你丟幀)。關於DTS,編碼器應提供該值。

+0

謝謝您的回答! 爲什麼如果我只有I和P幀,PTS和DTS不可能相等? I幀很明顯。但是P幀也必須解碼並顯示爲它們的存儲方式。或者我錯了? 關於'QueryPerformanceCounter'。我用它來保持恆定的FPS,同時抓住屏幕(帶有各種系統負載,我改變了睡眠時間以確保我的抓取儘可能接近所需的fps)。 至於計算PTS。我完全失去了90kHz的恆定。目前PTS計算爲每幀增加1。我相信'av_packet_rescale_ts'會爲我計算一切。 – ElDorado

+0

計算的PTS和持續時間(3600,參見代碼評論和ffprobe輸出)我認爲現在在90kHz時序方面更合理。但爲什麼幀持續時間不是在ffprobe輸出中計算的? – ElDorado

+0

感謝您的回答! 我設法讓VLC在視頻中尋找。不知道爲什麼它在其他視頻上工作,但更新到2.2.4它也適用於我的視頻。 – ElDorado