1. 程式人生 > >ffmpeg播放器實現詳解 - 視訊顯示

ffmpeg播放器實現詳解 - 視訊顯示

ffplay是ffmpeg原始碼中一個自帶的開源播放器例項,同時支援本地視訊檔案的播放以及線上流媒體播放,功能非常強大。 > **FFplay:** FFplay is a very simple and portable media player using the FFmpeg libraries and the SDL library. It is mostly used as a testbed for the various FFmpeg APIs. **ffplay中的程式碼充分呼叫了ffmpeg中的函式庫,因此,想學習ffmpeg的使用,或基於ffmpeg開發一個自己的播放器,ffplay都是一個很好的切入點**。 由於ffmpeg本身的開發文件比較少,且ffplay播放器原始碼的實現相對複雜,除了基礎的ffmpeg元件呼叫外,還包含視訊幀的渲染、音訊幀的播放、音視訊同步策略及執行緒排程等問題。 因此,**這裡我們以ffmpeg官網推薦的一個ffplay播放器簡化版本的開發例程為基礎,在此基礎上循序漸進由淺入深,最終探討實現一個視訊播放器的完整邏輯**。 在上篇文章中介紹瞭如果搭建一個基於ffmpeg的播放器框架 本文在上篇文章的基礎上,繼續討論如何將ffmpeg解碼出的視訊幀進行渲染顯示 ### 1、視訊幀渲染 上篇文章中介紹瞭如何基於ffmpeg搭建一個視訊播放器框架,執行程式後可以看到,除了生成幾張圖片外,程式好像什麼也做不了。 **這是因為ffmpeg通過其封裝的api及元件,為我們遮蔽了不同視訊封裝格式及編碼格式的差異,以統一的api介面提供給開發者使用,開發者不需要了解每種編碼方式及封裝方式具體的技術細節,只需要呼叫ffmpeg提供的api就可以完成解封裝和解碼的操作了**。 至於視訊幀的渲染及音訊幀的播放,ffmpeg就無能為力了,因此需要藉助類似sdl庫等其他第三方元件來完成。 這裡講述如何使用sdl庫完成視訊幀的渲染,sdl在底層封裝了opengl圖形庫,sdl提供的api簡化了opengl的繪圖操作,為開發者提供了很多便利的操作,當然,你也可以採用其他系統支援的圖形庫來繪製視訊幀。 sdl庫的編譯安裝詳見[公眾號:斷點實驗室]的前述文章 [ffmpeg播放器實現詳解 - 框架搭建]。 #### 1.1 渲染環境搭建 **一個視訊幀在顯示前,需要準備一個用於顯示視訊的視窗物件,以及附著在視窗上的畫布物件** 建立SDL視窗,並指定影象尺寸及畫素個數 ```c // 建立SDL視窗,並指定影象尺寸 screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 24, 0); ``` 建立畫布物件 ```c // 建立畫布物件 bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen); ``` #### 1.2 視訊幀渲染 在視窗和畫布物件建立完成後,就可以開始視訊幀的渲染顯示了。 在對畫布物件操作前,需要對其加執行緒鎖保護,避免其他執行緒對畫布中的內容進行競爭性訪問(後面的內容很快會涉及到多執行緒環境的開發)。對執行緒操作不熟悉的同學可以瞭解一下在多執行緒環境下,多個執行緒對臨界區資源的競爭性訪問與執行緒同步操作。 ```c SDL_LockYUVOverlay(bmp);//locks the overlay for direct access to pixel data ``` 向畫布注入解碼後的視訊幀 ```c sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pict.data, pict.linesize); ``` 在畫布物件的視訊幀填充操作完成後,釋放sdl執行緒鎖。 ```c //Unlocks a previously locked overlay. An overlay must be unlocked before it can be displayed SDL_UnlockYUVOverlay(bmp); ``` 對視訊幀的渲染 ```c SDL_DisplayYUVOverlay(bmp, &rect);//影象渲染 ``` 可以看到,由於藉助了sdl封裝的api繪圖介面,視訊幀的渲染還是非常容易的,如果直接採用opengl繪圖,繪製過程會相對複雜些,例程主要的目的是為了介紹ffmpeg的使用,因此,這裡採用sdl簡化了渲染流程。 #### 1.3 專案原始碼編譯 本例程和上篇文章中用到的編譯方法完全一樣 ```powershell tutorial02: tutorial02.c gcc -o tutorial02 -g3 tutorial02.c -I${FFMPEG_INCLUDE} -I${SDL_INCLUDE} \ -L${FFMPEG_LIB} -lavutil -lavformat -lavcodec -lswscale -lswresample -lz -lm \ `sdl-config --cflags --libs` clean: rm -rf tutorial02 ``` 執行make命令開始編譯,編譯完成後,可在原始碼目錄生成名為[tutorial02]的可執行檔案。 可通過ldd命令查詢當前可執行檔案所有依賴的動態庫。 #### 1.4 驗證 執行[tutorial02 url]命令,可以看到有畫面輸出了。 ```powershell ./tutorial02 rtmp://58.200.131.2:1935/livetv/hunantv ``` ![](https://img2020.cnblogs.com/blog/2063669/202007/2063669-20200715232507777-1705655792.png) 雖然畫面已經有了,但還缺少聲音,下篇文章會繼續完善我們的播放器開發,討論如何播放聲音。 ### 2、視訊播放中可能出現的問題 視訊播放中可能會出現以下兩個問題 sdl找不到音訊裝置 SDL_OpenAudio no such audio device sdl無法初始化 Could not initialize SDL, no available video device 解決方法見[公眾號:斷點實驗室]的前述文章 [ffplay原始碼編譯]。 ### 3、原始碼清單 原始碼非常的簡單,僅在上篇的內容基礎上,增加了sdl渲染環境的搭建,整個原始碼仍然執行在main的主執行緒中,後面的內容會涉及多個執行緒的排程及同步的場景。 ```c // tutorial02.c // A pedagogical video player that will stream through every video frame as fast as it can. // // This tutorial was written by Stephen Dranger ([email protected]). // // Code based on FFplay, Copyright (c) 2003 Fabrice Bellard, // and a tutorial by Martin Bohme ([email protected]) // Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1 // // Updates tested on: // Mac OS X 10.11.6 // Apple LLVM version 8.0.0 (clang-800.0.38) // // Use // // $ gcc -o tutorial02 tutorial02.c -lavutil -lavformat -lavcodec -lswscale -lz -lm `sdl-config --cflags --libs` // // to build (assuming libavutil/libavformat/libavcodec/libswscale are correctly installed your system). // // Run using // // $ tutorial02 myvideofile.mpg // // to play the video stream on your screen. #