這個播放器是用的七牛的播放器,直播一般都是需要後臺先推流,然後根據後臺給的播放地址開始直播,我這裏只是一個演示,自己在網上找了一個地址,可以直接播放。
1. 拷貝架包和so文件
複製pldroid-player-1.5.0.jar到libs目錄以及複製相關so文件到libs目錄下面,build.gradle文件裏面添加,用於編譯.so文件
sourceSets{
main(){
jniLibs.srcDirs=['libs']
}
}
2. 佈局中使用
<com.pili.pldroid.player.widget.PLVideoView
android:id="@+id/id_video_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
3. 代碼中使用
代碼比較簡單 直接拷貝全部代碼了
package com.livevideo.zlc.ui;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.support.v4.content.ContextCompat;
import android.view.OrientationEventListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.livevideo.zlc.MyApp;
import com.livevideo.zlc.R;
import com.livevideo.zlc.utils.LogUtil;
import com.livevideo.zlc.utils.NetworkStateUtil;
import com.livevideo.zlc.utils.ScreenUtil;
import com.livevideo.zlc.utils.StatusBarUtil;
import com.pili.pldroid.player.AVOptions;
import com.pili.pldroid.player.PLMediaPlayer;
import com.pili.pldroid.player.widget.PLVideoView;
//直播
public class LiveActivity extends BaseActivity implements View.OnClickListener{
private ImageView im_zhuan_fangda;
private ImageView im_room_video_off;
private ImageView im_fanhui2;
private TextView id_tv_load;
private ImageView id_iv_load;
private RelativeLayout id_rl_video;
private PLVideoView mVideoView;
private LinearLayout id_ll_head;
private LinearLayout id_ll_bottom;
private LinearLayout id_ll_load;
private String TAG = "";
private PowerManager.WakeLock mWakeLock = null;
private String mVideoPath = "";
private int mDisplayAspectRatio = PLVideoView.ASPECT_RATIO_16_9;
private static final int MESSAGE_ID_RECONNECTING = 0x01;
boolean showF = true;
private boolean canChanged = true;
private boolean isVerticalScreen = true; // 是不是豎屏
private Handler handler = new Handler(Looper.getMainLooper());
private int canReconnect = 1; //1代表可以重新連接
//控制面板的顯示與隱藏
final Runnable runnable = new Runnable() {
@Override
public void run() {
LogUtil.e("執行動畫",showF+"");
if(showF){//隱藏動畫
showView(View.GONE,id_ll_head,id_ll_bottom);
}else{ //顯示動畫
showView(View.VISIBLE,id_ll_head,id_ll_bottom);
show_or_hidden(3000);
}
showF = !showF;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
PowerManager pm = (PowerManager) this.getSystemService(POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "Test");
TAG = this.getClass().getSimpleName();
initView();
initData();
initListener();
}
@Override
protected void onStart() {
super.onStart();
show_or_hidden(3000);
}
private void initView(){
im_room_video_off= findView(R.id.id_iv_video_bg);
im_zhuan_fangda = findView(R.id.id_im_rotate);
mVideoView = findView(R.id.id_video_view);
im_fanhui2 = findView(R.id.im_fanhui2);
id_tv_load = findView(R.id.id_tv_load);
id_iv_load = findView(R.id.id_iv_load);
id_rl_video = findView(R.id.id_rl_video);
id_ll_head = findView(R.id.id_ll_head);
id_ll_bottom = findView(R.id.id_ll_bottom);
id_ll_load = findView(R.id.id_ll_load);
ViewGroup.LayoutParams params = id_rl_video.getLayoutParams();
int width = params.width = ScreenUtil.getScreenWidth(this);
params.height = width*9 / 16 ;
id_rl_video.setLayoutParams(params);
}
private void initListener(){
im_fanhui2.setOnClickListener(this);
id_rl_video.setOnClickListener(this);
im_zhuan_fangda.setOnClickListener(this);
id_tv_load.setOnClickListener(this);
}
private void initData(){
mVideoPath = "rtmp://live.hkstv.hk.lxdns.com/live/hks";
LogUtil.e("mVideoPath",mVideoPath);
initVideo();
}
//初始化七牛視頻播放器
private void initVideo(){
AVOptions options = new AVOptions();
int isLiveStreaming = getIntent().getIntExtra("liveStreaming", 1);
// the unit of timeout is ms
options.setInteger(AVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
options.setInteger(AVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000);
// Some optimization with buffering mechanism when be set to 1
options.setInteger(AVOptions.KEY_LIVE_STREAMING, isLiveStreaming);
if (isLiveStreaming == 1) {
options.setInteger(AVOptions.KEY_DELAY_OPTIMIZATION, 1);
}
// 1 -> hw codec enable, 0 -> disable [recommended]
int codec = getIntent().getIntExtra("mediaCodec", AVOptions.MEDIA_CODEC_AUTO); //0是軟解,1是硬解,2是自動
options.setInteger(AVOptions.KEY_MEDIACODEC, codec);
// whether start play automatically after prepared, default value is 1
options.setInteger(AVOptions.KEY_START_ON_PREPARED, 0);
mVideoView.setAVOptions(options);
mVideoView.setDisplayAspectRatio(PLVideoView.ASPECT_RATIO_16_9);
// Set some listeners
mVideoView.setOnInfoListener(mOnInfoListener);
// mVideoView.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
mVideoView.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
mVideoView.setOnCompletionListener(mOnCompletionListener);
mVideoView.setOnSeekCompleteListener(mOnSeekCompleteListener);
mVideoView.setOnErrorListener(mOnErrorListener);
mVideoView.setVideoPath(mVideoPath);
}
//直播相關
protected Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg.what != MESSAGE_ID_RECONNECTING) {
return;
}
if (!NetworkStateUtil.instance().isNetworkConnected(MyApp.getContext())) {
sendReconnectMessage();
return;
}
mVideoView.setVideoPath(mVideoPath);
mVideoView.start();
}
};
private PLMediaPlayer.OnInfoListener mOnInfoListener = new PLMediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(PLMediaPlayer plMediaPlayer, int what, int extra) {
LogUtil.e("OnInfoListener","Info");
return false;
}
};
private PLMediaPlayer.OnCompletionListener mOnCompletionListener = new PLMediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(PLMediaPlayer plMediaPlayer) {
LogUtil.e("OnCompletionListener","播放完成");
canReconnect = 1;
showView(View.VISIBLE,im_room_video_off,id_ll_load);
id_tv_load.setBackgroundResource(R.drawable.shape_btn_main_k_5dp);
id_tv_load.setText("重新加載");
}
};
private PLMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener = new PLMediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(PLMediaPlayer plMediaPlayer, int precent) {
LogUtil.e("OnBufferingUpdateListener","在緩衝更新");
canReconnect = 0;
im_room_video_off.setVisibility(View.GONE);
showView(View.INVISIBLE,id_ll_load);
}
};
private PLMediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener = new PLMediaPlayer.OnSeekCompleteListener() {
@Override
public void onSeekComplete(PLMediaPlayer plMediaPlayer) {
canReconnect = 0;
LogUtil.e("OnSeekCompleteListener","鏈接完成");
im_room_video_off.setVisibility(View.GONE);
showView(View.INVISIBLE,id_ll_load);
}
};
private PLMediaPlayer.OnErrorListener mOnErrorListener = new PLMediaPlayer.OnErrorListener() {
@Override
public boolean onError(PLMediaPlayer plMediaPlayer, int errorCode) {
LogUtil.e(TAG, "Error happened, errorCode = " + errorCode);
switch (errorCode) {
case PLMediaPlayer.ERROR_CODE_INVALID_URI:
showToastTips("無效的播放地址 !",true);
break;
case PLMediaPlayer.ERROR_CODE_404_NOT_FOUND:
showToastTips("未找到資源 !",true);
break;
case PLMediaPlayer.ERROR_CODE_CONNECTION_REFUSED:
showToastTips("連接錯誤",true);
break;
case PLMediaPlayer.ERROR_CODE_CONNECTION_TIMEOUT:
showToastTips("連接超時 !",true);
break;
case PLMediaPlayer.ERROR_CODE_EMPTY_PLAYLIST:
showToastTips("空的播放列表 !",true);
break;
case PLMediaPlayer.ERROR_CODE_STREAM_DISCONNECTED:
showToastTips("斷開連接 !",true);
break;
case PLMediaPlayer.ERROR_CODE_IO_ERROR:
showToastTips("網絡IO錯誤 !",true);
break;
case PLMediaPlayer.ERROR_CODE_UNAUTHORIZED:
showToastTips("未經授權的錯誤 !",true);
break;
case PLMediaPlayer.ERROR_CODE_PREPARE_TIMEOUT:
showToastTips("請求超時 !",true);
break;
case PLMediaPlayer.ERROR_CODE_READ_FRAME_TIMEOUT:
showToastTips("讀幀超時 !",false);
break;
case PLMediaPlayer.MEDIA_ERROR_UNKNOWN:
break;
default:
showToastTips("未知錯誤 !",true);
break;
}
return true;
}
};
private void showToastTips(final String tips,boolean isShow) {
LogUtil.e("Play==",tips);
if(isShow){
canReconnect = 1;
showView(View.VISIBLE,im_room_video_off,id_ll_load);
id_tv_load.setBackgroundResource(R.drawable.shape_btn_main_k_5dp);
id_tv_load.setText("重新加載");
}else{
canReconnect = 0;
sendReconnectMessage();
}
}
private void sendReconnectMessage() {
id_ll_load.setVisibility(View.VISIBLE);
id_tv_load.setBackgroundColor(ContextCompat.getColor(this,R.color.null_color));
id_tv_load.setText("正在加載...");
mHandler.removeCallbacksAndMessages(null);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ID_RECONNECTING), 3000);
}
boolean isFullScreen = false;
/**
* 當橫豎屏切換時執行的一些操作
*/
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
LogUtil.e("onConfigurationChanged",newConfig.orientation+"");
//全屏看視頻
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
if(StatusBarUtil.hasNavBar(this))
StatusBarUtil.hideBottomUIMenu(this);
int matchParent = ViewGroup.LayoutParams.MATCH_PARENT;
setVideoContainerParam(matchParent,matchParent);
mVideoView.setDisplayAspectRatio(PLVideoView.ASPECT_RATIO_PAVED_PARENT);
isFullScreen = true;
StatusBarUtil.fullscreen(true,this);
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { //從視頻全屏界面恢復豎屏
if(StatusBarUtil.hasNavBar(this))
StatusBarUtil.showBottomUiMenu(this);
int screenWidth = ScreenUtil.getScreenWidth(this);
setVideoContainerParam(screenWidth,screenWidth * 9 / 16);
StatusBarUtil.fullscreen(false,this);
mVideoView.setDisplayAspectRatio(mDisplayAspectRatio);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
isFullScreen = false;
}
}
private void setVideoContainerParam(int w,int h) {
ViewGroup.LayoutParams params = id_rl_video.getLayoutParams();
params.width = w;
params.height = h;
id_rl_video.setLayoutParams(params);
}
MyOrientationDetector myOrientationDetector;
@Override
public void onResume() {
super.onResume();
mVideoView.start();
mWakeLock.acquire();
myOrientationDetector = new MyOrientationDetector(this);
myOrientationDetector.enable();
}
@Override
public void onPause() {
super.onPause();
mVideoView.pause();
mWakeLock.release();
myOrientationDetector.disable();
}
@Override
protected void onDestroy() {
super.onDestroy();
mVideoView.stopPlayback();
handler.removeCallbacks(runnable);
}
@Override
public void onBackPressed() {
if(isFullScreen){
canChanged = false;
LiveActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}else{
super.onBackPressed();
}
}
private void show_or_hidden(int time){
handler.removeCallbacks(runnable); //清理前一個輪詢器
handler.postDelayed(runnable,time);
}
private void showView(int visible,View... views){
for (View v : views) {
v.setVisibility(visible);
}
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.im_fanhui2:
if(isFullScreen){
canChanged = false;
LiveActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}else{
finish();
}
break;
case R.id.id_im_rotate:
if (isFullScreen) {// 如果當前是橫屏,則切換爲豎屏
canChanged = false;
LiveActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {// 如果當前是豎屏,則切換爲橫屏
canChanged = false;
LiveActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
isFullScreen = !isFullScreen;
break;
case R.id.id_tv_load:
if(canReconnect==1){
sendReconnectMessage();
}
break;
case R.id.id_rl_video:
show_or_hidden(0);
break;
}
}
//自定義加速度傳感器的監聽事件
public class MyOrientationDetector extends OrientationEventListener {
public MyOrientationDetector( Context context ) {
super(context );
}
@Override
public void onOrientationChanged(int orientation) {
if(orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
return; //手機平放時,檢測不到有效的角度
}
//只檢測是否有四個角度的改變
if( orientation > 350 || orientation< 10 ) { //0度
isVerticalScreen = true;
if(!canChanged){
return;
}
LiveActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
} else if( orientation > 80 &&orientation < 100 ) { //90度
isVerticalScreen = false;
if(!canChanged){
return;
}
LiveActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
} else if( orientation > 170 &&orientation < 190 ) { //180度
isVerticalScreen = true;
if(!canChanged){
return;
}
LiveActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
} else if( orientation > 260 &&orientation < 280 ) { //270度
isVerticalScreen = false;
if(!canChanged){
return;
}
LiveActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
} else {
}
//物理橫屏
canChanged = (isFullScreen == !isVerticalScreen);
}
}
}
4. 清單文件中添加權限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
5. 聯繫方式
qq:1509815887
email : zlc921022@163.com
phone : 18684732678
6. 下載地址