点播/直播/VR视频播放器研究(2)-Android

来源:互联网 发布:我的淘宝卖家旺旺号 编辑:程序博客网 时间:2024/05/18 03:21

 点播+直播+VR:ijkPlayer+MD360 (推荐);ijkPlayer可以实现点播和直播,MD360 可以实现VR视频播放。

> MD360+ijkplayer 的GitHub源代码:
MD360 VR- https://github.com/ashqal/MD360Player4Android
GiraffePlayer- https://github.com/tcking/GiraffePlayer (作者不再维护)
GiraffePlayer2- https://github.com/tcking/GiraffePlayer2

jjdxm_ijkplayer借鉴了GiraffePlayer项目的IJKPlayer- https://github.com/jjdxmashl/jjdxm_ijkplayer

ijkplayer版本更新日志- https://github.com/Bilibili/ijkplayer/blob/k0.8.4/NEWS.md

MD360 VR 版本更新日志- https://github.com/ashqal/MD360Player4Android/wiki/Changelog

MD360Player4Android Q/A- https://github.com/ashqal/MD360Player4Android/wiki/Q&A

  ijkplayer 是一个基于 ffplay 的开源视频播放器核心 https://github.com/bbcallen/ijkplayer,已经切换到bilibili , ijkplayer 目前在 iOS 平台各方面表现较佳,Android 方面仍存在一些问题。


B站开源的弹幕引擎DanmakuFlameMaster:https://github.com/Bilibili/DanmakuFlameMaster
移动视频播放框架ijkplayer:https://github.com/Bilibili/ijkplayer, 
html5视频转码内核flv.js:https://github.com/Bilibili/flv.js


> 注意:如果App添加防止反编译文件配置的话,一定得添加 如下代码(有待进一步优化)
#ijkplayer vrlib,不要去混淆这里面的代码,否则会找不到一些类和SO包
-keep class com.asha.vrlib.** { *; }
-keep class tv.danmaku.ijk.media.player.** { *; }

tcking.github.com.giraffeplayer.GiraffePlayer 普通视频的View显示与隐藏都在这边显示,

所有的错误码都在ijkplayer-java/tv.danmaku.ijk.media.player/IMediaPlayer接口文件下,

VR中,设置横竖屏切换监听,可以切屏,OrientationEventListener.

------------------------------------------------

 VR问题

> Ijkplayer+VR使用研究

android 基于ijkplayer项目进行的播放器- http://blog.csdn.net/u014608640/article/details/52607577
Android,ijkplayer增加https协议支持,编译运行ijkplayer- http://www.jianshu.com/p/8403ddc48de1
IJKPlayer编译so支持HTTPS的踩坑历程- http://www.jianshu.com/p/bd289e25d272

音频开发ijkplayer小结 android- http://blog.csdn.net/nothingl3/article/details/51204966

Android MediaPlayer使用方法简单介绍(setdatasource)- http://blog.csdn.net/u013366022/article/details/26448911
ijkplayer阅读学习笔记之从代码上看播放流程- http://blog.csdn.net/i_do_can/article/details/51374732


> windows下用cygwin编译android版ijkplayer(windows下编译so一直有坑,没搞定)
Windows下编译android版ijkplayer- http://blog.csdn.net/King1425/article/details/70331868
ijkplayer在windows下编译并导入Android Studio- http://blog.csdn.net/u010072711/article/details/51354834
windows下用cygwin编译android版ijkplayer- http://blog.csdn.net/ytzys/article/details/47302123

> Linux下编译android版ijkplayer,使用VMware安装的Ubuntu 16.04(转向VM 的Linux下编译so)
关于编译ijkplayer下的so经验分享- http://blog.csdn.net/ht_android/article/details/51859698
VMware安装Ubuntu教程,Linux下搭建Android开发环境- http://blog.csdn.net/linchaolong/article/details/52802401
Android 关于编译ijkplayer下的so经验分享- http://www.cnblogs.com/zhujiabin/p/7207669.html


> 改变裁剪eyes的大小

 com.asha.vrlib.MDVRLibrary
protected MDVRLibrary createVRLibrary() {
        return MDVRLibrary.with(this)
                .displayMode(MDVRLibrary.DISPLAY_MODE_NORMAL)
                .interactiveMode(MDVRLibrary.INTERACTIVE_MODE_MOTION)
                .asVideo(new MDVRLibrary.IOnSurfaceReadyCallback() {
                    @Override
                    public void onSurfaceReady(Surface surface) {
                        mMediaPlayerWrapper.setSurface(surface);
                    }
                })
                .ifNotSupport(new MDVRLibrary.INotSupportCallback() {
                    @Override
                    public void onNotSupport(int mode) {
                        String tip = mode == MDVRLibrary.INTERACTIVE_MODE_MOTION
                                ? "onNotSupport:MOTION" : "onNotSupport:" + String.valueOf(mode);
                        Toast.makeText(PlayerActivity.this, tip, Toast.LENGTH_SHORT).show();
                    }
                })
                .pinchConfig(new MDPinchConfig().setMin(1.0f).setMax(8.0f).setDefaultValue(0.1f))
                .pinchEnabled(true)
                .directorFactory(new MD360DirectorFactory() {
                    @Override
                    public MD360Director createDirector(int index) {
                        return MD360Director.builder().setPitch(90).build();
                    }
                })
                .projectionFactory(new CustomProjectionFactory())
                .barrelDistortionConfig(new BarrelDistortionConfig().setDefaultEnabled(false).setScale(0.95f))//TODO 这里可以裁剪屏幕setScale(0.95f),设置所占屏幕的百分比
                .build(findViewById(R.id.gl_view));

    }


> 陀螺仪和重力感应

mVRLibrary.onPause(PlayerActivity.this);//暂停视频 ,mMediaPlayerWrapper.pause();//VR 视频在可见的范围是不动的,不会感应重力和陀螺仪

mVRLibrary.onResume(PlayerActivity.this);//VR 视频在可见的范围内可以适应重力感应和陀螺仪 ,mMediaPlayerWrapper.resume();//播放器能够开始播放

  -- java.lang.NullPointerException: Attempt to invoke virtual method 'boolean com.asha.vrlib.texture.MD360Texture.texture(com.asha.vrlib.MD360Program)' on a null object reference at com.asha.vrlib.plugins.MDPanoramaPlugin.renderer(MDPanoramaPlugin.java:80).不Pause的话,opengl一直在render

解决方案:mVRLibrary设置mVRLibrary.onPause()方法,恢复陀螺仪和重力感应mVRLibrary.onResume()


> 改变VR图像显示与左右眼偏离值

在 OpenGL中,摄像机离人的远近。近的话(sNear越大0.9),图像是放大的,可能会越模糊;远的话,图像是缩小的;改变左右眼偏离值。

com.asha.vrlib.MD360Director
private static final float sNear = 0.5f;//TODO 0.7 0.9 0.5
 改变VR OpenGL中,左右眼的偏离值-2.0f
MD360Director.builder().setLookX(-2.0f)//TODO
                       .setEyeX(-2.0f)//TODO
                       .setPitch(90)

                       .build();

//手指可以滑动VR视频画面
mVRLibrary.switchInteractiveMode(MD360PlayerActivity.this, 2);
private static final SparseArray<String> sInteractiveMode = new SparseArray<>();
static {
  sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_TOUCH,"TOUCH");
}

---------------------------------------------------

  IJKPlayer问题

> ijkplayer 问题
Error (-10000,0)
ijkplayer tv.danmaku.ijk.media.player.IMediaPlayer -> error_code
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;//数据错误没有有效的回收

使用ijkplayer播放视频一些问题解- http://www.cnblogs.com/renhui/p/6420140.html
IjkMediaPlayer: Error (-10000,0),原来 ijkPlayer默认不支持 https 协议的视频,播放器内部错误或视频源问题或网络不好

> ijkplayer视频缓存问题
  视频缓存因该是下载,储存流,但是下载在提交到App Store是需要版权的,想要做成缓存,我有了解过,也询问过IJKPlayer作者,得到肯定答复是客户端都不支持流缓存的协议。

Android 实现视屏播放器、边播边缓存功能、外加铲屎(IJKPlayer)- http://www.jianshu.com/p/9fe377dd9750

https://github.com/CarGuo/GSYVideoPlayer , https://github.com/danikula/AndroidVideoCache


 IJKPlayer拖动播放进度会导致重新请求数据,未使用已经缓冲好的数据,所以应该尽量控制缓冲区大小,减少不必要的数据损失。
  1.mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", 100 * 1024);//设置缓冲区为100KB,目前我看来,多缓冲了4秒
  2.mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", 100);// 视频的话,设置100帧即开始播放
  3.mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "reconnect", 1);//重连模式,如果中途服务器断开了连接,
让它重新连接,参考 https://github.com/Bilibili/ijkplayer/issues/445,解决播放一段时间后出错

  4.ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);因为缓存协议不支持在移动设备,你说会做一个补丁来制定一个文件进行存储
  5.ijk我印象里是用于流播放的,能用来做边下边播么- https://github.com/Bilibili/ijkplayer/issues/2479#issuecomment-268945110
New feature suggestion #2375- https://github.com/Bilibili/ijkplayer/issues/2375
  6.FFmpeg3.3 视频缓存- https://www.ffmpeg.org/ffmpeg-protocols.html#cache
  What you said has been implemented in cache in ffmpeg except specifying the storage location and I will improve it (may be next release) to ffmpeg.
  HOW TO DO
 1.add cache prefix in your video video url. http://xxx.yyy.zzz/1.flv => cache:http://xxx.yyy.zzz/1.flv
 2.pass transferred url to ijkplayer
 3.using option to specify the storage location to ijkplayer (NOT IMPLEMENTED YET)

  -- 直播技术总结(三)ijkplayer的一些问题优化记录- http://blog.csdn.net/hejjunlin/article/details/57075026http://blog.csdn.net/hejjunlin/article/details/57075026
  在做音频播放的时候,使用的是开源的ijkplayer播放器,ijkplayer解码使用的是ffmpeg,声音输出使用的是audiotrack,在某机型上面播放遇到锁屏、返回后台、点击home键的时候会出现声音卡顿的现象

-- 对于播放器来说,音视频同步是一个关键点,同时也是一个难点,同步效果的好坏,直接决定着播放器的质量。通常音视频同步的解决方案就是选择一个参考时钟(主 clock),播放时读取音视频帧上的时间戳,同时参考当前时钟参考时钟(主 clock)上的时间来安排播放。
  1.如果音视频帧的播放时间大于当前参考时钟上的时间,则不急于播放该帧,直到参考时钟达到该帧的时间戳;
  2.如果音视频帧的时间戳小于当前参考时钟上的时间,则需要“尽快”播放该帧或丢弃,以便播放进度追上参考时钟。
-- 参考时钟的选择也有多种方式:
 1.选取视频时间戳作为参考时钟源;
 2.选取音频时间戳作为参考时钟源;
 3.选取外部时间作为参考时钟源;
考虑人对视频、和音频的敏感度,在存在音频的情况下,优先选择音频作为主时钟源。

-------------------------------------------------

> 滚动ListView/RecyclerView 列表中实现视频的自动播放
新版的百度贴吧,网易新闻中有看视频的界面。
Android在滚动列表中实现视频的播放(ListView &amp; RecyclerView)- https://github.com/danylovolokh/VideoPlayerManager
https://github.com/hongyang51/VideoPlayerManager

滚动列表自动播放视频(引用了JiaoZiVideoPlayer)- https://github.com/zzzlw/autovideoplayer
节操播放器JiaoZiVideoPlayer- https://github.com/lipangit/JiaoZiVideoPlayer
节操播放器有使用MediaPlayer和使用ijkPlayer核心包:
compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.4'
compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'

仿网易新闻嵌套视频,小屏,全屏播放-http://download.csdn.net/download/zqs62761130/8910069

----------------------------------------------------

> IjkPlayer加滤镜

让IjkPlayer支持插入自定义的GPU滤镜- http://blog.csdn.net/junzia/article/details/75172160

ijkplayer 播放rtmp等实时性要求很高的流媒体时候,会出现10S左右的延迟,原因是因为加了缓冲区处理,可以把其缓存设置变小,达到实时的效果:
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);  
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);  
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);  
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 8);  
ijkMediaPlayer.setOption(1, "analyzemaxduration", 100L);  
ijkMediaPlayer.setOption(1, "probesize", 10240L);  
ijkMediaPlayer.setOption(1, "flush_packets", 1L);  
ijkMediaPlayer.setOption(4, "packet-buffering", 0L);  
ijkMediaPlayer.setOption(4, "framedrop", 1L);



IJKMEDIA: SDL_JNI_DetachThreadEnv
ijkplayer如何断掉握手 Android ?
ijkplayer如何释放连接  Android ?
/*
 * Do not change these values without updating their counterparts in native
 */
int MEDIA_INFO_UNKNOWN = 1;//未知信息
int MEDIA_INFO_STARTED_AS_NEXT = 2;//播放下一条
int MEDIA_INFO_VIDEO_RENDERING_START = 3;//视频开始整备中
int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;//视频日志跟踪
int MEDIA_INFO_BUFFERING_START = 701;//开始缓冲中
int MEDIA_INFO_BUFFERING_END = 702;//缓冲结束
int MEDIA_INFO_NETWORK_BANDWIDTH = 703;//网络带宽,网速方面
int MEDIA_INFO_BAD_INTERLEAVING = 800;//
int MEDIA_INFO_NOT_SEEKABLE = 801;//不可设置播放位置,直播方面
int MEDIA_INFO_METADATA_UPDATE = 802;//
int MEDIA_INFO_TIMED_TEXT_ERROR = 900;
int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901;//不支持字幕
int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;//字幕超时

int MEDIA_INFO_VIDEO_INTERRUPT= -10000;//数据连接中断
int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;//视频方向改变
int MEDIA_INFO_AUDIO_RENDERING_START = 10002;//音频开始整备中

int MEDIA_ERROR_UNKNOWN = 1;//未知错误
int MEDIA_ERROR_SERVER_DIED = 100;//服务挂掉
int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;//数据错误没有有效的回收
int MEDIA_ERROR_IO = -1004;//IO 错误
int MEDIA_ERROR_MALFORMED = -1007;
int MEDIA_ERROR_UNSUPPORTED = -1010;//数据不支持
int MEDIA_ERROR_TIMED_OUT = -110;//数据超时


> ijkPlayer中的错误码:

MD360Player4Android Q/A- https://github.com/ashqal/MD360Player4Android/wiki/Q&A
Error (-10000,0)
ijkplayer tv.danmaku.ijk.media.player.IMediaPlayer -> error_code
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;//数据错误没有有效的回收

-----------------------------------------------------------------

>视频倍速播放和弹幕
Vitamio和VLC.最后我选择了Vitamio,因为这个的资料多一些。朋友们也可以去github看看VLC怎么做。这里提醒一下,使用Vitamio需要到官网去下载最新的5.2版本。因为github的4.0版本bug太多,而且不支持64位架构的处理器。还不支持android6.0.直接来看看我怎么做的吧

  gpu运算,假如一个视频的默认帧率为60帧每秒,当我们在播放时采用120帧每秒的帧速率。那么我们看到的视频就以原来的2倍速度播放。声音也是如此。硬件是有运算极限的,当速率过大时,如果没有设置帧同步的情况下,硬件会忽略一些帧,如果设置了帧同步,那么硬件可能无法达到我们所设置的速率。
  另外一种通过cpu来控制,视频是有一定长度的,那么自然我们能通过控制时间线来控制播放速度,这样gpu只需要知道要绘制哪一帧就行了,但是这给cpu带来了承重的负担,他需要不断的读取文件,而且形成的画面也不再是连续的,通常这种方法是不可取的。

Android 自定义View修炼-自定义弹幕效果View- https://www.cnblogs.com/JczmDeveloper/p/4872460.html https://github.com/Bilibili/DanmakuFlameMaster
弹幕实现原理方案:
 1、自定义ViewGroup-XCDanmuView,继承RelativeLayout来实现,当然也可以继承其他三大布局类哈;
 2、初始化若干个TextView(弹幕的item View,这里以TextView 为例,当然也可以其他了~),然后通过addView添加到自定义View中;
 3、通过addView添加到XCDanmuView中,位置在坐标,为了实现 从屏幕外移动进来的效果;我们还需要修改添加进来TextView的位置,以从右向左移动方向来说,addView后必须将该TextView的位置设置到右边的屏幕外;这样我们采用的方法,是在onLayout()方法中对childView进行layout重新布局设置位置;
 4、随机冲左侧或右侧出来弹幕itemView,移动采用属性动画来实现平移,从屏幕的一端移动到另一端,当动画结束后,就将该child从XCDanmuView中remove掉。并重新new 一个弹幕itemView ,并addView到XCDanmuView中,并开始动画移动;
 5、本自定义弹幕View支持从左到右和从右到左两个方向,支持自定义设置屏幕弹幕最多显示个数。

> 音频焦点
Android音频焦点详解(上)- http://blog.csdn.net/wangjihuanghun/article/details/54957459
Android音频焦点详解(下)源码详解-  http://blog.csdn.net/wangjihuanghun/article/details/56069283
Android AudioManager处理两个播放器同时有声音- http://blog.csdn.net/shuaicike/article/details/39930823

> Ijkplayer倍速变调
视频直播技术(五):使用Ijkplayer倍速变调问题解决方案- https://www.cnblogs.com/renhui/p/6510872.html
https://github.com/Bilibili/ijkplayer/issues/2785  https://github.com/Bilibili/ijkplayer/issues/2930
 mMediaPlayer.setPlaybackSpeed(1.0f);