diff --git a/app/src/main/java/com/xypower/mpapp/v2/AspectRatioFrameLayout.java b/app/src/main/java/com/xypower/mpapp/v2/AspectRatioFrameLayout.java new file mode 100644 index 00000000..b281c90b --- /dev/null +++ b/app/src/main/java/com/xypower/mpapp/v2/AspectRatioFrameLayout.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.xypower.mpapp.v2; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +import androidx.annotation.IntDef; + +import com.xypower.mpapp.R; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A {@link FrameLayout} that resizes itself to match a specified aspect ratio. + */ +public final class AspectRatioFrameLayout extends FrameLayout { + + /** + * Resize modes for {@link AspectRatioFrameLayout}. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({RESIZE_MODE_FIT, RESIZE_MODE_FIXED_WIDTH, RESIZE_MODE_FIXED_HEIGHT, RESIZE_MODE_FILL}) + public @interface ResizeMode {} + + /** + * Either the width or height is decreased to obtain the desired aspect ratio. + */ + public static final int RESIZE_MODE_FIT = 0; + /** + * The width is fixed and the height is increased or decreased to obtain the desired aspect ratio. + */ + public static final int RESIZE_MODE_FIXED_WIDTH = 1; + /** + * The height is fixed and the width is increased or decreased to obtain the desired aspect ratio. + */ + public static final int RESIZE_MODE_FIXED_HEIGHT = 2; + /** + * The specified aspect ratio is ignored. + */ + public static final int RESIZE_MODE_FILL = 3; + + /** + * The {@link FrameLayout} will not resize itself if the fractional difference between its natural + * aspect ratio and the requested aspect ratio falls below this threshold. + *

+ * This tolerance allows the view to occupy the whole of the screen when the requested aspect + * ratio is very close, but not exactly equal to, the aspect ratio of the screen. This may reduce + * the number of view layers that need to be composited by the underlying system, which can help + * to reduce power consumption. + */ + private static final float MAX_ASPECT_RATIO_DEFORMATION_FRACTION = 0.01f; + + private float videoAspectRatio; + private int resizeMode; + + public AspectRatioFrameLayout(Context context) { + this(context, null); + } + + public AspectRatioFrameLayout(Context context, AttributeSet attrs) { + super(context, attrs); + resizeMode = RESIZE_MODE_FIT; + if (attrs != null) { + TypedArray a = context.getTheme().obtainStyledAttributes(attrs, + R.styleable.AspectRatioFrameLayout, 0, 0); + try { + resizeMode = a.getInt(R.styleable.AspectRatioFrameLayout_resize_mode, RESIZE_MODE_FIT); + } finally { + a.recycle(); + } + } + } + + /** + * Set the aspect ratio that this view should satisfy. + * + * @param widthHeightRatio The width to height ratio. + */ + public void setAspectRatio(float widthHeightRatio) { + if (this.videoAspectRatio != widthHeightRatio) { + this.videoAspectRatio = widthHeightRatio; + requestLayout(); + } + } + + /** + * Sets the resize mode. + * + * @param resizeMode The resize mode. + */ + public void setResizeMode(@ResizeMode int resizeMode) { + if (this.resizeMode != resizeMode) { + this.resizeMode = resizeMode; + requestLayout(); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (resizeMode == RESIZE_MODE_FILL || videoAspectRatio <= 0) { + // Aspect ratio not set. + return; + } + + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + float viewAspectRatio = (float) width / height; + float aspectDeformation = videoAspectRatio / viewAspectRatio - 1; + if (Math.abs(aspectDeformation) <= MAX_ASPECT_RATIO_DEFORMATION_FRACTION) { + // We're within the allowed tolerance. + return; + } + + switch (resizeMode) { + case RESIZE_MODE_FIXED_WIDTH: + height = (int) (width / videoAspectRatio); + break; + case RESIZE_MODE_FIXED_HEIGHT: + width = (int) (height * videoAspectRatio); + break; + default: + if (aspectDeformation > 0) { + height = (int) (width / videoAspectRatio); + } else { + width = (int) (height * videoAspectRatio); + } + break; + } + super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/xypower/mpapp/v2/AutoFitGLView.java b/app/src/main/java/com/xypower/mpapp/v2/AutoFitGLView.java index 1915f16e..4d2e2cb6 100644 --- a/app/src/main/java/com/xypower/mpapp/v2/AutoFitGLView.java +++ b/app/src/main/java/com/xypower/mpapp/v2/AutoFitGLView.java @@ -1,4 +1,4 @@ -package com.xypower.gpuvideoandroid.widget; +package com.xypower.mpapp.v2; import android.content.Context; import android.opengl.GLSurfaceView; 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 ec2b2a77..49c43407 100644 --- a/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivity.java +++ b/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivity.java @@ -35,7 +35,7 @@ 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.v2.AutoFitGLView; import com.xypower.mpapp.MicroPhotoService; import com.xypower.mpapp.R; @@ -57,7 +57,8 @@ public class Camera2VideoActivity 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 static final int DEFAULT_FONT_SIZE = 32; + private static final float DEFAULT_STROKE_WIDTH = 0.8f; private AutoFitGLView mPreviewView; protected GPUCameraRecorder mGPUCameraRecorder; @@ -67,6 +68,9 @@ public class Camera2VideoActivity extends AppCompatActivity { protected int mVideoWidth = 1280; protected int mVideoHeight = 720; + protected int mPreviewWidth = 1280; + protected int mPreviewHeight = 720; + private int mCameraId; private long mVideoId = 0; private long mDuration = 0; @@ -130,7 +134,7 @@ public class Camera2VideoActivity extends AppCompatActivity { try { long ts = System.currentTimeMillis(); - Bitmap bm = Bitmap.createBitmap(mVideoWidth, mVideoHeight, Bitmap.Config.ARGB_8888); + Bitmap bm = Bitmap.createBitmap(mPreviewWidth, mPreviewHeight, Bitmap.Config.ARGB_8888); Bitmap oldBm = null; Canvas canvas = new Canvas(bm); @@ -236,6 +240,9 @@ public class Camera2VideoActivity extends AppCompatActivity { mCameraWidth = mVideoWidth; mCameraHeight = mVideoHeight; + AspectRatioFrameLayout frameLayout = (AspectRatioFrameLayout)findViewById(R.id.wrap_view); + frameLayout.setAspectRatio((float)mVideoWidth / (float)mVideoHeight); + mTimeMask = 0; if (!TextUtils.isEmpty(mOSDLeftTop)) { mOSDLeftTop = mOSDLeftTop.replace("\r\n", "\n"); @@ -297,50 +304,27 @@ public class Camera2VideoActivity extends AppCompatActivity { mHandler = new Handler(); - 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); - - Bitmap bm = Bitmap.createBitmap(mVideoWidth, mVideoHeight, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bm); - canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); - - long ts = System.currentTimeMillis(); - long zeroTs = ts - (ts % 1000); - initOSD(bm, zeroTs); - mOSDFilter = new GlWatermarkFilter(bm); - - if (mGPUCameraRecorder != null) { - mGPUCameraRecorder.setFilter(mOSDFilter); - } - - mOsdThread.start(); - } - - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - mNextVideoAbsolutePath = getVideoFilePath(); - mGPUCameraRecorder.start(mNextVideoAbsolutePath); - } - }, 0); - // getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } @Override protected void onResume() { super.onResume(); - setUpCamera(); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + setUpCamera(); + + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mNextVideoAbsolutePath = getVideoFilePath(); + mGPUCameraRecorder.start(mNextVideoAbsolutePath); + } + }, 0); + } + }, 100); + } @Override @@ -358,8 +342,14 @@ public class Camera2VideoActivity extends AppCompatActivity { } int statusHeight = mStatusBarHeight; - int bmWidth = bm.getWidth(); - int bmHeight = bm.getHeight(); + int bmWidth = 1620; + int bmHeight = 1080; + + AspectRatioFrameLayout frameLayout = (AspectRatioFrameLayout)findViewById(R.id.wrap_view); + + int w = frameLayout.getWidth(); + int h = frameLayout.getMeasuredHeight(); + int margin = mOSDMargin; int x = 0; int y = 0; @@ -630,8 +620,9 @@ public class Camera2VideoActivity extends AppCompatActivity { runOnUiThread(() -> { - FrameLayout frameLayout = findViewById(R.id.wrap_view); + AspectRatioFrameLayout frameLayout = (AspectRatioFrameLayout)findViewById(R.id.wrap_view); frameLayout.removeAllViews(); + mPreviewView = null; mPreviewView = new AutoFitGLView(getApplicationContext()); mPreviewView.setTouchListener((event, width, height) -> { @@ -640,12 +631,47 @@ public class Camera2VideoActivity extends AppCompatActivity { }); frameLayout.addView(mPreviewView); + + if (!TextUtils.isEmpty(mOSDLeftTop) || !TextUtils.isEmpty(mOSDLeftTop) || !TextUtils.isEmpty(mOSDLeftTop) || !TextUtils.isEmpty(mOSDLeftTop)) { + mPreviewWidth = frameLayout.getMeasuredWidth(); + mPreviewHeight = frameLayout.getMeasuredHeight(); + + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setColor(Color.WHITE); + int fontSize = DEFAULT_FONT_SIZE * mPreviewHeight / 1024; + float strokeWidth = DEFAULT_STROKE_WIDTH * mPreviewHeight / 1024; + mPaint.setTextSize(fontSize); + + mPaintStroker = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaintStroker.setStyle(Paint.Style.STROKE); + mPaintStroker.setColor(Color.BLACK); + mPaintStroker.setTextSize(fontSize); + mPaintStroker.setStrokeWidth(strokeWidth); + + Bitmap bm = Bitmap.createBitmap(mPreviewWidth, mPreviewHeight, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bm); + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + + long ts = System.currentTimeMillis(); + long zeroTs = ts - (ts % 1000); + initOSD(bm, zeroTs); + mOSDFilter = new GlWatermarkFilter(bm); + + if (mGPUCameraRecorder != null) { + mGPUCameraRecorder.setFilter(mOSDFilter); + } + + mOsdThread.start(); + } }); } private void setUpCamera() { setUpCameraView(); + + if (mNextVideoAbsolutePath == null || mNextVideoAbsolutePath.isEmpty()) { mNextVideoAbsolutePath = getVideoFilePath(this); } 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 79f3ea8c..acd2048e 100644 --- a/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivityOld.java +++ b/app/src/main/java/com/xypower/mpapp/v2/Camera2VideoActivityOld.java @@ -33,7 +33,7 @@ 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.v2.AutoFitGLView; import com.xypower.mpapp.MicroPhotoService; import com.xypower.mpapp.R; diff --git a/app/src/main/res/layout/activity_camera2_video.xml b/app/src/main/res/layout/activity_camera2_video.xml index cdf43001..7c58cc11 100644 --- a/app/src/main/res/layout/activity_camera2_video.xml +++ b/app/src/main/res/layout/activity_camera2_video.xml @@ -6,7 +6,7 @@ > - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file