美文网首页
二、MagicCamera3#Kotlin部分

二、MagicCamera3#Kotlin部分

作者: YongtaoHuang | 来源:发表于2019-11-09 15:29 被阅读0次

两个部分

代码分为app和pickphotoview两个部分
app依赖于pickphotoview:

dependencies {
    implementation project(':pickphotoview')
}

pickphotoview是一个用来选择图片的Android UI程序,可以忽略。
app部分是核心。

app部分结构

app.png

MainActivity→
→ CameraActivity // 普通摄像头功能的活动
→ CameraFilterActivity // 滤镜摄像头功能的活动
→ ImageEditActivity // 图片编辑,这里使用了pickphotoview

CameraFilterActivity是主要需要阅读的部分:


kotlin.png

CameraFilterV2Activity中使用的3个类

这个Activity涉及的3个主要类

  • FilterAdapter
  • CameraCompat
  • CameraFilterSurfaceCallbackV2(核心)
FilterAdapter

FilterAdapter是选择滤镜类型的RecyclView:

// FilterAdapter继承了RecycleView.Adapter
class FilterAdapter(private val context: Context, private val filters: IntArray) : RecyclerView.Adapter<FilterAdapter.FilterHolder>() {
    private var selected = 0

    interface onFilterChangeListener {
        fun onFilterChanged(filterType: Int)
    }

    var filterListener: onFilterChangeListener? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FilterHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.filter_item_layout,
                parent, false)
        return FilterHolder(view)
    }

    override fun onBindViewHolder(holder: FilterHolder, position: Int) {
        holder.thumbImage.setImageResource(FilterTypeHelper.FilterType2Thumb(filters[position]))
        holder.filterName.setText(FilterTypeHelper.FilterType2Name(filters[position]))
        holder.filterName.setBackgroundColor(context.resources.getColor(
                FilterTypeHelper.FilterType2Color(filters[position])))
        if (position == selected) {
            holder.thumbSelected.visibility = View.VISIBLE
            holder.thumbSelected_bg.setBackgroundColor(context.resources.getColor(
                    FilterTypeHelper.FilterType2Color(filters[position])))
            holder.thumbSelected_bg.alpha = 0.7f
        } else {
            holder.thumbSelected.visibility = View.GONE
        }

        holder.filterRoot.setOnClickListener { v ->
            if (selected != position) {
                val lastSelected = selected
                selected = position
                notifyItemChanged(lastSelected)
                notifyItemChanged(position)
                filterListener?.onFilterChanged(filters[position])
            }
        }
    }

    override fun getItemCount(): Int {
        return filters.size
    }

    inner class FilterHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var thumbImage: ImageView
        var filterName: TextView
        var thumbSelected: FrameLayout
        var filterRoot: FrameLayout
        var thumbSelected_bg: View

        init {
        // ......
        }
    }
}

CameraCompat

这是一个Camera抽象类,包含预览功能:

abstract class CameraCompat(protected var mContext: Context) {

    private var mSwitchFlag: Boolean = false
    protected var mSurfaceTexture: SurfaceTexture? = null   
    private var mSupportFlash = false // 是否支持闪光灯    
    protected var mCameraReady: Boolean = false // 相机是否初始化完成    
    protected var mStarted: Boolean = false // 是否开始预览
 
    @CameraType
    protected var mCameraType = BACK_CAMERA

    var outputSize: CameraSize? = null

    private val mCameraInfo = SparseArray<String>(2)

    protected val frontCameraIdV19: Int
        get() = Integer.valueOf(mCameraInfo.get(FRONT_CAMERA))

    protected val backCameraIdV19: Int
        get() = Integer.valueOf(mCameraInfo.get(BACK_CAMERA))

    protected val frontCameraIdV21: String
        get() = mCameraInfo.get(FRONT_CAMERA)

    protected val backCameraIdV21: String
        get() = mCameraInfo.get(BACK_CAMERA)

    @IntDef(FRONT_CAMERA, BACK_CAMERA)
    @Retention(RetentionPolicy.SOURCE)
    annotation class CameraType

    init {
        mSupportFlash = mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)
        initCameraInfo()
    }

    fun setSurfaceTexture(texture: SurfaceTexture) {
        this.mSurfaceTexture = texture
    }

    protected fun setFrontCameraId(id: String) {
        mCameraInfo.put(FRONT_CAMERA, id)
    }

    protected fun setFrontCameraId(id: Int) {
        mCameraInfo.put(FRONT_CAMERA, id.toString())
    }

    protected fun setBackCameraId(id: Int) {
        mCameraInfo.put(BACK_CAMERA, id.toString())
    }

    protected fun setBackCameraId(id: String) {
        mCameraInfo.put(BACK_CAMERA, id)
    }

    protected abstract fun initCameraInfo()

    fun startPreview() {  }

    protected abstract fun onStartPreview()

    fun stopPreview(releaseSurface: Boolean) { }

    abstract fun onStopPreview()

    protected fun openCamera(@CameraType cameraType: Int) {
        mCameraType = cameraType
        onOpenCamera(cameraType)
    }

    protected abstract fun onOpenCamera(@CameraType cameraType: Int)

    fun turnLight(on: Boolean) { }

    protected abstract fun onTurnLight(on: Boolean)

    fun switchCamera() { }

    class CameraSize {
        var width: Int = 0
        var height: Int = 0
        // ...
    }

    companion object {
        const val DESIRED_HEIGHT = 720
        const val FRONT_CAMERA = 1
        const val BACK_CAMERA = 2
        fun newInstance(context: Context): CameraCompat {
            val api = Build.VERSION.SDK_INT
            return if (api >= 21) {
                CameraCompatV21(context)
            } else {
                CameraCompatV19(context)
            }
        }
    }

}

CameraFilterSurfaceCallbackV2

CameraFilterSurfaceCallbackV2继承SurfaceHolder,用来实现相机滤镜的响应:

// CameraFilterSurfaceCallbackV2继承SurfaceHolder
class CameraFilterSurfaceCallbackV2(camera:CameraCompat?):SurfaceHolder.Callback{
    // 覆写surfaceChanged方法
    override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) {
        changeOpenGL(width,height)
    }
    // 覆写surfaceDestroyed方法
    override fun surfaceDestroyed(holder: SurfaceHolder?) {
        releaseOpenGL()
    }
    // 覆写surfaceCreated方法
    override fun surfaceCreated(holder: SurfaceHolder?) {
        initOpenGL(it.surface)
    }
    // 初始化OpenGL
    fun initOpenGL(surface: Surface){
        // 相机滤镜创建是在C++底层实现的
        val textureId = OpenGLJniLib.magicFilterCreate(surface,BaseApplication.context.assets)
    }
    
    fun changeCamera(camera:CameraCompat? ){}

    fun changeOpenGL(width:Int,height:Int){}

    fun drawOpenGL(){}

    fun releaseOpenGL(){}
    // 设置滤镜类型
    fun setFilterType(type:Int){}

    fun doStartPreview(){}

    fun takePhoto(){}
    
}

渲染一个素描摄像头的流程

运行CameraFilterV2Activity

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initView() // 调用 initView()和initCamera()
    }

调用 initView():

    fun initView(){
        filter_listView.layoutManager = LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false)
        mAdapter = FilterAdapter(this, types)
        mAdapter?.filterListener= object:FilterAdapter.onFilterChangeListener{
            override fun onFilterChanged(type: Int) {
                mSurfaceCallback?.setFilterType(type) // 此处设置滤镜类型
            }
        }
        filter_listView.adapter= mAdapter
    }

调用initCamera():

    private fun initCamera(){
        mCamera = CameraCompat.newInstance(this)
        // pay great attention,please!!! 
        mSurfaceCallback = CameraFilterSurfaceCallbackV2(mCamera)
        glsurfaceview_camera.holder.addCallback(mSurfaceCallback)
        mCamera?.startPreview()
    }

CameraFilterSurfaceCallbackV2是核心类,它继承了SurfaceHolder#Callback

class CameraFilterSurfaceCallbackV2(camera:CameraCompat?):SurfaceHolder.Callback{
    override fun surfaceCreated(holder: SurfaceHolder?) {
        holder?.let {
            initOpenGL(it.surface)
        }
    }

    fun initOpenGL(surface: Surface){
        mExecutor.execute {
            // 这一行代码将这个SurfaceView和这个应用的assets(内部主要包含glsl语言)传递给C++底层操作了。
            val textureId = OpenGLJniLib.magicFilterCreate(surface,BaseApplication.context.assets)
//            OpenGLJniLib.setFilterType(MagicFilterType.NONE.ordinal)
            if (textureId < 0){
                Log.e(TAG, "surfaceCreated init OpenGL ES failed!")
                return@execute
            }
            mSurfaceTexture = SurfaceTexture(textureId)
            mSurfaceTexture?.setOnFrameAvailableListener { drawOpenGL() }
            try {
                mSurfaceTexture?.let {
                    mCamera?.setSurfaceTexture(it)
                }
                doStartPreview()
            }catch (e:IOException){
                Log.e(TAG,e.localizedMessage)
                releaseOpenGL()
            }
        }
    }
}

这一行代码将这个SurfaceView和这个应用的assets(内部主要包含glsl语言)传递给C++底层操作了。

OpenGLJniLib.magicFilterCreate(surface,BaseApplication.context.assets)

这里通过JNI调用了C++的代码

//相机滤镜surfaceView初始化的时候创建
JNIEXPORT jint JNICALL
Java_com_cangwang_magic_util_OpenGLJniLib_magicFilterCreate(JNIEnv *env, jobject obj,
                                                        jobject surface,jobject assetManager) {
    std::unique_lock<std::mutex> lock(gMutex);
    if(glCameraFilter){ //停止摄像头采集并销毁
        glCameraFilter->stop();
        delete glCameraFilter;
    }

    //初始化native window
    ANativeWindow *window = ANativeWindow_fromSurface(env,surface);
    //初始化app内获取数据管理
    aAssetManager= AAssetManager_fromJava(env,assetManager);
    //初始化相机采集
    glCameraFilter = new CameraFilter(window,aAssetManager);
    //创建
    return glCameraFilter->create();
}

相关文章

  • 二、MagicCamera3#Kotlin部分

    两个部分 代码分为app和pickphotoview两个部分app依赖于pickphotoview: pickph...

  • python基础部分(二)

    变量及类型 变量 在python中,经常要存储数据,这时我们就需要一个叫变量的东西。如图所示,a、b就是变量,分别...

  • 二、数组部分习题

    //实现想数组输入随机数,要求输入的随机数不重复 通过一个for循环往数组里添加随机数,这时候要想添加的时候可能会...

  • python部分基础二

    排序分为两种,一种原地排序,一种是复制排序 原地排序 :sort() 复制排序:sorted() Note:元组不...

  • 基本部分 (二)

    基本部分完成能力目标。 音乐游戏 红红的新年 小朋友们,刚才我们了解到了红红的新年,知道了新年里有很多的好玩的和好...

  • Swift基础部分(二)

    基础部分 当你声明常量或者变量的时候可以加上类型注解(type annotation),说明常量或者变量中要存储的...

  • iOS runtime 部分二

    主要探究方法的底层结构以及方法缓存 文中使用的 objc4源码是objc-781版本; runtime 部分一ru...

  • iOS Block 部分二

    主要讲解 Block 的分类和变量捕获的强弱引用; Block部分一Block部分二Block部分三Block知识...

  • iOS 锁 部分二

    主要讲解NSLock/NSCondition/NSRecursiveLock/锁的基本用法 常见锁的分类: 自旋锁...

  • SQL进阶部分二

    表之间关系 一对一 ​ 一夫一妻​ 一对多关系 ​ 一个人可以拥有多辆汽车,要求查询某个人拥有的所有车辆。...

网友评论

      本文标题:二、MagicCamera3#Kotlin部分

      本文链接:https://www.haomeiwen.com/subject/orsgvctx.html