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. C# 获取Enum 描述和值集合

    //获取枚举的值 public static IEnumerable<T> GetEnumValues<T>() where T : struct { T[] values = ...

  2. HTML简单入门

    - Java攻城狮学习路线 - 基本结构 标准文档:www.w3.org <!DOCTYPE html> <html> <head> <meta charse ...

  3. 联想VIBE Shot(Z90-7/全网通) 解锁BootLoader

    工具下载链接: http://pan.baidu.com/s/1dF7zGTb 备用下载链接: http://pan.baidu.com/s/1i4UHP4L 本篇教程教你如何傻瓜式解锁BootLoa ...

  4. shiro登陆权限验证

    一>引入shirojar包 <!-- shiro登陆权限控制 -->        <dependency>            <groupId>org. ...

  5. 如何修改yii2.0用户登录使用的user表为其它的表

      这只是自己练习的一个记录而已. 因为某种原因,不想用yii自带的user表,想用自己建的admin数据库表,修改如下: 1. 参考高级模板里里的common\models\User 修改 Admi ...

  6. Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)

    多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ...

  7. MySQL基础命令小结

    数据库授权登录[root@localhost ~]# mysql -uroot -p123456mysql> grant select,lock tables on auth.* to 'adm ...

  8. PAT_A1142#Maximal Clique

    Source: PAT A1142 Maximal Clique (25 分) Description: A clique is a subset of vertices of an undirect ...

  9. 关于 docsify ssr 的研究

    关于 docsify ssr 的研究 docsify 虽然不错, 但是不支持 seo .官网虽然提供 seo 的一个简单示例, 但总总问题在 issues 中无人解答. 今天再次尝试, 解决了 ind ...

  10. 多重循环、缓冲区管理、数组(day06)

    无法预知的数字叫随机数 rand标准函数可以用来获得随机数 为了使用这个标准函数需要包含stdlib.h头文件 srand标准函数用来设置随机数种子 这个函数把一个整数作为种子使用 不同的种子产生的随 ...