• camera特效app(安卓)


    1.前言:

    相信大家都看过直播,直播中的礼物特效非常的炫酷,今天就教大家如何实现这一过程。其原理就是在摄像头画面上播放透明的特效视频。首先需要准备好mp4格式的特效视频。然后使用opengles进行渲染,实现透明化。当然,由于没有服务器,只能白嫖了。只需要把制作好的特效视频上传到好看视频网站上面,通过抓包拿到播放地址,然后将地址上传到一篇博客上面即可。启动app时首先会爬取该博客上面的视频播放地址。通过这种方法即可以减小app的体积(仅有3.5M),又无需自己购买服务器。后期如果需要更改或修改特效视频,只需要修改博客上面的播放地址即可。

    2. 效果预览:

    app下载地址:https://www.pgyer.com/T6he

    3.特效视频制作及上传

    3.1特效视频格式

    特效视频的制作也很简单,视频格式如下所示:

    在这里插入图片描述
    视频的上半部分为我们想要的特效视频,下半部分为透明度,其值越接近255,则表示越不透明。在使用opengles渲染视频的时候,只需要把下半部分的像素值作为其透明度即可。

    3.2视频上传到网站

    关于视频如何上传到好看视频网站,已经如何抓包获取视频播放地址,我在之前的一篇博客上面已经详细的说明了,如果不明白可前往查看。

    3.3 发布博客

    上传完视频拿到播放地址以后,只需要发布一篇博客,并将视频的播放地址都发布到该博客上面即可。博客内容如下所示:
    在这里插入图片描述
    为了app自动获取特效的名称,需要在播放地址后面加上特效的名字,这样app特效的下拉框中就会自动填写这些特效名字。

    4.camera使用

    使用camerax来显示摄像头画面。camerax相比于camera2更加方便,兼容性更广。
    使用camerax首先需要添加摄像头权限

    <uses-feature android:name="android.hardware.camera.any" />
    <uses-permission android:name="android.permission.CAMERA" />
    
    • 1
    • 2

    添加相关依赖:

        //CameraX
        def camerax_version = "1.1.0-beta03"
    // CameraX core library using camera2 implementation
        implementation "androidx.camera:camera-camera2:$camerax_version"
    // CameraX Lifecycle Library
        implementation "androidx.camera:camera-lifecycle:$camerax_version"
    // CameraX View class
        implementation "androidx.camera:camera-view:1.0.0-alpha24"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    开启摄像头代码:

    //开启摄像头
    if(allPermissionsGranted()){
    	startCamera(); //start camera if permission has been granted by user
    } else{
    	ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, 1001);
    }
    
    /**
     * 获取摄像头权限
     */
    private final String[] REQUIRED_PERMISSIONS = new String[]{"android.permission.CAMERA", "android.permission.WRITE_EXTERNAL_STORAGE"};
    private boolean allPermissionsGranted() {
        for (String permission : REQUIRED_PERMISSIONS) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }
    
    
    /**
    * 开始预览
    */
    private CameraControl cameraControl;
    private Executor executor = Executors.newSingleThreadExecutor();
    private void startCamera() {
       ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
               ProcessCameraProvider.getInstance(this);
       ((ListenableFuture<?>) cameraProviderFuture).addListener(new Runnable() {
           @SuppressLint("RestrictedApi")
           @Override
           public void run() {
               try {
    
                   ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
                           //.setBackpressureStrategy(ImageAnalysis.STRATEGY_BLOCK_PRODUCER)//阻塞模式
                           //.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888)
                           //.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
                           .build();
                   imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
                       @Override
                       public void analyze(@NonNull @NotNull ImageProxy image) {
    
                           //yuv图像数据转bitmap
                           ImageProxy.PlaneProxy[] planes = image.getPlanes();
                           //cameraX 获取yuv
                           ByteBuffer yBuffer = planes[0].getBuffer();
                           ByteBuffer uBuffer = planes[1].getBuffer();
                           ByteBuffer vBuffer = planes[2].getBuffer();
    
                           int ySize = yBuffer.remaining();
                           int uSize = uBuffer.remaining();
                           int vSize = vBuffer.remaining();
    
                           byte[] nv21 = new byte[ySize + uSize + vSize];
    
                           yBuffer.get(nv21, 0, ySize);
                           vBuffer.get(nv21, ySize, vSize);
                           uBuffer.get(nv21, ySize + vSize, uSize);
                           //获取yuvImage
                           YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
                           //输出流
                           ByteArrayOutputStream out = new ByteArrayOutputStream();
                           //压缩写入out
                           yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()), 50, out);
                           //转数组
                           byte[] imageBytes = out.toByteArray();
                           //生成bitmap
                           Bitmap bmp = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
    
    //                            Bitmap rotateBitmap=null;
    
    //                            Dector(bmp);
    
    //                            Message message=new Message();
    //                            message.what=2;
    //                            message.obj=FPS;
    //                            handler.sendMessage(message);
    
    
                           image.close();
                       }
                   });
    
    
    
                   //将相机的生命周期和activity的生命周期绑定,camerax 会自己释放
                   ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                   Preview preview = new Preview.Builder().build();
                   //创建图片的 capture
                   ImageCapture mImageCapture = new ImageCapture.Builder()
                           .setFlashMode(ImageCapture.FLASH_MODE_OFF)
                           .build();
                   //选择前置摄像头
                   CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
                   // Unbind use cases before rebinding
                   cameraProvider.unbindAll();
    
                   // Bind use cases to camera
                   //参数中如果有mImageCapture才能拍照,否则会报下错
                   //Not bound to a valid Camera [ImageCapture:androidx.camera.core.ImageCapture-bce6e930-b637-40ee-b9b9-
                   Camera camera = cameraProvider.bindToLifecycle(MainActivity.this, cameraSelector, preview, imageAnalysis,mImageCapture);
    
                   cameraControl = camera.getCameraControl();
                   cameraControl.setLinearZoom(0.1f);
                   preview.setSurfaceProvider(pvCameraPreview.getSurfaceProvider());
               } catch (ExecutionException e) {
                   e.printStackTrace();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       }, ContextCompat.getMainExecutor(this));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115

    opengl片源渲染器代码:

    "#extension GL_OES_EGL_image_external : require\n" +
    "precision mediump float;" +
    "uniform samplerExternalOES textureSampler;" +
    "varying vec2 textureCoordinate;" +
    
    "void main(){" +
    "vec4 mycolor=texture2D(textureSampler,vec2(textureCoordinate.x,textureCoordinate.y/2.0));"+
    "vec4 Alpha=texture2D(textureSampler,vec2(textureCoordinate.x,textureCoordinate.y/2.0+0.5));"+
    "float alpha=1.0-(mycolor.r+mycolor.g+mycolor.b)/3.0;"+
    
    "gl_FragColor=vec4(1.0-mycolor.rgb,alpha);" +
    
    "}";
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    5.项目源码

    手机端如果打不开链接,可以使用电脑试一下。
    gitee地址:https://gitee.com/mqwdasddqw/SpecialEffect3

  • 相关阅读:
    Feign的简介及使用
    动态规划-矩阵连乘
    “用友审批,兴业付款”,YonSuite让企业资金调拨更高效
    Python语言:求水仙花数案例讲解
    【c++提高1】单调队列
    JAVA 0基础 转义字符
    【Markdown】 Markdown 操作备忘录
    配置参考一
    (Matalb分类预测)WOA-BP鲸鱼算法优化BP神经网络的多维分类预测
    信息化、数字化时代的变局,商业智能BI未来发展前景如何?
  • 原文地址:https://blog.csdn.net/qq_45087786/article/details/126616030