| | |
| | | package com.anyun.h264 |
| | | |
| | | import android.os.Bundle |
| | | import android.os.Handler |
| | | import android.os.Looper |
| | | import android.util.Log |
| | | import androidx.activity.ComponentActivity |
| | | import androidx.activity.compose.setContent |
| | |
| | | import androidx.compose.ui.Alignment |
| | | import androidx.compose.ui.Modifier |
| | | import androidx.compose.ui.unit.dp |
| | | import com.anyun.h264.H264FileTransmitter.OnTransmitProgressCallback |
| | | import com.anyun.h264.ui.theme.MyApplicationTheme |
| | | import timber.log.Timber |
| | | import java.io.File |
| | |
| | | class MainActivity : ComponentActivity() { |
| | | private var h264Encoder: H264Encoder? = null |
| | | private var transmitter: H264FileTransmitter? = null |
| | | private var fileList: List<File> = emptyList() |
| | | private var currentFileIndex: Int = 0 |
| | | private val handler = Handler(Looper.getMainLooper()) |
| | | companion object{ |
| | | const val TAG ="MainActivity" |
| | | } |
| | |
| | | modifier = Modifier.padding(innerPadding), |
| | | isRunning = isRunning, |
| | | onStartH264Click = { |
| | | val success = startH264Encoder() |
| | | val success = startFileTransmitter() |
| | | if (success) { |
| | | isRunning = true |
| | | } |
| | | }, |
| | | onStopH264Click = { |
| | | stopH264Encoder() |
| | | // stopH264Encoder() |
| | | stopFileTransmitter() |
| | | isRunning = false |
| | | } |
| | | ) |
| | |
| | | override fun onDestroy() { |
| | | super.onDestroy() |
| | | stopH264Encoder() |
| | | stopFileTransmitter() |
| | | } |
| | | |
| | | private fun startFileTransmitter():Boolean { |
| | | |
| | | if (transmitter != null) { |
| | | Timber.w("H264Encoder is already running") |
| | | Timber.w("FileTransmitter is already running") |
| | | return false |
| | | } |
| | | |
| | | // 获取目录中的所有 .h264 文件 |
| | | val directory = application.applicationContext.getExternalFilesDir(null) |
| | | Timber.i("视频目录=${directory?.absolutePath}") |
| | | |
| | | if (directory?.isDirectory != true) { |
| | | Timber.e("Directory is not valid: ${directory?.absolutePath}") |
| | | return false |
| | | } |
| | | |
| | | // 获取所有 .h264 文件并按文件名排序 |
| | | fileList = directory.listFiles() |
| | | ?.filter { it.isFile && it.name.endsWith(".h264", ignoreCase = true) } |
| | | ?.sortedBy { it.name } |
| | | ?: emptyList() |
| | | |
| | | if (fileList.isEmpty()) { |
| | | Timber.w("No .h264 files found in directory") |
| | | return false |
| | | } |
| | | |
| | | Timber.i("Found ${fileList.size} .h264 files to transmit") |
| | | currentFileIndex = 0 |
| | | |
| | | try { |
| | | transmitter = H264FileTransmitter() |
| | |
| | | transmitter?.setServerAddress("192.168.16.138", 1078) |
| | | transmitter?.setProtocolType(JT1076ProtocolHelper.PROTOCOL_TYPE_TCP) // 或 PROTOCOL_TYPE_UDP |
| | | |
| | | |
| | | // 设置协议参数 |
| | | transmitter?.setProtocolParams("013120122580", 1.toByte()) |
| | | |
| | | |
| | | // 设置帧率(用于计算时间戳间隔) |
| | | transmitter?.setFrameRate(25) |
| | | transmitter?.setOnTransmitProgressCallback(object : OnTransmitProgressCallback { |
| | | override fun onProgress(currentFrame: Int, totalFrames: Int) { |
| | | val currentFile = if (currentFileIndex < fileList.size) fileList[currentFileIndex] else null |
| | | Timber.d("Transmitting file ${currentFileIndex + 1}/${fileList.size}: ${currentFile?.name}, frame: $currentFrame") |
| | | } |
| | | |
| | | override fun onComplete() { |
| | | val currentFile = if (currentFileIndex < fileList.size) fileList[currentFileIndex] else null |
| | | Timber.i("File transmission complete: ${currentFile?.name} (${currentFileIndex + 1}/${fileList.size})") |
| | | |
| | | // 使用 Handler 延迟调用,确保前一个文件的传输状态已重置 |
| | | currentFileIndex++ |
| | | handler.postDelayed({ |
| | | transmitNextFile() |
| | | }, 100) // 延迟100ms,确保前一个文件的 finally 块已执行 |
| | | } |
| | | |
| | | override fun onError(error: String?) { |
| | | val currentFile = if (currentFileIndex < fileList.size) fileList[currentFileIndex] else null |
| | | Timber.e("File transmission error: ${currentFile?.name}, error: $error") |
| | | |
| | | // 即使出错也继续传输下一个文件 |
| | | // 使用 Handler 延迟调用,确保前一个文件的传输状态已重置 |
| | | currentFileIndex++ |
| | | handler.postDelayed({ |
| | | transmitNextFile() |
| | | }, 100) // 延迟100ms,确保前一个文件的 finally 块已执行 |
| | | } |
| | | }) |
| | | |
| | | // 初始化Socket |
| | | if (transmitter?.initialize()==true) { |
| | | // 开始传输文件 |
| | | transmitter?.transmitFile("/storage/emulated/0/Android/data/com.anyun.h264/files/h264_1764574451071.h264") |
| | | if (transmitter?.initialize() == true) { |
| | | // 开始传输第一个文件 |
| | | transmitNextFile() |
| | | return true |
| | | }else{ |
| | | } else { |
| | | Timber.e("Failed to initialize transmitter") |
| | | transmitter = null |
| | | return false |
| | | } |
| | | } catch (e: Exception) { |
| | | Timber.e(e, "Failed to start H264Encoder") |
| | | Timber.e(e, "Failed to start FileTransmitter") |
| | | transmitter = null |
| | | return false |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 传输下一个文件 |
| | | */ |
| | | private fun transmitNextFile() { |
| | | if (transmitter == null) { |
| | | Timber.w("Transmitter is null, cannot transmit next file") |
| | | return |
| | | } |
| | | |
| | | if (currentFileIndex >= fileList.size) { |
| | | Timber.i("All files transmission complete! Total: ${fileList.size} files") |
| | | // 所有文件传输完成,停止传输器 |
| | | stopFileTransmitter() |
| | | return |
| | | } |
| | | |
| | | val nextFile = fileList[currentFileIndex] |
| | | Timber.i("Starting transmission of file ${currentFileIndex + 1}/${fileList.size}: ${nextFile.name}") |
| | | |
| | | // 传输下一个文件 |
| | | transmitter?.transmitFile(nextFile.absolutePath) |
| | | } |
| | | |
| | | /** |
| | | * 停止文件传输器 |
| | | */ |
| | | private fun stopFileTransmitter() { |
| | | // 移除所有待处理的 Handler 任务 |
| | | handler.removeCallbacksAndMessages(null) |
| | | |
| | | transmitter?.let { tx -> |
| | | try { |
| | | tx.stop() |
| | | Timber.d("FileTransmitter stopped") |
| | | } catch (e: Exception) { |
| | | Timber.e(e, "Failed to stop FileTransmitter") |
| | | } |
| | | } |
| | | transmitter = null |
| | | fileList = emptyList() |
| | | currentFileIndex = 0 |
| | | } |
| | | |
| | | private fun startH264Encoder(): Boolean { |
| | |
| | | // 设置输出文件(可选) |
| | | val outputFile = File(getExternalFilesDir(null), "test2.h264") |
| | | h264Encoder?.setOutputFile(outputFile.absolutePath) |
| | | h264Encoder?.setEnableFileOutput(false) // 启用文件输出 |
| | | h264Encoder?.setEnableFileOutput(true) // 启用文件输出 |
| | | |
| | | // 设置UDP服务器地址(可选) |
| | | // h264Encoder?.setServerAddress("58.48.93.67", 11935) |
| | | h264Encoder?.setEnableNetworkTransmission(true) |
| | | h264Encoder?.setEnableNetworkTransmission(false) |
| | | h264Encoder?.setServerAddress("192.168.16.138", 1078) |
| | | h264Encoder?.setProtocolParams("013120122580", 1) |
| | | |