19

我的 xml 文件:

<SurfaceView
    android:id="@+id/surfaceView"
    android:layout_marginTop="50dp"
    android:layout_width="fill_parent"
    android:layout_height="300dp" />

我设置显示的功能:

public void playVideo() {
    MediaPlayer mp = new MediaPlayer();
    SurfaceView sv = (SurfaceView) this.findViewById(R.id.surfaceView);
    try {
        mp.setDataSource("sdcard/test/a.3gp");
        SurfaceHolder sh = sv.getHolder();
        mp.setDisplay(sh);***----the exception occured here***
        mp.prepare();
        mp.start();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

日志如下:

04-24 22:19:33.645: W/System.err(16106): java.lang.IllegalArgumentException: The surface has been released
04-24 22:19:33.645: W/System.err(16106):    at android.media.MediaPlayer._setVideoSurface(Native Method)
04-24 22:19:33.645: W/System.err(16106):    at android.media.MediaPlayer.setDisplay(MediaPlayer.java:698)

我在这里发现了一些类似的问题,但所有这些都不适合我。等待您的答复。非常感谢。

4

6 回答 6

14

表面可以被破坏。这就是为什么您需要将 a 添加到public void surfaceDestroyed(SurfaceHolder holder)SurfaceView 的实现中,如下所示:

  @Override
public void surfaceDestroyed(SurfaceHolder holder) {
    synchronized (this) {
        hasActiveHolder = false;

        synchronized(this)          {
              this.notifyAll(); 
        }
    } 
}

您还应该添加一个处理 Surface 创建的函数:

@Override
public void surfaceCreated(SurfaceHolder holder) {
     synchronized (this) {
        hasActiveHolder = true;
        this.notifyAll()
     }
}

并以这种方式修改您自己的功能:

    mp.setDataSource("sdcard/test/a.3gp");
    SurfaceHolder sh = sv.getHolder();
    synchronized (this) {
       while (!hasActiveHolder) {
              try {
                  this.wait();
              } catch (InterruptedException e) {
                //Print something
              }
        }
        mp.setDisplay(sh);
        mp.prepare();
    }

您还有另一种选择,这是 Google 建议您使用 SurfaceView 的方式:在单独的线程中。

于 2013-04-24T15:05:22.200 回答
11

这与执行顺序有关,因为在设置显示之前必须先创建表面MediaPlayer,因此您必须将回调方法覆盖surfaceCreated为以下内容:

@Override
public void surfaceCreated(SurfaceHolder holder) {
    mp.setDisplay(sh); // now "mp" is defined as a class variable
}

现在不需要在你的播放方法中设置显示:

private MediaPlayer mp; // to use it inside surfaceCreated callback method
public void playVideo() {
    mp = new MediaPlayer();
    SurfaceView sv = (SurfaceView) this.findViewById(R.id.surfaceView);
    try {
        mp.setDataSource("sdcard/test/a.3gp");
        SurfaceHolder sh = sv.getHolder();
        mp.prepare();
        mp.start();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
于 2015-07-21T09:09:19.847 回答
4

使用 SurfaceHolder.Callback 如下

SurfaceView mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
SurfaceHolder holder = mSurfaceView.getHolder();
final MediaPlayer player = new MediaPlayer();

holder.addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        player.setDisplay(holder);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, 
    int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }
});

String UrlPath="android.resource://"+getActivity().getPackageName()+"/"+R.raw.your_file_name_without_extension;
try {
    player.setDataSource(getActivity(),Uri.parse(UrlPath));
    player.prepareAsync();
} catch (IOException e) {
    e.printStackTrace();
}
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {

    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.start();
    }
});
于 2017-08-24T07:14:22.230 回答
3

setDisplay最简单的方法就是调用surfaceCreated

@Override
public void surfaceCreated(SurfaceHolder holder) {
    mp.setDisplay(holder)
}

并且不要忘记取消绑定表面:

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    mp.setDisplay(null);
}

注意:媒体播放器应该在之前的某个地方初始化,例如在onCreate.

于 2016-03-08T22:37:06.803 回答
1

对于那些仍然有问题的人,请尝试在您的活动/片段/等和onCreate/onCreateView方法中实现SurfaceHolder.Callback ,调用addCallback(SurfaceHolder.Callback 回调)方法,使用您的活动/片段/等作为参数回调。

于 2016-11-16T17:29:10.803 回答
0

我们可以看一下VideoView源码:

SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback(){
...
    public void surfaceCreated(SurfaceHolder holder)
    {
        mSurfaceHolder = holder;
        openVideo();
    }
    private void openVideo() {
        ...
        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setDisplay(mSurfaceHolder);
    }
}

所以我们可以知道我们应该mediaplayer.setDisplay()surfaceCreate方法被调用时使用。

于 2018-02-08T05:19:45.307 回答