Created
December 23, 2021 13:49
-
-
Save naveenrobo/7ab5137778d84ed826267da759cf7eb5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.annotation.TargetApi | |
import android.content.Context | |
import android.graphics.ImageFormat | |
import android.hardware.Camera | |
import android.hardware.camera2.CameraCharacteristics | |
import android.hardware.camera2.CameraManager | |
import android.hardware.camera2.CameraMetadata | |
import android.os.Build | |
import android.util.Log | |
import com.twilio.video.Camera2Capturer | |
import com.twilio.video.CameraCapturer | |
import com.twilio.video.VideoCapturer | |
import dev.dotworld.mdm.utils.Utils | |
import tvi.webrtc.Camera1Enumerator | |
import tvi.webrtc.CapturerObserver | |
import tvi.webrtc.SurfaceTextureHelper | |
import java.util.* | |
/* | |
* Simple wrapper class that uses Camera2Capturer with supported devices. | |
*/ | |
class CameraCapturerCompat(context: Context, cameraId: String) : VideoCapturer { | |
private val camera1Capturer: CameraCapturer? | |
private val camera2Capturer: Camera2Capturer? | |
private val activeCapturer: VideoCapturer | |
private val camera1IdMap: MutableMap<Source, String> = EnumMap(Source::class.java) | |
private val camera1SourceMap: MutableMap<String, Source> = HashMap() | |
enum class Source { | |
FRONT_CAMERA, BACK_CAMERA | |
} | |
override fun initialize( | |
surfaceTextureHelper: SurfaceTextureHelper, | |
context: Context, | |
capturerObserver: CapturerObserver | |
) { | |
activeCapturer.initialize(surfaceTextureHelper, context, capturerObserver) | |
} | |
override fun startCapture(width: Int, height: Int, framerate: Int) { | |
activeCapturer.startCapture(width, height, framerate) | |
} | |
@Throws(InterruptedException::class) | |
override fun stopCapture() { | |
activeCapturer.stopCapture() | |
} | |
override fun isScreencast(): Boolean { | |
return activeCapturer.isScreencast | |
} | |
override fun dispose() { | |
activeCapturer.dispose() | |
} | |
private fun usingCamera1(): Boolean { | |
return camera1Capturer != null | |
} | |
@TargetApi(Build.VERSION_CODES.LOLLIPOP) | |
private fun isCameraIdSupported(context: Context, cameraId: String): Boolean { | |
var isMonoChromeSupported = false | |
var isPrivateImageFormatSupported = false | |
val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager | |
val cameraCharacteristics: CameraCharacteristics = try { | |
cameraManager.getCameraCharacteristics(cameraId) | |
} catch (e: Exception) { | |
e.printStackTrace() | |
return false | |
} | |
/* | |
* This is a temporary work around for a RuntimeException that occurs on devices which contain cameras | |
* that do not support ImageFormat.PRIVATE output formats. A long term fix is currently in development. | |
* https://github.com/twilio/video-quickstart-android/issues/431 | |
*/ | |
val streamMap = | |
cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) | |
if (streamMap != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | |
isPrivateImageFormatSupported = streamMap.isOutputSupportedFor(ImageFormat.PRIVATE) | |
} | |
/* | |
* Read the color filter arrangements of the camera to filter out the ones that support | |
* SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO or SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR. | |
* Visit this link for details on supported values - https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT | |
*/ | |
val colorFilterArrangement = cameraCharacteristics.get( | |
CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT | |
) | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && colorFilterArrangement != null) { | |
isMonoChromeSupported = (colorFilterArrangement | |
== CameraMetadata.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO || | |
colorFilterArrangement | |
== CameraMetadata.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR) | |
} | |
return isPrivateImageFormatSupported && !isMonoChromeSupported | |
} | |
init { | |
if (Camera2Capturer.isSupported(context) && isCameraIdSupported( | |
context, | |
cameraId | |
) && Utils.isLollipopApiSupported | |
) { | |
Log.i(TAG, "Camera 2: ") | |
camera2Capturer = Camera2Capturer(context, cameraId) | |
activeCapturer = camera2Capturer | |
camera1Capturer = null | |
} else { | |
Log.i(TAG, "Camera 1") | |
setCamera1Maps() | |
camera1Capturer = CameraCapturer(context, camera1IdMap[getCameraSourceByCameraId(cameraId)]!!) | |
activeCapturer = camera1Capturer | |
camera2Capturer = null | |
} | |
} | |
private fun getCameraSourceByCameraId(cameraId: String): Source? { | |
for (i in 0 until Camera.getNumberOfCameras()) { | |
val cameraInfo = Camera.CameraInfo() | |
Camera.getCameraInfo(i, cameraInfo) | |
if (cameraId.contains(i.toString())) { | |
return if (cameraInfo.facing == 1) { | |
Source.FRONT_CAMERA | |
} else { | |
Source.BACK_CAMERA | |
} | |
} | |
} | |
return null | |
} | |
private fun setCamera1Maps() { | |
val camera1Enumerator = Camera1Enumerator() | |
for (deviceName in camera1Enumerator.deviceNames) { | |
if (camera1Enumerator.isFrontFacing(deviceName)) { | |
camera1IdMap[Source.FRONT_CAMERA] = deviceName | |
camera1SourceMap[deviceName] = Source.FRONT_CAMERA | |
} | |
if (camera1Enumerator.isBackFacing(deviceName)) { | |
camera1IdMap[Source.BACK_CAMERA] = deviceName | |
camera1SourceMap[deviceName] = Source.BACK_CAMERA | |
} | |
} | |
} | |
companion object { | |
private const val TAG = "CameraCapturerCompat" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment