Android 播放器渲染一帧图像

本文想要介绍ijkplayer 软硬解下是如何渲染一帧图像到屏幕上。


先简单的介绍一下MediaCodec API,不过 需要好好研究学习一番,它涉及解码播放的方方面面。下面的2个图能给我们清晰的认识。

Android 播放器渲染一帧图像_第1张图片

Android 播放器渲染一帧图像_第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、以及 MediaCodec dequeueOutputBuffer 返回索引值 等等,这里的 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 转换 效率更高

你可能感兴趣的:(Android 播放器渲染一帧图像)