将遮罩应用于Android上的视频预览

将遮罩应用于Android上的视频预览,android,video,surfaceview,mask,Android,Video,Surfaceview,Mask,我正在尝试在Android上的视频源(预览)上应用一个掩码 其想法是在设备屏幕上裁剪出视频,使其看起来呈圆形 以下是我迄今为止所能完成的: (忽略视频提要中的黑色圆形带,这是xml布局中的一个单独资源) 正如你所看到的,我有录像带,中间有个圆孔。我需要相反的(即,我应该看到“洞”内的视频,其余的应该是不可见的) 我正在覆盖SurfaceView的draw方法并应用Porter-Duff模式: 以下是相关代码: package org.dornad.test; import android.c

我正在尝试在Android上的视频源(预览)上应用一个掩码

其想法是在设备屏幕上裁剪出视频,使其看起来呈圆形

以下是我迄今为止所能完成的:

(忽略视频提要中的黑色圆形带,这是xml布局中的一个单独资源)

正如你所看到的,我有录像带,中间有个圆孔。我需要相反的(即,我应该看到“洞”内的视频,其余的应该是不可见的)

我正在覆盖SurfaceView的draw方法并应用Porter-Duff模式:

以下是相关代码:

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
一般来说,你可以尝试将位图倾倒,看看它是否是你想要的(中间有一个圆圈的图像(用正确的颜色/ alpha):


免责声明:我没有使用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);