3.使用MediaPlayer+SurfaceView播放视频文件

使用MediaPlayer+SurfaceView播放视频文件

MediaPlayer 主要用于播放音频,没有提供图像输出界面,所以需要借助其他的组件来显示 MediaPlayer 播放的图像,可以使用 SurfaceView 来显示。

Surface 和 SurfaceHolder | Android 开源项目 | Android Open Source Project (google.cn)

Surface 、SurfaceHolder和SurfaceView

Surface 对象使应用能够渲染要在屏幕上显示的图像。通过 SurfaceHolder 接口,应用可以编辑和控制 Surface。

Surface

Surface 是一个接口,供生产方与消耗方交换缓冲区。

SurfaceHolder

SurfaceHolder 是系统用于与应用共享 Surface 所有权的接口。与 Surface 配合使用的一些客户端需要 SurfaceHolder,因为用于获取和设置 Surface 参数的 API 是通过 SurfaceHolder 实现的。一个 SurfaceView 包含一个 SurfaceHolder。

与 View 交互的大多数组件都涉及到 SurfaceHolder。

SurfaceView

SurfaceView 是一个组件,可以像对待其他任何 View 一样对其进行操作,但 SurfaceView 的内容是透明的。

当 SurfaceView 的 View 组件即将变得可见时,框架会要求 SurfaceControl 从 SurfaceFlinger 请求新的 surface。如需在创建或销毁 Surface 时收到回调,请使用 SurfaceHolder 接口。默认情况下,新创建的 Surface 放置在应用界面 Surface 的后面。您可以替换默认的 Z 轴顺序,将新的 Surface 放在前面。

当 Activity 启动时,您将按以下顺序获得回调:

  1. onCreate()
  2. onResume()
  3. surfaceCreated()
  4. surfaceChanged()

如果点击“返回”,您会获得:

  1. onPause()
  2. surfaceDestroyed()(在 Surface 消失前调用)

这句话照应了前面的 获取和设置 Surface 参数的 API 是通过 SurfaceHolder 实现

Access to the underlying surface is provided via the SurfaceHolder interface, which can be retrieved by calling getHolder().

通过SurfaceHolder.Callback让Surface可

三者的理解

什么是surfaceview?和surface有区别吗?SurfaceHolder和他们的关系是怎样? - 知乎 (zhihu.com)

Canvas是Java层构建的数据结构,是给View用的画布。ViewGroup会把自己的Canvas拆分给子View。View会在onDraw方法里将图形数据绘制在它获得的Canvas上。

而Surface是Native层构建的数据结构,是给SurfaceFlinger用的画布。它是直接被用来绘制到屏幕上的数据结构。

开发者一般所用的View都是在Canvas进行绘制,然后最顶层的View(通常是DecorView)的Canvas的数据信息会转换到一个Surface上。SurfaceFlinger会将各个应用窗口的Surface进行合成,然后绘制到屏幕上。

那为什么会有一个SurfaceView呢?

这是因为View的测量(Measure),布局(Layout)以及绘制(Draw)的计算量比较大。计算完以后再从Canvas转换成Surface中数据,然后再绘制屏幕,这个流程比较耗时。对于常规的UI绘制不会有什么问题,但是像Camera的预览以及视频的播放这样的应用场景来说就不可接受了。

SurfaceView就是为了解决这个问题。SurfaceView内容不再是绘制在Canvas上,而是直接绘制在其持有的一个Surface上。由于省去了很多步骤,其绘制性能大大提高。而SurfaceView本身只是用来控制这个Surface的大小和位置而已。

surfaceview 和surfaceholder的理解和使用-CSDN博客

通过SurfaceView的getHolder()函数可以获取SurfaceHolder对象,Surface 就在SurfaceHolder对象内。虽然Surface保存了当前窗口的像素数据,但是在使用过程中是不直接和Surface打交道的,由SurfaceHolder的Canvas lockCanvas()或则Canvas lockCanvas(Rect dirty)函数来获取Canvas对象,通过在Canvas上绘制内容来修改Surface中的数据。如果Surface不可编辑或则尚未创建调用该函数会返回null,在
unlockCanvas() 和 lockCanvas()中Surface的内容是不缓存的,所以需要完全重绘Surface的内容,为了提高效率只重绘变化的部分则可以调用lockCanvas(Rect dirty)函数来指定一个dirty区域,这样该区域外的内容会缓存起来。

在调用lockCanvas函数获取Canvas后,SurfaceView会获取Surface的一个同步锁直到调用unlockCanvasAndPost(Canvas canvas)函数才释放该锁,这里的同步机制保证在Surface绘制过程中不会被改变(被摧毁、修改)。

当在Canvas中绘制完成后,调用函数unlockCanvasAndPost(Canvas canvas)来通知系统Surface已经绘制完成,这样系统会把绘制完的内容显示出来。

Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系_surfaceholder callback2 callback-CSDN博客

引伸地,可以认为Android中的Surface就是一个用来画图形(graphics)或图像(image)的地方。

通过SurfaceView就可以看到Surface的部分或者全部的内容。

SurfaceHolder是一个接口,其作用就像一个关于Surface的监听器。提供访问和控制SurfaceView背后的Surface 相关的方法。

Coding

public class MediaPlayerVideoActivity extends AppCompatActivity implements View.OnClickListener, SurfaceHolder.Callback {
    /**
     * MediaPlayer + SurfaceView 播放视频
     */
    private static final String TAG = "MediaPlayerVideoActivity";

    private Button mStartButton;
    private Button mPauseButton;
    private Button mStopButton;
    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;
    private MediaPlayer mPlayer = null;
    private boolean isRelease = false;   //判断是否MediaPlayer是否释放的标志

    public static Intent newIntent(Context packageContext) {
        Intent intent = new Intent(packageContext, MediaPlayerVideoActivity.class);
        return intent;
    }

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

        bindViews();
    }

    private void bindViews() {
        mStartButton = (Button) findViewById(R.id.btn_media_player_video_start);
        mPauseButton = (Button) findViewById(R.id.btn_media_player_video_pause);
        mStopButton = (Button) findViewById(R.id.btn_media_player_video_stop);

        mStartButton.setOnClickListener(this);
        mPauseButton.setOnClickListener(this);
        mStopButton.setOnClickListener(this);

        mSurfaceView = (SurfaceView) findViewById(R.id.sfv_media_player_video);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(this);
        mSurfaceHolder.setFixedSize(320, 220);   //显示的分辨率,不设置为视频默认
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_media_player_video_start:
                if (isRelease) {
                    loadVideo();
                    isRelease = false;
                }
                mPlayer.start();
                mStartButton.setEnabled(false);
                mPauseButton.setEnabled(true);
                mStopButton.setEnabled(true);
                break;
            case R.id.btn_media_player_video_pause:
                mPlayer.pause();
                mStartButton.setEnabled(true);
                mPauseButton.setEnabled(false);
                mStopButton.setEnabled(false);
                break;
            case R.id.btn_media_player_video_stop:
                mPlayer.reset();
                isRelease = true;
                // stop() 之后如果想再次播放,就得再次prepare()
                mStartButton.setEnabled(true);
                mPauseButton.setEnabled(false);
                mStopButton.setEnabled(false);
                break;
        }
    }

    @SuppressLint("LongLogTag")
    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        mPlayer = new MediaPlayer();
        loadVideo();
    }

    private void loadVideo() {
        // 播放raw目录下文件
//        mPlayer = MediaPlayer.create(MediaPlayerVideoActivity.this, R.raw.big_buck_bunny);

        // 播放 本地资源

        mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        File file = new File("//sdcard/Movies/lesson.mp4");
        try {
            mPlayer.setDataSource(getApplicationContext(), Uri.parse(file.getAbsolutePath()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            mPlayer.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mPlayer.setDisplay(mSurfaceHolder);    //设置显示视频显示在SurfaceView上
    }


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

    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        if (mPlayer.isPlaying()) {
            mPlayer.stop();
        }
        mPlayer.release();
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用以下代码实现MediaPlayer SurfaceView播放视频、暂停播放、停止播放: 播放视频: ``` MediaPlayer mediaPlayer = new MediaPlayer(); SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView); SurfaceHolder surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { try { mediaPlayer.setDataSource("your_video_path"); mediaPlayer.setDisplay(holder); mediaPlayer.prepare(); mediaPlayer.start(); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // do nothing } @Override public void surfaceDestroyed(SurfaceHolder holder) { mediaPlayer.release(); } }); ``` 暂停播放: ``` if (mediaPlayer.isPlaying()) { mediaPlayer.pause(); } ``` 停止播放: ``` if (mediaPlayer.isPlaying()) { mediaPlayer.stop(); } ``` ### 回答2: 使用MediaPlayerSurfaceView播放视频,可以按照以下步骤进行操作: 1. 首先,创建一个MediaPlayer对象和SurfaceView对象,用于控制视频的播放和显示。 2. 设置SurfaceView的回调方法,在回调方法中获取到SurfaceHolder对象,并将其与MediaPlayer对象进行关联。 3. 通过MediaPlayer的setDataSource()方法设置要播放的视频文件的路径。 4. 调用MediaPlayer的prepareAsync()方法进行异步准备,准备完成后触发onPrepared()回调方法。 5. 在onPrepared()方法中,可以调用MediaPlayer的start()方法开始播放视频。 6. 若要暂停播放视频,可以调用MediaPlayer的pause()方法。 7. 若要停止播放视频,可以调用MediaPlayer的stop()方法,并在停止后调用MediaPlayer的release()方法释放资源。 简单的示例代码如下: ```java MediaPlayer mediaPlayer = new MediaPlayer(); SurfaceView surfaceView = findViewById(R.id.surfaceView); surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { mediaPlayer.setDisplay(holder); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } }); try { mediaPlayer.setDataSource("视频文件路径"); mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mediaPlayer.start(); } }); } catch (IOException e) { e.printStackTrace(); } // 暂停播放 mediaPlayer.pause(); // 停止播放 mediaPlayer.stop(); mediaPlayer.release(); ``` 以上就是使用MediaPlayerSurfaceView播放视频、暂停播放和停止播放的简要步骤。 ### 回答3: 使用MediaPlayer SurfaceView播放视频、暂停播放、停止播放的步骤如下: 1. 创建MediaPlayer对象,并设置其数据源为要播放的视频文件路径或URL。 2. 创建SurfaceView对象,并通过getHolder()方法获取SurfaceHolder对象。 3. 通过SurfaceHolder对象添加回调方法,实现SurfaceHolder.Callback接口的三个方法:surfaceCreated、surfaceChanged和surfaceDestroyed。在surfaceCreated方法中,将SurfaceHolder传给MediaPlayer对象的setDisplay方法。 4. 调用MediaPlayer对象的prepareAsync或prepare方法准备播放。 5. 在MediaPlayer对象准备完成的监听器中,调用MediaPlayer对象的start方法开始播放视频。 6. 若要暂停播放视频,调用MediaPlayer对象的pause方法。 7. 若要停止播放视频,调用MediaPlayer对象的stop方法,并在停止后调用MediaPlayer对象的release方法释放资源。 可以在播放视频之前设置一些附加功能,如设置循环播放、设置音量等。此外,还可以监听MediaPlayer对象的各种事件,如播放完成、缓冲进度等,以便进行相应的处理。 需要注意的是,在使用MediaPlayer SurfaceView播放视频时,可能会涉及到一些多线程的处理。比如,在surfaceCreated方法中设置MediaPlayer对象的setDisplay方法时,MediaPlayer对象可能还未准备好,需要等待MediaPlayer对象准备完成后才能设置。因此,可以通过监听MediaPlayer对象的准备完成事件来确保播放视频SurfaceView已经生成。 以上是通过MediaPlayer SurfaceView播放视频、暂停播放、停止播放的基本步骤,具体实现还需根据需要进行适当调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值