| | |
| | | private H264FileTransmitter h264FileTransmitter; // H264文件传输器 |
| | | private String outputFileDirectory; // H264文件输出目录 |
| | | private WatermarkInfo currentWatermarkInfo; // 当前水印信息 |
| | | private static final int H264_FILE_RETENTION_DAYS = 5; // 可根据需求调整为3或5天 |
| | | private static final int H264_FILE_RETENTION_DAYS = 1; // 可根据需求调整为3或5天 |
| | | |
| | | // 多进程支持:第二个摄像头的服务连接 |
| | | private IH264EncodeService camera2Service; |
| | |
| | | config.width = DEFAULT_WIDTH; |
| | | config.height = DEFAULT_HEIGHT; |
| | | config.framerate = DEFAULT_FRAME_RATE; |
| | | config.enableFileOutput = false; |
| | | config.enableNetworkTransmit = false; |
| | | config.ip = null; |
| | | config.port = 0; |
| | | config.simPhone = null; |
| | |
| | | config.width = json.optInt("width", DEFAULT_WIDTH); |
| | | config.height = json.optInt("height", DEFAULT_HEIGHT); |
| | | config.framerate = json.optInt("framerate", DEFAULT_FRAME_RATE); |
| | | config.enableFileOutput = json.optBoolean("enableFileOutput", false); |
| | | config.enableNetworkTransmit = json.optBoolean("enableNetworkTransmit", false); |
| | | config.ip = json.optString("ip", null); |
| | | config.port = json.optInt("port", 0); |
| | | config.simPhone = json.optString("simPhone", null); |
| | |
| | | case 0: // 开启h264文件写入 |
| | | try { |
| | | EncodeConfig config0 = EncodeConfig.fromJson(jsonConfig); |
| | | return startFileEncode(config0); |
| | | config0.enableFileOutput = true; |
| | | config0.enableNetworkTransmit = false; |
| | | return startEncode(config0); |
| | | } catch (JSONException e) { |
| | | Timber.e(e, "Failed to parse JSON config: %s", jsonConfig); |
| | | return 1; |
| | |
| | | } |
| | | return stopEncoder(); |
| | | |
| | | case 2: // 开启网络推送h264(不写入文件) |
| | | case 2: // 开启网络推送h264(可同时写入文件) |
| | | try { |
| | | EncodeConfig config2 = EncodeConfig.fromJson(jsonConfig); |
| | | return startNetworkEncode(config2); |
| | | // 检查必需的配置参数 |
| | | if (config2 == null || config2.ip == null || config2.ip.trim().isEmpty() || config2.port <= 0) { |
| | | Timber.e("Network encode requires valid ip and port in config"); |
| | | return 1; // 失败 |
| | | } |
| | | config2.enableNetworkTransmit = true; |
| | | return startEncode(config2); |
| | | } catch (JSONException e) { |
| | | Timber.e(e, "Failed to parse JSON config: %s", jsonConfig); |
| | | return 1; |
| | | } |
| | | |
| | | case 3: // 停止h264编码并停止网络推送 |
| | | case 3: // 停止网络推送(保持文件写入) |
| | | // 检查是否指定了cameraId=2 |
| | | if (cameraId != null && cameraId == 2) { |
| | | return controlEncodeInProcess2(action, jsonConfig); |
| | | } |
| | | return stopEncoder(); |
| | | // 只关闭网络传输,保持文件写入 |
| | | if (h264Encoder != null) { |
| | | h264Encoder.setEnableNetworkTransmission(false); |
| | | Timber.d("Network transmission stopped, file output continues"); |
| | | return 0; |
| | | } else { |
| | | Timber.w("Encoder is not running"); |
| | | return 0; // 成功(没有运行的编码器,视为成功) |
| | | } |
| | | |
| | | case 4: // 开始传输H264文件 |
| | | try { |
| | |
| | | } |
| | | |
| | | /** |
| | | * 启动文件编码模式(只写入文件,不进行网络推送) |
| | | * 启动编码(统一方法,支持文件写入和网络传输的组合) |
| | | * @param config 编码配置 |
| | | * @return 0-成功,1-失败 |
| | | */ |
| | | private int startFileEncode(EncodeConfig config) { |
| | | Timber.d("Starting file encode mode"); |
| | | private int startEncode(EncodeConfig config) { |
| | | if (config == null) { |
| | | Timber.e("Encode config cannot be null"); |
| | | return 1; |
| | | } |
| | | Timber.d("Starting encode mode, fileOutput: %b, networkTransmit: %b", |
| | | config.enableFileOutput, config.enableNetworkTransmit); |
| | | |
| | | // 如果编码器已经在运行,先停止 |
| | | // 如果编码器已经在运行,只更新配置 |
| | | if (h264Encoder != null) { |
| | | Timber.w("Encoder is already running, stopping it first"); |
| | | stopEncoder(); |
| | | Timber.d("Encoder is already running, updating configuration"); |
| | | try { |
| | | h264Encoder.setEnableFileOutput(config.enableFileOutput); |
| | | |
| | | |
| | | // 如果开启网络传输,需要设置服务器地址和协议参数 |
| | | if (config.enableNetworkTransmit) { |
| | | if (config == null || config.ip == null || config.ip.trim().isEmpty() || config.port <= 0) { |
| | | Timber.e("Network transmit requires valid ip and port in config"); |
| | | return 1; // 失败 |
| | | } |
| | | h264Encoder.setServerAddress(config.ip, config.port); |
| | | |
| | | // 设置协议参数(使用配置中的simPhone,如果未提供则使用默认值) |
| | | String simPhone = config.simPhone != null && !config.simPhone.trim().isEmpty() |
| | | ? config.simPhone : "013120122580"; |
| | | h264Encoder.setProtocolParams(simPhone, (byte)1); |
| | | } |
| | | h264Encoder.setEnableNetworkTransmission(config.enableNetworkTransmit); |
| | | Timber.d("Encoder configuration updated successfully"); |
| | | return 0; // 成功 |
| | | } catch (Exception e) { |
| | | Timber.e(e, "Error updating encoder configuration"); |
| | | return 1; // 失败 |
| | | } |
| | | } |
| | | |
| | | // 编码器未运行,需要初始化并启动 |
| | | try { |
| | | // 如果开启网络传输,检查必需的配置参数 |
| | | if (config.enableNetworkTransmit) { |
| | | if (config == null || config.ip == null || config.ip.trim().isEmpty() || config.port <= 0) { |
| | | Timber.e("Network transmit requires valid ip and port in config"); |
| | | return 1; // 失败 |
| | | } |
| | | } |
| | | |
| | | // 创建编码器 |
| | | h264Encoder = new H264Encoder(); |
| | | |
| | | // 设置编码参数(使用配置中的参数) |
| | | int width = config != null && config.width > 0 ? config.width : DEFAULT_WIDTH; |
| | | int height = config != null && config.height > 0 ? config.height : DEFAULT_HEIGHT; |
| | | int framerate = config != null && config.framerate > 0 ? config.framerate : DEFAULT_FRAME_RATE; |
| | | int framerate = config != null && config.framerate > 0 ? config.framerate : DEFAULT_FRAME_RATE; |
| | | h264Encoder.setEncoderParams(width, height, framerate, DEFAULT_BITRATE); |
| | | |
| | | // 设置输出文件目录(H264Encoder会自动管理文件创建,每分钟一个文件) |
| | | // 使用一个临时文件名来设置目录,H264Encoder会在初始化时创建第一个文件 |
| | | File tempFile = new File(outputFileDirectory, "temp.h264"); |
| | | h264Encoder.setOutputFile(tempFile.getAbsolutePath()); |
| | | h264Encoder.setEnableFileOutput(true); // 启用文件输出 |
| | | h264Encoder.setOutputFile(tempFile.getAbsolutePath()); |
| | | h264Encoder.setEnableFileOutput(config.enableFileOutput); |
| | | |
| | | // 禁用网络传输 |
| | | h264Encoder.setEnableNetworkTransmission(false); |
| | | // 设置网络传输 |
| | | h264Encoder.setEnableNetworkTransmission(config.enableNetworkTransmit); |
| | | if (config.enableNetworkTransmit) { |
| | | h264Encoder.setServerAddress(config.ip, config.port); |
| | | |
| | | // 设置协议参数(使用配置中的simPhone,如果未提供则使用默认值) |
| | | String simPhone = config.simPhone != null && !config.simPhone.trim().isEmpty() |
| | | ? config.simPhone : "013120122580"; |
| | | h264Encoder.setProtocolParams(simPhone, (byte)1); |
| | | } |
| | | |
| | | // 初始化并启动(使用配置中的分辨率) |
| | | // 根据cameraId选择摄像头范围 |
| | |
| | | Timber.d("Applied saved watermark info to encoder"); |
| | | } |
| | | h264Encoder.start(); |
| | | Timber.d("File encode started successfully, output directory: %s, resolution: %dx%d, framerate: %d", |
| | | outputFileDirectory, width, height, framerate); |
| | | return 0; // 成功 |
| | | } else { |
| | | Timber.e("Failed to initialize encoder"); |
| | | h264Encoder = null; |
| | | return 1; // 失败 |
| | | } |
| | | } catch (Exception e) { |
| | | Timber.e(e, "Failed to start file encode"); |
| | | h264Encoder = null; |
| | | return 1; // 失败 |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 启动网络推送模式(只进行网络推送,不写入文件) |
| | | */ |
| | | private int startNetworkEncode(EncodeConfig config) { |
| | | Timber.d("Starting network encode mode"); |
| | | |
| | | // 如果编码器已经在运行,先停止 |
| | | if (h264Encoder != null) { |
| | | Timber.w("Encoder is already running, stopping it first"); |
| | | stopEncoder(); |
| | | } |
| | | |
| | | // 检查必需的配置参数 |
| | | if (config == null || config.ip == null || config.ip.trim().isEmpty() || config.port <= 0) { |
| | | Timber.e("Network encode requires valid ip and port in config"); |
| | | return 1; // 失败 |
| | | } |
| | | |
| | | try { |
| | | // 创建编码器 |
| | | h264Encoder = new H264Encoder(); |
| | | |
| | | // 设置编码参数(使用配置中的参数) |
| | | int width = config != null && config.width > 0 ? config.width : DEFAULT_WIDTH; |
| | | int height = config != null && config.height > 0 ? config.height : DEFAULT_HEIGHT; |
| | | int framerate = config != null && config.framerate > 0 ? config.framerate : DEFAULT_FRAME_RATE; |
| | | h264Encoder.setEncoderParams(width, height, framerate, DEFAULT_BITRATE); |
| | | |
| | | // 设置输出文件目录(H264Encoder会自动管理文件创建,每分钟一个文件) |
| | | // 使用一个临时文件名来设置目录,H264Encoder会在初始化时创建第一个文件 |
| | | File tempFile = new File(outputFileDirectory, "temp.h264"); |
| | | h264Encoder.setOutputFile(tempFile.getAbsolutePath()); |
| | | h264Encoder.setEnableFileOutput(config.enableFileOutput); // 启用文件输出 |
| | | |
| | | |
| | | // 启用网络传输并设置服务器地址 |
| | | h264Encoder.setEnableNetworkTransmission(config.enableNetworkTransmit); |
| | | h264Encoder.setServerAddress(config.ip, config.port); |
| | | |
| | | // 设置协议参数(使用配置中的simPhone,如果未提供则使用默认值) |
| | | String simPhone = config.simPhone != null && !config.simPhone.trim().isEmpty() |
| | | ? config.simPhone : "013120122580"; |
| | | h264Encoder.setProtocolParams(simPhone, (byte)1); |
| | | |
| | | // 初始化并启动(使用配置中的分辨率) |
| | | // 根据cameraId选择摄像头范围 |
| | | int[] cameraIdRange = DEFAULT_CAMERA_ID_RANGE; |
| | | |
| | | int[] resolution = {width, height}; |
| | | if (h264Encoder.initialize(cameraIdRange, null, resolution, false)) { |
| | | // 应用已保存的水印信息(如果有) |
| | | if (currentWatermarkInfo != null) { |
| | | h264Encoder.setWatermarkInfo(currentWatermarkInfo); |
| | | Timber.d("Applied saved watermark info to encoder"); |
| | | Timber.d("Encode started successfully, fileOutput: %b, networkTransmit: %b, resolution: %dx%d, framerate: %d", |
| | | config.enableFileOutput, config.enableNetworkTransmit, width, height, framerate); |
| | | if (config.enableNetworkTransmit) { |
| | | Timber.d("Network server: %s:%d", config.ip, config.port); |
| | | } |
| | | h264Encoder.start(); |
| | | Timber.d("Network encode started successfully, server: %s:%d, resolution: %dx%d, framerate: %d", |
| | | config.ip, config.port, width, height, framerate); |
| | | return 0; // 成功 |
| | | } else { |
| | | Timber.e("Failed to initialize encoder"); |
| | |
| | | return 1; // 失败 |
| | | } |
| | | } catch (Exception e) { |
| | | Timber.e(e, "Failed to start network encode"); |
| | | Timber.e(e, "Failed to start encode"); |
| | | h264Encoder = null; |
| | | return 1; // 失败 |
| | | } |
| | |
| | | h264FileTransmitter.setOnTransmitProgressCallback(new H264FileTransmitter.OnTransmitProgressCallback() { |
| | | @Override |
| | | public void onProgress(int currentFrame, int totalFrames) { |
| | | Timber.d("File transmit progress: frame %d%s", currentFrame, |
| | | totalFrames > 0 ? " of " + totalFrames : ""); |
| | | // Timber.d("File transmit progress: frame %d%s", currentFrame, |
| | | // totalFrames > 0 ? " of " + totalFrames : ""); |
| | | } |
| | | |
| | | @Override |