文章目录

  • I . FFMPEG ANativeWindow 原生绘制
  • II . FFMPEG 原生绘制流程
  • III . Java 层获取 Surface 画布
  • IV . 传递 Surface 画布到 Native 层
  • V . Native 层创建 ANativeWindow 原生绘制窗口

I . FFMPEG ANativeWindow 原生绘制


FFMPEG ANativeWindow 原生绘制前置操作 :

① FFMPEG 初始化 : 参考博客 【Android FFMPEG 开发】FFMPEG 初始化 ( 网络初始化 | 打开音视频 | 查找音视频流 )

② FFMPEG 获取 AVStream 音视频流 : 参考博客 【Android FFMPEG 开发】FFMPEG 获取 AVStream 音视频流 ( AVFormatContext 结构体 | 获取音视频流信息 | 获取音视频流个数 | 获取音视频流 )

③ FFMPEG 获取 AVCodec 编解码器 : 参考博客 【Android FFMPEG 开发】FFMPEG 获取编解码器 ( 获取编解码参数 | 查找编解码器 | 获取编解码器上下文 | 设置上下文参数 | 打开编解码器 )

④ FFMPEG 读取音视频流中的数据到 AVPacket : 参考博客 【Android FFMPEG 开发】FFMPEG 读取音视频流中的数据到 AVPacket ( 初始化 AVPacket 数据 | 读取 AVPacket )

⑤ FFMPEG 解码 AVPacket 数据到 AVFrame : 参考博客 【Android FFMPEG 开发】FFMPEG 解码 AVPacket 数据到 AVFrame ( AVPacket->解码器 | 初始化 AVFrame | 解码为 AVFrame 数据 )

⑥ FFMPEG AVFrame 图像格式转换 YUV -> RGBA : 参考博客 【Android FFMPEG 开发】FFMPEG AVFrame 图像格式转换 YUV -> RGBA ( 获取 SwsContext | 初始化图像数据存储内存 | 图像格式转换 )

II . FFMPEG 原生绘制流程


FFMPEG 解码 AVPacket 数据到 AVFrame 流程 :

〇 前置操作 : FFMPEG 环境初始化 , 获取 AVStream 音视频流 , 获取 AVCodec 编解码器 , 读取音视频流中的数据到 AVPacket , 解码 AVPacket 数据到 AVFrame , AVFrame 图像格式转换 YUV -> RGBA , 然后才能进行下面的操作 ;

① Java 层获取 Surface 对象 : Surface 画布可以在 SurfaceView 的 SurfaceHolder 中获取

//绘制图像的 SurfaceView
SurfaceView surfaceView;//在 SurfaceView 回调函数中获取
SurfaceHolder surfaceHolder = surfaceView.getHolder() ; //获取 Surface 画布
Surface surface = surfaceHolder.getSurface() ;

② 将 Surface 对象传递到 Native 层 : 在 SurfaceHolder.Callback 接口的 surfaceChanged 实现方法中 , 将 Surface 画布传递给 Native 层 ;

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {//画布改变 , 横竖屏切换 , 按下 Home 键 , 按下菜单键//将 Surface 传到 Native 层 , 在 Native 层绘制图像native_set_surface(holder.getSurface());
}//调用该方法将 Surface 传递到 Native 层
native void native_set_surface(Surface surface);

③ 创建 ANativeWindow : 在 Native 层的 C++ 代码中 , 接收 Surface 画布 , 并创建 ANativeWindow 本地绘制窗口 , 原生绘制主要在 ANativeWindow 中进行 ;

//CPP 中接收 Surface 画布 , 并创建 ANativeWindow
extern "C"
JNIEXPORT void JNICALL
Java_kim_hsl_ffmpeg_Player_native_1set_1surface(JNIEnv *env, jobject instance, jobject surface) {// 将从 Java 层传递的 Surface 对象转换成 ANativeWindow 结构体//      如果之前已经有了 ANativeWindow 结构体 , 那么先将原来的释放掉//释放原来的 ANativeWindowif(aNativeWindow){ANativeWindow_release(aNativeWindow);}//转换新的 ANativeWindowaNativeWindow = ANativeWindow_fromSurface(env, surface);
}

III . Java 层获取 Surface 画布


1 . Surface 画布 : 这里的 Surface 画布从 SurfaceView 中获得 , SurfaceHolder.Callback 的监听方法中获取 SurfaceHolder 及 Surface ;

2 . 设置 SurfaceHolder 回调函数 : 首先要获取 SurfaceView 的 SurfaceHolder ; 设置 SurfaceHolder 监听回调函数 SurfaceHolder.Callback ;

        //监听获取画布this.surfaceHolder = this.surfaceView.getHolder();surfaceHolder.addCallback(this);

3 . 获取 Surface 画布 : 在 surfaceChanged 回调方法中 , 获取 Surface 画布 , 这样可以保证在横竖屏切换时可以实时获取到最新画布 ;

    @Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {//画布改变 , 横竖屏切换 , 按下 Home 键 , 按下菜单键//holder.getSurface() 就是 Surface 画布 ; }

4 . Surface 画布获取 代码示例 :

package kim.hsl.ffmpeg;import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;/*** Java 层与 Native 层交互 接口*/
public class Player implements SurfaceHolder.Callback {private static final String TAG = "Player";// 加载动态库static {System.loadLibrary("native-lib");}/*** 视频显示组件*/private SurfaceView surfaceView;/*** 控制 Surface 画布接口*/private SurfaceHolder surfaceHolder;...public void setSurfaceView(SurfaceView surfaceView) {this.surfaceView = surfaceView;//监听获取画布this.surfaceHolder = this.surfaceView.getHolder();surfaceHolder.addCallback(this);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {//画布创建}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {//画布改变 , 横竖屏切换 , 按下 Home 键 , 按下菜单键//holder.getSurface() 就是 Surface 画布 ; }@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {//画布销毁}
}

IV . 传递 Surface 画布到 Native 层


1 . 原生绘制需求 : 在 Native 层使用 C/C++ 进行原生绘制需要将 Surface 画布传递到 Native 层进行绘制 ;

2 . 定义传递方法 : 在 Java 层定义传递 Surface 画布的 Native 方法 ;

native void native_set_surface(Surface surface);

3 . 实现 Surface 传递方法 : 在 Native 层实现 Java 中定义的方法 ;


extern "C"
JNIEXPORT void JNICALL
Java_kim_hsl_ffmpeg_Player_native_1set_1surface(JNIEnv *env, jobject instance, jobject surface) {...
}

4 . 传递 Surface 画布操作 : 在 surfaceChanged 函数中 , 通过调用 SurfaceHolder 的 getSurface ( ) 方法获取 Surface 画布 , 再调用 native_set_surface(holder.getSurface()) , 将画布传递到 Surface 层 ;

    @Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {//画布改变 , 横竖屏切换 , 按下 Home 键 , 按下菜单键//将 Surface 传到 Native 层 , 在 Native 层绘制图像native_set_surface(holder.getSurface());}

V . Native 层创建 ANativeWindow 原生绘制窗口


1 . ANativeWindow 创建 : 在 Native 层实现 Java 中定义的本地方法 native_set_surface ( ) , 在该方法中传入了 Surface 对象作为参数 ; 在该 Native 方法中 , 调用了 ANativeWindow_fromSurface ( ) 方法 , 将 Surface 对象转为了 ANativeWindow 原生绘制窗口 ;

2 . ANativeWindow_fromSurface ( ) 函数原型 :

① JNIEnv* env 参数 : JNI 环境 , 在 JNI 方法中自带 ;

② jobject surface 参数 : Java 层传入的 Surface 对象 ;

/*** Return the ANativeWindow associated with a Java Surface object,* for interacting with it through native code.  This acquires a reference* on the ANativeWindow that is returned; be sure to use ANativeWindow_release()* when done with it so that it doesn't leak.*/
ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);

3 . Native 层创建 ANativeWindow 原生绘制窗口 代码示例 :

/*** 原生绘制窗口*/
ANativeWindow * aNativeWindow;extern "C"
JNIEXPORT void JNICALL
Java_kim_hsl_ffmpeg_Player_native_1set_1surface(JNIEnv *env, jobject instance, jobject surface) {//加同步锁pthread_mutex_lock(&mutex);// 将从 Java 层传递的 Surface 对象转换成 ANativeWindow 结构体//      如果之前已经有了 ANativeWindow 结构体 , 那么先将原来的释放掉//释放原来的 ANativeWindowif(aNativeWindow){ANativeWindow_release(aNativeWindow);}//转换新的 ANativeWindowaNativeWindow = ANativeWindow_fromSurface(env, surface);//解除同步锁pthread_mutex_unlock(&mutex);}

【Android FFMPEG 开发】FFMPEG ANativeWindow 原生绘制 ( Java 层获取 Surface | 传递画布到本地 | 创建 ANativeWindow )相关推荐

  1. 【Android FFMPEG 开发】FFMPEG ANativeWindow 原生绘制 ( 设置 ANativeWindow 缓冲区属性 | 获取绘制缓冲区 | 填充数据到缓冲区 | 启动绘制 )

    文章目录 I . FFMPEG ANativeWindow 原生绘制 前置操作 II . FFMPEG 原生绘制流程 III . 设置 ANativeWindow 绘制窗口属性 ANativeWind ...

  2. 【Android 应用开发】Canvas 精准绘制文字 ( 文本边界坐标解析 | 绘图位置 )

    文章目录 一.文本边界坐标解析 二.绘图位置 一.文本边界坐标解析 在上一篇博客 [Android 应用开发]Canvas 精准绘制文字 ( 测量文本真实边界 | 将文本中心点与给定中心点对齐 ) 中 ...

  3. Android设计开发 答题app 安卓+后台Java+数据库mysql

    Android设计开发 答题app 安卓+后台Java+数据库mysql 基于安卓设计开发答题系统界面简洁大方 有用户注册,登录模块 主页,答题,选择答案,提交答案等模块 程序已经调试完成,包括前端安 ...

  4. Android开发之六:SurfaceView、ANativeWindow原生绘制

    SurfaceView ​ Activity的View hierachy的树形结构,最顶层的DecorView,也就是根结点视图,在SurfaceFlinger中有对应的Layer. ​ 对于具有Su ...

  5. 【Android FFMPEG 开发】OpenSLES 播放音频 ( 创建引擎 | 输出混音设置 | 配置输入输出 | 创建播放器 | 获取播放/队列接口 | 回调函数 | 开始播放 | 激活回调 )

    文章目录 I . FFMPEG 播放视频流程 II . OpenSLES 播放音频流程 III . OpenSLES 播放参考 Google 官方示例 IV . OpenSL ES 播放代码 ( 详细 ...

  6. 【Android FFMPEG 开发】FFMPEG 音频重采样 ( 初始化音频重采样上下文 SwrContext | 计算音频延迟 | 计算输出样本个数 | 音频重采样 swr_convert )

    文章目录 I . FFMPEG 播放视频流程 II . FFMPEG 音频重采样流程 III . FFMPEG 音频重采样 IV . FFMPEG 初始化音频重采样上下文 SwrContext V . ...

  7. 《Android应用开发入门经典(第3版)》——第6.1节创建演示应用

    本节书摘来自异步社区<Android应用开发入门经典(第3版)>一书中的第6章,第6.1节创建演示应用,作者 [美]Carmen Delessio , Lauren Darcey , Sh ...

  8. surfacecontrol.java_简单说说JAVA层中Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系...

    1.Surface Surface extends Object implements Parcelable java.lang.Object android.view.Surface Class O ...

  9. ffmpeg学习笔记-native原生绘制

    上次已将ffmpeg的动态库编译出来了,并且使用了ffmpeg的转码功能,成功将mp4格式视频转化为yuv视频,这篇文章基于上次测试的demo,使用surfaceview显示解码完成的像素数据 布局设 ...

最新文章

  1. 在Asp.Net中从sqlserver检索(retrieve)图片
  2. MyEclipse2014安装svn插件
  3. Qt 解决MySQL 中文乱码问题
  4. CentOS系列启动流程和内核原理(5系列,6系列,7系列)
  5. 计算机电力英语翻译,电力专业英语阅读与翻译..doc
  6. xsslabs靶机解题_web 攻击靶机解题过程
  7. 【博士招生】卢森堡大学​SnT(CVI²)研究小组,DeepFake 检测领域
  8. java forkjoin 简书_ForkJoinPool in Java
  9. welcome-file-list标签的控制作用以及在springmvc中此标签的的配置方式
  10. [转载] python基于内置的SimpleHTTPServer来搭建简易的FTP服务器实现局域网内文件共享
  11. spring扩展点六:监听spring容器刷新事件
  12. c语言编程被当作病毒,c语言编写病毒
  13. c语言定义函数return,在C语言的函数定义中,如果不需要返回结果,就可以省略return语句。...
  14. php怎么处理背景虚化,图片虚化处理 照片制作成视频|图片背景虚化后制作成视频并添加音乐...
  15. 百度云直链下载-IDM+网页解析(三)
  16. 袋鼠云数据湖平台「DataLake」,存储全量数据,打造数字底座
  17. PHP 毫秒级时间戳生成
  18. 企业面临大危机,CRM崩溃告急,程序员竟用特殊手段化解危机!
  19. iOS之身份证的正则校验
  20. 原生js中attributes属性

热门文章

  1. POJ3335(半平面交)
  2. 【学习记录】无法找到“Procedural Foliage Spawner”
  3. 十一. 图形、图像与多媒体1.绘图基础
  4. 递归--练习8--noi1788Pell数列
  5. 全局变量引起的BUG
  6. Husband的忏悔书(IT攻城狮)
  7. Repeater使用 AspNetPager分页控件
  8. 《bbs.yingjiesheng.com,超全的求职笔经面经论坛》
  9. OK,让我们开始吧!
  10. 第1章 1.9计算机网络概述--OSI参考模型和网络安全