Android视频采集渲染学习(1)

声明:代码来源于慕课网视频学习,跟随老师讲解手敲;如有侵权,请及时联系;

功能:Android kotlin基于cameraX,绑定摄像头到preview,imgcapture;进行拍照

注意拍照中的版本判断P,以及写权限,可能影响手机测试时候拍照报错:

qdgralloc: GetYUVPlaneInfo: Invalid format passed: 0x21

 

if(Build.VERSION.SDK_INT<Build.VERSION_CODES.P) { put(MediaStore.Images.Media.RELATIVE_PATH,"Pictures/CamX"); }

 

package com.example.cameraxdemo

import android.content.ContentValues
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.util.Size
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.widget.Toast
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.OutputOptions
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.cameraxdemo.databinding.ActivityMainBinding
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
import java.util.jar.Manifest
import kotlin.math.log

class MainActivity : AppCompatActivity() {
    private lateinit var viewBinding: ActivityMainBinding;
    private var imgcap:ImageCapture?=null;
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewBinding =ActivityMainBinding.inflate(layoutInflater);
        setContentView(viewBinding.root);
        //权限判断
        if(allpermissionagree())
        {
            //ok
            Log.d("have static permission","permission ok");
            startCamera();
        }else{
              ActivityCompat.requestPermissions(this, PermissList,permissCode);
        }



        viewBinding.imgCap.setOnClickListener({takephoto()});

    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if(requestCode == permissCode)
        {
            if(allpermissionagree())
            {
                startCamera();
            //ok
            }else{
                Log.d("no permission","onrequest permission result");
                Toast.makeText(this, "no permission", Toast.LENGTH_SHORT).show();
                finish();//程序结束
            }
        }
    }


    private fun allpermissionagree() = PermissList.all {
        //遍历是否赋予了动态权限
        ContextCompat.checkSelfPermission(baseContext,it)== PackageManager.PERMISSION_GRANTED;
    }


    private fun startCamera(){

        //val 只赋值一次
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        //监听,主线程显示
        cameraProviderFuture.addListener({
            val cameraProvider:ProcessCameraProvider = cameraProviderFuture.get();

            val preview =Preview.Builder().build().also { it.setSurfaceProvider(viewBinding.photoview.surfaceProvider) };
            imgcap = ImageCapture.Builder()
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                .setTargetResolution(Size(1920, 1080))
                .build();

            try {
                cameraProvider.unbindAll();
                //窗口绑定摄像头,后置摄像头
                val camera = cameraProvider.bindToLifecycle(this, CameraSelector.DEFAULT_BACK_CAMERA,preview,imgcap);
                val cameractonrol =camera.cameraControl;
                val cameraInfo =camera.cameraInfo;
                //cameractonrol.enableTorch(true);//允许拍照的时候开启闪光灯
                //1手势监听
                val gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
                    override fun onScroll(
                        e1: MotionEvent,
                        e2: MotionEvent,
                        distanceX: Float,
                        distanceY: Float
                    ): Boolean {
                        val currentZoomRatio = cameraInfo.zoomState.value?.zoomRatio ?: 1f
                        val delta = (e1?.y ?: 0f) - (e2?.y ?: 0f)
                        val scale = delta / viewBinding.photoview.height.toFloat()
                        val zoomRatio = currentZoomRatio + scale
                        cameractonrol.setZoomRatio(
                            zoomRatio.coerceIn(
                                0f,
                                cameraInfo.zoomState.value?.maxZoomRatio ?: 1f
                            )
                        )
                        return true
                    }
                })

                viewBinding.photoview.setOnTouchListener { _, event ->
                    gestureDetector.onTouchEvent(event)
                    true
                }


            }catch (exec:Exception)
            {
                Log.e("preview bind fail","error");
            }

        },ContextCompat.getMainExecutor(this))
    }

    private fun takephoto()
    {
        Log.d("demo","test..........")
        val imgCap =imgcap?:return;

        val name = SimpleDateFormat( FORMATE, Locale.CHINA).format(System.currentTimeMillis())
        //创建文件媒体信息保存contentresolve
        val contentval =ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME,name);
            put(MediaStore.MediaColumns.MIME_TYPE,"image/jpeg");
            if(Build.VERSION.SDK_INT<Build.VERSION_CODES.P)
            {
                put(MediaStore.Images.Media.RELATIVE_PATH,"Pictures/CamX");

            }
        };

        val outputOption =ImageCapture.OutputFileOptions.Builder(
            contentResolver,
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            contentval
        ).build();

        imgCap.takePicture(outputOption,
            ContextCompat.getMainExecutor(this),//主线程
            object:ImageCapture.OnImageSavedCallback{
                override fun onError(exception: ImageCaptureException) {
                    
                    Log.e("take photo error","error");
                }

                override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                    Toast.makeText(baseContext, "take photo ok", Toast.LENGTH_SHORT).show()
                }
            }
        )
    }

    //参数初始化
    companion object{
        private const val permissCode =10;
        private  val FORMATE ="yyyy-MM-dd-HH-mm-ss-SSS";
        //权限列表
        private val PermissList= mutableListOf(
            android.Manifest.permission.CAMERA,
            android.Manifest.permission.RECORD_AUDIO,

            ).apply {
            if(Build.VERSION.SDK_INT <=Build.VERSION_CODES.P)
            {
                add(android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
            }
        }.toTypedArray();
    }

}

  

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <androidx.camera.view.PreviewView
        android:id="@+id/photoview"
        android:layout_width ="match_parent"
        android:layout_height ="match_parent"
        tools:ignore="MissingConstraints" />
    <Button
        android:id="@+id/img_cap"
        android:layout_width="150dp"
        android:layout_height="60dp"
        android:layout_margin="50dp"
        android:text="take-photo"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>


</androidx.constraintlayout.widget.ConstraintLayout>

  

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.cameraxdemo">

    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Cameraxdemo"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

  

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdk 33

    defaultConfig {
        applicationId "com.example.cameraxdemo"
        minSdk 25
        targetSdk 33
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
    buildFeatures{
        viewBinding true
    }
}

dependencies {

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    implementation "androidx.camera:camera-core:1.2.3"

    implementation "androidx.camera:camera-camera2:1.2.3"

    implementation "androidx.camera:camera-lifecycle:1.2.3"

    implementation "androidx.camera:camera-video:1.2.3"

    implementation "androidx.camera:camera-view:1.2.3"
   
    implementation "androidx.camera:camera-extensions:1.2.3"
}

  

posted on 2025-03-16 15:36  邗影  阅读(37)  评论(0)    收藏  举报

导航