Я пытаюсь реализовать функциональность медленного движения в моем приложении Android, но у меня нет достаточно знаний о том, как заставить его работать.
Что не так с моим кодом? />
[*] Профиль камеры: camcorderprofile.quality_high_speed_1080 .
Скорость захвата: setCaptureRate (профиль !! Скорость, вместо того, чтобы быть в замедленном движении. < /p>
Полный тестируемый пример кода: < /p>
class TempMainActivity : AppCompatActivity() {
companion object {
private const val TAG = "SlowMotionCamera"
private const val REQUEST_CODE_PERMISSIONS = 10
private val REQUIRED_PERMISSIONS = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
}
private lateinit var textureView: TextureView
private lateinit var recordButton: Button
private lateinit var statusText: TextView
private lateinit var cameraManager: CameraManager
private lateinit var cameraId: String
private var cameraDevice: CameraDevice? = null
private var cameraCaptureSession: CameraCaptureSession? = null
private var mediaRecorder: MediaRecorder? = null
private var isRecording = false
private var videoFile: File? = null
private var profile: CamcorderProfile? = null
private lateinit var backgroundHandler: Handler
private lateinit var backgroundThread: HandlerThread
private val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int) {
openCamera()
}
override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) {}
override fun onSurfaceTextureDestroyed(texture: SurfaceTexture) = true
override fun onSurfaceTextureUpdated(texture: SurfaceTexture) {}
}
private val stateCallback = object : CameraDevice.StateCallback() {
override fun onOpened(camera: CameraDevice) {
cameraDevice = camera
createCameraPreviewSession()
}
override fun onDisconnected(camera: CameraDevice) {
camera.close()
cameraDevice = null
}
override fun onError(camera: CameraDevice, error: Int) {
camera.close()
cameraDevice = null
finish()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_temp)
textureView = findViewById(R.id.textureView)
recordButton = findViewById(R.id.recordButton)
statusText = findViewById(R.id.statusText)
cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
cameraId = cameraManager.cameraIdList[0] // Use back camera
// Set fixed size that matches high-speed resolution
textureView.layoutParams.width = 1920
textureView.layoutParams.height = 1080
textureView.requestLayout()
recordButton.setOnClickListener {
if (isRecording) {
stopRecording()
} else {
startRecording()
}
}
}
override fun onResume() {
super.onResume()
startBackgroundThread()
if (textureView.isAvailable) {
openCamera()
} else {
textureView.surfaceTextureListener = surfaceTextureListener
}
}
override fun onPause() {
stopRecording()
closeCamera()
stopBackgroundThread()
super.onPause()
}
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
}
private fun startBackgroundThread() {
backgroundThread = HandlerThread("CameraBackground").also { it.start() }
backgroundHandler = Handler(backgroundThread.looper)
}
private fun stopBackgroundThread() {
backgroundThread.quitSafely()
try {
backgroundThread.join()
} catch (e: InterruptedException) {
Log.e(TAG, "Error stopping background thread", e)
}
}
private fun openCamera() {
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return
}
cameraManager.openCamera(cameraId, stateCallback, backgroundHandler)
} catch (e: CameraAccessException) {
Log.e(TAG, "Cannot access the camera", e)
}
}
private fun closeCamera() {
cameraCaptureSession?.close()
cameraCaptureSession = null
cameraDevice?.close()
cameraDevice = null
}
private fun createCameraPreviewSession() {
try {
val texture = textureView.surfaceTexture
texture?.setDefaultBufferSize(1920, 1080)
val surface = Surface(texture)
val captureRequestBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureRequestBuilder?.addTarget(surface)
cameraDevice?.createCaptureSession(
listOf(surface),
object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
if (cameraDevice == null) return
cameraCaptureSession = session
try {
captureRequestBuilder?.set(
CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE
)
session.setRepeatingRequest(
captureRequestBuilder?.build()!!,
null,
backgroundHandler
)
} catch (e: CameraAccessException) {
Log.e(TAG, "Cannot access camera", e)
}
}
override fun onConfigureFailed(session: CameraCaptureSession) {
Toast.makeText(this@TempMainActivity,
"Failed to configure camera", Toast.LENGTH_SHORT).show()
}
},
backgroundHandler
)
} catch (e: CameraAccessException) {
Log.e(TAG, "Cannot access camera", e)
}
}
private fun startRecording() {
if (isRecording || cameraDevice == null || !textureView.isAvailable) {
Log.e(TAG, "Cannot start recording - invalid state")
return
}
try {
// Check device capabilities
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val highSpeedProfiles = characteristics.get(
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES
)?.contains(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO)
?: false
if (!highSpeedProfiles) {
Toast.makeText(this, "Slow motion not supported on this device",
Toast.LENGTH_LONG).show()
return
}
// Get the best available high speed profile
profile = when {
CamcorderProfile.hasProfile(cameraId.toInt(),
CamcorderProfile.QUALITY_HIGH_SPEED_1080P) -> {
CamcorderProfile.get(cameraId.toInt(),
CamcorderProfile.QUALITY_HIGH_SPEED_1080P)
}
CamcorderProfile.hasProfile(cameraId.toInt(),
CamcorderProfile.QUALITY_HIGH_SPEED_720P) -> {
CamcorderProfile.get(cameraId.toInt(),
CamcorderProfile.QUALITY_HIGH_SPEED_720P)
}
else -> {
Toast.makeText(this, "No high speed profile available",
Toast.LENGTH_LONG).show()
return
}
}
// Create video file
videoFile = createVideoFile()
if (videoFile == null) {
Toast.makeText(this, "Error creating video file",
Toast.LENGTH_SHORT).show()
return
}
// Set up media recorder
Log.d(TAG, "startRecording: >>>>>>>>>>>>>>>>>>>>>>>>>>>> profile!!.videoFrameRate ${profile!!.videoFrameRate}")
// Set up media recorder
mediaRecorder = MediaRecorder().apply {
setAudioSource(MediaRecorder.AudioSource.CAMCORDER)
setVideoSource(MediaRecorder.VideoSource.SURFACE)
setOutputFormat(profile!!.fileFormat)
setAudioEncoder(profile!!.audioCodec)
setVideoEncoder(profile!!.videoCodec)
setVideoSize(profile!!.videoFrameWidth, profile!!.videoFrameHeight)
setVideoFrameRate(profile!!.videoFrameRate)
setVideoEncodingBitRate(profile!!.videoBitRate * 2)
setOrientationHint(90)
setOutputFile(videoFile?.absolutePath)
// Critical slow motion settings
setCaptureRate(profile!!.videoFrameRate.toDouble())
// Alternative method for API 24+ to set slow motion
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
try {
// Using reflection as a last resort since there's no public API
val setParametersMethod = MediaRecorder::class.java.getMethod(
"setParameters",
String::class.java
)
setParametersMethod.invoke(
this,
"slow-motion=${profile!!.videoFrameRate}"
)
} catch (e: Exception) {
Log.w(TAG, "Couldn't set slow-motion parameter", e)
}
}
try {
prepare()
} catch (e: Exception) {
Log.e(TAG, "MediaRecorder prepare failed", e)
release()
Toast.makeText(this@TempMainActivity,
"Prepare failed: ${e.message}", Toast.LENGTH_LONG).show()
return@apply
}
}
// Create recording session
val surfaces = listOf(
Surface(textureView.surfaceTexture),
mediaRecorder?.surface!!
)
// Configure for high speed FPS
val captureRequestBuilder = cameraDevice?.createCaptureRequest(
CameraDevice.TEMPLATE_RECORD).apply {
this?.addTarget(mediaRecorder?.surface!!)
this?.addTarget(Surface(textureView.surfaceTexture))
this?.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
this?.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
Range(profile!!.videoFrameRate, profile!!.videoFrameRate))
}
cameraDevice?.createConstrainedHighSpeedCaptureSession(
surfaces,
object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
cameraCaptureSession = session
try {
// Create high speed request list properly
val highSpeedRequestList = (session as? CameraConstrainedHighSpeedCaptureSession)?.let {
captureRequestBuilder?.build()?.let { request ->
it.createHighSpeedRequestList(request)
}
}
highSpeedRequestList?.let { requests ->
session.setRepeatingBurst(requests, null, backgroundHandler)
}
mediaRecorder?.start()
isRecording = true
runOnUiThread {
recordButton.text = "Stop Recording"
statusText.text = "Recording Slow Motion (${profile!!.videoFrameRate}FPS)"
}
} catch (e: CameraAccessException) {
Log.e(TAG, "Failed to start high speed recording", e)
runOnUiThread {
Toast.makeText(this@TempMainActivity,
"Failed to start recording", Toast.LENGTH_SHORT).show()
}
}
}
override fun onConfigureFailed(session: CameraCaptureSession) {
runOnUiThread {
Toast.makeText(this@TempMainActivity,
"Failed to configure high speed session", Toast.LENGTH_SHORT).show()
}
}
},
backgroundHandler
)
} catch (e: Exception) {
Log.e(TAG, "Error starting recording", e)
Toast.makeText(this, "Error starting recording: ${e.message}",
Toast.LENGTH_SHORT).show()
}
}
private fun stopRecording() {
if (!isRecording) return
try {
cameraCaptureSession?.stopRepeating()
cameraCaptureSession?.abortCaptures()
mediaRecorder?.apply {
stop()
reset()
}
saveVideoToGallery()
Toast.makeText(this, "Slow motion video saved to gallery",
Toast.LENGTH_SHORT).show()
} catch (e: Exception) {
Log.e(TAG, "Error stopping recording", e)
Toast.makeText(this, "Error saving video", Toast.LENGTH_SHORT).show()
} finally {
mediaRecorder = null
isRecording = false
runOnUiThread {
recordButton.text = "Start Recording"
statusText.text = ""
}
createCameraPreviewSession() // Return to preview mode
}
}
private fun createVideoFile(): File? {
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val storageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES)
return try {
File.createTempFile(
"SLOW_${timeStamp}_",
".mp4",
storageDir
).apply {
createNewFile()
}
} catch (e: Exception) {
Log.e(TAG, "Error creating video file", e)
null
}
}
private fun saveVideoToGallery() {
videoFile?.let { file ->
try {
val contentValues = ContentValues().apply {
put(MediaStore.Video.Media.TITLE, "Slow Motion Video")
put(MediaStore.Video.Media.DISPLAY_NAME, file.name)
put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000)
put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
profile?.let {
put(MediaStore.Video.Media.CAPTURE_FRAMERATE, it.videoFrameRate.toDouble())
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.Video.Media.RELATIVE_PATH,
Environment.DIRECTORY_MOVIES + "/SlowMotion")
put(MediaStore.Video.Media.IS_PENDING, 1)
} else {
put(MediaStore.Video.Media.DATA, file.absolutePath)
}
}
val uri = contentResolver.insert(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
contentValues
) ?: throw IllegalStateException("Failed to create new MediaStore record")
contentResolver.openOutputStream(uri)?.use { outputStream ->
file.inputStream().use { inputStream ->
inputStream.copyTo(outputStream)
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.clear()
contentValues.put(MediaStore.Video.Media.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
}
// Notify gallery
sendBroadcast(
Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri)
)
// Delete temporary file
if (!file.delete()) {
Log.w(TAG, "Failed to delete temporary file: ${file.absolutePath}")
}
runOnUiThread {
Toast.makeText(this, "Video saved to gallery", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Log.e(TAG, "Error saving video to gallery", e)
runOnUiThread {
Toast.makeText(this, "Failed to save video: ${e.message}", Toast.LENGTH_LONG).show()
}
}
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/795 ... camera-api
Как реализовать функцию замедленного движения с помощью API Android Camera API? [закрыто] ⇐ Android
Форум для тех, кто программирует под Android
1745586881
Anonymous
Я пытаюсь реализовать функциональность медленного движения в моем приложении Android, но у меня нет достаточно знаний о том, как заставить его работать.
Что не так с моим кодом? />
[*] Профиль камеры: camcorderprofile.quality_high_speed_1080 .
Скорость захвата: setCaptureRate (профиль !! Скорость, вместо того, чтобы быть в замедленном движении. < /p>
Полный тестируемый пример кода: < /p>
class TempMainActivity : AppCompatActivity() {
companion object {
private const val TAG = "SlowMotionCamera"
private const val REQUEST_CODE_PERMISSIONS = 10
private val REQUIRED_PERMISSIONS = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
}
private lateinit var textureView: TextureView
private lateinit var recordButton: Button
private lateinit var statusText: TextView
private lateinit var cameraManager: CameraManager
private lateinit var cameraId: String
private var cameraDevice: CameraDevice? = null
private var cameraCaptureSession: CameraCaptureSession? = null
private var mediaRecorder: MediaRecorder? = null
private var isRecording = false
private var videoFile: File? = null
private var profile: CamcorderProfile? = null
private lateinit var backgroundHandler: Handler
private lateinit var backgroundThread: HandlerThread
private val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int) {
openCamera()
}
override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) {}
override fun onSurfaceTextureDestroyed(texture: SurfaceTexture) = true
override fun onSurfaceTextureUpdated(texture: SurfaceTexture) {}
}
private val stateCallback = object : CameraDevice.StateCallback() {
override fun onOpened(camera: CameraDevice) {
cameraDevice = camera
createCameraPreviewSession()
}
override fun onDisconnected(camera: CameraDevice) {
camera.close()
cameraDevice = null
}
override fun onError(camera: CameraDevice, error: Int) {
camera.close()
cameraDevice = null
finish()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_temp)
textureView = findViewById(R.id.textureView)
recordButton = findViewById(R.id.recordButton)
statusText = findViewById(R.id.statusText)
cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
cameraId = cameraManager.cameraIdList[0] // Use back camera
// Set fixed size that matches high-speed resolution
textureView.layoutParams.width = 1920
textureView.layoutParams.height = 1080
textureView.requestLayout()
recordButton.setOnClickListener {
if (isRecording) {
stopRecording()
} else {
startRecording()
}
}
}
override fun onResume() {
super.onResume()
startBackgroundThread()
if (textureView.isAvailable) {
openCamera()
} else {
textureView.surfaceTextureListener = surfaceTextureListener
}
}
override fun onPause() {
stopRecording()
closeCamera()
stopBackgroundThread()
super.onPause()
}
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
}
private fun startBackgroundThread() {
backgroundThread = HandlerThread("CameraBackground").also { it.start() }
backgroundHandler = Handler(backgroundThread.looper)
}
private fun stopBackgroundThread() {
backgroundThread.quitSafely()
try {
backgroundThread.join()
} catch (e: InterruptedException) {
Log.e(TAG, "Error stopping background thread", e)
}
}
private fun openCamera() {
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return
}
cameraManager.openCamera(cameraId, stateCallback, backgroundHandler)
} catch (e: CameraAccessException) {
Log.e(TAG, "Cannot access the camera", e)
}
}
private fun closeCamera() {
cameraCaptureSession?.close()
cameraCaptureSession = null
cameraDevice?.close()
cameraDevice = null
}
private fun createCameraPreviewSession() {
try {
val texture = textureView.surfaceTexture
texture?.setDefaultBufferSize(1920, 1080)
val surface = Surface(texture)
val captureRequestBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureRequestBuilder?.addTarget(surface)
cameraDevice?.createCaptureSession(
listOf(surface),
object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
if (cameraDevice == null) return
cameraCaptureSession = session
try {
captureRequestBuilder?.set(
CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE
)
session.setRepeatingRequest(
captureRequestBuilder?.build()!!,
null,
backgroundHandler
)
} catch (e: CameraAccessException) {
Log.e(TAG, "Cannot access camera", e)
}
}
override fun onConfigureFailed(session: CameraCaptureSession) {
Toast.makeText(this@TempMainActivity,
"Failed to configure camera", Toast.LENGTH_SHORT).show()
}
},
backgroundHandler
)
} catch (e: CameraAccessException) {
Log.e(TAG, "Cannot access camera", e)
}
}
private fun startRecording() {
if (isRecording || cameraDevice == null || !textureView.isAvailable) {
Log.e(TAG, "Cannot start recording - invalid state")
return
}
try {
// Check device capabilities
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val highSpeedProfiles = characteristics.get(
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES
)?.contains(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO)
?: false
if (!highSpeedProfiles) {
Toast.makeText(this, "Slow motion not supported on this device",
Toast.LENGTH_LONG).show()
return
}
// Get the best available high speed profile
profile = when {
CamcorderProfile.hasProfile(cameraId.toInt(),
CamcorderProfile.QUALITY_HIGH_SPEED_1080P) -> {
CamcorderProfile.get(cameraId.toInt(),
CamcorderProfile.QUALITY_HIGH_SPEED_1080P)
}
CamcorderProfile.hasProfile(cameraId.toInt(),
CamcorderProfile.QUALITY_HIGH_SPEED_720P) -> {
CamcorderProfile.get(cameraId.toInt(),
CamcorderProfile.QUALITY_HIGH_SPEED_720P)
}
else -> {
Toast.makeText(this, "No high speed profile available",
Toast.LENGTH_LONG).show()
return
}
}
// Create video file
videoFile = createVideoFile()
if (videoFile == null) {
Toast.makeText(this, "Error creating video file",
Toast.LENGTH_SHORT).show()
return
}
// Set up media recorder
Log.d(TAG, "startRecording: >>>>>>>>>>>>>>>>>>>>>>>>>>>> profile!!.videoFrameRate ${profile!!.videoFrameRate}")
// Set up media recorder
mediaRecorder = MediaRecorder().apply {
setAudioSource(MediaRecorder.AudioSource.CAMCORDER)
setVideoSource(MediaRecorder.VideoSource.SURFACE)
setOutputFormat(profile!!.fileFormat)
setAudioEncoder(profile!!.audioCodec)
setVideoEncoder(profile!!.videoCodec)
setVideoSize(profile!!.videoFrameWidth, profile!!.videoFrameHeight)
setVideoFrameRate(profile!!.videoFrameRate)
setVideoEncodingBitRate(profile!!.videoBitRate * 2)
setOrientationHint(90)
setOutputFile(videoFile?.absolutePath)
// Critical slow motion settings
setCaptureRate(profile!!.videoFrameRate.toDouble())
// Alternative method for API 24+ to set slow motion
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
try {
// Using reflection as a last resort since there's no public API
val setParametersMethod = MediaRecorder::class.java.getMethod(
"setParameters",
String::class.java
)
setParametersMethod.invoke(
this,
"slow-motion=${profile!!.videoFrameRate}"
)
} catch (e: Exception) {
Log.w(TAG, "Couldn't set slow-motion parameter", e)
}
}
try {
prepare()
} catch (e: Exception) {
Log.e(TAG, "MediaRecorder prepare failed", e)
release()
Toast.makeText(this@TempMainActivity,
"Prepare failed: ${e.message}", Toast.LENGTH_LONG).show()
return@apply
}
}
// Create recording session
val surfaces = listOf(
Surface(textureView.surfaceTexture),
mediaRecorder?.surface!!
)
// Configure for high speed FPS
val captureRequestBuilder = cameraDevice?.createCaptureRequest(
CameraDevice.TEMPLATE_RECORD).apply {
this?.addTarget(mediaRecorder?.surface!!)
this?.addTarget(Surface(textureView.surfaceTexture))
this?.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
this?.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
Range(profile!!.videoFrameRate, profile!!.videoFrameRate))
}
cameraDevice?.createConstrainedHighSpeedCaptureSession(
surfaces,
object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
cameraCaptureSession = session
try {
// Create high speed request list properly
val highSpeedRequestList = (session as? CameraConstrainedHighSpeedCaptureSession)?.let {
captureRequestBuilder?.build()?.let { request ->
it.createHighSpeedRequestList(request)
}
}
highSpeedRequestList?.let { requests ->
session.setRepeatingBurst(requests, null, backgroundHandler)
}
mediaRecorder?.start()
isRecording = true
runOnUiThread {
recordButton.text = "Stop Recording"
statusText.text = "Recording Slow Motion (${profile!!.videoFrameRate}FPS)"
}
} catch (e: CameraAccessException) {
Log.e(TAG, "Failed to start high speed recording", e)
runOnUiThread {
Toast.makeText(this@TempMainActivity,
"Failed to start recording", Toast.LENGTH_SHORT).show()
}
}
}
override fun onConfigureFailed(session: CameraCaptureSession) {
runOnUiThread {
Toast.makeText(this@TempMainActivity,
"Failed to configure high speed session", Toast.LENGTH_SHORT).show()
}
}
},
backgroundHandler
)
} catch (e: Exception) {
Log.e(TAG, "Error starting recording", e)
Toast.makeText(this, "Error starting recording: ${e.message}",
Toast.LENGTH_SHORT).show()
}
}
private fun stopRecording() {
if (!isRecording) return
try {
cameraCaptureSession?.stopRepeating()
cameraCaptureSession?.abortCaptures()
mediaRecorder?.apply {
stop()
reset()
}
saveVideoToGallery()
Toast.makeText(this, "Slow motion video saved to gallery",
Toast.LENGTH_SHORT).show()
} catch (e: Exception) {
Log.e(TAG, "Error stopping recording", e)
Toast.makeText(this, "Error saving video", Toast.LENGTH_SHORT).show()
} finally {
mediaRecorder = null
isRecording = false
runOnUiThread {
recordButton.text = "Start Recording"
statusText.text = ""
}
createCameraPreviewSession() // Return to preview mode
}
}
private fun createVideoFile(): File? {
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val storageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES)
return try {
File.createTempFile(
"SLOW_${timeStamp}_",
".mp4",
storageDir
).apply {
createNewFile()
}
} catch (e: Exception) {
Log.e(TAG, "Error creating video file", e)
null
}
}
private fun saveVideoToGallery() {
videoFile?.let { file ->
try {
val contentValues = ContentValues().apply {
put(MediaStore.Video.Media.TITLE, "Slow Motion Video")
put(MediaStore.Video.Media.DISPLAY_NAME, file.name)
put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000)
put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
profile?.let {
put(MediaStore.Video.Media.CAPTURE_FRAMERATE, it.videoFrameRate.toDouble())
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.Video.Media.RELATIVE_PATH,
Environment.DIRECTORY_MOVIES + "/SlowMotion")
put(MediaStore.Video.Media.IS_PENDING, 1)
} else {
put(MediaStore.Video.Media.DATA, file.absolutePath)
}
}
val uri = contentResolver.insert(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
contentValues
) ?: throw IllegalStateException("Failed to create new MediaStore record")
contentResolver.openOutputStream(uri)?.use { outputStream ->
file.inputStream().use { inputStream ->
inputStream.copyTo(outputStream)
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.clear()
contentValues.put(MediaStore.Video.Media.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
}
// Notify gallery
sendBroadcast(
Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri)
)
// Delete temporary file
if (!file.delete()) {
Log.w(TAG, "Failed to delete temporary file: ${file.absolutePath}")
}
runOnUiThread {
Toast.makeText(this, "Video saved to gallery", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Log.e(TAG, "Error saving video to gallery", e)
runOnUiThread {
Toast.makeText(this, "Failed to save video: ${e.message}", Toast.LENGTH_LONG).show()
}
}
}
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79590026/how-to-implement-slow-motion-feature-using-android-camera-api[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия