توجه: این صفحه به پکیج Camera2 اشاره دارد. توصیه میکنیم از CameraX استفاده کنید، مگر اینکه برنامه شما به ویژگیهای خاص و سطح پایین Camera2 نیاز داشته باشد. هر دو CameraX و Camera2 از اندروید 5.0 (سطح API 21) و بالاتر پشتیبانی می کنند.
بسیاری از دستگاه های اندرویدی مدرن دارای دو یا چند دوربین در جلو، پشت یا هر دو طرف دستگاه هستند. هر لنز میتواند قابلیتهای منحصربهفردی مانند عکسبرداری پشت سر هم، کنترل دستی یا ردیابی حرکت داشته باشد. یک برنامه برای واریز چک ممکن است فقط از اولین دوربین پشتی استفاده کند، در حالی که یک برنامه رسانه اجتماعی ممکن است به طور پیش فرض از دوربین جلو استفاده کند، اما به کاربران این امکان را می دهد که بین تمام لنزهای موجود جابجا شوند. همچنین می تواند انتخاب های آنها را به خاطر بسپارد.
این صفحه نحوه فهرست کردن لنزهای دوربین و قابلیتهای آنها را پوشش میدهد تا بتوانید در برنامه خود تصمیم بگیرید که از کدام لنز در یک موقعیت خاص استفاده کنید. قطعه کد زیر لیستی از تمام دوربین ها را بازیابی می کند و روی آنها تکرار می شود:
کاتلین
try { val cameraIdList = cameraManager.cameraIdList // may be empty // iterate over available camera devices for (cameraId in cameraIdList) { val characteristics = cameraManager.getCameraCharacteristics(cameraId) val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING) val cameraCapabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES) // check if the selected camera device supports basic features // ensures backward compatibility with the original Camera API val isBackwardCompatible = cameraCapabilities?.contains( CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false ... } } catch (e: CameraAccessException) { e.message?.let { Log.e(TAG, it) } ... }
جاوا
try { String[] cameraIdList = cameraManager.getCameraIdList(); // may be empty // iterate over available camera devices for (String cameraId : cameraIdList) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); int cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING); int[] cameraCapabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); // check if the selected camera device supports basic features // ensures backward compatibility with the original Camera API boolean isBackwardCompatible = false; for (int capability : cameraCapabilities) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) { isBackwardCompatible = true; break; } } ... } } catch (CameraAccessException e) { Log.e(TAG, e.getMessage()); ... }
متغیر cameraLensFacing
جهتی را که دوربین نسبت به صفحه دستگاه رو به رو می شود، توصیف می کند و یکی از مقادیر زیر را دارد:
-
CameraMetadata.LENS_FACING_FRONT
-
CameraMetadata.LENS_FACING_BACK
-
CameraMetadata.LENS_FACING_EXTERNAL
برای اطلاعات بیشتر در مورد پیکربندی رو به لنز، CameraCharacteristics.LENS_FACING
را ببینید.
متغیر cameraCapabilities
از نمونه کد قبلی حاوی اطلاعاتی در مورد قابلیت های متفرقه است، از جمله اینکه آیا دوربین قادر به تولید فریم های استاندارد به عنوان یک خروجی است (بر خلاف، برای مثال، فقط داده های حسگر عمق). میتوانید ببینید CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
یکی از قابلیتهای فهرستشده دوربین است که بهعنوان یک پرچم در isBackwardCompatible
ذخیره میشود یا خیر.
پیش فرض های معقول را انتخاب کنید
در برنامه خود، احتمالاً می خواهید یک دوربین خاص را به طور پیش فرض باز کنید (اگر در دسترس باشد). به عنوان مثال، یک برنامه سلفی احتمالاً دوربین جلو را باز می کند، در حالی که یک برنامه واقعیت افزوده ممکن است با دوربین پشتی شروع شود. تابع زیر اولین دوربینی را که در جهت مشخصی قرار دارد برمی گرداند:
کاتلین
fun getFirstCameraIdFacing(cameraManager: CameraManager, facing: Int = CameraMetadata.LENS_FACING_BACK): String? { try { // Get list of all compatible cameras val cameraIds = cameraManager.cameraIdList.filter { val characteristics = cameraManager.getCameraCharacteristics(it) val capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES) capabilities?.contains( CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false } // Iterate over the list of cameras and return the first one matching desired // lens-facing configuration cameraIds.forEach { val characteristics = cameraManager.getCameraCharacteristics(it) if (characteristics.get(CameraCharacteristics.LENS_FACING) == facing) { return it } } // If no camera matched desired orientation, return the first one from the list return cameraIds.firstOrNull() } catch (e: CameraAccessException) { e.message?.let { Log.e(TAG, it) } } }
جاوا
public String getFirstCameraIdFacing(CameraManager cameraManager, @Nullable Integer facing) { if (facing == null) facing = CameraMetadata.LENS_FACING_BACK; String cameraId = null; try { // Get a list of all compatible cameras String[] cameraIdList = cameraManager.getCameraIdList(); // Iterate over the list of cameras and return the first one matching desired // lens-facing configuration and backward compatibility for (String id : cameraIdList) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); for (int capability : capabilities) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE && characteristics.get(CameraCharacteristics.LENS_FACING).equals(facing)) { cameraId = id; break; } } } // If no camera matches the desired orientation, return the first one from the list cameraId = cameraIdList[0]; } catch (CameraAccessException e) { Log.e(TAG, "getFirstCameraIdFacing: " + e.getMessage()); } return cameraId; }
فعال کردن سوئیچ دوربین
بسیاری از برنامه های دوربین به کاربران این امکان را می دهند که بین دوربین ها جابجا شوند:
بسیاری از دستگاهها دارای چندین دوربین هستند که در یک جهت قرار دارند. برخی حتی دوربین های USB خارجی دارند. برای ارائه رابط کاربری به کاربران که به آنها امکان جابهجایی بین دوربینهای مختلف روبرو را میدهد، اولین دوربین موجود را برای هر پیکربندی احتمالی رو به لنز انتخاب کنید.
اگرچه هیچ منطق جهانی برای انتخاب دوربین بعدی وجود ندارد، کد زیر برای بیشتر موارد استفاده کار می کند:
کاتلین
fun filterCompatibleCameras(cameraIds: Array<String>, cameraManager: CameraManager): List<String> { return cameraIds.filter { val characteristics = cameraManager.getCameraCharacteristics(it) characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)?.contains( CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false } } fun filterCameraIdsFacing(cameraIds: List<String>, cameraManager: CameraManager, facing: Int): List<String> { return cameraIds.filter { val characteristics = cameraManager.getCameraCharacteristics(it) characteristics.get(CameraCharacteristics.LENS_FACING) == facing } } fun getNextCameraId(cameraManager: CameraManager, currCameraId: String? = null): String? { // Get all front, back and external cameras in 3 separate lists val cameraIds = filterCompatibleCameras(cameraManager.cameraIdList, cameraManager) val backCameras = filterCameraIdsFacing( cameraIds, cameraManager, CameraMetadata.LENS_FACING_BACK) val frontCameras = filterCameraIdsFacing( cameraIds, cameraManager, CameraMetadata.LENS_FACING_FRONT) val externalCameras = filterCameraIdsFacing( cameraIds, cameraManager, CameraMetadata.LENS_FACING_EXTERNAL) // The recommended order of iteration is: all external, first back, first front val allCameras = (externalCameras + listOf( backCameras.firstOrNull(), frontCameras.firstOrNull())).filterNotNull() // Get the index of the currently selected camera in the list val cameraIndex = allCameras.indexOf(currCameraId) // The selected camera may not be in the list, for example it could be an // external camera that has been removed by the user return if (cameraIndex == -1) { // Return the first camera from the list allCameras.getOrNull(0) } else { // Return the next camera from the list, wrap around if necessary allCameras.getOrNull((cameraIndex + 1) % allCameras.size) } }
جاوا
public List<String> filterCompatibleCameras(CameraManager cameraManager, String[] cameraIds) { final List<String> compatibleCameras = new ArrayList<>(); try { for (String id : cameraIds) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); for (int capability : capabilities) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) { compatibleCameras.add(id); } } } } catch (CameraAccessException e) { Log.e(TAG, "filterCompatibleCameras: " + e.getMessage()); } return compatibleCameras; } public List<String> filterCameraIdsFacing(CameraManager cameraManager, List<String> cameraIds, int lensFacing) { final List<String> compatibleCameras = new ArrayList<>(); try { for (String id : cameraIds) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); if (characteristics.get(CameraCharacteristics.LENS_FACING) == lensFacing) { compatibleCameras.add(id); } } } catch (CameraAccessException e) { Log.e(TAG, "filterCameraIdsFacing: " + e.getMessage()); } return compatibleCameras; } public String getNextCameraId(CameraManager cameraManager, @Nullable String currentCameraId) { String nextCameraId = null; try { // Get all front, back, and external cameras in 3 separate lists List<String> compatibleCameraIds = filterCompatibleCameras(cameraManager, cameraManager.getCameraIdList()); List<String> backCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_BACK); List<String> frontCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_FRONT); List<String>externalCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_EXTERNAL); // The recommended order of iteration is: all external, first back, first front List<String> allCameras = new ArrayList<>(externalCameras); if (!backCameras.isEmpty()) allCameras.add(backCameras.get(0)); if (!frontCameras.isEmpty()) allCameras.add(frontCameras.get(0)); // Get the index of the currently selected camera in the list int cameraIndex = allCameras.indexOf(currentCameraId); // The selected camera may not be in the list, for example it could be an // external camera that has been removed by the user if (cameraIndex == -1) { // Return the first camera from the list nextCameraId = !allCameras.isEmpty() ? allCameras.get(0) : null; else { if (!allCameras.isEmpty()) { // Return the next camera from the list, wrap around if necessary nextCameraId = allCameras.get((cameraIndex + 1) % allCameras.size()); } } } catch (CameraAccessException e) { Log.e(TAG, "getNextCameraId: " + e.getMessage()); } return nextCameraId; }
این کد برای مجموعه بزرگی از دستگاه ها با پیکربندی های مختلف کار می کند. برای اطلاعات بیشتر در مورد حسابداری موارد لبه، CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
را ببینید.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA.
برنامه های سازگار ایجاد کنید
برای برنامههایی که هنوز از Camera API منسوخ شده استفاده میکنند، تعداد دوربینهایی که Camera.getNumberOfCameras()
برمیگرداند به اجرای OEM بستگی دارد. اگر یک دوربین چندگانه منطقی در سیستم وجود داشته باشد، برای حفظ سازگاری برنامه به عقب، این روش تنها یک دوربین را برای هر دوربین منطقی و گروه دوربین های فیزیکی زیربنایی نشان می دهد. از Camera2 API برای دیدن همه دوربین ها استفاده کنید.
برای اطلاعات پس زمینه بیشتر در مورد جهت گیری دوربین، Camera.CameraInfo.orientation
را ببینید.
به طور کلی، از Camera.getCameraInfo()
API برای پرس و جوی همه orientation
دوربین استفاده کنید و تنها یک دوربین را برای هر جهت در دسترس کاربرانی که در حال جابجایی بین دوربین ها هستند، قرار دهید.
انواع دستگاه ها را در خود جای دهد
تصور نکنید که برنامه شما همیشه روی یک دستگاه دستی با یک یا دو دوربین اجرا می شود. در عوض، مناسب ترین دوربین ها را برای برنامه انتخاب کنید. اگر به دوربین خاصی نیاز ندارید، اولین دوربینی را که در جهت دلخواه قرار دارد انتخاب کنید. اگر یک دوربین خارجی متصل است، ممکن است فرض کنید که کاربر آن را به عنوان پیش فرض ترجیح می دهد.