Suche…


Parameter

Parameter Einzelheiten
CameraCaptureSession Eine konfigurierte Aufnahmesitzung für ein CameraDevice , die zum CameraDevice von Bildern von der Kamera oder zum Wiederaufbereiten von Bildern verwendet wird, die zuvor in derselben Sitzung von der Kamera aufgenommen wurden
CameraDevice Eine Darstellung einer einzelnen Kamera, die mit einem Android-Gerät verbunden ist
CameraCharacteristics Die Eigenschaften, die ein CameraDevice beschreiben. Diese Eigenschaften sind für ein bestimmtes CameraDevice festgelegt und können über die CameraManager-Benutzeroberfläche mit getCameraCharacteristics(String) abgefragt werden.
CameraManager Ein System Service Manager zum Erkennen, Charakterisieren und Verbinden mit CameraDevices . Sie können eine Instanz dieser Klasse Context.getSystemService() indem Sie Context.getSystemService() aufrufen.
CaptureRequest Ein unveränderliches Paket von Einstellungen und Ausgaben, das zum Erfassen eines einzelnen Bilds vom Kameragerät benötigt wird. Enthält die Konfiguration für die Erfassungshardware (Sensor, Objektiv, Blitz), die Verarbeitungspipeline, die Steuerungsalgorithmen und die Ausgabepuffer. Enthält auch die Liste der Zieloberflächen, an die Bilddaten für diese Aufnahme gesendet werden sollen. Kann mit einer CaptureRequest.Builder Instanz erstellt werden, die durch Aufrufen von createCaptureRequest(int) abgerufen wird.
CaptureResult Die Teilmenge der Ergebnisse einer einzelnen Bildaufnahme vom Bildsensor. Enthält eine Teilmenge der endgültigen Konfiguration für die Erfassungshardware (Sensor, Objektiv, Blitzlicht), die Verarbeitungspipeline, die Steuerungsalgorithmen und die Ausgangspuffer. Es wird von einem CameraDevice nach der Verarbeitung eines CaptureRequest

Bemerkungen

  • Camera2-APIs sind in API 21+ (Lollipop und höher) verfügbar.
  • Selbst wenn ein Android-Gerät offiziell über 21 ROM-ROMs verfügt, gibt es keine Garantie, dass Camera2-APIs implementiert werden. Es ist völlig Sache des Herstellers, es zu implementieren oder nicht.
  • Bei Camera2 ist Camera ("Camera1") veraltet
  • Mit großer Leistung geht eine große Verantwortung einher: Es ist einfacher, diese APIs zu verwenden.
  • Denken Sie daran, wenn Sie nur ein Foto in Ihrer App aufnehmen und es einfach erhalten möchten, müssen Sie Camera2 nicht implementieren. Sie können die Kamera-App des Geräts über einen Intent öffnen und sie zurückerhalten

Vorschau der Hauptkamera in einer TextureView

In diesem Fall wird mit API 23 erstellt, sodass auch Berechtigungen behandelt werden.

Sie müssen im Manifest die folgende Berechtigung hinzufügen (wo auch immer die API-Ebene verwendet wird):

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

Wir erstellen gerade eine Aktivität (Camera2Activity.java), die eine TextureView mit der Vorschau der Kamera des Geräts füllt.

Die Aktivität, die wir verwenden werden, ist eine typische AppCompatActivity:

public class Camera2Activity extends AppCompatActivity {

Attribute (Sie müssen möglicherweise das gesamte Beispiel lesen, um einige davon zu verstehen.)

Die MAX_PREVIEW_SIZE von Camera2 API garantiert ist 1920x1080

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

TextureView.SurfaceTextureListener verarbeitet mehrere Lebenszyklusereignisse in einer TextureView . In diesem Fall hören wir uns diese Ereignisse an. Wenn die SurfaceTexture fertig ist, initialisieren wir die Kamera. Wenn sich die Größe ändert, stellen wir die Vorschau der Kamera entsprechend ein

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) {
    }

};

Ein CameraDevice repräsentiert die Kamera eines physischen Geräts. In diesem Attribut speichern wir die ID des aktuellen CameraDevice

private String mCameraId;

Dies ist die Ansicht ( TextureView ), mit der wir die Vorschau der Kamera "zeichnen"

private TextureView mTextureView;

Die CameraCaptureSession für die CameraCaptureSession

private CameraCaptureSession mCaptureSession;

Ein Verweis auf das geöffnete CameraDevice

private CameraDevice mCameraDevice;

Die Size der Kameravorschau.

private Size mPreviewSize;

CameraDevice.StateCallback wird aufgerufen, wenn CameraDevice seinen CameraDevice ändert

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();
    }

};

Ein zusätzlicher Thread zum Ausführen von Aufgaben, die die Benutzeroberfläche nicht blockieren sollen

private HandlerThread mBackgroundThread;

Ein Handler zum Ausführen von Aufgaben im Hintergrund

private Handler mBackgroundHandler;

Ein ImageReader , der die Erfassung von Standbildern übernimmt

private ImageReader mImageReader;

CaptureRequest.Builder für die CaptureRequest.Builder

private CaptureRequest.Builder mPreviewRequestBuilder;

CaptureRequest das von mPreviewRequestBuilder generiert wird

private CaptureRequest mPreviewRequest;

Ein Semaphore , um zu verhindern, dass die App beendet wird, bevor die Kamera geschlossen wird.

private Semaphore mCameraOpenCloseLock = new Semaphore(1);

Konstante ID der Berechtigungsanfrage

private static final int REQUEST_CAMERA_PERMISSION = 1;

Android-Lebenszyklusmethoden

@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();
}

Camera2 verwandte Methoden

Dies sind Methoden, die die Camera2-APIs verwenden

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

Schließt die aktuelle Kamera

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();
    }
}

Legt Mitgliedsvariablen für die Kamera fest

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();
    }
}

Erstellt eine neue CameraCaptureSession für die Kameravorschau

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();
    }
}

Berechtigungsbezogene Methoden Für Android API 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);
    }
}

Hintergrund-Thread / Handler-Methoden

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();
    }
}

Gebrauchsmethoden

Wählen Sie bei Auswahl der von einer Kamera unterstützten Size s die kleinste Größe aus, die mindestens der Gesamtgröße der Texturansicht entspricht und die der maximalen Größe entspricht und deren Seitenverhältnis mit dem angegebenen Wert übereinstimmt. Falls nicht vorhanden, wählen Sie den größten Wert, der höchstens so groß wie die jeweilige maximale Größe ist und dessen Seitenverhältnis mit dem angegebenen Wert übereinstimmt

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];
    }
}

Diese Methode konfiguriert die erforderliche Matrix Umwandlung 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);
}

Diese Methode vergleicht zwei Size basierend auf ihren Bereichen.

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());
    }
}

Hier nicht viel zu sehen

/**
 * 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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow