ijkplayer的github地址

ijkplayer的编译

gradle

现在可以直接使用gradle引入ijkplayer了。但是,如果需要对更多格式进行支持,还是需要自己编译一次。

allprojects {repositories {jcenter()}
}dependencies {# required, enough for most devices.compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.1.2'compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.1.2'# Other ABIs: optionalcompile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.1.2'compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.1.2'compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.1.2'compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.1.2'# ExoPlayer as IMediaPlayer: optional, experimentalcompile 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.1.2'
}
编译

如果我们需要获取更多的视频格式支持(比如mkv,rmvb等),需要自己进行编译。我这里有个成品,包括一个小的demo,不想编译的同学可以自提。github地址。

我是在Ubuntu下编译的。具体的方法官方的GitHub有,我总结一下,基本就是对着终端输入指令:

  1. 自行在ubuntu下配置好Android的sdk和ndk。

  2. 安装git和yasm。打开终端,依次输入如下指令:

sudo apt-get update
sudo apt-get install git
sudo apt-get install yasm
  1. 从github中拉取代码,并且cd到代码的目录下
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
cd ijkplayer-android
  1. 把代码更新到最新的版本。最新的版本号可以看GitHub。输入指令:
git checkout -B latest k0.8.1.2
  1. 初始化,包括了把ffmpeg的代码拉取到本地等操作,输入指令:
./init-android.sh
  1. clean一下,输入指令:
cd android/contrib./compile-ffmpeg.sh clean
  1. 编译ffmpeg软解码库,输入指令:
./compile-ffmpeg.sh all
  1. cd到上一级目录,输入指令:
cd ..
  1. 得到ijkplayer的项目,输入指令:
./compile-ijk.sh all

其实就是跟着步骤在命令行中敲指令。看清楚指令,不要敲错,应该很快就可以得到我们ijkplayer的项目了。这个项目已经可以支持所有的视频格式了。

在这个项目中,有好多好多个module,有exmaple,ijkplayer-java,ijkplayer-armv5等。分别是例子,ijkplayer java层的代码,适配不同cpu的native层代码等。

简单的ijkplayer使用

下面是我使用的方法。可以直接看这个demo:github地址。

  1. 引入依赖。
    我使用的ijkplayer的支持库,是编译得来的。所以我依赖了这些module
    compile project(':ijkplayer-java')compile project(':ijkplayer-armv5')compile project(':ijkplayer-armv7a')compile project(':ijkplayer-arm64')compile project(':ijkplayer-x86')compile project(':ijkplayer-x86_64')
  1. 自定义播放控件
    ijkplayer提供的没有提供一个播放器控件给我们使用,所以我们自己定义一个。主要是创建一个surfaceview,把它赋给IMediaPlayer。
/*** 由ijkplayer提供,用于播放视频,需要给他传入一个surfaceView*/private IMediaPlayer mMediaPlayer = null;/*** 视频文件地址*/private String mPath = "";private SurfaceView surfaceView;private VideoPlayerListener listener;private Context mContext;public VideoPlayerIJK(@NonNull Context context) {super(context);initVideoView(context);}public VideoPlayerIJK(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);initVideoView(context);}public VideoPlayerIJK(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {super(context, attrs, defStyleAttr);initVideoView(context);}private void initVideoView(Context context) {mContext = context;//获取焦点,不知道有没有必要~。~setFocusable(true);}/*** 设置视频地址。* 根据是否第一次播放视频,做不同的操作。** @param path the path of the video.*/public void setVideoPath(String path) {if (TextUtils.equals("", mPath)) {//如果是第一次播放视频,那就创建一个新的surfaceViewmPath = path;createSurfaceView();} else {//否则就直接loadmPath = path;load();}}/*** 新建一个surfaceview*/private void createSurfaceView() {//生成一个新的surface viewsurfaceView = new SurfaceView(mContext);surfaceView.getHolder().addCallback(new LmnSurfaceCallback());LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER);surfaceView.setLayoutParams(layoutParams);this.addView(surfaceView);}/*** surfaceView的监听器*/private class LmnSurfaceCallback implements SurfaceHolder.Callback {@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {//surfaceview创建成功后,加载视频load();}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}}/*** 加载视频*/private void load() {//每次都要重新创建IMediaPlayercreatePlayer();try {mMediaPlayer.setDataSource(mPath);} catch (IOException e) {e.printStackTrace();}//给mediaPlayer设置视图mMediaPlayer.setDisplay(surfaceView.getHolder());mMediaPlayer.prepareAsync();}/*** 创建一个新的player*/private void createPlayer() {if (mMediaPlayer != null) {mMediaPlayer.stop();mMediaPlayer.setDisplay(null);mMediaPlayer.release();}IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);//开启硬解码        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);mMediaPlayer = ijkMediaPlayer;if (listener != null) {mMediaPlayer.setOnPreparedListener(listener);mMediaPlayer.setOnInfoListener(listener);mMediaPlayer.setOnSeekCompleteListener(listener);mMediaPlayer.setOnBufferingUpdateListener(listener);mMediaPlayer.setOnErrorListener(listener);}}public void setListener(VideoPlayerListener listener) {this.listener = listener;if (mMediaPlayer != null) {mMediaPlayer.setOnPreparedListener(listener);}}/*** -------======--------- 下面封装了一下控制视频的方法*/public void start() {if (mMediaPlayer != null) {mMediaPlayer.start();}}public void release() {if (mMediaPlayer != null) {mMediaPlayer.reset();mMediaPlayer.release();mMediaPlayer = null;}}public void pause() {if (mMediaPlayer != null) {mMediaPlayer.pause();}}public void stop() {if (mMediaPlayer != null) {mMediaPlayer.stop();}}public void reset() {if (mMediaPlayer != null) {mMediaPlayer.reset();}}public long getDuration() {if (mMediaPlayer != null) {return mMediaPlayer.getDuration();} else {return 0;}}public long getCurrentPosition() {if (mMediaPlayer != null) {return mMediaPlayer.getCurrentPosition();} else {return 0;}}public void seekTo(long l) {if (mMediaPlayer != null) {mMediaPlayer.seekTo(l);}}
}

我们这个控件继承自framelayout。这个控件负责存放一个surfaceView和一个IMediaPlayer 。

3,设置监听器,我自己定义了一个监听器,继承了IMediaPlayer的n个listener。

public abstract class VideoPlayerListener implements IMediaPlayer.OnBufferingUpdateListener, IMediaPlayer.OnCompletionListener, IMediaPlayer.OnPreparedListener, IMediaPlayer.OnInfoListener, IMediaPlayer.OnVideoSizeChangedListener, IMediaPlayer.OnErrorListener, IMediaPlayer.OnSeekCompleteListener {
}

当我们继承这个抽象类的时候,最重要的是在onPrepared()方法中,让视频开始播放:

ijkPlayer.setListener(new VideoPlayerListener() {@Overridepublic void onBufferingUpdate(IMediaPlayer mp, int percent) {}@Overridepublic void onCompletion(IMediaPlayer mp) {}@Overridepublic boolean onError(IMediaPlayer mp, int what, int extra) {return false;}@Overridepublic boolean onInfo(IMediaPlayer mp, int what, int extra) {return false;}@Overridepublic void onPrepared(IMediaPlayer mp) {// 视频准备好播放了,但是他不会自动播放,需要手动让他开始。mp.start();}@Overridepublic void onSeekComplete(IMediaPlayer mp) {}@Overridepublic void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sar_num, int sar_den) {//在此可以获取到视频的宽和高}});
  1. 在xml中放入播放器控件
  2. 在activity中加载so包,设置监听器,设置路径
 //加载native库
try {IjkMediaPlayer.loadLibrariesOnce(null);IjkMediaPlayer.native_profileBegin("libijkplayer.so");} catch (Exception e) {this.finish();}
ijkPlayer.setListener(...)
ijkPlayer.setVideoPath(path);

记得在onStop()方法中关闭native库

IjkMediaPlayer.native_profileEnd();

这样就完成了一个简单的视频播放器了。

注意事项

1,IjkMediaPlayer的setDataSource是不建议重新赋值的,每次更改视频源都需要:player.release() -> create new player -> player.setDataSource。

但是SurfaceView并不需要每次都重新创建。

2,设置倍速播放:IjkMediaPlayer.setSpeed();

3,一些重要的视频信息返回码(这些信息返回码可以从监听器的onInfo()方法中获得):

int MEDIA_INFO_VIDEO_RENDERING_START = 3;//视频准备渲染
int MEDIA_INFO_BUFFERING_START = 701;//开始缓冲
int MEDIA_INFO_BUFFERING_END = 702;//缓冲结束
int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;//视频选择信息
int MEDIA_ERROR_SERVER_DIED = 100;//视频中断,一般是视频源异常或者不支持的视频类型。
int MEDIA_ERROR_IJK_PLAYER = -10000,//一般是视频源有问题或者数据格式不支持,比如音频不是AAC之类的
int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;//数据错误没有有效的回收

参考资料:

在ubuntu下编译ijkplayer-android

视频直播技术(四):使用Ijkplayer播放直播视频

1、Ijkplayer 编码

IjkPlayer支持硬解码和软解码。 软解码时不会旋转视频角度这时需要你通过onInfowhat == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED去获取角度,自己旋转画面。或者开启硬解硬解码,不过硬解码容易造成黑屏无声(硬件兼容问题),下面是设置硬解码相关的代码

mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);

2、Ijkplayer倍速播放

目前IjkPlayer最新版本支持倍速播放(版本号0.7.7.1)。在早期版本对倍速播放支持的不是很好,只有6.0及以上的手机才能进行倍速播放。但是目前虽然所有的机型都支持倍速,但是6.0以下的手机明显有声调变化,这样用户体验不是很好(针对变调的文章会在以后更新)。下面是最新的倍速设置代码:

public void setSpeed(float speed) {_setPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, speed);
}

老版本代码:

@TargetApi(Build.VERSION_CODES.M)public void setSpeed(float speed) {_setPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, speed);}

老版本代码只能设置速度,不能获取,所以基本上不能用(而且机型方面只支持6.0以上的机型)。

3、Ijkplayer的一些重要的视频返回码

int MEDIA_INFO_VIDEO_RENDERING_START = 3;//视频准备渲染
int MEDIA_INFO_BUFFERING_START = 701;//开始缓冲
int MEDIA_INFO_BUFFERING_END = 702;//缓冲结束
int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;//视频选择信息
int MEDIA_ERROR_SERVER_DIED = 100;//视频中断,一般是视频源异常或者不支持的视频类型。
int MEDIA_ERROR_IJK_PLAYER = -10000,//一般是视频源有问题或者数据格式不支持,比如音频不是AAC之类的
int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;//数据错误没有有效的回收

4、Ijkplayer调用seekTo存在的问题

部分视频播放时,调用seekTo的时候,会跳回到拖动前的位置,这是因为视频的关键帧的问题(GOP导致的),视频压缩比较高,而seek只支持关键帧,出现这个情况就是原始的视频文件中i帧比较少,播放器会在拖动的位置找最近的关键帧。所以,目前针对此问题IjkPlayer无解。

5. Ijkplayer音视频不同步问题

在开始使用过程当中对rtmp视频流进行播放,会出现严重的视频音频不同步现象,并且随着播放的时间越长,视频与音频的差距越大。具体原因是CPU在处理视频帧的时候处理得太慢,默认的音视频同步方案是视频同步到音频, 导致了音频播放过快,视频跟不上。

{ "framedrop",                      "drop frames when cpu is too slow",OPTION_OFFSET(framedrop),       OPTION_INT(0, -1, 120) },

framedrop 控制着允许丢帧的范围。可以通过修改 framedrop 的数值来解决不同步的问题,framedrop 是在视频帧处理不过来的时候丢弃一些帧达到同步的效果。具体设置:

player.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 5);

framedrop 的具体大小根据实际情况而定, 一般丢太多帧也不好,会影响用户的观看体验。

6、如何支持https链接播放?

如果你的项目要进行加密播放HLS协议的视频,要想支持https,须要在普通编译的基础上,进行一些配置。

接下来我们来编译openssl

a). init openssl

$ cd .. 进入到ijkplayer的目下
$ ./init-android-openssl.sh 去远程仓库拉取openssl的远程代码,如果是iOS的,这里是init-ios-openssl.h 

b). compile openssl

$ cd android/contrib
$ ./compile-openssl.sh clean
$ ./compile-openssl.sh all

经过以上步骤已经编译好openssl了,然后我们执行一下方法

$./compile-ffmpeg.sh clean
编译ffmpeg软解码库,这个过程会生成各种架构的ffmpeg 这个过程比较耗时
$./compile-ffmpeg.sh all

7、Ijkplayer使用小技巧

a. 下载速度可以通过IjkMediaPlayer的 getTcpSpeed获取。

b. 高分辨率开启硬解码,不支持的话会自动切换到软解,就算开启mediacodec,如果设备不支持,显示的解码器也是avcodec软解。

c. IjkMediaPlayer.setOption可配置的对应头文件参考:ff_ffplay_options。

d. 设置cookie 可以通过ijkPlayer的public void setDataSource(String path, Map<String, String> headers) 的header实现设置,参考ijkPlayer的issues-1150,headers也是在内部被转化为何issuses一样的setOption方法

Android_观看视频卡顿原因及解决办法

在LiveView界面观看视频时,有时会出现画面卡顿的情况,有一种情况可能是只解了I帧的原因。在调用startShow(int avChannel,  boolean clearBuf,

boolean runSoftwareDecode,  boolean isDropFrame)方法时将isDropFrame设置成了true。

解决方法:将isDropFrame设置为false即可。

Android 超好用的播放器ijkplayer相关推荐

  1. Android 超好用的播放器——ijkplayer

    前言 ijkplayer是b站开源的超级好用的视频播放器喔,相信大家都早有耳闻.ijkplayer Android和ios都可用,还支持多种视频的硬解码.人生苦短,不如快点试一试. ijkplayer ...

  2. Android应用开发--MP3音乐播放器滚动歌词实现

    Android应用开发--MP3音乐播放器滚动歌词实现 2013年6月2日  简.美音乐播放器开发记录 -----前话 有网友给我博客评论说,让我借鉴好的Android代码,代码贴出来的时候最好整体先 ...

  3. Android之简单本地音乐播放器

    平台:Android studio APK:http://fir.im/apps/56ea5187e75e2d69af000042 本地的音乐播放器,主要功能就是可以播放音乐,能够读取本地的音乐,并显 ...

  4. 基于Android的MediaPlayer的音乐播放器的封装

    基于Android的MediaPlayer的音乐播放器的封装 使用过android原生的mediaplayer来做音频播放的同学们,肯定是经历过一些痛苦的,因为android提供了一个状态机,确实这个 ...

  5. Android studio怎么实现swf播放器

    使用Android studio 怎么实现swf播放器 比较着急 求

  6. LZH_IJKPlayer-一个最简单使用的视频播放器,集成于bilibili开源直播播放器(ijkplayer)

    随着视频直播APP的迅速发展,许多APP也都会加入直播的功能,提高用户量.在网上也是寻找了许多直播的播放器,无意间发现Bilibili开源了一款播放器ijkplayer,想从最开始的步骤集成的同学可以 ...

  7. 深入DIY,打造超苗条绿色REAL播放器

    转自:   http://hi.baidu.com/cankyo/item/aeb8ed10740996423b176e6d 深入DIY,打造超苗条绿色REAL播放器 自从Real视频编码(RM和RM ...

  8. android 存放音频文件夹里,Android 实现简单的音乐播放器效果(音频文件的三种存放)...

    Android 实现简单的音乐播放器效果(音频文件的三种存放).三种方法主要使用到的类 MediaPlayer.create() getAssets() new Mediaplayer() - 几个控 ...

  9. android使用阿里云推流播放器记录

    android使用阿里云推流播放器记录: 在这里扯一句,如何删除csdn自己上传的资源:(参考:https://blog.csdn.net/qq_38122230/article/details/79 ...

最新文章

  1. [原] Jenkins Android 自动打包配置
  2. 将Linux脚本中的正常输出,警告,错误等信息输出到文件中
  3. 计算勒让德多项式的系数
  4. 监控GoldenGate进程
  5. HTML的map-area的使用
  6. python 外部程序 交互_使用Python与其他程序交互
  7. 会话,授权,认证概念解析
  8. Redis的常见实际应用,不仅仅是缓存(转)
  9. Python XML解析器– ElementTree
  10. window.parent.document jquery
  11. java swing 提示信息,java swing工具提示与不同的消息
  12. 一步一步理解拖拽Drag(一)
  13. 淘宝API开发(一) 简单的用TOPAPI来获取淘宝用户信息
  14. 《网络科学导论》——博弈模型笔记
  15. 休假管理系统的用况详情和用况表
  16. html中zoom方法,css中的zoom的作用
  17. 非线性回归分析及其Matlab实现
  18. 分子动力学模型的发展由来
  19. python3 安装 pip (PyPI)
  20. C/C++编程:libcurl学习(linux + cmake windows10 + vs2019)

热门文章

  1. 有java基础学习大数据该如何规划
  2. 用Python爬取淘宝1000多商品,只想为老父亲做点事
  3. 哈佛大学公开课:计算机科学cs50 学习笔记(第7集:数组,其它)
  4. 用java实现队列(简易)
  5. 解决windows FTP共享、局域网共享文件等解决方案。
  6. C/C++ - 基本数据类型(默认:32位操作系统)
  7. 慕课网前端面试06--js基础-作用域和闭包
  8. 速达软件中建账套时注意事项
  9. SurfaceView使用方法简介-来自网络
  10. 高智能颜值好OKI票据打印机ML6100F热销