zoukankan      html  css  js  c++  java
  • ijkplayer视频播放

     

     
    http://android-doc.com/androiddocs/2017/1018/5416.html
    https://www.2cto.com/kf/201801/714366.html
    https://zhuanlan.zhihu.com/p/25262844
     
    时间:2017-10-18 16:08来源:未知 作者:卓一哥 点击: 1296 次
    图1 视频播放是一个很常见的功能,根据功能需求的不同,有不同的实现方式。 如果只是类似预览的功能,可以直接调取系统的视频播放功能: Intent intent = new Intent(); intent.setAction(Int

    图1图1
    视频播放是一个很常见的功能,根据功能需求的不同,有不同的实现方式。
    如果只是类似预览的功能,可以直接调取系统的视频播放功能:

     

     Intent intent = new Intent();
     intent.setAction(Intent.ACTION_VIEW);
     intent.setDataAndType(Uri.fromFile(new File(path)), "video/mp4");
     activity.startActivity(intent);

    这样做的话,就会跳出App,好处就是用起来简单,坏处就是离开的应用,如果有其他需求的话则无法实现。

    最近的项目中用到的视频播放,有一些特殊的功能,比如不允许用户快进,但是可以退回,用户看过的部分可以快进。要记录播放进度,再次进入时要恢复进度。可以设置断点,断点暂停后用户需要手动点击继续播放。综上,上面的做法就不能用了,只能自己写一个播放器了。

    之前用过Vitamio,整体的使用感觉还是比较顺利,文档示例都比较全。也没有什么大bug。但是商用收费!如果你对Vitamio感兴趣可以看这里

    这次就用了ijkplayer。ijkplayer的文档和示例都没有Vitamio那么多,我是在示例上修修改改的。它是可以支持的在线播放和本地播放的。

    它们都是基于FFmpeg的,你也可以直接干FFmpeg。

    按照ijkplayer的github一步步集成进来,还是比较顺利的。就是这样:

     

    图2图2

     

    官方示例

    上面例子最好down下来,跑一下。

    我用到了一个VideoView来播放视频,它是一个FrameLayout。
    我是在这里扒的,这里代码还用到了其他的调用,一并copy过来,最后是这样的。

    图3图3
    其他的代码你也可以在示例中找到。我把上面的代码放到了自己的项目中。

     

    然后在布局中放入你写(拷)的IjkVideoView。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="@color/black">
    
        <com.greendami.video.widget.media.IjkVideoView
            android:id="@+id/video"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"></com.greendami.video.widget.media.IjkVideoView>
    
    </LinearLayout>

    如果你只是想简单的播放视频,对界面没有什么要求的话,可以使用ijkplayer提供的MediaController,直接就有进度条,暂停,播放等功能。
    video.setMediaController(AndroidMediaController(this)),不需要的话就传个null进去就行。

    只要这样就行:

    package com.greendami.actvity.worknotes
    
    import android.content.pm.ActivityInfo
    import android.content.res.Configuration
    import android.net.Uri
    import android.os.Environment
    import android.view.WindowManager
    import android.widget.FrameLayout
    import android.widget.LinearLayout
    import com.allrun.dangjianshisanshi.R
    import com.allrun.dangjianshisanshi.actvity.BaseActivity
    import com.allrun.dangjianshisanshi.video.widget.media.AndroidMediaController
    import com.allrun.dangjianshisanshi.widget.LoadingDialog
    import kotlinx.android.synthetic.main.activity_worknote_videoplayer.*
    import org.jetbrains.anko.toast
    import tv.danmaku.ijk.media.player.IjkMediaPlayer
    
    /**
     * Created by greendami on 2017/8/30.
     */
    class WorkNoteVideoPlayerActivity : BaseActivity() {
    
        private val SIZE_DEFAULT = 0
        private val SIZE_4_3 = 1
        private val SIZE_16_9 = 2
        private val currentSize = SIZE_DEFAULT
    
        private var screenWidth = 0
        private var screenHeight = 0
    
    
        ////http://www.modrails.com/videos/passenger_nginx.mov
        var uri = Uri.parse(Environment.getExternalStorageDirectory().path + "/test.mp4")
        var path = ""
    
        override fun setContentView() {
            setContentView(R.layout.activity_worknote_videoplayer)
        }
    
        override fun initView() {
            IjkMediaPlayer.loadLibrariesOnce(null)
            IjkMediaPlayer.native_profileBegin("libijkplayer.so")
            LoadingDialog.showDialog(this)
            initEvent()
        }
    
        private fun initEvent() {
    
            back.setOnClickListener { finish() }
            video.setOnCompletionListener {
                toast("播放完毕")
                finish()
            }
    
            video.setOnPreparedListener {
                LoadingDialog.dismissDialog()
                video.start()
                setVideoLayoutSize()
            }
    
    
        }
    
    
        private fun setVideoLayoutSize() {
            initScreenInfo()
            var width = video.width
            var height = video.height
            if (video.getmVideoWidth() / video.getmVideoHeight() > width / height) {
                height = width * video.getmVideoHeight() / video.getmVideoWidth()
            } else {
                width = height * video.getmVideoWidth() / video.getmVideoHeight()
            }
    
    
            if (width > 0 && height > 0) {
                val lp = video.getmRenderView().view.layoutParams as FrameLayout.LayoutParams
                lp.width = width
                lp.height = height
                video.getmRenderView().view.layoutParams = lp
            }
        }
    
    
        override fun bindData() {
            video.setVideoPath(path)
            video.setMediaController(AndroidMediaController(this))
        }
    
        override fun loadData() {
            path = intent.extras["path"].toString()
        }
    
        private fun setScreenRate(newConfig: Configuration) {
            var width = 0
            var height = 0
            if (newConfig.orientation === Configuration.ORIENTATION_LANDSCAPE) {//切换为横屏
                when (currentSize) {
                    SIZE_DEFAULT -> {
                        width = video.getmVideoWidth()
                        height = video.getmVideoHeight()
                    }
                    SIZE_4_3 -> {
                        width = screenHeight / 3 * 4
                        height = screenHeight
                    }
                    SIZE_16_9 -> {
                        width = screenHeight / 9 * 16
                        height = screenHeight
                    }
                }
            } else { //竖屏
    
                when (currentSize) {
                    SIZE_DEFAULT -> {
                        width = video.getmVideoWidth()
                        height = video.getmVideoHeight()
                    }
                    SIZE_4_3 -> {
                        width = screenWidth
                        height = screenWidth * 3 / 4
                    }
                    SIZE_16_9 -> {
                        width = screenWidth
                        height = screenWidth * 9 / 16
                    }
                }
            }
            if (width > 0 && height > 0) {
                val lp = video.getmRenderView().view.layoutParams as FrameLayout.LayoutParams
                lp.width = width
                lp.height = height
                video.getmRenderView().view.layoutParams = lp
            }
    
        }
    
        private fun fullChangeScreen() {
            requestedOrientation = if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {// 切换为竖屏
                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
            } else {
                ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
            }
        }
    
        override fun onConfigurationChanged(newConfig: Configuration) {
            super.onConfigurationChanged(newConfig)
            //重新获取屏幕宽高
            initScreenInfo()
            if (newConfig.orientation === Configuration.ORIENTATION_LANDSCAPE) {//切换为横屏
    
                //去掉通知栏
                //获得 WindowManager.LayoutParams 属性对象
                val lp2 = window.attributes
                //直接对它flags变量操作   LayoutParams.FLAG_FULLSCREEN 表示设置全屏
                lp2.flags = lp2.flags or WindowManager.LayoutParams.FLAG_FULLSCREEN
                //设置属性
                window.attributes = lp2
                //意思大致就是  允许窗口扩展到屏幕之外
                window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
    
    
                val lp = video.layoutParams as LinearLayout.LayoutParams
                lp.height = screenHeight
                lp.width = screenWidth
                video.layoutParams = lp
            } else {
    
                //恢复通知栏
                //获得 WindowManager.LayoutParams 属性对象
                val lp2 = window.attributes
                //LayoutParams.FLAG_FULLSCREEN 强制屏幕状态条栏弹出
                lp2.flags = lp2.flags and WindowManager.LayoutParams.FLAG_FULLSCREEN.inv()
                //设置属性
                window.attributes = lp2
                //不允许窗口扩展到屏幕之外  clear掉了
                window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
    
    
                val lp = video.layoutParams as LinearLayout.LayoutParams
                when (currentSize) {
                    SIZE_DEFAULT -> {
                        lp.height = video.getmVideoHeight() * screenWidth / video.getmVideoWidth()
                    }
                    SIZE_4_3 -> {
                        lp.height = screenWidth * 3 / 4
                    }
                    SIZE_16_9 -> {
                        lp.height = screenWidth * 9 / 16
                    }
                }
    
                lp.width = screenWidth
                video.layoutParams = lp
            }
            setScreenRate(newConfig)
        }
    
        private fun initScreenInfo() {
            val wm = this.windowManager
    
            screenWidth = wm.defaultDisplay.width
            screenHeight = wm.defaultDisplay.height
        }
    
    
        override fun onDestroy() {
            video.release(true)
            LoadingDialog.dismissDialog()
            super.onDestroy()
        }
    }

    如果不把BaseActivity放上来,可能看起来费劲,这个是我随便写的,请不要在意。

    abstract class BaseActivity : LifecycleActivity() {
        lateinit var modelHolder: ModelHolder
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            modelHolder = ViewModelProviders.of(this).get(ModelHolder::class.java)
            setContentView()
            loadData()
            initView()
            bindData()
        }
    
        abstract fun setContentView()
    
        /**
         * 请求数据
         */
        abstract fun loadData()
    
        abstract fun initView()
    
        /**
        * 把数据和控件绑定
        */
        abstract fun bindData()
    
    }

    大体的步骤是:

    //加载库文件
    IjkMediaPlayer.loadLibrariesOnce(null)
    IjkMediaPlayer.native_profileBegin("libijkplayer.so")
    
    //设置文件路径可以是网络地址或者本地文件路径
    video.setVideoPath(path)
    //使用默认的控制界面,进度条快进等等
    video.setMediaController(AndroidMediaController(this))
    
    //绑定加载完成监听器,加载完了就播放
    video.setOnPreparedListener {
            LoadingDialog.dismissDialog()
            video.start()
            //这里是设置视频的尺寸,不是必须
            setVideoLayoutSize()
        }
    //到此就完成了,如果你需要重力感应,全屏切换,请往下看
    
    //如果按钮切换横竖屏,调用这个方法
    fullChangeScreen()
    //这里是横竖屏切换事件的回调
    override fun onConfigurationChanged(newConfig: Configuration)
    
    //这里是屏幕方向改变后重新计算视频尺寸,我是默认不改变视频长宽比的前提下铺满屏幕
    //video.getmVideoWidth()是视频的尺寸,是我自己加的方法,只是返回了tmVideoWidth
    //video.getmRenderView().view.layoutParams = lp这句是真正设置视频尺寸
    private fun setScreenRate(newConfig: Configuration) {
            initScreenInfo()
            var width = screenWidth
            var height = screenHeight
            if (video.getmVideoWidth() / video.getmVideoHeight() > width / height) {
                height = width * video.getmVideoHeight() / video.getmVideoWidth()
            } else {
                width = height * video.getmVideoWidth() / video.getmVideoHeight()
            }
            if (width > 0 && height > 0) {
                val lp = video.getmRenderView().view.layoutParams as FrameLayout.LayoutParams
                lp.width = width
                lp.height = height
                video.getmRenderView().view.layoutParams = lp
            }
    
        }

    如果你需要控制视频,下面的API你可能会用到:

    //进度控制
    video.seekTo(progress)
    //视频播放完毕回调
    video.setOnCompletionListener {toast("播放完毕")}
    //视频长度
    video.duration
    //暂停
    video.pause()
    //继续播放
    if (!video.isPlaying) video.start();

    http://android-doc.com/androiddocs/2017/1018/5416.html
  • 相关阅读:
    SQL Server: TRUSTWORTHY数据库属性
    查看SQL Server的版本
    SQL学习笔记7
    SQL Server Database:ReadOnly
    Shell编程(五)find与grep命令简介及正则表达式
    windowXP 任务计划无法启动 错误代码:0X80041315
    ORA14400: inserted partition key does not map to any partition
    Windows 批处理实现 定时打开IE 延时一段时间后 关闭IE
    尝试创建自定义事件日志时,将会收到“Requested registry access is not allowed(不允许所请求的注册表访问权)”错误消息
    Linux的用户和组群管理
  • 原文地址:https://www.cnblogs.com/pengmn/p/9068094.html
Copyright © 2011-2022 走看看