将遮罩应用于Android上的视频预览
我正在尝试在Android上的视频源(预览)上应用一个掩码 其想法是在设备屏幕上裁剪出视频,使其看起来呈圆形 以下是我迄今为止所能完成的: (忽略视频提要中的黑色圆形带,这是xml布局中的一个单独资源) 正如你所看到的,我有录像带,中间有个圆孔。我需要相反的(即,我应该看到“洞”内的视频,其余的应该是不可见的) 我正在覆盖SurfaceView的draw方法并应用Porter-Duff模式: 以下是相关代码:将遮罩应用于Android上的视频预览,android,video,surfaceview,mask,Android,Video,Surfaceview,Mask,我正在尝试在Android上的视频源(预览)上应用一个掩码 其想法是在设备屏幕上裁剪出视频,使其看起来呈圆形 以下是我迄今为止所能完成的: (忽略视频提要中的黑色圆形带,这是xml布局中的一个单独资源) 正如你所看到的,我有录像带,中间有个圆孔。我需要相反的(即,我应该看到“洞”内的视频,其余的应该是不可见的) 我正在覆盖SurfaceView的draw方法并应用Porter-Duff模式: 以下是相关代码: package org.dornad.test; import android.c
package org.dornad.test;
import android.content.Context;
import android.graphics.*;
import android.hardware.Camera;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private Camera camera;
private final SurfaceHolder holder;
private Bitmap rounderBitmap;
private Paint xferPaint;
public CameraPreview(Context context, Camera camera) {
super(context);
this.camera = camera;
holder = getHolder();
holder.addCallback(this);
this.setDrawingCacheEnabled(true);
}
@Override
public void draw(Canvas canvas) {
Bitmap currentBitmap = get();
int w = currentBitmap.getWidth(), h = currentBitmap.getHeight();
if (rounderBitmap == null)
rounderBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(rounderBitmap);
if (xferPaint == null)
xferPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
xferPaint.setColor(Color.RED);
c.drawCircle(w/2, h/2, 100, xferPaint);
xferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(currentBitmap, 0, 0, null);
canvas.drawBitmap(rounderBitmap, 0, 0, xferPaint);
}
private Bitmap get() {
return this.getDrawingCache();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
setWillNotDraw(false);
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (IOException e) {
L.d("Error setting camera preview : %s", e.getMessage());
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (holder.getSurface() == null) {
return;
}
try {
camera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop an non-existent preview
}
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (IOException e) {
L.d("Error setting camera preview : %s", e.getMessage());
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in the Activity/Fragment.
}
}
根据波特-达夫混合模式的视觉指南:
我要找的应该是PorterDuff.Mode.XOR,但我得到的是带有红色填充的圆圈,而不是视频提要。(我知道红色来自xferPaint.setColor调用)
有什么想法吗?你用
xfirpaint
做两件事:
- 在缓冲区中画圆
- 在预览顶部绘制缓冲区的步骤
DST_IN
将每个渲染上的圆绘制到rounderBitmap
中
我认为,如果您对代码重新排序,您可能会得到想要的结果(未经测试):
此外,如果有效,您可能需要考虑:
- 将
分配为rounderBitmap
位图,而不是200x200
w x h
drawCircle(100100100
- 将
定位在rounderBitmap
,w/2-100
当h/2-100
时drawBitmap
免责声明:我没有使用PorterDuff的经验,以上只是一般性的建议。所以相机正在向曲面发送帧,而您也在曲面上绘制?我的期望是,一旦您在曲面上绘制了一次,您就再也看不到相机输出了。您在logcat中看到任何抱怨吗?我将在下面查看logcat我一回到办公室就开始工作了。但是AFAIK(或记住)没有投诉。只是检查了一下。logcat上没有投诉。我想我读错了你的代码……你将帧发送到表面,并渲染到视图中(通常只是一个透明的“孔”)。视图和曲面之间的混合将由系统合成器完成,因此应用程序渲染没有任何要混合的先前内容。请选择一种模式,将输出像素中的alpha设置为透明或不透明(视情况而定)。
Bitmap currentBitmap = get();
int w = currentBitmap.getWidth(), h = currentBitmap.getHeight();
if (rounderBitmap == null) {
rounderBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(rounderBitmap);
Paint holePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
holePaint.setColor(Color.RED);
c.drawCircle(w / 2, h / 2, 100, holePaint);
}
if (xferPaint == null) {
Paint xferPaint = new Paint();
xferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
}
canvas.drawBitmap(currentBitmap, 0, 0, null);
canvas.drawBitmap(rounderBitmap, 0, 0, xferPaint);
static int counter;
// inside draw:
File out = new File(getContext().getExternalCacheDir(), "frame_"+ counter++ +".png");
Bitmap.compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(out));
Log.d("DEBUG", "Written: " + out);