android直播之流媒体开发(转载)
关于直播的相关信息这里不做详解,我们对直播应该很熟悉,实现生活中有各种直播,他们 如何实现的呢,其实开发一个简单不能简单的直播,只需要两个: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;
- @Override
- protected 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() {
- @Override
- public 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);
- }
- });
- }
- @Override
- public 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;
- @Override
- public 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);
- }
- @Override
- protected void onPause() {
- super.onPause();
- if (mVideoView != null)
- mVideoView.pause();
- }
- @Override
- protected void onResume() {
- super.onResume();
- if (mVideoView != null)
- mVideoView.resume();
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (mVideoView != null)
- mVideoView.stopPlayback();
- }
- @Override
- public 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 {
- /** 双击 */
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- if (mLayout == VideoView.VIDEO_LAYOUT_ZOOM)
- mLayout = VideoView.VIDEO_LAYOUT_ORIGIN;
- else
- mLayout++;
- if (mVideoView != null)
- mVideoView.setVideoLayout(mLayout, 0);
- return true;
- }
- /** 滑动 */
- @SuppressWarnings("deprecation")
- @Override
- public 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() {
- @Override
- public 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);
- }
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- if (mVideoView != null)
- mVideoView.setVideoLayout(mLayout, 0);
- super.onConfigurationChanged(newConfig);
- }
- @Override
- public 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;
- @Override
- public 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>
播放的显示效果: