diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ce86e08a..390d8b1f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -93,7 +93,6 @@ diff --git a/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivity.java b/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivity.java index e45ab8fa..8d48dfe8 100644 --- a/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivity.java +++ b/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivity.java @@ -10,7 +10,6 @@ import android.graphics.Insets; import android.graphics.Paint; import android.graphics.Point; import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.net.Uri; import android.opengl.GLException; @@ -23,12 +22,10 @@ import android.text.TextUtils; import android.util.Log; import android.view.Window; import android.view.WindowInsets; -import android.view.WindowInsetsController; import android.view.WindowManager; import android.view.WindowMetrics; import android.widget.FrameLayout; -import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -85,7 +82,9 @@ public class Camera2VideoActivity extends AppCompatActivity { private Paint mPaint; private Paint mPaintStroker; private Bitmap mBitmap; - GlWatermarkFilter mOSDFilter = null; + private GlWatermarkFilter mOSDFilter = null; + private Object mBitmapLocker = new Object(); + private SimpleDateFormat mDateFormater; // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss a"); @@ -97,7 +96,7 @@ public class Camera2VideoActivity extends AppCompatActivity { private int mStatusBarHeight = -1; private long mOsdTs = 0; private Semaphore mOSDSemaphore = new Semaphore(0); - private Thread mOsdThread = null; + private static class OSD_ITEM { @@ -130,32 +129,53 @@ public class Camera2VideoActivity extends AppCompatActivity { private Runnable mTimerRunnable = new Runnable() { @Override public void run() { + + synchronized (mBitmapLocker) { + if (mBitmap != null) { + Bitmap bitmap = mBitmap; + mBitmap = null; + mOSDFilter.updateBitmap(bitmap); + } + } + long ts = System.currentTimeMillis(); + mOsdTs = ts + 1000; // next second long ms = ts % 1000; - if (ms > 900) { - ts += 1000 - ms; - ms = 0; - } - // updateOSD(ts); - Bitmap bitmap = mBitmap; - mBitmap = null; - mOSDFilter.updateBitmap(bitmap); + Log.d("OSD", "Cur TS=" + Long.toString(ts / 1000) + " Timer=" + Long.toString(1000 - ms)); - mBitmap = Bitmap.createBitmap(mVideoWidth, mVideoHeight, Bitmap.Config.ARGB_8888); - mOsdTs = ts; mOSDSemaphore.release(); + mHandler.postDelayed(this, 1000 - ms); } }; + private Thread mOsdThread = new Thread(new Runnable() { + @Override + public void run() { + while (true) { + try { + mOSDSemaphore.acquire(); + } catch (Exception ex) { + } + + if (mOsdTs == -1) { + break; + } + + updateOSD(mOsdTs); + } + } + }); + + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); Window win = getWindow(); - // win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { /* @@ -206,9 +226,6 @@ public class Camera2VideoActivity extends AppCompatActivity { } protected void onCreateActivity() { - // - - // SysApi.setCam3V3Enable(true); Intent intent = getIntent(); @@ -288,27 +305,11 @@ public class Camera2VideoActivity extends AppCompatActivity { mHandler = new Handler(); - mOsdThread = new Thread(new Runnable() { - @Override - public void run() { - while (true) { - try { - mOSDSemaphore.acquire(); - } catch (Exception ex) { - - } - - if (mOsdTs == -1) { - break; - } - - updateOSD(mOsdTs); - } - } - }); - mOsdThread.start(); + long ts = 0; + long zeroTs = 0; + if (!TextUtils.isEmpty(mOSDLeftTop) || !TextUtils.isEmpty(mOSDLeftTop) || !TextUtils.isEmpty(mOSDLeftTop) || !TextUtils.isEmpty(mOSDLeftTop)) { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.FILL); @@ -327,33 +328,46 @@ public class Camera2VideoActivity extends AppCompatActivity { Canvas canvas = new Canvas(mBitmap); canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); - mOSDFilter = new GlWatermarkFilter(mBitmap); - - long ts = System.currentTimeMillis(); + ts = System.currentTimeMillis(); + zeroTs = ts - (ts % 1000); + initOSD(zeroTs); - initOSD(ts); + mOSDFilter = new GlWatermarkFilter(mBitmap); - mOsdTs = ts + 1000; - long ms = ts % 1000; - mOSDSemaphore.release(); - mHandler.postDelayed(mTimerRunnable, 1000 - ms); + mBitmap = Bitmap.createBitmap(mVideoWidth, mVideoHeight, Bitmap.Config.ARGB_8888); + updateOSD(zeroTs + 1000); } + final long prevZeroTs = zeroTs; mHandler.postDelayed(new Runnable() { @Override public void run() { mNextVideoAbsolutePath = getVideoFilePath(); mGPUCameraRecorder.start(mNextVideoAbsolutePath); + + long ts2 = System.currentTimeMillis(); + long zeroTs2 = ts2 - (ts2 % 1000); + + if (zeroTs2 > prevZeroTs) { + // Next second + mOSDFilter.updateBitmap(mBitmap); + mBitmap = null; + mOsdTs = zeroTs2 + 1000; + mOSDSemaphore.release(); + } + + Log.d("OSD", "Cur TS=" + Long.toString(ts2 / 1000) + " Timer=" + Long.toString(1000 - (ts2 - zeroTs2))); + mHandler.postDelayed(mTimerRunnable, 1000 - (ts2 - zeroTs2)); } - }, 32); + }, 0); mHandler.postDelayed(new Runnable() { @Override public void run() { mGPUCameraRecorder.stop(); } - }, 48 + mDuration * 1000); + }, 16 + mDuration * 1000); // getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } @@ -372,11 +386,13 @@ public class Camera2VideoActivity extends AppCompatActivity { private void initOSD(long ts) { + Log.d("OSD", "INIT OSD " + Long.toString(ts / 1000)); + if (mStatusBarHeight == -1) { mStatusBarHeight = getStatusBarHeight(this); } int statusHeight = mStatusBarHeight; - synchronized (mBitmap) { + synchronized (mBitmapLocker) { int bmWidth = mBitmap.getWidth(); int bmHeight = mBitmap.getHeight(); int margin = mOSDMargin; @@ -416,7 +432,6 @@ public class Camera2VideoActivity extends AppCompatActivity { } else { String newText = updateOSDTime(item, ts); - Log.d("OSD", "INIT OSD x=" + origin.x + " y=" + origin.y); canvas.drawText(newText, origin.x, origin.y, mPaint); canvas.drawText(newText, origin.x, origin.y, mPaintStroker); @@ -556,72 +571,67 @@ public class Camera2VideoActivity extends AppCompatActivity { private void updateOSD(long ts) { + Log.d("OSD", "prepareOSD " + Long.toString(ts / 1000)); if (mStatusBarHeight == -1) { mStatusBarHeight = getStatusBarHeight(this); } int statusHeight = mStatusBarHeight; - synchronized (mBitmap) { - int bmWidth = mBitmap.getWidth(); - int bmHeight = mBitmap.getHeight(); - int margin = mOSDMargin; - Canvas canvas = new Canvas(mBitmap); - boolean aa = canvas.isHardwareAccelerated(); - Rect textBounds = new Rect(); + Bitmap bm = Bitmap.createBitmap(mVideoWidth, mVideoHeight, Bitmap.Config.ARGB_8888); - // mBitmap.eraseColor(Color.argb(0, 0, 0, 0)); - // bitmap.eraseColor(Color.argb(0, 0, 0, 0)); + Canvas canvas = new Canvas(bm); + boolean aa = canvas.isHardwareAccelerated(); + Rect textBounds = new Rect(); - canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); - for (OSD_ITEM osdItem : mOSDItems) { - String text = updateOSDTime(osdItem.text, ts); - - int x = osdItem.previousRect.left; - int y = osdItem.previousRect.top; - - if ((osdItem.mask & TIME_MASK_LT) != 0) { - // canvas.drawRect(osdItem.previousRect, mEmptyPaint); - mPaintStroker.getTextBounds(text, 0, text.length(), textBounds); - - Log.d("OSD", "UPD OSD x=" + x + " y=" + y); - canvas.drawText(text, x, y, mPaint); - canvas.drawText(text, x, y, mPaintStroker); - osdItem.previousRect.set(x, y, x + textBounds.width(), y + textBounds.height()); - - } else if ((osdItem.mask & TIME_MASK_LB) != 0) { - // canvas.drawRect(osdItem.previousRect, mEmptyPaint); - mPaintStroker.getTextBounds(text, 0, text.length(), textBounds); - - y = osdItem.origin.y - textBounds.height(); - canvas.drawText(text, x, y, mPaint); - canvas.drawText(text, x, y, mPaintStroker); - osdItem.previousRect.set(x, y, x + textBounds.width(), y + textBounds.height()); - - } else if ((osdItem.mask & TIME_MASK_RT) != 0) { - // canvas.drawRect(osdItem.previousRect, mEmptyPaint); - mPaintStroker.getTextBounds(text, 0, text.length(), textBounds); - - x = osdItem.origin.x - textBounds.width(); - canvas.drawText(text, x, osdItem.origin.y, mPaint); - canvas.drawText(text, x, osdItem.origin.y, mPaintStroker); - osdItem.previousRect.set(x, osdItem.origin.y, x + textBounds.width(), osdItem.origin.y + textBounds.height()); - - } else if ((osdItem.mask & TIME_MASK_RB) != 0) { - // canvas.drawRect(osdItem.previousRect, mEmptyPaint); - mPaintStroker.getTextBounds(text, 0, text.length(), textBounds); - - x = osdItem.origin.x - textBounds.width(); - y = osdItem.origin.y - textBounds.height(); - canvas.drawText(text, x, y, mPaint); - canvas.drawText(text, x, y, mPaintStroker); - osdItem.previousRect.set(x, y, x + textBounds.width(), y + textBounds.height()); - } else { - canvas.drawText(text, x, y, mPaint); - canvas.drawText(text, x, y, mPaintStroker); - } + for (OSD_ITEM osdItem : mOSDItems) { + String text = updateOSDTime(osdItem.text, ts); + + int x = osdItem.previousRect.left; + int y = osdItem.previousRect.top; + + if ((osdItem.mask & TIME_MASK_LT) != 0) { + mPaintStroker.getTextBounds(text, 0, text.length(), textBounds); + + // Log.d("OSD", "UPD OSD x=" + x + " y=" + y); + canvas.drawText(text, x, y, mPaint); + canvas.drawText(text, x, y, mPaintStroker); + osdItem.previousRect.set(x, y, x + textBounds.width(), y + textBounds.height()); + + } else if ((osdItem.mask & TIME_MASK_LB) != 0) { + mPaintStroker.getTextBounds(text, 0, text.length(), textBounds); + + y = osdItem.origin.y - textBounds.height(); + canvas.drawText(text, x, y, mPaint); + canvas.drawText(text, x, y, mPaintStroker); + osdItem.previousRect.set(x, y, x + textBounds.width(), y + textBounds.height()); + + } else if ((osdItem.mask & TIME_MASK_RT) != 0) { + mPaintStroker.getTextBounds(text, 0, text.length(), textBounds); + + x = osdItem.origin.x - textBounds.width(); + canvas.drawText(text, x, osdItem.origin.y, mPaint); + canvas.drawText(text, x, osdItem.origin.y, mPaintStroker); + osdItem.previousRect.set(x, osdItem.origin.y, x + textBounds.width(), osdItem.origin.y + textBounds.height()); + + } else if ((osdItem.mask & TIME_MASK_RB) != 0) { + mPaintStroker.getTextBounds(text, 0, text.length(), textBounds); + + x = osdItem.origin.x - textBounds.width(); + y = osdItem.origin.y - textBounds.height(); + canvas.drawText(text, x, y, mPaint); + canvas.drawText(text, x, y, mPaintStroker); + osdItem.previousRect.set(x, y, x + textBounds.width(), y + textBounds.height()); + } else { + canvas.drawText(text, x, y, mPaint); + canvas.drawText(text, x, y, mPaintStroker); } } + + synchronized (mBitmapLocker) { + mBitmap = bm; + } } private String updateOSDTime(String osd, long ts) { @@ -640,7 +650,6 @@ public class Camera2VideoActivity extends AppCompatActivity { return newOSD; } - private void releaseCamera() { if (mPreviewView != null) { mPreviewView.onPause(); @@ -685,8 +694,6 @@ public class Camera2VideoActivity extends AppCompatActivity { mNextVideoAbsolutePath = getVideoFilePath(this); } - - mGPUCameraRecorder = new GPUCameraRecorderBuilder(this, mPreviewView) //.recordNoFilter(true) .cameraRecordListener(new CameraRecordListener() { @@ -712,9 +719,6 @@ public class Camera2VideoActivity extends AppCompatActivity { @Override public void onRecordStart() { - - - } @Override @@ -729,7 +733,6 @@ public class Camera2VideoActivity extends AppCompatActivity { @Override public void onVideoFileReady() { - } }) .videoSize(mVideoWidth, mVideoHeight) @@ -740,7 +743,6 @@ public class Camera2VideoActivity extends AppCompatActivity { if (mOSDFilter != null) { mGPUCameraRecorder.setFilter(mOSDFilter); } - } // private void changeFilter(Filters filters) { @@ -846,7 +848,6 @@ public class Camera2VideoActivity extends AppCompatActivity { } } - public static void exportMp4ToGallery(Context context, String filePath) { final ContentValues values = new ContentValues(2); values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4"); diff --git a/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/GPUCameraRecorder.java b/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/GPUCameraRecorder.java index bcdb52cc..e058bf20 100644 --- a/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/GPUCameraRecorder.java +++ b/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/GPUCameraRecorder.java @@ -90,7 +90,6 @@ public class GPUCameraRecorder { }); } - private synchronized void startPreview(SurfaceTexture surfaceTexture) { if (cameraHandler == null) { final CameraThread thread = new CameraThread(cameraRecordListener, new CameraThread.OnStartPreviewListener() { @@ -132,7 +131,6 @@ public class GPUCameraRecorder { cameraHandler.startPreview(cameraWidth, cameraHeight); } - public void setFilter(final GlFilter filter) { if (filter == null) return; glPreviewRenderer.setGlFilter(filter); @@ -153,7 +151,6 @@ public class GPUCameraRecorder { } } - public void switchFlashMode() { if (!flashSupport) return; if (cameraHandler != null) { @@ -171,7 +168,6 @@ public class GPUCameraRecorder { return flashSupport; } - private void destroyPreview() { if (glPreviewRenderer != null) { glPreviewRenderer.release(); diff --git a/gpuv/src/main/java/com/xypower/gpuv/egl/filter/GlOverlayFilter.java b/gpuv/src/main/java/com/xypower/gpuv/egl/filter/GlOverlayFilter.java index 617432f8..e5082181 100644 --- a/gpuv/src/main/java/com/xypower/gpuv/egl/filter/GlOverlayFilter.java +++ b/gpuv/src/main/java/com/xypower/gpuv/egl/filter/GlOverlayFilter.java @@ -73,7 +73,6 @@ public abstract class GlOverlayFilter extends GlFilter { createBitmap(); } - // bitmap.eraseColor(Color.argb(0, 0, 0, 0)); Canvas bitmapCanvas = new Canvas(bitmap); bitmapCanvas.scale(1, -1, bitmapCanvas.getWidth() / 2, bitmapCanvas.getHeight() / 2); drawCanvas(bitmapCanvas); diff --git a/gpuv/src/main/java/com/xypower/gpuv/egl/filter/GlWatermarkFilter.java b/gpuv/src/main/java/com/xypower/gpuv/egl/filter/GlWatermarkFilter.java index 07f0da9a..e30d11c8 100644 --- a/gpuv/src/main/java/com/xypower/gpuv/egl/filter/GlWatermarkFilter.java +++ b/gpuv/src/main/java/com/xypower/gpuv/egl/filter/GlWatermarkFilter.java @@ -4,32 +4,32 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PorterDuff; -import android.graphics.Rect; import android.util.Log; public class GlWatermarkFilter extends GlOverlayFilter { private Object mLocker = new Object(); - private Bitmap bitmap; + private Bitmap mBitmap; private boolean invalidated = true; - private Position position = Position.LEFT_TOP; + private Position mPosition = Position.LEFT_TOP; public GlWatermarkFilter(Bitmap bitmap) { - this.bitmap = bitmap; + this.mBitmap = bitmap; } public GlWatermarkFilter(Bitmap bitmap, Position position) { - this.bitmap = bitmap; - this.position = position; + mBitmap = bitmap; + mPosition = position; } public void updateBitmap(Bitmap bm) { Bitmap oldBitmap = null; + Log.d("OSD", "updateBitmap"); synchronized (mLocker) { invalidated = true; - oldBitmap = bitmap; - bitmap = bm; + oldBitmap = mBitmap; + mBitmap = bm; } if (oldBitmap != null) { @@ -40,10 +40,10 @@ public class GlWatermarkFilter extends GlOverlayFilter { @Override protected void drawCanvas(Canvas canvas) { synchronized (mLocker) { - Log.d("OSD", "drawCanvas"); + // Log.d("OSD", "drawCanvas invalidated=" + Boolean.toString(invalidated)); if (invalidated) { canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); - canvas.drawBitmap(bitmap, null, canvas.getClipBounds(), null); + canvas.drawBitmap(mBitmap, null, canvas.getClipBounds(), null); invalidated = false; } }