Ricerca…


Parametri

Parametro Dettagli
CameraCaptureSession Una sessione di acquisizione configurata per un dispositivo CameraDevice , utilizzata per catturare immagini dalla fotocamera o rielaborare le immagini acquisite dalla fotocamera nella stessa sessione in precedenza
CameraDevice Una rappresentazione di una singola videocamera collegata a un dispositivo Android
CameraCharacteristics Le proprietà che descrivono un dispositivo CameraDevice. Queste proprietà sono corrette per un determinato CameraDevice e possono essere interrogate tramite l'interfaccia di CameraManager con getCameraCharacteristics(String)
CameraManager Un gestore di servizi di sistema per il rilevamento, la caratterizzazione e la connessione a CameraDevices . È possibile ottenere un'istanza di questa classe chiamando Context.getSystemService()
CaptureRequest Un pacchetto immutabile di impostazioni e uscite necessarie per acquisire una singola immagine dal dispositivo della fotocamera. Contiene la configurazione per l'hardware di acquisizione (sensore, obiettivo, flash), la pipeline di elaborazione, gli algoritmi di controllo e i buffer di uscita. Contiene anche l'elenco delle Superfici di destinazione per inviare dati di immagine a per questa cattura. Può essere creato utilizzando un'istanza CaptureRequest.Builder , ottenuta chiamando createCaptureRequest(int)
CaptureResult Il sottoinsieme dei risultati di una singola acquisizione di immagini dal sensore di immagine. Contiene un sottoinsieme della configurazione finale per l'hardware di acquisizione (sensore, obiettivo, flash), la pipeline di elaborazione, gli algoritmi di controllo e i buffer di uscita. Viene prodotto da un dispositivo CameraDevice dopo l'elaborazione di CaptureRequest

Osservazioni

  • Le API Camera2 sono disponibili in API 21+ (Lollipop e oltre)
  • Anche se un dispositivo Android ha ufficialmente una ROM 21+, non è garantito che implementa le API di Camera2, è totalmente compito del produttore implementarlo o meno (Esempio: LG G2 ha il supporto ufficiale di Lollipop, ma nessuna API Camera2)
  • Con Camera2, Camera ("Camera1") è deprecato
  • Con una grande potenza arriva una grande responsabilità: è più facile rovinarlo quando usi questa API.
  • Ricorda, se vuoi solo scattare una foto nella tua app, e semplicemente ottenerla, non è necessario implementare Camera2, puoi aprire l'app della fotocamera del dispositivo tramite un Intento e riceverla indietro

Visualizza l'anteprima della fotocamera principale in un TextureView

In questo caso, costruire contro l'API 23, quindi anche le autorizzazioni sono gestite.

Devi aggiungere nel manifesto la seguente autorizzazione (ovunque il livello API stai usando):

<uses-permission android:name="android.permission.CAMERA"/>

Stiamo per creare un'attività (Camera2Activity.java) che riempie un TextureView con l'anteprima della fotocamera del dispositivo.

L'attività che useremo è una tipica appCompatActivity:

public class Camera2Activity extends AppCompatActivity {

Attributi (potrebbe essere necessario leggere l'intero esempio per comprenderne alcuni)

MAX_PREVIEW_SIZE garantito da Camera2 API è 1920x1080

private static final int MAX_PREVIEW_WIDTH = 1920;
private static final int MAX_PREVIEW_HEIGHT = 1080;

TextureView.SurfaceTextureListener gestisce diversi eventi del ciclo di vita su un TextureView . In questo caso, stiamo ascoltando quegli eventi. Quando SurfaceTexture è pronto, inizializziamo la videocamera. Quando cambia la dimensione, impostiamo l'anteprima proveniente dalla fotocamera di conseguenza

private final TextureView.SurfaceTextureListener mSurfaceTextureListener
        = new TextureView.SurfaceTextureListener() {

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
        openCamera(width, height);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
        configureTransform(width, height);
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture texture) {
    }

};

Un dispositivo CameraDevice rappresenta la videocamera di un dispositivo fisico. In questo attributo, salviamo l'ID del dispositivo CameraDevice corrente

private String mCameraId;

Questa è la vista ( TextureView ) che useremo per "disegnare" l'anteprima della Camera

private TextureView mTextureView;

CameraCaptureSession per l'anteprima della fotocamera

private CameraCaptureSession mCaptureSession;

Un riferimento al CameraDevice aperto

private CameraDevice mCameraDevice;

La Size dell'anteprima della fotocamera.

private Size mPreviewSize;

CameraDevice.StateCallback viene chiamato quando CameraDevice modifica il suo stato

private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {

    @Override
    public void onOpened(@NonNull CameraDevice cameraDevice) {
        // This method is called when the camera is opened.  We start camera preview here.
        mCameraOpenCloseLock.release();
        mCameraDevice = cameraDevice;
        createCameraPreviewSession();
    }

    @Override
    public void onDisconnected(@NonNull CameraDevice cameraDevice) {
        mCameraOpenCloseLock.release();
        cameraDevice.close();
        mCameraDevice = null;
    }

    @Override
    public void onError(@NonNull CameraDevice cameraDevice, int error) {
        mCameraOpenCloseLock.release();
        cameraDevice.close();
        mCameraDevice = null;
        finish();
    }

};

Un thread aggiuntivo per l'esecuzione di attività che non dovrebbero bloccare l'interfaccia utente

private HandlerThread mBackgroundThread;

Un Handler per eseguire attività in background

private Handler mBackgroundHandler;

Un ImageReader che gestisce l'acquisizione di immagini statiche

private ImageReader mImageReader;

CaptureRequest.Builder per l'anteprima della fotocamera

private CaptureRequest.Builder mPreviewRequestBuilder;

CaptureRequest generato da mPreviewRequestBuilder

private CaptureRequest mPreviewRequest;

Un Semaphore per impedire all'app di uscire prima di chiudere la fotocamera.

private Semaphore mCameraOpenCloseLock = new Semaphore(1);

ID costante della richiesta di autorizzazione

private static final int REQUEST_CAMERA_PERMISSION = 1;

Metodi Android Lifecycle

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_camera2);

    mTextureView = (TextureView) findViewById(R.id.texture);
}

@Override
public void onResume() {
    super.onResume();
    startBackgroundThread();

    // When the screen is turned off and turned back on, the SurfaceTexture is already
    // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
    // a camera and start preview from here (otherwise, we wait until the surface is ready in
    // the SurfaceTextureListener).
    if (mTextureView.isAvailable()) {
        openCamera(mTextureView.getWidth(), mTextureView.getHeight());
    } else {
        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
    }
}

@Override
public void onPause() {
    closeCamera();
    stopBackgroundThread();
    super.onPause();
}

Metodi correlati a Camera2

Quelli sono metodi che utilizzano le API Camera2

private void openCamera(int width, int height) {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {
        requestCameraPermission();
        return;
    }
    setUpCameraOutputs(width, height);
    configureTransform(width, height);
    CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
            throw new RuntimeException("Time out waiting to lock camera opening.");
        }
        manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
    }
}

Chiude la videocamera corrente

private void closeCamera() {
    try {
        mCameraOpenCloseLock.acquire();
        if (null != mCaptureSession) {
            mCaptureSession.close();
            mCaptureSession = null;
        }
        if (null != mCameraDevice) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
        if (null != mImageReader) {
            mImageReader.close();
            mImageReader = null;
        }
    } catch (InterruptedException e) {
        throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
    } finally {
        mCameraOpenCloseLock.release();
    }
}

Imposta le variabili membro relative alla telecamera

private void setUpCameraOutputs(int width, int height) {
    CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        for (String cameraId : manager.getCameraIdList()) {
            CameraCharacteristics characteristics
                    = manager.getCameraCharacteristics(cameraId);

            // We don't use a front facing camera in this sample.
            Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
            if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
                continue;
            }

            StreamConfigurationMap map = characteristics.get(
                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            if (map == null) {
                continue;
            }

            // For still image captures, we use the largest available size.
            Size largest = Collections.max(
                    Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
                    new CompareSizesByArea());
            mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
                    ImageFormat.JPEG, /*maxImages*/2);
            mImageReader.setOnImageAvailableListener(
                    null, mBackgroundHandler);

            Point displaySize = new Point();
            getWindowManager().getDefaultDisplay().getSize(displaySize);
            int rotatedPreviewWidth = width;
            int rotatedPreviewHeight = height;
            int maxPreviewWidth = displaySize.x;
            int maxPreviewHeight = displaySize.y;

            if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
                maxPreviewWidth = MAX_PREVIEW_WIDTH;
            }

            if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
                maxPreviewHeight = MAX_PREVIEW_HEIGHT;
            }

            // Danger! Attempting to use too large a preview size could  exceed the camera
            // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
            // garbage capture data.
            mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
                    rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
                    maxPreviewHeight, largest);

            mCameraId = cameraId;
            return;
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    } catch (NullPointerException e) {
        // Currently an NPE is thrown when the Camera2API is used but not supported on the
        // device this code runs.
        Toast.makeText(Camera2Activity.this, "Camera2 API not supported on this device", Toast.LENGTH_LONG).show();
    }
}

Crea una nuova CameraCaptureSession per l'anteprima della videocamera

private void createCameraPreviewSession() {
    try {
        SurfaceTexture texture = mTextureView.getSurfaceTexture();
        assert texture != null;

        // We configure the size of default buffer to be the size of camera preview we want.
        texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());

        // This is the output Surface we need to start preview.
        Surface surface = new Surface(texture);

        // We set up a CaptureRequest.Builder with the output Surface.
        mPreviewRequestBuilder
                = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mPreviewRequestBuilder.addTarget(surface);

        // Here, we create a CameraCaptureSession for camera preview.
        mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                new CameraCaptureSession.StateCallback() {

                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                        // The camera is already closed
                        if (null == mCameraDevice) {
                            return;
                        }

                        // When the session is ready, we start displaying the preview.
                        mCaptureSession = cameraCaptureSession;
                        try {
                            // Auto focus should be continuous for camera preview.
                            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

                            // Finally, we start displaying the camera preview.
                            mPreviewRequest = mPreviewRequestBuilder.build();
                            mCaptureSession.setRepeatingRequest(mPreviewRequest,
                                    null, mBackgroundHandler);
                        } catch (CameraAccessException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onConfigureFailed(
                            @NonNull CameraCaptureSession cameraCaptureSession) {
                        showToast("Failed");
                    }
                }, null
        );
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

Metodi correlati alle autorizzazioni Per l'API Android 23+

private void requestCameraPermission() {
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
        new AlertDialog.Builder(Camera2Activity.this)
                .setMessage("R string request permission")
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ActivityCompat.requestPermissions(Camera2Activity.this,
                                new String[]{Manifest.permission.CAMERA},
                                REQUEST_CAMERA_PERMISSION);
                    }
                })
                .setNegativeButton(android.R.string.cancel,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                finish();

                            }
                        })
                .create();

    } else {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
                REQUEST_CAMERA_PERMISSION);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {
    if (requestCode == REQUEST_CAMERA_PERMISSION) {
        if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(Camera2Activity.this, "ERROR: Camera permissions not granted", Toast.LENGTH_LONG).show();
        }
    } else {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

Metodi di thread di background / handler

private void startBackgroundThread() {
    mBackgroundThread = new HandlerThread("CameraBackground");
    mBackgroundThread.start();
    mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}

private void stopBackgroundThread() {
    mBackgroundThread.quitSafely();
    try {
        mBackgroundThread.join();
        mBackgroundThread = null;
        mBackgroundHandler = null;
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

Metodi di utilità

Date le scelte di Size s supportate da una telecamera, scegliete quella più piccola che è almeno ampia come le rispettive dimensioni della vista della trama, e che è grande quanto la rispettiva dimensione massima e le cui proporzioni corrispondono al valore specificato. Se non esiste, scegli il più grande che sia grande al massimo come la rispettiva dimensione massima e le cui proporzioni corrispondono al valore specificato

private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
                                      int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {

    // Collect the supported resolutions that are at least as big as the preview Surface
    List<Size> bigEnough = new ArrayList<>();
    // Collect the supported resolutions that are smaller than the preview Surface
    List<Size> notBigEnough = new ArrayList<>();
    int w = aspectRatio.getWidth();
    int h = aspectRatio.getHeight();
    for (Size option : choices) {
        if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
                option.getHeight() == option.getWidth() * h / w) {
            if (option.getWidth() >= textureViewWidth &&
                    option.getHeight() >= textureViewHeight) {
                bigEnough.add(option);
            } else {
                notBigEnough.add(option);
            }
        }
    }

    // Pick the smallest of those big enough. If there is no one big enough, pick the
    // largest of those not big enough.
    if (bigEnough.size() > 0) {
        return Collections.min(bigEnough, new CompareSizesByArea());
    } else if (notBigEnough.size() > 0) {
        return Collections.max(notBigEnough, new CompareSizesByArea());
    } else {
        Log.e("Camera2", "Couldn't find any suitable preview size");
        return choices[0];
    }
}

Questo metodo congfigura la trasformazione mTextureView Matrix in mTextureView

private void configureTransform(int viewWidth, int viewHeight) {
    if (null == mTextureView || null == mPreviewSize) {
        return;
    }
    int rotation = getWindowManager().getDefaultDisplay().getRotation();
    Matrix matrix = new Matrix();
    RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
    RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
    float centerX = viewRect.centerX();
    float centerY = viewRect.centerY();
    if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
        bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
        matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
        float scale = Math.max(
                (float) viewHeight / mPreviewSize.getHeight(),
                (float) viewWidth / mPreviewSize.getWidth());
        matrix.postScale(scale, scale, centerX, centerY);
        matrix.postRotate(90 * (rotation - 2), centerX, centerY);
    } else if (Surface.ROTATION_180 == rotation) {
        matrix.postRotate(180, centerX, centerY);
    }
    mTextureView.setTransform(matrix);
}

Questo metodo confronta due Size base alle loro aree.

static class CompareSizesByArea implements Comparator<Size> {

    @Override
    public int compare(Size lhs, Size rhs) {
        // We cast here to ensure the multiplications won't overflow
        return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
                (long) rhs.getWidth() * rhs.getHeight());
    }
}

Non c'è molto da vedere qui

/**
 * Shows a {@link Toast} on the UI thread.
 *
 * @param text The message to show
 */
private void showToast(final String text) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            Toast.makeText(Camera2Activity.this, text, Toast.LENGTH_SHORT).show();
        }
    });
}


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow