From be26453cfe152ea09ab70d654421013230a8fd30 Mon Sep 17 00:00:00 2001
From: xiaowusky <chenyangyang3858@dingtalk.com>
Date: Tue, 16 May 2023 10:04:07 +0800
Subject: [PATCH] =?UTF-8?q?desc:java=E6=96=B9=E5=BC=8F=E6=B0=B4=E5=8D=B0?=
 =?UTF-8?q?=E9=80=82=E9=85=8D=E8=A7=86=E9=A2=91=E5=88=86=E8=BE=A8=E7=8E=87?=
 =?UTF-8?q?=EF=BC=8C=E8=80=83=E8=99=91=E6=97=8B=E8=BD=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/org/easydarwin/push/MediaStream.java | 119 +++++++++---------
 .../java/org/easydarwin/sw/TxtOverlay.java    |  24 ++--
 2 files changed, 76 insertions(+), 67 deletions(-)

diff --git a/library/src/main/java/org/easydarwin/push/MediaStream.java b/library/src/main/java/org/easydarwin/push/MediaStream.java
index ef9a3dd..ab53430 100644
--- a/library/src/main/java/org/easydarwin/push/MediaStream.java
+++ b/library/src/main/java/org/easydarwin/push/MediaStream.java
@@ -3,12 +3,14 @@ package org.easydarwin.push;
 import android.app.Activity;
 import android.app.Application;
 import android.app.Service;
+
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleObserver;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.Observer;
 import androidx.lifecycle.OnLifecycleEvent;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -30,9 +32,11 @@ import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Process;
 import android.preference.PreferenceManager;
+
 import androidx.annotation.MainThread;
 import androidx.annotation.Nullable;
 import androidx.core.app.ActivityCompat;
+
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Surface;
@@ -90,15 +94,15 @@ public class MediaStream extends Service implements LifecycleObserver {
     }
 
     public class MediaBinder extends Binder {
-        public MediaStream getService(){
+        public MediaStream getService() {
             return MediaStream.this;
         }
     }
 
-    static class MediaStreamPublisher implements Publisher<MediaStream>, LifecycleObserver{
+    static class MediaStreamPublisher implements Publisher<MediaStream>, LifecycleObserver {
 
         private final LifecycleOwner lifecyclerOwner;
-        private  ServiceConnection conn;
+        private ServiceConnection conn;
         private final WeakReference<Context> context;
 
         private MediaStreamPublisher(Context context, LifecycleOwner owner) {
@@ -129,21 +133,21 @@ public class MediaStream extends Service implements LifecycleObserver {
             Context c = context.get();
             if (c == null) return;
             Intent serv = new Intent(c, MediaStream.class);
-            if (!c.bindService(serv, conn, 0)){
+            if (!c.bindService(serv, conn, 0)) {
                 s.onError(new IllegalStateException("bindService error!"));
                 s.onComplete();
             }
         }
 
         @OnLifecycleEvent(value = Lifecycle.Event.ON_DESTROY)
-        void destory(){
+        void destory() {
             Context c = context.get();
             if (c == null) return;
             c.unbindService(conn);
         }
     }
 
-    public static Publisher<MediaStream> getBindedMediaStream(final Context context, LifecycleOwner owner){
+    public static Publisher<MediaStream> getBindedMediaStream(final Context context, LifecycleOwner owner) {
         final MediaStreamPublisher publisher = new MediaStreamPublisher(context, owner);
         return publisher;
     }
@@ -186,13 +190,14 @@ public class MediaStream extends Service implements LifecycleObserver {
         boolean hevcEncode = false;
         public String mime = "";
     }
+
     public CodecInfo info = new CodecInfo();
 
 
     public void startStream(String ip, String port, String id, InitCallback callback) {
-        mEasyPusher.initPush( mApplicationContext, callback);
-        PushingState.sCodec = mSWCodec ? "x264":(info.hevcEncode ? "hevc":"avc");
-        mEasyPusher.setMediaInfo(!mSWCodec && info.hevcEncode ? Pusher.Codec.EASY_SDK_VIDEO_CODEC_H265:Pusher.Codec.EASY_SDK_VIDEO_CODEC_H264, 25, Pusher.Codec.EASY_SDK_AUDIO_CODEC_AAC, 1, 8000, 16);
+        mEasyPusher.initPush(mApplicationContext, callback);
+        PushingState.sCodec = mSWCodec ? "x264" : (info.hevcEncode ? "hevc" : "avc");
+        mEasyPusher.setMediaInfo(!mSWCodec && info.hevcEncode ? Pusher.Codec.EASY_SDK_VIDEO_CODEC_H265 : Pusher.Codec.EASY_SDK_VIDEO_CODEC_H264, 25, Pusher.Codec.EASY_SDK_AUDIO_CODEC_AAC, 1, 8000, 16);
         mEasyPusher.start(ip, port, String.format("%s.sdp", id), Pusher.TransType.EASY_RTP_OVER_TCP);
     }
 
@@ -212,7 +217,7 @@ public class MediaStream extends Service implements LifecycleObserver {
         if (pushScreenService != null) {
             stopPushScreen();
 
-        }else{
+        } else {
             Intent intent = new Intent(mApplicationContext, PushScreenService.class);
 
             conn = new ServiceConnection() {
@@ -252,7 +257,7 @@ public class MediaStream extends Service implements LifecycleObserver {
         public final String msg;
         public final String url;
         public final boolean screenPushing;
-        static String sCodec ="avc";
+        static String sCodec = "avc";
         public String videoCodec = sCodec;
 
         public PushingState(int state, String msg) {
@@ -351,7 +356,7 @@ public class MediaStream extends Service implements LifecycleObserver {
 
         mApplicationContext = getApplication();
         File youyuan = getFileStreamPath("SIMYOU.ttf");
-        if (!youyuan.exists()){
+        if (!youyuan.exists()) {
             AssetManager am = getAssets();
             try {
                 InputStream is = am.open("zk/SIMYOU.ttf");
@@ -403,32 +408,30 @@ public class MediaStream extends Service implements LifecycleObserver {
     }
 
     public void onPreviewFrame2(byte[] data, Object camera) {
+        boolean enableOverlay = PreferenceManager.getDefaultSharedPreferences(mApplicationContext).getBoolean("key_enable_video_overlay", true);
         if (camera instanceof Camera) {
-            if (PreferenceManager.getDefaultSharedPreferences(mApplicationContext).getBoolean("key_enable_video_overlay", true)) {
-                overlay.javaOverlay(data, "EasyPusher");
+            Camera.CameraInfo camInfo = new Camera.CameraInfo();
+            Camera.getCameraInfo(mCameraId, camInfo);
+            int cameraRotationOffset = camInfo.orientation;
+            if (enableOverlay) {
+                overlay.javaOverlay(data, width, height, cameraRotationOffset, "EasyPusher");
             }
             if (mDgree == 0) {
-                Camera.CameraInfo camInfo = new Camera.CameraInfo();
-                Camera.getCameraInfo(mCameraId, camInfo);
-                int cameraRotationOffset = camInfo.orientation;
-
                 if (cameraRotationOffset % 180 != 0) {
                     yuvRotate(data, 1, width, height, cameraRotationOffset);
                 }
                 save2file(data, String.format("/sdcard/yuv_%d_%d.yuv", height, width));
             }
-            if (PreferenceManager.getDefaultSharedPreferences(mApplicationContext).getBoolean("key_enable_video_overlay", true)) {
-                String txt;// = String.format("drawtext=fontfile=" + mApplicationContext.getFileStreamPath("SIMYOU.ttf") + ": text='%s%s':x=(w-text_w)/2:y=H-60 :fontcolor=white :box=1:boxcolor=0x00000000@0.3", "EasyPusher", new SimpleDateFormat("yyyy-MM-ddHHmmss").format(new Date()));
-                txt = "EasyPusher " + new SimpleDateFormat("yy-MM-dd HH:mm:ss SSS").format(new Date());
+            if (enableOverlay) {
+                String txt = "EasyPusher " + new SimpleDateFormat("yy-MM-dd HH:mm:ss SSS").format(new Date());
                 overlay.overlay(data, txt);
             }
             mVC.onVideo(data, NV21);
             mCamera.addCallbackBuffer(data);
         } else {
-            if (PreferenceManager.getDefaultSharedPreferences(mApplicationContext).getBoolean("key_enable_video_overlay", true)) {
-                String txt;// = String.format("drawtext=fontfile=" + mApplicationContext.getFileStreamPath("SIMYOU.ttf") + ": text='%s%s':x=(w-text_w)/2:y=H-60 :fontcolor=white :box=1:boxcolor=0x00000000@0.3", "EasyPusher", new SimpleDateFormat("yyyy-MM-ddHHmmss").format(new Date()));
-                txt = "EasyPusher " + new SimpleDateFormat("yy-MM-dd HH:mm:ss SSS").format(new Date());
-                overlay.javaOverlay(data, txt);
+            if (enableOverlay) {
+                String txt = "EasyPusher " + new SimpleDateFormat("yy-MM-dd HH:mm:ss SSS").format(new Date());
+                overlay.javaOverlay(data, width, height, 0, txt);
                 overlay.overlay(data, txt);
             }
             mVC.onVideo(data, NV21);
@@ -442,7 +445,7 @@ public class MediaStream extends Service implements LifecycleObserver {
             mCameraHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    startStream(ip,port, id);
+                    startStream(ip, port, id);
                 }
             });
             return;
@@ -454,7 +457,7 @@ public class MediaStream extends Service implements LifecycleObserver {
             @Override
             public void onCallback(int code) {
                 String msg = "";
-                String url = String.format("rtsp://%s:%s/%s.sdp", ip,port,id);
+                String url = String.format("rtsp://%s:%s/%s.sdp", ip, port, id);
                 switch (code) {
                     case EasyPusher.OnInitPusherCallback.CODE.EASY_ACTIVATE_INVALID_KEY:
                         msg = ("无效Key");
@@ -495,7 +498,7 @@ public class MediaStream extends Service implements LifecycleObserver {
         };
 
 //        mEasyPusher.initPush(ip, port, String.format("%s.sdp", id), mApplicationContext, callback);
-        startStream(ip,port,id, callback);
+        startStream(ip, port, id, callback);
     }
 
 
@@ -515,12 +518,12 @@ public class MediaStream extends Service implements LifecycleObserver {
     }
 
 
-    public boolean isScreenPushing(){
+    public boolean isScreenPushing() {
         return pushScreenService != null;
     }
 
 
-    public boolean isCameraPushing(){
+    public boolean isCameraPushing() {
         return cameraPushing;
     }
 
@@ -546,7 +549,7 @@ public class MediaStream extends Service implements LifecycleObserver {
     @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
     public void destory() {
         if (false)
-        closeCameraPreview();
+            closeCameraPreview();
         if (lifecycle != null) lifecycle.removeObserver(this);
     }
 
@@ -592,15 +595,15 @@ public class MediaStream extends Service implements LifecycleObserver {
     }
 
 
-    public static void initEncoder(Context context, CodecInfo info){
+    public static void initEncoder(Context context, CodecInfo info) {
         info.hevcEncode = false;
         boolean try265Encode = PreferenceManager.getDefaultSharedPreferences(context).getBoolean("try_265_encode", false);
-        ArrayList<CodecInfo> infos = listEncoders(try265Encode ?MediaFormat.MIMETYPE_VIDEO_HEVC:MediaFormat.MIMETYPE_VIDEO_AVC);
+        ArrayList<CodecInfo> infos = listEncoders(try265Encode ? MediaFormat.MIMETYPE_VIDEO_HEVC : MediaFormat.MIMETYPE_VIDEO_AVC);
         if (infos.isEmpty()) {
-            if (try265Encode){
+            if (try265Encode) {
                 infos = listEncoders(MediaFormat.MIMETYPE_VIDEO_AVC);
             }
-        }else{
+        } else {
             if (try265Encode) info.hevcEncode = true;
         }
         if (!infos.isEmpty()) {
@@ -608,7 +611,7 @@ public class MediaStream extends Service implements LifecycleObserver {
             info.mName = ci.mName;
             info.mColorFormat = ci.mColorFormat;
             info.mime = ci.mime;
-        }else{
+        } else {
             info.mName = "";
             info.mColorFormat = 0;
         }
@@ -643,10 +646,10 @@ public class MediaStream extends Service implements LifecycleObserver {
             if (value != null) {
                 // uvc camera.
                 uvcCamera = value;
-                value.setPreviewSize(width, height,1, 30, UVCCamera.PIXEL_FORMAT_YUV420SP,1.0f);
+                value.setPreviewSize(width, height, 1, 30, UVCCamera.PIXEL_FORMAT_YUV420SP, 1.0f);
                 return;
 //            value.startPreview();
-            }else{
+            } else {
                 Log.i(TAG, "NO UVCCamera");
                 uvcError = new Exception("no uvccamera connected!");
                 return;
@@ -752,7 +755,7 @@ public class MediaStream extends Service implements LifecycleObserver {
         return length;
     }
 
-    public synchronized boolean isRecording(){
+    public synchronized boolean isRecording() {
         return mIsRecording;
     }
 
@@ -828,11 +831,11 @@ public class MediaStream extends Service implements LifecycleObserver {
                 value.setFrameCallback(uvcFrameCallback, UVCCamera.PIXEL_FORMAT_YUV420SP/*UVCCamera.PIXEL_FORMAT_NV21*/);
                 value.startPreview();
                 cameraPreviewResolution.postValue(new int[]{width, height});
-            }catch (Throwable e){
+            } catch (Throwable e) {
                 uvcError = e;
             }
 
-        }else if (mCamera != null) {
+        } else if (mCamera != null) {
             int previewFormat = mCamera.getParameters().getPreviewFormat();
             Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
             int size = previewSize.width * previewSize.height * ImageFormat.getBitsPerPixel(previewFormat) / 8;
@@ -989,8 +992,7 @@ public class MediaStream extends Service implements LifecycleObserver {
     }
 
     /**
-     *
-     * @param cameraId      0表示后置,1表示前置,2表示uvc摄像头,-1表示默认切换(比如前后置来回切换.).在非-1的情况下,如果没有ID对应的摄像头,则也会作默认切换.
+     * @param cameraId 0表示后置,1表示前置,2表示uvc摄像头,-1表示默认切换(比如前后置来回切换.).在非-1的情况下,如果没有ID对应的摄像头,则也会作默认切换.
      */
     public Publisher<Object> switchCamera(final int cameraId) {
         Publisher pub = new Publisher<Object>() {
@@ -1005,7 +1007,7 @@ public class MediaStream extends Service implements LifecycleObserver {
         return pub;
     }
 
-    public void switchCamera(){
+    public void switchCamera() {
         switchCamera(-1).subscribe(new Subscriber<Object>() {
             @Override
             public void onSubscribe(Subscription s) {
@@ -1062,23 +1064,23 @@ public class MediaStream extends Service implements LifecycleObserver {
                 destroyCamera();
                 createCamera();
                 startPreview();
-            }finally {
-                if (uvcCamera != null){
-                    if (mSwitchCameraSubscriber != null){
+            } finally {
+                if (uvcCamera != null) {
+                    if (mSwitchCameraSubscriber != null) {
                         mSwitchCameraSubscriber.onNext(uvcCamera);
                     }
-                }else if (mCamera != null){
-                    if (mSwitchCameraSubscriber != null){
+                } else if (mCamera != null) {
+                    if (mSwitchCameraSubscriber != null) {
                         mSwitchCameraSubscriber.onNext(mCamera);
                     }
-                }else {
-                    if (mSwitchCameraSubscriber != null){
-                        if (uvcError != null){
+                } else {
+                    if (mSwitchCameraSubscriber != null) {
+                        if (uvcError != null) {
                             mSwitchCameraSubscriber.onError(uvcError);
-                        }else {
+                        } else {
                             mSwitchCameraSubscriber.onError(new IOException("could not create camera of id:" + mCameraId));
                         }
-                    }else{
+                    } else {
 //                        uvcCamera = new UVCCamera();
 //                        mSwitchCameraSubscriber.onNext(uvcCamera);
 //                        if (uvcFrameCallback != null){
@@ -1173,9 +1175,9 @@ public class MediaStream extends Service implements LifecycleObserver {
             mCameraHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    if (uvcCamera != null){
+                    if (uvcCamera != null) {
                         uvcCamera.setPreviewDisplay((Surface) null);
-                    }else {
+                    } else {
                         stopPreview();
                     }
                 }
@@ -1187,9 +1189,9 @@ public class MediaStream extends Service implements LifecycleObserver {
             mCameraHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    if (uvcCamera != null){
+                    if (uvcCamera != null) {
                         uvcCamera.setPreviewDisplay(new Surface(texture));
-                    }else {
+                    } else {
                         stopPreview();
                         if (cameraOpened) openCameraPreview();
                     }
@@ -1245,7 +1247,6 @@ public class MediaStream extends Service implements LifecycleObserver {
     }
 
 
-
     public static ArrayList<CodecInfo> listEncoders(String mime) {
         // 可能有多个编码库,都获取一下。。。
         ArrayList<CodecInfo> codecInfos = new ArrayList<CodecInfo>();
diff --git a/library/src/main/java/org/easydarwin/sw/TxtOverlay.java b/library/src/main/java/org/easydarwin/sw/TxtOverlay.java
index 39cb5ce..6caacb0 100644
--- a/library/src/main/java/org/easydarwin/sw/TxtOverlay.java
+++ b/library/src/main/java/org/easydarwin/sw/TxtOverlay.java
@@ -22,8 +22,8 @@ public class TxtOverlay {
 
     private final Context context;
 
-    int startY = 100;//水印Y轴的位置
-    int startX = 100;//水印X轴的位置
+    int startY = 50;//水印Y轴的位置
+    int startX = 10;//水印X轴的位置
     Bitmap bmp;
     byte[] mark;
 
@@ -55,15 +55,23 @@ public class TxtOverlay {
         txtOverlay(ctx, data, txt);
     }
 
-    public void javaOverlay(byte[] data,
+    public void javaOverlay(byte[] data, int width, int height, int cameraRotationOffset,
                             String txt) {
-        if (ctx == 0) return;
+        int bmpWidth = bmp.getWidth();
+        int bmpHeight = bmp.getHeight();
+        if (cameraRotationOffset == 90) {
+            startY = height - 50 - bmpHeight;
+            startX = 10;
+        } else if (cameraRotationOffset == 270) {
+            startY = 50;
+            startX = width - 50 - bmpWidth;
+        }
         int j = 0;
-        for (int i = startY; i < bmp.getHeight() + startY; i++) {
-            for (int c = 0; c < bmp.getWidth(); c++) {
+        for (int i = startY; i < bmpHeight + startY; i++) {
+            for (int c = 0; c < bmpWidth; c++) {
                 //去掉PNG水印的黑边
-                if (mark[j * bmp.getWidth() + c] != 0x10 && mark[j * bmp.getWidth() + c] != 0x80 && mark[j * bmp.getWidth() + c] != 0xeb) {
-                    System.arraycopy(mark, j * bmp.getWidth() + c, data, startX + i * 1280 + c, 1);
+                if (mark[j * bmpWidth + c] != 0x10 && mark[j * bmpWidth + c] != 0x80 && mark[j * bmpWidth + c] != 0xeb) {
+                    System.arraycopy(mark, j * bmpWidth + c, data, startX + i * width + c, 1);
                 }
             }
             j++;