本文想要介绍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 转换 效率更高
网友评论