Advertisement
Guest User

Untitled

a guest
Feb 28th, 2020
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.57 KB | None | 0 0
  1. package io.checkyou.android.camera
  2.  
  3. import android.graphics.*
  4. import android.hardware.Camera
  5. import android.os.Handler
  6. import android.os.HandlerThread
  7. import android.util.Log
  8. import com.jakewharton.rxrelay2.BehaviorRelay
  9. import io.checkyou.android.utils.*
  10. import io.checkyou.android.utils.Optional
  11. import io.reactivex.android.schedulers.AndroidSchedulers
  12. import io.reactivex.disposables.CompositeDisposable
  13. import io.reactivex.rxkotlin.plusAssign
  14. import io.reactivex.rxkotlin.withLatestFrom
  15. import java.util.*
  16. import io.checkyou.android.Application
  17. import io.checkyou.android.BuildConfig
  18. import io.reactivex.disposables.Disposable
  19. import io.reactivex.rxkotlin.Observables
  20. import jp.co.cyberagent.android.gpuimage.*
  21. import jp.co.cyberagent.android.gpuimage.context.GPUImageGlContext
  22. import jp.co.cyberagent.android.gpuimage.context.GPUImageTexture2d
  23. import java.io.File
  24. import kotlin.math.roundToInt
  25.  
  26. class CameraServiceLegacyImpl(private val disposable: CompositeDisposable = CompositeDisposable())
  27. : CameraService<GPUImageTexture2d>, Disposable by disposable {
  28.  
  29. companion object {
  30. private fun producePhoto(bitmap: Bitmap, mode: CameraService.Mode, zoom: Float) : Bitmap {
  31. val matrix = Matrix()
  32. matrix.postRotate(90f)
  33. if (mode == CameraService.Mode.FRONT) {
  34. matrix.postScale(1f, -1f)
  35. }
  36.  
  37. /*val ratio = HEIGHT / WIDTH.toFloat()
  38. val bitmapRatio = bitmap.height / bitmap.width.toFloat()
  39. var w = 0
  40. var h = 0
  41. var xDelta = 0
  42. var yDelta = 0
  43. if (ratio < bitmapRatio) {
  44. w = (bitmap.width / zoom).roundToInt()
  45. h = (w * ratio).roundToInt()
  46. } else {
  47. h = (bitmap.height / zoom).roundToInt()
  48. w = (h / ratio).roundToInt()
  49. }
  50. xDelta = (bitmap.width - w) / 2
  51. yDelta = (bitmap.height - h) / 2*/
  52.  
  53. val (p1, p2) = clampRect(WIDTH, HEIGHT, bitmap.width, bitmap.height, zoom)
  54. val (w, h) = p1
  55. val (xDelta, yDelta) = p2
  56.  
  57. return Bitmap.createBitmap(bitmap, xDelta, yDelta, w, h, matrix, true)
  58. }
  59.  
  60. protected fun setUpFlashMode(parameters: Camera.Parameters, flashEnabled: Boolean, videoMode: Boolean = false) {
  61. val supportedModes = parameters.supportedFlashModes
  62. if (supportedModes != null) {
  63. if (flashEnabled) {
  64. if (videoMode) {
  65. if (supportedModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
  66. parameters.flashMode = Camera.Parameters.FLASH_MODE_TORCH
  67. }
  68. } else {
  69. if (supportedModes.contains(Camera.Parameters.FLASH_MODE_ON)) {
  70. if (BuildConfig.DEBUG) Log.e("kek4es", "sw to on")
  71. parameters.flashMode = Camera.Parameters.FLASH_MODE_ON
  72. }
  73. }
  74. } else {
  75. if (supportedModes.contains(Camera.Parameters.FLASH_MODE_OFF)) {
  76. parameters.flashMode = Camera.Parameters.FLASH_MODE_OFF
  77. }
  78. }
  79. }
  80. }
  81.  
  82. protected fun pickSizeThatFits(width: Int, height: Int, sizes: List<Camera.Size>): Camera.Size? {
  83. var result: Camera.Size? = null
  84. var drawback: Camera.Size? = null
  85. for (option in sizes) {
  86. if (option.height >= option.width * height / width &&
  87. option.width >= width &&
  88. option.height >= height) {
  89. if (result == null || option.width * option.height < result.width * result.height) {
  90. result = option
  91. }
  92. }
  93. if (drawback == null || option.width * option.height > drawback.width * drawback.height) {
  94. drawback = option
  95. }
  96. }
  97.  
  98. return result ?: drawback
  99. }
  100.  
  101. protected fun clampRect(width: Int, height: Int, previewWidth: Int, previewHeight: Int, zoom: Float)
  102. : Pair<Pair<Int, Int>, Pair<Int, Int>> {
  103. val ratio = height / width.toFloat()
  104. val bitmapRatio = previewHeight / previewWidth.toFloat()
  105.  
  106. var w = 0
  107. var h = 0
  108. var xDelta = 0
  109. var yDelta = 0
  110.  
  111. if (ratio < bitmapRatio) {
  112. w = (previewWidth / zoom).roundToInt()
  113. h = (w * ratio).roundToInt()
  114. } else {
  115. h = (previewHeight / zoom).roundToInt()
  116. w = (h / ratio).roundToInt()
  117. }
  118.  
  119. xDelta = (previewWidth - w) / 2
  120. yDelta = (previewHeight - h) / 2
  121.  
  122. return (w to h) to (xDelta to yDelta)
  123. }
  124.  
  125. protected fun getFocusArea(
  126. width: Int,
  127. height: Int,
  128. previewWidth: Int,
  129. previewHeight: Int,
  130. zoom: Float,
  131. point: Pair<Float, Float>) : Camera.Area {
  132. val (p1, p2) = clampRect(width, height, previewWidth, previewHeight, zoom)
  133. val (w, h) = p1
  134. val (xDelta, yDelta) = p2
  135.  
  136. // TODO доделать
  137. return Camera.Area(Rect(-200, -200, 200, 200), 1000)
  138. }
  139.  
  140. const val WIDTH = 1920
  141. const val HEIGHT = 1080
  142. }
  143.  
  144. private val cameraThread = HandlerThread("Camera Thread").apply { start() }
  145. private val cameraScheduler = AndroidSchedulers.from(cameraThread.looper)
  146.  
  147. private val rawPhotoThread = HandlerThread("Raw Photo Thread").apply { start() }
  148. private val rawPhotoScheduler = AndroidSchedulers.from(rawPhotoThread.looper)
  149.  
  150. private val recordingRelay = publishRelayOf<Boolean>()
  151.  
  152. override val lastPhoto = publishRelayOf<Bitmap>()
  153. override val lastVideo = publishRelayOf<String>()
  154. override val recording = recordingRelay.distinctUntilChanged()
  155. override val previewSnapshotProcessing = publishRelayOf<Unit>()
  156. override val lastPreviewSnapshot = publishRelayOf<Bitmap>()
  157. override val prePhotoSnapshot = publishRelayOf<GPUImageTexture2d>()
  158. override val cameraMode = behaviourRelayOf(CameraService.Mode.BACK)
  159. private val cameraModeRelay = behaviourRelayOf(CameraService.Mode.BACK)
  160.  
  161. override val flashEnabled: BehaviorRelay<Boolean> = behaviourRelayOf(false)
  162. private val zoom = behaviourRelayOf(1f)
  163. private val focus = publishRelayOf<Pair<Float, Float>>()
  164.  
  165. private val cameraRequest = publishRelayOf<Boolean>()
  166. private val cameraLock = behaviourRelayOf(false)
  167. //private val takeSnapshotRequest = publishRelayOf<Unit>()
  168. private val takePhotoRequest = publishRelayOf<Unit>()
  169. override val cameraAvailable = publishRelayOf<Boolean>()
  170.  
  171. private val _pauseLock = behaviourRelayOf(false)
  172. private val pauseLock = _pauseLock.distinctUntilChanged()
  173.  
  174. private val _camera = behaviourOptionalRelayOf<Camera>()
  175. // действует такой инвариант: если camera не null, то она доступна ко всем функциям, иначе ее нельзя юзать
  176. private val camera = Observables.combineLatest(_camera, pauseLock).map { if (it.second) Optional.of(null) else it.first }
  177. private val cameraRelay = publishOptionalRelayOf<Camera>()
  178. private val previewSize = publishRelayOf<Camera.Size>()
  179.  
  180. private val textureUpdate = publishRelayOf<Unit>()
  181.  
  182. private val texture = behaviourOptionalRelayOf<GPUImageTextureRenderer.SurfaceTextureHolder>()
  183. private val textureRelay = publishOptionalRelayOf<GPUImageTextureRenderer.SurfaceTextureHolder>()
  184. private val recordRenderer = behaviourOptionalRelayOf<GPUImageRecordTextureRenderer>()
  185.  
  186. private val glContext = behaviourOptionalRelayOf<GPUImageGlContext>()
  187. private val renderingEnabled = behaviourRelayOf(true)
  188.  
  189. //private val rawPreview = publishRelayOf<ByteArray>()
  190. private val rawPhoto = publishRelayOf<ByteArray>()
  191. private val postPhoto = publishRelayOf<Bitmap>()
  192.  
  193. private val file = publishOptionalRelayOf<String>()
  194.  
  195. init {
  196.  
  197. disposable += cameraRequest
  198. .observeOn(cameraScheduler)
  199. .subscribeOn(cameraScheduler)
  200. .withLatestFrom(cameraLock)
  201. .filter { (_, lock) -> !lock }
  202. .map { it.first }
  203. .withLatestFrom(_camera, cameraModeRelay)
  204. .subscribe { (on, oldCamera, mode) ->
  205. cameraLock.accept(true)
  206. oldCamera.request()?.let { camera ->
  207. this._camera.acceptNull()
  208. if (BuildConfig.DEBUG) Log.e("kek4es", "camera stop")
  209. camera.stopPreview()
  210. camera.setPreviewCallback(null)
  211. camera.release()
  212. }
  213. val mNumberOfCameras = Camera.getNumberOfCameras()
  214.  
  215. val cameraInfo = Camera.CameraInfo()
  216. var cameraId = -1
  217. if (on) {
  218. for (i in 0 until mNumberOfCameras) {
  219. Camera.getCameraInfo(i, cameraInfo)
  220. if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT && mode == CameraService.Mode.FRONT) {
  221. cameraId = i
  222. break
  223. }
  224. if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK && mode == CameraService.Mode.BACK) {
  225. cameraId = i
  226. break
  227. }
  228. }
  229. }
  230. if (BuildConfig.DEBUG) Log.e("kek4es", "cam ${cameraId}")
  231. try {
  232. if (cameraId != -1) {
  233. cameraMode.accept(mode)
  234. }
  235. cameraRelay.accept(Optional.of(if (cameraId != -1) Camera.open(cameraId) else null))
  236. } catch (e: Exception) {
  237. cameraAvailable.accept(false)
  238. }
  239. }
  240.  
  241. disposable += cameraModeRelay
  242. .observeOn(cameraScheduler)
  243. .distinctUntilChanged()
  244. .withLatestFrom(camera, cameraRequest)
  245. .subscribeOn(cameraScheduler)
  246. .subscribe {(mode, camera, shouldEnable) ->
  247. if (BuildConfig.DEBUG) Log.e("kek4es", "qwq ${mode}")
  248. camera.request()?.let {
  249. cameraRequest.accept(shouldEnable)
  250. }
  251. }
  252.  
  253. disposable += cameraRelay
  254. .observeOn(cameraScheduler)
  255. .withLatestFrom(texture)
  256. .subscribeOn(cameraScheduler)
  257. .subscribe { (camera, texture) ->
  258. camera.request()?.let { camera -> texture.request()?.let { texture ->
  259. camera.setDisplayOrientation(90)
  260. val parameters = camera.parameters
  261. if (parameters.supportedFocusModes.contains(
  262. Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
  263. parameters.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
  264. }
  265. val previewSize = pickSizeThatFits(WIDTH, HEIGHT, parameters.supportedPreviewSizes)
  266. val pictureSize = pickSizeThatFits(WIDTH, HEIGHT, parameters.supportedPictureSizes)
  267. previewSize?.let {
  268. parameters.setPreviewSize(it.width, it.height)
  269. this.previewSize.accept(it)
  270. /*val desiredSize = "${previewSize.width}x${previewSize.height}"
  271. if (parameters.get("video-size-values").split(",").contains(desiredSize)) {
  272. parameters.set("video-size", desiredSize)
  273. parameters.setRecordingHint(true)
  274. }*/
  275. }
  276. pictureSize?.let {
  277. parameters.setPictureSize(it.width, it.height)
  278. }
  279. camera.parameters = parameters
  280. camera.setPreviewTexture(texture.surfaceTexture)
  281. texture.surfaceTexture.setOnFrameAvailableListener({ textureUpdate.accept(Unit) })
  282. camera.startPreview()
  283. if (BuildConfig.DEBUG) Log.e("kek4es", "preview started")
  284. _camera.accept(Optional.of(camera))
  285. }}
  286. cameraLock.accept(false)
  287. }
  288.  
  289. disposable += glContext
  290. .subscribe { context ->
  291. context.request()?.let { context ->
  292. context.enqueue {
  293. val textureHolder = GPUImageTextureRenderer.SurfaceTextureHolder(context)
  294. textureHolder.init()
  295. val renderer = GPUImageRecordTextureRenderer(context, textureHolder)
  296. renderer.setFilter(null)
  297. recordRenderer.accept(Optional.of(renderer))
  298. textureRelay.accept(Optional.of(textureHolder))
  299. }
  300. }
  301. }
  302.  
  303. disposable += Observables.combineLatest(recordRenderer, previewSize)
  304. .subscribe { (recordRenderer, previewSize) ->
  305. recordRenderer.request()?.let {
  306. it.setRotation(Rotation.ROTATION_90)
  307. it.setImageSize(previewSize.width, previewSize.height)
  308. }
  309. }
  310.  
  311. disposable += textureRelay
  312. .subscribeOn(cameraScheduler)
  313. .observeOn(cameraScheduler)
  314. .withLatestFrom(camera)
  315. .subscribe {(texture, camera) ->
  316. camera.request()?.let { camera ->
  317. camera.setPreviewTexture(null)
  318. camera.setPreviewCallback(null)
  319. camera.stopPreview()
  320. texture.request()?.let { texture ->
  321. camera.setPreviewTexture(texture.surfaceTexture)
  322. texture.surfaceTexture.setOnFrameAvailableListener({ textureUpdate.accept(Unit) }, Handler(cameraThread.looper))
  323. camera.startPreview()
  324. }}
  325. if (BuildConfig.DEBUG) Log.e("kek4es", "kek1")
  326. this.texture.accept(texture)
  327. }
  328.  
  329. /*disposable += takeSnapshotRequest
  330. .observeOn(cameraScheduler)
  331. .withLatestFrom(camera)
  332. .subscribe { (_, camera) ->
  333. camera.request()?.let {
  334. it.setOneShotPreviewCallback { data, _ ->
  335. previewSnapshotProcessing.accept(Unit)
  336. rawPreview.accept(data)
  337. }
  338. }
  339. }*/
  340.  
  341. disposable += textureUpdate
  342. .observeOn(cameraScheduler)
  343. .withLatestFrom(recordRenderer, renderingEnabled)
  344. .subscribe { (_, recordRenderer, renderingEnabled) ->
  345. recordRenderer.request()?.let {
  346. it.setClearMode(!renderingEnabled)
  347. }
  348. }
  349.  
  350. disposable += takePhotoRequest
  351. .subscribeOn(cameraScheduler)
  352. .observeOn(cameraScheduler)
  353. .withLatestFrom(camera, recordRenderer)
  354. .subscribe { (_, camera, renderer) ->
  355. camera.request()?.let {
  356. _pauseLock.accept(true)
  357. renderer.request()?.let { it.requestSnapshot { prePhotoSnapshot.accept(it) } }
  358. it.takePicture(null, null, Camera.PictureCallback { data, _ ->
  359. rawPhoto.accept(data)
  360. it.startPreview()
  361. _pauseLock.accept(false)
  362. })
  363. }
  364. }
  365.  
  366. /*disposable += rawPreview
  367. .subscribeOn(cameraScheduler)
  368. .observeOn(cameraScheduler)
  369. .withLatestFrom(cameraMode, previewSize)
  370. .withLatestFrom(zoom)
  371. .observeOn(rawPhotoScheduler)
  372. .subscribe { (triple, zoom) ->
  373.  
  374. val (data, mode, previewSize) = triple
  375. converter.onSizeChange(previewSize.width, previewSize.height)
  376. converter.updateData(data)
  377. converter.resultBitmap?.let {
  378. val res = producePhoto(it, mode, zoom)
  379. lastPreviewSnapshot.accept(res)
  380. }
  381. }*/
  382.  
  383. disposable += rawPhoto
  384. .observeOn(rawPhotoScheduler)
  385. .withLatestFrom(cameraMode, zoom)
  386. .subscribe { (bytes, mode, zoom) ->
  387. val t = System.currentTimeMillis()
  388. val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
  389. if (BuildConfig.DEBUG) Log.e("kek4es", "decode time: " + (System.currentTimeMillis() - t))
  390. val resultBitmap = producePhoto(bitmap, mode, zoom)
  391. if (BuildConfig.DEBUG) Log.e("kek4es", "produce time: " + (System.currentTimeMillis() - t))
  392. postPhoto.accept(resultBitmap)
  393. }
  394.  
  395. disposable += postPhoto
  396. .observeOn(cameraScheduler)
  397. .withLatestFrom(camera)
  398. .subscribeOn(cameraScheduler)
  399. .subscribe {
  400. lastPhoto.accept(it.first)
  401. }
  402.  
  403. disposable += recording
  404. .observeOn(cameraScheduler)
  405. .withLatestFrom(recordRenderer, camera)
  406. .withLatestFrom(flashEnabled)
  407. .subscribeOn(cameraScheduler)
  408. .subscribe { (triple, flashEnabled) ->
  409. val (recording, recordRenderer, camera) = triple
  410. if (!recording) {
  411. recordRenderer.request()?.stopRecording {
  412. file.acceptNull()
  413. }
  414. camera.request()?.let { camera ->
  415. val parameters = camera.parameters
  416. if (flashEnabled) {
  417. setUpFlashMode(parameters, false)
  418. camera.parameters = parameters
  419. setUpFlashMode(parameters, flashEnabled)
  420. camera.parameters = parameters
  421. }
  422. }
  423. return@subscribe
  424. }
  425. val file = File.createTempFile(UUID.randomUUID().toString(), ".mp4", Application.INSTANCE.applicationContext.cacheDir)
  426. if (file == null) {
  427. return@subscribe
  428. }
  429. this.file.accept(Optional.of(file.absolutePath))
  430. }
  431.  
  432. disposable += file
  433. .observeOn(cameraScheduler)
  434. .distinctUntilChanged()
  435. .scan { oldFile, newFile ->
  436. oldFile.request()?.let {
  437. lastVideo.accept(it)
  438. }
  439. newFile
  440. }
  441. .withLatestFrom(recordRenderer, camera)
  442. .withLatestFrom(flashEnabled)
  443. .subscribe { (triple, flashEnabled) ->
  444. val (file, recordRenderer, camera) = triple
  445. camera.request()?.let {camera -> file.request()?.let { file ->
  446. if (flashEnabled) {
  447. val parameters = camera.parameters
  448. setUpFlashMode(parameters, flashEnabled, true)
  449. camera.parameters = parameters
  450. }
  451.  
  452. val width = camera.parameters.previewSize.width
  453. val height = camera.parameters.previewSize.height
  454. recordRenderer.request()?.startRecording(file, height, width, 0)
  455. return@subscribe
  456. }}
  457. }
  458.  
  459. disposable += renderingEnabled
  460. .withLatestFrom(recordRenderer)
  461. .subscribe { (renderingEnabled, recordRenderer) ->
  462. if (renderingEnabled) {
  463. this.recordRenderer.accept(recordRenderer)
  464. }
  465. }
  466.  
  467. disposable += focus
  468. .observeOn(cameraScheduler)
  469. .withLatestFrom(camera, glContext)
  470. .withLatestFrom(previewSize, zoom)
  471. .subscribeOn(cameraScheduler)
  472. .subscribe { (triple, previewSize, zoom) ->
  473. val (point, camera, glContext) = triple
  474. glContext.request()?.let { glContext -> camera.request()?.let { camera ->
  475. val parameters = camera.parameters
  476. parameters.focusMode = Camera.Parameters.FOCUS_MODE_AUTO
  477. parameters.focusAreas = listOf(getFocusArea(glContext.width, glContext.height, previewSize.width, previewSize.height, zoom, point))
  478. camera.cancelAutoFocus()
  479. camera.parameters = parameters
  480. camera.autoFocus { _, _ ->
  481. camera.cancelAutoFocus()
  482. val parameters = camera.parameters
  483. parameters.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
  484. camera.parameters = parameters
  485. }
  486. }}
  487. }
  488.  
  489. disposable += Observables.combineLatest(glContext, recordRenderer)
  490. .subscribe { (glContext, recordRenderer) ->
  491. glContext.request()?.let {
  492. it.setMainRenderer(recordRenderer.request())
  493. }
  494. }
  495.  
  496. disposable += flashEnabled
  497. .withLatestFrom(camera)
  498. .observeOn(cameraScheduler)
  499. .subscribe { (flashEnabled, camera) ->
  500. camera.request()?.let {
  501. val parameters = it.parameters
  502. setUpFlashMode(parameters, flashEnabled)
  503. it.parameters = parameters
  504. }
  505. }
  506.  
  507. disposable += zoom
  508. .observeOn(cameraScheduler)
  509. .withLatestFrom(recordRenderer)
  510. .subscribe { (zoom, renderer) ->
  511. renderer.request()?.let { renderer ->
  512. renderer.setScale(zoom)
  513. }
  514. }
  515. }
  516.  
  517. override fun notifyStartVideoRecordingRequested() {
  518. recordingRelay.accept(true)
  519. }
  520.  
  521. override fun notifyFinishVideoRecordingRequested() {
  522. recordingRelay.accept(false)
  523. }
  524.  
  525. override fun notifyToggleCameraMode(mode: CameraService.Mode) {
  526. cameraModeRelay.accept(mode)
  527. }
  528.  
  529. override fun notifyFlashEnabled(enabled: Boolean) {
  530. flashEnabled.accept(enabled)
  531. }
  532.  
  533. override fun notifyFocusChanged(point: Pair<Float, Float>) {
  534. focus.accept(point)
  535. }
  536.  
  537. override fun notifyZoomChanged(zoom: Float) {
  538. this.zoom.accept(zoom)
  539. }
  540.  
  541. override fun notifyTakeSnapshotRequested() {
  542. //takeSnapshotRequest.accept(Unit)
  543. }
  544.  
  545. override fun notifyTakePhotoRequested() {
  546. takePhotoRequest.accept(Unit)
  547. }
  548.  
  549. override fun notifyCameraStart() {
  550. //rendererUpdateRequest.accept(true)
  551. cameraRequest.accept(true)
  552. }
  553.  
  554. override fun notifyCameraEnd() {
  555. //rendererUpdateRequest.accept(true)
  556. cameraRequest.accept(false)
  557. }
  558.  
  559. override fun notifyDrawEnabled(enabled: Boolean) {
  560. renderingEnabled.accept(enabled)
  561. }
  562.  
  563. override fun attachGlContext(context: GPUImageGlContext) {
  564. glContext.accept(Optional.of(context))
  565. }
  566. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement