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 99bff99c..85cc4711 100644 --- a/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivity.java +++ b/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivity.java @@ -69,7 +69,7 @@ public class Camera2VideoActivity extends AppCompatActivity { private int mCameraId; private long mVideoId = 0; - private int mDuration = 0; + private long mDuration = 0; private int mOrientation = -1; @@ -84,10 +84,7 @@ public class Camera2VideoActivity extends AppCompatActivity { private Paint mPaint; private Paint mPaintStroker; - private List mBitmaps = new ArrayList<>(); - private GlWatermarkFilter mOSDFilter = null; - private Object mBitmapLocker = new Object(); private SimpleDateFormat mDateFormater; // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss a"); @@ -127,71 +124,45 @@ public class Camera2VideoActivity extends AppCompatActivity { private Handler mHandler = null; - private class TimerRunner implements Runnable { - private Bitmap mBitmap; - - TimerRunner(Bitmap bm) { - mBitmap = bm; - } - + private Thread mOsdThread = new Thread(new Runnable() { @Override public void run() { - Bitmap oldBm = null; - if (mBitmap != null) { - oldBm = mOSDFilter.updateBitmap(mBitmap); - } - if (oldBm != null) { - synchronized (mBitmapLocker) { - mBitmaps.add(oldBm); - } - } + try { + long ts = System.currentTimeMillis(); + Bitmap bm = Bitmap.createBitmap(mVideoWidth, mVideoHeight, Bitmap.Config.ARGB_8888); + Bitmap oldBm = null; + Canvas canvas = new Canvas(bm); - long ts = System.currentTimeMillis(); - long ms = ts % 1000; + long zeroTs = ts - (ts % 1000); + long nextTs = zeroTs + 1000; - Log.d("OSD", "Cur TS=" + Long.toString(ts / 1000) + " Timer=" + Long.toString(1000 - ms)); + while (true) { + try { + if (nextTs > ts) { + Log.i("OSD", "Sleep " + Long.toString(nextTs - ts)); + Thread.sleep(nextTs - ts); + } + } catch (InterruptedException ex){ + break; + } catch(Exception ex){ + } - Message msg = Message.obtain(); - msg.what = 1; - msg.obj = new Long(ts - ms + 1000); - mOsdHandler.sendMessage(msg); - } - } + canvas.setBitmap(bm); + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + updateOSD(bm, nextTs); - private Handler mOsdHandler; - private Thread mOsdThread = new Thread(new Runnable() { - @Override - public void run() { - Looper.prepare(); - - mOsdHandler = new Handler(Looper.myLooper()) { - public void handleMessage(Message msg) { - if (msg.what == 1) { - Long targetTs = (Long)msg.obj; - long ts = System.currentTimeMillis(); - if (ts > targetTs.longValue()) { - return; - } - Bitmap bm = null; - synchronized (mBitmapLocker) { - if (!mBitmaps.isEmpty()) { - bm = mBitmaps.remove(0); - } - } - if (bm != null) { - updateOSD(bm, targetTs.longValue()); + oldBm = mOSDFilter.updateBitmap(bm); + bm = oldBm; - TimerRunner runner = new TimerRunner(bm); - mHandler.postDelayed(runner, targetTs.longValue() - ts); - } - } else if (msg.what == 0) { - Looper.myLooper().quitSafely(); + ts = System.currentTimeMillis(); + zeroTs = ts - (ts % 1000); + if (zeroTs + 1000 > nextTs) { + nextTs = zeroTs + 1000; } } - }; - - Looper.loop(); + } catch (Exception ex) { + } } }); @@ -326,12 +297,6 @@ public class Camera2VideoActivity extends AppCompatActivity { mHandler = new Handler(); - mOsdThread.start(); - - long ts = 0; - long zeroTs = 0; - - Bitmap bm2 = null; 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); @@ -345,15 +310,12 @@ public class Camera2VideoActivity extends AppCompatActivity { mPaintStroker.setTextSize(fontSize); mPaintStroker.setStrokeWidth(1); - bm2 = Bitmap.createBitmap(mVideoWidth, mVideoHeight, Bitmap.Config.ARGB_8888); - Bitmap bm = Bitmap.createBitmap(mVideoWidth, mVideoHeight, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bm); canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); - ts = System.currentTimeMillis(); - zeroTs = ts - (ts % 1000); + long ts = System.currentTimeMillis(); + long zeroTs = ts - (ts % 1000); initOSD(bm, zeroTs); mOSDFilter = new GlWatermarkFilter(bm); @@ -361,41 +323,14 @@ public class Camera2VideoActivity extends AppCompatActivity { mGPUCameraRecorder.setFilter(mOSDFilter); } - updateOSD(bm2, zeroTs + 1000); + mOsdThread.start(); } - final long prevZeroTs = zeroTs; - final Bitmap finalBm = bm2; mHandler.postDelayed(new Runnable() { @Override public void run() { mNextVideoAbsolutePath = getVideoFilePath(); - mGPUCameraRecorder.start(mNextVideoAbsolutePath); - - if (mOSDFilter != null) { - long ts2 = System.currentTimeMillis(); - long zeroTs2 = ts2 - (ts2 % 1000); - - if (zeroTs2 > prevZeroTs) { - // Next second - Bitmap oldBm = mOSDFilter.updateBitmap(finalBm); - if (oldBm != null) { - synchronized (mBitmapLocker) { - mBitmaps.add(oldBm); - } - } - Message msg = Message.obtain(); - msg.what = 1; - msg.obj = new Long(zeroTs2 + 1000); - // mOsdTs = zeroTs2 + 1000; - mOsdHandler.sendMessage(msg); - } else { - TimerRunner runner = new TimerRunner(finalBm); - mHandler.postDelayed(runner, 1000 - (ts2 - zeroTs2)); - } - Log.d("OSD", "Cur TS=" + Long.toString(ts2 / 1000) + " Timer=" + Long.toString(1000 - (ts2 - zeroTs2))); - } } }, 0); @@ -416,7 +351,7 @@ public class Camera2VideoActivity extends AppCompatActivity { private void initOSD(Bitmap bm, long ts) { - Log.d("OSD", "INIT OSD " + Long.toString(ts / 1000)); + Log.i("OSD", "INIT OSD " + Long.toString(ts / 1000)); if (mStatusBarHeight == -1) { mStatusBarHeight = getStatusBarHeight(this); @@ -600,7 +535,7 @@ public class Camera2VideoActivity extends AppCompatActivity { private void updateOSD(Bitmap bm, long ts) { - Log.d("OSD", "prepareOSD " + Long.toString(ts / 1000)); + Log.i("OSD", "prepareOSD " + Long.toString(ts / 1000)); if (mStatusBarHeight == -1) { mStatusBarHeight = getStatusBarHeight(this); } @@ -726,27 +661,28 @@ public class Camera2VideoActivity extends AppCompatActivity { @Override public void onRecordComplete() { // mHandler.removeCallbacks(mTimerRunnable); - Message msg = Message.obtain(); - msg.what = 0; - mOsdHandler.sendMessage(msg); + } @Override public void onRecordStart() { - Log.d("OSD", "Record Start "); + Log.i("OSD", "Record Start "); mHandler.postDelayed(new Runnable() { @Override public void run() { + Log.i("OSD", "Record Stop " + Long.toString(mDuration)); mGPUCameraRecorder.stop(); - Log.d("OSD", "Record Stop " + Long.toString(mDuration)); + + int aa = 0; } - }, 256 + mDuration * 1000); + }, 999 + mDuration * 1000); } @Override public void onError(Exception exception) { Log.e("GPUCameraRecorder", exception.toString()); + mOsdThread.interrupt(); broadcastVideoFile(false, mNextVideoAbsolutePath); } @@ -757,18 +693,26 @@ public class Camera2VideoActivity extends AppCompatActivity { @Override public void onVideoFileReady() { // exportMp4ToGallery(getApplicationContext(), mNextVideoAbsolutePath); + mOsdThread.interrupt(); broadcastVideoFile(true, mNextVideoAbsolutePath); mHandler.postDelayed(new Runnable() { @Override public void run() { Camera2VideoActivity.this.finish(); } - }, 100); + }, 1000); + } + + @Override + public void onDurationArrived() { + } }) .videoSize(mVideoWidth, mVideoHeight) .cameraSize(mCameraWidth, mCameraHeight) .cameraId(Integer.toString(mCameraId)) + .mute(true) + .duration(mDuration * 1000) .build(); if (mOSDFilter != null) { diff --git a/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivityOld.java b/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivityOld.java index 87f6851f..79f3ea8c 100644 --- a/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivityOld.java +++ b/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivityOld.java @@ -745,10 +745,16 @@ public class Camera2VideoActivityOld extends AppCompatActivity { } }, 100); } + + @Override + public void onDurationArrived() { + + } }) .videoSize(mVideoWidth, mVideoHeight) .cameraSize(mCameraWidth, mCameraHeight) .cameraId(Integer.toString(mCameraId)) + .duration(mDuration * 1000) .build(); if (mOSDFilter != null) { diff --git a/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/CameraRecordListener.java b/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/CameraRecordListener.java index 688928e1..26389194 100644 --- a/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/CameraRecordListener.java +++ b/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/CameraRecordListener.java @@ -16,6 +16,8 @@ public interface CameraRecordListener { void onCameraThreadFinish(); + void onDurationArrived(); + /** * Is called when native codecs finish to write file. */ 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 e058bf20..59b33db3 100644 --- a/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/GPUCameraRecorder.java +++ b/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/GPUCameraRecorder.java @@ -18,7 +18,7 @@ public class GPUCameraRecorder { private GlPreviewRenderer glPreviewRenderer; private final CameraRecordListener cameraRecordListener; - private static final String TAG = "GPUCameraRecorder"; + private static final String TAG = "OSD"; private boolean started = false; private CameraHandler cameraHandler = null; @@ -40,6 +40,9 @@ public class GPUCameraRecorder { private final boolean isLandscapeDevice; private final int degrees; private final boolean recordNoFilter; + private final long duration; + + private long startTime; GPUCameraRecorder( CameraRecordListener cameraRecordListener, @@ -55,7 +58,8 @@ public class GPUCameraRecorder { final CameraManager cameraManager, final boolean isLandscapeDevice, final int degrees, - final boolean recordNoFilter + final boolean recordNoFilter, + final long duration ) { @@ -76,6 +80,7 @@ public class GPUCameraRecorder { this.isLandscapeDevice = isLandscapeDevice; this.degrees = degrees; this.recordNoFilter = recordNoFilter; + this.duration = duration; // create preview Renderer if (null == glPreviewRenderer) { @@ -190,7 +195,7 @@ public class GPUCameraRecorder { @Override public void onPrepared(final MediaEncoder encoder) { - Log.v("TAG", "onPrepared:encoder=" + encoder); + Log.v(TAG, "onPrepared:encoder=" + encoder); if (encoder instanceof MediaVideoEncoder) { videoStopped = false; if (glPreviewRenderer != null) { @@ -206,7 +211,7 @@ public class GPUCameraRecorder { @Override public void onStopped(final MediaEncoder encoder) { - Log.v("TAG", "onStopped:encoder=" + encoder); + Log.v(TAG, "onStopped:encoder=" + encoder); if (encoder instanceof MediaVideoEncoder) { videoStopped = true; if (glPreviewRenderer != null) { @@ -301,7 +306,7 @@ public class GPUCameraRecorder { } catch (Exception e) { // RuntimeException is thrown when stop() is called immediately after start(). // In this case the output file is not properly constructed ans should be deleted. - Log.d("TAG", "RuntimeException: stop() is called immediately after start()"); + Log.d(TAG, "RuntimeException: stop() is called immediately after start()"); //noinspection ResultOfMethodCallIgnored notifyOnError(e); } @@ -330,7 +335,7 @@ public class GPUCameraRecorder { } catch (Exception e) { // RuntimeException is thrown when stop() is called immediately after start(). // In this case the output file is not properly constructed ans should be deleted. - Log.d("TAG", "RuntimeException: stop() is called immediately after start()"); + Log.d(TAG, "RuntimeException: stop() is called immediately after start()"); } destroyPreview(); diff --git a/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/GPUCameraRecorderBuilder.java b/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/GPUCameraRecorderBuilder.java index 5977d6e8..5dce8531 100644 --- a/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/GPUCameraRecorderBuilder.java +++ b/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/GPUCameraRecorderBuilder.java @@ -29,6 +29,7 @@ public class GPUCameraRecorderBuilder { private int cameraWidth = 1280; private int cameraHeight = 720; private GlFilter glFilter; + private long duration; public GPUCameraRecorderBuilder(Activity activity, GLSurfaceView glSurfaceView) { this.activity = activity; @@ -78,6 +79,11 @@ public class GPUCameraRecorderBuilder { return this; } + public GPUCameraRecorderBuilder duration(long d) { + this.duration = d; + return this; + } + public GPUCameraRecorderBuilder recordNoFilter(boolean recordNoFilter) { this.recordNoFilter = recordNoFilter; return this; @@ -112,7 +118,8 @@ public class GPUCameraRecorderBuilder { cameraManager, isLandscapeDevice, degrees, - recordNoFilter + recordNoFilter, + duration ); GPUCameraRecorder.setFilter(glFilter); diff --git a/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/capture/MediaVideoEncoder.java b/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/capture/MediaVideoEncoder.java index e489bc60..35d49baf 100644 --- a/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/capture/MediaVideoEncoder.java +++ b/gpuv/src/main/java/com/xypower/gpuv/camerarecorder/capture/MediaVideoEncoder.java @@ -15,7 +15,8 @@ import java.io.IOException; public class MediaVideoEncoder extends MediaEncoder { - private static final String TAG = "MediaVideoEncoder"; + // private static final String TAG = "MediaVideoEncoder"; + private static final String TAG = "OSD"; private static final String MIME_TYPE = "video/avc"; // parameters for recording