ffmpeg顯示視頻

項目最近須要實現播放視頻功能,這個在上家公司就作過。雖然跟以前的場景不同,有之前的功底仍是很快能夠解決,事實也確實如此。在使用DShow處理完視頻分割與合併後,繼續使用DShow顯示視頻,很快即完成。然而在播放dvr錄製的視頻文件時,發現播放幀率不對,分析發現是dvr存儲的視頻文件不是按標準格式進行存儲(使用ffplay效果還好點,media player根本無法播放),因而重寫代碼。緩存

先簡要說明一下項目:client是delphi開發的GUI程序,視頻全部操做功能都由mfc dll實現,這個dll也就是由我實現。delphi只傳入要顯示視頻的窗口句柄、操做類型、文件名,這個跟我在之前設計但未能完工的顯示流媒體庫有很多借鑑做用,所以在此記錄一下。線程

使用ffmpeg一直到讀取文件每一幀、解碼,剩下就是顯示的工做:解碼每一幀的rgb數據在CDC上顯示,顯示過程當中一開始經過CreateDIBSection建立一個HBITMAP對象,memorydc中選入,而後在顯示cdc中StretchBlt,代碼以下設計

bmpInfoHdr.biPlanes = 1;
bmpInfoHdr.biBitCount = 24;
bmpInfoHdr.biWidth = pAvCdcCtx->width;
bmpInfoHdr.biHeight = pAvCdcCtx->height;
bmpInfoHdr.biSizeImage = nBytes;
bmpInfoHdr.biSize = sizeof(bmpInfoHdr);

//建立DIB HBITMAP
hBmpShow = CreateDIBSection(NULL, (BITMAPINFO*)&bmpInfoHdr, DIB_RGB_COLORS, (void**)&pRgbData, NULL, 0);
if (!hBmpShow) {
    itrace("CreateDIBSection failed %d", GetLastError());
    continue;
}
memcpy(pRgbData, pBmpRgbData, nBytes);

//顯示圖片
hBmpBackup = (HBITMAP)m_memDc.SelectObject(hBmpShow);
m_pShowDc->StretchBlt(0, 0, m_width, m_height, &m_memDc, 0, 0, 
        pAvCdcCtx->width, pAvCdcCtx->height, SRCCOPY);

 結果發現現實視頻效果極差,轉而研究ffplay代碼,發現ffplay分讀線程與解碼線程。懷疑是播放前未能讀取足夠的視頻幀進行緩存,致使視頻在解碼播放過程當中出現因讀取視頻佔用時間致使效果極差的緣由。因而在代碼中添加了讀/解碼線程,修改後發現播放效果沒有任何改善。因而排除幀緩衝致使播放問題,這時候看到了yuv viewer代碼,發現其顯示是經過StretchDIBits實現,且不須要經過CreateDIBSection建立HBITMAP對象。嘗試修改代碼,播放效果很是好,代碼以下視頻

m_pShowDc->SetStretchBltMode(STRETCH_DELETESCANS);
StretchDIBits(m_pShowDc->m_hDC, 0, 0, m_width, m_height, 
		0, 0, pAvCdcCtx->width, pAvCdcCtx->height, 
		pBmpRgbData, (BITMAPINFO*)&bmpInfoHdr, DIB_RGB_COLORS, SRCCOPY);

 ====視頻定位對象

能夠經過前進或者後退多少秒以及百分比對視頻進行定位,其實都是獲取其絕對時間經過av_rescale_q轉成ffmpeg所須要的時間格式,進行視頻定位。blog

咱們知道能夠經過av_q2d(m_pAvFmtCtx->streams[i]->time_base)* pAvFrame->best_effort_timestamp來獲取當前播放時間圖片

AVRational bp = {1, AV_TIME_BASE};
target_pos = av_rescale_q(target_pos, bp, m_pAvFmtCtx->streams[idx]->time_base);
av_seek_frame(m_pAvFmtCtx, idx, target_pos, AVSEEK_FLAG_ANY);
相關文章
相關標籤/搜索