Zoeken…


parameters

Parameter Details
CameraCaptureSession Een geconfigureerde CameraDevice voor een CameraDevice , gebruikt voor het vastleggen van beelden van de camera of het opnieuw verwerken van beelden die zijn gemaakt met de camera in dezelfde sessie eerder
CameraDevice Een weergave van een enkele camera verbonden met een Android-apparaat
CameraCharacteristics De eigenschappen die een CameraDevice beschrijven. Deze eigenschappen zijn vast voor een gegeven CameraDevice en kunnen worden opgevraagd via de CameraManager-interface met getCameraCharacteristics(String)
CameraManager Een systeemservicemanager voor het detecteren, karakteriseren en verbinden met CameraDevices . U kunt een exemplaar van deze klasse krijgen door Context.getSystemService() aan te roepen
CaptureRequest Een onveranderlijk pakket van instellingen en uitgangen nodig om een enkel beeld van het camera-apparaat vast te leggen. Bevat de configuratie voor de vastleghardware (sensor, lens, flits), de verwerkingspijplijn, de besturingsalgoritmen en de uitvoerbuffers. Bevat ook de lijst met doeloppervlakken waarnaar afbeeldingsgegevens moeten worden verzonden voor deze opname. Kan worden gemaakt met behulp van een CaptureRequest.Builder instantie, verkregen door createCaptureRequest(int) aan te roepen
CaptureResult De subset van de resultaten van een enkele beeldopname van de beeldsensor. Bevat een subset van de uiteindelijke configuratie voor de vastleghardware (sensor, lens, flits), de verwerkingspijplijn, de besturingsalgoritmen en de uitvoerbuffers. Het wordt geproduceerd door een CameraDevice na verwerking van een CaptureRequest

Opmerkingen

  • Camera2 API's zijn beschikbaar in API 21+ (Lollipop en hoger)
  • Zelfs als een Android-apparaat officieel een ROM van 21+ heeft, is er geen garantie dat het Camera2 API's implementeert, het is volledig aan de fabrikant om het te implementeren of niet (bijvoorbeeld: LG G2 heeft officiële Lollipop-ondersteuning, maar geen Camera2 API's)
  • Met Camera2 is Camera ("Camera1") verouderd
  • Met grote kracht komt grote verantwoordelijkheid: het is gemakkelijker om het te verknoeien bij het gebruik van deze API's.
  • Vergeet niet dat als u alleen een foto in uw app wilt maken en deze eenvoudig wilt downloaden, u Camera2 niet hoeft te implementeren, u de camera-app van het apparaat kunt openen via een intentie en deze terug kunt ontvangen

Bekijk een voorbeeld van de hoofdcamera in een TextureView

In dit geval wordt gebouwd op basis van API 23, zodat ook machtigingen worden afgehandeld.

U moet in het Manifest de volgende toestemming toevoegen (ongeacht het API-niveau dat u gebruikt):

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

We gaan een activiteit maken (Camera2Activity.java) die een TextureView vult met het voorbeeld van de camera van het apparaat.

De activiteit die we gaan gebruiken, is een typische AppCompatActivity:

public class Camera2Activity extends AppCompatActivity {

Attributen (mogelijk moet u het hele voorbeeld lezen om er een deel van te begrijpen)

De MAX_PREVIEW_SIZE gegarandeerd door Camera2 API is 1920x1080

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

TextureView.SurfaceTextureListener verwerkt verschillende levenscyclusevents op een TextureView . In dit geval luisteren we naar die gebeurtenissen. Wanneer de SurfaceTexture klaar is, initialiseren we de camera. Wanneer het formaat verandert, stellen we het voorbeeld van de camera dienovereenkomstig in

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

};

Een CameraDevice vertegenwoordigt de camera van één fysiek apparaat. In dit kenmerk slaan we de ID van het huidige CameraDevice

private String mCameraId;

Dit is de weergave ( TextureView ) die we zullen gebruiken om de preview van de camera te "tekenen"

private TextureView mTextureView;

De CameraCaptureSession voor cameravoorbeeld

private CameraCaptureSession mCaptureSession;

Een verwijzing naar het geopende CameraDevice

private CameraDevice mCameraDevice;

De Size van cameravoorbeeld.

private Size mPreviewSize;

CameraDevice.StateCallback wordt aangeroepen wanneer CameraDevice verandert

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

};

Een extra thread voor het uitvoeren van taken die de gebruikersinterface niet mogen blokkeren

private HandlerThread mBackgroundThread;

Een Handler voor het uitvoeren van taken op de achtergrond

private Handler mBackgroundHandler;

Een ImageReader die het vastleggen van stilstaande beelden verwerkt

private ImageReader mImageReader;

CaptureRequest.Builder voor het cameravoorbeeld

private CaptureRequest.Builder mPreviewRequestBuilder;

CaptureRequest gegenereerd door mPreviewRequestBuilder

private CaptureRequest mPreviewRequest;

Een Semaphore om te voorkomen dat de app wordt afgesloten voordat de camera wordt gesloten.

private Semaphore mCameraOpenCloseLock = new Semaphore(1);

Constant ID van het toestemmingsverzoek

private static final int REQUEST_CAMERA_PERMISSION = 1;

Android Lifecycle-methoden

@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-gerelateerde methoden

Dat zijn methoden die de Camera2 API's gebruiken

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

Sluit de huidige camera

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

Stelt lidvariabelen in die gerelateerd zijn aan de camera

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

Maakt een nieuwe CameraCaptureSession voor cameravoorbeeld

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

Aan toestemmingen gerelateerde methoden voor 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);
    }
}

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

Hulpprogramma's

Gegeven de keuzes van Size die door een camera worden ondersteund, kies de kleinste die minstens even groot is als de respectieve textuurweergave, en die even groot is als de respectieve maximale grootte, en waarvan de beeldverhouding overeenkomt met de opgegeven waarde. Als dit niet bestaat, kiest u de grootste die maximaal even groot is als de respectieve maximale grootte en waarvan de beeldverhouding overeenkomt met de opgegeven waarde

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

Deze methode configureert de noodzakelijke Matrix transformatie naar 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);
}

Deze methode vergelijkt twee Size basis van hun gebieden.

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

Niet veel te zien hier

/**
 * 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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow