Android接收UDP TS流实现边缓存边播放 – 小崔的博客 – 博客频道 – CSDN.NET

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

具体实现代码如下:

package com.cayden.videodemo;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import android.app.Activity;

import android.app.ProgressDialog;

import android.content.Intent;

import android.media.MediaPlayer;

import android.media.MediaPlayer.OnCompletionListener;

import android.media.MediaPlayer.OnErrorListener;

import android.media.MediaPlayer.OnPreparedListener;

import android.os.Bundle;

import android.os.Environment;

import android.os.Handler;

import android.os.Message;

import android.util.Log;

import android.view.View;

import android.widget.MediaController;

import android.widget.TextView;

import android.widget.VideoView;

import com.cayden.videodemo.R;

/**

*

* 接收UDP TS流实现边缓存边播放<br/>

* 该类可以实现,但存在以下不足<br/>

* 1、播放过程会稍微卡一下这是 由于播放时候setOnCompletionListener中方法被执行<br/>

* 2、需要思考怎么解决调用onError方法

* @author cuiran

* @version 1.0.0

*/

public class UDPFileMPlayer extends Activity {

private static final String TAG=”UDPFileMPlayer”;

private VideoView mVideoView;

private TextView tvcache;

private String remoteUrl;

private String localUrl;

private ProgressDialog progressDialog = null;

private Thread receiveThread=null;

/**

* 定义了初始缓存区的大小,当视频加载到初始缓存区满的时候,播放器开始播放,

*/

private static final int READY_BUFF = 1316 * 1024*10;

 

private static final String FILE_DIR=Environment.getExternalStorageDirectory().getAbsolutePath()+”/VideoCache/”;

 

/**

* 核心交换缓存区,主要是用来动态调节缓存区,当网络环境较好的时候,该缓存区为初始大小,

* 当网络环境差的时候,该缓存区会动态增加,主要就是为了避免视频播放的时候出现一卡一卡的现象。

*/

private static final int CACHE_BUFF = 10 * 1024;

/**

* 单播或组播端口

*/

private static final int PORT = 1234;

 

private boolean isready = false;

private boolean iserror = false;

private int errorCnt = 0;

private int curPosition = 0;

private long mediaLength = 0;

private long readSize = 0;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.bbvideoplayer);

findViews();

init();

playvideo();

}

/**

* 初始化组件

* 2013-11-21 下午2:20:10

*

*/

private void findViews() {

this.mVideoView = (VideoView) findViewById(R.id.bbvideoview);

this.tvcache = (TextView) findViewById(R.id.tvcache);

}

 

private void init() {

Intent intent = getIntent();

this.remoteUrl = intent.getStringExtra(“url”);

System.out.println(“remoteUrl: ” + remoteUrl);

if (this.remoteUrl == null) {

finish();

return;

}

// this.localUrl = intent.getStringExtra(“cache”);

mVideoView.setMediaController(new MediaController(this));

mVideoView.setOnPreparedListener(new OnPreparedListener() {

public void onPrepared(MediaPlayer mediaplayer) {

Log.i(TAG, “onPrepared”);

dismissProgressDialog();

mVideoView.seekTo(curPosition);

mediaplayer.start();

}

});

mVideoView.setOnCompletionListener(new OnCompletionListener() {

public void onCompletion(MediaPlayer mediaplayer) {

Log.i(TAG, “onCompletion”+localUrl);

// curPosition = 0;

if(localUrl.endsWith(“1.mp4”)){

localUrl=localUrl.replace(“1.mp4”, “2.mp4”);

mVideoView.setVideoPath(localUrl);

mVideoView.start();

}else if(localUrl.endsWith(“2.mp4”)){

localUrl=localUrl.replace(“2.mp4”, “3.mp4”);

mVideoView.setVideoPath(localUrl);

mVideoView.start();

}else{

localUrl=localUrl.replace(“3.mp4”, “1.mp4”);

mVideoView.setVideoPath(localUrl);

mVideoView.start();

}

 

}

});

mVideoView.setOnErrorListener(new OnErrorListener() {

public boolean onError(MediaPlayer mediaplayer, int i, int j) {

Log.i(TAG, “onError”);

iserror = true;

errorCnt++;

mVideoView.pause();

showProgressDialog();

return true;

}

});

}

private void showProgressDialog() {

mHandler.post(new Runnable() {

@Override

public void run() {

if (progressDialog == null) {

progressDialog = ProgressDialog.show(UDPFileMPlayer.this,

“视频缓存”, “正在努力加载中 …”, true, false);

}

}

});

}

private void dismissProgressDialog() {

mHandler.post(new Runnable() {

@Override

public void run() {

if (progressDialog != null) {

progressDialog.dismiss();

progressDialog = null;

}

}

});

}

/**

* 播放视频

* 2013-11-21 下午2:20:34

*

*/

private void playvideo() {

 

showProgressDialog();

receiveThread=new Thread(new Runnable() {

@Override

public void run() {

FileOutputStream out = null;

DatagramSocket dataSocket=null;

DatagramPacket dataPacket=null;

try {

dataSocket = new DatagramSocket(PORT);

byte[] receiveByte = new byte[8192];

dataPacket = new DatagramPacket(receiveByte, receiveByte.length);

Log.i(TAG, “UDP服务启动…”);

if (localUrl == null) {

localUrl = FILE_DIR+”1.mp4″;

}

Log.i(TAG, “localUrl=”+localUrl);

File cacheFile = new File(localUrl);

if (!cacheFile.exists()) {

cacheFile.getParentFile().mkdirs();

cacheFile.createNewFile();

}

 

out = new FileOutputStream(cacheFile, true);

int size = 0;

long lastReadSize = 0;

int number=0;

 

int fileNum=0;

// mHandler.sendEmptyMessage(VIDEO_STATE_UPDATE);

 

while(size==0){

// 无数据,则循环

dataSocket.receive(dataPacket);

size = dataPacket.getLength();

if (size > 0) {

try {

if(readSize>=READY_BUFF){

fileNum++;

 

switch(fileNum%3){

case 0:

out=new FileOutputStream(FILE_DIR+”1.mp4″);

break;

case 1:

out=new FileOutputStream(FILE_DIR+”2.mp4″);

break;

case 2:

out=new FileOutputStream(FILE_DIR+”3.mp4”);

break;

}

 

readSize=0;

if (!isready) {

mHandler.sendEmptyMessage(CACHE_VIDEO_READY);

}

}

out.write(dataPacket.getData(), 0, size);

out.flush();

readSize += size;

size = 0;// 循环接收

 

 

} catch (Exception e) {

Log.e(TAG, “出现异常0”,e);

}

 

}else{

Log.i(TAG, “TS流停止发送数据”);

}

 

}

 

mHandler.sendEmptyMessage(CACHE_VIDEO_END);

} catch (Exception e) {

Log.e(TAG, “出现异常”,e);

} finally {

if (out != null) {

try {

out.close();

} catch (IOException e) {

//

Log.e(TAG, “出现异常1”,e);

}

}

if (dataSocket != null) {

try {

dataSocket.close();

} catch (Exception e) {

Log.e(TAG, “出现异常2”,e);

}

}

}

}

});

receiveThread.start();

}

private final static int VIDEO_STATE_UPDATE = 0;

/**

* 缓存准备

*/

private final static int CACHE_VIDEO_READY = 1;

/**

* 缓存修改

*/

private final static int CACHE_VIDEO_UPDATE = 2;

/**

* 缓存结束

*/

private final static int CACHE_VIDEO_END = 3;

/**

* 缓存播放

*/

private final static int CACHE_VIDEO_PLAY = 4;

private final Handler mHandler = new Handler() {

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case VIDEO_STATE_UPDATE:

boolean isPlay=mVideoView.isPlaying();

Log.i(TAG, “更新显示 isPlay=”+isPlay);

double cachepercent = readSize * 100.00 / mediaLength * 1.0;

String s = String.format(“已缓存: [%.2f%%]”, cachepercent);

if (isPlay) {

curPosition = mVideoView.getCurrentPosition();

int duration = mVideoView.getDuration();

duration = duration == 0 ? 1 : duration;

double playpercent = curPosition * 100.00 / duration * 1.0;

int i = curPosition / 1000;

int hour = i / (60 * 60);

int minute = i / 60 % 60;

int second = i % 60;

s += String.format(” 播放: %02d:%02d:%02d [%.2f%%]”, hour,

minute, second, playpercent);

}

//

// tvcache.setText(s);

tvcache.setVisibility(View.GONE);

mHandler.sendEmptyMessageDelayed(VIDEO_STATE_UPDATE, 1000);

 

 

break;

case CACHE_VIDEO_READY:

Log.i(TAG, “缓存准备”);

isready = true;

mVideoView.setVideoPath(localUrl);

mVideoView.start();

 

break;

case CACHE_VIDEO_UPDATE:

Log.i(TAG, “缓存修改”+iserror);

if (iserror) {

mVideoView.setVideoPath(localUrl);

mVideoView.start();

iserror = false;

}

break;

case CACHE_VIDEO_END:

Log.i(TAG, “缓存结束”+iserror);

if (iserror) {

 

mVideoView.setVideoPath(localUrl);

mVideoView.start();

iserror = false;

}

break;

case CACHE_VIDEO_PLAY:

Log.i(TAG, “CACHE_VIDEO_PLAY”);

mVideoView.setVideoPath(localUrl);

mVideoView.start();

mHandler.sendEmptyMessageDelayed(CACHE_VIDEO_PLAY, 5000);

break;

}

super.handleMessage(msg);

}

};

@Override

protected void onDestroy() {

// TODO Auto-generated method stub

if(mVideoView!=null){

mVideoView.stopPlayback();

}

super.onDestroy();

}

 

 

}

来源URL:http://cache.baiducontent.com/c?m=9d78d513d9901df918b0cf281a17a771695497103bc0a01068a5945f92141d005321a3e52878564291d27d141cb21902b7a52172405261e1c7df883d81ecd4357ecf7c7423409b12529542fe9511389777d609b2f158fabcf23894a9d6d6da&p=882a9546d78608e70be2962613488a&newp=882a9546d7af0efa00be9b7c494091231610db2151d4d614139bc610&user=baidu&fm=sc&query=android%B2%A5%B7%C5ts&qid=99777d3600046bec&p1=1