{"id":1640,"date":"2023-03-25T21:40:14","date_gmt":"2023-03-25T13:40:14","guid":{"rendered":"https:\/\/www.appblog.cn\/?p=1640"},"modified":"2023-04-23T22:00:09","modified_gmt":"2023-04-23T14:00:09","slug":"android-jetpack-architecture-components-camerax-video-recording","status":"publish","type":"post","link":"https:\/\/www.appblog.cn\/index.php\/2023\/03\/25\/android-jetpack-architecture-components-camerax-video-recording\/","title":{"rendered":"Android Jetpack\u67b6\u6784\u7ec4\u4ef6\uff08\u4e94\uff09CameraX\u89c6\u9891\u5f55\u5236"},"content":{"rendered":"<h2>\u6dfb\u52a0Gradle\u4f9d\u8d56<\/h2>\n<pre><code class=\"language-java\">\/\/ Use the most recent version of CameraX, currently that is alpha04\ndef camerax_core_version = &quot;1.0.0-beta03&quot;\ndef camerax_version = &quot;1.0.0-alpha10&quot;\nimplementation &quot;androidx.camera:camera-core:${camerax_core_version}&quot;\nimplementation &quot;androidx.camera:camera-camera2:${camerax_core_version}&quot;\n\/\/ If you want to use the CameraX View class\nimplementation &quot;androidx.camera:camera-view:${camerax_version}&quot;\n\/\/ If you want to use the CameraX Extensions library\nimplementation &quot;androidx.camera:camera-extensions:${camerax_version}&quot;\n\/\/ If you want to use the CameraX Lifecycle library\nimplementation &quot;androidx.camera:camera-lifecycle:${camerax_version}&quot;\n\n\/\/\u89c6\u9891\u64ad\u653e\u7ec4\u4ef6\nimplementation &#039;com.google.android.exoplayer:exoplayer-core:2.10.4&#039;\nimplementation &#039;com.google.android.exoplayer:exoplayer-dash:2.10.4&#039;\nimplementation &#039;com.google.android.exoplayer:exoplayer-ui:2.10.4&#039;\n\nimplementation &#039;com.github.chrisbanes:PhotoView:2.3.0&#039;\nimplementation &#039;com.github.bumptech.glide:glide:4.11.0&#039;\nannotationProcessor &#039;com.github.bumptech.glide:compiler:4.11.0&#039;<\/code><\/pre>\n<p><!-- more --><\/p>\n<h2>\u6743\u9650\u58f0\u660e<\/h2>\n<pre><code class=\"language-xml\">&lt;uses-permission android:name=&quot;android.permission.CAMERA&quot; \/&gt;\n&lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot; \/&gt;\n&lt;uses-permission android:name=&quot;android.permission.RECORD_AUDIO&quot; \/&gt;<\/code><\/pre>\n<pre><code class=\"language-java\">private static final String[] PERMISSIONS = new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO};\nprivate ArrayList&lt;String&gt; deniedPermission = new ArrayList&lt;&gt;();\n\n@Override\nprotected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    ...\n    ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_CODE);\n    ...\n}\n\n@Override\npublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n    super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n    if (requestCode == PERMISSION_CODE) {\n        deniedPermission.clear();\n        for (int i = 0; i &lt; permissions.length; i++) {\n            String permission = permissions[i];\n            int result = grantResults[i];\n            if (result != PackageManager.PERMISSION_GRANTED) {\n                deniedPermission.add(permission);\n            }\n        }\n\n        if (deniedPermission.isEmpty()) {\n            \/\/Toast.makeText(CaptureActivity.this, &quot;all permission allowed&quot;, Toast.LENGTH_SHORT).show();\n            initCamera();\n        } else {\n            new AlertDialog.Builder(this)\n                    .setMessage(getString(R.string.capture_permission_message))\n                    .setNegativeButton(getString(R.string.capture_permission_no), new DialogInterface.OnClickListener() {\n                        @Override\n                        public void onClick(DialogInterface dialog, int which) {\n                            dialog.dismiss();\n                            CameraXCaptureActivity.this.finish();\n                        }\n                    })\n                    .setPositiveButton(getString(R.string.capture_permission_ok), new DialogInterface.OnClickListener() {\n                        @Override\n                        public void onClick(DialogInterface dialog, int which) {\n                            String[] denied = new String[deniedPermission.size()];\n                            ActivityCompat.requestPermissions(CameraXCaptureActivity.this, deniedPermission.toArray(denied), PERMISSION_CODE);\n                        }\n                    }).create().show();\n        }\n    }\n}<\/code><\/pre>\n<h2>\u914d\u7f6eCameraX<\/h2>\n<pre><code class=\"language-java\">private void initCamera() {\n\n    executor = ContextCompat.getMainExecutor(this);\n\n    cameraProviderFuture = ProcessCameraProvider.getInstance(this);\n    cameraProviderFuture.addListener(() -&gt; {\n        try {\n            ProcessCameraProvider cameraProvider = cameraProviderFuture.get();\n            bindPreview(cameraProvider);\n        } catch (ExecutionException | InterruptedException e) {\n            \/\/ No errors need to be handled for this Future.\n            \/\/ This should never be reached.\n        }\n    }, executor);\n}<\/code><\/pre>\n<pre><code class=\"language-java\">@SuppressLint(&quot;RestrictedApi&quot;)\nprivate void bindPreview(ProcessCameraProvider cameraProvider) {\n    CameraX.unbindAll();\n    cameraSelector = new CameraSelector.Builder()\n            .requireLensFacing(CameraSelector.LENS_FACING_BACK)\n            .build();\n    Preview preview = new Preview.Builder()\n            .setCameraSelector(cameraSelector) \/\/\u524d\u540e\u6444\u50cf\u5934\n            .setTargetAspectRatio(AspectRatio.RATIO_16_9) \/\/\u5bbd\u9ad8\u6bd4\n            .setTargetRotation(rotation) \/\/\u65cb\u8f6c\u89d2\u5ea6\n            \/\/.setTargetResolution(resolution) \/\/\u5206\u8fa8\u7387\n            .build();\n\n    imageCapture = new ImageCapture.Builder()\n            .setCameraSelector(cameraSelector)\n            .setTargetAspectRatio(AspectRatio.RATIO_16_9)\n            .setTargetRotation(rotation)\n            \/\/.setTargetResolution(resolution)\n            .build();\n\n    videoCapture = new VideoCaptureConfig.Builder()\n            .setCameraSelector(cameraSelector)\n            .setTargetAspectRatio(AspectRatio.RATIO_16_9)\n            .setTargetRotation(rotation)\n            \/\/.setTargetResolution(resolution)\n            \/\/\u89c6\u9891\u5e27\u7387\n            .setVideoFrameRate(25)\n            \/\/bit\u7387\n            .setBitRate(10440).build();\n\n    \/\/Caused by: java.lang.IllegalArgumentException: No supported surface combination is found for camera device - Id : 0.  May be attempting to bind too many use cases.\n    \/\/cameraSelector\u4e0evideoCapture\u4e0d\u80fd\u540c\u65f6\u7ed1\u5b9a\n    \/\/Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, imageCapture, videoCapture, preview);\n\n    \/\/Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, imageCapture, preview);\n    Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, videoCapture, preview);\n\n    CameraInfo cameraInfo = camera.getCameraInfo();\n\n    preview.setSurfaceProvider(mBinding.previewView.createSurfaceProvider(cameraInfo));\n}<\/code><\/pre>\n<p>\u82e5\u62a5\u9519\uff1a<code>IllegalArgumentException: No supported surface combination is found<\/code>\uff0c\u5982\u4e0b\uff1a<\/p>\n<pre><code>java.lang.IllegalArgumentException: No supported surface combination is found for camera device - Id : 0.  May be attempting to bind too many use cases.\n    at androidx.camera.camera2.impl.Camera2DeviceSurfaceManager.getSuggestedResolutions(Camera2DeviceSurfaceManager.java:176)<\/code><\/pre>\n<p>\u89e3\u51b3\uff1acameraSelector\u4e0evideoCapture\u4e0d\u80fd\u540c\u65f6\u7ed1\u5b9a<\/p>\n<p>\u53c2\u8003\uff1a<a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/github.com\/android\/camera-samples\/issues\/38\">https:\/\/github.com\/android\/camera-samples\/issues\/38<\/a><br \/>\n\u53c2\u8003\uff1a<a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/stackoverflow.com\/questions\/57126429\/an-error-occurred-by-camerax-bindtolifecycle\">https:\/\/stackoverflow.com\/questions\/57126429\/an-error-occurred-by-camerax-bindtolifecycle<\/a><\/p>\n<h2>\u62cd\u7167\u548c\u5f55\u50cf<\/h2>\n<pre><code class=\"language-java\">@Override\nprotected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    mBinding = DataBindingUtil.setContentView(this, R.layout.activity_camerax_capture);\n\n    mBinding.recordView.setOnRecordListener(new RecordView.onRecordListener() {\n\n        @Override\n        public void onClick() {\n            takingPicture = true;\n            File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), System.currentTimeMillis() + &quot;.jpeg&quot;);\n            ImageCapture.OutputFileOptions outputFileOptions =\n                    new ImageCapture.OutputFileOptions.Builder(file).build();\n            mBinding.captureTips.setVisibility(View.INVISIBLE);\n            imageCapture.takePicture(outputFileOptions, executor, new ImageCapture.OnImageSavedCallback() {\n                @Override\n                public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {\n                    String msg = &quot;\u56fe\u7247\u4fdd\u5b58\u6210\u529f: &quot; + file.getAbsolutePath();\n                    Toast.makeText(CameraXCaptureActivity.this, msg, Toast.LENGTH_SHORT).show();\n                    Log.i(CommonConstants.TAG, msg);\n                    onFileSaved(file);\n                }\n\n                @Override\n                public void onError(@NonNull ImageCaptureException exception) {\n                    String msg = &quot;\u56fe\u7247\u4fdd\u5b58\u5931\u8d25: &quot; + exception.getMessage();\n                    showErrorToast(msg);\n                    Log.e(CommonConstants.TAG, msg);\n                }\n            });\n        }\n\n        @SuppressLint(&quot;RestrictedApi&quot;)\n        @Override\n        public void onLongClick() {\n            takingPicture = false;\n            File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), System.currentTimeMillis() + &quot;.mp4&quot;);\n            videoCapture.startRecording(file, executor, new VideoCapture.OnVideoSavedCallback() {\n                @Override\n                public void onVideoSaved(@NonNull File file) {\n                    onFileSaved(file);\n                }\n\n                @Override\n                public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {\n                    String msg = &quot;\u56fe\u7247\u4fdd\u5b58\u5931\u8d25: &quot; + message;\n                    showErrorToast(msg);\n                    Log.e(CommonConstants.TAG, msg);\n                }\n            });\n        }\n\n        @SuppressLint(&quot;RestrictedApi&quot;)\n        @Override\n        public void onFinish() {\n            videoCapture.stopRecording();\n        }\n    });\n\n}<\/code><\/pre>\n<h2>\u4fdd\u5b58\u548c\u9884\u89c8<\/h2>\n<pre><code class=\"language-java\">private void onFileSaved(File file) {\n    outputFilePath = file.getAbsolutePath();\n    String mimeType = takingPicture ? &quot;image\/jpeg&quot; : &quot;video\/mp4&quot;;\n    MediaScannerConnection.scanFile(this, new String[]{outputFilePath}, new String[]{mimeType}, null);\n    CameraXPreviewActivity.startActivityForResult(this, outputFilePath, !takingPicture, &quot;\u5b8c\u6210&quot;);\n}<\/code><\/pre>\n<h2>\u9884\u89c8\u7167\u7247\u548c\u5f55\u50cf<\/h2>\n<pre><code class=\"language-java\">private void previewImage(String previewUrl) {\n    mPreviewBinding.photoView.setVisibility(View.VISIBLE);\n    GlideApp.with(this).load(previewUrl).into(mPreviewBinding.photoView);\n}\n\nprivate void previewVideo(String previewUrl) {\n    mPreviewBinding.playerView.setVisibility(View.VISIBLE);\n    player = ExoPlayerFactory.newSimpleInstance(this, new DefaultRenderersFactory(this), new DefaultTrackSelector(), new DefaultLoadControl());\n\n    Uri uri = null;\n    File file = new File(previewUrl);\n    if (file.exists()) {\n        DataSpec dataSpec = new DataSpec(Uri.fromFile(file));\n        FileDataSource fileDataSource = new FileDataSource();\n        try {\n            fileDataSource.open(dataSpec);\n            uri = fileDataSource.getUri();\n        } catch (FileDataSource.FileDataSourceException e) {\n            e.printStackTrace();\n        }\n    } else {\n        uri = Uri.parse(previewUrl);\n    }\n\n    ProgressiveMediaSource.Factory factory = new ProgressiveMediaSource.Factory(\n            new DefaultDataSourceFactory(this, Util.getUserAgent(this, getPackageName())));\n    ProgressiveMediaSource mediaSource = factory.createMediaSource(uri);\n    player.prepare(mediaSource);\n    player.setPlayWhenReady(true);\n    mPreviewBinding.playerView.setPlayer(player);\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\u6dfb\u52a0Gradle\u4f9d\u8d56 \/\/ Use the most recent version of CameraX, c [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[311],"tags":[411,410],"class_list":["post-1640","post","type-post","status-publish","format-standard","hentry","category-android-advance","tag-camerax","tag-jetpack"],"_links":{"self":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/posts\/1640","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/comments?post=1640"}],"version-history":[{"count":0,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/posts\/1640\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/media?parent=1640"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/categories?post=1640"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/tags?post=1640"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}