Skip to content

Instantly share code, notes, and snippets.

@apkelly
Last active February 23, 2020 13:33
Show Gist options
  • Save apkelly/f1cd7df5bb9ae131ed66acf2ab212dc9 to your computer and use it in GitHub Desktop.
Save apkelly/f1cd7df5bb9ae131ed66acf2ab212dc9 to your computer and use it in GitHub Desktop.
CameraSourcePreview.kt
class CameraSourcePreview(private val mContext: Context, attrs: AttributeSet) : ViewGroup(mContext, attrs) {
companion object {
private const val TAG = "CameraSourcePreview"
}
private val mSurfaceView: SurfaceView
private var mStartRequested: Boolean = false
private var mSurfaceAvailable: Boolean = false
private var mCameraSource: ICameraSource? = null
private var mOverlay: GraphicOverlay? = null
private val isPortraitMode: Boolean
get() {
val orientation = mContext.resources.configuration.orientation
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
return false
}
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
return true
}
Log.d(TAG, "isPortraitMode returning false by default")
return false
}
init {
mStartRequested = false
mSurfaceAvailable = false
mSurfaceView = SurfaceView(mContext)
mSurfaceView.holder.addCallback(SurfaceCallback())
addView(mSurfaceView)
}
@Throws(IOException::class)
fun start(cameraSource: ICameraSource?) {
if (cameraSource == null) {
stop()
}
mCameraSource = cameraSource
if (mCameraSource != null) {
mStartRequested = true
startIfReady()
}
}
@Throws(IOException::class)
fun start(cameraSource: ICameraSource, overlay: GraphicOverlay) {
mOverlay = overlay
start(cameraSource)
}
fun stop() {
if (mCameraSource != null) {
mCameraSource!!.stop()
}
}
fun release() {
if (mCameraSource != null) {
mCameraSource!!.release()
mCameraSource = null
}
}
@Throws(IOException::class)
private fun startIfReady() {
if (mStartRequested && mSurfaceAvailable) {
mCameraSource!!.start(mSurfaceView.holder)
if (mOverlay != null) {
val size = mCameraSource!!.previewSize()
size?.let {
val min = Math.min(it.width, it.height)
val max = Math.max(it.width, it.height)
if (isPortraitMode) {
// Swap width and height sizes when in portrait, since it will be rotated by
// 90 degrees
mOverlay!!.setCameraInfo(min, max, mCameraSource!!.cameraFacing())
} else {
mOverlay!!.setCameraInfo(max, min, mCameraSource!!.cameraFacing())
}
mOverlay!!.clear()
}
}
mStartRequested = false
}
}
private inner class SurfaceCallback : SurfaceHolder.Callback {
override fun surfaceCreated(surface: SurfaceHolder) {
mSurfaceAvailable = true
try {
startIfReady()
} catch (e: IOException) {
Log.e(TAG, "Could not start camera source.", e)
}
}
override fun surfaceDestroyed(surface: SurfaceHolder) {
mSurfaceAvailable = false
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {}
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
var width = 640
var height = 480
if (mCameraSource != null) {
val size = mCameraSource!!.previewSize()
if (size != null) {
width = size.width
height = size.height
}
}
// Swap width and height sizes when in portrait, since it will be rotated 90 degrees
if (isPortraitMode) {
val tmp = width
width = height
height = tmp
}
val layoutWidth = right - left
val layoutHeight = bottom - top
// Computes height and width for potentially doing fit width.
var childWidth = layoutWidth
var childHeight = (layoutWidth.toFloat() / width.toFloat() * height).toInt()
// If height is too tall using fit width, does fit height instead.
if (childHeight > layoutHeight) {
childHeight = layoutHeight
childWidth = (layoutHeight.toFloat() / height.toFloat() * width).toInt()
}
for (i in 0 until childCount) {
getChildAt(i).layout(0, 0, childWidth, childHeight)
}
try {
startIfReady()
} catch (e: IOException) {
Log.e(TAG, "Could not start camera source.", e)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment