本文想要介紹ijkplayer 軟硬解下是如何渲染一幀圖像到屏幕上。
先簡單的介紹一下MediaCodec API,不過 需要好好研究學習一番,它涉及解碼播放的方方面面。下面的2個圖能給我們清晰的認識。
MediaCodec 在API level 16 configure Surface 后解碼播放的過程中運用的MediaCodec 接口
數據輸入接口:
- getInputBuffers
- int dequeueInputBuffer (long timeoutUs)
- [queueInputBuffer](https://developer.android.com/reference/android/media/MediaCodec.html#queueInputBuffer(int, int, int, long, int))(int index, int offset, int size, long presentationTimeUs, int flags)
獲取解碼后的數據:
- int dequeueOutputBuffer (MediaCodec.BufferInfo info, long timeoutUs)
- MediaFormat getOutputFormat ()
視頻渲染:
- [releaseOutputBuffer](https://developer.android.com/reference/android/media/MediaCodec.html#releaseOutputBuffer(int, boolean))(int index, boolean render)
ijkplayer 音視頻渲染引擎是在ijksdl庫實現的,它包含的東西較多:
- OpenSL ES 音頻
- AudioTrack / jni 音頻
- OpenGL ES 渲染視頻
- NativeWindow / 渲染視頻
- MediaCodec / jni 硬件解碼器
- MediaCodecDummy 虛擬硬件解碼器
- pthread 線程API / 線程同步封裝
備注1:ijkyuv庫其實是 libyuv 用于各種YUV/RGB格式直接轉換。遠比FFmpeg 中的 libswscale 提供的效率高。
備注2:MediaCodecDummy 虛擬硬件解碼器在Android 播放器音視頻同步機制 說明。
硬解渲染過程
- 解碼 入隊列
函數 amc_fill_frame
解碼線程中video_thread(ff_video_dec)
調用函數drain_output_buffer
獲取解碼后的信息后調用函數
static int amc_fill_frame( IJKFF_Pipenode *node, AVFrame *frame, int *got_frame, int output_buffer_index, int acodec_serial, SDL_AMediaCodecBufferInfo *buffer_info)
填充了當前幀的基本數據,PTS、width、height、以及 MediaCodecdequeueOutputBuffer
返回索引值 等等,這里的 AVFrame* frame 并沒有申請解碼后數據的緩沖區。
最后調用queue_picture
把填充好的AVFrame數據 入隊列。 - 出隊列渲染
video_refresh_thread(ff_vout)
視頻渲染線程(音視頻同步)調用SDL_VoutDisplayYUVOverlay
然后調用SDL_VoutOverlayAMediaCodec_releaseFrame_l
最終直接調用[releaseOutputBuffer](https://developer.android.com/reference/android/media/MediaCodec.html#releaseOutputBuffer(int, boolean))(int index, boolean render) 視頻渲染
軟解
- 解碼入隊列
- 出隊列渲染
video_refresh_thread(ff_vout)
視頻渲染線程(音視頻同步)調用SDL_VoutDisplayYUVOverlay
然后調用func_display_overlay_l
然后根據配置選擇ANativeWindow / OpenGL ES
1、ANativeWindow Copy機制
備注:ANativeWindow 也可以直接支持YUV(HAL_PIXEL_FORMAT_YV12)格式的copy 的。渲染線程調用SDL_Android_NativeWindow_display_l
渲染步驟:
ANativeWindow_setBuffersGeometry
ANativeWindow_lock
ANativeWindow_unlockAndPost
2、OpenGL ES
渲染線程調用 IJK_EGL_display
IJK_GLES2_Renderer_renderOverlay
func_uploadTexture
glDrawArrays
eglSwapBuffers
備注:OpenGL ES shader 實現了yuv 到rgb 轉換 效率更高