B4A=true Group=Default Group ModulesStructureVersion=1 Type=Class Version=7.3 @EndOfDesignText@ 'Version: 1.30 Sub Class_Globals Public Camera As Camera2 Private jcamera As JavaObject Private id As String Private mFront As Boolean = False Public PreviewSize, CaptureSize As CameraSize Public PreviewSettingsMap, CaptureSettingMap As Map Private bothMaps As List Private mPanel As Panel Private tv As View Private StaticCaptureRequest As JavaObject Private StaticCameraCharacteristics As JavaObject Private StaticCaptureResult As JavaObject Private AF_STATE As List = Array("INACTIVE", "PASSIVE_SCAN", "PASSIVE_FOCUSED", "ACTIVE_SCAN", "FOCUSED_LOCKED", "NOT_FOCUSED_LOCKED", "PASSIVE_UNFOCUSED") Private FLASH_STATE As List = Array("UNAVAILABLE", "CHARGING", "READY", "FIRED", "PARTIAL") 'ignore 'auto exposure Private AF_MODE As List = Array("OFF", "AUTO", "MACRO", "CONTINUOUS_VIDEO", "CONTINUOUS_PICTURE", "EDOF") 'flash Private AE_MODE As List = Array("OFF", "ON", "ON_AUTO_FLASH", "ON_ALWAYS_FLASH", "ON_AUTO_FLASH_REDEYE") Private FLASH_MODE As List = Array("OFF", "SINGLE", "TORCH") Private SCENE_MODE As List = Array("DISABLED", "FACE_PRIORITY", "ACTION", "PORTRAIT", "LANDSCAPE", "NIGHT", "PORTRAIT", "THEATRE", "BEACH", "SNOW", "SUNSET", _ "STEADYPHOTO", "FIREWORKS", "SPORTS", "PARTY", "CANDLELIGHT", "BARCODE", "HIGH_SPEED_VIDEO", "MODE_HDR", "FACE_PRIORITY_LOW_LIGHT") Private EFFECT_MODE As List = Array("OFF", "MONO", "NEGATIVE", "SOLARIZE", "SEPIA", "POSTERIZE", "WHITEBOARD", "BLACKBOARD", "AQUA") Private SUPPORTED_HARDWARE_LEVEL As List = Array("LIMITED", "FULL", "LEGACY", "LEVEL_3") Private CONTROL_MODE As List = Array("OFF", "AUTO", "USE_SCENE_MODE", "OFF_KEEP_STATE") Public PrintKeys As Boolean = False Private PreviewRequest As JavaObject Private FocusState As String Private MediaRecorder As JavaObject Public RecordingVideo As Boolean Public TaskIndex As Int = 1 End Sub Public Sub Initialize (CameraPanel As Panel) mPanel = CameraPanel Camera.Initialize("Camera") jcamera = Camera PreviewSize.Initialize(640, 480) CaptureSize.Initialize(1920, 1080) StaticCaptureRequest.InitializeStatic("android.hardware.camera2.CaptureRequest") StaticCameraCharacteristics.InitializeStatic("android.hardware.camera2.CameraCharacteristics") StaticCaptureResult.InitializeStatic("android.hardware.camera2.CaptureResult") PreviewSettingsMap.Initialize CaptureSettingMap.Initialize bothMaps = Array(PreviewSettingsMap, CaptureSettingMap) End Sub 'Opens the camera and returns the "TaskIndex" number. You need to keep it and use it in future calls. 'Returns 0 if failed to open the camera. Public Sub OpenCamera (Front As Boolean) As ResumableSub TaskIndex = TaskIndex + 1 If Camera.IsCameraOpen Then Stop End If mFront = Front id = Camera.FindCameraId(mFront) If id = "" Then Log("Camera not found.") id = Camera.CameraIDs(0) End If Camera.OpenCamera(id) Wait For Camera_CameraState (Open As Boolean) If Open = False Then Log("Failed to open camera") Return 0 End If If PrintKeys Then PrintAllKeys(Camera.GetCameraCharacteristics(id), "Camera Characteristics") Return TaskIndex End Sub Private Sub CloseSession Dim session As JavaObject = jcamera.GetFieldJO("captureSession") If session.IsInitialized Then session.RunMethod("stopRepeating", Null) session.RunMethod("abortCaptures", Null) jcamera.SetField("captureSession", Null) End If End Sub Public Sub getSupportedHardwareLevel As String Dim jo As JavaObject = Camera.GetCameraCharacteristics(0) Return IntToConst(jo.RunMethod("get", Array(StaticCameraCharacteristics.GetField("INFO_SUPPORTED_HARDWARE_LEVEL"))), SUPPORTED_HARDWARE_LEVEL) End Sub 'Prepared the surface for still capture. Public Sub PrepareSurface (MyTaskIndex As Int) As ResumableSub If MyTaskIndex <> TaskIndex Then Return False CloseSession Wait For (CreateSurface) Complete (Result As Boolean) If MyTaskIndex <> TaskIndex Then Return False Camera.StartSession(tv, PreviewSize, CaptureSize, 256, 0, False) '256 = JPEG Wait For Camera_SessionConfigured (Success As Boolean) If MyTaskIndex <> TaskIndex Then Return False Return Success End Sub 'Prepares the surface for video capture. 'Need to add this line to the manifest editor: 'AddPermission(android.permission.RECORD_AUDIO) Public Sub PrepareSurfaceForVideo (MyTaskIndex As Int, Dir As String, FileName As String) As ResumableSub If MyTaskIndex <> TaskIndex Then Return False CloseSession Wait For (CreateSurface) Complete (Result As Boolean) If MyTaskIndex <> TaskIndex Then Return False File.Delete(Dir, FileName) MediaRecorder = Camera.CreateMediaRecorder(PreviewSize, Dir, FileName) MediaRecorder.RunMethod("setOrientationHint", Array(GetHintOrientation)) Camera.StartSession(tv, PreviewSize, CaptureSize, 0, 0, True) Wait For Camera_SessionConfigured (Success As Boolean) If MyTaskIndex <> TaskIndex Then Return False Return Success End Sub Private Sub GetHintOrientation As Int Dim SensorOrientation As Int = GetFromCameraCharacteristic("SENSOR_ORIENTATION") Dim front As Int = -1 If getIsFrontFacingCamera Then front = 1 Dim orientation As Int = (SensorOrientation + jcamera.GetField("lastKnownOrientation") * front + 360) Mod 360 Return orientation End Sub 'Startd recording. Public Sub StartVideoRecording (MyTaskIndex As Int) If MyTaskIndex <> TaskIndex Then Return MediaRecorder.RunMethod("start", Null) RecordingVideo = True End Sub 'Stops recording. Need to prepare the surface again. Public Sub StopVideoRecording (MyTaskIndex As Int) CloseSession Try MediaRecorder.RunMethod("stop", Null) Catch Log(LastException) End Try RecordingVideo = False End Sub Private Sub CreateSurface As ResumableSub If tv.IsInitialized Then tv.RemoveView tv = Camera.CreateSurface mPanel.AddView(tv, 0, 0, mPanel.Width, mPanel.Height) tv.SendToBack Wait For Camera_SurfaceReady Return True End Sub 'Starts the preview. Public Sub StartPreview (MyTaskIndex As Int, VideoRecording As Boolean) Dim PreviewBuilder As JavaObject If VideoRecording Then PreviewBuilder = Camera.CreateVideoRequestBuilder Else PreviewBuilder = Camera.CreatePreviewBuilder End If SetSettingsFromMap(PreviewBuilder, PreviewSettingsMap) PreviewRequest = Camera.SetRepeatingRequest(PreviewBuilder) If PrintKeys Then PrintAllKeys(PreviewRequest, "Preview Capture Request") End Sub 'Gets the supported preview sizes. Public Sub getSupportedPreviewSizes As List Return Camera.GetSupportedPreviewSizes(id) End Sub 'Gets the supported capture sizes. Public Sub getSupportedCaptureSizes As List Return Camera.GetSupportedCaptureSizes(id) End Sub Public Sub getSupportedVideoSizes As List Return Camera.GetSupportedVideoSizes(id) End Sub 'Gets the supported scene modes. Public Sub getSupportedSceneModes As List Return RemoveDuplicates(IntsToConstsList(GetFromCameraCharacteristic("CONTROL_AVAILABLE_SCENE_MODES"), SCENE_MODE)) End Sub 'Gets or sets the scene mode (one of the SCENE_MODE values). Call StartPreview to apply changes. Public Sub setSceneMode(Mode As String) SetBothMaps("CONTROL_SCENE_MODE", SCENE_MODE.IndexOf(Mode)) End Sub Public Sub getSceneMode As String Return IntToConst(GetFromCaptureRequest(PreviewRequest, "CONTROL_SCENE_MODE"), SCENE_MODE) End Sub 'Gets or sets the applied effect (one of the EFFECT_MODE values). Call StartPreview to apply changes. Public Sub setEffectMode(Mode As String) SetBothMaps("CONTROL_EFFECT_MODE", EFFECT_MODE.IndexOf(Mode)) End Sub Public Sub getEffectMode As String Return IntToConst(GetFromCaptureRequest(PreviewRequest, "CONTROL_EFFECT_MODE"), EFFECT_MODE) End Sub 'Returns the supported effects modes. Public Sub getSupportedEffectModes As List Return IntsToConstsList(GetFromCameraCharacteristic("CONTROL_AVAILABLE_EFFECTS"), EFFECT_MODE) End Sub 'Returns the supported focus modes. Best mode in most cases is CONTINUOUS_PICTURE. Public Sub getSupportedFocusModes As List Return RemoveDuplicates(IntsToConstsList(GetFromCameraCharacteristic("CONTROL_AF_AVAILABLE_MODES"), AF_MODE)) End Sub Private Sub RemoveDuplicates(Raw As List) As List Dim unique As Map unique.Initialize For Each f As String In Raw unique.Put(f, "") Next Raw.Clear For Each f As String In unique.Keys Raw.Add(f) Next Return Raw End Sub 'Gets or sets the focus mode (one of the AF_MODE values). Call StartPreview to apply changes. Public Sub getFocusMode As String Return IntToConst(GetFromCaptureRequest(PreviewRequest, "CONTROL_AF_MODE"), AF_MODE) End Sub Public Sub setFocusMode(mode As String) SetBothMaps("CONTROL_AF_MODE", AF_MODE.IndexOf(mode)) End Sub 'Gets the maximum value of the digital zoom. Public Sub getMaxDigitalZoom As Float Return GetFromCameraCharacteristic("SCALER_AVAILABLE_MAX_DIGITAL_ZOOM") End Sub 'Gets the supported auto exposure modes. Public Sub getSupportedAutoExposureModes As List Return IntsToConstsList(GetFromCameraCharacteristic("CONTROL_AE_AVAILABLE_MODES"), AE_MODE) End Sub 'Gets or sets the auto exposure mode (one of the AE_MODE values). Call StartPreview to apply changes. Public Sub getAutoExposureMode As String Return IntToConst(GetFromCaptureRequest(PreviewRequest, "CONTROL_AE_MODE"), AE_MODE) End Sub Public Sub getControlMode As String Return IntToConst(GetFromCaptureRequest(PreviewRequest, "CONTROL_MODE"), CONTROL_MODE) End Sub Public Sub setAutoExposureMode (Mode As String) SetBothMaps("CONTROL_AE_MODE", AE_MODE.IndexOf(Mode)) PreviewSettingsMap.Put("FLASH_MODE", FLASH_MODE.IndexOf("OFF")) If Mode = "ON_ALWAYS_FLASH" Then CaptureSettingMap.Put("FLASH_MODE", FLASH_MODE.IndexOf("SINGLE")) End If End Sub 'Sets the preview region. Public Sub setPreviewCropRegion(r As Rect) PreviewSettingsMap.Put("SCALER_CROP_REGION", r) End Sub 'Gets the image sensor region. Public Sub getActiveArraySize As Rect Return GetFromCameraCharacteristic("SENSOR_INFO_ACTIVE_ARRAY_SIZE") End Sub Private Sub SetBothMaps(Key As String, Value As Object) For Each m As Map In bothMaps m.Put(Key, Value) Next End Sub 'Triggers the auto focus feature and then takes a picture. Public Sub FocusAndTakePicture (MyTaskIndex As Int) As ResumableSub Dim PreviewFocusMode As String = AF_MODE.Get(GetFromCaptureRequest(PreviewRequest, "CONTROL_AF_MODE")) Dim PreviewAEMode As String = AE_MODE.Get(GetFromCaptureRequest(PreviewRequest, "CONTROL_AE_MODE")) If PreviewFocusMode = "OFF" Or PreviewFocusMode = "EDOF" Then Log("Focus not supported") Else if PreviewFocusMode.Contains("CONTINUOUS") = False Or PreviewAEMode = "ON_ALWAYS_FLASH" Then Dim PreviewBuilder As JavaObject = Camera.CreatePreviewBuilder PreviewSettingsMap.Put("CONTROL_AF_TRIGGER", 1) 'CONTROL_AF_TRIGGER_START SetSettingsFromMap(PreviewBuilder, PreviewSettingsMap) Camera.AddCaptureRequest(PreviewBuilder) Wait For (WaitForFocusWithTimeout(5000)) Complete (Success As Boolean) If Success = False Then Log("Focus failed") Else Log("Focused!") End If Wait For (TakePictureNow(MyTaskIndex)) Complete (data() As Byte) Dim PreviewBuilder As JavaObject = Camera.CreatePreviewBuilder PreviewSettingsMap.Put("CONTROL_AF_TRIGGER", 2) 'CONTROL_AF_TRIGGER_CANCEL SetSettingsFromMap(PreviewBuilder, PreviewSettingsMap) Camera.AddCaptureRequest(PreviewBuilder) PreviewSettingsMap.Remove("CONTROL_AF_TRIGGER") Wait For (PreviewBuilder) Camera_CaptureComplete (CaptureResult As Object) Return data End If Wait For (TakePictureNow(MyTaskIndex)) Complete (data() As Byte) Return data End Sub Private Sub WaitForFocusWithTimeout (TimeoutMs As Int) As ResumableSub Dim start As Long = DateTime.Now Do Until FocusState = "FOCUSED_LOCKED" Or FocusState = "NOT_FOCUSED_LOCKED" Sleep(50) If DateTime.Now - start > TimeoutMs Then Return False Loop Return FocusState = "FOCUSED_LOCKED" End Sub Private Sub Camera_PreviewCaptureComplete (CaptureResult As Object) FocusState = IntToConst(GetFromCaptureResult(CaptureResult, "CONTROL_AF_STATE"), AF_STATE) 'Log(IntToConst(GetFromCaptureResult(CaptureResult, "FLASH_STATE"), FLASH_STATE)) ' PrintAllKeys(CaptureResult, "Capture Result") End Sub 'Takes a picture now. Without waiting for the picture to be focused. Public Sub TakePictureNow (MyTaskIndex As Int) As ResumableSub If MyTaskIndex <> TaskIndex Then Return False Camera.AbortCaptures Dim builder As JavaObject = Camera.CreateCaptureBuilder CaptureSettingMap.Put("JPEG_ORIENTATION", GetHintOrientation) SetSettingsFromMap(builder, CaptureSettingMap) Dim CaptureRequest As Object = Camera.AddCaptureRequest(builder) If PrintKeys Then PrintAllKeys(CaptureRequest, "Capture Request") Wait For Camera_PictureTaken (Data() As Byte) StartPreview(MyTaskIndex, False) Return Data End Sub 'Private Sub Camera_PreviewTaken (Image As Object) ' Log(Image) 'End Sub 'Takes multiple pictures. Should be called like this: 'Wait For(cam.TakePicturesNow(MyTaskIndex, 9)) Complete (Pictures As List) Public Sub TakePicturesNow (MyTaskIndex As Int, NumberOfPictures As Int) As ResumableSub If MyTaskIndex <> TaskIndex Then Return False Camera.AbortCaptures Dim builder As JavaObject = Camera.CreateCaptureBuilder CaptureSettingMap.Put("JPEG_ORIENTATION", GetHintOrientation) SetSettingsFromMap(builder, CaptureSettingMap) Dim result As List result.Initialize For i = 1 To NumberOfPictures Camera.AddCaptureRequest(builder) Next For i = 1 To NumberOfPictures Wait For Camera_PictureTaken (Data() As Byte) result.Add(Data) Next StartPreview(MyTaskIndex, False) Return result End Sub 'Gets a Bitmap object from the preview stream. 'Returns an uninitialized bitmap if not available. Public Sub GetPreviewBitmap(Width As Int, Height As Int) As Bitmap Dim mbmp As Bitmap mbmp.InitializeMutable(Width, Height) Dim jo As JavaObject = tv Return jo.RunMethod("getBitmap", Array(mbmp)) End Sub 'Converts the data to a bitmap. Public Sub DataToBitmap(Data() As Byte) As Bitmap Dim in As InputStream in.InitializeFromBytesArray(Data, 0, Data.Length) Dim bmp As Bitmap bmp.Initialize2(in) in.Close Return bmp End Sub 'Saves the data to a file. Public Sub DataToFile(Data() As Byte, Dir As String, FileName As String) Dim out As OutputStream = File.OpenOutput(Dir, FileName, False) out.WriteBytes(Data, 0, Data.Length) out.Close End Sub 'Returns true if the camera is a front camera Public Sub getIsFrontFacingCamera As Boolean Return 0 = GetFromCameraCharacteristic("LENS_FACING") End Sub Private Sub GetFromCameraCharacteristic (Field As String) As Object Dim jo As JavaObject = Camera.GetCameraCharacteristics(id) Return jo.RunMethod("get", Array(StaticCameraCharacteristics.GetField(Field))) End Sub Private Sub GetFromCaptureResult(CaptureResult As Object, Field As String) As Object Dim jresult As JavaObject = CaptureResult Return jresult.RunMethod("get", Array(StaticCaptureResult.GetField(Field))) End Sub Private Sub GetFromCaptureRequest(CaptureRequest As Object, Field As String) As Object Dim jo As JavaObject = CaptureRequest Return jo.RunMethod("get", Array(StaticCaptureRequest.GetField(Field))) End Sub Private Sub IntToConst (Int1 As Object, Consts As List) As String If Int1 = Null Then Return "" Dim i As Int = Int1 If i >= 0 And i < Consts.Size Then Return Consts.Get(i) Else Log(Consts)'ignore Log("Unknown const: " & i) Return "" End If End Sub Private Sub IntsToConstsList (Ints As Object, Consts As List) As List Dim res As List res.Initialize If Ints = Null Then Return res Dim f() As Int = Ints For Each mode As Int In f If mode >=0 And mode < Consts.Size Then res.Add(Consts.Get(mode)) Else Log(Consts) 'ignore Log("Unknown consts: " & mode) End If Next Return res End Sub Private Sub SetSettingsFromMap (Builder As JavaObject, m As Map) For Each key As String In m.Keys Builder.RunMethod("set", Array(StaticCaptureRequest.GetField(key), m.Get(key))) Next End Sub Public Sub Stop RecordingVideo = False Camera.Stop TaskIndex = TaskIndex + 1 End Sub #Region Not interesting Private Sub PrintAllKeys (CameraMap As Object, title As String) 'ignore Log($"****** ${title} **********"$) Dim jo As JavaObject = CameraMap Dim keys As List = jo.RunMethod("getKeys", Null) For Each k As JavaObject In keys Dim value As Object = jo.RunMethod("get", Array(k)) If value = Null Then Continue Dim typ As String = GetType(value) If typ = "[F" Then value = FloatsToList(value) Else If typ = "[I" Then value = IntsToList(value) Else If typ = "[Z" Then value = BoolsToList(value) Else If typ = "[B" Then value = BytesToList(value) Else if typ.StartsWith("[") Then value = ObjectsToList(value) End If Log($"${k.RunMethod("getName", Null)}: ${value}"$) Next End Sub Private Sub ObjectsToList(Obj As Object) As List Dim res As List res.Initialize If Obj = Null Then Return res Dim o() As Object = Obj For Each oo As Object In o res.Add(oo) Next Return res End Sub Private Sub BoolsToList (Obj As Object) As List Dim res As List res.Initialize If Obj = Null Then Return res Dim i() As Boolean = Obj For Each ii As Boolean In i res.Add(ii) Next Return res End Sub Private Sub BytesToList (Obj As Object) As List Dim res As List res.Initialize If Obj = Null Then Return res Dim i() As Byte = Obj For Each ii As Byte In i res.Add(ii) Next Return res End Sub Private Sub IntsToList (Obj As Object) As List Dim res As List res.Initialize If Obj = Null Then Return res Dim i() As Int = Obj For Each ii As Int In i res.Add(ii) Next Return res End Sub Private Sub FloatsToList (Obj As Object) As List Dim res As List res.Initialize If Obj = Null Then Return res Dim f() As Float = Obj For Each ff As Float In f res.Add(ff) Next Return res End Sub #End Region