ijkplayer视频播放
图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视频播放的更多相关文章
- 基于Retrotfit2.1+Material Design+ijkplayer开发的一个APP(新闻,gif 动图,视频播放)
此项目主要目的还是为了练习框架的使用,仅供学习用途. 数据来源 新闻 直接用的聚合数据提供的接口:https://www.juhe.cn/docs/api/id/235gif动图 通过jsoup爬的某 ...
- Android 音视频深入 十九 使用ijkplayer做个视频播放器(附源码下载)
项目地址https://github.com/979451341/Myijkplayer 前段时候我觉得FFmpeg做个视频播放器好难,虽然播放上没问题,但暂停还有通过拖动进度条来设置播放进度,这些都 ...
- Eclipse集成ijkplayer并实现本地和网络视频播放等
概述 Eclipse 集成ijkplayer demo,播放本地视频.和rtmp流. 详细 代码下载:http://www.demodashi.com/demo/10630.html 原文地址:Ecl ...
- Android ijkplayer 强大的视频播放器框架教程 -- 导入demo运行(一)
首先介绍下这个开源项目,这个开源项目是BiliBli 开源的,首先感谢他们的团队. 这是开源的地址: https://github.com/Bilibili/ijkplayer 首先我为什么要选这个, ...
- Android 关于ijkplayer
基于ijkplayer封装支持简单界面UI定制的视频播放器 可以解析ts格式的so库 怎样编译出可以解析ts等格式的so库?就是编译的时候需要在哪一步修改配置? 一些电视台的m3u8 CCTV1综合, ...
- Android音视频之MediaPlayer音视频播放
前言: 昨天总结了视频录制,今天来学习一下视频的播放,Android的视频播放主要采用MediaPlayer类. MediaPlayer介绍 MediaPlayer类可用于控制音频/视频文件或流的播放 ...
- B站开源ijkplayer 等多个项目
弹幕视频网 Bilibili(B 站)近日在 GitHub 网站上建立了开源工作组(BOSTF),用以分享与维护自己的开源项目,其中包括 DanmakuFlameMaster(燃烧吧!烈焰弹幕使)与 ...
- Android 多媒体视频播放一( 多媒体理解与经验分享)
前言 说到android的多媒体,一把辛酸一把泪,当初听说会多媒体的比较牛掰,公司也有需求,于是乎我也积极的加入研究android多媒体的行列,记得以前刚接触的时候,最开始还是比较头大的,主要是但是很 ...
- 1.iOS直播ijkplayer(第一周)
准备工作: 1.使用的B站的开源框架ijkplayer ,下载地址: https://github.com/Bilibili/ijkplayer ijkplayer 是一个基于 ffplay 的轻量级 ...
随机推荐
- MySQL命令学习之技巧(博主推荐)
关于,这篇博客呢,是
- Entity Framework Code First -- 延迟加载和预先加载
还是以这两个表为例子 country包含零个或多个city, 这个外键关系是我后来加上去,原来没有. 然后再用Power Tool逆向, 产生如下代码 1: using System.Componen ...
- [转]浏览器缓存详解: expires, cache-control, last-modified, etag详细说明
最近在对CDN进行优化,对浏览器缓存深入研究了一下,记录一下,方便后来者 画了一个草图: 每个状态的详细说明如下: 1.Last-Modified 在浏览器第一次请求某一个URL时,服务器端的返回状态 ...
- Assembly之instruction之Register Mode
Assembler Code Content of ROM MOV R10,R11 MOV R10,R11 Length: One or two words Operation: Move the c ...
- OpenCV: OpenCV人脸检测框可信度排序
参考文章:http://blog.csdn.net/hua_007/article/details/45368607 使用OpenCV进行人脸识别时,使用 casecade.detectMultiSc ...
- window 8 电脑操作服务集合(网址)
如何开启Win8远程桌面 http://jingyan.baidu.com/album/48206aeae06627216ad6b3bf.html?picindex=2 Win8.1用户账户的配置管理 ...
- tomcat实现连接数据库
192.168.30.23mkdir /web/webapptar xf SLSaleSystem.tar.gz -C /web/webappls /web/wenbappvim /usr/loca ...
- Crossing Rivers UVA - 12230 概率与期望
题目大意:有个人每天要去公司上班,每次会经过N条河,家和公司的距离为D,默认在陆地的速度为1,给出N条河的信息,包括起始坐标p,宽度L,以及船的速度v.船会往返在河的两岸,人到达河岸时,船的位置是随机 ...
- ansible-galera集群部署(13)
一.环境准备 1.各主机配置静态域名解析: [root@node1 ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain local ...
- S-HR界面控件赋值取值
属性值: this.getField("entrys.variationReason").shrPromptBox("getValue").name