Çoklu kamera API'sı

Not: Bu sayfa Kamera2 paketiyle ilgilidir. Uygulamanız için Kamera2'nin belirli, alt düzey özellikleri gerekmiyorsa, KameraX'i kullanmanızı öneririz. Hem CameraX hem de Camera2, Android 5.0 (API düzeyi 21) ve sonraki sürümleri destekler.

Çoklu kamera, Android 9 (API düzeyi 28) sürümünde kullanıma sunulmuştur. Yayınlandığından beri cihaz piyasasına API'yi destekleyen ek özellikler getirmiştir. Çok kameralı birçok kullanım alanı belirli bir donanım yapılandırmasıyla sıkı sıkıya bağlantılı. Başka bir deyişle Tüm kullanım alanları her cihazla uyumludur,  bu da birden fazla kameranın Oyun Özelliği için iyi bir adaya sahip. Yayınlama.

Bazı tipik kullanım alanları şunlardır:

  • Yakınlaştırma: Kırpma bölgesine veya istenen odak noktasına bağlı olarak kameralar arasında geçiş yapma seçeceğiz.
  • Derinlik: Derinlik haritası oluşturmak için birden fazla kamera kullanma.
  • Bokeh: DSLR benzeri dar bir görünümü simüle etmek için tahmin edilen derinlik bilgilerinin kullanılması odak aralığı.

Mantıksal ve fiziksel kameralar arasındaki fark

Çoklu kamera API'sini anlamak, mantıksal ve fiziksel kameralar. Referans olarak, üç özellik olan bir cihaz düşünün: kameralar. Bu örnekte, arkadaki üç kameranın her biri fiziksel bir kamera olarak değerlendirilir. Mantıksal kamera, iki veya daha fazla kameradan oluşan bir gruptur çok daha kolay oluyor. Mantıksal kamera, alttaki fiziksel kameraların birinden gelen bir akış olabilir. temeldeki birden fazla fiziksel kameradan gelen karma akış olanak tanır. Her iki durumda da akış kamera Donanımı tarafından işlenir. Soyutlama Katmanı (HAL).

Birçok telefon üreticisi, genellikle birinci taraf kamera uygulamaları yüklü olarak gelir. Donanımın tüm özelliklerini kullanmak için gizli API'ler kullanabilir veya gizli API'lerden özel muamele görebilirler. diğer uygulamaların erişemediği sürücü uygulamasıdır. Biraz mantıksal kameralar kavramını uygulamaya koyan cihazlar, farklı fiziksel kameralardan kareler alır, ancak yalnızca belirli ayrıcalıklı kameralara izin verir. Çoğu zaman fiziksel kameralardan yalnızca biri görüntüye maruz kalır. bahsedeceğim. Android 9'dan önceki üçüncü taraf geliştiriciler için durum: aşağıdaki şemada gösterilmektedir:

Şekil 1. Kamera özellikleri genellikle yalnızca gizli uygulamalar

Android 9'dan itibaren Android uygulamalarında gizli API'lere artık izin verilmemektedir. Çerçeveye birden fazla kamera desteğinin dahil edilmesiyle birlikte, Android en iyi telefon üreticilerinin mantığa dayalı bir kamera ya da kameralar oluşturur. Bu dönüşüm üçüncü taraf geliştiriciler, Android 9 ve sonraki sürümleri çalıştıran cihazlarda daha yüksek:

Şekil 2. Geliştiricilerin tüm kamera cihazlarına tam erişimi Android 9'dan itibaren

Mantıksal kameranın sağladıkları, tamamen OEM uygulamasına bağlıdır bir görüntü kalitesidir. Örneğin, Pixel 3 gibi bir cihaz mantıksal konumdaki fiziksel kameralardan birini seçecek şekilde istenen odak uzaklığı ve kırpma bölgesi.

Çok kameralı API

Yeni API, aşağıdaki yeni sabit değerleri, sınıfları ve yöntemleri ekler:

Android Uyumluluk Tanımlama Belgesi'nde (CDD) yapılan değişiklikler nedeniyle çoklu kamera API'sini kullanmak, geliştiricilerin belirli beklentilerini de beraberinde getiriyor. Cihazlar Android 9'dan önce de çift kamera bulunuyordu ancak birden fazla kamera açılıyor hem de deneme yanılma yöntemini kullanıyordu. Android 9 ve sonraki sürümlerde çok kameralı bir çift fiziksel aktivitenin açılabileceğini belirten bir dizi Bunlar aynı mantıksal kameranın parçası olan kameralar.

Çoğu durumda, Android 9 ve sonraki sürümleri çalıştıran cihazlar tüm fiziksel kameralar (kızılötesi gibi daha seyrek görülen sensör türleri hariç) kullanımı kolay, mantıklı bir kamera. En iyi performans gösteren akış kombinasyonları için çalışacağı garanti edildiğinde, mantıksal bir kameraya ait bir akış, temel fiziksel kameralardan gelen iki akış bulunur.

Aynı anda birden fazla yayın

Birden fazla kamera akışını aynı anda kullanma , tek bir kamerada aynı anda birden çok yayın kullanmaya ilişkin kuralları kapsar. Önemli bir eklemeyle birlikte aynı kurallar birden fazla kamera için geçerli olur. CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA Mantıksal bir YUV_420_888 veya ham akışın iki gerçekleşebilir. Yani, YUV veya RAW türündeki her akış aynı tür ve büyüklükte iki akıştan oluşur. Şu videoya ait kamera yayınıyla başlayabilirsiniz: Tek kameralı cihazlar için aşağıdaki garantili yapılandırma:

  • 1. akış: YUV türü, mantıksal kameradan MAXIMUM boyut (id = 0)

Ardından, çoklu kamera desteği sunan bir cihaz ile oturum oluşturmanıza olanak tanır. bu mantıksal YUV akışını iki fiziksel akışla değiştirir:

  • 1. akış: YUV türü, fiziksel kameradan MAXIMUM boyut id = 1
  • 2. akış: YUV türü, fiziksel kameradan MAXIMUM boyut id = 2

Bir YUV veya RAW akışını yalnızca aşağıdaki durumlarda iki eşdeğer akışla değiştirebilirsiniz: bu iki kamera mantıksal bir kamera gruplandırmasının parçasıdır. Bu gruplandırma CameraCharacteristics.getPhysicalCameraIds().

Çerçevenin sağladığı garantiler, sözleşmenin uygulanması için gereken aynı anda birden fazla fiziksel kameradan kare alabilir. Ek akışlar çoğu cihazda desteklenir. Hatta bazen, birden fazla fiziksel ayrı ayrı çalışır. Daha kesin bir ifadeyle, bunu yaparken cihaz başına test ve ince ayar yapılmasını gerektirir. deneme yanılma yöntemidir.

Birden çok fiziksel kamerayla oturum oluşturma

Çok kameralı bir cihazda fiziksel kameralar kullanırken tek bir CameraDevice (mantıksal kamera) ve tek bir kamerada bu kamerayla etkileşimde bulunun kabul edilir. API'yi kullanarak tek oturum oluşturma Önceki fiyatı: CameraDevice.createCaptureSession(SessionConfiguration config) API düzeyi 28'de eklenmiştir. Oturum yapılandırmasında bir dizi çıkış vardır. Her biri bir dizi çıkış hedefine sahip yapılandırma ve isteğe bağlı olarak fiziksel kamera kimliğini girin.

Şekil 3. SessionConfiguration ve ExitConfiguration modeli

Yakalama isteklerinin ilişkilendirilmiş bir çıkış hedefi vardır. Çerçeve isteklerin hangi fiziksel (veya mantıksal) kameraya gönderileceğini belirler hedefin ekli olduğunu görebilirsiniz. Çıkış hedefi fiziksel yapılandırmayla birlikte çıkış yapılandırması olarak gönderilen çıkış hedefleri fiziksel kameranın isteği alıp işlediğini gösterir.

Bir çift fiziksel kamera kullanma

Çoklu kamera için kamera API'lerine ek bir özellik de mantıksal kameralar ve bunların arkasındaki fiziksel kameraları bulur. Hedeflerinize göre bir kullanabileceğiniz potansiyel fiziksel kamera çiftlerini tanımlamaya yardımcı olan bir işlev mantıksal kamera akışlarından birini değiştirin:

Kotlin

/**
     * Helper class used to encapsulate a logical camera and two underlying
     * physical cameras
     */
    data class DualCamera(val logicalId: String, val physicalId1: String, val physicalId2: String)

    fun findDualCameras(manager: CameraManager, facing: Int? = null): List {
        val dualCameras = MutableList()

        // Iterate over all the available camera characteristics
        manager.cameraIdList.map {
            Pair(manager.getCameraCharacteristics(it), it)
        }.filter {
            // Filter by cameras facing the requested direction
            facing == null || it.first.get(CameraCharacteristics.LENS_FACING) == facing
        }.filter {
            // Filter by logical cameras
            // CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA requires API >= 28
            it.first.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)!!.contains(
                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)
        }.forEach {
            // All possible pairs from the list of physical cameras are valid results
            // NOTE: There could be N physical cameras as part of a logical camera grouping
            // getPhysicalCameraIds() requires API >= 28
            val physicalCameras = it.first.physicalCameraIds.toTypedArray()
            for (idx1 in 0 until physicalCameras.size) {
                for (idx2 in (idx1 + 1) until physicalCameras.size) {
                    dualCameras.add(DualCamera(
                        it.second, physicalCameras[idx1], physicalCameras[idx2]))
                }
            }
        }

        return dualCameras
    }

Java

/**
     * Helper class used to encapsulate a logical camera and two underlying
     * physical cameras
     */
    final class DualCamera {
        final String logicalId;
        final String physicalId1;
        final String physicalId2;

        DualCamera(String logicalId, String physicalId1, String physicalId2) {
            this.logicalId = logicalId;
            this.physicalId1 = physicalId1;
            this.physicalId2 = physicalId2;
        }
    }
    List findDualCameras(CameraManager manager, Integer facing) {
        List dualCameras = new ArrayList<>();

        List cameraIdList;
        try {
            cameraIdList = Arrays.asList(manager.getCameraIdList());
        } catch (CameraAccessException e) {
            e.printStackTrace();
            cameraIdList = new ArrayList<>();
        }

        // Iterate over all the available camera characteristics
        cameraIdList.stream()
                .map(id -> {
                    try {
                        CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
                        return new Pair<>(characteristics, id);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                        return null;
                    }
                })
                .filter(pair -> {
                    // Filter by cameras facing the requested direction
                    return (pair != null) &&
                            (facing == null || pair.first.get(CameraCharacteristics.LENS_FACING).equals(facing));
                })
                .filter(pair -> {
                    // Filter by logical cameras
                    // CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA requires API >= 28
                    IntPredicate logicalMultiCameraPred =
                            arg -> arg == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA;
                    return Arrays.stream(pair.first.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES))
                            .anyMatch(logicalMultiCameraPred);
                })
                .forEach(pair -> {
                    // All possible pairs from the list of physical cameras are valid results
                    // NOTE: There could be N physical cameras as part of a logical camera grouping
                    // getPhysicalCameraIds() requires API >= 28
                    String[] physicalCameras = pair.first.getPhysicalCameraIds().toArray(new String[0]);
                    for (int idx1 = 0; idx1 < physicalCameras.length; idx1++) {
                        for (int idx2 = idx1 + 1; idx2 < physicalCameras.length; idx2++) {
                            dualCameras.add(
                                    new DualCamera(pair.second, physicalCameras[idx1], physicalCameras[idx2]));
                        }
                    }
                });
return dualCameras;
}

Fiziksel kameraların durumu, mantıksal kamera tarafından kontrol edilir. Alıcı: "çift kamera"yı açın, fiziksel makineye karşılık gelen mantıksal kamerayı kameralar:

Kotlin

fun openDualCamera(cameraManager: CameraManager,
                       dualCamera: DualCamera,
        // AsyncTask is deprecated beginning API 30
                       executor: Executor = AsyncTask.SERIAL_EXECUTOR,
                       callback: (CameraDevice) -> Unit) {

        // openCamera() requires API >= 28
        cameraManager.openCamera(
            dualCamera.logicalId, executor, object : CameraDevice.StateCallback() {
                override fun onOpened(device: CameraDevice) = callback(device)
                // Omitting for brevity...
                override fun onError(device: CameraDevice, error: Int) = onDisconnected(device)
                override fun onDisconnected(device: CameraDevice) = device.close()
            })
    }

Java

void openDualCamera(CameraManager cameraManager,
                        DualCamera dualCamera,
                        Executor executor,
                        CameraDeviceCallback cameraDeviceCallback
    ) {

        // openCamera() requires API >= 28
        cameraManager.openCamera(dualCamera.logicalId, executor, new CameraDevice.StateCallback() {
            @Override
            public void onOpened(@NonNull CameraDevice cameraDevice) {
               cameraDeviceCallback.callback(cameraDevice);
            }

            @Override
            public void onDisconnected(@NonNull CameraDevice cameraDevice) {
                cameraDevice.close();
            }

            @Override
            public void onError(@NonNull CameraDevice cameraDevice, int i) {
                onDisconnected(cameraDevice);
            }
        });
    }

Hangi kameranın açılacağını seçmenin dışındaki işlemler, kamera kullanıyor olması. Yeni oturum yapılandırma API'sı, çerçeveye belirli hedeflerin Belirli fiziksel kamera kimlikleri:

Kotlin

/**
 * Helper type definition that encapsulates 3 sets of output targets:
 *
 *   1. Logical camera
 *   2. First physical camera
 *   3. Second physical camera
 */
typealias DualCameraOutputs =
        Triple<MutableList?, MutableList?, MutableList?>

fun createDualCameraSession(cameraManager: CameraManager,
                            dualCamera: DualCamera,
                            targets: DualCameraOutputs,
                            // AsyncTask is deprecated beginning API 30
                            executor: Executor = AsyncTask.SERIAL_EXECUTOR,
                            callback: (CameraCaptureSession) -> Unit) {

    // Create 3 sets of output configurations: one for the logical camera, and
    // one for each of the physical cameras.
    val outputConfigsLogical = targets.first?.map { OutputConfiguration(it) }
    val outputConfigsPhysical1 = targets.second?.map {
        OutputConfiguration(it).apply { setPhysicalCameraId(dualCamera.physicalId1) } }
    val outputConfigsPhysical2 = targets.third?.map {
        OutputConfiguration(it).apply { setPhysicalCameraId(dualCamera.physicalId2) } }

    // Put all the output configurations into a single flat array
    val outputConfigsAll = arrayOf(
        outputConfigsLogical, outputConfigsPhysical1, outputConfigsPhysical2)
        .filterNotNull().flatMap { it }

    // Instantiate a session configuration that can be used to create a session
    val sessionConfiguration = SessionConfiguration(
        SessionConfiguration.SESSION_REGULAR,
        outputConfigsAll, executor, object : CameraCaptureSession.StateCallback() {
            override fun onConfigured(session: CameraCaptureSession) = callback(session)
            // Omitting for brevity...
            override fun onConfigureFailed(session: CameraCaptureSession) = session.device.close()
        })

    // Open the logical camera using the previously defined function
    openDualCamera(cameraManager, dualCamera, executor = executor) {

        // Finally create the session and return via callback
        it.createCaptureSession(sessionConfiguration)
    }
}

Java

/**
 * Helper class definition that encapsulates 3 sets of output targets:
 * 

* 1. Logical camera * 2. First physical camera * 3. Second physical camera */ final class DualCameraOutputs { private final List logicalCamera; private final List firstPhysicalCamera; private final List secondPhysicalCamera; public DualCameraOutputs(List logicalCamera, List firstPhysicalCamera, List third) { this.logicalCamera = logicalCamera; this.firstPhysicalCamera = firstPhysicalCamera; this.secondPhysicalCamera = third; } public List getLogicalCamera() { return logicalCamera; } public List getFirstPhysicalCamera() { return firstPhysicalCamera; } public List getSecondPhysicalCamera() { return secondPhysicalCamera; } } interface CameraCaptureSessionCallback { void callback(CameraCaptureSession cameraCaptureSession); } void createDualCameraSession(CameraManager cameraManager, DualCamera dualCamera, DualCameraOutputs targets, Executor executor, CameraCaptureSessionCallback cameraCaptureSessionCallback) { // Create 3 sets of output configurations: one for the logical camera, and // one for each of the physical cameras. List outputConfigsLogical = targets.getLogicalCamera().stream() .map(OutputConfiguration::new) .collect(Collectors.toList()); List outputConfigsPhysical1 = targets.getFirstPhysicalCamera().stream() .map(s -> { OutputConfiguration outputConfiguration = new OutputConfiguration(s); outputConfiguration.setPhysicalCameraId(dualCamera.physicalId1); return outputConfiguration; }) .collect(Collectors.toList()); List outputConfigsPhysical2 = targets.getSecondPhysicalCamera().stream() .map(s -> { OutputConfiguration outputConfiguration = new OutputConfiguration(s); outputConfiguration.setPhysicalCameraId(dualCamera.physicalId2); return outputConfiguration; }) .collect(Collectors.toList()); // Put all the output configurations into a single flat array List outputConfigsAll = Stream.of( outputConfigsLogical, outputConfigsPhysical1, outputConfigsPhysical2 ) .filter(Objects::nonNull) .flatMap(Collection::stream) .collect(Collectors.toList()); // Instantiate a session configuration that can be used to create a session SessionConfiguration sessionConfiguration = new SessionConfiguration( SessionConfiguration.SESSION_REGULAR, outputConfigsAll, executor, new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { cameraCaptureSessionCallback.callback(cameraCaptureSession); } // Omitting for brevity... @Override public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { cameraCaptureSession.getDevice().close(); } }); // Open the logical camera using the previously defined function openDualCamera(cameraManager, dualCamera, executor, (CameraDevice c) -> // Finally create the session and return via callback c.createCaptureSession(sessionConfiguration)); }

Görüntüleyin createCaptureSession başlıklı makaleye göz atın. Akışları birleştirme tek bir mantıksal kamerada birden fazla yayın yapmak için kullanılır. Uyumluluk aynı yapılandırmayı kullanarak ve bu akışlardan birini iki akışla değiştirerek iki fiziksel kameradan çekilmiş görüntülerdir.

Şununla kamera oturumu hazır, istenen öğeyi yakalama istekleri. Her biri yakalama isteğinin hedefi, verilerini ilişkili fiziksel cihazdan alır kameranın yerini değiştirebilir veya mantıksal kameraya geri dönebilirsiniz.

Zoom örneği kullanım alanı

Fiziksel kameraların birleştirilmesiyle tek bir akış kullanılabilir. Farklı fiziksel kameralar arasında geçiş yaparak etkili bir şekilde farklı bir "yakınlaştırma seviyesi" yakalayan farklı bir görüş alanı sağlar.

Şekil 4. Yakınlaştırma düzeyi kullanım alanına göre kamera değiştirme örneği (Pixel 3 reklamından)

Kullanıcıların geçiş yapmasına izin vermek için fiziksel kamera çiftini seçerek başlayın arasında yer alır. En yüksek efekt için, her bir resmi ayrı ayrı oynatan mevcut minimum ve maksimum odak uzaklığı.

Kotlin

fun findShortLongCameraPair(manager: CameraManager, facing: Int? = null): DualCamera? {

    return findDualCameras(manager, facing).map {
        val characteristics1 = manager.getCameraCharacteristics(it.physicalId1)
        val characteristics2 = manager.getCameraCharacteristics(it.physicalId2)

        // Query the focal lengths advertised by each physical camera
        val focalLengths1 = characteristics1.get(
            CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS) ?: floatArrayOf(0F)
        val focalLengths2 = characteristics2.get(
            CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS) ?: floatArrayOf(0F)

        // Compute the largest difference between min and max focal lengths between cameras
        val focalLengthsDiff1 = focalLengths2.maxOrNull()!! - focalLengths1.minOrNull()!!
        val focalLengthsDiff2 = focalLengths1.maxOrNull()!! - focalLengths2.minOrNull()!!

        // Return the pair of camera IDs and the difference between min and max focal lengths
        if (focalLengthsDiff1 < focalLengthsDiff2) {
            Pair(DualCamera(it.logicalId, it.physicalId1, it.physicalId2), focalLengthsDiff1)
        } else {
            Pair(DualCamera(it.logicalId, it.physicalId2, it.physicalId1), focalLengthsDiff2)
        }

        // Return only the pair with the largest difference, or null if no pairs are found
    }.maxByOrNull { it.second }?.first
}

Java

// Utility functions to find min/max value in float[]
    float findMax(float[] array) {
        float max = Float.NEGATIVE_INFINITY;
        for(float cur: array)
            max = Math.max(max, cur);
        return max;
    }
    float findMin(float[] array) {
        float min = Float.NEGATIVE_INFINITY;
        for(float cur: array)
            min = Math.min(min, cur);
        return min;
    }

DualCamera findShortLongCameraPair(CameraManager manager, Integer facing) {
        return findDualCameras(manager, facing).stream()
                .map(c -> {
                    CameraCharacteristics characteristics1;
                    CameraCharacteristics characteristics2;
                    try {
                        characteristics1 = manager.getCameraCharacteristics(c.physicalId1);
                        characteristics2 = manager.getCameraCharacteristics(c.physicalId2);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                        return null;
                    }

                    // Query the focal lengths advertised by each physical camera
                    float[] focalLengths1 = characteristics1.get(
                            CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
                    float[] focalLengths2 = characteristics2.get(
                            CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);

                    // Compute the largest difference between min and max focal lengths between cameras
                    Float focalLengthsDiff1 = findMax(focalLengths2) - findMin(focalLengths1);
                    Float focalLengthsDiff2 = findMax(focalLengths1) - findMin(focalLengths2);

                    // Return the pair of camera IDs and the difference between min and max focal lengths
                    if (focalLengthsDiff1 < focalLengthsDiff2) {
                        return new Pair<>(new DualCamera(c.logicalId, c.physicalId1, c.physicalId2), focalLengthsDiff1);
                    } else {
                        return new Pair<>(new DualCamera(c.logicalId, c.physicalId2, c.physicalId1), focalLengthsDiff2);
                    }

                }) // Return only the pair with the largest difference, or null if no pairs are found
                .max(Comparator.comparing(pair -> pair.second)).get().first;
    }

Bunun için mantıklı bir mimari, iki SurfaceViews: Her akış için bir adet. Bu SurfaceViews, kullanıcı etkileşimine göre değiştirilir. Böylece yalnızca biri görünür olmalıdır.

Aşağıdaki kod, mantıksal kameranın nasıl açılacağını, kameranın nasıl yapılandırılacağını gösterir kamera oturumu oluşturun ve iki önizleme akışı başlatın:

Kotlin

val cameraManager: CameraManager = ...

// Get the two output targets from the activity / fragment
val surface1 = ...  // from SurfaceView
val surface2 = ...  // from SurfaceView

val dualCamera = findShortLongCameraPair(manager)!!
val outputTargets = DualCameraOutputs(
    null, mutableListOf(surface1), mutableListOf(surface2))

// Here you open the logical camera, configure the outputs and create a session
createDualCameraSession(manager, dualCamera, targets = outputTargets) { session ->

  // Create a single request which has one target for each physical camera
  // NOTE: Each target receive frames from only its associated physical camera
  val requestTemplate = CameraDevice.TEMPLATE_PREVIEW
  val captureRequest = session.device.createCaptureRequest(requestTemplate).apply {
    arrayOf(surface1, surface2).forEach { addTarget(it) }
  }.build()

  // Set the sticky request for the session and you are done
  session.setRepeatingRequest(captureRequest, null, null)
}

Java

CameraManager manager = ...;

        // Get the two output targets from the activity / fragment
        Surface surface1 = ...;  // from SurfaceView
        Surface surface2 = ...;  // from SurfaceView

        DualCamera dualCamera = findShortLongCameraPair(manager, null);
                DualCameraOutputs outputTargets = new DualCameraOutputs(
                null, Collections.singletonList(surface1), Collections.singletonList(surface2));

        // Here you open the logical camera, configure the outputs and create a session
        createDualCameraSession(manager, dualCamera, outputTargets, null, (session) -> {
            // Create a single request which has one target for each physical camera
            // NOTE: Each target receive frames from only its associated physical camera
            CaptureRequest.Builder captureRequestBuilder;
            try {
                captureRequestBuilder = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                Arrays.asList(surface1, surface2).forEach(captureRequestBuilder::addTarget);

                // Set the sticky request for the session and you are done
                session.setRepeatingRequest(captureRequestBuilder.build(), null, null);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        });

Kalan tek şey, kullanıcının bu ikisi arasında geçiş yapması için bir kullanıcı arayüzü sağlamaktır. (ör. düğme veya SurfaceView simgesine iki kez dokunma) Hatta, Bir tür sahne analizi yapma ve iki akış arasında geçiş yapma otomatik olarak oluşturur.

Lens bozulması

Tüm lensler belirli bir miktarda distorsiyon oluşturur. Android'de, kullanarak lenslerin oluşturduğu distorsiyon CameraCharacteristics.LENS_DISTORTION Bu segment, desteği sonlandırılan CameraCharacteristics.LENS_RADIAL_DISTORTION. Mantıksal kameralarda bozulma minimum düzeydedir ve uygulamanız, kameradan gelen kare sayısını artırır. Fiziksel kameralarda özellikle geniş açılı çekimde çok farklı lens konfigürasyonları lensler.

Bazı cihazlar otomatik distorsiyon düzeltmeyi CaptureRequest.DISTORTION_CORRECTION_MODE. Distorsiyon düzeltme özelliği çoğu cihazda varsayılan olarak açıktır.

Kotlin

val cameraSession: CameraCaptureSession = ...

        // Use still capture template to build the capture request
        val captureRequest = cameraSession.device.createCaptureRequest(
            CameraDevice.TEMPLATE_STILL_CAPTURE
        )

        // Determine if this device supports distortion correction
        val characteristics: CameraCharacteristics = ...
        val supportsDistortionCorrection = characteristics.get(
            CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES
        )?.contains(
            CameraMetadata.DISTORTION_CORRECTION_MODE_HIGH_QUALITY
        ) ?: false

        if (supportsDistortionCorrection) {
            captureRequest.set(
                CaptureRequest.DISTORTION_CORRECTION_MODE,
                CameraMetadata.DISTORTION_CORRECTION_MODE_HIGH_QUALITY
            )
        }

        // Add output target, set other capture request parameters...

        // Dispatch the capture request
        cameraSession.capture(captureRequest.build(), ...)

Java

CameraCaptureSession cameraSession = ...;

        // Use still capture template to build the capture request
        CaptureRequest.Builder captureRequestBuilder = null;
        try {
            captureRequestBuilder = cameraSession.getDevice().createCaptureRequest(
                    CameraDevice.TEMPLATE_STILL_CAPTURE
            );
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

        // Determine if this device supports distortion correction
        CameraCharacteristics characteristics = ...;
        boolean supportsDistortionCorrection = Arrays.stream(
                        characteristics.get(
                                CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES
                        ))
                .anyMatch(i -> i == CameraMetadata.DISTORTION_CORRECTION_MODE_HIGH_QUALITY);
        if (supportsDistortionCorrection) {
            captureRequestBuilder.set(
                    CaptureRequest.DISTORTION_CORRECTION_MODE,
                    CameraMetadata.DISTORTION_CORRECTION_MODE_HIGH_QUALITY
            );
        }

        // Add output target, set other capture request parameters...

        // Dispatch the capture request
        cameraSession.capture(captureRequestBuilder.build(), ...);

Bu modda bir yakalama isteği ayarlamak, üretiliyor. Distorsiyon düzeltmesini yalnızca şuna ayarlamayı seçebilirsiniz: hareketsiz görüntü alınır.