从本地读取视频以及播放(3)——学习笔记
来源:互联网 发布:c语言异步调用 编辑:程序博客网 时间:2024/05/16 05:14
首先是如何让其他软件能调起自己写的播放器
可以参照系统源代码
将下面这些代码拷贝到SystemVideoPlayer的Activity配置清单处:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="rtsp" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="video/*" /> <data android:mimeType="application/sdp" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="http" /> <data android:mimeType="video/mp4" /> <data android:mimeType="video/3gp" /> <data android:mimeType="video/3gpp" /> <data android:mimeType="video/3gpp2" /> </intent-filter>
然后点击一个视频文件的时候,系统会传递这个视频文件的地址,这样就可以调用这个播放器了。
接下来判断一下如果有网络视频的话,地址是本地的还是网络的。在Utils.class中添加下面的方法:
public boolean isNetUri(String uri) { boolean reault = false; if (uri != null) { if (uri.toLowerCase().startsWith("http") || uri.toLowerCase().startsWith("rtsp") || uri.toLowerCase().startsWith("mms")) { reault = true; } } return reault; }
然后在下面这些地方添加判断:
private boolean isNetUri; setData(){ if (mediaItems != null && mediaItems.size() > 0){ ... isNetUri = utils.isNetUri(mediaItem.getData()); ... } else if (uri != null){ ... isNetUri = utils.isNetUri(uri.toString()); ... } } private void playPreVideo(){ if(position >= 0){ ... isNetUri = utils.isNetUri(mediaItem.getData()); ... } } private void playNextVideo(){ if (position < mediaItems.size()){ ... isNetUri = utils.isNetUri(mediaItem.getData()); ... } }
接下来如果判断视频来源于网络,就去为视频做缓冲,在每秒发一次消息的handler中添加:
case PROGRESS:... //缓存进度的更新 if (isNetUri) { //只有网络资源才有缓存效果 int buffer = videoview.getBufferPercentage();//0~100 int totalBuffer = buffer * seekbarVideo.getMax(); int secondaryProgress = totalBuffer / 100; seekbarVideo.setSecondaryProgress(secondaryProgress); } else { //本地视频没有缓冲效果 seekbarVideo.setSecondaryProgress(0); }...
这样播放网络视频就可以显示缓冲进度了,接下来去监听网络视频播放是否卡顿。
设置监听播放网络视频卡setOnInfoListener
前提:播放视频的时候,网络比较慢才会出现
1.Android2.3,在MediaPlayer引入的监听卡–自定义VideoView,把监听卡封装一下
2.Android4.2.2左右才把监听卡封装在VideoView中
在setListener()中添加:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { videoview.setOnInfoListener(new MyOnInfoListener()); }
然后准备MyOnInfoListener()之前先去为卡顿设置一下布局,在中添加:
... <include layout="@layout/ll_buffer" android:id="@+id/ll_buffer"/> <include layout="@layout/ll_loading" android:id="@+id/ll_loading"/>
下面是布局详情,先是ll_buffer的:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="#33000000" android:gravity="center" android:orientation="horizontal" android:padding="3dp" android:visibility="gone"> <ProgressBar android:layout_width="30dp" android:layout_height="30dp" /> <TextView android:id="@+id/tv_buffer_netspeed" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="3dp" android:gravity="center" android:text="正在缓冲...30kb/s" android:textColor="#ffffff" android:textSize="10sp" /></LinearLayout>
再是ll_loading的:
<?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:background="@drawable/bg_player_loading_background" android:gravity="center" android:orientation="vertical"> <ProgressBar android:layout_width="30dp" android:layout_height="30dp" /> <TextView android:layout_marginTop="3dp" android:id="@+id/tv_laoding_netspeed" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="3dp" android:gravity="center" android:text="玩命加载中...30kb/s" android:textColor="#ffffff" android:textSize="10sp" /></LinearLayout>
接着将上面布局的控件都实例化,然后是监听MyOnInfoListener():
class MyOnInfoListener implements MediaPlayer.OnInfoListener { @Override public boolean onInfo(MediaPlayer mp, int what, int extra) { switch (what) { case MediaPlayer.MEDIA_INFO_BUFFERING_START://视频卡了,拖动卡 ll_buffer.setVisibility(View.VISIBLE); break; case MediaPlayer.MEDIA_INFO_BUFFERING_END://视频不卡了,拖动卡结束了 ll_buffer.setVisibility(View.GONE); break; } return true; } }
除了使用上面的方法外,还可以自己去校验视频的播放进度来判断是否卡顿,原理就是
当播放进度 -上一次播放进度 < 0 ——>卡顿
不过这个不适用于直播,所以一般结合这种方法和之前的方法使用
然后就去编写代码,首先添加这个判断,判断是否使用系统的监听卡:
private boolean isUseSystem = true;
在setListener中修改:
if (isUseSystem) { //监听视频播放卡-系统的api if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { videoview.setOnInfoListener(new MyOnInfoListener()); } }
校验进度前先添加一个记录上一次播放进度的int数据:
private int preCurrentPosition; //上一次的播放进度
在handler中去校验:
switch (msg.what){...case PROGRESS:... //视频播放的时候去监听 if (!isUseSystem && videoview.isPlaying()) { if(videoview.isPlaying()){ int buffer = currentPosition - preCurrentPosition; if (buffer < 500) { //视频卡了 ll_buffer.setVisibility(View.VISIBLE); } else { //视频不卡了 ll_buffer.setVisibility(View.GONE); } }else{ ll_buffer.setVisibility(View.GONE); } }...}
这样监听视频是否卡顿就完成了,接下来继续完成之前布局的loading效果,也就是加载效果。
首先在onPrepared中去设置让loading隐藏:
...ll_loading.setVisibility(View.GONE); //隐藏加载界面
在playNextVideo和playPreVideo的判断方法中去设置loading显示:
ll_loading.setVisibility(View.VISIBLE);
然后去获取网速并且显示到控件上面,在Utils.class中添加下面这个方法:
private long lastTimeStamp; private long lastTotalRxBytes; /** * 得到网络速度 * 每隔两秒调用一次 * @param context * @return */ public String getNetSpeed(Context context) { String netSpeed = "0 kb/s"; long nowTotalRxBytes = TrafficStats.getUidRxBytes(context.getApplicationInfo().uid)== TrafficStats.UNSUPPORTED ? 0 :(TrafficStats.getTotalRxBytes()/1024);//转为KB; long nowTimeStamp = System.currentTimeMillis(); long speed = ((nowTotalRxBytes - lastTotalRxBytes) * 1000 / (nowTimeStamp - lastTimeStamp));//毫秒转换 lastTimeStamp = nowTimeStamp; lastTotalRxBytes = nowTotalRxBytes; netSpeed = String.valueOf(speed) + " kb/s"; return netSpeed; }
接下来在SystemVideoPlayer中添加
private static final int SHOW_SPEED = 3;//显示网速
然后在handler中判断:
case SHOW_SPEED: //显示网速 String netSpeed = utils.getNetSpeed(SystemVideoPlayer.this);//得到网速 //在控件上显示网速 tv_laoding_netspeed.setText("玩命加载中..." + netSpeed); tv_buffer_netspeed.setText("正在缓冲..." + netSpeed); removeMessages(SHOW_SPEED); sendEmptyMessageDelayed(SHOW_SPEED, 2000); //每两秒更新一次 break;
在findViews()中去发送消息:
... //开始更新网络速度 handler.sendEmptyMessage(SHOW_SPEED);
有的时候,系统播放器遇到有些视频无法播放,解决办法就是在项目中去集成vitamio万能播放器
由于官网打不开,所以在github上面去下载
地址是https://github.com/yixia/VitamioBundle.git
下载完成后,导入vitamio库并且关联,然后复制一份SystemVideoPlayer,粘贴为VitamioVideoPlayer;将MyVedioView复制粘贴一份为VitamioVideoView,同时将VitamioVideoPlayer和VitamioVideoView中的MediaPlayer,VideoView的包都换成Vitamio的,并且里面的实例也要替换掉。同时SystemVideoPlayer的布局文件也复制一份,粘贴为activity_vitmiao_video_player.xml,将VitamioVideoPlayer的布局文件替换掉,并且布局文件中的一些控件也替换为Vitamio的控件。
别忘记给VitamioVideoPlayer在功能清单中注册活动。
接下来将下面这些权限添加到功能清单文件中:
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
然后下面这些代码也添加进去:
<!-- Don't forgot InitActivity --> <activity android:name="io.vov.vitamio.activity.InitActivity" android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation" android:launchMode="singleTop" android:theme="@android:style/Theme.NoTitleBar" android:windowSoftInputMode="stateAlwaysHidden" />
还需要在布局文件加载之前初始化Vitamio库,在VitamioVideoPlayer的findViews()方法的第一行添加:
Vitamio.isInitialized(this);
接着在SystemVideoPlayer的MyOnErrorListener监听里面添加startVitamioPlayer();
private void startVitamioPlayer() { if(videoview != null){ videoview.stopPlayback(); } Intent intent = new Intent(this,VitamioVideoPlayer.class); if(mediaItems != null && mediaItems.size() > 0){ Bundle bundle = new Bundle(); bundle.putSerializable("videolist", mediaItems); intent.putExtras(bundle); intent.putExtra("position", position); }else if(uri != null){ intent.setData(uri); } startActivity(intent); finish();//关闭页面 }
系统播放器出错的时候就去跳转到万能播放器,同时在VitamioVideoPlayer中的MyOnErrorListener监听里面添加showErrorDialog();
private void showErrorDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("提示"); builder.setMessage("抱歉,无法播放该视频!!"); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); builder.show(); }
由于有些视频也能播放但是没有画面,只有声音,这时候是不会调用万能播放器的,接下来去设置手动切换万能播放器。
在SystemVideoPlayer中的按钮btnSwichPlayer点击事件中添加showSwichPlayerDialog();
private void showSwichPlayerDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("系统播放器提醒您"); builder.setMessage("当您播放视频,有声音没有画面的时候,请切换万能播放器播放"); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startVitamioPlayer(); } }); builder.setNegativeButton("取消",null); builder.show(); }
同时也在VitamioVideoPlayer的btnSwichPlayer点击事件中添加showSwichPlayerDialog();
private void showSwichPlayerDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("万能播放器提醒您"); builder.setMessage("当您播放一个视频,有花屏的时候,可以尝试使用系统播放器播放"); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startSystemPlayer(); } }); builder.setNegativeButton("取消",null); builder.show(); }
然后就可以手动切换了,不过每次切换播放器的时候会有动画效果,接下来去除这个动画效果可以在values的styles.xml中添加
<style name="noAnimation_Theme" parent="android:Theme"> <item name="android:windowAnimationStyle">@style/noAnimation</item> <item name="android:windowNoTitle">true</item> <item name="android:windowFullscreen">true</item> <item name="android:windowContentOverlay">@null</item> </style> <style name="noAnimation"> <item name="android:activityOpenEnterAnimation">@null</item> <item name="android:activityOpenExitAnimation">@null</item> <item name="android:activityCloseEnterAnimation">@null</item> <item name="android:activityCloseExitAnimation">@null</item> <item name="android:taskOpenEnterAnimation">@null</item> <item name="android:taskOpenExitAnimation">@null</item> <item name="android:taskCloseEnterAnimation">@null</item> <item name="android:taskCloseExitAnimation">@null</item> <item name="android:taskToFrontEnterAnimation">@null</item> <item name="android:taskToFrontExitAnimation">@null</item> <item name="android:taskToBackEnterAnimation">@null</item> <item name="android:taskToBackExitAnimation">@null</item> </style>
之后在功能清单文件中的SystemVideoPlayer活动和VitamioVideoPlayer活动中添加
android:theme="@style/noAnimation_Theme"
- 从本地读取视频以及播放——学习笔记
- 从本地读取视频以及播放(3)——学习笔记
- 从本地读取视频以及播放(2)——学习笔记
- OpenCV 3学习笔记(四)读取并播放视频
- OpenCV-002:从本地摄像头读取视频并播放
- OpenCV学习笔记(3)——进度条视频播放控制
- OpenCV学习笔记(3)——进度条视频播放控制
- opencv学习笔记—播放AVI视频(下)
- python opencv入门(学习笔记no.3)-从摄像头读取视频并显示
- 从数据库读取二进制流视频保存到本地并播放
- Android:本地视频播放器开发 — 搜索本地视频(1)
- Android:本地视频播放器开发 — 搜索本地视频(2)
- vitamio全屏切换播放视频 以及响应本地视频播放
- OpenCV学习笔记(2)——播放视频
- Android——视频播放器学习笔记
- OpenCV学习笔记(2)——播放视频
- FFmpeg+SDL视频播放器—图形界面版学习笔记
- OpenCV学习笔记【3】:视频播放控制
- 求最长回文串
- java 如何获得线程池中正在执行的线程数
- Leetcode
- IOS蓝牙4.0(BLE)开发一基本概念
- gdb 调试
- 从本地读取视频以及播放(3)——学习笔记
- codeforces883I,二分+单调性 思想是dp的思想
- ThinkPHP5微信支付扩展库(超级简单, 超级超好用!)
- FCN和U-Net
- Codeforces 887C
- Ubuntu16.04下mysql基本命令|ubuntu16.04重启apache服务命令
- c++调试信息输出
- GUI学习笔记
- win8,win10简捷快速重装系统