在特定时间/帧播放视频时叠加图像

时间:2013-12-16 07:46:36

标签: android image video overlay android-canvas

我将这个VideoView覆盖了另一个用于手绘的画布视图或从文件中绘制一系列图像。我想在视频的特定时间/帧上显示图像/绘图。我已经设置了一个线程来检查视频的播放时间,我会在哪里显示图像,但问题是在播放过程中除了继续播放的视频外,所有内容都会冻结。视频播放完毕后,仅显示最后一张图片。

这是我的布局:

    <FrameLayout
        android:id="@+id/flVidArea"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1" >

        <com.sample.CustomVideoView
            android:id="@+id/vvBg"
            android:layout_width="fill_parent"
            android:layout_height="330dp"
            android:layout_gravity="center" />

        <com.sample.DrawingView
            android:id="@+id/drawing"
            android:layout_width="fill_parent"
            android:layout_height="330dp"
            android:layout_gravity="center"
            android:background="@null"
            android:visibility="visible" />
    </FrameLayout>

这是我的CustomVideoView(实现自己的videoView来监听播放/暂停事件)

public class CustomVideoView extends SurfaceView implements MediaPlayerControl {
private String TAG = "VideoView";
private Uri mUri;
private int mDuration;

private SurfaceHolder mSurfaceHolder = null;
private MediaPlayer mMediaPlayer = null;
private boolean mIsPrepared;
private int mVideoWidth;
private int mVideoHeight;
private int mSurfaceWidth;
private int mSurfaceHeight;
private MediaController mMediaController;
private OnCompletionListener mOnCompletionListener;
private MediaPlayer.OnPreparedListener mOnPreparedListener;
private int mCurrentBufferPercentage;
private OnErrorListener mOnErrorListener;
private boolean mStartWhenPrepared;
private int mSeekWhenPrepared;

private PlayPauseListener mListener;

public CustomVideoView(Context context) {
    super(context);
    initVideoView();
}

public CustomVideoView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
    initVideoView();
}

public CustomVideoView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    initVideoView();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
    int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
    if (mVideoWidth > 0 && mVideoHeight > 0) {
        if (mVideoWidth * height > width * mVideoHeight) {
            height = width * mVideoHeight / mVideoWidth;
        } else if (mVideoWidth * height < width * mVideoHeight) {
            width = height * mVideoWidth / mVideoHeight;
        } else {
        }
    }
    setMeasuredDimension(width, height);
}

public int resolveAdjustedSize(int desiredSize, int measureSpec) {
    int result = desiredSize;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    switch (specMode) {
    case MeasureSpec.UNSPECIFIED:

        result = desiredSize;
        break;

    case MeasureSpec.AT_MOST:

        result = Math.min(desiredSize, specSize);
        break;

    case MeasureSpec.EXACTLY:
        result = specSize;
        break;
    }
    return result;
}

private void initVideoView() {
    mVideoWidth = 0;
    mVideoHeight = 0;
    getHolder().addCallback(mSHCallback);
    getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    setFocusable(true);
    setFocusableInTouchMode(true);
    requestFocus();
}

public void setVideoPath(String path) {
    setVideoURI(Uri.parse(path));
}

public void setVideoURI(Uri uri) {
    mUri = uri;
    mStartWhenPrepared = false;
    mSeekWhenPrepared = 0;
    openVideo();
    requestLayout();
    invalidate();
}

public void stopPlayback() {
    if (mMediaPlayer != null) {
        mMediaPlayer.stop();
        mMediaPlayer.release();
        mMediaPlayer = null;
    }
}

private void openVideo() {
    if (mUri == null || mSurfaceHolder == null) {
        return;
    }
    Intent i = new Intent("com.android.music.musicservicecommand");
    i.putExtra("command", "pause");
    getContext().sendBroadcast(i);

    if (mMediaPlayer != null) {
        mMediaPlayer.reset();
        mMediaPlayer.release();
        mMediaPlayer = null;
    }
    try {
        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setOnPreparedListener(mPreparedListener);
        mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
        mIsPrepared = false;
        Log.v(TAG, "reset duration to -1 in openVideo");
        mDuration = -1;
        mMediaPlayer.setOnCompletionListener(mCompletionListener);
        mMediaPlayer.setOnErrorListener(mErrorListener);
        mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
        mCurrentBufferPercentage = 0;
        mMediaPlayer.setDataSource(getContext(), mUri);
        mMediaPlayer.setDisplay(mSurfaceHolder);
        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mMediaPlayer.setScreenOnWhilePlaying(true);
        mMediaPlayer.prepareAsync();
        attachMediaController();
    } catch (IOException ex) {
        Log.w(TAG, "Unable to open content: " + mUri, ex);
        return;
    } catch (IllegalArgumentException ex) {
        Log.w(TAG, "Unable to open content: " + mUri, ex);
        return;
    }
}

public void setMediaController(MediaController controller) {
    if (mMediaController != null) {
        mMediaController.hide();
    }
    mMediaController = controller;
    attachMediaController();
}

private void attachMediaController() {
    if (mMediaPlayer != null && mMediaController != null) {
        mMediaController.setMediaPlayer(this);
        View anchorView = this.getParent() instanceof View ? (View) this
                .getParent() : this;
        mMediaController.setAnchorView(anchorView);
        mMediaController.setEnabled(mIsPrepared);
    }
}

MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() {
    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
        mVideoWidth = mp.getVideoWidth();
        mVideoHeight = mp.getVideoHeight();
        if (mVideoWidth != 0 && mVideoHeight != 0) {
            getHolder().setFixedSize(mVideoWidth, mVideoHeight);
        }
    }
};

MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
    public void onPrepared(MediaPlayer mp) {
        mIsPrepared = true;
        if (mOnPreparedListener != null) {
            mOnPreparedListener.onPrepared(mMediaPlayer);
        }
        if (mMediaController != null) {
            mMediaController.setEnabled(true);
        }
        mVideoWidth = mp.getVideoWidth();
        mVideoHeight = mp.getVideoHeight();
        if (mVideoWidth != 0 && mVideoHeight != 0) {

            getHolder().setFixedSize(mVideoWidth, mVideoHeight);
            if (mSurfaceWidth == mVideoWidth
                    && mSurfaceHeight == mVideoHeight) {
                if (mSeekWhenPrepared != 0) {
                    mMediaPlayer.seekTo(mSeekWhenPrepared);
                    mSeekWhenPrepared = 0;
                }
                if (mStartWhenPrepared) {
                    mMediaPlayer.start();
                    mStartWhenPrepared = false;
                    if (mMediaController != null) {
                        mMediaController.show();
                    }
                } else if (!isPlaying()
                        && (mSeekWhenPrepared != 0 || getCurrentPosition() > 0)) {
                    if (mMediaController != null) {
                        mMediaController.show(0);
                    }
                }
            }
        } else {
            if (mSeekWhenPrepared != 0) {
                mMediaPlayer.seekTo(mSeekWhenPrepared);
                mSeekWhenPrepared = 0;
            }
            if (mStartWhenPrepared) {
                mMediaPlayer.start();
                mStartWhenPrepared = false;
            }
        }
    }
};

private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
    public void onCompletion(MediaPlayer mp) {
        if (mMediaController != null) {
            mMediaController.hide();
        }
        if (mOnCompletionListener != null) {
            mOnCompletionListener.onCompletion(mMediaPlayer);
        }
    }
};

private MediaPlayer.OnErrorListener mErrorListener = new MediaPlayer.OnErrorListener() {
    public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
        if (mMediaController != null) {
            mMediaController.hide();
        }

        if (mOnErrorListener != null) {
            if (mOnErrorListener.onError(mMediaPlayer, framework_err,
                    impl_err)) {
                return true;
            }
        }

        if (getWindowToken() != null) {
            Resources r = getContext().getResources();
            int messageId;

            if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
                messageId = android.R.string.VideoView_error_text_invalid_progressive_playback;
            } else {
                messageId = android.R.string.VideoView_error_text_unknown;
            }

            new AlertDialog.Builder(getContext())
                    .setTitle(android.R.string.VideoView_error_title)
                    .setMessage(messageId)
                    .setPositiveButton(
                            android.R.string.VideoView_error_button,
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog,
                                        int whichButton) {

                                    if (mOnCompletionListener != null) {
                                        mOnCompletionListener
                                                .onCompletion(mMediaPlayer);
                                    }
                                }
                            }).setCancelable(false).show();
        }
        return true;
    }
};

private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
    public void onBufferingUpdate(MediaPlayer mp, int percent) {
        mCurrentBufferPercentage = percent;
    }
};

public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
    mOnPreparedListener = l;
}

public void setOnCompletionListener(OnCompletionListener l) {
    mOnCompletionListener = l;
}

public void setOnErrorListener(OnErrorListener l) {
    mOnErrorListener = l;
}

SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() {
    public void surfaceChanged(SurfaceHolder holder, int format, int w,
            int h) {
        mSurfaceWidth = w;
        mSurfaceHeight = h;
        if (mMediaPlayer != null && mIsPrepared && mVideoWidth == w
                && mVideoHeight == h) {
            if (mSeekWhenPrepared != 0) {
                mMediaPlayer.seekTo(mSeekWhenPrepared);
                mSeekWhenPrepared = 0;
            }
            mMediaPlayer.start();
            if (mMediaController != null) {
                mMediaController.show();
            }
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {
        mSurfaceHolder = holder;
        openVideo();
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        mSurfaceHolder = null;
        if (mMediaController != null)
            mMediaController.hide();
        if (mMediaPlayer != null) {
            mMediaPlayer.reset();
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
    }
};

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (mIsPrepared && mMediaPlayer != null && mMediaController != null) {
        toggleMediaControlsVisiblity();
    }
    return false;
}

@Override
public boolean onTrackballEvent(MotionEvent ev) {
    if (mIsPrepared && mMediaPlayer != null && mMediaController != null) {
        toggleMediaControlsVisiblity();
    }
    return false;
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (mIsPrepared && keyCode != KeyEvent.KEYCODE_BACK
            && keyCode != KeyEvent.KEYCODE_VOLUME_UP
            && keyCode != KeyEvent.KEYCODE_VOLUME_DOWN
            && keyCode != KeyEvent.KEYCODE_MENU
            && keyCode != KeyEvent.KEYCODE_CALL
            && keyCode != KeyEvent.KEYCODE_ENDCALL && mMediaPlayer != null
            && mMediaController != null) {
        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
                || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
            if (mMediaPlayer.isPlaying()) {
                pause();
                mMediaController.show();
            } else {
                start();
                mMediaController.hide();
            }
            return true;
        } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
                && mMediaPlayer.isPlaying()) {
            pause();
            mMediaController.show();
        } else {
            toggleMediaControlsVisiblity();
        }
    }

    return super.onKeyDown(keyCode, event);
}

private void toggleMediaControlsVisiblity() {
    if (mMediaController.isShowing()) {
        mMediaController.hide();
    } else {
        mMediaController.show();
    }
}

public void start() {
    if (mMediaPlayer != null && mIsPrepared) {
        mMediaPlayer.start();
        mStartWhenPrepared = false;
    } else {
        mStartWhenPrepared = true;
    }

    if (mListener != null) {
        mListener.onPlay();
    }
}

public void pause() {
    if (mMediaPlayer != null && mIsPrepared) {
        if (mMediaPlayer.isPlaying()) {
            mMediaPlayer.pause();
        }
    }
    mStartWhenPrepared = false;

    if (mListener != null) {
        mListener.onPause();
    }
}

public int getDuration() {
    if (mMediaPlayer != null && mIsPrepared) {
        if (mDuration > 0) {
            return mDuration;
        }
        mDuration = mMediaPlayer.getDuration();
        return mDuration;
    }
    mDuration = -1;
    return mDuration;
}

public int getCurrentPosition() {
    if (mMediaPlayer != null && mIsPrepared) {
        return mMediaPlayer.getCurrentPosition();
    }
    return 0;
}

public void seekTo(int msec) {
    if (mMediaPlayer != null && mIsPrepared) {
        mMediaPlayer.seekTo(msec);
    } else {
        mSeekWhenPrepared = msec;
    }
}

public boolean isPlaying() {
    if (mMediaPlayer != null && mIsPrepared) {
        return mMediaPlayer.isPlaying();
    }

    return false;

}

public int getBufferPercentage() {
    if (mMediaPlayer != null) {
        return mCurrentBufferPercentage;
    }
    return 0;
}

@Override
public boolean canPause() {
    return true;
}

@Override
public boolean canSeekBackward() {
    return false;
}

@Override
public boolean canSeekForward() {
    return false;
}

@Override
public int getAudioSessionId() {
    return 0;
}

public void setPlayPauseListener(PlayPauseListener listener) {
    mListener = listener;
}

interface PlayPauseListener {
    void onPlay();

    void onPause();
}
}

这是用于绘制图像/徒手绘图的绘图视图(画布)

public class DrawingView extends View {

Queue<DrawAgain> qDa;
DrawAgain drawAgain;
private Path drawPath;
private Paint drawPaint, canvasPaint;
private int paintColor = 0xFF660000;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private float brushSize, lastBrushSize;
private boolean erase = false;

public DrawingView(Context context, AttributeSet attrs) {
    super(context, attrs);
    setupDrawing();
}

private void setupDrawing() {

    brushSize = getResources().getInteger(R.integer.small_size);
    lastBrushSize = brushSize;
    drawPath = new Path();
    drawPaint = new Paint();
    drawPaint.setColor(paintColor);
    drawPaint.setAntiAlias(true);
    drawPaint.setStrokeWidth(brushSize);
    drawPaint.setStyle(Paint.Style.STROKE);
    drawPaint.setStrokeJoin(Paint.Join.ROUND);
    drawPaint.setStrokeCap(Paint.Cap.ROUND);
    canvasPaint = new Paint(Paint.DITHER_FLAG);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    drawCanvas = new Canvas(canvasBitmap);
}

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
    canvas.drawPath(drawPath, drawPaint);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    float touchX = event.getX();
    float touchY = event.getY();

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        drawPath.moveTo(touchX, touchY);
        break;
    case MotionEvent.ACTION_MOVE:
        drawPath.lineTo(touchX, touchY);
        break;
    case MotionEvent.ACTION_UP:
        drawPath.lineTo(touchX, touchY);
        drawCanvas.drawPath(drawPath, drawPaint);
        drawPath.reset();
        break;
    default:
        return false;
    }

    drawAgain = new DrawAgain(touchX, touchY, event, drawPath, drawCanvas,
            drawPaint);

    invalidate();
    return true;
}

public void setColor(String newColor) {
    invalidate();
    paintColor = Color.parseColor(newColor);
    drawPaint.setColor(paintColor);
}

public void setBrushSize(float newSize) {
    float pixelAmount = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, newSize, getResources()
                    .getDisplayMetrics());
    brushSize = pixelAmount;
    drawPaint.setStrokeWidth(brushSize);
}

public void setLastBrushSize(float lastSize) {
    lastBrushSize = lastSize;
}

public float getLastBrushSize() {
    return lastBrushSize;
}

public void setErase(boolean isErase) {
    erase = isErase;
    if (erase)
        drawPaint
                .setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    else
        drawPaint.setXfermode(null);
}

public void startNew() {
    drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
    invalidate();
}

public void drawBitmap(String filePath) {
    File imageFile = new File(filePath);
    if (imageFile.exists()) {

        Bitmap bitmap = BitmapFactory.decodeFile(filePath);
        drawCanvas.drawBitmap(bitmap, 0, 0, canvasPaint);

        invalidate();
    }
}
}

这是主要活动。这里的过程是在视频的3,9,13和17秒期间,图像显示。 在AsyncTask上,我在postExecute上放置了drawImages(),因为它不允许在另一个线程上执行View进程。

public class OverlayActivity extends Activity {

MediaMetadataRetriever mt;
private FrameLayout flAreaCopy;
private String source;
private CustomVideoView video;
private DrawingView drawView;
Bitmap drawingPic = null;

private String[] imagesName = new String[] { "image_9335.png",
        "image_3680.png", "image_13427.png", "image_17684.png" };
MediaController mediaController;
long videoDuration;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ActionBar actionBar = getActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
    actionBar.setDisplayShowHomeEnabled(false);
    actionBar.setDisplayShowTitleEnabled(true);
    actionBar.setTitle("Back");
    actionBar.setDisplayUseLogoEnabled(false);

    source = "/mnt/sdcard/sample4.mp4";

    setContentView(R.layout.videoeditor_layout);

    flAreaCopy = (FrameLayout) this.findViewById(R.id.flVidArea);
    flAreaCopy.setDrawingCacheEnabled(true);
    video = (CustomVideoView) this.findViewById(R.id.vvBg);
    video.setDrawingCacheEnabled(true);
    mediaController = new MediaController(this) {
        @Override
        public void hide() {
            this.show(0);
        }

    };
    mediaController.setMediaPlayer(video);
    mediaController.setAnchorView(video);
    video.setMediaController(mediaController);
    video.setVideoURI(Uri.parse("file://" + source));
    video.setOnPreparedListener(new OnPreparedListener() {

        @Override
        public void onPrepared(MediaPlayer mp) {
            mediaController.show(0);
            new DrawTask().execute();
        }

    });

    video.setPlayPauseListener(new CustomVideoView.PlayPauseListener() {

        @Override
        public void onPlay() {
            Log.i("OverlayAct", "Play!");
            videoDuration = video.getDuration();
            new DrawTask().execute();
        }

        @Override
        public void onPause() {
            Log.i("OverlayAct", "Pause!");
        }
    });

}

private void drawImages() {

    while (video.isPlaying()) {
        int time = video.getCurrentPosition() / 1000;

        if (time == 3) {
            drawView.drawBitmap(Environment.getExternalStorageDirectory()
                    + "/Kobera/" + imagesName[0]);

        } else if (time == 9) {
            drawView.drawBitmap(Environment.getExternalStorageDirectory()
                    + "/Kobera/" + imagesName[1]);

        } else if (time == 13) {
            drawView.drawBitmap(Environment.getExternalStorageDirectory()
                    + "/Kobera/" + imagesName[2]);

        } else if (time == 17) {
            drawView.drawBitmap(Environment.getExternalStorageDirectory()
                    + "/Kobera/" + imagesName[3]);
        }
    }
}

private class DrawTask extends AsyncTask<Void, Void, Boolean> {

    @Override
    protected void onPreExecute() {

        super.onPreExecute();

    }

    @Override
    protected Boolean doInBackground(Void... params) {

        return true;

    }

    @Override
    protected void onPostExecute(Boolean isValid) {

        drawImages();

        super.onPostExecute(isValid);
    }
}

}

以下是我的应用的截图:

enter image description here

我的问题是:

  1. 当在视频的特定时间显示一系列图像时,它仅在视频播放完毕后才能工作(但是当我将日志放在应该显示图像的位置时,它表明手机正在处理显示图像)。 我想也许是因为我使用的线索,但我不能想出更好的方法来做到这一点。
  2. 当视频播放时,一切都冻结了。绘图按钮和MediaController不再工作了。
  3. 我希望有人可以帮助我。感谢。

0 个答案:

没有答案