Android m3u8网络视频播放

最近在做 m3u8网络视频播放,踩了不少坑,也试了不少的 框架,特别记录一下其中用的比较多的三种

第一种:media:ijkplayer

media:ijkplayer 是由 bilbil 提供的开源的视频 框架,但是由过之后感觉不太好用:

优点:
1、支持 Android 和 IOS
2、支持多种视频的硬解码

缺点:
1、加载时间过长;从开始加载 到 开始播放 第一帧视频,中间最少需要十秒时间(一开始以为是自己的配置有问题,但在网上找了一下,但都没有找到好的解决方案)
2、不支持实时视频截图(由于项目的需要,需要关闭时,最后显示的视频截图,但看了一下源码,并没有找到提供相关源码)

如果有哪位大神解决的,麻烦给留个言!!!!!

media:ijkplayer 的github地址:https://github.com/bilibili/ijkplayer

集成方式:

// required, enough for most devices.
    implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
    implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'
    // Other ABIs: optional
    implementation 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'
    implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
    implementation 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'
    implementation 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'
    // ExoPlayer as IMediaPlayer: optional, experimental
    implementation 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'

混淆配置:

-keep class tv.danmaku.ijk.media.player.** { *; }

使用:
1):IjkVideoView

public class IjkVideoView extends FrameLayout {
    private Context mContext;//上下文
    private IMediaPlayer mMediaPlayer = null;//视频控制类
    private VideoPlayerListener mVideoPlayerListener;//自定义监听器
    private SurfaceView mSurfaceView;//播放视图
    private String mPath = "";//视频文件地址

    public IjkVideoView(@NonNull Context context) {
        super(context);
        initVideoView(context);
    }

    public IjkVideoView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initVideoView(context);
    }

    public IjkVideoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initVideoView(context);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public IjkVideoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public abstract static class VideoPlayerListener implements IMediaPlayer.OnPreparedListener,
            IMediaPlayer.OnCompletionListener,
            IMediaPlayer.OnErrorListener {
    }

    private void initVideoView(Context context) {
        mContext = context;
        setFocusable(true);
    }

    public void setPath(String path) {
        if (TextUtils.equals("", mPath)) {
            mPath = path;
            initSurfaceView();
        } else {
            mPath = path;
            loadVideo();
        }
    }

    private void initSurfaceView() {
        mSurfaceView = new SurfaceView(mContext);
        mSurfaceView.getHolder().addCallback(new LmnSurfaceCallback());
        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER);
        mSurfaceView.setLayoutParams(layoutParams);
        this.addView(mSurfaceView);
    }

    //surfaceView的监听器
    private class LmnSurfaceCallback implements SurfaceHolder.Callback {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
        }

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

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
        }
    }

    //加载视频
    private void loadVideo() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.release();
        }

        IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();
        mMediaPlayer = ijkMediaPlayer;
        if (mVideoPlayerListener != null) {
            mMediaPlayer.setOnPreparedListener(mVideoPlayerListener);
            mMediaPlayer.setOnErrorListener(mVideoPlayerListener);
        }
        try {
            mMediaPlayer.setDataSource(mPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        mMediaPlayer.setDisplay(mSurfaceView.getHolder());
        mMediaPlayer.prepareAsync();
    }

    public void setListener(VideoPlayerListener listener) {
        this.mVideoPlayerListener = listener;
        if (mMediaPlayer != null) {
            mMediaPlayer.setOnPreparedListener(listener);
        }
    }

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

    public void start() {
        if (mMediaPlayer != null) {
            mMediaPlayer.start();
        }
    }

    public void pause() {
        if (mMediaPlayer != null) {
            mMediaPlayer.pause();
        }
    }

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

    public void reset() {
        if (mMediaPlayer != null) {
            mMediaPlayer.reset();
        }
    }

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

2):布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="@color/color_000000"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_centerInParent="true"
        android:layout_height="wrap_content"
        android:background="@color/color_000000"
        android:orientation="vertical">

        <com.tzyun.pip.view.IjkVideoView
            android:id="@+id/jkVideoView"
            android:layout_width="match_parent"
            android:layout_height="300dp" />

    </LinearLayout>

    <ImageView
        android:id="@+id/back"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:contentDescription="@null"
        android:paddingStart="13dp"
        android:paddingEnd="13dp"
        android:src="@mipmap/back_video" />

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

</RelativeLayout>

3):Activity

public class IjkPlayerVideoActivity extends Activity {

    private AlertDialog alertDialog;
    private String path;
    private IjkVideoView ijkVideoView;


    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        path = getIntent().getStringExtra("ADDRESS");
        setContentView(R.layout.ijkplayervideo_layout);
        findViewById(R.id.back).setOnClickListener(v -> onBackPressed());

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("播放错误");
        builder.setNegativeButton("重试", (dialogInterface, i) -> setLiveParam());
        builder.setPositiveButton("退出", (dialogInterface, i) -> finish());
        alertDialog = builder.create();
        alertDialog.setCancelable(false);
        alertDialog.setCanceledOnTouchOutside(false);
        setLiveParam();
    }

    private void setLiveParam() {
        findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
        IjkMediaPlayer.loadLibrariesOnce(null);
        IjkMediaPlayer.native_profileBegin("libijkplayer.so");
        //监听
        ijkVideoView=findViewById(R.id.jkVideoView);
        ijkVideoView.setListener(new IjkVideoView.VideoPlayerListener() {
            @Override
            public void onPrepared(IMediaPlayer mp) {
                //播放成功处理
                mp.start();
                findViewById(R.id.progressBar).setVisibility(View.INVISIBLE);
            }

            @Override
            public void onCompletion(IMediaPlayer iMediaPlayer) {
            }

            @Override
            public boolean onError(IMediaPlayer mp, int what, int extra) {
                ToastUtils.showToast("播放失败");
                finish();
                return true;
            }
        });

//        path = "你自己的播放地址";

        //路径
        ijkVideoView.setPath(path);

        ijkVideoView.start();
    }

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) ijkVideoView.getLayoutParams();
        //横屏
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            params.height = RelativeLayout.LayoutParams.MATCH_PARENT;
        } else {
            //竖屏
            params.height = (int) UnitUtils.dp2px(this, 300);
        }
        ijkVideoView.setLayoutParams(params);
    }

    @Override
    protected void onDestroy() {
        IjkMediaPlayer.native_profileEnd();
        if (alertDialog != null && alertDialog.isShowing()) {
            alertDialog.dismiss();
        }
        ijkVideoView.stop();
        super.onDestroy();
    }

    @Override
    protected void onResume() {
        super.onResume();
        findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
        if (!ijkVideoView.isPlaying()) {
            ijkVideoView.start();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        ijkVideoView.pause();
    }
}

第二种:Vitamio

Vitamio是适用于Android和iOS的开放式多媒体框架,具有完整,真实的硬件加速解码器和渲染器。

新的功能:

  1. 支持大多数FFmpeg AVOptions,从而启用自定义HTTP标头支持。
  2. 支持更多的硬件,例如X86或MIPS。
  3. 改善流媒体,特别是支持自适应比特率流媒体,需要手动打开。
  4. 包含OpenSSL,因此支持某些与SSL相关的协议,例如https,tls,rtmps,rtmpts。
  5. 播放速度控制从0.5倍到2.0倍。
  6. 改进的字幕支持,包括外部位图字幕。
  7. 在线视频缓存到本地存储中,并且可以重复使用,直到删除缓存文件为止。
  8. 更多MediaPlayer API,例如getMetadata,getVideoTrack。
  9. 完整的Java代码对所有开发人员开放,欢迎修改和贡献。
    10.支持RGBA_8888渲染​​,支持将RGB_565或RGBA_8888切换到视频渲染。

Vitamio 感觉是强大的,播放速度也很快,也可以截图,但在使用过程也遇到了问题:
根据文档的提示,Vitamio 是可以 支持 https 的,但使用的结果是 https 无法播放,所以放弃了使用,也不知道是不是因为安全证书出了问题,还有一个问题就是,Vitamio 最早是更新于七年前,很多方法已经过时了,不知道还有没有人在维护。

Vitamio gitHub地址:https://github.com/yixia/VitamioBundleStudio

使用:
1)、解压文件,将其中的vitamio导入到as中
Android m3u8网络视频播放_第1张图片
其中的vitamio-sample是官方提供的demo,而我们要导入as的是vitamio.

2)、打开AS,File -> New -> Import Moudle,选择刚才解压文件夹下的 vitamio 文件.
导入后的文件目录中会多出vitamin文件夹,如下图
Android m3u8网络视频播放_第2张图片
3)、在 dependencies 中添加 compile project(’:vitamio’) 如果你导入module中更改过名字的话 要改成修改后的名字 如图:
Android m3u8网络视频播放_第3张图片
混淆配置:

# For Vitamio classes
-keep class io.vov.utils.** { *; }
-keep class io.vov.vitamio.** { *; }

4)、打开app/src/main目录下的AndroidManifest.xml,注册io.vov.vitamio.activity.InitActivity

<activity
    android:name="io.vov.vitamio.activity.InitActivity"
    android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
    android:launchMode="singleTop"
    android:theme="@android:style/Theme.NoTitleBar"
    android:windowSoftInputMode="stateAlwaysHidden" />

注意:这个InitActivity存在于vitamio/src/对应的目录下,不需要用户编写.

添加权限:

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

至此,vitamio导入完毕.

5)、VideoView控件的使用

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <io.vov.vitamio.widget.CenterLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/color_000000"
        android:orientation="vertical">

        <io.vov.vitamio.widget.VideoView
            android:id="@+id/buffer"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" />

    </io.vov.vitamio.widget.CenterLayout>

    <ImageView
        android:id="@+id/back"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:contentDescription="@null"
        android:paddingStart="13dp"
        android:paddingEnd="13dp"
        android:src="@mipmap/back_video" />

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

</RelativeLayout>
public class VideoActivity extends Activity implements MediaPlayer.OnInfoListener {

    private VideoView mVideoView;
    private AlertDialog alertDialog;
    private int errorCount;
    private int requestCode;
    private String shotsName;
    private String path;
    private MediaPlayer mediaPlayer;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        Vitamio.isInitialized(this);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.vitamio_layout);
        mVideoView = findViewById(R.id.buffer);
        findViewById(R.id.back).setOnClickListener(v -> onBackPressed());

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("播放错误");
        builder.setNegativeButton("重试", (dialogInterface, i) -> {
            setLiveParam();

            mVideoView.resume();
        });
        builder.setPositiveButton("退出", (dialogInterface, i) -> finish());
        alertDialog = builder.create();
        alertDialog.setCancelable(false);
        alertDialog.setCanceledOnTouchOutside(false);

        setLiveParam();
    }

    private void setLiveParam() {
        errorCount = 0;

        findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
        Intent intent = getIntent();
        path = intent.getStringExtra("ADDRESS");
        requestCode = intent.getIntExtra("requestCode", 200);
        shotsName = intent.getStringExtra("shotsName");
        Uri uri = Uri.parse(path);
        mVideoView.setVideoURI(uri);
        mVideoView.setBufferSize(1024);
        mVideoView.setHardwareDecoder(true);
        mVideoView.requestFocus();
        mVideoView.setOnInfoListener(this);
        mVideoView.setOnPreparedListener(mediaPlayer -> {
            // optional need Vitamio 4.0
            mediaPlayer.setPlaybackSpeed(1.0f);
        });
        mVideoView.setOnErrorListener((mediaPlayer, i, i1) -> {
            errorCount++;

            if (errorCount > 3) {
                String errMsg = "MEDIA_ERROR_UNKNOWN";

                switch (i) {
                    case MediaPlayer.MEDIA_ERROR_UNKNOWN:
                        errMsg = "MEDIA_ERROR_UNKNOWN";
                        break;
                    case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
                        errMsg = "MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK";
                        break;
                    case MediaPlayer.MEDIA_ERROR_IO:
                        errMsg = "MEDIA_ERROR_IO";
                        break;
                    case MediaPlayer.MEDIA_ERROR_MALFORMED:
                        errMsg = "MEDIA_ERROR_MALFORMED";
                        break;
                    case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
                        errMsg = "MEDIA_ERROR_UNSUPPORTED";
                        break;
                    case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
                        errMsg = "MEDIA_ERROR_TIMED_OUT";
                        break;
                }

                alertDialog.setTitle("播放错误:" + errMsg);
                alertDialog.show();
            } else {
                new Handler().postDelayed(this::setLiveParam, 1000);
            }

            return true;
        });
    }

    @Override
    protected void onDestroy() {
        if (alertDialog != null && alertDialog.isShowing())
            alertDialog.dismiss();

        super.onDestroy();
    }

    @Override
    protected void onResume() {
        super.onResume();
        findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
    }

    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {
        mediaPlayer = mp;
        switch (what) {
            case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                if (mVideoView.isPlaying()) {
                    mVideoView.pause();
                }
                findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
                break;
            case MediaPlayer.MEDIA_INFO_BUFFERING_END:
                mVideoView.start();

                findViewById(R.id.progressBar).setVisibility(View.INVISIBLE);
                break;
            case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED:
                LogUtils.Log(getClass().getSimpleName(), "vitamio download rate" + extra + "kb/s");
                break;
        }
        return true;
    }

    // 捕获返回键的方法2
    @Override
    public void onBackPressed() {
        if (requestCode == 200) {
            super.onBackPressed();
        } else {
            viewShot();
        }
    }

    /**
     * view截图
     *
     * @return
     */
    public void viewShot() {
        if (mediaPlayer != null) {
            // 核心代码start
            Bitmap bitmap = mediaPlayer.getCurrentFrame();
            String savePath;
            if (bitmap != null) {
                String path = getExternalFilesDir(null).toString() + "/monitoringScreenshots/";
                File file = new File(path);
                if (!file.exists()) {
                    file.mkdirs();
                }
                try {
                    path = path + shotsName + ".png";
                    File file2 = new File(path);
                    if (file2.exists()) {
                        file2.delete();
                    }
                    savePath = BitmapUtils.saveBitmapToFileWithFilePathWithOriginParams(path, bitmap).toString();
                    setResult(savePath);
                } catch (IOException e) {
                    e.printStackTrace();
                    setResult("");
                }
            } else {
                setResult("");
            }
        } else {
            setResult("");
        }
    }

    /**
     * savePath 截图保存地址
     *
     * @param savePath
     */
    private void setResult(String savePath) {
        Intent intent = new Intent();
        intent.putExtra("screenshotPath", savePath);
        setResult(RESULT_OK, intent);
        finish();
    }
}

VideoView常用函数

/**
 * 获取扫描视频的Uri。
 * 参数layout(缩放参数)参见MediaPlayer的常量:VIDEO_LAYOUT_ORIGIN(原始大小)、VIDEO_LAYOUT_SCALE(画面全屏)、VIDEO_LAYOUT_STRETCH(画面拉伸)、VIDEO_LAYOUT_ZOOM(画面裁剪)、VIDEO_LAYOUT_FIT_PARENT(画面铺满)
 * 参数aspectRation(宽高比),为0将自动检测
 */
public void setVideoLayout(int layout,float aspectRatio);
//Surface是否有效。 参见Surface的isValid方法。
public boolean isValid();
//设置视频路径。
public void setVideoPath(String path);
//设置视频URI。(可以是网络视频地址)
public void setVideoURI(Uri uri);
//停止视频播放,并释放资源。
public void stopPlayback();
/**
 * 设置媒体控制器。
 * 参数controller:媒体控制器,注意是io.vov.vitamio.widget.MediaController。
 */
public void setMediaController(MediaController controller);    
//注册一个回调函数,在视频预处理完成后调用。在视频预处理完成后被调用。此时视频的宽度、高度、宽高比信息已经获取到,此时可调用seekTo让视频从指定位置开始播放。
public void setOnPreparedListener(OnPreparedListener l);
//获取当前播放位置。
public long getCurrentPosition();
//设置播放位置。单位毫秒
public void seekTo(long msec);
//是否正在播放。
public boolean isPlaying();
//获取缓冲百分比。
public int getBufferPercentage();
/**
 * 设置视频质量。
 * 参数quality参见MediaPlayer的常量:VIDEOQUALITY_LOW(流畅)、VIDEOQUALITY_MEDIUM(普通)、VIDEOQUALITY_HIGH(高质)
 */
public void setVideoQuality(int quality);
//设置视频缓冲大小。默认1024KB,单位byte
public void setBufferSize(int bufSize);
//检测是否缓冲完毕。
public boolean isBuffering();
//设置元数据编码。例如:UTF-8
public void setMetaEncoding(String encoding);

第三种:ExoPlayer

ExoPlayer是构建在Android低水平媒体API之上的一个应用层媒体播放器。和Android内置的媒体播放器相比,ExoPlayer有许多优点。ExoPlayer支持内置的媒体播放器支持的所有格式外加自适应格式DASH和SmoothStreaming。ExoPlayer可以被高度定制和扩展以适应不同的使用场景。

优点:

  1. 支持HTTP上的动态自适应流DASH和SmoothStreaming。更多详情请参看 Supported formats。
  2. 支持高级的HLS特点,例如正确的处理#EXT-X-DISCONTINUITY标签。
  3. 能够无缝的合并,串联,循环播放媒体文件。
  4. 能够被高度扩展和定制,以适用不同的场景。
  5. 加载速度快
  6. 支持视频截图
  7. 支持自定义组件

缺点:

  1. 在某些设备上播放音频,ExoPlayer可能会比MediaPlayer消耗更多的电量。

ExoPlayer gitHub 地址:https://github.com/google/ExoPlayer/

集成方式:

implementation 'com.google.android.exoplayer:exoplayer:2.13.2'

使用:

class ExoplayerActivity : Activity(), Player.EventListener {
    var path: String? = null
    private var simpleExoPlayer: SimpleExoPlayer? = null
    private var requestCode = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requestWindowFeature(Window.FEATURE_NO_TITLE)
        window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN)
        setContentView(R.layout.activity_exoplayer)
        path = intent.getStringExtra("ADDRESS")
        requestCode = intent.getIntExtra("requestCode", 200)
        initView()
    }

    private fun initView() {
        simpleExoPlayer = SimpleExoPlayer.Builder(this).build()
        path?.let {
            val mediaItem: MediaItem = MediaItem.fromUri(it)
            simpleExoPlayer?.setMediaItem(mediaItem)
            simpleExoPlayer?.prepare()
        }
        simpleExoPlayer?.addListener(this)
        exoplayer_videoView.player = simpleExoPlayer
        findViewById<View>(R.id.exoplayer_back).setOnClickListener { onBackPressed() }
    }

    override fun onPlaybackStateChanged(state: Int) {
//        Player.STATE_IDLE -> "ExoPlayer.闲置状态      -"
//        Player.STATE_BUFFERING -> "ExoPlayer.国家缓冲 -"
//        Player.STATE_READY -> "ExoPlayer.准备就绪     -"
//        Player.STATE_ENDED -> "ExoPlayer.状态已结束     -"
//        else -> "UNKNOWN_STATE
        when (state) {
            Player.STATE_READY -> {
                exoplayer_progressBar.visibility = View.GONE
            }
            else -> {
            }
        }

    }


    override fun onResume() {
        super.onResume()
        simpleExoPlayer?.play()
    }

    override fun onStop() {
        super.onStop()
        simpleExoPlayer?.pause()
    }

    override fun onDestroy() {
        super.onDestroy()
        simpleExoPlayer?.removeListener(this)
        simpleExoPlayer?.release()
    }

    // 捕获返回键的方法2
    @Override
    override fun onBackPressed() {
        if (requestCode == 200) {
            super.onBackPressed()
        } else {
            saveBitmap()
        }
    }

    /**
     * 获取并保存截图
     */
    private fun saveBitmap() {
        try {
            val textureView: TextureView = exoplayer_videoView.videoSurfaceView as TextureView
            val screenshotBitmap = textureView.bitmap
            val path = getExternalFilesDir(null).toString() + "/monitoringScreenshots/"
            val file = File(path)
            if (!file.exists()) {
                file.mkdirs()
            }
            //文件名为时间
            val timeStamp = System.currentTimeMillis()
            val sdf = SimpleDateFormat("yyyyMMdd_HHmmss")
            val sd = sdf.format(Date(timeStamp))
            val fileName = "$sd.jpg"
            val savePath = path + fileName

            val outputStream = FileOutputStream(savePath)
            screenshotBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
            outputStream.flush()
            outputStream.close()
            setResult(savePath)
        } catch (e: IOException) {
            e.printStackTrace()
            finish()
        }
    }

    /**
     * savePath 截图保存地址
     *
     * @param savePath
     */
    private fun setResult(savePath: String) {
        val intent = Intent()
        intent.putExtra("screenshotPath", savePath)
        setResult(RESULT_OK, intent)
        finish()
    }
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/color_000000"
    tools:context="com.tzyun.pip.ijkPlayer.ExoplayerActivity">


    <com.google.android.exoplayer2.ui.PlayerView
        android:id="@+id/exoplayer_videoView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:auto_show="false"
        app:use_controller="false"
        app:surface_type="texture_view"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/exoplayer_back"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:contentDescription="@null"
        android:paddingStart="13dp"
        android:paddingEnd="13dp"
        android:src="@mipmap/back_video"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ProgressBar
        android:id="@+id/exoplayer_progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

你可能感兴趣的:(android)