From 964db3e1a2d6e2ab277da1ffcb27064bd2776848 Mon Sep 17 00:00:00 2001
From: Dana <Dana_Lee1016@126.com>
Date: 星期一, 01 十二月 2025 14:53:03 +0800
Subject: [PATCH] 1.添加一个设置水印的aidl接口 2.h264Encoder 设置usbcamera加水印
---
app/src/main/java/com/anyun/h264/H264EncodeService.java | 111 +++++++++++++++++++++++++++
app/src/main/java/com/anyun/h264/service/H264EncodeServiceClient.java | 27 ++++++
app/src/main/aidl/com/anyun/h264/IH264EncodeService.aidl | 6 +
app/src/main/java/com/anyun/h264/H264Encoder.java | 84 +++++++++++++++++++++
4 files changed, 228 insertions(+), 0 deletions(-)
diff --git a/app/src/main/aidl/com/anyun/h264/IH264EncodeService.aidl b/app/src/main/aidl/com/anyun/h264/IH264EncodeService.aidl
index 4521fe8..87f6348 100644
--- a/app/src/main/aidl/com/anyun/h264/IH264EncodeService.aidl
+++ b/app/src/main/aidl/com/anyun/h264/IH264EncodeService.aidl
@@ -33,5 +33,11 @@
* @return 璧勬簮鍒楄〃锛堟牴鎹甁T/T 1076-2016琛�23瀹氫箟锛�
*/
List<ResourceInfo> getResourceList(String startTime, String endTime);
+
+ /**
+ * 璁剧疆姘村嵃淇℃伅
+ * @param watermarkInfo 姘村嵃淇℃伅瀛楃涓�
+ */
+ void setWatermarkInfo(String watermarkInfo);
}
diff --git a/app/src/main/java/com/anyun/h264/H264EncodeService.java b/app/src/main/java/com/anyun/h264/H264EncodeService.java
index 0f63836..9c535de 100644
--- a/app/src/main/java/com/anyun/h264/H264EncodeService.java
+++ b/app/src/main/java/com/anyun/h264/H264EncodeService.java
@@ -7,6 +7,7 @@
import timber.log.Timber;
import com.anyun.h264.model.ResourceInfo;
+import com.anyun.h264.model.WatermarkInfo;
import org.json.JSONException;
import org.json.JSONObject;
@@ -29,6 +30,7 @@
private H264Encoder h264Encoder;
private H264FileTransmitter h264FileTransmitter; // H264鏂囦欢浼犺緭鍣�
private String outputFileDirectory; // H264鏂囦欢杈撳嚭鐩綍
+ private WatermarkInfo currentWatermarkInfo; // 褰撳墠姘村嵃淇℃伅
// 榛樿缂栫爜鍙傛暟
private static final int DEFAULT_WIDTH = 640;
@@ -50,6 +52,11 @@
@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);
}
};
@@ -259,6 +266,11 @@
// 鍒濆鍖栧苟鍚姩锛堜娇鐢ㄩ厤缃腑鐨勫垎杈ㄧ巼锛�
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);
@@ -321,6 +333,11 @@
// 鍒濆鍖栧苟鍚姩锛堜娇鐢ㄩ厤缃腑鐨勫垎杈ㄧ巼锛�
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);
@@ -534,6 +551,100 @@
}
/**
+ * 璁剧疆姘村嵃淇℃伅
+ * @param watermarkInfoJson 姘村嵃淇℃伅JSON瀛楃涓诧紝鍖呭惈锛氳溅鐗�(plateNumber)銆佸鍛�(student)銆佹暀缁�(coach)銆�
+ * 缁忓害(longitude)銆佺含搴�(latitude)銆侀┚鏍�(drivingSchool)銆佽溅閫�(speed)
+ * 绀轰緥锛歿"plateNumber":"浜珹12345","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;
+ }
+
+ // 瑙f瀽JSON
+ JSONObject json = new JSONObject(watermarkInfoJson);
+ WatermarkInfo watermarkInfo = new WatermarkInfo();
+
+ // 瑙f瀽鍚勪釜瀛楁锛堜娇鐢� 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) {
diff --git a/app/src/main/java/com/anyun/h264/H264Encoder.java b/app/src/main/java/com/anyun/h264/H264Encoder.java
index 80a992a..2aa6e5d 100644
--- a/app/src/main/java/com/anyun/h264/H264Encoder.java
+++ b/app/src/main/java/com/anyun/h264/H264Encoder.java
@@ -4,11 +4,14 @@
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import com.anyun.libusbcamera.UsbCamera;
+import com.anyun.libusbcamera.WatermarkParam;
+import com.anyun.h264.model.WatermarkInfo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -148,6 +151,87 @@
}
/**
+ * 璁剧疆姘村嵃淇℃伅
+ * @param watermarkInfo 姘村嵃淇℃伅瀵硅薄
+ */
+ public void setWatermarkInfo(WatermarkInfo watermarkInfo) {
+ if (watermarkInfo == null) {
+ Timber.w("WatermarkInfo is null, disabling watermark");
+ usbCamera.enableWatermark(false, null);
+ return;
+ }
+
+ try {
+ // 鏋勫缓姘村嵃鏂囨湰鍒楄〃锛堝垎琛屾樉绀猴紝姣忚涓�涓俊鎭」锛�
+ ArrayList<WatermarkParam> watermarkParams = new ArrayList<>();
+
+ // 浠庡乏涓婅寮�濮嬶紝姣忚闂撮殧25鍍忕礌
+ int yOffset = 30;
+ int xOffset = 10;
+
+ // 杞︾墝鍙�
+ if (watermarkInfo.getPlateNumber() != null && !watermarkInfo.getPlateNumber().isEmpty()) {
+ watermarkParams.add(new WatermarkParam(xOffset, yOffset,
+ "杞︾墝:" + watermarkInfo.getPlateNumber()));
+ yOffset += 25;
+ }
+
+ // 瀛﹀憳濮撳悕
+ if (watermarkInfo.getStudent() != null && !watermarkInfo.getStudent().isEmpty()) {
+ watermarkParams.add(new WatermarkParam(xOffset, yOffset,
+ "瀛﹀憳:" + watermarkInfo.getStudent()));
+ yOffset += 25;
+ }
+
+ // 鏁欑粌濮撳悕
+ if (watermarkInfo.getCoach() != null && !watermarkInfo.getCoach().isEmpty()) {
+ watermarkParams.add(new WatermarkParam(xOffset, yOffset,
+ "鏁欑粌:" + watermarkInfo.getCoach()));
+ yOffset += 25;
+ }
+
+ // 浣嶇疆淇℃伅锛堢含搴�,缁忓害锛�
+ if (watermarkInfo.getLongitude() != null && watermarkInfo.getLatitude() != null) {
+ watermarkParams.add(new WatermarkParam(xOffset, yOffset,
+ String.format("浣嶇疆:%.6f,%.6f", watermarkInfo.getLatitude(), watermarkInfo.getLongitude())));
+ yOffset += 25;
+ }
+
+ // 椹炬牎鍚嶇О
+ if (watermarkInfo.getDrivingSchool() != null && !watermarkInfo.getDrivingSchool().isEmpty()) {
+ watermarkParams.add(new WatermarkParam(xOffset, yOffset,
+ "椹炬牎:" + watermarkInfo.getDrivingSchool()));
+ yOffset += 25;
+ }
+
+ // 杞﹂��
+ if (watermarkInfo.getSpeed() != null) {
+ watermarkParams.add(new WatermarkParam(xOffset, yOffset,
+ String.format("杞﹂��:%.1fkm/h", watermarkInfo.getSpeed())));
+ }
+
+ if (!watermarkParams.isEmpty()) {
+ // 鍚敤姘村嵃锛屼娇鐢ㄩ粯璁ゅ瓧浣撹矾寰勶紙濡傛灉绯荤粺鏈夊瓧浣撴枃浠讹級
+ // 棰滆壊锛�0-REVERSE锛堝弽鑹诧級锛�1-BLACK锛�2-WHITE锛�3-RED锛�4-GREEN锛�5-BLUE
+ // 瀛椾綋澶у皬銆佸�嶆暟鍙互鏍规嵁闇�瑕佽皟鏁�
+ String fontPath = "/system/fonts/DroidSans.ttf"; // 榛樿瀛椾綋璺緞锛屽鏋滀笉瀛樺湪鍙互浼爊ull
+ usbCamera.enableWatermark(true, fontPath);
+
+ // 璁剧疆姘村嵃锛氶鑹诧紙2=鐧借壊锛夛紝瀛椾綋澶у皬锛�24锛夛紝鍊嶆暟锛�1锛夛紝鏂囨湰鍒楄〃
+ usbCamera.setWatermark(2, 24, 1, watermarkParams);
+
+ Timber.d("Watermark set successfully: %s", watermarkInfo);
+ } else {
+ Timber.w("No watermark text to display, disabling watermark");
+ usbCamera.enableWatermark(false, null);
+ }
+ } catch (Exception e) {
+ Timber.e(e, "Failed to set watermark");
+ usbCamera.enableWatermark(false, null);
+ }
+ }
+
+ /**
* 鍒濆鍖栨憚鍍忓ご鍜岀紪鐮佸櫒
*/
public boolean initialize(int[] cameraIdRange, String cameraName, int[] resolution, boolean ayCamera) {
diff --git a/app/src/main/java/com/anyun/h264/service/H264EncodeServiceClient.java b/app/src/main/java/com/anyun/h264/service/H264EncodeServiceClient.java
index 728d4de..be12c39 100644
--- a/app/src/main/java/com/anyun/h264/service/H264EncodeServiceClient.java
+++ b/app/src/main/java/com/anyun/h264/service/H264EncodeServiceClient.java
@@ -40,6 +40,10 @@
* // 鑾峰彇璧勬簮鍒楄〃
* List<ResourceInfo> resources = client.getResourceList("240101000000", "240101235959");
*
+ * // 璁剧疆姘村嵃淇℃伅
+ * String watermarkJson = "{\"plateNumber\":\"浜珹12345\",\"student\":\"寮犱笁\",\"coach\":\"鏉庡洓\",\"longitude\":116.397128,\"latitude\":39.916527,\"drivingSchool\":\"XX椹炬牎\",\"speed\":60.5}";
+ * client.setWatermarkInfo(watermarkJson);
+ *
* // 瑙g粦鏈嶅姟
* client.unbindService();
* </pre>
@@ -202,5 +206,28 @@
return null;
}
}
+
+ /**
+ * 璁剧疆姘村嵃淇℃伅
+ * @param watermarkInfo JSON鏍煎紡鐨勬按鍗颁俊鎭瓧绗︿覆锛屽寘鍚細plateNumber锛堣溅鐗岋級銆乻tudent锛堝鍛橈級銆乧oach锛堟暀缁冿級銆乴ongitude锛堢粡搴︼級銆乴atitude锛堢含搴︼級銆乨rivingSchool锛堥┚鏍★級銆乻peed锛堣溅閫燂級
+ * 绀轰緥锛歿"plateNumber":"浜珹12345","student":"寮犱笁","coach":"鏉庡洓","longitude":116.397128,"latitude":39.916527,"drivingSchool":"XX椹炬牎","speed":60.5}
+ * 濡傛灉浼犲叆null鎴栫┖瀛楃涓诧紝灏嗘竻闄ゆ按鍗�
+ * @return true-鎴愬姛锛宖alse-澶辫触
+ */
+ public boolean setWatermarkInfo(String watermarkInfo) {
+ if (!isServiceBound()) {
+ Log.e(TAG, "Service is not bound");
+ return false;
+ }
+
+ try {
+ service.setWatermarkInfo(watermarkInfo);
+ Log.d(TAG, "setWatermarkInfo called with: " + watermarkInfo);
+ return true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling setWatermarkInfo", e);
+ return false;
+ }
+ }
}
--
Gitblit v1.8.0