zoukankan      html  css  js  c++  java
  • 重写Android相机适配不同的设备,对于相机旋转角度问题解决方案

    Android开发中经常需要重写相机,由此会导致一些旋转的情况(不同的设备摄像头角度是不一样的),此处按照解决思路给出解决方案:

    情形一:只需要旋转摄像头方向以及最终的照片,注意两者需要保持一致

    1. 获取当前相机摄像头的角度,并进行相应的旋转,方法如下:

    此处获取到的摄像头角度可以保存下来,在后面情形二中会用到,这里存到静态变量 orientationDegree 中。

    public static int orientationDegree = 0;

       /**
         * 适配相机旋转
         *
         * @param activity
         * @param cameraId
         * @param camera
         */
        public void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
            Camera.CameraInfo info = new Camera.CameraInfo();
            Camera.getCameraInfo(cameraId, info);
            int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
            int degrees = 0;
            switch (rotation) {
                case Surface.ROTATION_0:
                    degrees = 0;
                    break;
                case Surface.ROTATION_90:
                    degrees = 90;
                    break;
                case Surface.ROTATION_180:
                    degrees = 180;
                    break;
                case Surface.ROTATION_270:
                    degrees = 270;
                    break;
            }
            int result;
            //前置
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                result = (info.orientation + degrees) % 360;
                result = (360 - result) % 360;
            }
            //后置
            else {
                result = (info.orientation - degrees + 360) % 360;
            }
            orientationDegree = result;
            camera.setDisplayOrientation(result);
        }
    

    2. 上述方法中涉及到的参数,第一个Activity,可以传入当前相机Activity的Context,随后进行强转;第二个参数为相机ID(一般设备有多个摄像头,前置,后置等等),下面将给出获取相机ID的方法;

    第三个参数为camera对象,当调用open方法的时候就可以获取到 mCamera = Camera.open();

    获取相机ID的方法如下:

       /**
         * 获取摄像头ID
         *
         * @return
         */
        private int getDefaultCameraId() {
            int defaultId = -1;
            int numberOfCameras = Camera.getNumberOfCameras();
    
            Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
            for (int i = 0; i < numberOfCameras; i++) {
                Camera.getCameraInfo(i, cameraInfo);
                if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                    defaultId = i;
                }
            }
            if (defaultId == -1) {
                if (numberOfCameras > 0) {
                    //没有后置摄像头
                    defaultId = 0;
                } else {
                    Logger.e("没有摄像头");
                }
            }
            return defaultId;
        }

    情形二:在情形一的基础上,需要旋转拍摄过程中的视频帧,与其他平台对接,涉及到JNI编程。此处参考了stackoverflow上的解答,链接如下:

    https://stackoverflow.com/questions/14167976/rotate-an-yuv-byte-array-on-android

    拍照回调过程中会产生图片数据,格式为NV21.类型是字节数据。如果需要将此数据传输到其他平台或者保存到本地(本地视频),则也需要进行相应的旋转。

    public class CameraPreviewCallback implements Camera.PreviewCallback {
    public CameraPreviewCallback(CameraPreviewSend previewSend) { this.mCameraPreviewSend = previewSend; } /** * 在相机预览时每产生一帧时回调 * * @param data 图片数据,格式 NV21 * @param camera 相机对象 */ @Override public void onPreviewFrame(byte[] data, Camera camera) { //todo:业务逻辑 } }

    情形一中获取到的相机旋转角度,此处根据角度来进行相应的旋转。具体方法如下:

    switch (orientationDegree) {
                    case 0:
                        localFrameSave(data);
                        break;
                    case 90:
                        localFrameSave(picRotate90(data, previewWidth, previewHeight));
                        break;
                    case 180:
                        localFrameSave(picRotate180(data, previewWidth, previewHeight));
                        break;
                    case 270:
                        localFrameSave(picRotate270(data, previewWidth, previewHeight));
                        break;
                }
        /**
         * 旋转图片,顺时针旋转90度
         *
         * @param data   nv21格式的图片
         * @param width  图片宽度
         * @param height 图片高度
         * @return 转换后的图片数据
         */
        public native byte[] picRotate90(byte[] data, int width, int height);
    
        static {
            System.loadLibrary("native-lib");
        }

    cpp部分:

    /**
     * 将nv21格式的图片旋转90度
     */
    extern "C"
    jbyteArray
    Java_com_XXX_io_CameraPreviewSend_picRotate90(
            JNIEnv *env, jobject /*this*/, jbyteArray data, jint width, jint height) {
        jbyte *pBuffer = env->GetByteArrayElements(data, 0);
        int length = env->GetArrayLength(data);
        jbyte newData[length];//返回的图片数据
        //根据原数据pBuffer生成新数据newData
        doRotate(pBuffer, newData, width, height);
    
        jbyteArray array = env->NewByteArray(length);
        env->SetByteArrayRegion(array, 0, length, newData);
        env->ReleaseByteArrayElements(data, pBuffer, 0);
        return array;
    } 
    /**
     * 将nv21格式的图片旋转90度
     * @param data 原图片数据
     * @param newData 转换所得图片数据
     * @param width 转换后的图片的宽度
     * @param height 转换后的图片的高度
     */
    void doRotate(jbyte *data, jbyte *newData, jint width, jint height) {
        int i = 0;
        for (int x = 0; x < width; x++) {
            for (int y = height - 1; y >= 0; y--) {
                newData[i] = data[y * width + x];
                i++;
            }
        }
        i = width * height * 3 / 2 - 1;
        for (int x = width - 1; x > 0; x = x - 2) {
            for (int y = 0; y < height / 2; y++) {
                newData[i] = data[(width * height) + (y * width) + x];
                i--;
                newData[i] = data[(width * height) + (y * width) + (x - 1)];
                i--;
            }
        }
    }

    旋转180度的情况:

    /**
     * 将nv21格式的图片旋转180度
     * @param data
     * @param newData
     * @param width
     * @param height
     */
    void doRotate180(jbyte *data, jbyte *newData, jint width, jint height) {
        int i = 0;
        int count = 0;
        for (i = width * height - 1; i >= 0; i--) {
            newData[count] = data[i];
            count++;
        }
        for (i = width * height * 3 / 2 - 1; i >= width * height; i -= 2) {
            newData[count++] = data[i - 1];
            newData[count++] = data[i];
        }
    }
    
    /**
     * 将nv21格式的图片旋转180度
     */
    extern "C"
    jbyteArray
    Java_com_XXX_io_CameraPreviewSend_picRotate180(
            JNIEnv *env, jobject /*this*/, jbyteArray data, jint width, jint height) {
        jbyte *pBuffer = env->GetByteArrayElements(data, 0);
        int length = env->GetArrayLength(data);
        jbyte newData[length];//返回的图片数据
        //根据原数据pBuffer生成新数据newData
        doRotate180(pBuffer, newData, width, height);
    
        jbyteArray array = env->NewByteArray(length);
        env->SetByteArrayRegion(array, 0, length, newData);
        env->ReleaseByteArrayElements(data, pBuffer, 0);
        return array;
    }

    旋转270度的情况:

    /**
     * 将nv21格式的图片旋转270度
     * @param data
     * @param newData
     * @param width
     * @param height
     */
    void doRotate270(jbyte *data, jbyte *newData, jint width, jint height) {
        // Rotate the Y
        int i = 0;
        for (int x = width - 1; x >= 0; x--) {
            for (int y = 0; y < height; y++) {
                newData[i] = data[y * width + x];
                i++;
            }
        }// Rotate the U and V color components
        i = width * height;
        for (int x = width - 1; x > 0; x = x - 2) {
            for (int y = 0; y < height / 2; y++) {
                newData[i] = data[(width * height) + (y * width) + (x - 1)];
                i++;
                newData[i] = data[(width * height) + (y * width) + x];
                i++;
            }
        }
    }
    
    /**
     * 将nv21格式的图片旋转270度
     */
    extern "C"
    jbyteArray
    Java_com_XXX_io_CameraPreviewSend_picRotate270(
            JNIEnv *env, jobject /*this*/, jbyteArray data, jint width, jint height) {
        jbyte *pBuffer = env->GetByteArrayElements(data, 0);
        int length = env->GetArrayLength(data);
        jbyte newData[length];//返回的图片数据
        //根据原数据pBuffer生成新数据newData
        doRotate270(pBuffer, newData, width, height);
    
        jbyteArray array = env->NewByteArray(length);
        env->SetByteArrayRegion(array, 0, length, newData);
        env->ReleaseByteArrayElements(data, pBuffer, 0);
        return array;
    }

    完结,很感谢stackoverflow上的解答。

  • 相关阅读:
    在centos7上安装ClamAV杀毒,并杀毒(centos随机英文10字母)成功
    在centos7上安装Jenkins
    Spring cache简单使用guava cache
    Spring resource bundle多语言,单引号format异常
    如何优化coding
    IIS配置中出现HRESULT:0X80070020错误
    如何解决:对应的服务器 tls 为 tls 1.0,小程序要求的TLS版本必须大于等于1.2问题
    微信小程序--后台交互/wx.request({})方法/渲染页面方法 解析
    微信小程序页面带参数跳转及接收参数内容navigator
    微信小程序阿里云服务器https搭建
  • 原文地址:https://www.cnblogs.com/xuanwei-qingfeng/p/8058562.html
Copyright © 2011-2022 走看看