使用vitaimo搭建可以播放组播流的播放器

                              这今天做电视端项目,需要写一个可以播放组播流的播放器,可以直接播放像CCTV频道的电视节目。

我们先来说说组播流以及它所用到的协议;

                 组播一种组播流分发节点接收组播流的方法,效保证了组播流传输的可靠性以及组播业务不发生间断,并保证了双组播源在组网中的应用;

                 流媒体协议: (rtp/rtcp/rtsp/rtmp/mms/hls)

                      这里我在网上找到了一篇很好的博客。里面专门详细讲解流媒体协议。地址: 流媒体协议介绍(rtp/rtcp/rtsp/rtmp/mms/hls)

                             如果要播放流媒体,我们也可以搭建一个VLC的服务器,来向网段中分发流,我之前写过关于VLC搭建流媒体的博客。以供大家参考;     使用VLC搭建组播服务器,在客户端进行播放

                            闲话少说,上代码;

                 这是从vitaimo官网下载的工程依赖,initActivity,其目录结构如下:

                 使用vitaimo搭建可以播放组播流的播放器_第1张图片

                    将他导入项目后作为工程依赖即可。

                    下面就是播放器代码:

import io.vov.vitamio.ChannelChangeImp;
import io.vov.vitamio.LibsChecker;
import io.vov.vitamio.MediaPlayer;
import io.vov.vitamio.MediaPlayer.OnBufferingUpdateListener;
import io.vov.vitamio.MediaPlayer.OnCompletionListener;
import io.vov.vitamio.MediaPlayer.OnPreparedListener;
import io.vov.vitamio.SetChannelList;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.widget.ListView;
import android.widget.Toast;

public class PlayAcy extends Activity implements OnBufferingUpdateListener,
		OnCompletionListener, OnPreparedListener,
		TextureView.SurfaceTextureListener {
	private static final String TAG = PlayAcy.class.getSimpleName();
	private TextureView mTextureView;
	private ListView lvAcyPlay;
	private String path;
	private Surface surf;
	private MediaPlayer mMediaPlayer;
	private boolean mIsVideoReadyToBePlayed = false;
	SurfaceTexture surfaceTexture;

	public List ChannelName = new ArrayList();

	public List ChannelAddress = new ArrayList();

	// 播放位置
	private int position = 0;

	private SetChannelList setChannelList;

	private ChannelChangeImp channelChangeImp;

	private Context mContext;

	private Adapter adapter;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		if (!LibsChecker.checkVitamioLibs(this))
			return;
		setContentView(R.layout.acy_play);
		mContext = this;
		initView();
		initData();
		InitPlayer();
	}

	private void initView() {
		lvAcyPlay = (ListView) findViewById(R.id.lv_acy_play);

	}

	private void initData() {
		setChannelList = new SetChannelList(mContext);
		channelChangeImp = new ChannelChangeImp();
		// 添加频道名称
		ChannelName.add("CCTV1");
		ChannelName.add("CCTV3");
		ChannelName.add("UDP");
		//
		setChannelList.setChannelNameList(ChannelName);

		// 添加播放地址
		ChannelAddress.add("http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8");
		ChannelAddress.add("http://ivi.bupt.edu.cn/hls/cctv3hd.m3u8");
		ChannelAddress.add("udp://@239.255.255.255:1234");
		//
		setChannelList.setChannelAddressList(ChannelAddress);
		adapter = new Adapter(mContext, ChannelName);

		lvAcyPlay.setAdapter(adapter);
	}

	public void InitPlayer() {
		path = ChannelAddress.get(2);
		mTextureView = (TextureView) findViewById(R.id.surface);
		mTextureView.setSurfaceTextureListener(this);
		mTextureView.setFocusable(true);
		mTextureView.setOnFocusChangeListener(new OnFocusChangeListener() {

			@Override
			public void onFocusChange(View v, boolean hasFocus) {
				if (hasFocus == true) {// 如果获得到焦点
					Toast.makeText(getApplicationContext(), "获取到焦点", 0).show();
				} else {
					Toast.makeText(getApplicationContext(), "没有获取到焦点", 0)
							.show();
				}
			}
		});
	}

	// 节目列表
	private void playVideo(String path) {
		channelChangeImp.release(mMediaPlayer);
		try {
			mMediaPlayer = new MediaPlayer(this, true);
			mMediaPlayer.setDataSource(path);
			if (surf == null) {
				surf = new Surface(surfaceTexture);
			}
			mMediaPlayer.setSurface(surf);
			mMediaPlayer.prepareAsync();
			mMediaPlayer.setTimedTextShown(true);
			mMediaPlayer.setOnBufferingUpdateListener(this);// 设置缓冲监听
			mMediaPlayer.setOnCompletionListener(this);// 设置播放完毕监听
			mMediaPlayer.setOnPreparedListener(this);// 设置准备完毕监听
			mMediaPlayer.setBufferSize(512 * 1024);
			mMediaPlayer.setVideoQuality(MediaPlayer.VIDEOQUALITY_MEDIUM);
			setVolumeControlStream(AudioManager.STREAM_MUSIC);
			mMediaPlayer.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
			int height) {
		surfaceTexture = surface;
		playVideo(ChannelAddress.get(0));

	}

	@Override
	public boolean onSurfaceTextureDestroyed(SurfaceTexture arg0) {

		return false;
	}

	@Override
	public void onSurfaceTextureSizeChanged(SurfaceTexture arg0, int arg1,
			int arg2) {

	}

	@Override
	public void onSurfaceTextureUpdated(SurfaceTexture arg0) {

	}

	@Override
	public void onPrepared(MediaPlayer mp) {
		mIsVideoReadyToBePlayed = true;
		if (mIsVideoReadyToBePlayed) {
			startVideoPlayback();
		}
	}

	@Override
	public void onCompletion(MediaPlayer mp) {

	}

	@Override
	public void onBufferingUpdate(MediaPlayer mp, int percent) {

	}

	private void startVideoPlayback() {
		adjustAspectRatio(mMediaPlayer.getVideoWidth(),
				mMediaPlayer.getVideoHeight());
		mMediaPlayer.start();
	}

	public void adjustAspectRatio(int videoWidth, int videoHeight) {
		int viewWidth = mTextureView.getWidth();
		int viewHeight = mTextureView.getHeight();
		double aspectRatio = (double) videoHeight / videoWidth;

		int newWidth, newHeight;
		if (viewHeight > (int) (viewWidth * aspectRatio)) {
			newWidth = viewWidth;
			newHeight = (int) (viewWidth * aspectRatio);
		} else {
			newWidth = (int) (viewHeight / aspectRatio);
			newHeight = viewHeight;
		}
		int xoff = (viewWidth - newWidth) / 2;
		int yoff = (viewHeight - newHeight) / 2;

		Matrix txform = new Matrix();
		mTextureView.getTransform(txform);
		txform.setScale((float) newWidth / viewWidth, (float) newHeight
				/ viewHeight);
		txform.postTranslate(xoff, yoff);
		mTextureView.setTransform(txform);
	}

	@Override
	protected void onDestroy() {
		if (channelChangeImp != null)
			channelChangeImp.release(mMediaPlayer);
		super.onDestroy();
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == 19) {
			position = ++position;
		} else if (keyCode == 20) {
			position = --position;
		}
		if (position < ChannelAddress.size() && position >= 0) {
			playVideo(ChannelAddress.get(position));
		} else if (position > ChannelAddress.size()) {
			position = ChannelAddress.size() - 1;
		} else if (position < 0) {
			position = 0;
		}
		return super.onKeyDown(keyCode, event);
	}

	@Override
	protected void onPause() {
		super.onPause();
		channelChangeImp.release(mMediaPlayer);
	}

}

              播放器界面布局:



    

    


                同时我在里面又新加了一个设置频道列表以及换台的功能接口。

/**
 * 换台接口
 * 
 * @author Administrator
 * 
 */
public class ChannelChangeImp {

	private boolean mIsVideoSizeKnown = false;

	private boolean mIsVideoReadyToBePlayed = false;

	public ChannelChangeImp() {
		super();
	}

	public void release(MediaPlayer mMediaPlayer) {
		if (mMediaPlayer != null) {
			mMediaPlayer.release();
			mMediaPlayer = null;
		}
		doCleanUp();
	}

	private void doCleanUp() {
		mIsVideoReadyToBePlayed = false;
		mIsVideoSizeKnown = false;
	}
}

/**
 * 设置频道列表
 * 
 * @author Administrator
 * 
 */
public class SetChannelList {

	// 频道名称
	private List ChannelName = new ArrayList();

	// 频道地址
	private List ChannelAddress = new ArrayList();

	private Context context;

	public SetChannelList(Context mContext) {
		super();
		this.context = mContext;
	}

	// 设置频道名称列表
	public void setChannelNameList(List mChannelName) {
		this.ChannelName = mChannelName;
	}

	// 设置频道地址列表
	public void setChannelAddressList(List mChannelAddress) {
		this.ChannelAddress = mChannelAddress;
	}

	public List getChannelNameList() {
		if (ChannelName.size() == 0 && context != null) {
			Toast.makeText(context, "頻道名称为空", 0).show();
		} else if (ChannelName.size() >= 0 && context != null) {
			return ChannelName;
		}
		return ChannelName;
	}

	public List getChannelAddressList() {
		if (ChannelAddress.size() == 0) {
			Toast.makeText(context, "頻道地址为空", 0).show();
		} else if (ChannelName.size() >= 0) {
			return ChannelAddress;
		}
		return ChannelAddress;
	}
}

                   以上就是基于Vitaimo自定义组播流播放器的代码。

                    至此,共勉。



                  

  

你可能感兴趣的:(Android开发进阶-通讯篇)