|
@@ -1,5 +1,10 @@
|
|
package com.cr.pages
|
|
package com.cr.pages
|
|
|
|
|
|
|
|
+import android.graphics.ImageFormat
|
|
|
|
+import android.graphics.Rect
|
|
|
|
+import android.graphics.YuvImage
|
|
|
|
+import android.media.MediaCodecInfo
|
|
|
|
+import android.media.MediaFormat
|
|
import android.os.Bundle
|
|
import android.os.Bundle
|
|
import android.view.LayoutInflater
|
|
import android.view.LayoutInflater
|
|
import android.view.SurfaceHolder
|
|
import android.view.SurfaceHolder
|
|
@@ -9,15 +14,28 @@ import android.view.ViewGroup
|
|
import android.widget.Button
|
|
import android.widget.Button
|
|
import android.widget.TextView
|
|
import android.widget.TextView
|
|
import androidx.fragment.app.activityViewModels
|
|
import androidx.fragment.app.activityViewModels
|
|
|
|
+import com.cr.common.CrUnitManager
|
|
|
|
+import com.cr.cruav.CrApplication
|
|
import com.cr.cruav.R
|
|
import com.cr.cruav.R
|
|
|
|
+import com.cr.data.CrUtil
|
|
|
|
+import com.cr.event.CrCommonAction
|
|
|
|
+import com.cr.event.EventCommon
|
|
import com.cr.viewmodel.CrFlightControlVM
|
|
import com.cr.viewmodel.CrFlightControlVM
|
|
import com.cr.viewmodel.CrVideoChannelListener
|
|
import com.cr.viewmodel.CrVideoChannelListener
|
|
import com.cr.viewmodel.CrVideoChannelVM
|
|
import com.cr.viewmodel.CrVideoChannelVM
|
|
|
|
+import com.squareup.otto.Subscribe
|
|
import dji.v5.common.video.channel.VideoChannelType
|
|
import dji.v5.common.video.channel.VideoChannelType
|
|
import dji.v5.common.video.decoder.DecoderOutputMode
|
|
import dji.v5.common.video.decoder.DecoderOutputMode
|
|
import dji.v5.common.video.decoder.DecoderState
|
|
import dji.v5.common.video.decoder.DecoderState
|
|
import dji.v5.common.video.decoder.VideoDecoder
|
|
import dji.v5.common.video.decoder.VideoDecoder
|
|
import dji.v5.common.video.interfaces.*
|
|
import dji.v5.common.video.interfaces.*
|
|
|
|
+import kotlinx.coroutines.GlobalScope
|
|
|
|
+import kotlinx.coroutines.launch
|
|
|
|
+import java.io.File
|
|
|
|
+import java.io.FileNotFoundException
|
|
|
|
+import java.io.FileOutputStream
|
|
|
|
+import java.io.IOException
|
|
|
|
+import java.io.OutputStream
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -30,10 +48,11 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
|
|
/**
|
|
/**
|
|
* FPV窗口监听
|
|
* FPV窗口监听
|
|
*/
|
|
*/
|
|
- interface FPVListener{
|
|
|
|
|
|
+ interface FPVListener {
|
|
// todo: 2023/3/13 切换窗口
|
|
// todo: 2023/3/13 切换窗口
|
|
fun triggerWindow()
|
|
fun triggerWindow()
|
|
}
|
|
}
|
|
|
|
+
|
|
// define: 2023/3/10 延迟初始化一个通道模型
|
|
// define: 2023/3/10 延迟初始化一个通道模型
|
|
private val videoChannelVM: CrVideoChannelVM by activityViewModels()
|
|
private val videoChannelVM: CrVideoChannelVM by activityViewModels()
|
|
|
|
|
|
@@ -43,7 +62,7 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
|
|
// define: 2023/3/10 延迟初始化一个视频画布
|
|
// define: 2023/3/10 延迟初始化一个视频画布
|
|
private lateinit var surfaceView: SurfaceView
|
|
private lateinit var surfaceView: SurfaceView
|
|
private var btnTrigger: Button? = null
|
|
private var btnTrigger: Button? = null
|
|
- private var lblInfo:TextView?=null // define: 2023/8/4 显示信息
|
|
|
|
|
|
+ private var lblInfo: TextView? = null // define: 2023/8/4 显示信息
|
|
|
|
|
|
// define: 2023/3/11 视频通道
|
|
// define: 2023/3/11 视频通道
|
|
private var curVideoChannel: IVideoChannel? = null
|
|
private var curVideoChannel: IVideoChannel? = null
|
|
@@ -52,14 +71,14 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
|
|
private var videoDecoder: IVideoDecoder? = null
|
|
private var videoDecoder: IVideoDecoder? = null
|
|
|
|
|
|
// todo: 2023/8/4 视频相关参数
|
|
// todo: 2023/8/4 视频相关参数
|
|
- private var videoWidth:Int = -1
|
|
|
|
- private var videoHeight:Int = -1
|
|
|
|
- private var widthChanged:Boolean = false
|
|
|
|
- private var heightChange:Boolean = false
|
|
|
|
- private var fps:Int = -1
|
|
|
|
|
|
+ private var videoWidth: Int = -1
|
|
|
|
+ private var videoHeight: Int = -1
|
|
|
|
+ private var widthChanged: Boolean = false
|
|
|
|
+ private var heightChange: Boolean = false
|
|
|
|
+ private var fps: Int = -1
|
|
|
|
|
|
// todo: 2023/3/13 监听
|
|
// todo: 2023/3/13 监听
|
|
- lateinit var listener:FPVListener
|
|
|
|
|
|
+ lateinit var listener: FPVListener
|
|
|
|
|
|
/**
|
|
/**
|
|
* 创建视图
|
|
* 创建视图
|
|
@@ -75,7 +94,7 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
|
|
): View? {
|
|
): View? {
|
|
var view = inflater.inflate(R.layout.frag_fpv, container, false)
|
|
var view = inflater.inflate(R.layout.frag_fpv, container, false)
|
|
// todo: 2023/8/4 关闭 View Layer。 View Layer 可以加速无 invalidate() 时的刷新效率,但对于需要调用 invalidate() 的刷新无法加速
|
|
// todo: 2023/8/4 关闭 View Layer。 View Layer 可以加速无 invalidate() 时的刷新效率,但对于需要调用 invalidate() 的刷新无法加速
|
|
- view.setLayerType(View.LAYER_TYPE_NONE,null)
|
|
|
|
|
|
+ view.setLayerType(View.LAYER_TYPE_NONE, null)
|
|
// todo: 2023/3/13 给View挂接事件
|
|
// todo: 2023/3/13 给View挂接事件
|
|
view.setOnClickListener(clickListener)
|
|
view.setOnClickListener(clickListener)
|
|
// todo: 2023/3/10 挂接图传视图控件
|
|
// todo: 2023/3/10 挂接图传视图控件
|
|
@@ -86,6 +105,8 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
|
|
lblInfo = view.findViewById(R.id.fpv_info)
|
|
lblInfo = view.findViewById(R.id.fpv_info)
|
|
// todo: 2023/3/10 设置视图控件监听
|
|
// todo: 2023/3/10 设置视图控件监听
|
|
surfaceView.holder.addCallback(this)
|
|
surfaceView.holder.addCallback(this)
|
|
|
|
+ // todo: 2023/8/7 注册事件监听
|
|
|
|
+ CrApplication.getEventBus().register(this)
|
|
return view
|
|
return view
|
|
}
|
|
}
|
|
|
|
|
|
@@ -104,12 +125,12 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
|
|
* 点击事件
|
|
* 点击事件
|
|
*/
|
|
*/
|
|
private var clickListener = View.OnClickListener {
|
|
private var clickListener = View.OnClickListener {
|
|
- when(it.id){
|
|
|
|
|
|
+ when (it.id) {
|
|
R.id.fpv_trigger -> {
|
|
R.id.fpv_trigger -> {
|
|
// todo: 2023/3/13 切换视频通道
|
|
// todo: 2023/3/13 切换视频通道
|
|
videoChannelVM.triggerStreamSource()
|
|
videoChannelVM.triggerStreamSource()
|
|
}
|
|
}
|
|
- R.id.fpv_layout ->{
|
|
|
|
|
|
+ R.id.fpv_layout -> {
|
|
// todo: 2023/3/13 切换窗口
|
|
// todo: 2023/3/13 切换窗口
|
|
listener?.triggerWindow()
|
|
listener?.triggerWindow()
|
|
}
|
|
}
|
|
@@ -121,9 +142,10 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
|
|
*/
|
|
*/
|
|
private fun init() {
|
|
private fun init() {
|
|
// todo: 2023/8/4 注册订阅
|
|
// todo: 2023/8/4 注册订阅
|
|
- videoChannelVM.videoChannelInfo.observe(viewLifecycleOwner){
|
|
|
|
|
|
+ videoChannelVM.videoChannelInfo.observe(viewLifecycleOwner) {
|
|
it?.let {
|
|
it?.let {
|
|
- val videoStreamInfo = "fps:[${it.fps}] width:[${videoWidth}] height:[${videoHeight}]"
|
|
|
|
|
|
+ val videoStreamInfo =
|
|
|
|
+ "fps:[${it.fps}] width:[${videoWidth}] height:[${videoHeight}]"
|
|
lblInfo?.text = videoStreamInfo
|
|
lblInfo?.text = videoStreamInfo
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -158,7 +180,7 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
|
|
* 变更通道类型
|
|
* 变更通道类型
|
|
* @param channelType VideoChannelType
|
|
* @param channelType VideoChannelType
|
|
*/
|
|
*/
|
|
- private fun changeVideoDecoder(channelType:VideoChannelType){
|
|
|
|
|
|
+ private fun changeVideoDecoder(channelType: VideoChannelType) {
|
|
videoDecoder?.videoChannelType = channelType
|
|
videoDecoder?.videoChannelType = channelType
|
|
surfaceView.invalidate()
|
|
surfaceView.invalidate()
|
|
}
|
|
}
|
|
@@ -201,26 +223,27 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
|
|
*/
|
|
*/
|
|
private val streamDataListener = StreamDataListener {
|
|
private val streamDataListener = StreamDataListener {
|
|
it?.let {
|
|
it?.let {
|
|
- if(fps != it.fps){
|
|
|
|
|
|
+ if (fps != it.fps) {
|
|
fps = it.fps
|
|
fps = it.fps
|
|
- mainHandler.post{
|
|
|
|
|
|
+ mainHandler.post {
|
|
videoChannelVM.videoChannelInfo.value?.fps = fps
|
|
videoChannelVM.videoChannelInfo.value?.fps = fps
|
|
videoChannelVM.refreshVideoChannelInfo()
|
|
videoChannelVM.refreshVideoChannelInfo()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- if(videoWidth != it.width){
|
|
|
|
|
|
+ if (videoWidth != it.width) {
|
|
videoWidth = it.width
|
|
videoWidth = it.width
|
|
widthChanged = true
|
|
widthChanged = true
|
|
}
|
|
}
|
|
- if(videoHeight != it.height){
|
|
|
|
|
|
+ if (videoHeight != it.height) {
|
|
videoHeight = it.height
|
|
videoHeight = it.height
|
|
heightChange = true
|
|
heightChange = true
|
|
}
|
|
}
|
|
- if(widthChanged || heightChange){
|
|
|
|
|
|
+ if (widthChanged || heightChange) {
|
|
widthChanged = false
|
|
widthChanged = false
|
|
heightChange = false
|
|
heightChange = false
|
|
- mainHandler.post{
|
|
|
|
- videoChannelVM.videoChannelInfo.value?.resolution = "${videoWidth}*${videoHeight}"
|
|
|
|
|
|
+ mainHandler.post {
|
|
|
|
+ videoChannelVM.videoChannelInfo.value?.resolution =
|
|
|
|
+ "${videoWidth}*${videoHeight}"
|
|
videoChannelVM.refreshVideoChannelInfo()
|
|
videoChannelVM.refreshVideoChannelInfo()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -256,15 +279,239 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * 覆写视图释放
|
|
|
|
|
|
+ * 释放资源
|
|
*/
|
|
*/
|
|
- override fun onDestroyView() {
|
|
|
|
- super.onDestroyView()
|
|
|
|
|
|
+ private fun releaseResource(){
|
|
|
|
+ // todo: 2023/8/7 解除监听
|
|
curVideoChannel?.removeStreamDataListener(streamDataListener)
|
|
curVideoChannel?.removeStreamDataListener(streamDataListener)
|
|
|
|
+ videoDecoder?.removeDecoderStateChangeListener(decoderStateChangeListener)
|
|
|
|
+ videoDecoder?.removeYuvDataListener(yuvDataListener)
|
|
// todo: 2023/3/10 释放编码资源
|
|
// todo: 2023/3/10 释放编码资源
|
|
if (videoDecoder != null) {
|
|
if (videoDecoder != null) {
|
|
videoDecoder?.destroy()
|
|
videoDecoder?.destroy()
|
|
videoDecoder = null
|
|
videoDecoder = null
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 覆写视图释放
|
|
|
|
+ */
|
|
|
|
+ override fun onDestroyView() {
|
|
|
|
+ super.onDestroyView()
|
|
|
|
+ // todo: 2023/8/7 释放资源
|
|
|
|
+ releaseResource()
|
|
|
|
+ // todo: 2023/8/7 解除事件监听
|
|
|
|
+ CrApplication.getEventBus().unregister(this)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 生命周期函数
|
|
|
|
+ * 转入前台可见
|
|
|
|
+ */
|
|
|
|
+ override fun onResume() {
|
|
|
|
+ super.onResume()
|
|
|
|
+ // todo: 2023/8/7 添加监听
|
|
|
|
+ curVideoChannel?.addStreamDataListener(streamDataListener)
|
|
|
|
+ // todo: 2023/8/7 启动图传
|
|
|
|
+ handlerYUV(true)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 转入后台不可见
|
|
|
|
+ */
|
|
|
|
+ override fun onStop() {
|
|
|
|
+ super.onStop()
|
|
|
|
+ // todo: 2023/8/7 释放资源
|
|
|
|
+ releaseResource()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 模式切换 true表示切换到图传模式 false表示切换到YUV模式
|
|
|
|
+ * @param isSelected Boolean
|
|
|
|
+ */
|
|
|
|
+ private fun handlerYUV(isSelected: Boolean) {
|
|
|
|
+ if (!isSelected) {
|
|
|
|
+ // todo: 2023/8/7 如果解码器存在 则停用并置null
|
|
|
|
+ videoDecoder?.let {
|
|
|
|
+ videoDecoder!!.onPause()
|
|
|
|
+ videoDecoder!!.destroy()
|
|
|
|
+ videoDecoder = null
|
|
|
|
+ }
|
|
|
|
+ // todo: 2023/8/7 重新定义解码器
|
|
|
|
+ videoDecoder =
|
|
|
|
+ VideoDecoder(this@FragmentFPV.context, curVideoChannel!!.videoChannelType)
|
|
|
|
+ videoDecoder?.addDecoderStateChangeListener(decoderStateChangeListener)
|
|
|
|
+ videoDecoder?.addYuvDataListener(yuvDataListener)
|
|
|
|
+ } else {
|
|
|
|
+ // todo: 2023/8/7 如果解码器存在 则停用并置null
|
|
|
|
+ videoDecoder?.let {
|
|
|
|
+ videoDecoder!!.onPause()
|
|
|
|
+ videoDecoder!!.destroy()
|
|
|
|
+ videoDecoder = null
|
|
|
|
+ }
|
|
|
|
+ // todo: 2023/8/7 重新定义解码器
|
|
|
|
+ videoDecoder = VideoDecoder(
|
|
|
|
+ this@FragmentFPV.context,
|
|
|
|
+ curVideoChannel!!.videoChannelType,
|
|
|
|
+ DecoderOutputMode.SURFACE_MODE,
|
|
|
|
+ surfaceView.holder
|
|
|
|
+ )
|
|
|
|
+ videoDecoder?.addDecoderStateChangeListener(decoderStateChangeListener)
|
|
|
|
+ videoDecoder?.removeYuvDataListener(yuvDataListener)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * yuv数据监听
|
|
|
|
+ */
|
|
|
|
+ private val yuvDataListener =
|
|
|
|
+ YuvDataListener { mediaFormat, data, width, height ->
|
|
|
|
+ // todo: 2023/8/7 创建立即执行的协程
|
|
|
|
+ data?.let {
|
|
|
|
+ GlobalScope.launch {
|
|
|
|
+ // todo: 2023/8/7 执行一次保存 就恢复图传
|
|
|
|
+ handlerYUV(true)
|
|
|
|
+ // todo: 2023/8/7 保存图片
|
|
|
|
+ saveYuvData(mediaFormat,data,width,height)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 保存当前帧Yuv数据
|
|
|
|
+ * @param mediaFormat MediaFormat? 媒体格式
|
|
|
|
+ * @param data ByteArray? 数据
|
|
|
|
+ * @param width Int 宽度
|
|
|
|
+ * @param height Int 高度
|
|
|
|
+ */
|
|
|
|
+ private fun saveYuvData(mediaFormat: MediaFormat?, data: ByteArray?, width: Int, height: Int) {
|
|
|
|
+ data?.let {
|
|
|
|
+ mediaFormat?.let {
|
|
|
|
+ when(it.getInteger(MediaFormat.KEY_COLOR_FORMAT)){
|
|
|
|
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar->{
|
|
|
|
+ newSaveYuvDataToJPEG420P(data,width,height)
|
|
|
|
+ }
|
|
|
|
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar->{
|
|
|
|
+ newSaveYuvDataToJPEG(data,width,height)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }?:sendFailureMessage("数据格式异常")
|
|
|
|
+ }?:sendFailureMessage("无图像数据")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 发送错误消息事件
|
|
|
|
+ * @param error String 错误消息
|
|
|
|
+ */
|
|
|
|
+ private fun sendFailureMessage(error:String){
|
|
|
|
+ CrApplication.getEventBus().post(EventCommon<String>(CrCommonAction.VIDEO_SAVE_YUV_FAILURE,error))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 发送YUA数据保存成功消息
|
|
|
|
+ * @param fileName String 保存的文件名称
|
|
|
|
+ */
|
|
|
|
+ private fun sendSaveYUVSuccessMessage(fileName:String){
|
|
|
|
+ CrApplication.getEventBus().post(EventCommon<String>(CrCommonAction.VIDEO_SAVE_YUV_SUCCESS,fileName))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 保存yuv数据到JPEG420P
|
|
|
|
+ * @param yuvFrame ByteArray 帧数据
|
|
|
|
+ * @param width Int 宽度
|
|
|
|
+ * @param height Int 高度
|
|
|
|
+ */
|
|
|
|
+ private fun newSaveYuvDataToJPEG420P(yuvFrame: ByteArray, width: Int, height: Int) {
|
|
|
|
+ if (yuvFrame.size < width * height) {
|
|
|
|
+ sendFailureMessage("帧数据异常")
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ val length = width * height
|
|
|
|
+ val u = ByteArray(width * height / 4)
|
|
|
|
+ val v = ByteArray(width * height / 4)
|
|
|
|
+ for (i in u.indices) {
|
|
|
|
+ u[i] = yuvFrame[length + i]
|
|
|
|
+ v[i] = yuvFrame[length + u.size + i]
|
|
|
|
+ }
|
|
|
|
+ for (i in u.indices) {
|
|
|
|
+ yuvFrame[length + 2 * i] = v[i]
|
|
|
|
+ yuvFrame[length + 2 * i + 1] = u[i]
|
|
|
|
+ }
|
|
|
|
+ screenShot(
|
|
|
|
+ yuvFrame,
|
|
|
|
+ width,
|
|
|
|
+ height
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 保存Yuv数据到JPEG
|
|
|
|
+ * @param yuvFrame ByteArray 帧数据
|
|
|
|
+ * @param width Int 宽度
|
|
|
|
+ * @param height Int 高度
|
|
|
|
+ */
|
|
|
|
+ private fun newSaveYuvDataToJPEG(yuvFrame: ByteArray, width: Int, height: Int) {
|
|
|
|
+ if (yuvFrame.size < width * height) {
|
|
|
|
+ sendFailureMessage("帧数据异常")
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ val length = width * height
|
|
|
|
+ val u = ByteArray(width * height / 4)
|
|
|
|
+ val v = ByteArray(width * height / 4)
|
|
|
|
+ for (i in u.indices) {
|
|
|
|
+ v[i] = yuvFrame[length + 2 * i]
|
|
|
|
+ u[i] = yuvFrame[length + 2 * i + 1]
|
|
|
|
+ }
|
|
|
|
+ for (i in u.indices) {
|
|
|
|
+ yuvFrame[length + 2 * i] = u[i]
|
|
|
|
+ yuvFrame[length + 2 * i + 1] = v[i]
|
|
|
|
+ }
|
|
|
|
+ screenShot(
|
|
|
|
+ yuvFrame,
|
|
|
|
+ width,
|
|
|
|
+ height
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * 保存图片
|
|
|
|
+ * @param buf ByteArray 数据
|
|
|
|
+ * @param width Int 宽度
|
|
|
|
+ * @param height Int 高度
|
|
|
|
+ */
|
|
|
|
+ private fun screenShot(buf:ByteArray,width:Int,height:Int){
|
|
|
|
+ // todo: 2023/8/7 获取图片
|
|
|
|
+ val yuvImage = YuvImage(buf,ImageFormat.NV21,width,height,null)
|
|
|
|
+ // todo: 2023/8/7 保存文件
|
|
|
|
+ val outputFile:OutputStream
|
|
|
|
+ var fileName = "uav_${CrUnitManager.toSystemDate()}.jpg"
|
|
|
|
+ var path = "${CrUtil.IMAGE_PATH}${fileName}"
|
|
|
|
+ outputFile = try{
|
|
|
|
+ FileOutputStream(File(path))
|
|
|
|
+ }catch (e:FileNotFoundException){
|
|
|
|
+ sendFailureMessage("异常:${e.message}")
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ // todo: 2023/8/7 压缩保存图片
|
|
|
|
+ yuvImage.compressToJpeg(Rect(0,0,width,height),100,outputFile)
|
|
|
|
+ try{
|
|
|
|
+ outputFile.close()
|
|
|
|
+ // todo: 2023/8/7 发送正确消息
|
|
|
|
+ sendSaveYUVSuccessMessage(fileName)
|
|
|
|
+ }catch (e:IOException){
|
|
|
|
+ sendFailureMessage("IO错误:${e.message}")
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // todo: 2023/8/7 订阅事件
|
|
|
|
+ @Subscribe
|
|
|
|
+ fun onChanged(event:EventCommon<String>){
|
|
|
|
+ event?.let {
|
|
|
|
+ when(it.action){
|
|
|
|
+ CrCommonAction.VIDEO_SAVE_YUV->{
|
|
|
|
+ // todo: 2023/8/7 切换到YUV模式
|
|
|
|
+ handlerYUV(false)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|