回退优化osd时间的代码
parent
c01e10c2c3
commit
9b2c1be718
@ -0,0 +1,916 @@
|
||||
package com.xypower.mpapp.v2;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.opengl.GLException;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowMetrics;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import com.xypower.gpuv.camerarecorder.CameraRecordListener;
|
||||
import com.xypower.gpuv.camerarecorder.GPUCameraRecorder;
|
||||
import com.xypower.gpuv.camerarecorder.GPUCameraRecorderBuilder;
|
||||
import com.xypower.gpuv.egl.filter.GlWatermarkFilter;
|
||||
import com.xypower.gpuvideoandroid.widget.AutoFitGLView;
|
||||
import com.xypower.mpapp.MicroPhotoService;
|
||||
import com.xypower.mpapp.R;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLContext;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.IntBuffer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public class Camera2VideoActivityNew extends AppCompatActivity {
|
||||
|
||||
public static final String ACTION_FINISH = "com.xypower.mvapp.ACT_FINISH";
|
||||
public static final String ACTION_MP_VIDEO_FINISHED = "com.xypower.mpapp.ACT_V_FINISHED";
|
||||
|
||||
private static final int DEFAULT_FONT_SIZE = 20;
|
||||
private AutoFitGLView mPreviewView;
|
||||
protected GPUCameraRecorder mGPUCameraRecorder;
|
||||
// protected LensFacing lensFacing = LensFacing.BACK;
|
||||
protected int mCameraWidth = 1280;
|
||||
protected int mCameraHeight = 720;
|
||||
protected int mVideoWidth = 1280;
|
||||
protected int mVideoHeight = 720;
|
||||
|
||||
private int mCameraId;
|
||||
private long mVideoId = 0;
|
||||
private int mDuration = 0;
|
||||
|
||||
private int mOrientation = -1;
|
||||
|
||||
private String mNextVideoAbsolutePath;
|
||||
|
||||
private String mOSDLeftTop = null;
|
||||
private String mOSDRightTop = null;
|
||||
private String mOSDRightBottom = null;
|
||||
private String mOSDLeftBottom = null;
|
||||
|
||||
private int mOSDMargin = 0;
|
||||
private Paint mPaint;
|
||||
private Paint mPaintStroker;
|
||||
|
||||
private List<Bitmap> 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");
|
||||
|
||||
private final String TIME_MICRO_TS = "$$TS$$";
|
||||
private final String TIME_MICRO_DT = "$$DATETIME$$";
|
||||
|
||||
private int mTimeMask = 0;
|
||||
private int mStatusBarHeight = -1;
|
||||
|
||||
private static class OSD_ITEM
|
||||
{
|
||||
String text;
|
||||
int mask;
|
||||
Point origin;
|
||||
Rect previousRect;
|
||||
}
|
||||
|
||||
private List<OSD_ITEM> mOSDItems = new ArrayList<>();
|
||||
|
||||
private final static int TIME_MASK_LT_TS = 1;
|
||||
private final static int TIME_MASK_LT_DT = 2;
|
||||
private final static int TIME_MASK_LT_ML = 4;
|
||||
private final static int TIME_MASK_LT = TIME_MASK_LT_TS | TIME_MASK_LT_DT | TIME_MASK_LT_ML;
|
||||
private final static int TIME_MASK_RT_TS = 8;
|
||||
private final static int TIME_MASK_RT_DT = 16;
|
||||
private final static int TIME_MASK_RT_ML = 32;
|
||||
private final static int TIME_MASK_RT = TIME_MASK_RT_TS | TIME_MASK_RT_DT | TIME_MASK_RT_ML;
|
||||
private final static int TIME_MASK_RB_TS = 64;
|
||||
private final static int TIME_MASK_RB_DT = 128;
|
||||
private final static int TIME_MASK_RB_ML = 256;
|
||||
private final static int TIME_MASK_RB = TIME_MASK_RB_TS | TIME_MASK_RB_DT | TIME_MASK_RB_ML;
|
||||
private final static int TIME_MASK_LB_TS = 512;
|
||||
private final static int TIME_MASK_LB_DT = 1024;
|
||||
private final static int TIME_MASK_LB_ML = 2048;
|
||||
private final static int TIME_MASK_LB = TIME_MASK_LB_TS | TIME_MASK_LB_DT | TIME_MASK_LB_ML;
|
||||
|
||||
private Handler mHandler = null;
|
||||
|
||||
private class TimerRunner implements Runnable {
|
||||
private Bitmap mBitmap;
|
||||
|
||||
TimerRunner(Bitmap bm) {
|
||||
mBitmap = bm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
Bitmap oldBm = null;
|
||||
if (mBitmap != null) {
|
||||
oldBm = mOSDFilter.updateBitmap(mBitmap);
|
||||
}
|
||||
if (oldBm != null) {
|
||||
synchronized (mBitmapLocker) {
|
||||
mBitmaps.add(oldBm);
|
||||
}
|
||||
}
|
||||
|
||||
long ts = System.currentTimeMillis();
|
||||
long ms = ts % 1000;
|
||||
|
||||
Log.d("OSD", "Cur TS=" + Long.toString(ts / 1000) + " Timer=" + Long.toString(1000 - ms));
|
||||
|
||||
Message msg = Message.obtain();
|
||||
msg.what = 1;
|
||||
msg.obj = new Long(ts - ms + 1000);
|
||||
mOsdHandler.sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
TimerRunner runner = new TimerRunner(bm);
|
||||
mHandler.postDelayed(runner, targetTs.longValue() - ts);
|
||||
}
|
||||
} else if (msg.what == 0) {
|
||||
Looper.myLooper().quitSafely();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Looper.loop();
|
||||
}
|
||||
});
|
||||
|
||||
@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);
|
||||
|
||||
setContentView(R.layout.activity_camera2_video);
|
||||
|
||||
getSupportActionBar().hide();
|
||||
|
||||
// mStatusBarHeight = getStatusBarHeight(this);
|
||||
onCreateActivity();
|
||||
|
||||
getWindow().getDecorView().setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
mStatusBarHeight = px2dip(Camera2VideoActivityNew.this, insets.getStableInsetTop());
|
||||
|
||||
return insets;
|
||||
});
|
||||
}
|
||||
|
||||
public static int px2dip(Context context, float pxValue) {
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (pxValue / scale + 0.5f);
|
||||
}
|
||||
|
||||
public int getStatusBarHeight(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
WindowMetrics windowMetrics = wm.getCurrentWindowMetrics();
|
||||
WindowInsets windowInsets = windowMetrics.getWindowInsets();
|
||||
Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.statusBars() | WindowInsets.Type.displayCutout());
|
||||
return px2dip(this, insets.top);
|
||||
}
|
||||
|
||||
Rect frame = new Rect();
|
||||
getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
|
||||
int statusBarHeight = frame.top;
|
||||
|
||||
if (statusBarHeight == 0) {
|
||||
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
|
||||
if (resourceId > 0) {
|
||||
statusBarHeight = getResources().getDimensionPixelSize(resourceId);
|
||||
}
|
||||
}
|
||||
|
||||
return px2dip(context, statusBarHeight);
|
||||
}
|
||||
|
||||
protected void onCreateActivity() {
|
||||
|
||||
Intent intent = getIntent();
|
||||
|
||||
mCameraId = intent.getIntExtra("cameraId", 0);
|
||||
mVideoId = intent.getLongExtra("videoId", 0);
|
||||
mDuration = intent.getIntExtra("duration", 0);
|
||||
mVideoWidth = intent.getIntExtra("width", 0);
|
||||
mVideoHeight = intent.getIntExtra("height", 0);
|
||||
mOrientation = intent.getIntExtra("orientation", -1);
|
||||
mOSDLeftTop = intent.getStringExtra("leftTopOsd");
|
||||
mOSDLeftBottom = intent.getStringExtra("leftBottomOsd");
|
||||
mOSDRightBottom = intent.getStringExtra("rightBottomOsd");
|
||||
mOSDRightTop = intent.getStringExtra("rightTopOsd");
|
||||
mOSDMargin = px2dip(this, intent.getIntExtra("margin", 12));
|
||||
|
||||
mCameraWidth = mVideoWidth;
|
||||
mCameraHeight = mVideoHeight;
|
||||
|
||||
mTimeMask = 0;
|
||||
if (!TextUtils.isEmpty(mOSDLeftTop)) {
|
||||
mOSDLeftTop = mOSDLeftTop.replace("\r\n", "\n");
|
||||
mOSDLeftTop = mOSDLeftTop.replace("\n\r", "\n");
|
||||
mOSDLeftTop = mOSDLeftTop.replace("\r", "\n");
|
||||
if (mOSDLeftTop.indexOf(TIME_MICRO_TS) != 0) {
|
||||
mTimeMask |= TIME_MASK_LT_TS;
|
||||
}
|
||||
if (mOSDLeftTop.indexOf(TIME_MICRO_DT) != 0) {
|
||||
mTimeMask |= TIME_MASK_LT_DT;
|
||||
}
|
||||
if (mOSDLeftTop.indexOf("\n") != 0) {
|
||||
mTimeMask |= TIME_MASK_LT_ML;
|
||||
}
|
||||
}
|
||||
if (!TextUtils.isEmpty(mOSDRightTop)) {
|
||||
mOSDRightTop = mOSDRightTop.replace("\r\n", "\n");
|
||||
mOSDRightTop = mOSDRightTop.replace("\n\r", "\n");
|
||||
mOSDRightTop = mOSDRightTop.replace("\r", "\n");
|
||||
if (mOSDRightTop.indexOf(TIME_MICRO_TS) != 0) {
|
||||
mTimeMask |= TIME_MASK_RT_TS;
|
||||
}
|
||||
if (mOSDRightTop.indexOf(TIME_MICRO_DT) != 0) {
|
||||
mTimeMask |= TIME_MASK_RT_DT;
|
||||
}
|
||||
if (mOSDRightTop.indexOf("\n") != 0) {
|
||||
mTimeMask |= TIME_MASK_RT_ML;
|
||||
}
|
||||
}
|
||||
if (!TextUtils.isEmpty(mOSDRightBottom)) {
|
||||
mOSDRightBottom = mOSDRightBottom.replace("\r\n", "\n");
|
||||
mOSDRightBottom = mOSDRightBottom.replace("\n\r", "\n");
|
||||
mOSDRightBottom = mOSDRightBottom.replace("\r", "\n");
|
||||
if (mOSDRightBottom.indexOf(TIME_MICRO_TS) != 0) {
|
||||
mTimeMask |= TIME_MASK_RB_TS;
|
||||
}
|
||||
if (mOSDRightBottom.indexOf(TIME_MICRO_DT) != 0) {
|
||||
mTimeMask |= TIME_MASK_RB_DT;
|
||||
}
|
||||
if (mOSDRightBottom.indexOf("\n") != 0) {
|
||||
mTimeMask |= TIME_MASK_RB_ML;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(mOSDLeftBottom)) {
|
||||
mOSDLeftBottom = mOSDLeftBottom.replace("\r\n", "\n");
|
||||
mOSDLeftBottom = mOSDLeftBottom.replace("\n\r", "\n");
|
||||
mOSDLeftBottom = mOSDLeftBottom.replace("\r", "\n");
|
||||
if (mOSDLeftBottom.indexOf(TIME_MICRO_TS) != 0) {
|
||||
mTimeMask |= TIME_MASK_LB_TS;
|
||||
}
|
||||
if (mOSDLeftBottom.indexOf(TIME_MICRO_DT) != 0) {
|
||||
mTimeMask |= TIME_MASK_LB_DT;
|
||||
}
|
||||
if (mOSDLeftBottom.indexOf("\n") != 0) {
|
||||
mTimeMask |= TIME_MASK_LB_ML;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
mPaint.setColor(Color.WHITE);
|
||||
int fontSize = DEFAULT_FONT_SIZE;
|
||||
mPaint.setTextSize(fontSize);
|
||||
|
||||
mPaintStroker = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mPaintStroker.setStyle(Paint.Style.STROKE);
|
||||
mPaintStroker.setColor(Color.BLACK);
|
||||
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);
|
||||
initOSD(bm, zeroTs);
|
||||
mOSDFilter = new GlWatermarkFilter(bm);
|
||||
|
||||
if (mGPUCameraRecorder != null) {
|
||||
mGPUCameraRecorder.setFilter(mOSDFilter);
|
||||
}
|
||||
|
||||
updateOSD(bm2, zeroTs + 1000);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mGPUCameraRecorder.stop();
|
||||
}
|
||||
}, 16 + mDuration * 1000);
|
||||
|
||||
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
setUpCamera();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
releaseCamera();
|
||||
}
|
||||
|
||||
private void initOSD(Bitmap bm, long ts) {
|
||||
|
||||
Log.d("OSD", "INIT OSD " + Long.toString(ts / 1000));
|
||||
|
||||
if (mStatusBarHeight == -1) {
|
||||
mStatusBarHeight = getStatusBarHeight(this);
|
||||
}
|
||||
int statusHeight = mStatusBarHeight;
|
||||
|
||||
int bmWidth = bm.getWidth();
|
||||
int bmHeight = bm.getHeight();
|
||||
int margin = mOSDMargin;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
Canvas canvas = new Canvas(bm);
|
||||
Rect textBounds = new Rect();
|
||||
|
||||
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
|
||||
|
||||
if (!TextUtils.isEmpty(mOSDLeftTop)) {
|
||||
String[] items = mOSDLeftTop.split("\n");
|
||||
Point origin = new Point(margin, margin + statusHeight);
|
||||
|
||||
for (String item : items) {
|
||||
|
||||
int mask = 0;
|
||||
if (item.indexOf(TIME_MICRO_TS) != 0) {
|
||||
mask |= TIME_MASK_LT_TS;
|
||||
}
|
||||
if (item.indexOf(TIME_MICRO_DT) != 0) {
|
||||
mask |= TIME_MASK_LT_DT;
|
||||
}
|
||||
|
||||
OSD_ITEM osdItem = new OSD_ITEM();
|
||||
osdItem.text = item;
|
||||
osdItem.mask = mask;
|
||||
osdItem.origin = new Point(origin);
|
||||
|
||||
if (mask == 0) {
|
||||
canvas.drawText(item, origin.x, origin.y, mPaint);
|
||||
canvas.drawText(item, origin.x, origin.y, mPaintStroker);
|
||||
|
||||
mPaintStroker.getTextBounds(item, 0, item.length(), textBounds);
|
||||
} else {
|
||||
String newText = updateOSDTime(item, ts);
|
||||
|
||||
canvas.drawText(newText, origin.x, origin.y, mPaint);
|
||||
canvas.drawText(newText, origin.x, origin.y, mPaintStroker);
|
||||
|
||||
mPaintStroker.getTextBounds(newText, 0, item.length(), textBounds);
|
||||
}
|
||||
|
||||
osdItem.previousRect = new Rect(origin.x, origin.y, origin.x + textBounds.width(), origin.y + textBounds.height());
|
||||
|
||||
mOSDItems.add(osdItem);
|
||||
origin.y += (textBounds.height() * 3) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(mOSDLeftBottom)) {
|
||||
|
||||
String[] items = mOSDLeftBottom.split("\n");
|
||||
Point origin = new Point(margin, bmHeight - margin);
|
||||
|
||||
for(int idx = items.length-1; idx >= 0; idx--) {
|
||||
|
||||
int mask = 0;
|
||||
String item = items[idx];
|
||||
if (item.indexOf(TIME_MICRO_TS) != 0) {
|
||||
mask |= TIME_MASK_LB_TS;
|
||||
}
|
||||
if (item.indexOf(TIME_MICRO_DT) != 0) {
|
||||
mask |= TIME_MASK_LB_DT;
|
||||
}
|
||||
|
||||
OSD_ITEM osdItem = new OSD_ITEM();
|
||||
osdItem.text = item;
|
||||
osdItem.mask = mask;
|
||||
osdItem.origin = new Point(origin);
|
||||
if (mask == 0) {
|
||||
mPaintStroker.getTextBounds(item, 0, item.length(), textBounds);
|
||||
y = origin.y - textBounds.height();
|
||||
|
||||
canvas.drawText(item, origin.x, y, mPaint);
|
||||
canvas.drawText(item, origin.x, y, mPaintStroker);
|
||||
} else {
|
||||
String newText = updateOSDTime(item, ts);
|
||||
|
||||
mPaintStroker.getTextBounds(newText, 0, newText.length(), textBounds);
|
||||
y = origin.y - textBounds.height();
|
||||
|
||||
canvas.drawText(newText, origin.x, y, mPaint);
|
||||
canvas.drawText(newText, origin.x, y, mPaintStroker);
|
||||
}
|
||||
|
||||
osdItem.previousRect = new Rect(origin.x, y, origin.x + textBounds.width(), y + textBounds.height());
|
||||
mOSDItems.add(osdItem);
|
||||
origin.y -= (textBounds.height() * 3) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(mOSDRightTop)) {
|
||||
|
||||
String[] items = mOSDRightTop.split("\n");
|
||||
Point origin = new Point(bmWidth - margin, margin + statusHeight);
|
||||
|
||||
for (String item : items) {
|
||||
|
||||
int mask = 0;
|
||||
if (item.indexOf(TIME_MICRO_TS) != 0) {
|
||||
mask |= TIME_MASK_RT_TS;
|
||||
}
|
||||
if (item.indexOf(TIME_MICRO_DT) != 0) {
|
||||
mask |= TIME_MASK_RT_DT;
|
||||
}
|
||||
|
||||
OSD_ITEM osdItem = new OSD_ITEM();
|
||||
osdItem.text = item;
|
||||
osdItem.origin = new Point(origin);
|
||||
osdItem.mask = mask;
|
||||
|
||||
if (mask == 0) {
|
||||
mPaintStroker.getTextBounds(item, 0, item.length(), textBounds);
|
||||
|
||||
canvas.drawText(item, origin.x - textBounds.width(), origin.y, mPaint);
|
||||
canvas.drawText(item, origin.x - textBounds.width(), origin.y, mPaintStroker);
|
||||
} else {
|
||||
|
||||
String newText = updateOSDTime(item, ts);
|
||||
mPaintStroker.getTextBounds(newText, 0, item.length(), textBounds);
|
||||
|
||||
canvas.drawText(newText, origin.x - textBounds.width(), origin.y, mPaint);
|
||||
canvas.drawText(newText, origin.x - textBounds.width(), origin.y, mPaintStroker);
|
||||
}
|
||||
osdItem.previousRect = new Rect(origin.x - textBounds.width(), origin.y, origin.x, origin.y + textBounds.height());
|
||||
mOSDItems.add(osdItem);
|
||||
|
||||
origin.y += (textBounds.height() * 3) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(mOSDRightBottom)) {
|
||||
|
||||
String[] items = mOSDRightBottom.split("\n");
|
||||
Point origin = new Point(bmWidth - margin, bmHeight - margin);
|
||||
|
||||
for(int idx = items.length-1; idx >= 0; idx--) {
|
||||
|
||||
int mask = 0;
|
||||
String item = items[idx];
|
||||
if (item.indexOf(TIME_MICRO_TS) != 0) {
|
||||
mask |= TIME_MASK_RB_TS;
|
||||
}
|
||||
if (item.indexOf(TIME_MICRO_DT) != 0) {
|
||||
mask |= TIME_MASK_RB_DT;
|
||||
}
|
||||
|
||||
OSD_ITEM osdItem = new OSD_ITEM();
|
||||
osdItem.text = item;
|
||||
osdItem.origin = new Point(origin);
|
||||
osdItem.mask = mask;
|
||||
if (mask == 0) {
|
||||
mPaintStroker.getTextBounds(item, 0, item.length(), textBounds);
|
||||
|
||||
canvas.drawText(item, origin.x - textBounds.width(), origin.y - textBounds.height(), mPaint);
|
||||
canvas.drawText(item, origin.x - textBounds.width(), origin.y - textBounds.height(), mPaintStroker);
|
||||
} else {
|
||||
String newText = updateOSDTime(item, ts);
|
||||
mPaintStroker.getTextBounds(newText, 0, item.length(), textBounds);
|
||||
|
||||
canvas.drawText(newText, origin.x - textBounds.width(), origin.y - textBounds.height(), mPaint);
|
||||
canvas.drawText(newText, origin.x - textBounds.width(), origin.y - textBounds.height(), mPaintStroker);
|
||||
}
|
||||
|
||||
osdItem.previousRect = new Rect(origin.x - textBounds.width(), origin.y - textBounds.height(), origin.x, origin.y);
|
||||
mOSDItems.add(osdItem);
|
||||
|
||||
origin.y -= (textBounds.height() * 3) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void updateOSD(Bitmap bm, long ts) {
|
||||
|
||||
Log.d("OSD", "prepareOSD " + Long.toString(ts / 1000));
|
||||
if (mStatusBarHeight == -1) {
|
||||
mStatusBarHeight = getStatusBarHeight(this);
|
||||
}
|
||||
int statusHeight = mStatusBarHeight;
|
||||
|
||||
Canvas canvas = new Canvas(bm);
|
||||
boolean aa = canvas.isHardwareAccelerated();
|
||||
Rect textBounds = new Rect();
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String updateOSDTime(String osd, long ts) {
|
||||
String newOSD = osd;
|
||||
if (newOSD.indexOf(TIME_MICRO_TS) != -1) {
|
||||
newOSD = newOSD.replace(TIME_MICRO_TS, Long.toString(ts / 1000));
|
||||
}
|
||||
if (newOSD.indexOf(TIME_MICRO_DT) != -1) {
|
||||
if (mDateFormater == null) {
|
||||
mDateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
Date dt = new Date(ts);
|
||||
newOSD = newOSD.replace(TIME_MICRO_DT, mDateFormater.format(dt));
|
||||
}
|
||||
|
||||
return newOSD;
|
||||
}
|
||||
|
||||
private void releaseCamera() {
|
||||
if (mPreviewView != null) {
|
||||
mPreviewView.onPause();
|
||||
}
|
||||
|
||||
if (mGPUCameraRecorder != null) {
|
||||
mGPUCameraRecorder.stop();
|
||||
mGPUCameraRecorder.release();
|
||||
mGPUCameraRecorder = null;
|
||||
}
|
||||
|
||||
if (mPreviewView != null) {
|
||||
((FrameLayout) findViewById(R.id.wrap_view)).removeView(mPreviewView);
|
||||
mPreviewView = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpCameraView() {
|
||||
|
||||
runOnUiThread(() -> {
|
||||
|
||||
FrameLayout frameLayout = findViewById(R.id.wrap_view);
|
||||
frameLayout.removeAllViews();
|
||||
mPreviewView = null;
|
||||
mPreviewView = new AutoFitGLView(getApplicationContext());
|
||||
mPreviewView.setTouchListener((event, width, height) -> {
|
||||
if (mGPUCameraRecorder == null) return;
|
||||
mGPUCameraRecorder.changeManualFocusPoint(event.getX(), event.getY(), width, height);
|
||||
});
|
||||
|
||||
frameLayout.addView(mPreviewView);
|
||||
});
|
||||
}
|
||||
|
||||
private void setUpCamera() {
|
||||
setUpCameraView();
|
||||
|
||||
if (mNextVideoAbsolutePath == null || mNextVideoAbsolutePath.isEmpty()) {
|
||||
mNextVideoAbsolutePath = getVideoFilePath(this);
|
||||
}
|
||||
|
||||
mGPUCameraRecorder = new GPUCameraRecorderBuilder(this, mPreviewView)
|
||||
//.recordNoFilter(true)
|
||||
.cameraRecordListener(new CameraRecordListener() {
|
||||
@Override
|
||||
public void onGetFlashSupport(boolean flashSupport) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordComplete() {
|
||||
// mHandler.removeCallbacks(mTimerRunnable);
|
||||
Message msg = Message.obtain();
|
||||
msg.what = 0;
|
||||
mOsdHandler.sendMessage(msg);
|
||||
|
||||
exportMp4ToGallery(getApplicationContext(), mNextVideoAbsolutePath);
|
||||
broadcastVideoFile(true, mNextVideoAbsolutePath);
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Camera2VideoActivityNew.this.finish();
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordStart() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
Log.e("GPUCameraRecorder", exception.toString());
|
||||
broadcastVideoFile(false, mNextVideoAbsolutePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraThreadFinish() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoFileReady() {
|
||||
}
|
||||
})
|
||||
.videoSize(mVideoWidth, mVideoHeight)
|
||||
.cameraSize(mCameraWidth, mCameraHeight)
|
||||
.cameraId(Integer.toString(mCameraId))
|
||||
.build();
|
||||
|
||||
if (mOSDFilter != null) {
|
||||
mGPUCameraRecorder.setFilter(mOSDFilter);
|
||||
}
|
||||
}
|
||||
|
||||
// private void changeFilter(Filters filters) {
|
||||
// GPUCameraRecorder.setFilter(Filters.getFilterInstance(filters, getApplicationContext()));
|
||||
// }
|
||||
|
||||
|
||||
private interface BitmapReadyCallbacks {
|
||||
void onBitmapReady(Bitmap bitmap);
|
||||
}
|
||||
|
||||
private void captureBitmap(final BitmapReadyCallbacks bitmapReadyCallbacks) {
|
||||
mPreviewView.queueEvent(() -> {
|
||||
EGL10 egl = (EGL10) EGLContext.getEGL();
|
||||
GL10 gl = (GL10) egl.eglGetCurrentContext().getGL();
|
||||
Bitmap snapshotBitmap = createBitmapFromGLSurface(mPreviewView.getMeasuredWidth(), mPreviewView.getMeasuredHeight(), gl);
|
||||
|
||||
runOnUiThread(() -> {
|
||||
bitmapReadyCallbacks.onBitmapReady(snapshotBitmap);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void broadcastVideoFile(boolean result, String path) {
|
||||
if (mDuration <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Context context = getApplicationContext();
|
||||
String receiverName = MicroPhotoService.AlarmReceiver.class.getName();
|
||||
String packageName = context.getPackageName();
|
||||
|
||||
Intent intent = new Intent(ACTION_MP_VIDEO_FINISHED);
|
||||
// intent.setPackage(packageName);
|
||||
intent.putExtra("result", result);
|
||||
intent.putExtra("path", path);
|
||||
intent.putExtra("videoId", mVideoId);
|
||||
|
||||
// intent.setComponent(new ComponentName(packageName, receiverName));
|
||||
|
||||
// Log.i(TAG, "Notify recording videoId=" + Long.toString(mVideoId) + " " + path);
|
||||
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(getApplicationContext());
|
||||
localBroadcastManager.sendBroadcast(intent);
|
||||
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
private String getVideoFilePath(Context context) {
|
||||
// final File dir = context.getExternalFilesDir(null);
|
||||
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
if (!path.endsWith(File.separator)) {
|
||||
path += File.separator;
|
||||
}
|
||||
path += context.getPackageName() + File.separator;
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
path += System.currentTimeMillis() + ".mp4";
|
||||
return path;
|
||||
}
|
||||
|
||||
private Bitmap createBitmapFromGLSurface(int w, int h, GL10 gl) {
|
||||
|
||||
int bitmapBuffer[] = new int[w * h];
|
||||
int bitmapSource[] = new int[w * h];
|
||||
IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);
|
||||
intBuffer.position(0);
|
||||
|
||||
try {
|
||||
gl.glReadPixels(0, 0, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, intBuffer);
|
||||
int offset1, offset2, texturePixel, blue, red, pixel;
|
||||
for (int i = 0; i < h; i++) {
|
||||
offset1 = i * w;
|
||||
offset2 = (h - i - 1) * w;
|
||||
for (int j = 0; j < w; j++) {
|
||||
texturePixel = bitmapBuffer[offset1 + j];
|
||||
blue = (texturePixel >> 16) & 0xff;
|
||||
red = (texturePixel << 16) & 0x00ff0000;
|
||||
pixel = (texturePixel & 0xff00ff00) | red | blue;
|
||||
bitmapSource[offset2 + j] = pixel;
|
||||
}
|
||||
}
|
||||
} catch (GLException e) {
|
||||
Log.e("CreateBitmap", "createBitmapFromGLSurface: " + e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
public void saveAsPngImage(Bitmap bitmap, String filePath) {
|
||||
try {
|
||||
File file = new File(filePath);
|
||||
FileOutputStream outStream = new FileOutputStream(file);
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
|
||||
outStream.close();
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void exportMp4ToGallery(Context context, String filePath) {
|
||||
final ContentValues values = new ContentValues(2);
|
||||
values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
|
||||
values.put(MediaStore.Video.Media.DATA, filePath);
|
||||
context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
|
||||
values);
|
||||
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
|
||||
Uri.parse("file://" + filePath)));
|
||||
}
|
||||
|
||||
public static String getVideoFilePath() {
|
||||
return getAndroidMoviesFolder().getAbsolutePath() + "/" + new SimpleDateFormat("yyyyMM_dd-HHmmss").format(new Date()) + "GPUCameraRecorder.mp4";
|
||||
}
|
||||
|
||||
public static File getAndroidMoviesFolder() {
|
||||
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
|
||||
}
|
||||
|
||||
private static void exportPngToGallery(Context context, String filePath) {
|
||||
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
||||
File f = new File(filePath);
|
||||
Uri contentUri = Uri.fromFile(f);
|
||||
mediaScanIntent.setData(contentUri);
|
||||
context.sendBroadcast(mediaScanIntent);
|
||||
}
|
||||
|
||||
public static String getImageFilePath() {
|
||||
return getAndroidImageFolder().getAbsolutePath() + "/" + new SimpleDateFormat("yyyyMM_dd-HHmmss").format(new Date()) + "GPUCameraRecorder.png";
|
||||
}
|
||||
|
||||
public static File getAndroidImageFolder() {
|
||||
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue