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

 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

官方示例

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

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

图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.star
t(); http://android-doc.com/androiddocs/2017/1018/5416.html

ijkplayer视频播放的更多相关文章

  1. 基于Retrotfit2.1+Material Design+ijkplayer开发的一个APP(新闻,gif 动图,视频播放)

    此项目主要目的还是为了练习框架的使用,仅供学习用途. 数据来源 新闻 直接用的聚合数据提供的接口:https://www.juhe.cn/docs/api/id/235gif动图 通过jsoup爬的某 ...

  2. Android 音视频深入 十九 使用ijkplayer做个视频播放器(附源码下载)

    项目地址https://github.com/979451341/Myijkplayer 前段时候我觉得FFmpeg做个视频播放器好难,虽然播放上没问题,但暂停还有通过拖动进度条来设置播放进度,这些都 ...

  3. Eclipse集成ijkplayer并实现本地和网络视频播放等

    概述 Eclipse 集成ijkplayer demo,播放本地视频.和rtmp流. 详细 代码下载:http://www.demodashi.com/demo/10630.html 原文地址:Ecl ...

  4. Android ijkplayer 强大的视频播放器框架教程 -- 导入demo运行(一)

    首先介绍下这个开源项目,这个开源项目是BiliBli 开源的,首先感谢他们的团队. 这是开源的地址: https://github.com/Bilibili/ijkplayer 首先我为什么要选这个, ...

  5. Android 关于ijkplayer

    基于ijkplayer封装支持简单界面UI定制的视频播放器 可以解析ts格式的so库 怎样编译出可以解析ts等格式的so库?就是编译的时候需要在哪一步修改配置? 一些电视台的m3u8 CCTV1综合, ...

  6. Android音视频之MediaPlayer音视频播放

    前言: 昨天总结了视频录制,今天来学习一下视频的播放,Android的视频播放主要采用MediaPlayer类. MediaPlayer介绍 MediaPlayer类可用于控制音频/视频文件或流的播放 ...

  7. B站开源ijkplayer 等多个项目

    弹幕视频网 Bilibili(B 站)近日在 GitHub 网站上建立了开源工作组(BOSTF),用以分享与维护自己的开源项目,其中包括 DanmakuFlameMaster(燃烧吧!烈焰弹幕使)与 ...

  8. Android 多媒体视频播放一( 多媒体理解与经验分享)

    前言 说到android的多媒体,一把辛酸一把泪,当初听说会多媒体的比较牛掰,公司也有需求,于是乎我也积极的加入研究android多媒体的行列,记得以前刚接触的时候,最开始还是比较头大的,主要是但是很 ...

  9. 1.iOS直播ijkplayer(第一周)

    准备工作: 1.使用的B站的开源框架ijkplayer ,下载地址: https://github.com/Bilibili/ijkplayer ijkplayer 是一个基于 ffplay 的轻量级 ...

随机推荐

  1. windows phone媒体应用开发

    MediaElement 可以播放许多不同类型的音频和视频媒体. MediaElement 是一个可以在其表面显示视频的矩形区域,也可以播放音频.MediaElement 支持触控输入事件. 使用属性 ...

  2. Lua eval实现

    因为loadstring总是在全局环境中编译它的串,所以编译出的函数访问的变量是全局变量.为了避免污染全局环境我们需要用setfenv修改函数的环境 function eval(equation, v ...

  3. 【java基础】(1)Java的权限修饰符(public,protected,default,private)

    访问权限修饰符权限从高到低排列是public  ,protected  ,default, private. 一.根据“是否是同包”.“是否是子类”分为4中情况+本类 5种情况 二.把 同包中的子类 ...

  4. buf.readInt8函数详解

    offset {Number} 0 noAssert {Boolean} 默认:false 返回:{Number} 从该 Buffer 指定的 offset 位置开始读取一个有符号的8位整数值. 设置 ...

  5. 如何在Eclipse中创建Web服务器

    使用Eclipse开发Web项目时,需要先配置Web服务器,如果已经配置好Web服务器,就不需要再重新配置了.也就是说,本节的内容不是开发每个项目时,都必须经过的步骤.创建Web服务器的具体步骤如下: ...

  6. 【原创】python中文编码问题深入分析(三):python2.7文件读写中文编码问题

    上一篇文章介绍和分析了python2.7中使用print遇到的中文编码问题的原因和解决方案,本篇主要介绍一下python2.7中执行文件读写可能遇到的编码问题. 1.文件读取 假如我们读取一个文件,文 ...

  7. 【oracle开发】wmsys.wm_concat介绍

    wmsys.wm_concat是一个聚合函数,其作用是将一列数据转换成一行,也就是我们常用的行专列,但是该函数是一个undocument函数,所以不推荐大家使用这个函数.因为在后续的版本中还提不提供这 ...

  8. vue遇到的大坑,h5在ios10版本下不能打开页面

    无论是谁,在做事情的过程中总是会遇到学坑,才能成为最后的大神 这个坑不说了,找了半天.希望能帮助到你们 进入build文件夹: 找到webpack.prod.conf.js文件: 在UglifyPlu ...

  9. vue路由中的 Meta

    在项目中肯定有这样的需求,那就是在某个页面的时候,顶部展示 现在当前的页面路径,如下图: 这个在vue中其实很好实现. 首先出现这个肯定是相对应不同的页面,也就是说对应不同的路由,我们在定义路由的时候 ...

  10. iframe的2个问题

    1.iframe里的视频无全屏按钮<iframe src="" allowfullscreen></iframe>allowfullscreen有个浏览器前 ...