Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - Creating a circular mask on video

I'm relatively new to Android development, and I was wondering if it's possible to mask a VideoView into a shape. This is what I have so far:

Expected Result

Expected Results (Mockup)

Actual Results

My XML for video view and layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#0088ff"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".VideoPlayerActivity" >

    <FrameLayout
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:background="@drawable/circular_mask"
        android:foreground="@drawable/circular_mask" >

        <VideoView
            android:id="@+id/videoView1"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:fitsSystemWindows="false"
            android:focusable="false"
            android:focusableInTouchMode="false"
            android:scrollbarAlwaysDrawVerticalTrack="false" />

        <Space
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </FrameLayout>

</RelativeLayout>

Mask shape xml:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:padding="20dp"
    android:shape="oval" >

    <solid android:color="#FFFFFFFF" />

    <corners android:radius="10dp" />

</shape>

Main java:

package com.example.webmvideo;

import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.annotation.TargetApi;
import android.app.Activity;
import android.view.Menu;
import android.widget.MediaController;
import android.widget.VideoView;
import android.util.Log;
import android.media.MediaPlayer;

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class MainActivity extends Activity {

    Uri srcPath = Uri.parse("android.resource://com.example.webmvideo/" + R.raw.test);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final VideoView videoView = (VideoView) 
                findViewById(R.id.videoView1);

        videoView.setVideoURI(srcPath);

        MediaController mediaController = new MediaController(this);
        mediaController.setAnchorView(videoView);
        videoView.setMediaController(mediaController);

        videoView.setOnPreparedListener(new 
                MediaPlayer.OnPreparedListener()  {
            @Override
            public void onPrepared(MediaPlayer mp) {                         
                String TAG = null;
                Log.i(TAG , "Duration = " + videoView.getDuration());
            }
        });     
        videoView.start();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}
like image 721
jamesbar Avatar asked Jan 08 '14 16:01

jamesbar


2 Answers

Turns out it is possible to clip a video into a circle. What you're going to want to do is create your own SurfaceView class and override dispatchDraw from here you can call canvas.clipPath and pass in a Path object that contains the circle you want the video to be masked to.

Here's the view:

public class CircleSurface extends SurfaceView {

    private Path clipPath;

    public CircleSurface(Context context) {
        super(context);
        init();
    }

    public CircleSurface(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CircleSurface(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        clipPath = new Path();
        //TODO: define the circle you actually want
        clipPath.addCircle(710, 330, 250, Path.Direction.CW);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.clipPath(clipPath);
        super.dispatchDraw(canvas);
    }
}

Here's what the activity might look like

public class MainActivity extends Activity implements SurfaceHolder.Callback {

    CircleSurface surface;
    MediaPlayer player;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        surface = (CircleSurface) findViewById(R.id.surface);
        SurfaceHolder holder = surface.getHolder();
        holder.addCallback(this);

        player = MediaPlayer.create(this, R.raw.yourvideo);
    }


    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        player.setDisplay(holder);
        player.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        //TODO: handle this
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        //TODO: handle this
    }
}
like image 73
Troy Warmboe Avatar answered Nov 14 '22 02:11

Troy Warmboe


I've done something like this mask before. you can get what you want as following steps
1) prepare a png image with the shape you want and fill it with color 0x0000000
2) use a blank layout and make sure it covers the VideView
3) now, all touchevents are captured by this blank layout
4) judge the points' colors which are contained in TouchEvent, if the color is 0x00000000 then pass the event to VideView

here is a example to get a point's color, and it runs efficently:

// build a drawingCache and draw the mask layer to the bitmap
        Bitmap drawingCache = Bitmap.createBitmap(getWidth(), getHeight(),Bitmap.Config.ARGB_4444);
        Canvas drawingCacheCanvas = new Canvas(drawingCache);
        drawingCacheCanvas.clipRect(x, y, x + 1, y + 1); 
        draw(drawingCacheCanvas);

        int color = drawingCache.getPixel(x, y);

        if (color == getMaskColor()) { 
            //TODO dispatch event to VideoView and let it to handle event
        }
like image 35
exloong Avatar answered Nov 14 '22 03:11

exloong