android|camera特效app(安卓)


文章目录

  • 1.前言:
  • 2. 效果预览:
  • 3.特效视频制作及上传
    • 3.1特效视频格式
    • 3.2视频上传到网站
    • 3.3 发布博客
  • 4.camera使用
  • 5.项目源码

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


app下载地址:https://www.pgyer.com/T6he
3.特效视频制作及上传 3.1特效视频格式 特效视频的制作也很简单,视频格式如下所示:
android|camera特效app(安卓)
文章图片

视频的上半部分为我们想要的特效视频,下半部分为透明度,其值越接近255,则表示越不透明。在使用opengles渲染视频的时候,只需要把下半部分的像素值作为其透明度即可。
3.2视频上传到网站 关于视频如何上传到好看视频网站,已经如何抓包获取视频播放地址,我在之前的一篇博客上面已经详细的说明了,如果不明白可前往查看。
3.3 发布博客 上传完视频拿到播放地址以后,只需要发布一篇博客,并将视频的播放地址都发布到该博客上面即可。博客内容如下所示:
android|camera特效app(安卓)
文章图片

为了app自动获取特效的名称,需要在播放地址后面加上特效的名字,这样app特效的下拉框中就会自动填写这些特效名字。
4.camera使用 使用camerax来显示摄像头画面。camerax相比于camera2更加方便,兼容性更广。
使用camerax首先需要添加摄像头权限

添加相关依赖:
//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"

开启摄像头代码:
//开启摄像头 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 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)); }

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); " +"}";

5.项目源码 【android|camera特效app(安卓)】手机端如果打不开链接,可以使用电脑试一下。
gitee地址:https://gitee.com/mqwdasddqw/SpecialEffect3

    推荐阅读