Texture View video and Bitmap display

2019-08-06 08:48发布

问题:

I have a TextureView that displays a bitmap(placeholder image) and when the user loads a video the textureView should show the video.

I managed to get video playback in the texture view and showing a bitmap in a textureview, but when done in sequence i just get a black screen.

In my onSurfaceTextureAvailable method i draw a bitmap on the surface view as followed:

@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
    Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_add_clip);
    Canvas canvas = lockCanvas();
    canvas.drawBitmap(bm, (width/2)-(bm.getWidth()/2), (height/2)-(bm.getHeight()/2), null);
    unlockCanvasAndPost(canvas);
}

When the user selects a video from its gallery i load the Uri in the Media player and set the surface to the mediaplayer. But the bitmap is still shown. i tried to remove the bitmap by clearing the canvas, and it does remove the bitmap but then the texture view is just black and won't show the video as well.

public void setMediaPlayer(MediaPlayer mediaPlayer) {
    // Canvas canvas = lockCanvas();
    // canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    // unlockCanvasAndPost(canvas);

    Surface s = new Surface(getSurfaceTexture());
    mMediaPlayer = mediaPlayer;
    mMediaPlayer.setSurface(s);
    mMediaPlayer.setOnPreparedListener(this);
}

Something tells me that the surface view i'm using to display the video is behind the bitmap that i draw in the on TextureAvailble. And when i try to clear the canvas i also clear the surface that the mediaplayer wants to use. Any solutions?

回答1:

Your approach won't work.

The Surface is a queue of buffers with a producer-consumer relationship. There can be only one producer at a time, and you have two producers (Canvas and MediaPlayer). When you call mMediaPlayer.setSurface() it attaches MediaPlayer; when you call lockCanvas() it attaches Canvas. You need to detach one before you can attach the other.

(Check your logcat output -- there's probably some "already connected" complaints in there.)

The trouble is, while you should be able to detach MediaPlayer, you can't detach Canvas. There's simply no call that does it. This is an unfortunate artifact in the API. (Confirmed up through 4.4 "KitKat", and I doubt it has changed since.)

You have a few options:

  1. Draw the bitmap with GLES instead. You can see an example in Grafika's PlayMovieSurface activity -- see the clearSurface() method, which just clears the screen. With GLES, you can attach and detach from the surface.
  2. Convert your bitmap into a single-frame video and play it through MediaPlayer.
  3. Put an ImageView on top of the video window with a FrameLayout. Hide the ImageView while the video is playing.

I should add that I haven't actually tried detaching a MediaPlayer from a Surface. The lower-level MediaCodec works this way, as shown by the Grafika player, so I'm assuming MediaPlayer will also detach cleanly. For your use case, though, #3 is probably the easiest solution, and requires no attach/detach gymnastics.



回答2:

You can use opengl es to draw a bitmap to the display surface , and then draw video frame with the same way. I did in this way and it works fine.