Android-接收UDP TS流实现边缓存边播放

Android播放本地文件视频是硬解,这样对CPU占用比较少,所以将直播收到的数据临时缓存3个文件,给定每个文件的大小,然后进行播放。后续还会进行优化。

具体实现代码如下:

[java]  view plain  copy
  1. package com.cayden.videodemo;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.net.DatagramPacket;  
  7. import java.net.DatagramSocket;  
  8.   
  9.   
  10. import android.app.Activity;  
  11. import android.app.ProgressDialog;  
  12. import android.content.Intent;  
  13. import android.media.MediaPlayer;  
  14. import android.media.MediaPlayer.OnCompletionListener;  
  15. import android.media.MediaPlayer.OnErrorListener;  
  16. import android.media.MediaPlayer.OnPreparedListener;  
  17. import android.os.Bundle;  
  18. import android.os.Environment;  
  19. import android.os.Handler;  
  20. import android.os.Message;  
  21. import android.util.Log;  
  22. import android.view.View;  
  23. import android.widget.MediaController;  
  24. import android.widget.TextView;  
  25. import android.widget.VideoView;  
  26. import com.cayden.videodemo.R;  
  27. /** 
  28.  *  
  29.  *  接收UDP TS流实现边缓存边播放<br/> 
  30.  * 该类可以实现,但存在以下不足<br/> 
  31.  * 1、播放过程会稍微卡一下这是 由于播放时候setOnCompletionListener中方法被执行<br/> 
  32.  * 2、需要思考怎么解决调用onError方法 
  33.  * @author cuiran 
  34.  * @version 1.0.0 
  35.  */  
  36. public class UDPFileMPlayer extends Activity {  
  37.   
  38.     private static final String TAG="UDPFileMPlayer";  
  39.     private VideoView mVideoView;  
  40.     private TextView tvcache;  
  41.     private String remoteUrl;  
  42.     private String localUrl;  
  43.     private ProgressDialog progressDialog = null;  
  44.     private Thread receiveThread=null;  
  45.     /** 
  46.      * 定义了初始缓存区的大小,当视频加载到初始缓存区满的时候,播放器开始播放, 
  47.      */  
  48.     private static final int READY_BUFF = 1316 * 1024*10;  
  49.       
  50.     private static final String FILE_DIR=Environment.getExternalStorageDirectory().getAbsolutePath()+"/VideoCache/";  
  51.               
  52.     /** 
  53.      * 核心交换缓存区,主要是用来动态调节缓存区,当网络环境较好的时候,该缓存区为初始大小, 
  54.      * 当网络环境差的时候,该缓存区会动态增加,主要就是为了避免视频播放的时候出现一卡一卡的现象。 
  55.      */  
  56.     private static final int CACHE_BUFF = 10 * 1024;  
  57.     /** 
  58.      * 单播或组播端口 
  59.      */  
  60.     private static final int PORT = 1234;  
  61.       
  62.     private boolean isready = false;  
  63.     private boolean iserror = false;  
  64.     private int errorCnt = 0;  
  65.     private int curPosition = 0;  
  66.     private long mediaLength = 0;  
  67.     private long readSize = 0;  
  68.   
  69.     @Override  
  70.     protected void onCreate(Bundle savedInstanceState) {  
  71.         super.onCreate(savedInstanceState);  
  72.         setContentView(R.layout.bbvideoplayer);  
  73.   
  74.         findViews();  
  75.         init();  
  76.         playvideo();  
  77.     }  
  78.     /** 
  79.      * 初始化组件 
  80.      * 2013-11-21 下午2:20:10 
  81.      * 
  82.      */  
  83.     private void findViews() {  
  84.         this.mVideoView = (VideoView) findViewById(R.id.bbvideoview);  
  85.         this.tvcache = (TextView) findViewById(R.id.tvcache);  
  86.     }  
  87.       
  88.     private void init() {  
  89.         Intent intent = getIntent();  
  90.   
  91.         this.remoteUrl = intent.getStringExtra("url");  
  92.         System.out.println("remoteUrl: " + remoteUrl);  
  93.   
  94.         if (this.remoteUrl == null) {  
  95.             finish();  
  96.             return;  
  97.         }  
  98.   
  99. //      this.localUrl = intent.getStringExtra("cache");  
  100.         mVideoView.setMediaController(new MediaController(this));  
  101.         mVideoView.setOnPreparedListener(new OnPreparedListener() {  
  102.   
  103.             public void onPrepared(MediaPlayer mediaplayer) {  
  104.                 Log.i(TAG, "onPrepared");  
  105.                 dismissProgressDialog();  
  106.                 mVideoView.seekTo(curPosition);  
  107.                 mediaplayer.start();  
  108.             }  
  109.         });  
  110.   
  111.         mVideoView.setOnCompletionListener(new OnCompletionListener() {  
  112.   
  113.             public void onCompletion(MediaPlayer mediaplayer) {  
  114.                 Log.i(TAG, "onCompletion"+localUrl);  
  115. //              curPosition = 0;  
  116.                 if(localUrl.endsWith("1.mp4")){  
  117.                     localUrl=localUrl.replace("1.mp4""2.mp4");  
  118.                     mVideoView.setVideoPath(localUrl);  
  119.                     mVideoView.start();  
  120.                 }else if(localUrl.endsWith("2.mp4")){  
  121.                     localUrl=localUrl.replace("2.mp4""3.mp4");  
  122.                     mVideoView.setVideoPath(localUrl);  
  123.                     mVideoView.start();  
  124.                 }else{  
  125.                     localUrl=localUrl.replace("3.mp4""1.mp4");  
  126.                     mVideoView.setVideoPath(localUrl);  
  127.                     mVideoView.start();  
  128.                 }  
  129.                   
  130.             }  
  131.         });  
  132.   
  133.         mVideoView.setOnErrorListener(new OnErrorListener() {  
  134.   
  135.             public boolean onError(MediaPlayer mediaplayer, int i, int j) {  
  136.                 Log.i(TAG, "onError");  
  137.                 iserror = true;  
  138.                 errorCnt++;  
  139.                 mVideoView.pause();  
  140.                 showProgressDialog();  
  141.                 return true;  
  142.             }  
  143.         });  
  144.     }  
  145.   
  146.     private void showProgressDialog() {  
  147.         mHandler.post(new Runnable() {  
  148.   
  149.             @Override  
  150.             public void run() {  
  151.                 if (progressDialog == null) {  
  152.                     progressDialog = ProgressDialog.show(UDPFileMPlayer.this,  
  153.                             "视频缓存""正在努力加载中 ..."truefalse);  
  154.                 }  
  155.             }  
  156.         });  
  157.     }  
  158.   
  159.     private void dismissProgressDialog() {  
  160.         mHandler.post(new Runnable() {  
  161.   
  162.             @Override  
  163.             public void run() {  
  164.                 if (progressDialog != null) {  
  165.                     progressDialog.dismiss();  
  166.                     progressDialog = null;  
  167.                 }  
  168.             }  
  169.         });  
  170.     }  
  171.     /** 
  172.      * 播放视频 
  173.      * 2013-11-21 下午2:20:34 
  174.      * 
  175.      */  
  176.     private void playvideo() {  
  177.           
  178.   
  179.         showProgressDialog();  
  180.   
  181.         receiveThread=new Thread(new Runnable() {  
  182.   
  183.             @Override  
  184.             public void run() {  
  185.                 FileOutputStream out = null;  
  186.                 DatagramSocket dataSocket=null;  
  187.                 DatagramPacket dataPacket=null;  
  188.                 try {  
  189.                      dataSocket = new DatagramSocket(PORT);  
  190.                     byte[] receiveByte = new byte[8192];  
  191.                      dataPacket = new DatagramPacket(receiveByte, receiveByte.length);  
  192.                     Log.i(TAG, "UDP服务启动...");  
  193.                     if (localUrl == null) {  
  194.                         localUrl = FILE_DIR+"1.mp4";  
  195.                     }  
  196.                     Log.i(TAG, "localUrl="+localUrl);  
  197.                     File cacheFile = new File(localUrl);  
  198.   
  199.                     if (!cacheFile.exists()) {  
  200.                         cacheFile.getParentFile().mkdirs();  
  201.                         cacheFile.createNewFile();  
  202.                     }  
  203.                       
  204.                     out = new FileOutputStream(cacheFile, true);  
  205.                     int size = 0;  
  206.                     long lastReadSize = 0;  
  207.                     int number=0;  
  208.                       
  209.                     int fileNum=0;  
  210. //                  mHandler.sendEmptyMessage(VIDEO_STATE_UPDATE);  
  211.                   
  212.                      while(size==0){  
  213.                         // 无数据,则循环  
  214.                          dataSocket.receive(dataPacket);  
  215.                          size = dataPacket.getLength();  
  216.                           if (size > 0) {  
  217.                                 try {  
  218.                                     if(readSize>=READY_BUFF){  
  219.                                         fileNum++;  
  220.                                           
  221.                                         switch(fileNum%3){  
  222.                                             case 0:  
  223.                                                 out=new FileOutputStream(FILE_DIR+"1.mp4");  
  224.                                                 break;  
  225.                                             case 1:  
  226.                                                 out=new FileOutputStream(FILE_DIR+"2.mp4");  
  227.                                                 break;  
  228.                                             case 2:  
  229.                                                 out=new FileOutputStream(FILE_DIR+"3.mp4");  
  230.                                                 break;  
  231.                                         }  
  232.                                           
  233.                                         readSize=0;  
  234.                                         if (!isready) {  
  235.                                             mHandler.sendEmptyMessage(CACHE_VIDEO_READY);  
  236.                                         }  
  237.                                     }  
  238.                                     out.write(dataPacket.getData(), 0, size);  
  239.                                     out.flush();  
  240.                                     readSize += size;  
  241.                                     size = 0;// 循环接收  
  242.                                       
  243.                                       
  244.                                 } catch (Exception e) {  
  245.                                     Log.e(TAG, "出现异常0",e);  
  246.                                 }  
  247.                                   
  248.                           }else{  
  249.                               Log.i(TAG, "TS流停止发送数据");  
  250.                           }  
  251.                             
  252.                      }  
  253.                   
  254.                     mHandler.sendEmptyMessage(CACHE_VIDEO_END);  
  255.                 } catch (Exception e) {  
  256.                     Log.e(TAG, "出现异常",e);  
  257.                 } finally {  
  258.                     if (out != null) {  
  259.                         try {  
  260.                             out.close();  
  261.                         } catch (IOException e) {  
  262.                             //  
  263.                             Log.e(TAG, "出现异常1",e);  
  264.                         }  
  265.                     }  
  266.   
  267.                     if (dataSocket != null) {  
  268.                         try {  
  269.                             dataSocket.close();  
  270.                         } catch (Exception e) {  
  271.                             Log.e(TAG, "出现异常2",e);  
  272.                         }  
  273.                     }  
  274.                 }  
  275.   
  276.             }  
  277.         });  
  278.         receiveThread.start();  
  279.     }  
  280.   
  281.     private final static int VIDEO_STATE_UPDATE = 0;  
  282.     /** 
  283.      * 缓存准备 
  284.      */  
  285.     private final static int CACHE_VIDEO_READY = 1;  
  286.     /** 
  287.      * 缓存修改 
  288.      */  
  289.     private final static int CACHE_VIDEO_UPDATE = 2;  
  290.     /** 
  291.      * 缓存结束 
  292.      */  
  293.     private final static int CACHE_VIDEO_END = 3;  
  294.     /** 
  295.      * 缓存播放 
  296.      */  
  297.     private final static int CACHE_VIDEO_PLAY = 4;  
  298.   
  299.     private final Handler mHandler = new Handler() {  
  300.         @Override  
  301.         public void handleMessage(Message msg) {  
  302.             switch (msg.what) {  
  303.             case VIDEO_STATE_UPDATE:  
  304.                 boolean isPlay=mVideoView.isPlaying();  
  305.                 Log.i(TAG, "更新显示 isPlay="+isPlay);  
  306.                 double cachepercent = readSize * 100.00 / mediaLength * 1.0;  
  307.                 String s = String.format("已缓存: [%.2f%%]", cachepercent);  
  308.                 if (isPlay) {  
  309.                     curPosition = mVideoView.getCurrentPosition();  
  310.                     int duration = mVideoView.getDuration();  
  311.                     duration = duration == 0 ? 1 : duration;  
  312.   
  313.                     double playpercent = curPosition * 100.00 / duration * 1.0;  
  314.   
  315.                     int i = curPosition / 1000;  
  316.                     int hour = i / (60 * 60);  
  317.                     int minute = i / 60 % 60;  
  318.                     int second = i % 60;  
  319.   
  320.                     s += String.format(" 播放: %02d:%02d:%02d [%.2f%%]", hour,  
  321.                             minute, second, playpercent);  
  322.                 }  
  323. //  
  324. //              tvcache.setText(s);  
  325.                 tvcache.setVisibility(View.GONE);  
  326.                 mHandler.sendEmptyMessageDelayed(VIDEO_STATE_UPDATE, 1000);  
  327.                   
  328.   
  329.                   
  330.                 break;  
  331.   
  332.             case CACHE_VIDEO_READY:  
  333.                 Log.i(TAG, "缓存准备");  
  334.                 isready = true;  
  335.                 mVideoView.setVideoPath(localUrl);  
  336.                 mVideoView.start();  
  337.                   
  338.                 break;  
  339.   
  340.             case CACHE_VIDEO_UPDATE:  
  341.                 Log.i(TAG, "缓存修改"+iserror);  
  342.                 if (iserror) {  
  343.                     mVideoView.setVideoPath(localUrl);  
  344.                     mVideoView.start();  
  345.                     iserror = false;  
  346.                 }  
  347.                 break;  
  348.   
  349.             case CACHE_VIDEO_END:  
  350.                 Log.i(TAG, "缓存结束"+iserror);  
  351.                 if (iserror) {  
  352.                       
  353.                     mVideoView.setVideoPath(localUrl);  
  354.                     mVideoView.start();  
  355.                     iserror = false;  
  356.                 }  
  357.                 break;  
  358.             case CACHE_VIDEO_PLAY:  
  359.                 Log.i(TAG, "CACHE_VIDEO_PLAY");  
  360.                 mVideoView.setVideoPath(localUrl);  
  361.                 mVideoView.start();  
  362.                 mHandler.sendEmptyMessageDelayed(CACHE_VIDEO_PLAY, 5000);  
  363.                 break;  
  364.             }  
  365.   
  366.             super.handleMessage(msg);  
  367.         }  
  368.     };  
  369.   
  370.     @Override  
  371.     protected void onDestroy() {  
  372.         // TODO Auto-generated method stub  
  373.         if(mVideoView!=null){  
  374.             mVideoView.stopPlayback();  
  375.         }  
  376.         super.onDestroy();  
  377.     }  
  378.       
  379.       
  380. }  

分享是人类进步的源泉,可参考:http://blog.csdn.net/cuiran/article/details/40855677
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值