iCamera Android Camera Library

repository·master·Indexed 19 days ago

https://github.com/shouheng88/icamera

A customizable Android camera library that abstracts Camera1 and Camera2 APIs to support photo capture and video recording. It features a CameraView XML component, a ConfigurationProvider for global settings and caching, and a strategy-based architecture allowing developers to customize camera manager strategies and output size calculation algorithms. The library provides real-time preview data in NV21 format and includes built-in support for focus markers, zoom, and orientation change listeners.

Tokens
5.9K
Snippets
17
Records
25
Agent score
66%

What's inside iCamera

  1. How iCamera manages Camera1 and Camera2 via Strategy Pattern

    master

    iCamera uses a combination of the Facade and Strategy design patterns to abstract the differences between the legacy Camera1 API and the modern Camera2 API.

    • Facade: The CameraManager interface provides a unified set of methods (e.g., switching cameras, toggling flash, zooming, taking photos) so the consumer doesn't need to know which underlying API is being used.
    • Strategy: The library uses a CameraManagerCreator to decide at runtime whether to instantiate a Camera2Manager or a Camera1Manager based on device support and OS version.

    By default, CameraManagerCreatorImpl checks if the device supports Camera2 via CameraHelper.hasCamera2(context). If it fails or is unsupported, it falls back to Camera1Manager.

    // The strategy interface for creating a manager
    public interface CameraManagerCreator {
        CameraManager create(Context context, CameraPreview cameraPreview);
    }
    
    // The default implementation that handles Camera1/Camera2 fallback
    public class CameraManagerCreatorImpl implements CameraManagerCreator {
        @Override
        public CameraManager create(Context context, CameraPreview cameraPreview) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && CameraHelper.hasCamera2(context)) {
                return new Camera2Manager(cameraPreview);
            }
            return new Camera1Manager(cameraPreview);
        }
    }
  2. Configure iCamera using ConfigurationProvider

    master
    In addition to calling instance methods on CameraView, you can use the ConfigurationProvider singleton to manage global camera settings and cache data. ConfigurationProvider.get() allows you to access the provider, which is used to cache camera attributes to improve startup speed and perform 'pre-loading' of camera parameters before the camera is actually opened.
  3. Install iCamera via Gradle

    master

    iCamera is hosted on MavenCentral. To use it, ensure mavenCentral() is included in your project's repositories block, then add the dependency to your app's build.gradle file.

    repositories {
        mavenCentral()
    }
    
    dependencies {
        implementation "com.github.Shouheng88:icamera:${latest-version}"
    }
  4. Integrate CameraView into Android layouts

    master

    The CameraView is the primary UI component for integrating the camera into your Android application. It extends FrameLayout and can be added directly to your XML layout files or instantiated programmatically. It handles camera lifecycle, preview rendering, and common camera operations like zooming, switching cameras, and capturing media.

    <me.shouheng.icamera.CameraView
        android:id="@+id/camera_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:cameraFace="@me.shouheng.icamera.enums.CameraFace.FRONT"
        app:mediaType="@me.shouheng.icamera.enums.MediaType.VIDEO" />
  5. Configure the global iCamera settings

    master

    The ConfigurationProvider is a singleton used to manage global settings and cache camera values for the iCamera library. You can access it via ConfigurationProvider.get() and modify default behaviors before the camera is launched.

    Key configuration options include:

    • defaultCameraFace: Set the default camera (e.g., CameraFace.FACE_REAR).
    • defaultMediaType: Set the default media type (e.g., MediaType.TYPE_PICTURE).
    • defaultMediaQuality: Set the default quality (e.g., MediaQuality.QUALITY_HIGH).
    • defaultAspectRatio: Set the default aspect ratio using AspectRatio.of(width, height).
    • defaultFlashMode: Set the default flash mode (e.g., FlashMode.FLASH_AUTO).
    • isUseCacheValues: Enable or disable memory caching for camera sizes and ratios (defaults to true).
    • useCameraFallback: If true, the library will attempt to use the front camera if the rear camera fails to launch.
    • isDebug: Enable debug logging via XLog.
    • isVoiceEnable: Enable/disable voice feedback.
    • isAutoFocus: Enable/disable auto-focus.
    val config = ConfigurationProvider.get()
    config.defaultCameraFace = CameraFace.FACE_FRONT
    config.defaultAspectRatio = AspectRatio.of(16, 9)
    config.isDebug = true
  6. Use the CameraView XML component

    master

    You can integrate the camera directly into your layout files using the me.shouheng.icamera.CameraView component. Use XML attributes to configure basic properties like media type, camera face, and aspect ratio.

    <me.shouheng.icamera.CameraView
            android:id="@+id/cv"
            app:scaleRate="10"
            app:mediaType="picture"
            app:cameraFace="rear"
            android:adjustViewBounds="true"
            app:clipScreen="false"
            app:aspectRatio="4:3"
            app:cameraAdjustType="heightFirst"
            android:layout_centerInParent="true"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
  7. Manage camera output sizes and aspect ratios

    master

    iCamera provides specific interfaces to handle the complexity of Android camera dimensions, which differ for Preview, Picture (photos), and Video.

    1. Querying Supported Sizes

    You can retrieve supported sizes using getSize() (for a single size) or getSizes() (for a map of sizes grouped by aspect ratio). Use the @Camera.SizeFor annotation to specify the type:

    • Camera.SIZE_FOR_PREVIEW
    • Camera.SIZE_FOR_PICTURE
    • Camera.SIZE_FOR_VIDEO

    2. Setting Desired Output

    Instead of manually calculating compatible dimensions, you can tell iCamera what you want, and it will find the best match from the supported hardware list:

    • setExpectSize(Size expectSize): Sets the desired dimensions for the output file.
    • setExpectAspectRatio(AspectRatio expectAspectRatio): Sets the desired aspect ratio.

    3. Customizing Size Calculation

    If the default logic doesn't suit your needs, you can implement the CameraSizeCalculator interface and register it via ConfigurationProvider to control how previewSize, pictureSize, and videoSize are derived from the hardware capabilities.

    // Example: Getting supported picture sizes mapped by aspect ratio
    SizeMap pictureSizes = cameraManager.getSizes(Camera.SIZE_FOR_PICTURE);
    
    // Example: Setting desired output parameters
    cameraManager.setExpectSize(new Size(1920, 1080));
    cameraManager.setExpectAspectRatio(AspectRatio.RATIO_16_9);
  8. Get real-time preview data

    master
    iCamera provides an interface to access real-time preview data. For Camera2, it retrieves data in YUV_420_888 format and converts it to NV21 to maintain consistency with Camera1 callbacks. This is useful for implementing features like light intensity detection or custom image processing (e.g., converting NV21 to Bitmap). For high-performance requirements, it is recommended to implement the image format conversion in C++ rather than Java.
  9. Customize Output Size Calculation Algorithm

    master

    You can control how the library selects output dimensions (for photos/videos or previews) by implementing the CameraSizeCalculator interface. The library provides two default strategies:

    1. Output Size Strategy: Selects the best size for photos/videos by matching the desired aspect ratio, then the desired size, and finally considering quality.
    2. Preview Size Strategy: Matches aspect ratio and then size to find a preview dimension close to the output dimensions.

    Assign your custom implementation to ConfigurationProvider to use it.

  10. Implement a custom CameraSizeCalculator

    master

    To control how the library selects the best available camera dimensions for preview, photos, or video, implement the CameraSizeCalculator interface. This is useful when you have specific requirements for how the library should pick a size when an exact match isn't available.

    Methods to implement:

    • getPicturePreviewSize(...)
    • getVideoPreviewSize(...)
    • getPictureSize(...)
    • getVideoSize(...)
    public interface CameraSizeCalculator {
        Size getPicturePreviewSize(@NonNull List<Size> previewSizes, @NonNull Size pictureSize);
        Size getVideoPreviewSize(@NonNull List<Size> previewSizes, @NonNull Size videoSize);
        Size getPictureSize(@NonNull List<Size> pictureSizes, @NonNull AspectRatio expectAspectRatio, @Nullable Size expectSize);
        Size getVideoSize(@NonNull List<Size> videoSizes, @NonNull AspectRatio expectAspectRatio, @Nullable Size expectSize);
    }
  11. Configure global settings with ConfigurationProvider

    master

    The ConfigurationProvider is a singleton used to manage global library settings and cache camera-specific properties (like supported sizes) to improve performance.

    Key capabilities:

    • Global Configuration: Set custom strategies for camera management or size calculation.
    • Caching: It can cache supported camera sizes to avoid repeated expensive calls to the hardware. You can control this via the useCacheValues flag.

    Access the provider using ConfigurationProvider.get().

    // Access the singleton instance
    ConfigurationProvider config = ConfigurationProvider.get();
  12. Customize Camera Manager Strategy

    master

    By default, iCamera uses Camera2 if the device API level is $\ge 21$ and Camera2 is supported. You can override this behavior by implementing the CameraManagerCreator interface. This is useful if you want to force the use of Camera1 on devices where Camera2 support is unstable.

    // 1. Implement the creator
    class Camera1OnlyCreator : CameraManagerCreator {
        override fun create(context: Context?, cameraPreview: CameraPreview?) = Camera1Manager(cameraPreview)
    }
    
    // 2. Set it in the ConfigurationProvider
    ConfigurationProvider.get().cameraManagerCreator = Camera1OnlyCreator()