美文网首页FFmpegAndroid开发学习Android开发经验谈
分享几个Android摄像头采集的YUV数据旋转与镜像翻转的方法

分享几个Android摄像头采集的YUV数据旋转与镜像翻转的方法

作者: 这真不是玩笑 | 来源:发表于2017-08-31 16:19 被阅读2451次

  最近在做直播推流方面的工作,因为需要添加美白,滤镜,AR贴图等效果。所以不能简单的使用SufaceView加Camera的方式进行数据的采集,而是需要对Camera采集到的YUV数据进行相关的处理之后然后再进行推流的操作,YUV数据的返回接口。

@Override
    public void onPreviewFrame(byte[] data, Camera camera) {
       
    }

  当然,美白,滤镜,AR贴图等效果采用的是第三方的SDK了。除此之外,因为Android摄像头采集的数据都是有一定的旋转的。一般前置摄像头有270度的旋转,后置摄像头有90的旋转。所以要对YUV数据进行一定旋转操作,同时对于前置摄像头的数据还要进行镜像翻转的操作。网上一般比较多的算法是关于旋转的

private byte[] rotateYUVDegree90(byte[] data, int imageWidth, int imageHeight) {
        byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2];
        // Rotate the Y luma
        int i = 0;
        for (int x = 0; x < imageWidth; x++) {
            for (int y = imageHeight - 1; y >= 0; y--) {
                yuv[i] = data[y * imageWidth + x];
                i++;
            }
        }
        // Rotate the U and V color components
        i = imageWidth * imageHeight * 3 / 2 - 1;
        for (int x = imageWidth - 1; x > 0; x = x - 2) {
            for (int y = 0; y < imageHeight / 2; y++) {
                yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x];
                i--;
                yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x - 1)];
                i--;
            }
        }
        return yuv;
    }
 private byte[] rotateYUVDegree270(byte[] data, int imageWidth, int imageHeight) {
        byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2];
        // Rotate the Y luma
        int i = 0;
        for (int x = imageWidth - 1; x >= 0; x--) {
            for (int y = 0; y < imageHeight; y++) {
                yuv[i] = data[y * imageWidth + x];
                i++;
            }
        }// Rotate the U and V color components
        i = imageWidth * imageHeight;
        for (int x = imageWidth - 1; x > 0; x = x - 2) {
            for (int y = 0; y < imageHeight / 2; y++) {
                yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x - 1)];
                i++;
                yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x];
                i++;
            }
        }
        return yuv;
    }

  上述两个算法分别用于90度旋转(后置摄像头)和270度旋转(前置摄像头),但是对于前置摄像头的YUV数据是需要镜像的,参照上面的算法,实现了前置摄像头的镜像算法。

 private byte[] rotateYUVDegree270AndMirror(byte[] data, int imageWidth, int imageHeight) {
        byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2];
        // Rotate and mirror the Y luma
        int i = 0;
        int maxY = 0;
        for (int x = imageWidth - 1; x >= 0; x--) {
            maxY = imageWidth * (imageHeight - 1) + x * 2;
            for (int y = 0; y < imageHeight; y++) {
                yuv[i] = data[maxY - (y * imageWidth + x)];
                i++;
            }
        }
        // Rotate and mirror the U and V color components
        int uvSize = imageWidth * imageHeight;
        i = uvSize;
        int maxUV = 0;
        for (int x = imageWidth - 1; x > 0; x = x - 2) {
            maxUV = imageWidth * (imageHeight / 2 - 1) + x * 2 + uvSize;
            for (int y = 0; y < imageHeight / 2; y++) {
                yuv[i] = data[maxUV - 2 - (y * imageWidth + x - 1)];
                i++;
                yuv[i] = data[maxUV - (y * imageWidth + x)];
                i++;
            }
        }
        return yuv;
    }

  至于更多关于YUV和推流的知识,目前我还不是很了解。这篇文章也主要是分享这三个算法。

相关文章

网友评论

  • ed55f5882629:那个,前辈,最近在学习做安卓MediaRecordor录像的demo,现在被前置摄像头拍出的视频左右颠倒了,想知道怎么实现镜像?
  • 小白学AI:看样子楼主是在java里面做的镜像,如果图片比较大,Java的处理速度能跟得上吗?有没有考虑放在jni中做?另外楼主有没有考虑一个问题,这个镜像效果,一般都是一个可选功能。就是说用户点击了这个镜像按钮,才会有镜像效果,再次点击按钮,镜像效果就没了。如果这样的话,对于大量的循环操作,java岂不是更加力不从心。因为我最近也在研究这个,所以和楼主探讨下。我在OpenGL 中实现的。但是按钮控制不是太方便。
    小白学AI:@请叫我百米冲刺 我目前的方法有问题:因为我是直接改动的纹理坐标,让其左右颠倒,就能实现镜像效果。但是这样不太好控制镜像效果的有无。另外也会对其他的操作,比如滤镜产生影像(因为除了镜像之外,其他的需要的都是正常的图像)。
    这真不是玩笑:如果只是对图片处理的话,不需要转化为yuv来处理吧
    这真不是玩笑:我们这块是需要直接对yuv数据进行操作处理,目前采用的是libyuv的方式对yuv数据进行直接的操作处理,https://www.jianshu.com/p/bd0feaf4c0f9
    当然如果能直接使用opengl不经过yuv效率上更好
  • qluojieq:没有镜像成功时为什么呢;

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
    Log.e(TAG, "预览帧frame");
    rotateYUVDegree90(data,640,480);
    camera.addCallbackBuffer(gBuffer);
    }
    这真不是玩笑:@qluojieq 对于摄像头预览的效果直接调用Camera相关的api就好了,而如果是要保存摄像头的数据,比如编码成h264等等,,那么这里提供的三个方法就是用来处理数据使用的,,,而且这里介绍rotateYUVDegree90的方法是旋转90度啊,而rotateYUVDegree270AndMirror是旋转270度并且镜像翻转
    qluojieq:这个设置只能达到翻转的效果,并不是镜像;rotateYUVDegree90这个方法不是应该像我在留言中提到的那个地方使用吗,
    这真不是玩笑:摄像头预览镜像应该是调用Camera.setDisplayOrientation()方法,一般
    private int setCameraDisplayOrientation(int cameraId) {
    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(cameraId, info);
    int rotation = mContext.getCurrentActivity().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;
    //前置摄像头需要镜像,转化后进行设置
    mCamera.setDisplayOrientation((360 - result) % 360);
    } else {
    result = (info.orientation - degrees + 360) % 360;
    //后置摄像头直接进行显示
    mCamera.setDisplayOrientation(result);
    }
    return result;
    }
    这里面的几个方法是对摄像头获取的数据进行使用的
  • wangxin_05:我试了一下rotateYUVDegree270AndMirror,镜像没有生效 是什么原因?
  • 不会飞的小猪:因为没做过视频这块,想请问下rotateYUVDegree270AndMirror这个方法是在什么时候使用?
    pursuit_hu:在Camera.PreviewCallback复写的方法中
  • 平仔:谢谢分享,很有用

本文标题:分享几个Android摄像头采集的YUV数据旋转与镜像翻转的方法

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