關於直播的相關資訊這裡不做詳解,我們對直播應該很熟悉,實現生活中有各種直播,他們如何?的呢,其實開發一個簡單不能簡單的直播,只需要兩個:1、直播地址 2、播放器,對於直播地址我們可以利用很多軟體擷取串連,播放器,現在開源的也有很多,最常見的就是ffmpeg,但是如果直接用ffmpeg開發工作量比較大,我們可以使用第三方的播放器庫,例如vlc,vitamio等等,這裡我使用的時vitamio庫。
首先建立一個項目,命名為Live,項目建立好了以後我們需要配置vitamio需要的環境,網上有很多,這裡就不寫出了,添加了依賴庫後添加一個主介面,這裡我只添加了一個EditView和Button,配置如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".Live" > <EditText android:id="@+id/live_url" android:layout_width="match_parent" android:layout_height="100dp" /> <Button android:id="@+id/play" android:layout_width="120dp" android:layout_height="60dp" android:layout_below="@id/live_url" android:layout_centerHorizontal="true" android:layout_marginTop="100dp" android:text="Play" > </Button></RelativeLayout>
主介面的類:
package com.jwzhangjie.live;import android.os.Bundle;import android.app.Activity;import android.content.Intent;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;public class Live extends Activity {public static final String DEFAULTPATH = "http://ipadlive.cntv.soooner.com/cctv_p2p_hdcctv6.m3u8";EditText Live_Url;Button PlayBtn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_live);Live_Url = (EditText)findViewById(R.id.live_url);Live_Url.setText(DEFAULTPATH);PlayBtn = (Button)findViewById(R.id.play);PlayBtn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent();intent.setClass(Live.this, JieVideoPlayer.class);String path = Live_Url.getText().toString();if (path == null) {path = DEFAULTPATH;}intent.putExtra("path", path);startActivity(intent);}});}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.live, menu);return true;}}
播放介面的類:
package com.jwzhangjie.live;import io.vov.vitamio.LibsChecker;import io.vov.vitamio.MediaPlayer;import io.vov.vitamio.MediaPlayer.OnCompletionListener;import io.vov.vitamio.MediaPlayer.OnInfoListener;import io.vov.vitamio.widget.MediaController;import io.vov.vitamio.widget.VideoView;import android.annotation.SuppressLint;import android.app.Activity;import android.content.Context;import android.content.pm.ActivityInfo;import android.content.res.Configuration;import android.media.AudioManager;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.Display;import android.view.GestureDetector.SimpleOnGestureListener;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import android.widget.ImageView;@SuppressLint("HandlerLeak")public class JieVideoPlayer extends Activity implements OnCompletionListener, OnInfoListener {private String mPath;private String mTitle;private VideoView mVideoView;private View mVolumeBrightnessLayout;private ImageView mOperationBg;private ImageView mOperationPercent;private AudioManager mAudioManager;/** 聲音 */private int mMaxVolume;/** 當前聲音 */private int mVolume = -1;/** 當前亮度 */private float mBrightness = -1f;/** 當前縮放模式 */private int mLayout = VideoView.VIDEO_LAYOUT_ZOOM;private GestureDetector mGestureDetector;private MediaController mMediaController;private View mLoadingView;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (!LibsChecker.checkVitamioLibs(this))return;// ~~~ 擷取播放地址和標// ~~~ 繫結控制項setContentView(R.layout.videoview);mPath = getIntent().getStringExtra("path");mVideoView = (VideoView) findViewById(R.id.surface_view);mVolumeBrightnessLayout = findViewById(R.id.operation_volume_brightness);mOperationBg = (ImageView) findViewById(R.id.operation_bg);mOperationPercent = (ImageView) findViewById(R.id.operation_percent);mLoadingView = findViewById(R.id.video_loading);// ~~~ 綁定事件mVideoView.setOnCompletionListener(this);mVideoView.setOnInfoListener(this);// ~~~ 綁定資料mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);if (mPath.startsWith("http:")){mVideoView.setVideoURI(Uri.parse(mPath));}else{mVideoView.setVideoPath(mPath);}//設定顯示名稱mMediaController = new MediaController(this);mMediaController.setFileName(mTitle);mVideoView.setMediaController(mMediaController);mVideoView.requestFocus();mGestureDetector = new GestureDetector(this, new MyGestureListener());setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);}@Overrideprotected void onPause() {super.onPause();if (mVideoView != null)mVideoView.pause();}@Overrideprotected void onResume() {super.onResume();if (mVideoView != null)mVideoView.resume();}@Overrideprotected void onDestroy() {super.onDestroy();if (mVideoView != null)mVideoView.stopPlayback();}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (mGestureDetector.onTouchEvent(event))return true;// 處理手勢結束switch (event.getAction() & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_UP:endGesture();break;}return super.onTouchEvent(event);}/** 手勢結束 */private void endGesture() {mVolume = -1;mBrightness = -1f;// 隱藏mDismissHandler.removeMessages(0);mDismissHandler.sendEmptyMessageDelayed(0, 500);}private class MyGestureListener extends SimpleOnGestureListener {/** 雙擊 */@Overridepublic boolean onDoubleTap(MotionEvent e) {if (mLayout == VideoView.VIDEO_LAYOUT_ZOOM)mLayout = VideoView.VIDEO_LAYOUT_ORIGIN;elsemLayout++;if (mVideoView != null)mVideoView.setVideoLayout(mLayout, 0);return true;}/** 滑動 */@SuppressWarnings("deprecation")@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {float mOldX = e1.getX(), mOldY = e1.getY();int y = (int) e2.getRawY();Display disp = getWindowManager().getDefaultDisplay();int windowWidth = disp.getWidth();int windowHeight = disp.getHeight();if (mOldX > windowWidth * 4.0 / 5)// 右邊滑動onVolumeSlide((mOldY - y) / windowHeight);else if (mOldX < windowWidth / 5.0)// 左邊滑動onBrightnessSlide((mOldY - y) / windowHeight);return super.onScroll(e1, e2, distanceX, distanceY);}}/** 定時隱藏 */private Handler mDismissHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {mVolumeBrightnessLayout.setVisibility(View.GONE);}};/** * 滑動改變聲音大小 * * @param percent */private void onVolumeSlide(float percent) {if (mVolume == -1) {mVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);if (mVolume < 0)mVolume = 0;// 顯示mOperationBg.setImageResource(R.drawable.video_volumn_bg);mVolumeBrightnessLayout.setVisibility(View.VISIBLE);}int index = (int) (percent * mMaxVolume) + mVolume;if (index > mMaxVolume)index = mMaxVolume;else if (index < 0)index = 0;// 變更聲音mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0);// 變更進度�?ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams();lp.width = findViewById(R.id.operation_full).getLayoutParams().width * index / mMaxVolume;mOperationPercent.setLayoutParams(lp);}/** * 滑動改變亮度 * * @param percent */private void onBrightnessSlide(float percent) {if (mBrightness < 0) {mBrightness = getWindow().getAttributes().screenBrightness;if (mBrightness <= 0.00f)mBrightness = 0.50f;if (mBrightness < 0.01f)mBrightness = 0.01f;// 顯示mOperationBg.setImageResource(R.drawable.video_brightness_bg);mVolumeBrightnessLayout.setVisibility(View.VISIBLE);}WindowManager.LayoutParams lpa = getWindow().getAttributes();lpa.screenBrightness = mBrightness + percent;if (lpa.screenBrightness > 1.0f)lpa.screenBrightness = 1.0f;else if (lpa.screenBrightness < 0.01f)lpa.screenBrightness = 0.01f;getWindow().setAttributes(lpa);ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams();lp.width = (int) (findViewById(R.id.operation_full).getLayoutParams().width * lpa.screenBrightness);mOperationPercent.setLayoutParams(lp);}@Overridepublic void onConfigurationChanged(Configuration newConfig) {if (mVideoView != null)mVideoView.setVideoLayout(mLayout, 0);super.onConfigurationChanged(newConfig);}@Overridepublic void onCompletion(MediaPlayer player) {Log.e("tet", "播放完成");}private void stopPlayer() {if (mVideoView != null)mVideoView.pause();}private void startPlayer() {if (mVideoView != null)mVideoView.start();}private boolean isPlaying() {return mVideoView != null && mVideoView.isPlaying();}/** 是否�?��自動回復播放,用於自動暫停,恢複播放 */private boolean needResume;@Overridepublic boolean onInfo(MediaPlayer arg0, int arg1, int down_rate) {switch (arg1) {case MediaPlayer.MEDIA_INFO_BUFFERING_START://�?��緩衝,暫停播�?if (isPlaying()) {stopPlayer();needResume = true;}mLoadingView.setVisibility(View.VISIBLE);break;case MediaPlayer.MEDIA_INFO_BUFFERING_END://緩衝完成,繼續播�?if (needResume)startPlayer();mLoadingView.setVisibility(View.GONE);break;case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED://顯示 下載速度Log.e("test","download rate:" + down_rate);//mLoadingPerce.setText("正在緩衝�?.."+"緩衝完成�?+down_rate);//mListener.onDownloadRateChanged(arg2);break;}return true;}}
播放介面的配置:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <io.vov.vitamio.widget.VideoView android:id="@+id/surface_view" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_centerHorizontal="true" android:layout_centerVertical="true" /> <LinearLayout android:id="@+id/video_loading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center_vertical" > <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/video_loading_perce" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="7.0dip" android:text="@string/video_layout_loading" android:textColor="@color/white" android:textSize="20.0sp" /> </LinearLayout> <FrameLayout android:id="@+id/operation_volume_brightness" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="#00000000" android:orientation="horizontal" android:padding="0dip" android:visibility="invisible" > <ImageView android:id="@+id/operation_bg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/video_volumn_bg" /> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:paddingBottom="25dip" > <ImageView android:id="@+id/operation_full" android:layout_width="94dip" android:layout_height="wrap_content" android:layout_gravity="left" android:src="@drawable/video_num_bg" /> <ImageView android:id="@+id/operation_percent" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_gravity="left" android:scaleType="matrix" android:src="@drawable/video_num_front" /> </FrameLayout> </FrameLayout></RelativeLayout>
播放的顯示效果: