1. 程式人生 > >手機影音第十一天,顯示視頻緩沖,顯示卡頓時的網速,播放系統視頻時調用播放器的選擇

手機影音第十一天,顯示視頻緩沖,顯示卡頓時的網速,播放系統視頻時調用播放器的選擇

顯示視頻緩沖 顯示卡頓時的網速 播放系統視頻時調用播放器的選擇

代碼已經托管到碼雲,有興趣的小夥伴可以下載看看

https://git.oschina.net/joy_yuan/MobilePlayer

一、設置視頻緩沖進度

顯示視頻播放進度的效果圖如下:灰色的是緩沖的進度。

技術分享



原理:只有播放網絡視頻時,才有緩沖這個說法,所以要先判斷視頻資源是否為網絡資源

/**
 * 判斷是否是網絡的資源
 * @param uri
 * @return
 */
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;
}

因此在前面,不管是單個的URI還是通過list傳來的mediaitem數組,都要根據地址來去判斷,然後在handler裏去設置進度條。

進度條很簡單,只需要設置seekbarVideo.setSecondaryProgress(int progress);即可達到設置進度。那麽這個緩沖值怎麽獲取的呢,這個是一個統一的寫法,沒有什麽原因,如下代碼:

//網絡資源緩沖
if (isNetUri){
    //只有網絡資源有緩沖
    int bufferPercentage = videoview.getBufferPercentage();  //0~100
    int totalbuffer = bufferPercentage * seekbarVideo.getMax();
    int secordProgress=totalbuffer/100;
    seekbarVideo.setSecondaryProgress(secordProgress);
}else{
    //本地進度條沒有緩沖,即第二條進度條為灰色
    seekbarVideo.setSecondaryProgress(0);
}

二、使播放本地視頻時,可以跳出來選擇自定義播放器的方法。
    當我們手機裏裝了多個播放器後,如果要播放本地視頻,系統會跳出來一個選擇框,讓用戶選擇播放哪個視頻
    這裏用到裏隱式意圖,只要給SystemVideoPlayer這個activity在AndroidManifext.xml裏配置隱式意圖即可:
    <activity
    android:name=".activity.SystemVideoPlayer"

    android:configChanges="keyboardHidden|screenSize|orientation"

    android:screenOrientation="landscape"
   >

    <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>

    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data
            android:mimeType="video/*"
            android:scheme="http" />
        <data
            android:mimeType="video/*"
            android:scheme="rtsp" />
        <data
            android:mimeType="video/*"
            android:scheme="rtmp" />
        <data
            android:mimeType="video/*"
            android:scheme="udp" />
        <data
            android:mimeType="video/*"
            android:scheme="tcp" />
        <data
            android:mimeType="video/*"
            android:scheme="file" />
        <data
            android:mimeType="video/*"
            android:scheme="content" />
        <data
            android:mimeType="video/*"
            android:scheme="mms" />
        <data android:mimeType="application/octet-stream" />
        <data android:mimeType="application/x-mpegurl" />
        <data android:mimeType="application/vnd.apple.mpegurl" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />

        <data android:scheme="content" />
    </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:mimeType="application/x-mpegurl"
            android:scheme="http" />
    </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="rtsp" />
        <data android:scheme="rtmp" />
        <data android:scheme="mms" />
        <data android:scheme="tcp" />
        <data android:scheme="udp" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <action android:name="android.intent.action.SEND" />
        <action android:name="android.intent.action.SENDTO" />

        <category android:name="android.intent.category.DEFAULT" />

        <data android:mimeType="video/*" />
        <data android:mimeType="application/sdp" />
        <data android:mimeType="application/octet-stream" />
    </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/*" />
    </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="file" />
        <data android:scheme="content" />
        <data android:scheme="http" />
        <data android:scheme="https" />
        <data android:scheme="ftp" />
        <data android:scheme="rtsp" />
        <data android:scheme="rtmp" />
        <data android:scheme="mms" />
        <data android:scheme="tcp" />
        <data android:scheme="udp" />
        <data android:scheme="gopher" />
        <data android:mimeType="video/*" />
        <!-- <data android:mimeType="audio/*" /> -->
    </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="file" />
        <data android:scheme="content" />
        <data android:scheme="http" />
        <data android:scheme="https" />
        <data android:scheme="ftp" />
        <data android:scheme="rtsp" />
        <data android:scheme="rtmp" />
        <data android:scheme="mms" />
        <data android:scheme="tcp" />
        <data android:scheme="udp" />
        <data android:scheme="gopher" />
        <data android:host="*" />
        <data android:pathPattern=".*\\.avi" />
        <data android:pathPattern=".*\\.asf" />
        <data android:pathPattern=".*\\.f4v" />
        <data android:pathPattern=".*\\.flv" />
        <data android:pathPattern=".*\\.mkv" />
        <data android:pathPattern=".*\\.mpeg" />
        <data android:pathPattern=".*\\.mpg" />
        <data android:pathPattern=".*\\.mov" />
        <data android:pathPattern=".*\\.rm" />
        <data android:pathPattern=".*\\.vob" />
        <data android:pathPattern=".*\\.wmv" />
        <data android:pathPattern=".*\\.ts" />
        <data android:pathPattern=".*\\.tp" />
        <data android:pathPattern=".*\\.m3u" />
        <data android:pathPattern=".*\\.m3u8" />
        <data android:pathPattern=".*\\.m4v" />
        <data android:pathPattern=".*\\.mp4" />
    </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="rtsp" />
        <data android:mimeType="video/*" />
    </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="rtsp" />
    </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/*" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="video/*" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="file" />
        <data android:mimeType="video/*" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEARCH" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>

</activity>



三、監聽視頻播放卡頓時,彈出一個progressbar並提示用戶當前網速

在這裏就要寫一個布局,與視頻播放布局在同一個布局,同樣是include進來

在system_video_player.xml裏加入

<include layout="@layout/buffering" android:id="@+id/buffering"/>

3.1 buffering.xml

<?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:orientation="horizontal"
              android:gravity="center"
              android:visibility="gone"
              android:padding="3dp"
              android:layout_centerInParent="true"
              android:background="#33000000">
    <ProgressBar

        android:layout_width="30dp"
        android:layout_height="30dp"/>

    <TextView
        android:gravity="center"

        android:id="@+id/tv_netspeed"
        android:text="緩沖中...30kb/s"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

3.2 視頻卡頓時,在Android4.2.2後,系統集成進到了videoview裏了,作為一個監聽,那麽我們只要實現了這個監聽就可以在裏面獲取卡頓時與不卡頓時的回調方法:

//監聽網絡播放卡頓現象
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    videoview.setOnInfoListener(new MyOnInfoListener());
}


/**
 * 視頻播放卡頓時的監聽,Android4.2.2後封裝到了videoview裏了已經
 */
public class MyOnInfoListener implements MediaPlayer.OnInfoListener

{
    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {
        switch (what){
            case MediaPlayer.MEDIA_INFO_BUFFERING_START: //開始卡頓
                //顯示卡頓的布局
                buffering.setVisibility(View.VISIBLE);
                break;
            case MediaPlayer.MEDIA_INFO_BUFFERING_END:  //結束卡頓
                buffering.setVisibility(View.GONE);
                break;
        }
        return true;
    }
}

這時候,只要是卡頓了,那麽就會彈出一個progressbar在視頻中央


3.3 在上面的這個,是系統集成好的判斷是否卡頓的方法,那麽我們也可以自定義判斷視頻是否卡頓,

原理是:在handler每一秒循環的消息體中,去判斷當前視頻進度和上一次循環消息時的視頻進度相減,如果進度小魚500ms,那麽就判斷是卡頓了,否則就不卡。

if (videoview.isPlaying()){
    int buffer=currentPosition-preCurrentPosition;
    if (buffer<500){
        //視頻卡了
        buffering.setVisibility(View.VISIBLE);
    }else{
        buffering.setVisibility(View.GONE);
    }

}else{
    buffering.setVisibility(View.GONE);
}

preCurrentPosition=currentPosition;

上面的代碼也能判斷視頻卡頓時,顯示progressbar。



四、視頻播放前的loading布局與獲取系統的網速

原理:寫一個布局,與視頻播放頁面system_video_player.xml在一個布局裏,寬高都是match_parent即覆蓋整個屏幕。這樣當點擊播放視頻時,會先顯示這個布局,然後我們再在視頻準備好播放時,讓這個布局消失,即可達到效果

4.1 system_video_player.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
                android:gravity="center"
                android:background="#000000"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <com.yuanlp.mobileplayer.view.MyVideoView
        android:layout_centerInParent="true"
        android:id="@+id/videoview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <!-- loading 視頻卡播放頁面的各種控制按鈕頁面布局-->
    <include layout="@layout/media_controller" android:id="@+id/media_controller"/>
    <!-- loading 視頻卡頓時的頁面布局-->
    <include layout="@layout/buffering" android:id="@+id/buffering"/>
<!-- loading 頁面布局-->
    <include layout="@layout/ll_loading" android:id="@+id/ll_loading"/>
</RelativeLayout>

4.2 在systemVideoPlayer.java裏

public void onPrepared(MediaPlayer mp) {
    videoview.start(); //開始播放
    duration = videoview.getDuration();  //獲取視頻總時長
    seekbarVideo.setMax(duration);   //設置播放進度的最大值

    //發送消息,來更新視頻進度
    handler.sendEmptyMessage(PROGRESS);

    //設置顯示的視頻總時長
    tvDuration.setText(utils.stringForTime(duration));

    //默認進入播放時,隱藏
    media_controller.setVisibility(View.GONE);
    isShow=false;  //設置為隱藏

    //獲取播放器播放視頻的寬度和高度
    videoHeight=mp.getVideoHeight();
    videoWidth=mp.getVideoWidth();
   // videoview.setVideoSize(mp.getVideoWidth(),mp.getVideoHeight());

    setVideoType(DEFAULTSCREEN);

    //當準備好播放時,把loading頁面消失掉
    ll_loading.setVisibility(View.GONE);

}


4.2 獲取網速

原理是:每次handler2秒循環一次獲取網速消息,在2秒內,獲取的數據量/時間,即可得到網速。

具體代碼如下:

/**
 * 得到網絡速度
 * 每隔兩秒調用一次
 * @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";
    Log.d(TAG, "當前總的數據"+nowTotalRxBytes);
    return  netSpeed;
}

這裏要在loading布局聲明好時,就立刻發消息,去handler處理,來獲取網速,以便loading界面也出現網速顯示。

//加載布局時的布局與網速顯示
ll_loading= (LinearLayout) findViewById(R.id.ll_loading);
tv_loading_netspeed= (TextView) findViewById(R.id.tv_loading_netspeed);

handler.sendEmptyMessage(SPEED);  //控件只要一聲明好就發消息去獲取網速


發完聲明後,就在handler裏去處理消息,獲取網速,然後在loading和卡頓時,顯示網速,不卡頓時,隱藏對應的布局

public Handler handler=new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case SPEED:  //顯示當前網速
                //得到網速
                String netSpeed = utils.getNetSpeed(SystemVideoPlayer.this);
                System.out.println("當前網速"+netSpeed);
                //顯示網速
                tv_loading_netspeed.setText("玩命加載中"+netSpeed);  //loading時的速度顯示
                tv_netspeed.setText("緩沖中"+netSpeed);  //緩沖時的速度顯示
                removeMessages(SPEED);
                handler.sendEmptyMessageDelayed(SPEED,2000);  //一定要隔2秒才能去獲取網速
                break;
                
         }
         
    };


本文出自 “YuanGuShi” 博客,請務必保留此出處http://cm0425.blog.51cto.com/10819451/1950630

手機影音第十一天,顯示視頻緩沖,顯示卡頓時的網速,播放系統視頻時調用播放器的選擇