项目地址
https://github.com/979451341/Myijkplayer

前段时候我觉得FFmpeg做个视频播放器好难,虽然播放上没问题,但暂停还有通过拖动进度条来设置播放进度,这些都即便做得到,可以那个延缓。。。。。

现在学习一下目前移动端最知名的视频播放器的框架ijkplayer,这个框架他是基于FFmpeg、SDL、还有安卓原生API MediaCodec之类的。他是没有播放界面的,这个需要我们去做,所以这个里我就做个基于ijkplayer的视频播放器,随便浅显的说一下ijkplayer的源码,关于ijkplayer的源码以后会专门出一篇博客说一下。

1.首先了解一下ijkplayer咋用

我这里引入ijkplayer是通过添加依赖

implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'implementation 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'implementation 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'

然后说说ijkplayer是如何播放视频的

ijkplayer每一次播放视频都是通过创建Mediaplayer,然后赋值到一个接口类上,这里他创建的时候能够挑选解码的类型,是因为基于安卓原生API MediaCodec的话是硬解,速度快、兼容差,如果是基于FFmpeg则是软解,速度慢、兼容好,不过这个兼容问题,因为我们在引入依赖的时候把各个处理器相应的依赖,所以可以使用硬解,兼容问题基本都是手机处理器不同产生的。

    IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);

// //开启硬解码
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
IMediaPlayer mMediaPlayer = null;
mMediaPlayer = ijkMediaPlayer;

关于IjkMediaPlayer的源码我只贴出一个函数的,从下面几个loadLibrary看出来,他还是基于FFmpeg、SDL底层实现的。

public static void loadLibrariesOnce(IjkLibLoader libLoader) {Class var1 = IjkMediaPlayer.class;synchronized(IjkMediaPlayer.class) {if(!mIsLibLoaded) {if(libLoader == null) {libLoader = sLocalLibLoader;}libLoader.loadLibrary("ijkffmpeg");libLoader.loadLibrary("ijksdl");libLoader.loadLibrary("ijkplayer");mIsLibLoaded = true;}}
}

好了,回到那个接口类的IMediaPlayer,源码不多贴出来看一下,通过这些接口函数我们都可以知道这个ijkplayer如何使用我们都有了一个底,什么setDataSource、setDisplay,设置播放源、设置播放的屏幕信息。还有start、stop、pause,视频播放的开始、停止、暂停,还有一大堆的接口,这些都是为了监听播放器的状态

public interface IMediaPlayer {
。。。。。。

void setDisplay(SurfaceHolder var1);void setDataSource(Context var1, Uri var2) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;@TargetApi(14)
void setDataSource(Context var1, Uri var2, Map<String, String> var3) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;void setDataSource(FileDescriptor var1) throws IOException, IllegalArgumentException, IllegalStateException;void setDataSource(String var1) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;String getDataSource();void prepareAsync() throws IllegalStateException;void start() throws IllegalStateException;void stop() throws IllegalStateException;void pause() throws IllegalStateException;void setScreenOnWhilePlaying(boolean var1);int getVideoWidth();int getVideoHeight();boolean isPlaying();void seekTo(long var1) throws IllegalStateException;long getCurrentPosition();long getDuration();void release();void reset();void setVolume(float var1, float var2);int getAudioSessionId();MediaInfo getMediaInfo();/** @deprecated */
@Deprecated
void setLogEnabled(boolean var1);/** @deprecated */
@Deprecated
boolean isPlayable();void setOnPreparedListener(IMediaPlayer.OnPreparedListener var1);void setOnCompletionListener(IMediaPlayer.OnCompletionListener var1);void setOnBufferingUpdateListener(IMediaPlayer.OnBufferingUpdateListener var1);void setOnSeekCompleteListener(IMediaPlayer.OnSeekCompleteListener var1);void setOnVideoSizeChangedListener(IMediaPlayer.OnVideoSizeChangedListener var1);void setOnErrorListener(IMediaPlayer.OnErrorListener var1);void setOnInfoListener(IMediaPlayer.OnInfoListener var1);void setOnTimedTextListener(IMediaPlayer.OnTimedTextListener var1);void setAudioStreamType(int var1);/** @deprecated */
@Deprecated
void setKeepInBackground(boolean var1);int getVideoSarNum();int getVideoSarDen();/** @deprecated */
@Deprecated
void setWakeMode(Context var1, int var2);void setLooping(boolean var1);boolean isLooping();ITrackInfo[] getTrackInfo();void setSurface(Surface var1);void setDataSource(IMediaDataSource var1);public interface OnTimedTextListener {void onTimedText(IMediaPlayer var1, IjkTimedText var2);
}public interface OnInfoListener {boolean onInfo(IMediaPlayer var1, int var2, int var3);
}public interface OnErrorListener {boolean onError(IMediaPlayer var1, int var2, int var3);
}public interface OnVideoSizeChangedListener {void onVideoSizeChanged(IMediaPlayer var1, int var2, int var3, int var4, int var5);
}public interface OnSeekCompleteListener {void onSeekComplete(IMediaPlayer var1);
}public interface OnBufferingUpdateListener {void onBufferingUpdate(IMediaPlayer var1, int var2);
}public interface OnCompletionListener {void onCompletion(IMediaPlayer var1);
}public interface OnPreparedListener {void onPrepared(IMediaPlayer var1);
}

}

2.写界面

全屏播放,潜入式

//正真的全屏,隐藏了状态栏、AtionBar、导航栏
@Override
public void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);if (hasFocus && Build.VERSION.SDK_INT >= 19) {View decorView = getWindow().getDecorView();decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION| View.SYSTEM_UI_FLAG_FULLSCREEN| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);}
}

然后上下两个栏目,负责一些播放器的控制,顶部负责设置返回、设置按钮,底部需要设置播放/暂停按钮、播放进度条、停止按钮

<com.example.zth.two.VideoPlayerIJKandroid:id="@+id/ijk_player"android:layout_width="match_parent"android:layout_height="match_parent"/><includeandroid:id="@+id/include_play_top"layout="@layout/include_play_top"android:layout_alignParentTop="true"android:layout_width="match_parent"android:layout_height="50dp" /><includeandroid:id="@+id/include_play_bottom"layout="@layout/include_play_bottom"android:layout_alignParentBottom="true"android:layout_width="match_parent"android:layout_height="50dp" />

关于上下两个栏目在用户观看视频时需要隐藏,在用户点击屏幕则显示两个栏目,供用户使用
这个则是需要通过计时器来完成记录目前距离上一次用户点击屏幕的时间,如果视频超过3秒,则隐藏栏目,如果点击屏幕则恢复,关于隐藏和恢复使用Animation来完成。

    timer = new Timer();timerTask = new TimerTask() {@Overridepublic void run() {long t = System.currentTimeMillis();if (t - time > 3000 && menu_visible) {time = t;handler.post(new Runnable() {@Overridepublic void run() {Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.move_bottom);rl_bottom.startAnimation(animation);Animation animation_top = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.move_top);rl_top.startAnimation(animation_top);menu_visible = false;}});}}};

还需要加载框,这个在视频加载完的接口回调里隐藏他

    <ProgressBarandroid:id="@+id/pb_loading"android:layout_width="60dp"android:layout_height="60dp"android:layout_centerInParent="true"android:layout_marginTop="60dp"android:indeterminate="false"android:indeterminateDrawable="@drawable/video_loading"android:padding="5dp" />

3.播放实现

这里我是使用了一个另一个博主封装的ijkplayer的类

说一下这个类的运行过程

一开始创建MediaPlayer做一些配置,赋值给一个接口类,并且暴露了接口

    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);}

然后设置播放源,这个播放源能够是本地视频路径、网络视频url、还可以是网络RTMP推流url,还要讲SurfaceView的配置信息给他

    try {mMediaPlayer.setDataSource(mPath);} catch (IOException e) {e.printStackTrace();}//给mediaPlayer设置视图mMediaPlayer.setDisplay(surfaceView.getHolder());mMediaPlayer.prepareAsync();

想开始播放就调用IMediaPlayer的那些控制函数

public void start() {if (mMediaPlayer != null) {mMediaPlayer.start();}
}

还有关于activity的生命周期控制,其中native_profileEnd就相当于很智能的暂停,当屏幕回的时候就继续播放视频。

@Override
protected void onStop() {IjkMediaPlayer.native_profileEnd();handler.removeCallbacksAndMessages(null);super.onStop();}

结束Activity的时候就停止播放视频并释放资源

@Override
protected void onDestroy() {if (ijkPlayer != null) {ijkPlayer.stop();ijkPlayer.release();ijkPlayer = null;}super.onDestroy();
}

最后还有播放进度,我这里是通过handler自己调用自己循环更新播放时间显示和进度条

    handler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_REFRESH:if (ijkPlayer.isPlaying()) {refresh();handler.sendEmptyMessageDelayed(MSG_REFRESH, 1000);}break;}}};private void refresh() {long current = ijkPlayer.getCurrentPosition() / 1000;long duration = ijkPlayer.getDuration() / 1000;Log.v("zzw", current + " " + duration);long current_second = current % 60;long current_minute = current / 60;long total_second = duration % 60;long total_minute = duration / 60;String time = current_minute + ":" + current_second + "/" + total_minute + ":" + total_second;tvTime.setText(time);if(duration != 0){seekBar.setProgress((int) (current * 100 / duration));}}

在用户拖动进度条的时候取消handler发送消息,拖动结束再接续更新播放进度

    seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int i, boolean b) {//进度改变}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {//开始拖动handler.removeCallbacksAndMessages(null);}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {//停止拖动ijkPlayer.seekTo(ijkPlayer.getDuration() * seekBar.getProgress() / 100);handler.sendEmptyMessageDelayed(MSG_REFRESH, 100);}});

关于播放网络视频和网络RTMP推流,播放本身没问题就是不能获取视频时长和视频当前时间,不过暂停和停止还有效。

还有就是如果想要重新播放需要重新setVideoPath然后start

看看效果
本地视频播放

播放RTMP推流

播放网络视频

ijkplayer的使用看起来是不是很简单,但是还没有实现小窗口和全屏之间的切换。。。。。。这两天我再看看ijkplayer,再和各位说说
博客首发地址
http://blog.csdn.net/z979451341

转载于:https://blog.51cto.com/13591594/2084627

Android 音视频深入 十九 使用ijkplayer做个视频播放器(附源码下载)相关推荐

  1. android flv 编码器,Android 音视频深入 十七 FFmpeg 获取 RTMP 流保存为 flv (附源码下载)...

    Android 音视频深入 十七 FFmpeg 获取 RTMP 流保存为 flv (附源码下载) 项目地址 https://github.com/979451341/RtmpSave 这个项目主要代码 ...

  2. Android 音视频深入 一 AudioRecord录音生成pcm转换为wav(附源码下载)

    本篇项目地址,求star https://github.com/979451341/Audio-and-video-learning-materials/tree/master/AudioRecord ...

  3. Android音视频学习系列(九) — Android端实现rtmp推流

    系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...

  4. html实现视频网站,仿爱奇艺,搜狐,迅雷看看(附源码)

    文章目录 1.功能模板 1.1 仿爱奇艺 1.2 仿搜狐视频 1.3 仿迅雷看看 1.4 视频播放 1.5 影视公司官网 2.效果和源码 2.1 源代码 2.2 模板目录 源码下载 作者:xcLeig ...

  5. java实现高德地图app,Android 高德地图入门demo,最新高德地图实现方法,附源码及apk...

    [实例简介] Android 高德地图入门demo,最新高德地图实现方法,附源码及apk [实例截图] [核心代码] GaoDeDemo ├── GaoDeDemo │   ├── app │   │ ...

  6. android音视频【十】音频mp3剪切

    人间观察 为了等你,我错过了等我的人. 介绍 Android中在一些短视频的制作app软件上,会有给视频增加背景音乐的功能,而背景音乐/歌曲(一般是mp3)是从服务器上下载后,然后本地解码,往往用户会 ...

  7. 疯狂python讲义视频 百度云-疯狂Python讲义 PDF高清版附源码

    内容简介 本书全面,深入地介绍了Python编程的相关内容,大致可分为四个部分.*系统部分介绍了Python的基本语法结构,函数编程,类和对象,模块和包,异常处理等: 第二部分主要介绍Python常用 ...

  8. Android 利用广播实现黑名单【指定号码】的短信的拦截 附源码下载链接

    Android 利用广播实现指定号码的短信的拦截 根据最近的学习内容,今天实现了利用广播进行指定号码的拦截 步骤: ①.写一个数据库的帮助类,实现对数据库的创建,总共创建两个数据库psms(受保护的短 ...

  9. Android 统一打包框架(附源码下载)

    唠叨: 把手给我,我带你去吃云浮吃石磨肠粉.云吞面,木瓜渣. 那里的肠粉和广州的不一样,皮很薄很滑,肉馅没广州的那么花里胡哨,只有肉碎和香葱.但吃起来就很香滑,再配上它的甜辣酱.那味道好极了. 云吞面 ...

  10. Android可滑动画板,Android实现画板、写字板功能(附源码下载)

    前言 本文给大家分享一个使用Android开发写字板功能Dem.简单操作内存中的图像.对图像进行简单的处理.绘制直线.以达到写字板的效果 效果图如下 XML布局代码 xmlns:tools=" ...

最新文章

  1. nrf52840开发套件_nRF52840蓝牙5.0模块有几个突出的优势
  2. 服务器mvc提示404错误信息,解决Spring MVC提示404错误找不到JSP问题
  3. mysql 5.6.11 error 1059_mysql5.6.15问题如何解决
  4. 45.JVM调优策略、常见问题:内存泄漏(年老代堆空间被占满、持久代被占满、堆栈溢出、线程堆栈满、系统内存被占满)优化方法:优化目标、优化GC步骤、优化总结;案例分析(公司系统参数、网上给的配置参数)
  5. linux得到当前系统时间,在LINUX下用C++编程,怎么获取系统当前的时间。
  6. linux phpunit 安装,在CentOS 7/CentOS 8系统中安装PHPUnit的方法
  7. Unix EM乱码问题
  8. android 数据持久化——读写SD卡中的内容
  9. c语言递归函数奇偶归一猜想,计算机科学视角下的奇偶归一猜想
  10. Android 模拟机键盘不可用的问题 !!
  11. python arp_在python上发出ARP请求
  12. MD(d)、MT(d)编译选项的区别
  13. oracle 表 队列,如何将复制队列表移出系统(SYSTEM)表空间
  14. 实用新型专利撰写模板(自己总结)
  15. linux安装音乐软件教程,Ubuntu 下安装深度音乐播放器
  16. bom_clear.php,金蝶KIS专业版常用SQL语句
  17. 如何求矩阵的特征值和特征向量
  18. October cms-Plugins(插件-注册)
  19. 邂逅你,是我最美的相遇
  20. UIImagePicketView(照相机类)的使用

热门文章

  1. [BZOJ2048] [2009国家集训队] 书堆
  2. STL之map容器的详解
  3. ApiDemos示例学习(1)——ApiDemos示例的导入
  4. sicily 1282. Computer Game
  5. Floyd算法 C++实现
  6. ORB-SLAM2-建立双目稠密点云(一)
  7. window.innerHeight和document.documentElement.clientHeight区别
  8. HashMap源码详解与对比
  9. L2与L1正则化理解
  10. centos 7 redis-4.0.11 主从