Android 短视频源码开发之相机拍照

这篇博客详细介绍了如何在Android短视频源码开发中实现相机拍照功能,包括两种方法:从EGL环境中获取渲染图像数据和通过摄像头原始数据处理。在OpenGL环境下,对图像进行滤镜处理,然后保存处理后的图片。博客内容涉及OpenGL ES的使用、纹理映射、帧缓冲对象以及滤镜应用等技术。
摘要由CSDN通过智能技术生成

原理:
   Android 短视频源码开发的相机拍照实现其实就很简单了,主要是在执行拍照动作后把摄像头回调的数据进行处理后保存到本地就可以了。

实现思路:

这里我采用两种方式实现拍照

1、在onDrawFrame(GL10 gl)回调方法中获取当前EGL中渲染过的图像数据(由于这里每帧都会回调,要注意性能问题)。

2、拿到摄像头捕获的原始数据放到GLSurfaceView的渲染队列中进行OpengGL渲染后(涉及到FrameBuffer的使用),再从EGL环境下获取渲染后的图片数据进行保存。

具体实现
代码实现方式一:

  @Override
    public void onDrawFrame(GL10 gl) {
        super.onDrawFrame(gl);
        if(surfaceTexture == null)
            return;
        surfaceTexture.updateTexImage();  //获取最新的数据
       
        float[] mtx = new float[16];
        surfaceTexture.getTransformMatrix(mtx);
        cameraInputFilter.setTextureTransformMatrix(mtx);
        int id = textureId;
        //进行OpenGL渲染
        if(filter == null){
            cameraInputFilter.onDrawFrame(textureId, gLCubeBuffer, gLTextureBuffer);
        }else{
            id = cameraInputFilter.onDrawToTexture(textureId);
            filter.onDrawFrame(id, gLCubeBuffer, gLTextureBuffer);
        }
      
        if(isTakePicture){
            
            CameraInfo info = CameraEngine.getCameraInfo();
            int width = getWidth();
            int height = getHeight();
            GLES20.glViewport(0,0,width,height);
            IntBuffer ib = IntBuffer.allocate(width * height);
            //获取EGL环境的图像数据
            GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ib); 
            Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            result.copyPixelsFromBuffer(IntBuffer.wrap(ib.array()));
            //            Bitmap result = createBitmapFromGLSurface(0,0,getWidth(),getHeight(), gl);
            //异步保存图片
            new SavePictureTask(getOutputMediaFile(),null).execute(result);
            isTakePicture = false;
        }
    }

这里有很多优化空间,我这里只提供一种实现方式具体优化,可以根据情况自行处理。

方式二实现 

    1.先获取摄像头原始数据的bitmap图像

   CameraEngine.takePicture(null, null, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                CameraEngine.stopPreview();
                //摄像头原始图像数据
                final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                //要利用OpenGl 绘图暂时停止摄像头预览,并且渲染操作要放到EGLContenxt环境下
                queueEvent(new Runnable() {
                    @Override
                    public void run() {
                        //把摄像头获取的bitmap图片经过Opengl滤镜处理后返回保存
                        final Bitmap photo = drawPhoto(bitmap,CameraEngine.getCameraInfo().isFront);
                        GLES20.glViewport(0, 0, surfaceWidth, surfaceHeight);
                        if (photo != null)
                            savePictureTask.execute(photo);
                    }
                });
                CameraEngine.startPreview();
            }
        });

 2.通过drawPhoto方法使用OpenGL 处理源图像数据

   private Bitmap drawPhoto(Bitmap bitmap,boolean isRotated){
        //设置最终生成的图片的宽高
        CameraInfo info = CameraEngine.getCameraInfo();
        int width = info.previewHeight;
        int height = info.previewWidth;
 
        if(beautyFilter == null)
            beautyFilter = new MagicBeautyFilter();
        beautyFilter.init();
        beautyFilter.onDisplaySizeChanged(width, height);
        beautyFilter.onInputSizeChanged(width, height);
 
        if(filter != null) {
            filter.onInputSizeChanged(width, height);
            filter.onDisplaySizeChanged(width, height);
        }
 
 
        //创建并使用FBO //使用帧缓冲绘制渲染到离屏的buffer中
        int[] mFrameBuffers = new int[1];
        int[] mFrameBufferTextures = new int[1];
        GLES20.glGenFramebuffers(1, mFrameBuffers, 0);
        GLES20.glGenTextures(1, mFrameBufferTextures, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mFrameBufferTextures[0]);
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0,
                GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffers[0]);
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
                GLES20.GL_TEXTURE_2D, mFrameBufferTextures[0], 0);
 
        //设置渲染窗口大小
        GLES20.glViewport(0, 0, width, height);
        //加载原始图片到纹理对象中
        int textureId = OpenGlUtils.loadTexture(bitmap, OpenGlUtils.NO_TEXTURE, true);
 
        FloatBuffer gLCubeBuffer = ByteBuffer.allocateDirect(TextureRotationUtil.CUBE.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        FloatBuffer gLTextureBuffer = ByteBuffer.allocateDirect(TextureRotationUtil.TEXTURE_NO_ROTATION.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        gLCubeBuffer.put(TextureRotationUtil.CUBE).position(0);
        //这是纹理是否要旋转,因为前置摄像头拍照时反转了的
        if(isRotated)
            gLTextureBuffer.put(TextureRotationUtil.getRotation(Rotation.NORMAL, false, false)).position(0);
        else
            gLTextureBuffer.put(TextureRotationUtil.getRotation(Rotation.NORMAL, false, true)).position(0);
 
 
        if(filter == null){
            //只要美颜滤镜直接渲染
            beautyFilter.onDrawFrame(textureId, gLCubeBuffer, gLTextureBuffer);
        }else{
            //双滤镜叠加,首先美颜渲染到原始图片纹理上
            beautyFilter.onDrawFrame(textureId);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
            //然后颜色滤镜渲染到帧缓存FBO上
            filter.onDrawFrame(mFrameBufferTextures[0], gLCubeBuffer, gLTextureBuffer);
        }
 
        //从EGL环境下获取图片数据
        IntBuffer ib = IntBuffer.allocate(width * height);
        GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ib);
        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        result.copyPixelsFromBuffer(ib);
 
        //释放资源
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
        GLES20.glDeleteTextures(1, new int[]{textureId}, 0);
        GLES20.glDeleteFramebuffers(mFrameBuffers.length, mFrameBuffers, 0);
        GLES20.glDeleteTextures(mFrameBufferTextures.length, mFrameBufferTextures, 0);
 
        beautyFilter.destroy();
        beautyFilter = null;
        if(filter != null) {
            filter.onDisplaySizeChanged(surfaceWidth, surfaceHeight);
            filter.onInputSizeChanged(imageWidth, imageHeight);
        }
        return result;
    }

这样就能把处理后的图片给保存下来了。Android 短视频源码开发之相机拍照的实现是不是很简单?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值