761 lines
30 KiB
Python
761 lines
30 KiB
Python
"""
|
|
Android Camera2 组件 — CameraManager, CameraDevice, CaptureRequest 等
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
import time
|
|
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
|
|
|
|
from .._core import Stub, AndroidOnlyError, android_context, HAS_PIL
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CameraMetadata
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CameraMetadata(Stub):
|
|
"""CameraMetadata — 相机元数据基类"""
|
|
|
|
# CONTROL_AE modes
|
|
CONTROL_AE_MODE_OFF = 0
|
|
CONTROL_AE_MODE_ON = 1
|
|
CONTROL_AE_MODE_ON_AUTO_FLASH = 2
|
|
CONTROL_AE_MODE_ON_ALWAYS_FLASH = 3
|
|
CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4
|
|
CONTROL_AE_MODE_EXTERNAL_FLASH = 5
|
|
|
|
# CONTROL_AF modes
|
|
CONTROL_AF_MODE_OFF = 0
|
|
CONTROL_AF_MODE_AUTO = 1
|
|
CONTROL_AF_MODE_MACRO = 2
|
|
CONTROL_AF_MODE_CONTINUOUS_VIDEO = 3
|
|
CONTROL_AF_MODE_CONTINUOUS_PICTURE = 4
|
|
CONTROL_AF_MODE_EDOF = 5
|
|
|
|
# CONTROL_AWB modes
|
|
CONTROL_AWB_MODE_OFF = 0
|
|
CONTROL_AWB_MODE_AUTO = 1
|
|
CONTROL_AWB_MODE_INCANDESCENT = 2
|
|
CONTROL_AWB_MODE_FLUORESCENT = 3
|
|
CONTROL_AWB_MODE_WARM_FLUORESCENT = 4
|
|
CONTROL_AWB_MODE_DAYLIGHT = 5
|
|
CONTROL_AWB_MODE_CLOUDY_DAYLIGHT = 6
|
|
CONTROL_AWB_MODE_TWILIGHT = 7
|
|
CONTROL_AWB_MODE_SHADE = 8
|
|
|
|
# CONTROL modes
|
|
CONTROL_MODE_OFF = 0
|
|
CONTROL_MODE_AUTO = 1
|
|
CONTROL_MODE_USE_SCENE_MODE = 2
|
|
CONTROL_MODE_OFF_KEEP_STATE = 3
|
|
|
|
# FLASH modes
|
|
FLASH_MODE_OFF = 0
|
|
FLASH_MODE_SINGLE = 1
|
|
FLASH_MODE_TORCH = 2
|
|
|
|
# STATISTICS_FACE_DETECT modes
|
|
STATISTICS_FACE_DETECT_MODE_OFF = 0
|
|
STATISTICS_FACE_DETECT_MODE_SIMPLE = 1
|
|
STATISTICS_FACE_DETECT_MODE_FULL = 2
|
|
|
|
# EDGE modes
|
|
EDGE_MODE_OFF = 0
|
|
EDGE_MODE_FAST = 1
|
|
EDGE_MODE_HIGH_QUALITY = 2
|
|
EDGE_MODE_ZERO_SHUTTER_LAG = 3
|
|
|
|
# NOISE_REDUCTION modes
|
|
NOISE_REDUCTION_MODE_OFF = 0
|
|
NOISE_REDUCTION_MODE_FAST = 1
|
|
NOISE_REDUCTION_MODE_HIGH_QUALITY = 2
|
|
NOISE_REDUCTION_MODE_MINIMAL = 3
|
|
NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG = 4
|
|
|
|
# TONEMAP modes
|
|
TONEMAP_MODE_CONTRAST_CURVE = 0
|
|
TONEMAP_MODE_FAST = 1
|
|
TONEMAP_MODE_HIGH_QUALITY = 2
|
|
TONEMAP_MODE_GAMMA_VALUE = 3
|
|
TONEMAP_MODE_PRESET_CURVE = 4
|
|
|
|
# COLOR_CORRECTION modes
|
|
COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0
|
|
COLOR_CORRECTION_MODE_FAST = 1
|
|
COLOR_CORRECTION_MODE_HIGH_QUALITY = 2
|
|
|
|
# COLOR_CORRECTION_ABERRATION modes
|
|
COLOR_CORRECTION_ABERRATION_MODE_OFF = 0
|
|
COLOR_CORRECTION_ABERRATION_MODE_FAST = 1
|
|
COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2
|
|
|
|
# CONTROL_AE_PRECAPTURE_TRIGGER
|
|
CONTROL_AE_PRECAPTURE_TRIGGER_IDLE = 0
|
|
CONTROL_AE_PRECAPTURE_TRIGGER_START = 1
|
|
CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL = 2
|
|
|
|
# CONTROL_EFFECT modes
|
|
CONTROL_EFFECT_MODE_OFF = 0
|
|
CONTROL_EFFECT_MODE_MONO = 1
|
|
CONTROL_EFFECT_MODE_NEGATIVE = 2
|
|
CONTROL_EFFECT_MODE_SOLARIZE = 3
|
|
CONTROL_EFFECT_MODE_SEPIA = 4
|
|
CONTROL_EFFECT_MODE_POSTERIZE = 5
|
|
CONTROL_EFFECT_MODE_WHITEBOARD = 6
|
|
CONTROL_EFFECT_MODE_BLACKBOARD = 7
|
|
CONTROL_EFFECT_MODE_AQUA = 8
|
|
|
|
# CONTROL_SCENE modes
|
|
CONTROL_SCENE_MODE_DISABLED = 0
|
|
CONTROL_SCENE_MODE_FACE_PRIORITY = 1
|
|
CONTROL_SCENE_MODE_ACTION = 2
|
|
CONTROL_SCENE_MODE_PORTRAIT = 3
|
|
CONTROL_SCENE_MODE_LANDSCAPE = 4
|
|
CONTROL_SCENE_MODE_NIGHT = 5
|
|
CONTROL_SCENE_MODE_NIGHT_PORTRAIT = 6
|
|
CONTROL_SCENE_MODE_THEATRE = 7
|
|
CONTROL_SCENE_MODE_BEACH = 8
|
|
CONTROL_SCENE_MODE_SNOW = 9
|
|
CONTROL_SCENE_MODE_SUNSET = 10
|
|
CONTROL_SCENE_MODE_STEADYPHOTO = 11
|
|
CONTROL_SCENE_MODE_FIREWORKS = 12
|
|
CONTROL_SCENE_MODE_SPORTS = 13
|
|
CONTROL_SCENE_MODE_PARTY = 14
|
|
CONTROL_SCENE_MODE_CANDLELIGHT = 15
|
|
CONTROL_SCENE_MODE_BARCODE = 16
|
|
CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO = 17
|
|
CONTROL_SCENE_MODE_HDR = 18
|
|
|
|
# CONTROL_VIDEO_STABILIZATION modes
|
|
CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0
|
|
CONTROL_VIDEO_STABILIZATION_MODE_ON = 1
|
|
|
|
# DISTORTION_CORRECTION modes
|
|
DISTORTION_CORRECTION_MODE_OFF = 0
|
|
DISTORTION_CORRECTION_MODE_FAST = 1
|
|
DISTORTION_CORRECTION_MODE_HIGH_QUALITY = 2
|
|
|
|
# HOT_PIXEL modes
|
|
HOT_PIXEL_MODE_OFF = 0
|
|
HOT_PIXEL_MODE_FAST = 1
|
|
HOT_PIXEL_MODE_HIGH_QUALITY = 2
|
|
|
|
# LENS_OPTICAL_STABILIZATION modes
|
|
LENS_OPTICAL_STABILIZATION_MODE_OFF = 0
|
|
LENS_OPTICAL_STABILIZATION_MODE_ON = 1
|
|
|
|
# LENS_FACING
|
|
LENS_FACING_FRONT = 0
|
|
LENS_FACING_BACK = 1
|
|
LENS_FACING_EXTERNAL = 2
|
|
|
|
# INFO_SUPPORTED_HARDWARE_LEVEL
|
|
INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0
|
|
INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1
|
|
INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2
|
|
INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3
|
|
INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL = 4
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CameraCharacteristics
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CameraCharacteristics(CameraMetadata):
|
|
"""CameraCharacteristics — 相机特性"""
|
|
|
|
LENS_FACING = "android.lens.facing"
|
|
SENSOR_ORIENTATION = "android.sensor.orientation"
|
|
FLASH_INFO_AVAILABLE = "android.flash.info.available"
|
|
INFO_SUPPORTED_HARDWARE_LEVEL = "android.info.supportedHardwareLevel"
|
|
SCALER_STREAM_CONFIGURATION_MAP = "android.scaler.streamConfigurationMap"
|
|
CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES = "android.control.aeAvailableTargetFpsRanges"
|
|
CONTROL_AE_AVAILABLE_MODES = "android.control.aeAvailableModes"
|
|
CONTROL_AF_AVAILABLE_MODES = "android.control.afAvailableModes"
|
|
CONTROL_AVAILABLE_EFFECTS = "android.control.availableEffects"
|
|
CONTROL_AVAILABLE_SCENE_MODES = "android.control.availableSceneModes"
|
|
CONTROL_MAX_REGIONS_AE = "android.control.maxRegionsAe"
|
|
CONTROL_MAX_REGIONS_AF = "android.control.maxRegionsAf"
|
|
CONTROL_MAX_REGIONS_AWB = "android.control.maxRegionsAwb"
|
|
JPEG_AVAILABLE_THUMBNAIL_SIZES = "android.jpeg.availableThumbnailSizes"
|
|
JPEG_MAX_SIZE = "android.jpeg.maxSize"
|
|
SENSOR_INFO_PIXEL_ARRAY_SIZE = "android.sensor.info.pixelArraySize"
|
|
SENSOR_INFO_ACTIVE_ARRAY_SIZE = "android.sensor.info.activeArraySize"
|
|
FLASH_MODE = "android.flash.mode"
|
|
|
|
def __init__(self, camera_id: str = "0"):
|
|
super().__init__()
|
|
self._properties: Dict[str, Any] = {
|
|
CameraCharacteristics.LENS_FACING: CameraCharacteristics.LENS_FACING_BACK,
|
|
CameraCharacteristics.SENSOR_ORIENTATION: 90,
|
|
CameraCharacteristics.FLASH_INFO_AVAILABLE: True,
|
|
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL:
|
|
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
|
|
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP: {
|
|
"output_sizes": [(1920, 1080), (1280, 720), (640, 480)],
|
|
"input_sizes": [(1920, 1080)],
|
|
},
|
|
CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES: [(15, 30), (30, 30)],
|
|
CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES: [0, 1, 2, 3, 4],
|
|
CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES: [0, 1, 2, 3, 4, 5],
|
|
CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS: list(range(9)),
|
|
CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES: list(range(19)),
|
|
CameraCharacteristics.CONTROL_MAX_REGIONS_AE: 1,
|
|
CameraCharacteristics.CONTROL_MAX_REGIONS_AF: 1,
|
|
CameraCharacteristics.CONTROL_MAX_REGIONS_AWB: 0,
|
|
CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES: [(320, 240), (160, 120)],
|
|
CameraCharacteristics.JPEG_MAX_SIZE: 5000000,
|
|
CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE: (4032, 3024),
|
|
CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE: (4032, 3024),
|
|
}
|
|
|
|
def get(self, key: str) -> Any:
|
|
return self._properties.get(key)
|
|
|
|
def keys(self) -> Set[str]:
|
|
return set(self._properties.keys())
|
|
|
|
def query(self, key: str) -> Any:
|
|
return self._properties.get(key)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CameraId
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CameraId(Stub):
|
|
"""CameraId — 相机ID封装"""
|
|
|
|
def __init__(self, id_string: str):
|
|
super().__init__()
|
|
self._id = id_string
|
|
|
|
def getId(self) -> str:
|
|
return self._id
|
|
|
|
def toString(self) -> str:
|
|
return self._id
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, CameraId):
|
|
return self._id == other._id
|
|
if isinstance(other, str):
|
|
return self._id == other
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._id)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CameraCharacteristicsKey
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CameraCharacteristicsKey(Stub):
|
|
"""CameraCharacteristicsKey — 相机特性键"""
|
|
|
|
def __init__(self, name: str, native_type: type = object):
|
|
super().__init__()
|
|
self._name = name
|
|
self._native_type = native_type
|
|
|
|
def getName(self) -> str:
|
|
return self._name
|
|
|
|
def getNativeType(self) -> type:
|
|
return self._native_type
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, CameraCharacteristicsKey):
|
|
return self._name == other._name
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._name)
|
|
|
|
def toString(self) -> str:
|
|
return f"CameraCharacteristicsKey({self._name})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CaptureRequest
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CaptureRequest(CameraMetadata):
|
|
"""CaptureRequest — 捕获请求"""
|
|
|
|
CONTROL_AE_MODE = "android.control.aeMode"
|
|
CONTROL_AF_MODE = "android.control.afMode"
|
|
CONTROL_AWB_MODE = "android.control.awbMode"
|
|
CONTROL_MODE = "android.control.mode"
|
|
FLASH_MODE = "android.flash.mode"
|
|
SENSOR_EXPOSURE_TIME = "android.sensor.exposureTime"
|
|
SENSOR_SENSITIVITY = "android.sensor.sensitivity"
|
|
LENS_FOCUS_DISTANCE = "android.lens.focusDistance"
|
|
STATISTICS_FACE_DETECT_MODE = "android.statistics.faceDetectMode"
|
|
JPEG_QUALITY = "android.jpeg.quality"
|
|
JPEG_ORIENTATION = "android.jpeg.orientation"
|
|
JPEG_THUMBNAIL_QUALITY = "android.jpeg.thumbnailQuality"
|
|
JPEG_THUMBNAIL_SIZE = "android.jpeg.thumbnailSize"
|
|
SCALER_CROP_REGION = "android.scaler.cropRegion"
|
|
EDGE_MODE = "android.edge.mode"
|
|
NOISE_REDUCTION_MODE = "android.noiseReduction.mode"
|
|
TONEMAP_MODE = "android.tonemap.mode"
|
|
BLACK_LEVEL_LOCK = "android.blackLevel.lock"
|
|
CONTROL_AE_TARGET_FPS_RANGE = "android.control.aeTargetFpsRange"
|
|
CONTROL_AE_EXPOSURE_COMPENSATION = "android.control.aeExposureCompensation"
|
|
CONTROL_AE_LOCK = "android.control.aeLock"
|
|
CONTROL_AE_PRECAPTURE_TRIGGER = "android.control.aePrecaptureTrigger"
|
|
CONTROL_AWB_LOCK = "android.control.awbLock"
|
|
CONTROL_EFFECT_MODE = "android.control.effectMode"
|
|
CONTROL_SCENE_MODE = "android.control.sceneMode"
|
|
CONTROL_VIDEO_STABILIZATION_MODE = "android.control.videoStabilizationMode"
|
|
COLOR_CORRECTION_MODE = "android.colorCorrection.mode"
|
|
COLOR_CORRECTION_GAINS = "android.colorCorrection.gains"
|
|
COLOR_CORRECTION_TRANSFORM = "android.colorCorrection.transform"
|
|
COLOR_CORRECTION_ABERRATION_MODE = "android.colorCorrection.aberrationMode"
|
|
CONTROL_POST_RAW_SENSITIVITY_BOOST = "android.control.postRawSensitivityBoost"
|
|
DISTORTION_CORRECTION_MODE = "android.distortionCorrection.mode"
|
|
HOT_PIXEL_MODE = "android.hotPixel.mode"
|
|
LENS_OPTICAL_STABILIZATION_MODE = "android.lens.opticalStabilizationMode"
|
|
REQUEST_PIPELINE_MAX_DEPTH = "android.request.pipelineMaxDepth"
|
|
SENSOR_TIMESTAMP = "android.sensor.timestamp"
|
|
STATISTICS_LENS_SHADING_MAP_MODE = "android.statistics.lensShadingMapMode"
|
|
STATISTICS_OIS_DATA_MODE = "android.statistics.oisDataMode"
|
|
STATISTICS_SECTION = "android.statistics.section"
|
|
TONEMAP_CURVE = "android.tonemap.curve"
|
|
TONEMAP_GAMMA = "android.tonemap.gamma"
|
|
|
|
class Builder(Stub):
|
|
"""CaptureRequest.Builder — 捕获请求构建器"""
|
|
|
|
def __init__(self, camera_device: "CameraDevice"):
|
|
super().__init__()
|
|
self._parameters: Dict[str, Any] = {}
|
|
self._tag = None
|
|
self._camera_device = camera_device
|
|
|
|
def set(self, key: str, value: Any):
|
|
self._parameters[key] = value
|
|
|
|
def get(self, key: str) -> Any:
|
|
return self._parameters.get(key)
|
|
|
|
def setTag(self, tag: Any):
|
|
self._tag = tag
|
|
|
|
def build(self) -> "CaptureRequest":
|
|
req = CaptureRequest()
|
|
req._parameters = dict(self._parameters)
|
|
req._tag = self._tag
|
|
return req
|
|
|
|
def addTarget(self, surface):
|
|
pass
|
|
|
|
def removeTarget(self, surface):
|
|
pass
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._parameters: Dict[str, Any] = {
|
|
CaptureRequest.CONTROL_AE_MODE: CameraMetadata.CONTROL_AE_MODE_ON,
|
|
CaptureRequest.CONTROL_AF_MODE: CameraMetadata.CONTROL_AF_MODE_AUTO,
|
|
CaptureRequest.CONTROL_AWB_MODE: CameraMetadata.CONTROL_AWB_MODE_AUTO,
|
|
CaptureRequest.CONTROL_MODE: CameraMetadata.CONTROL_MODE_AUTO,
|
|
CaptureRequest.FLASH_MODE: CameraMetadata.FLASH_MODE_OFF,
|
|
CaptureRequest.JPEG_QUALITY: 95,
|
|
CaptureRequest.JPEG_ORIENTATION: 0,
|
|
}
|
|
self._tag = None
|
|
self._targets: List[Any] = []
|
|
|
|
def get(self, key: str) -> Any:
|
|
return self._parameters.get(key)
|
|
|
|
def keys(self) -> Set[str]:
|
|
return set(self._parameters.keys())
|
|
|
|
def getTag(self) -> Any:
|
|
return self._tag
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CaptureResult
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CaptureResult(CameraMetadata):
|
|
"""CaptureResult — 捕获结果"""
|
|
|
|
# Same keys as CaptureRequest
|
|
CONTROL_AE_MODE = CaptureRequest.CONTROL_AE_MODE
|
|
CONTROL_AF_MODE = CaptureRequest.CONTROL_AF_MODE
|
|
CONTROL_AWB_MODE = CaptureRequest.CONTROL_AWB_MODE
|
|
CONTROL_MODE = CaptureRequest.CONTROL_MODE
|
|
FLASH_MODE = CaptureRequest.FLASH_MODE
|
|
SENSOR_EXPOSURE_TIME = CaptureRequest.SENSOR_EXPOSURE_TIME
|
|
SENSOR_SENSITIVITY = CaptureRequest.SENSOR_SENSITIVITY
|
|
LENS_FOCUS_DISTANCE = CaptureRequest.LENS_FOCUS_DISTANCE
|
|
STATISTICS_FACE_DETECT_MODE = CaptureRequest.STATISTICS_FACE_DETECT_MODE
|
|
JPEG_QUALITY = CaptureRequest.JPEG_QUALITY
|
|
JPEG_ORIENTATION = CaptureRequest.JPEG_ORIENTATION
|
|
JPEG_THUMBNAIL_QUALITY = CaptureRequest.JPEG_THUMBNAIL_QUALITY
|
|
JPEG_THUMBNAIL_SIZE = CaptureRequest.JPEG_THUMBNAIL_SIZE
|
|
SCALER_CROP_REGION = CaptureRequest.SCALER_CROP_REGION
|
|
EDGE_MODE = CaptureRequest.EDGE_MODE
|
|
NOISE_REDUCTION_MODE = CaptureRequest.NOISE_REDUCTION_MODE
|
|
TONEMAP_MODE = CaptureRequest.TONEMAP_MODE
|
|
BLACK_LEVEL_LOCK = CaptureRequest.BLACK_LEVEL_LOCK
|
|
CONTROL_AE_TARGET_FPS_RANGE = CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE
|
|
CONTROL_AE_EXPOSURE_COMPENSATION = CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION
|
|
CONTROL_AE_LOCK = CaptureRequest.CONTROL_AE_LOCK
|
|
CONTROL_AE_PRECAPTURE_TRIGGER = CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER
|
|
CONTROL_AWB_LOCK = CaptureRequest.CONTROL_AWB_LOCK
|
|
CONTROL_EFFECT_MODE = CaptureRequest.CONTROL_EFFECT_MODE
|
|
CONTROL_SCENE_MODE = CaptureRequest.CONTROL_SCENE_MODE
|
|
CONTROL_VIDEO_STABILIZATION_MODE = CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE
|
|
COLOR_CORRECTION_MODE = CaptureRequest.COLOR_CORRECTION_MODE
|
|
COLOR_CORRECTION_GAINS = CaptureRequest.COLOR_CORRECTION_GAINS
|
|
COLOR_CORRECTION_TRANSFORM = CaptureRequest.COLOR_CORRECTION_TRANSFORM
|
|
COLOR_CORRECTION_ABERRATION_MODE = CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE
|
|
CONTROL_POST_RAW_SENSITIVITY_BOOST = CaptureRequest.CONTROL_POST_RAW_SENSITIVITY_BOOST
|
|
DISTORTION_CORRECTION_MODE = CaptureRequest.DISTORTION_CORRECTION_MODE
|
|
HOT_PIXEL_MODE = CaptureRequest.HOT_PIXEL_MODE
|
|
LENS_OPTICAL_STABILIZATION_MODE = CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE
|
|
REQUEST_PIPELINE_MAX_DEPTH = CaptureRequest.REQUEST_PIPELINE_MAX_DEPTH
|
|
SENSOR_TIMESTAMP = CaptureRequest.SENSOR_TIMESTAMP
|
|
STATISTICS_LENS_SHADING_MAP_MODE = CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE
|
|
STATISTICS_OIS_DATA_MODE = CaptureRequest.STATISTICS_OIS_DATA_MODE
|
|
STATISTICS_SECTION = CaptureRequest.STATISTICS_SECTION
|
|
TONEMAP_CURVE = CaptureRequest.TONEMAP_CURVE
|
|
TONEMAP_GAMMA = CaptureRequest.TONEMAP_GAMMA
|
|
|
|
def __init__(self, request: CaptureRequest = None):
|
|
super().__init__()
|
|
self._results: Dict[str, Any] = {
|
|
CaptureResult.CONTROL_AE_MODE: CameraMetadata.CONTROL_AE_MODE_ON,
|
|
CaptureResult.CONTROL_AF_MODE: CameraMetadata.CONTROL_AF_MODE_AUTO,
|
|
CaptureResult.CONTROL_AWB_MODE: CameraMetadata.CONTROL_AWB_MODE_AUTO,
|
|
CaptureResult.CONTROL_MODE: CameraMetadata.CONTROL_MODE_AUTO,
|
|
CaptureResult.FLASH_MODE: CameraMetadata.FLASH_MODE_OFF,
|
|
CaptureResult.SENSOR_EXPOSURE_TIME: 33333333,
|
|
CaptureResult.SENSOR_SENSITIVITY: 100,
|
|
CaptureResult.SENSOR_TIMESTAMP: int(time.time() * 1e9),
|
|
}
|
|
self._request = request
|
|
self._sequence_id = -1
|
|
self._frame_number = -1
|
|
|
|
def get(self, key: str) -> Any:
|
|
return self._results.get(key)
|
|
|
|
def keys(self) -> Set[str]:
|
|
return set(self._results.keys())
|
|
|
|
def getRequest(self) -> Optional[CaptureRequest]:
|
|
return self._request
|
|
|
|
def getSequenceId(self) -> int:
|
|
return self._sequence_id
|
|
|
|
def getFrameNumber(self) -> int:
|
|
return self._frame_number
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# TotalCaptureResult
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class TotalCaptureResult(CaptureResult):
|
|
"""TotalCaptureResult — 完整捕获结果"""
|
|
|
|
def __init__(self, request: CaptureRequest = None,
|
|
partial_results: List[CaptureResult] = None):
|
|
super().__init__(request)
|
|
self._partial_results = partial_results or []
|
|
|
|
def getPartialResults(self) -> List[CaptureResult]:
|
|
return list(self._partial_results)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CameraCaptureSession
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CameraCaptureSession(Stub):
|
|
"""CameraCaptureSession — 捕获会话"""
|
|
|
|
class StateCallback(Stub):
|
|
"""CameraCaptureSession.StateCallback — 会话状态回调"""
|
|
|
|
def onConfigured(self, session: "CameraCaptureSession"):
|
|
pass
|
|
|
|
def onConfigureFailed(self, session: "CameraCaptureSession"):
|
|
pass
|
|
|
|
def onReady(self, session: "CameraCaptureSession"):
|
|
pass
|
|
|
|
def onActive(self, session: "CameraCaptureSession"):
|
|
pass
|
|
|
|
def onClosed(self, session: "CameraCaptureSession"):
|
|
pass
|
|
|
|
def onSurfacePrepared(self, session: "CameraCaptureSession", surface):
|
|
pass
|
|
|
|
class CaptureCallback(Stub):
|
|
"""CameraCaptureSession.CaptureCallback — 捕获回调"""
|
|
|
|
def onCaptureStarted(self, session: "CameraCaptureSession", request: CaptureRequest,
|
|
timestamp: int, frameNumber: int):
|
|
pass
|
|
|
|
def onCaptureCompleted(self, session: "CameraCaptureSession", request: CaptureRequest,
|
|
result: TotalCaptureResult):
|
|
pass
|
|
|
|
def onCaptureFailed(self, session: "CameraCaptureSession", request: CaptureRequest,
|
|
failure):
|
|
pass
|
|
|
|
def onCaptureProgressed(self, session: "CameraCaptureSession", request: CaptureRequest,
|
|
result: CaptureResult):
|
|
pass
|
|
|
|
def onCaptureSequenceCompleted(self, session: "CameraCaptureSession",
|
|
sequenceId: int, frameNumber: int):
|
|
pass
|
|
|
|
def onCaptureSequenceAborted(self, session: "CameraCaptureSession", sequenceId: int):
|
|
pass
|
|
|
|
def onCaptureBufferLost(self, session: "CameraCaptureSession", request: CaptureRequest,
|
|
target, frameNumber: int):
|
|
pass
|
|
|
|
def __init__(self, device: "CameraDevice"):
|
|
super().__init__()
|
|
self._device = device
|
|
self._closed = False
|
|
self._repeating_request = None
|
|
self._state_callback = None
|
|
self._session_id = int(time.time() * 1000)
|
|
|
|
def capture(self, request: CaptureRequest, callback: CaptureCallback = None,
|
|
handler=None) -> int:
|
|
seq_id = int(time.time() * 1000)
|
|
result = TotalCaptureResult(request)
|
|
if callback:
|
|
callback.onCaptureStarted(self, request, int(time.time() * 1e9), 0)
|
|
callback.onCaptureCompleted(self, request, result)
|
|
callback.onCaptureSequenceCompleted(self, seq_id, 0)
|
|
return seq_id
|
|
|
|
def setRepeatingRequest(self, request: CaptureRequest, callback: CaptureCallback = None,
|
|
handler=None) -> int:
|
|
self._repeating_request = request
|
|
seq_id = int(time.time() * 1000)
|
|
result = TotalCaptureResult(request)
|
|
if callback:
|
|
callback.onCaptureStarted(self, request, int(time.time() * 1e9), 0)
|
|
callback.onCaptureCompleted(self, request, result)
|
|
return seq_id
|
|
|
|
def stopRepeatingRequest(self) -> None:
|
|
self._repeating_request = None
|
|
|
|
def abortCaptures(self) -> None:
|
|
pass
|
|
|
|
def close(self):
|
|
self._closed = True
|
|
|
|
def getDevice(self) -> "CameraDevice":
|
|
return self._device
|
|
|
|
def isClosed(self) -> bool:
|
|
return self._closed
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CameraDevice
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CameraDevice(Stub):
|
|
"""CameraDevice — 相机设备"""
|
|
|
|
STATE_OPENED = 0
|
|
STATE_CLOSED = 3
|
|
STATE_DISCONNECTED = 1
|
|
STATE_ERROR = 2
|
|
|
|
class StateCallback(Stub):
|
|
"""CameraDevice.StateCallback — 设备状态回调"""
|
|
|
|
def onOpened(self, device: "CameraDevice"):
|
|
pass
|
|
|
|
def onClosed(self, device: "CameraDevice"):
|
|
pass
|
|
|
|
def onDisconnected(self, device: "CameraDevice"):
|
|
pass
|
|
|
|
def onError(self, device: "CameraDevice", error: int):
|
|
pass
|
|
|
|
def __init__(self, camera_id: str = "0"):
|
|
super().__init__()
|
|
self._id = camera_id
|
|
self._state = CameraDevice.STATE_OPENED
|
|
self._state_callback = None
|
|
self._sessions: List[CameraCaptureSession] = []
|
|
|
|
def getId(self) -> str:
|
|
return self._id
|
|
|
|
def createCaptureRequest(self, templateType: int) -> CaptureRequest.Builder:
|
|
return CaptureRequest.Builder(self)
|
|
|
|
def createCaptureSession(self, outputs: List[Any],
|
|
callback: CameraCaptureSession.StateCallback,
|
|
handler=None):
|
|
session = CameraCaptureSession(self)
|
|
session._state_callback = callback
|
|
self._sessions.append(session)
|
|
if callback:
|
|
callback.onConfigured(session)
|
|
return session
|
|
|
|
def close(self):
|
|
self._state = CameraDevice.STATE_CLOSED
|
|
for session in self._sessions:
|
|
session.close()
|
|
|
|
def getState(self) -> int:
|
|
return self._state
|
|
|
|
def toString(self) -> str:
|
|
return f"CameraDevice@{self._id}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CameraManager
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CameraManager(Stub):
|
|
"""CameraManager — 相机管理器"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._cameras: Dict[str, CameraCharacteristics] = {
|
|
"0": CameraCharacteristics("0"),
|
|
}
|
|
self._open_devices: Dict[str, CameraDevice] = {}
|
|
self._availability_callbacks: List[Any] = []
|
|
self._torch_callbacks: List[Any] = []
|
|
|
|
def getCameraIdList(self) -> List[str]:
|
|
return list(self._cameras.keys())
|
|
|
|
def getCameraCharacteristics(self, cameraId: str) -> CameraCharacteristics:
|
|
if cameraId not in self._cameras:
|
|
raise AndroidOnlyError(f"Camera {cameraId} not available")
|
|
return self._cameras[cameraId]
|
|
|
|
def openCamera(self, cameraId: str, callback: CameraDevice.StateCallback,
|
|
handler=None):
|
|
if cameraId not in self._cameras:
|
|
if callback:
|
|
callback.onError(None, CameraDevice.STATE_ERROR)
|
|
return
|
|
device = CameraDevice(cameraId)
|
|
self._open_devices[cameraId] = device
|
|
if callback:
|
|
callback.onOpened(device)
|
|
|
|
def registerAvailabilityCallback(self, callback):
|
|
self._availability_callbacks.append(callback)
|
|
|
|
def unregisterAvailabilityCallback(self, callback):
|
|
if callback in self._availability_callbacks:
|
|
self._availability_callbacks.remove(callback)
|
|
|
|
def registerTorchCallback(self, callback, handler=None):
|
|
self._torch_callbacks.append(callback)
|
|
|
|
def unregisterTorchCallback(self, callback):
|
|
if callback in self._torch_callbacks:
|
|
self._torch_callbacks.remove(callback)
|
|
|
|
def setTorchMode(self, cameraId: str, enabled: bool):
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CameraOfflineSession
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CameraOfflineSession(CameraCaptureSession):
|
|
"""CameraOfflineSession — 离线会话 (API 30+)"""
|
|
|
|
def __init__(self, device: CameraDevice):
|
|
super().__init__(device)
|
|
|
|
def switchToOffline(self):
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CameraExtensionSession
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CameraExtensionSession(Stub):
|
|
"""CameraExtensionSession — 扩展会话 (API 31+)"""
|
|
|
|
class StateCallback(Stub):
|
|
def onConfigured(self, session: "CameraExtensionSession"):
|
|
pass
|
|
|
|
def onConfigureFailed(self, session: "CameraExtensionSession"):
|
|
pass
|
|
|
|
def onClosed(self, session: "CameraExtensionSession"):
|
|
pass
|
|
|
|
class ExtensionCaptureCallback(Stub):
|
|
def onCaptureStarted(self, session: "CameraExtensionSession", request: CaptureRequest,
|
|
timestamp: int):
|
|
pass
|
|
|
|
def onCaptureProcessStarted(self, session: "CameraExtensionSession", request: CaptureRequest):
|
|
pass
|
|
|
|
def onCaptureFailed(self, session: "CameraExtensionSession", request: CaptureRequest):
|
|
pass
|
|
|
|
def onCaptureResultAvailable(self, session: "CameraExtensionSession",
|
|
request: CaptureRequest, result: TotalCaptureResult):
|
|
pass
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._closed = False
|
|
|
|
def close(self):
|
|
self._closed = True
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# __all__
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
__all__ = [
|
|
"CameraManager", "CameraDevice", "CameraCaptureSession",
|
|
"CaptureRequest", "CaptureResult", "CameraCharacteristics",
|
|
"CameraMetadata", "CameraId", "CameraCharacteristicsKey",
|
|
"TotalCaptureResult", "CameraOfflineSession", "CameraExtensionSession",
|
|
] |