diff --git a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java index cdc3f66..f501c82 100644 --- a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java +++ b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java @@ -620,7 +620,9 @@ public final class Taoyao implements ITaoyao { * @param message 信令消息 */ private void dispatch(final String content, final Header header, final Message message) { - if(this.taoyaoListener.preOnMessage(message)) { + final boolean done = this.taoyaoListener.preOnMessage(message); + if(done) { + Log.d(Taoyao.class.getSimpleName(), "信令前置处理完成:" + message); return; } switch (header.getSignal()) { diff --git a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/signal/ITaoyao.java b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/signal/ITaoyao.java index a775e73..098fd4e 100644 --- a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/signal/ITaoyao.java +++ b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/signal/ITaoyao.java @@ -15,52 +15,59 @@ import java.util.function.Function; public interface ITaoyao { /** - * @param signal 信令 - * @param args 消息主体内容 + * @param signal 信令标识 + * @param args 消息主体 * - * @return 消息 + * @return 信令消息 */ Message buildMessage(String signal, Object ... args); /** - * @param signal 信令 + * @param signal 信令标识 * @param body 消息主体 * - * @return 消息 + * @return 信令消息 */ Message buildMessage(String signal, Object body); /** + * 推送信令消息 + * * @param message 信令消息 */ void push(Message message); /** - * @param request 信令请求消息 + * 请求信令消息 * - * @return 信令响应消息 + * @param request 请求信令消息 + * + * @return 响应信令消息 */ Message request(Message request); /** - * @param request 信令请求消息 - * @param success 成功 + * 请求信令消息 * - * @return 结果 + * @param request 请求信令消息 + * @param success 成功请求执行 + * + * @return 执行结果 */ default T requestFuture(Message request, Function success) { return this.requestFuture(request, success, null); } /** - * @param request 信令请求消息 - * @param success 成功 - * @param failure 失败 + * 请求信令消息 * - * @return 结果 + * @param request 请求信令消息 + * @param success 成功请求执行 + * @param failure 失败请求执行 + * + * @return 执行结果 */ default T requestFuture(Message request, Function success, Function failure) { -// final CompletableFuture completableFuture = new CompletableFuture<>(); final Message response = this.request(request); if(response != null && response.isSuccess()) { return success.apply(response); @@ -74,20 +81,23 @@ public interface ITaoyao { } /** - * @param request 信令请求消息 - * @param success 成功 + * 请求信令消息 + * + * @param request 请求信令消息 + * @param success 成功请求执行 */ default void requestFuture(Message request, Consumer success) { this.requestFuture(request, success, null); } /** + * 请求信令消息 + * * @param request 信令请求消息 - * @param success 成功 - * @param failure 失败 + * @param success 成功请求执行 + * @param failure 失败请求执行 */ default void requestFuture(Message request, Consumer success, Consumer failure) { -// final CompletableFuture completableFuture = new CompletableFuture<>(); final Message response = this.request(request); if(response != null && response.isSuccess()) { success.accept(response); diff --git a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/signal/ITaoyaoListener.java b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/signal/ITaoyaoListener.java index cddfdfc..aacc261 100644 --- a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/signal/ITaoyaoListener.java +++ b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/signal/ITaoyaoListener.java @@ -14,7 +14,7 @@ public interface ITaoyaoListener { * * @param message 信令消息 * - * @return 是否继续处理信令 + * @return 是否完成 */ default boolean preOnMessage(Message message) { return false; diff --git a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/AiProcesser.java b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/AiProcesser.java index 9bc4ba1..3450c71 100644 --- a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/AiProcesser.java +++ b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/AiProcesser.java @@ -11,6 +11,10 @@ import org.webrtc.VideoFrame; */ public class AiProcesser extends VideoProcesser { + public AiProcesser() { + super("AI识别处理器"); + } + @Override protected void doProcess(VideoFrame.I420Buffer i420Buffer) { } diff --git a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/VideoProcesser.java b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/VideoProcesser.java index d25dfa5..30638be 100644 --- a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/VideoProcesser.java +++ b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/VideoProcesser.java @@ -1,16 +1,36 @@ package com.acgist.taoyao.media.video; +import android.util.Log; + import org.webrtc.VideoFrame; import java.io.Closeable; /** * 视频处理器 + * + * @author acgist */ public abstract class VideoProcesser implements Closeable { + /** + * 处理器名称 + */ + protected final String name; + /** + * 下一个视频处理器 + */ protected VideoProcesser next; + public VideoProcesser(String name) { + this.name = name; + } + + /** + * 处理视频帧 + * + * @param i420Buffer 视频帧 + */ public void process(VideoFrame.I420Buffer i420Buffer) { this.doProcess(i420Buffer); if(this.next == null) { @@ -20,9 +40,18 @@ public abstract class VideoProcesser implements Closeable { } } + /** + * 处理视频帧 + * + * @param i420Buffer 视频帧 + */ protected abstract void doProcess(VideoFrame.I420Buffer i420Buffer); + /** + * 关闭处理器 + */ public void close() { + Log.i(VideoProcesser.class.getSimpleName(), "关闭视频处理器:" + this.name); if(this.next == null) { // 忽略 } else { diff --git a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/WatermarkProcesser.java b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/WatermarkProcesser.java index 92c2f35..e093ed5 100644 --- a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/WatermarkProcesser.java +++ b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/WatermarkProcesser.java @@ -29,40 +29,84 @@ import java.util.TimerTask; */ public class WatermarkProcesser extends VideoProcesser { + /** + * 字符矩阵 + */ private static final WatermarkMatrix[] MATRICES = new WatermarkMatrix[256]; + /** + * 水印字符 + */ + private static final String WATERMARK = "-: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + /** + * 时间格式 + */ private final String format; + /** + * 格式 + */ + private final DateTimeFormatter formatter; + /** + * 视频宽度 + */ private final int width; + /** + * 视频高度 + */ private final int height; + /** + * 定时器 + */ private final Timer timer; + /** + * 字符矩阵 + */ private final WatermarkMatrix[] watermark; + static { + final char[] chars = WATERMARK.toCharArray(); + for (char value : chars) { + WatermarkProcesser.build(value); + } + } + + /** + * @param format 时间格式 + * @param width 视频宽度 + * @param height 视频高度 + */ public WatermarkProcesser(String format, int width, int height) { + super("水印处理器"); this.format = format; - this.width = width; + this.width = width; this.height = height; - final String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern(format)); - this.watermark = new WatermarkMatrix[date.length()]; - this.timer = new Timer("Watermark-Timer", true); + this.formatter = DateTimeFormatter.ofPattern(format); + final String date = LocalDateTime.now().format(this.formatter); + this.watermark = new WatermarkMatrix[date.length()]; + this.timer = new Timer("Watermark-Timer", true); this.init(); } + /** + * @param format 时间格式 + * @param width 视频宽度 + * @param height 视频高度 + * @param videoProcesser 下个视频处理器 + */ public WatermarkProcesser(String format, int width, int height, VideoProcesser videoProcesser) { this(format, width, height); this.next = videoProcesser; } + /** + * 加载水印 + */ private void init() { - final String source = "-: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - final char[] chars = source.toCharArray(); - for (char value : chars) { - this.build(value); - } this.timer.schedule(new TimerTask() { @Override public void run() { int index = 0; - final char[] chars = LocalDateTime.now().format(DateTimeFormatter.ofPattern(WatermarkProcesser.this.format)).toCharArray(); + final char[] chars = LocalDateTime.now().format(WatermarkProcesser.this.formatter).toCharArray(); for (char value : chars) { WatermarkProcesser.this.watermark[index] = MATRICES[value]; index++; @@ -71,21 +115,25 @@ public class WatermarkProcesser extends VideoProcesser { }, 1000, 1000); } - private void build(char source) { - // TODO:优化复用bitmap - final String target = Character.toString(source); + /** + * 创建字符矩阵 + * + * @param source 字符 + */ + private static void build(char source) { final Paint paint = new Paint(); paint.setColor(Color.WHITE); paint.setDither(true); paint.setTextSize(40.0F); paint.setTextAlign(Paint.Align.LEFT); paint.setFilterBitmap(true); - final Paint.FontMetricsInt box = paint.getFontMetricsInt(); - final int width = (int) paint.measureText(target); - final int height = box.descent - box.ascent; + final Paint.FontMetricsInt fontMetricsInt = paint.getFontMetricsInt(); + final String target = Character.toString(source); + final int width = (int) paint.measureText(target); + final int height = fontMetricsInt.descent - fontMetricsInt.ascent; final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Canvas canvas = new Canvas(bitmap); - canvas.drawText(target, 0, box.leading - box.ascent, paint); + canvas.drawText(target, 0, fontMetricsInt.leading - fontMetricsInt.ascent, paint); canvas.save(); final boolean[][] matrix = new boolean[width][height]; for (int j = 0; j < height; j++) { @@ -97,16 +145,16 @@ public class WatermarkProcesser extends VideoProcesser { } } } - MATRICES[source] = new WatermarkMatrix(width, height, matrix); bitmap.recycle(); + WatermarkProcesser.MATRICES[source] = new WatermarkMatrix(width, height, matrix); } @Override protected void doProcess(VideoFrame.I420Buffer i420Buffer) { - int widthPos = 0; + int widthPos = 0; int heightPos = 0; final ByteBuffer buffer = i420Buffer.getDataY(); - for (WatermarkMatrix matrix : watermark) { + for (WatermarkMatrix matrix : this.watermark) { if(matrix == null) { continue; } @@ -117,7 +165,7 @@ public class WatermarkProcesser extends VideoProcesser { } } } - widthPos += matrix.width; + widthPos += matrix.width; heightPos += matrix.height; } } @@ -128,12 +176,31 @@ public class WatermarkProcesser extends VideoProcesser { this.timer.cancel(); } + /** + * 水印矩阵 + * + * @author acgist + */ static class WatermarkMatrix { + /** + * 字符宽度 + */ int width; + /** + * 字符高度 + */ int height; + /** + * 字符矩阵 + */ boolean[][] matrix; + /** + * @param width 字符宽度 + * @param height 字符高度 + * @param matrix 字符矩阵 + */ public WatermarkMatrix(int width, int height, boolean[][] matrix) { this.width = width; this.height = height;