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. Cloudera Manager安装之利用parcels方式(在线或离线)安装单节点集群(包含最新稳定版本或指定版本的安装)(添加服务)(Ubuntu14.04)(四)

    .. 欢迎大家,加入我的微信公众号:大数据躺过的坑     免费给分享       同时,大家可以关注我的个人博客:  http://www.cnblogs.com/zlslch/   和  http ...

  2. Spring Cloud (3) 服务消费者-Ribbon

    在上一篇中使用LoadBalancerClient接口实现了获取某个服务的具体实例,并根据实例信息发起服务接口消费请求.但是这样的做法需要我们手工的区编写服务选取.连接拼接等繁琐的工作,对于开发人员来 ...

  3. [跨域]js设置document.domain实现跨域

    document.domain用来得到当前网页的域名.比如在地址栏里输入: 代码如下: javascript:alert(document.domain); //www.jb51.net 我们也可以给 ...

  4. SEO之如何做301转向

    1.如果网站使用的是(Linux+Apache+MySQL+PHP)主机,可以使用.htaccess文件做301转向 比如把/index.html 301转向到http://www.xinlvtian ...

  5. android黑科技系列——爆破一款应用的签名验证问题

    一.前言 在之前的文章中说过Android中的安全和破解是相辅相成的,为了防止被破解,很多应用做了一些防护策略,但是防护策略也是分等级,一般简单的策略就是混淆代码和签名校验,而对于签名校验很多应用都是 ...

  6. android黑科技系列——分析某直播App的协议加密原理以及调用加密方法进行协议参数构造

    一.前言 随着直播技术火爆之后,各家都出了直播app,早期直播app的各种请求协议的参数信息都没有做任何加密措施,但是慢慢的有人开始利用这个后门开始弄刷粉关注工具,可以让一个新生的小花旦分分钟变成网红 ...

  7. CentOS 7 中配置通过 daemon 模式启动的 Tomcat 8 服务

    距离上次折腾已经有很长一段时间了... 不说这个,刚好有空闲,把这两天折腾的 Tomcat 8 的服务配置整理出来收录一下. 1.JDK安装 1)检查服务器是否预装了 openJdk,如果有就删除,在 ...

  8. C# 7.0新加特性

    以下将是 C# 7.0 中所有计划的语言特性的描述.随着 Visual Studio “15” Preview 4 版本的发布,这些特性中的大部分将活跃起来.现在是时候来展示这些特性,你也告诉借此告诉 ...

  9. HTML编辑器ASP.NET

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="kindeditor.aspx. ...

  10. springMvc学习地址新

    http://www.admin10000.com/document/6436.html 一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要的jar ...