将蒙版应用于Android上的视频预览

时间:2014-04-08 20:22:32

标签: android video surfaceview mask

我正在尝试在Android上的视频供稿(预览)中应用蒙版。

我们的想法是在设备屏幕上裁剪视频,使其看起来像圆形。

这是我迄今为止所取得的成就:

scren grab of app

(忽略视频Feed中的黑色圆形条带,即xml布局中的单独资源)

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

我正在覆盖我的SurfaceView的绘制方法并应用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.
    }
}

根据Porter-Duff混合模式的视觉指南:

XferModes Example

我正在寻找的应该是PorterDuff.Mode.XOR,但我得到的是带有红色填充的圆圈,而不是视频源。 (我知道红色来自xferPaint.setColor调用)

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

您正在使用xferPaint来做两件事:

  • 在缓冲区中绘制圆圈
  • 在预览上方绘制缓冲区

并且您正在使用rounderBitmap将每个渲染中的圆圈重新绘制到DST_IN中!

我认为如果您重新排序代码,您可能会得到想要的结果(未经测试):

    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);

如果它有效,那么您可能需要考虑:

  • rounderBitmap分配为200x200位图,而不是w x h
  • drawCircle(100, 100, 100
  • rounderBitmap位置w/2-100h/2-100drawBitmap位置。

一般情况下,您可以尝试转储位图以查看它是否是您想要的位置(图像中间有一个圆圈(正确的颜色/ alpha):

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);

免责声明:我没有使用PorterDuff的经验,以上所有内容只是一般建议。