Advertisement
thief_g

SwithingCameraAndRecordVideoWorking

Apr 25th, 2023
1,284
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 17.85 KB | None | 0 0
  1. package com.example.camerax
  2.  
  3. import android.Manifest
  4. import android.annotation.SuppressLint
  5. import android.content.ContentValues
  6. import android.content.pm.PackageManager
  7. import android.media.MediaCodec
  8. import android.media.MediaExtractor
  9. import android.media.MediaMuxer
  10. import android.net.Uri
  11. import android.os.Build
  12. import android.os.Bundle
  13. import android.os.SystemClock
  14. import android.provider.MediaStore
  15. import android.util.Log
  16. import android.view.View
  17. import android.widget.Chronometer
  18. import android.widget.Toast
  19. import androidx.appcompat.app.AppCompatActivity
  20. import androidx.camera.core.Camera
  21. import androidx.camera.core.CameraSelector
  22. import androidx.camera.core.ImageCapture
  23. import androidx.camera.core.ImageCaptureException
  24. import androidx.camera.core.Preview
  25. import androidx.camera.lifecycle.ProcessCameraProvider
  26. import androidx.camera.video.MediaStoreOutputOptions
  27. import androidx.camera.video.Quality
  28. import androidx.camera.video.QualitySelector
  29. import androidx.camera.video.Recorder
  30. import androidx.camera.video.Recording
  31. import androidx.camera.video.VideoCapture
  32. import androidx.camera.video.VideoRecordEvent
  33. import androidx.core.app.ActivityCompat
  34. import androidx.core.content.ContextCompat
  35. import androidx.core.content.PermissionChecker
  36. import androidx.core.net.toFile
  37. import com.example.camerax.databinding.ActivityMainBinding
  38. import com.google.android.exoplayer2.MediaItem
  39. import com.google.android.exoplayer2.SimpleExoPlayer
  40. import com.google.android.exoplayer2.mediacodec.MediaCodecSelector
  41. import com.google.android.exoplayer2.source.ConcatenatingMediaSource
  42. import com.google.android.exoplayer2.source.MediaSource
  43. import com.google.android.exoplayer2.source.ProgressiveMediaSource
  44. import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
  45. import com.google.android.exoplayer2.util.Util
  46. import com.google.android.exoplayer2.video.MediaCodecVideoRenderer
  47. import java.io.File
  48. import java.nio.ByteBuffer
  49. import java.text.SimpleDateFormat
  50. import java.util.Locale
  51. import java.util.concurrent.ExecutorService
  52. import java.util.concurrent.Executors
  53.  
  54.  
  55. class MainActivity : AppCompatActivity() {
  56.     private lateinit var mainBinding: ActivityMainBinding
  57.     private var mIsVideoRecording: Boolean = false
  58.  
  59.     private var mImageCapture: ImageCapture? = null
  60.     private lateinit var mImageCaptureExecutor: ExecutorService
  61.     private lateinit var mCameraSelector:CameraSelector
  62.  
  63.     private var mVideoCapture: VideoCapture<Recorder>? = null
  64.     private var mRecording: Recording? = null
  65.     private var quality = Quality.HD
  66.     private val qualitySelector = QualitySelector.from(quality)
  67.     private var recorderBuilder = Recorder.Builder()
  68.  
  69.     private var recorder = Recorder.Builder().build()
  70.     private var mIsVideoPaused: Boolean = false
  71.     private  lateinit var mChronometer: Chronometer
  72.     private var isFlashOn: Boolean = false
  73.     private lateinit var camera: Camera
  74.     private var mIsCameraSwitched: Boolean = false
  75.     private lateinit var videoFile1: File
  76.     private lateinit var videoFile2: File
  77.     override fun onCreate(savedInstanceState: Bundle?) {
  78.         super.onCreate(savedInstanceState)
  79.         mainBinding = ActivityMainBinding.inflate(layoutInflater)
  80.         setContentView(mainBinding.root)
  81.  
  82.         mImageCaptureExecutor = Executors.newSingleThreadExecutor()
  83.         if(allPermissionsGranted()) {
  84.             mCameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
  85.             startCamera()
  86.         } else {
  87.             Toast.makeText(this, "Require permissions to access camera", Toast.LENGTH_SHORT).show()
  88.         }
  89.  
  90.         mChronometer = mainBinding.chronometer
  91.         mChronometer.visibility = View.GONE
  92.         mainBinding.ivPauseResume.visibility = View.GONE
  93.  
  94.         recorderBuilder.setQualitySelector(qualitySelector)
  95.         mainBinding.ivStartStop.setOnClickListener {
  96.             if (mIsVideoRecording) {
  97.                stopRecording()
  98.             } else {
  99.                 startRecordingVideo()
  100.             }
  101.         }
  102.         var timeWhenPaused: Long = 0
  103.         mainBinding.ivPauseResume.setOnClickListener {
  104.             if (mIsVideoPaused) {
  105.                 mIsVideoPaused = false
  106.                 mainBinding.ivPauseResume.setBackgroundResource(R.drawable.ic_pause_icon)
  107.                 mRecording!!.resume()
  108.                 mChronometer.base = SystemClock.elapsedRealtime() + timeWhenPaused
  109.                 mChronometer.start()
  110.  
  111.             } else {
  112.                 mIsVideoPaused = true
  113.                 mainBinding.ivPauseResume.setBackgroundResource(R.drawable.ic_resume_icon)
  114.                 timeWhenPaused = mChronometer.base - SystemClock.elapsedRealtime()
  115.                 mChronometer.stop()
  116.                 mRecording!!.pause()
  117.             }
  118.         }
  119.  
  120.         mainBinding.ivSwitchCamera.setOnClickListener {
  121.             mIsCameraSwitched = false
  122.  
  123.             if (mIsVideoRecording) {
  124.  
  125.                 mIsCameraSwitched = true
  126.                 stopRecording()
  127.                 startRecordingVideo()
  128.             } else {
  129.                 switchCamera()
  130.                 startCamera()
  131.             }
  132.         }
  133.         mainBinding.ivTakePicture.setOnClickListener {
  134.             takePhoto() // it will also save the photo
  135.         }
  136.  
  137.         mainBinding.ivFlash.setOnClickListener {
  138.             onFlashButtonClicked()
  139.         }
  140.  
  141.     }
  142.  
  143.     private fun switchCamera() {
  144.         if ( mCameraSelector == CameraSelector.DEFAULT_BACK_CAMERA) {
  145.             camera.cameraControl.enableTorch(false)
  146.             mCameraSelector =  CameraSelector.DEFAULT_FRONT_CAMERA
  147.             mainBinding.ivFlash.setBackgroundResource(R.drawable.ic_flash_off_icon)
  148.         } else {
  149.             mCameraSelector =  CameraSelector.DEFAULT_BACK_CAMERA
  150.         }
  151.         if(mIsCameraSwitched) {
  152.             startCamera()
  153.         }
  154.     }
  155.  
  156.     private fun onFlashButtonClicked() {
  157.         if(mCameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) {
  158.             mainBinding.ivFlash.setBackgroundResource(R.drawable.ic_flash_off_icon)
  159.             Toast.makeText(this, "Flash is not available", Toast.LENGTH_SHORT).show()
  160.         } else {
  161.             if (isFlashOn) {
  162.                 isFlashOn = false
  163.                 mainBinding.ivFlash.setBackgroundResource(R.drawable.ic_flash_off_icon)
  164.                 camera.cameraControl.enableTorch(false)
  165.             } else {
  166.                 mainBinding.ivFlash.setBackgroundResource(R.drawable.ic_flash_icon)
  167.                 if(camera.cameraInfo.hasFlashUnit()){
  168.                     camera.cameraControl.enableTorch(true)
  169.                     isFlashOn = true
  170.                 } else {
  171.                     Toast.makeText(this, "Flash is not available", Toast.LENGTH_SHORT).show()
  172.                 }
  173.             }
  174.         }
  175.     }
  176.  
  177.     private fun startCamera() {
  178.         val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
  179.         if(mIsCameraSwitched) {
  180.             recorder = Recorder.Builder().build()
  181.         }
  182.         mVideoCapture = VideoCapture.withOutput(recorder)
  183.         cameraProviderFuture.addListener({
  184.  
  185.             val cameraProvider = cameraProviderFuture.get()
  186.             val preview = Preview.Builder()
  187.                 .build()
  188.                 .also {
  189.                     it.setSurfaceProvider(mainBinding.cameraPreview.surfaceProvider)
  190.                 }
  191.             mImageCapture = ImageCapture.Builder()
  192.                 .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
  193.                 .build()
  194.  
  195.             try {
  196.                 cameraProvider.unbindAll()
  197.                 camera = cameraProvider.bindToLifecycle(this, mCameraSelector,mImageCapture,mVideoCapture,preview)
  198.                 //camera.cameraControl.setZoomRatio(6.0f)
  199.             } catch (e: Exception) {
  200.                 Log.d("MainActivity", "Use case binding failed")
  201.             }
  202.  
  203.         }, ContextCompat.getMainExecutor(this))
  204.  
  205.     }
  206.     private fun takePhoto() {
  207.         mImageCapture?.let{
  208.  
  209.             val imageFileName = SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis())
  210.             val contentValues = ContentValues().apply {
  211.                 put(MediaStore.MediaColumns.DISPLAY_NAME, imageFileName)
  212.                 put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
  213.                 if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
  214.                     put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
  215.                 }
  216.             }
  217.             val outputFileOptions = ImageCapture.OutputFileOptions
  218.                 .Builder(contentResolver, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues
  219.                 ).build()
  220.             it.takePicture(
  221.                 outputFileOptions,
  222.                 mImageCaptureExecutor,
  223.                 object : ImageCapture.OnImageSavedCallback {
  224.                     override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults){
  225.                         startCamera()
  226.                     }
  227.  
  228.                     override fun onError(exception: ImageCaptureException) {
  229.                         Toast.makeText(
  230.                             mainBinding.root.context,
  231.                             "Error occurred in taking photo",
  232.                             Toast.LENGTH_LONG
  233.                         ).show()
  234.                         Log.d("MainActivity", "Error taking photo:$exception")
  235.                     }
  236.  
  237.                 })
  238.  
  239.             Toast.makeText( this@MainActivity , "The image has been saved to Gallery", Toast.LENGTH_SHORT).show()
  240.  
  241.         }
  242.     }
  243.  
  244.     private fun startRecordingVideo() {
  245.         mIsVideoRecording = true
  246.         mainBinding.ivStartStop.setBackgroundResource(R.drawable.ic_stop_video_icon)
  247.         mVideoCapture!!.let {
  248.             try {
  249.                 if (ActivityCompat.checkSelfPermission(
  250.                         this,
  251.                         Manifest.permission.RECORD_AUDIO
  252.                     ) != PackageManager.PERMISSION_GRANTED
  253.                 ) {
  254.                     allPermissionsGranted()
  255.                 }
  256.  
  257.                 val contentValues = ContentValues().apply {
  258.                     put(MediaStore.MediaColumns.DISPLAY_NAME, "VIDEO_${System.currentTimeMillis()}")
  259.                     put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
  260.                 }
  261.  
  262.                 val mediaStoreOutputOptions = MediaStoreOutputOptions
  263.                     .Builder(contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
  264.                     .setContentValues(contentValues)
  265.                     .build()
  266.  
  267.                 mRecording = mVideoCapture!!.output
  268.                     .prepareRecording(this, mediaStoreOutputOptions)
  269.                     .apply {
  270.                         // Enable Audio for recording
  271.                         if (PermissionChecker.checkSelfPermission(this@MainActivity, Manifest.permission.RECORD_AUDIO) ==
  272.                             PermissionChecker.PERMISSION_GRANTED ) {
  273.                             withAudioEnabled()
  274.                         }
  275.                     }
  276.                     .start(ContextCompat.getMainExecutor(this)) { recordEvent ->
  277.                         when(recordEvent) {
  278.                             is VideoRecordEvent.Start -> {
  279.                                 mainBinding.ivPauseResume.visibility = View.VISIBLE
  280.                                 mChronometer.visibility = View.VISIBLE
  281.                                 mChronometer.base = SystemClock.elapsedRealtime()
  282.                                 mChronometer.start()
  283.                             }
  284.                             is VideoRecordEvent.Pause -> {}
  285.                             is VideoRecordEvent.Finalize -> {
  286.                                 if (!recordEvent.hasError()) {
  287.                                     val msg = "Video saved: ${recordEvent.outputResults.outputUri}"
  288.                                     Toast.makeText(this,  recordEvent.outputResults.outputUri.path, Toast.LENGTH_SHORT).show()
  289.  
  290.                                     if (mIsCameraSwitched) {
  291.                                         mIsVideoRecording = false
  292.                                         videoFile2 = File(recordEvent.outputResults.outputUri.path!!)
  293.                                         mergeVideos(videoFile1, videoFile2, videoFile1.path)
  294.  
  295.                                     } else {
  296.                                         videoFile1 = File(recordEvent.outputResults.outputUri.path!!)
  297.                                         mainBinding.ivPauseResume.visibility = View.GONE
  298.                                         mChronometer.stop()
  299.                                         mChronometer.visibility = View.GONE
  300.                                     }
  301.                                     //startCamera()
  302.  
  303.                                 } else {
  304.                                     mRecording?.close()
  305.                                     mRecording = null
  306.                                     Log.e("MainActivity", "Video capture ends with error: ${recordEvent.error}")
  307.                                 }
  308.  
  309.                             }
  310.                             is VideoRecordEvent.Resume -> {}
  311.                         }
  312.                     }
  313.  
  314.             } catch (e: Exception) {
  315.                 e.printStackTrace()
  316.             }
  317.         }
  318.  
  319.     }
  320.  
  321.     private fun stopRecording() {
  322.         mainBinding.ivStartStop.setBackgroundResource(R.drawable.ic_start_video_icon)
  323.         mRecording!!.stop()
  324.         mChronometer.stop()
  325.         mChronometer.visibility = View.GONE
  326.         if (mIsCameraSwitched) {
  327.             switchCamera()
  328.  
  329.         }
  330.  
  331.     }
  332.  
  333.     private fun mergeVideos(videoFile1: File, videoFile2: File, outputFilePath: String) {
  334.         Log.e(TAG, outputFilePath)
  335. //        val mediaMuxer = MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
  336. //        val videoTrackIndex = -1
  337. //        var audioTrackIndex = -1
  338. //
  339. //        // Add the first video file to the media muxer
  340. //        val extractor1 = MediaExtractor()
  341. //        extractor1.setDataSource(videoFile1.path)
  342. //        val videoFormat1 = extractor1.getTrackFormat(0)
  343. //        val audioFormat1 = extractor1.getTrackFormat(1)
  344. //        val videoTrackIndex1 = mediaMuxer.addTrack(videoFormat1)
  345. //        val audioTrackIndex1 = mediaMuxer.addTrack(audioFormat1)
  346. //        extractor1.selectTrack(0)
  347. //
  348. //        // Add the second video file to the media muxer
  349. //        val extractor2 = MediaExtractor()
  350. //        extractor2.setDataSource(videoFile2.path)
  351. //        val videoFormat2 = extractor2.getTrackFormat(0)
  352. //        val audioFormat2 = extractor2.getTrackFormat(1)
  353. //        val videoTrackIndex2 = mediaMuxer.addTrack(videoFormat2)
  354. //        val audioTrackIndex2 = mediaMuxer.addTrack(audioFormat2)
  355. //        extractor2.selectTrack(0)
  356. //
  357. //        mediaMuxer.start()
  358. //
  359. //        // Write the data from the first video file to the output file
  360. //        val buffer1 = ByteBuffer.allocate(1024 * 1024)
  361. //        var sampleSize1 = extractor1.readSampleData(buffer1, 0)
  362. //        while (sampleSize1 >= 0) {
  363. //            val mflag = extractor1.sampleFlags
  364. //            val bufferInfo = MediaCodec.BufferInfo()
  365. //            bufferInfo.offset = 0
  366. //            bufferInfo.size = sampleSize1
  367. //            bufferInfo.presentationTimeUs = extractor1.sampleTime
  368. //            bufferInfo.flags = mflag
  369. //            mediaMuxer.writeSampleData(videoTrackIndex1, buffer1, bufferInfo)
  370. //            extractor1.advance()
  371. //            sampleSize1 = extractor1.readSampleData(buffer1, 0)
  372. //        }
  373. //        // Write the data from the second video file to the output file
  374. //        val buffer2 = ByteBuffer.allocate(1024 * 1024)
  375. //        var sampleSize2 = extractor2.readSampleData(buffer2, 0)
  376. //        while (sampleSize2 >= 0) {
  377. //            val flag = extractor2.sampleFlags
  378. //            val bufferInfo = MediaCodec.BufferInfo()
  379. //            bufferInfo.offset = 0
  380. //            bufferInfo.size = sampleSize2
  381. //            bufferInfo.presentationTimeUs = extractor2.sampleTime
  382. //            bufferInfo.flags = flag
  383. //            mediaMuxer.writeSampleData(videoTrackIndex2, buffer2, bufferInfo)
  384. //            extractor2.advance()
  385. //            sampleSize2 = extractor2.readSampleData(buffer2, 0)
  386. //        }
  387. //
  388. //        // Release the extractors
  389. //        extractor1.release()
  390. //        extractor2.release()
  391. //
  392. //        // Stop and release the media muxer
  393. //        mediaMuxer.stop()
  394. //        mediaMuxer.release()
  395.     }
  396.     private fun buildMediaSource(file: File): MediaSource {
  397.         val dataSourceFactory = DefaultDataSourceFactory(this, Util.getUserAgent(this, "CameraX"))
  398.         return ProgressiveMediaSource.Factory(dataSourceFactory)
  399.             .createMediaSource(MediaItem.fromUri(Uri.fromFile(file)))
  400.     }
  401.  
  402.  
  403.  
  404.     private fun allPermissionsGranted(): Boolean {
  405.         if (ActivityCompat.checkSelfPermission(
  406.                 this,
  407.                 Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){
  408.             ActivityCompat.requestPermissions(
  409.                 this,
  410.                 arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA_PERMISSION)
  411.         }
  412.         if(ActivityCompat.checkSelfPermission(
  413.                 this,
  414.                 Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
  415.             ActivityCompat.requestPermissions(
  416.                 this,
  417.                 arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_CAMERA_PERMISSION)
  418.         }
  419.         return ActivityCompat.checkSelfPermission(
  420.             this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED &&
  421.                 ActivityCompat.checkSelfPermission(
  422.                     this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
  423.     }
  424.     companion object {
  425.         const val TAG = "MainActivity"
  426.         const val REQUEST_CAMERA_PERMISSION: Int = 0
  427.         const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
  428.     }
  429. }
  430.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement