| | |
| | | import timber.log.Timber; |
| | | |
| | | import com.anyun.h264.model.ResourceInfo; |
| | | import com.anyun.h264.model.WatermarkInfo; |
| | | |
| | | import org.json.JSONException; |
| | | import org.json.JSONObject; |
| | |
| | | private H264Encoder h264Encoder; |
| | | private H264FileTransmitter h264FileTransmitter; // H264文件传输器 |
| | | private String outputFileDirectory; // H264文件输出目录 |
| | | private WatermarkInfo currentWatermarkInfo; // 当前水印信息 |
| | | |
| | | // 默认编码参数 |
| | | private static final int DEFAULT_WIDTH = 640; |
| | |
| | | @Override |
| | | public List<ResourceInfo> getResourceList(String startTime, String endTime) throws RemoteException { |
| | | return H264EncodeService.this.getResourceList(startTime, endTime); |
| | | } |
| | | |
| | | @Override |
| | | public void setWatermarkInfo(String watermarkInfo) throws RemoteException { |
| | | H264EncodeService.this.setWatermarkInfo(watermarkInfo); |
| | | } |
| | | }; |
| | | |
| | |
| | | // 初始化并启动(使用配置中的分辨率) |
| | | int[] resolution = {width, height}; |
| | | if (h264Encoder.initialize(DEFAULT_CAMERA_ID_RANGE, null, resolution, false)) { |
| | | // 应用已保存的水印信息(如果有) |
| | | if (currentWatermarkInfo != null) { |
| | | h264Encoder.setWatermarkInfo(currentWatermarkInfo); |
| | | Timber.d("Applied saved watermark info to encoder"); |
| | | } |
| | | h264Encoder.start(); |
| | | Timber.d("File encode started successfully, output file: %s, resolution: %dx%d, framerate: %d", |
| | | outputFile.getAbsolutePath(), width, height, framerate); |
| | |
| | | // 初始化并启动(使用配置中的分辨率) |
| | | int[] resolution = {width, height}; |
| | | if (h264Encoder.initialize(DEFAULT_CAMERA_ID_RANGE, null, resolution, false)) { |
| | | // 应用已保存的水印信息(如果有) |
| | | if (currentWatermarkInfo != null) { |
| | | h264Encoder.setWatermarkInfo(currentWatermarkInfo); |
| | | Timber.d("Applied saved watermark info to encoder"); |
| | | } |
| | | h264Encoder.start(); |
| | | Timber.d("Network encode started successfully, server: %s:%d, resolution: %dx%d, framerate: %d", |
| | | config.ip, config.port, width, height, framerate); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 设置水印信息 |
| | | * @param watermarkInfoJson 水印信息JSON字符串,包含:车牌(plateNumber)、学员(student)、教练(coach)、 |
| | | * 经度(longitude)、纬度(latitude)、驾校(drivingSchool)、车速(speed) |
| | | * 示例:{"plateNumber":"京A12345","student":"张三","coach":"李四", |
| | | * "longitude":116.397128,"latitude":39.916527,"drivingSchool":"XX驾校","speed":60.5} |
| | | */ |
| | | private void setWatermarkInfo(String watermarkInfoJson) { |
| | | Timber.d("setWatermarkInfo called, watermarkInfoJson: %s", watermarkInfoJson); |
| | | |
| | | try { |
| | | if (watermarkInfoJson == null || watermarkInfoJson.trim().isEmpty()) { |
| | | Timber.w("Watermark info JSON is null or empty, clearing watermark"); |
| | | currentWatermarkInfo = null; |
| | | // 如果编码器正在运行,清除水印 |
| | | if (h264Encoder != null) { |
| | | h264Encoder.setWatermarkInfo(null); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | // 解析JSON |
| | | JSONObject json = new JSONObject(watermarkInfoJson); |
| | | WatermarkInfo watermarkInfo = new WatermarkInfo(); |
| | | |
| | | // 解析各个字段(使用 optString/optDouble 避免字段不存在时抛出异常) |
| | | watermarkInfo.setPlateNumber(json.optString("plateNumber", null)); |
| | | watermarkInfo.setStudent(json.optString("student", null)); |
| | | watermarkInfo.setCoach(json.optString("coach", null)); |
| | | |
| | | // 经度和纬度可能是数字或字符串 |
| | | if (json.has("longitude")) { |
| | | Object lonObj = json.get("longitude"); |
| | | if (lonObj instanceof Number) { |
| | | watermarkInfo.setLongitude(((Number) lonObj).doubleValue()); |
| | | } else if (lonObj instanceof String) { |
| | | try { |
| | | watermarkInfo.setLongitude(Double.parseDouble((String) lonObj)); |
| | | } catch (NumberFormatException e) { |
| | | Timber.w("Invalid longitude format: %s", lonObj); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (json.has("latitude")) { |
| | | Object latObj = json.get("latitude"); |
| | | if (latObj instanceof Number) { |
| | | watermarkInfo.setLatitude(((Number) latObj).doubleValue()); |
| | | } else if (latObj instanceof String) { |
| | | try { |
| | | watermarkInfo.setLatitude(Double.parseDouble((String) latObj)); |
| | | } catch (NumberFormatException e) { |
| | | Timber.w("Invalid latitude format: %s", latObj); |
| | | } |
| | | } |
| | | } |
| | | |
| | | watermarkInfo.setDrivingSchool(json.optString("drivingSchool", null)); |
| | | |
| | | // 车速可能是数字或字符串 |
| | | if (json.has("speed")) { |
| | | Object speedObj = json.get("speed"); |
| | | if (speedObj instanceof Number) { |
| | | watermarkInfo.setSpeed(((Number) speedObj).doubleValue()); |
| | | } else if (speedObj instanceof String) { |
| | | try { |
| | | watermarkInfo.setSpeed(Double.parseDouble((String) speedObj)); |
| | | } catch (NumberFormatException e) { |
| | | Timber.w("Invalid speed format: %s", speedObj); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 保存水印信息 |
| | | currentWatermarkInfo = watermarkInfo; |
| | | Timber.i("Watermark info parsed successfully: %s", watermarkInfo); |
| | | |
| | | // 如果编码器正在运行,立即应用水印 |
| | | if (h264Encoder != null) { |
| | | h264Encoder.setWatermarkInfo(watermarkInfo); |
| | | Timber.d("Watermark applied to encoder"); |
| | | } else { |
| | | Timber.d("Encoder not running, watermark will be applied when encoder starts"); |
| | | } |
| | | |
| | | } catch (JSONException e) { |
| | | Timber.e(e, "Failed to parse watermark info JSON: %s", watermarkInfoJson); |
| | | currentWatermarkInfo = null; |
| | | } catch (Exception e) { |
| | | Timber.e(e, "Unexpected error setting watermark info"); |
| | | currentWatermarkInfo = null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 从文件创建资源信息(如果文件在时间范围内) |
| | | */ |
| | | private ResourceInfo createResourceInfoFromFile(File file, Date startDate, Date endDate) { |