Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 780|回复: 0

重写Android相机适配不同的设备,对于相机旋转角度问题解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-24 11:54:48 | 显示全部楼层 |阅读模式

    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 = 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 = data[(width * height) + (y * width) + x];
                i--;
                newData = 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;
            count++;
        }
        for (i = width * height * 3 / 2 - 1; i >= width * height; i -= 2) {
            newData[count++] = data[i - 1];
            newData[count++] = data;
        }
    }
    
    /**
     * 将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 = 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 = data[(width * height) + (y * width) + (x - 1)];
                i++;
                newData = 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上的解答。

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-1-12 16:09 , Processed in 0.063094 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表