編輯:Android開發實例
本文是在 Android使用MediaPlayer實現視頻預加載實例 基礎上做更進一步的優化,適應更多終端的MediaPlayer,不再唠叨預加載的作用和基礎,有興趣的讀者請看上回。
MediaPlayer由廠家定制,不同終端的MediaPlayer略有差異,例如:有些MediaPlayer首次播放從頭buffer,有些MdiaPlayer首次播放會多次Request,Range到網絡媒體文件的頭部、中間和文件尾,再從指定位置buffer...本文所做的優化就是適應播放前多次Request的MediaPlayer。
決定預加載效果好壞由三因素決定:
碼率低、網速快的情況沒必要使用預加載,碼率中等、網速一般的情況合適使用。另外,緩沖文件也不能設置太大:過大的緩沖區會刷爆MediaPlayer內置的緩沖區,影響正常播放;再者,讀取緩沖文件也耗時。
先看看本文程序的運行結果,以下是不使用預加載的運行LOG:
08-27 10:34:55.222: E//mnt/sdcard/ProxyBuffer/files(12949): --------共有0個緩存文件
08-27 10:34:55.327: E/MediaPlayer(12949): MediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:34:55.327: E/(12949): IMediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:34:55.367: E/MediaPlayer(12949): MediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:34:55.367: E/(12949): IMediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:35:01.152: E/MediaPlayer(12949): MediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:35:01.152: E/(12949): IMediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:35:01.402: E/MediaPlayer(12949): MediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:35:01.402: E/(12949): IMediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:35:02.382: E/testVideoPlayer(12949): 預加載開關:false,等待緩沖時間:8000,首次緩沖時間:7152
以下是使用預加載的運行LOG,內容有點多,這個MediaPlayer就是首次播放前多次Request:
08-27 10:40:02.627: E//mnt/sdcard/ProxyBuffer/files(13769): --------共有0個緩存文件
08-27 10:40:02.777: E/testVideoPlayer(13769): 預加載文件:/mnt/sdcard/ProxyBuffer/files/videorzx201208151345010952759.mp4
08-27 10:40:02.972: E/DownloadThread(13769): /mnt/sdcard/ProxyBuffer/files/videorzx201208151345010952759.mp4
08-27 10:40:10.782: E/MediaPlayer(13769): MediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:40:10.782: E/(13769): IMediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:40:10.787: E/HttpGetProxy(13769): ------------------------------------------------------------------
08-27 10:40:10.787: E/HttpGetProxy(13769): java.lang.NullPointerException
08-27 10:40:10.787: E/HttpGetProxy(13769): com.proxy.HttpGetProxy.startProxy 171line
08-27 10:40:10.787: E/HttpGetProxy(13769): com.proxy.HttpGetProxy.access$0 134line
08-27 10:40:10.787: E/HttpGetProxy(13769): com.proxy.HttpGetProxy$1.run 129line
08-27 10:40:10.787: E/HttpGetProxy(13769): ------------------------------------------------------------------
08-27 10:40:10.792: E/HttpParser(13769): GET /video/rzx/201208/15/1345010952759.mp4 HTTP/1.1
08-27 10:40:10.792: E/HttpParser(13769): Range: bytes=0-
08-27 10:40:10.792: E/HttpParser(13769): Host: video.cztv.com
08-27 10:40:10.792: E/HttpParser(13769): Accept: */*
08-27 10:40:10.792: E/HttpParser(13769): Pragma: no-cache
08-27 10:40:10.792: E/HttpParser(13769):
08-27 10:40:10.792: E/HttpParser(13769): _prebufferFilePath:/mnt/sdcard/ProxyBuffer/files/videorzx201208151345010952759.mp4
08-27 10:40:10.792: E/HttpParser(13769): ------->rangePosition:0
08-27 10:40:10.792: E/HttpGetProxy(13769): prebuffer size:999296
08-27 10:40:10.797: E/DownloadThread(13769): mTotalSize:8311866,mTargetSize:3145728
08-27 10:40:11.762: E/HttpGetProxy<---(13769): HTTP/1.1 206 Partial Content
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Date: Mon, 27 Aug 2012 02:33:24 GMT
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Server: Apache
08-27 10:40:11.762: E/HttpGetProxy<---(13769): X-Mod-H264-Streaming: version=2.2.7
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Last-Modified: Wed, 15 Aug 2012 06:24:38 GMT
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Accept-Ranges: bytes
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Cache-Control: max-age=315360000
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Expires: Thu, 25 Aug 2022 02:33:24 GMT
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Content-Type: video/mp4
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Powered-By-ChinaCache: HIT from 01006613Y4
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Content-Range: bytes 0-8311865/8311866
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Content-Length: 8311866
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Age: 407
08-27 10:40:11.762: E/HttpGetProxy<---(13769): Powered-By-ChinaCache: HIT from 01075913r4
08-27 10:40:11.762: E/HttpGetProxy<---(13769):
08-27 10:40:11.777: E/HttpGetProxy(13769): .........over..........
08-27 10:40:11.777: E/HttpGetProxy(13769): ------------------------------------------------------------------
08-27 10:40:11.782: E/HttpParser(13769): GET /video/rzx/201208/15/1345010952759.mp4 HTTP/1.1
08-27 10:40:11.782: E/HttpParser(13769): Range: bytes=101901-
08-27 10:40:11.782: E/HttpParser(13769): Host: video.cztv.com
08-27 10:40:11.782: E/HttpParser(13769): Accept: */*
08-27 10:40:11.782: E/HttpParser(13769): Pragma: no-cache
08-27 10:40:11.782: E/HttpParser(13769):
08-27 10:40:11.782: E/HttpParser(13769): _prebufferFilePath:/mnt/sdcard/ProxyBuffer/files/videorzx201208151345010952759.mp4
08-27 10:40:11.782: E/HttpParser(13769): ------->rangePosition:101901
08-27 10:40:11.782: E/HttpGetProxy(13769): prebuffer size:1000320
08-27 10:40:12.167: E/HttpGetProxy<---(13769): HTTP/1.1 206 Partial Content
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Date: Mon, 27 Aug 2012 02:33:24 GMT
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Server: Apache
08-27 10:40:12.167: E/HttpGetProxy<---(13769): X-Mod-H264-Streaming: version=2.2.7
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Last-Modified: Wed, 15 Aug 2012 06:24:38 GMT
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Accept-Ranges: bytes
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Cache-Control: max-age=315360000
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Expires: Thu, 25 Aug 2022 02:33:24 GMT
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Content-Type: video/mp4
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Powered-By-ChinaCache: HIT from 01006613Y4
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Content-Range: bytes 101901-8311865/8311866
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Content-Length: 8209965
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Age: 408
08-27 10:40:12.167: E/HttpGetProxy<---(13769): Powered-By-ChinaCache: HIT from 01075913r4
08-27 10:40:12.167: E/HttpGetProxy<---(13769):
08-27 10:40:12.172: E/HttpGetProxy(13769): >>>skip:101901
08-27 10:40:12.182: E/HttpGetProxy(13769): .........over..........
08-27 10:40:12.182: E/HttpGetProxy(13769): ------------------------------------------------------------------
08-27 10:40:12.187: E/HttpParser(13769): GET /video/rzx/201208/15/1345010952759.mp4 HTTP/1.1
08-27 10:40:12.187: E/HttpParser(13769): Range: bytes=74-
08-27 10:40:12.187: E/HttpParser(13769): Host: video.cztv.com
08-27 10:40:12.187: E/HttpParser(13769): Accept: */*
08-27 10:40:12.187: E/HttpParser(13769): Pragma: no-cache
08-27 10:40:12.187: E/HttpParser(13769):
08-27 10:40:12.187: E/HttpParser(13769): _prebufferFilePath:/mnt/sdcard/ProxyBuffer/files/videorzx201208151345010952759.mp4
08-27 10:40:12.187: E/HttpParser(13769): ------->rangePosition:74
08-27 10:40:12.187: E/HttpGetProxy(13769): prebuffer size:1000320
08-27 10:40:12.372: E/HttpGetProxy<---(13769): HTTP/1.1 206 Partial Content
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Date: Mon, 27 Aug 2012 02:33:24 GMT
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Server: Apache
08-27 10:40:12.372: E/HttpGetProxy<---(13769): X-Mod-H264-Streaming: version=2.2.7
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Last-Modified: Wed, 15 Aug 2012 06:24:38 GMT
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Accept-Ranges: bytes
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Cache-Control: max-age=315360000
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Expires: Thu, 25 Aug 2022 02:33:24 GMT
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Content-Type: video/mp4
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Powered-By-ChinaCache: HIT from 01006613Y4
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Content-Range: bytes 74-8311865/8311866
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Content-Length: 8311792
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Age: 408
08-27 10:40:12.372: E/HttpGetProxy<---(13769): Powered-By-ChinaCache: HIT from 01075913r4
08-27 10:40:12.372: E/HttpGetProxy<---(13769):
08-27 10:40:12.377: E/HttpGetProxy(13769): >>>skip:74
08-27 10:40:12.397: E/MediaPlayer(13769): MediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:40:12.397: E/(13769): IMediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:40:12.537: E/HttpGetProxy(13769): >>>讀取預加載耗時:164
08-27 10:40:12.537: E/HttpGetProxy(13769): >>>讀取完畢...下載:1000320,讀取:1000246
08-27 10:40:12.537: E/HttpGetProxy-pre->(13769): GET /video/rzx/201208/15/1345010952759.mp4 HTTP/1.1
08-27 10:40:12.537: E/HttpGetProxy-pre->(13769): Range: bytes=1000320-
08-27 10:40:12.537: E/HttpGetProxy-pre->(13769): Host: video.cztv.com
08-27 10:40:12.537: E/HttpGetProxy-pre->(13769): Accept: */*
08-27 10:40:12.537: E/HttpGetProxy-pre->(13769): Pragma: no-cache
08-27 10:40:12.537: E/HttpGetProxy-pre->(13769):
08-27 10:40:12.647: E/MediaPlayer(13769): MediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:40:12.647: E/(13769): IMediaPlayer::setVideoRect(0,25, 1280, 720)
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): HTTP/1.1 206 Partial Content
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Date: Mon, 27 Aug 2012 02:33:24 GMT
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Server: Apache
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): X-Mod-H264-Streaming: version=2.2.7
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Last-Modified: Wed, 15 Aug 2012 06:24:38 GMT
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Accept-Ranges: bytes
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Cache-Control: max-age=315360000
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Expires: Thu, 25 Aug 2022 02:33:24 GMT
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Content-Type: video/mp4
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Powered-By-ChinaCache: HIT from 01006613Y4
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Content-Range: bytes 1000320-8311865/8311866
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Content-Length: 7311546
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Age: 409
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769): Powered-By-ChinaCache: HIT from 01075913r4
08-27 10:40:12.962: E/HttpGetProxy ~~~~(13769):
08-27 10:40:14.037: E/testVideoPlayer(13769): 預加載開關:true,等待緩沖時間:8000,首次緩沖時間:3261
本文的源碼可以到這裡下載:http://download.csdn.net/detail/hellogv/4528270
HttpGetProxy.java源碼如下,可以讀出大概的運行流程:
- public class HttpGetProxy{
- final static public int SIZE = (int) (3 * 1024 * 1024);
- final static public String TAG = "HttpGetProxy";
- /** 鏈接帶的端口 */
- private int remotePort=-1;
- /** 遠程服務器地址 */
- private String remoteHost;
- /** 代理服務器使用的端口 */
- private int localPort;
- /** 本地服務器地址 */
- private String localHost;
- private ServerSocket localServer = null;
- /** 收發Media Player請求的Socket */
- private Socket sckPlayer = null;
- /** 收發Media Server請求的Socket */
- private Socket sckServer = null;
- /**服務器的Address*/
- private SocketAddress serverAddress;
- /**下載線程*/
- private DownloadThread download = null;
- /**
- * 初始化代理服務器
- * @param localport 代理服務器監聽的端口
- */
- public HttpGetProxy(int localport) {
- try {
- localPort = localport;
- localHost = C.LOCAL_IP_ADDRESS;
- localServer = new ServerSocket(localport, 1,InetAddress.getByName(localHost));
- } catch (Exception e) {
- System.exit(0);
- }
- }
- /**
- * 把URL提前下載在SD卡,實現預加載
- * @param urlString
- * @return 返回預加載文件名
- * @throws Exception
- */
- public String prebuffer(String urlString,int size) throws Exception{
- if(download!=null && download.isDownloading())
- download.stopThread(true);
- URI tmpURI=new URI(urlString);
- String fileName=Utils.urlToFileName(tmpURI.getPath());
- String filePath=C.getBufferDir()+"/"+fileName;
- download=new DownloadThread(urlString,filePath,size);
- download.startThread();
- return filePath;
- }
- /**
- * 把網絡URL轉為本地URL,127.0.0.1替換網絡域名
- *
- * @param url網絡URL
- * @return [0]:重定向後MP4真正URL,[1]:本地URL
- */
- public String[] getLocalURL(String urlString) {
- // ----排除HTTP特殊----//
- String targetUrl = Utils.getRedirectUrl(urlString);
- // ----獲取對應本地代理服務器的鏈接----//
- String localUrl = null;
- URI originalURI = URI.create(targetUrl);
- remoteHost = originalURI.getHost();
- if (originalURI.getPort() != -1) {// URL帶Port
- serverAddress = new InetSocketAddress(remoteHost, originalURI.getPort());// 使用默認端口
- remotePort = originalURI.getPort();// 保存端口,中轉時替換
- localUrl = targetUrl.replace(
- remoteHost + ":" + originalURI.getPort(), localHost + ":"
- + localPort);
- } else {// URL不帶Port
- serverAddress = new InetSocketAddress(remoteHost, C.HTTP_PORT);// 使用80端口
- remotePort = -1;
- localUrl = targetUrl.replace(remoteHost, localHost + ":"
- + localPort);
- }
- String[] result= new String[]{targetUrl,localUrl};
- return result;
- }
- /**
- * 異步啟動代理服務器
- *
- * @throws IOException
- */
- public void asynStartProxy() {
- new Thread() {
- public void run() {
- startProxy();
- }
- }.start();
- }
- private void startProxy() {
- HttpParser httpParser =null;
- HttpGetProxyUtils utils=null;
- int bytes_read;
- byte[] local_request = new byte[1024];
- byte[] remote_reply = new byte[1024];
- while (true) {
- boolean sentResponseHeader = false;
- try {// 開始新的request之前關閉過去的Socket
- if (sckPlayer != null)
- sckPlayer.close();
- if (sckServer != null)
- sckServer.close();
- } catch (IOException e1) {}
- try {
- // --------------------------------------
- // 監聽MediaPlayer的請求,MediaPlayer->代理服務器
- // --------------------------------------
- sckPlayer = localServer.accept();
- Log.e(TAG,"------------------------------------------------------------------");
- if(download!=null && download.isDownloading())
- download.stopThread(false);
- httpParser=new HttpParser(remoteHost,remotePort,localHost,localPort);
- utils = new HttpGetProxyUtils(sckPlayer,sckServer,serverAddress);
- ProxyRequest request = null;
- while ((bytes_read = sckPlayer.getInputStream().read(local_request)) != -1) {
- byte[] buffer=httpParser.getRequestBody(local_request,bytes_read);
- if(buffer!=null){
- request=httpParser.getProxyRequest(buffer);
- break;
- }
- }
- boolean isExists=new File(request._prebufferFilePath).exists();
- if(isExists)
- Log.e(TAG,"prebuffer size:"+download.getDownloadedSize());
- sckServer = utils.sentToServer(request._body);
- // ------------------------------------------------------
- // 把網絡服務器的反饋發到MediaPlayer,網絡服務器->代理服務器->MediaPlayer
- // ------------------------------------------------------
- while ((bytes_read = sckServer.getInputStream().read(remote_reply)) != -1) {
- if(sentResponseHeader){
- try{//拖動進度條時,容易在此異常,斷開重連
- utils.sendToMP(remote_reply,bytes_read);
- }catch (Exception e) {
- break;//發送異常直接退出while
- }
- continue;//退出本次while
- }
- List<byte[]> httpResponse = httpParser.getResponseBody(remote_reply, bytes_read);
- if (httpResponse.size() == 0)
- continue;//沒Header則退出本次循環
- sentResponseHeader = true;
- String responseStr = new String(httpResponse.get(0));
- Log.e(TAG + "<---", responseStr);
- //send http header to mediaplayer
- utils.sendToMP(httpResponse.get(0));
- if (isExists) {//需要發送預加載到MediaPlayer
- isExists = false;
- int sentBufferSize = 0;
- try{
- sentBufferSize = utils.sendPrebufferToMP(
- request._prebufferFilePath,
- request._rangePosition);
- }catch(Exception ex){
- break;
- }
- if (sentBufferSize > 0) {// 成功發送預加載,重新發送請求到服務器
- int newRange=(int) (sentBufferSize + request._rangePosition);
- String newRequestStr = httpParser.modifyRequestRange(request._body,newRange);
- Log.e(TAG + "-pre->", newRequestStr);
- //修改Range後的Request發送給服務器
- sckServer = utils.sentToServer(newRequestStr);
- //把服務器的Response的Header去掉
- utils.removeResponseHeader(httpParser);
- continue;
- }
- }
- // 發送剩余數據
- if (httpResponse.size() == 2) {
- utils.sendToMP(httpResponse.get(1));
- }
- }
- Log.e(TAG, ".........over..........");
- // 關閉 2個SOCKET
- sckPlayer.close();
- sckServer.close();
- } catch (Exception e) {
- Log.e(TAG,e.toString());
- Log.e(TAG,Utils.getExceptionMessage(e));
- }
- }
- }
本文著重講解如何使用MaskFilter創建模糊陰影以及浮雕效果。 我們知道Canvas中的各種
本文實例講述了使用SAX來解析XML。通常來說在Android裡面可以使用SAX和DOM,DOM需要把整個XML文件讀入內存再解析,比較消耗內存,而SAX是基於事
不知道大家是否用過天天動聽,對於它界面上的半透明Menu效果,筆者感覺非常漂亮
可以顯示在的Android任務,通過加載進度條的進展。進度條有兩種形狀。加載欄和加載微調(spinner)。在本章中,我們將討論微調(spinner)。Spinner 用