Android SurfaceView:在图片后显示视频

时间:2015-10-27 16:05:43

标签: android android-mediaplayer surfaceview

我希望在同一SurfaceView中的几张图片后播放视频。如果我在视频后显示图像,一切正常。但如果我想在图像后播放视频,SurfaceView将保持空白(黑色)。有人可以帮忙吗?这似乎是清除或重置SurfaceView的问题!

SurfaceView的代码(自定义SurfaceView !!!):

public class MySurfaceView extends SurfaceView implements  SurfaceHolder.Callback, MediaPlayer.OnCompletionListener {

    private Bitmap image;
    private MediaPlayer mediaPlayer;
    private List<MySurfaceListener> objectsToCall = new ArrayList<>();

    public MySurfaceView(Context context) {
        super(context);
        getHolder().addCallback(this);
    }

    public void addOnPlayingFinishedListener(MySurfaceListener listener) {
        objectsToCall.add(listener);
    }

    public void notifyAllOnPlayingFinishedListener() {
        for(MySurfaceListener l : objectsToCall) {
            l.onMediaPlayFinished();
        }
    }

    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Helper method to scale down the image files
    }

    public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight) {

        // Another helper method for the image files
    }

    public void drawImage(String path, final int durationMs) {
        this.image = decodeSampledBitmapFromFile(path, 1920, 1080);
        Canvas canvas = null;
        try {
            canvas = getHolder().lockCanvas(null);
            synchronized (getHolder()) {
                onDraw(canvas);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (canvas != null) {
                getHolder().unlockCanvasAndPost(canvas);
            }
            image.recycle();
            image = null;
        }

        Thread showPictureTimer = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(durationMs);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        showPictureTimer.start();
        try {
            showPictureTimer.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        notifyAllOnPlayingFinishedListener();
    }

    public void playVideo(String path) {
        try {
            mediaPlayer = new MediaPlayer();
            mediaPlayer.setOnCompletionListener(this);
            mediaPlayer.setDisplay(getHolder());
            mediaPlayer.setDataSource(path);
            mediaPlayer.prepare();
            mediaPlayer.start();
        } catch (IllegalArgumentException e) {
            Log.d("MyMediaPlayerControl", e.getMessage());
        } catch (IllegalStateException e) {
            Log.d("MyMediaPlayerControl", e.getMessage());
        } catch (IOException e) {
            Log.d("MyMediaPlayerControl", e.getMessage());
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.BLACK);
        canvas.drawBitmap(this.image, 0, 0, new Paint());
    }

    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        Log.e("myApp", "surfaceChanged");
    }

    public void surfaceCreated(SurfaceHolder arg0) {
        Log.e("myApp", "surfaceCreated");
    }

    public void surfaceDestroyed(SurfaceHolder arg0) {
        Log.e("myApp", "surfaceDestroyed");
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
        notifyAllOnPlayingFinishedListener();
    }
}

将文件路径提供给表面视图进行播放的线程(应该不是问题):

public class MediaControlThread extends Thread implements MySurfaceListener {
    public static List<String> mediaList = new ArrayList<String>();
    MyMediaActivity activity;
    private MySurfaceView surfaceView;
    private int currentVideo = 0;

    public MediaControlThread(MyMediaActivity activity) {
        this.activity = activity;
        this.surfaceView = activity.getSurfaceView();
        this.surfaceView.addOnPlayingFinishedListener(this);
    }

    @Override
    public void run() {
        try {
            while(mediaList.size() == 0) {
               Thread.sleep(1000);
            }
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        playMedia(mediaList.get(currentVideo));
    }

    private void playMedia(String mediaPath) {
        if(checkFileForImage(mediaPath)) {
            surfaceView.drawImage(mediaPath, 2000);
        } else {
            surfaceView.playVideo(mediaPath);
        }
    }

    private boolean checkFileForImage(String fileName) {
        String file = fileName.toLowerCase();
        return file.endsWith(".jpg") ||
                file.endsWith(".img") ||
                file.endsWith(".bmp") ||
                file.endsWith(".jpeg") ||
                file.endsWith(".ico") ||
                file.endsWith(".tif");
    }

    @Override
    public void onMediaPlayFinished() {
        surfaceView.invalidate();
        surfaceView.destroyDrawingCache();
        currentVideo++;
        if (currentVideo > mediaList.size() - 1) {
            currentVideo = 0;
        }
        playMedia(mediaList.get(currentVideo));
    }
}

1 个答案:

答案 0 :(得分:3)

不幸的是,这是预期的行为。由于Android中的怪癖,一旦你在带有画布的Surface上绘制,你就无法做任何其他事情。

您有三种选择:

  1. 使用OpenGL ES而不是Canvas绘制图像。分离GLES后,您可以返回显示视频。
  2. 将图像显示为单帧视频。这对于消隐屏幕等微不足道的事情很有效,但对于动态内容来说却是一个糟糕的选择。
  3. 使用FrameLayout覆盖ImageView或自定义视图。要显示图像时显示视图,否则隐藏它。只要Surface处于默认的Z深度,ImageView就会出现在它前面并使其模糊不清。