码迷,mamicode.com
首页 > 其他好文 > 详细

MediaPlayer+surfaceView实现视频播放器

时间:2015-08-13 18:09:25      阅读:130      评论:0      收藏:0      [点我收藏+]

标签:

最近项目中要用到视频播放器,就先写了个Demo,在写的过程中遇到些问题,来和大家分享一下:

1.Demo是基于Android电视的,因此与Android手机有点区别,但问题不大

2.MediaPlayer有个Bug,当视频播放完后getDuration(获取视频总时间)和getCurrentPosition(获取视频当前播放时间)方法获取到的数字不一样,相差300ms左右,如果单纯的播放不受影响,但是如果需要显示播放进度或播放时间就会有点小麻烦,暂时还没找到好的方法,只能在视频播放结束时处理时间,如果你们有好的方法也可以交流一下。

3.项目要实现显示当前时间的TextView与进度条同步移动,界面添加一个ViewGroup,然后在ViewGroup中放置TextView,通过TextView的Layout方法就能实现TextView的同步移动。

代码的解析挺详细,下面我就直接粘代码:

主Activity:

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

import com.example.play.R;
import com.luluvideo.view.TextMoveLayout;

import android.app.Activity;
import android.content.Intent;
import android.content.res.AssetManager;
import android.graphics.Color;
import android.graphics.Typeface;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener {

	private SurfaceView videoSurfaceView;// 视频播放器
	private MediaPlayer mediaPlayer;// 视频播放控制器
	private ImageView videoStart;// 播放
	private ImageView videoForward;// 快进
	private ImageView videoBack;// 快退
	private ImageView videoReport;// 举报视频
	private LinearLayout seekLayout;
	private LinearLayout videoProgress;
	private ProgressBar progressBar;// 视频进度条
	private TextView totalTime;// 播放总时间
	private View view;// 记忆获取焦点控件
	private TextView movieName;// 电影名字
	private TextView currentTime;// 当前播放时间
	private ViewGroup.LayoutParams layoutParams;
	private TextMoveLayout textMoveLayout;// 放置当前时间控件的ViewGroup

	private int screenWidth;// 屏幕宽度
	private Typeface roboto;// 自定义Roboto字体
	private float moveStep = 0;// 当前时间控件移动步长
	private SimpleDateFormat formatter;// 转换时间格式的类
	private SimpleDateFormat hourFormatter;
	private boolean isPlaying = true;// 视频播放状态标识
	private boolean isVisible = false;// 视频进度条隐藏或显示标识
	private boolean hourOrMin = false;
	private boolean threadRunning = true;
	private int postion = 0;
	private String uri = null;
	private AlphaAnimation animation_appear;// 进度条显现动画
	private AlphaAnimation animation_daiappear;// 进度条消失动画
	private float progressLength = 0;// 进度条相对长度
	private Thread thread = null;

	private MyTimerTask task;

	public static int PROGRESS_VISUBLE = 0;
	public static int PROGRESS_RATE = 1;

	public int i = 0;

	private Timer timer;

	/**
	 * 刷新进度条和当前时间
	 */
	private Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			if (msg.what == PROGRESS_RATE) {
				// 显示进度条
				progressBar.setProgress((Integer) msg.obj);
				// 设置当前时间
				currentTime.layout((int) ((Integer) msg.obj * moveStep), 0,
						(int) (screenWidth), 80);
				if (hourOrMin) {
					currentTime
							.setText(hourFormatter.format((Integer) msg.obj));
				} else {
					currentTime.setText(formatter.format((Integer) msg.obj));
				}
			} else if (msg.what == PROGRESS_VISUBLE) {
				Log.e("timer", msg.obj + "");
				if ((Integer) msg.obj == 4) {

					view = getCurrentFocus();
					// videoProgress
					// .setAnimation(animationAppear(animation_appear));
					// videoProgress.setVisibility(View.GONE);
					seekLayout.setAnimation(animationAppear(animation_appear));
					seekLayout.setVisibility(View.GONE);
					isVisible = false;
					timer.cancel();
				}

			}
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN); // 全屏
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 应用运行时,保持屏幕高亮,不锁屏

		initData();
		initView();
		getparams();

		movieName.setText("大圣归来");

	}

	private void getparams() {
		// TODO Auto-generated method stub
		Intent intent = getIntent();
	}

	private void initData() {
		// TODO Auto-generated method stub
		screenWidth = getWindowManager().getDefaultDisplay().getWidth();
		progressLength = (float) (screenWidth * 0.625);
		formatter = new SimpleDateFormat("mm:ss");// 初始化Formatter的转换格式。
		formatter.setTimeZone(TimeZone.getTimeZone("GMT+00:00"));
		hourFormatter = new SimpleDateFormat("HH:mm:ss");// 初始化Formatter的转换格式。
		hourFormatter.setTimeZone(TimeZone.getTimeZone("GMT+00:00"));
		mediaPlayer = new MediaPlayer();
		layoutParams = new ViewGroup.LayoutParams((int) (screenWidth), 20);
		uri = "android.resource://" + getPackageName() + "/" + R.raw.test;
		AssetManager mgr = getAssets();// 得到AssetManager
		roboto = Typeface.createFromAsset(mgr, "fonts/roboto.ttf");// 根据路径得到Typeface
		isPlaying = true;
		isVisible = false;
		hourOrMin = false;
		threadRunning = true;
	}

	private void initView() {
		videoSurfaceView = (SurfaceView) findViewById(R.id.videoSurfaceView);
		videoSurfaceView.getHolder().setKeepScreenOn(true);
		videoSurfaceView.getHolder().addCallback(new SurfaceViewVideo());

		currentTime = new TextView(this);
		currentTime.setTextColor(Color.rgb(255, 255, 255));
		currentTime.setTextSize(12);
		currentTime.setTypeface(roboto);

		videoProgress = (LinearLayout) findViewById(R.id.vedioProgress);
		videoStart = (ImageView) videoProgress.findViewById(R.id.videoStart);
		videoForward = (ImageView) videoProgress
				.findViewById(R.id.videoForward);
		videoBack = (ImageView) videoProgress.findViewById(R.id.videoBack);
		videoReport = (ImageView) videoProgress.findViewById(R.id.videoReqort);
		progressBar = (ProgressBar) videoProgress
				.findViewById(R.id.videoProgress);
		totalTime = (TextView) videoProgress.findViewById(R.id.videoTotal);
		movieName = (TextView) findViewById(R.id.movieName);
		seekLayout = (LinearLayout) findViewById(R.id.seekLayout);
		movieName.setTypeface(roboto);
		totalTime.setTypeface(roboto);
		videoStart.setFocusable(true);
		videoStart.requestFocus();
		videoStart.setOnClickListener(this);
		videoForward.setFocusable(true);
		videoForward.setOnClickListener(this);
		videoBack.setFocusable(true);
		videoBack.setOnClickListener(this);
		videoReport.setFocusable(true);
		videoReport.setOnClickListener(this);
		videoProgress.findViewById(R.id.videoForward).setOnClickListener(this);
		videoProgress.findViewById(R.id.videoBack).setOnClickListener(this);
		videoProgress.findViewById(R.id.videoReqort).setOnClickListener(this);
		textMoveLayout = (TextMoveLayout) videoProgress
				.findViewById(R.id.videoCurrent);
		textMoveLayout.addView(currentTime, layoutParams);
		currentTime.layout(0, 0, (int) (screenWidth), 80);

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	/**
	 * 设置播放文件
	 */
	public void play() throws IllegalArgumentException, SecurityException,
			IllegalStateException, IOException {
		mediaPlayer.reset();
		mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
		mediaPlayer.setDataSource(MainActivity.this, Uri.parse(uri));
		// 把视频输出到SurfaceView上
		mediaPlayer.setDisplay(videoSurfaceView.getHolder());
		mediaPlayer.prepare();
		mediaPlayer.start();
		progressBar.setMax(mediaPlayer.getDuration());
		moveStep = (float) ((progressLength / (float) mediaPlayer.getDuration()));
		// 开启进度刷新线程
		thread = new Thread(runnable);
		thread.start();
	}

	private Animation animationAppear(Animation animation) {
		animation = new AlphaAnimation(1.0f, 0.0f);
		animation.setDuration(1000);
		animation.setFillAfter(true);
		return animation;
	}

	private Animation animationDiaappear(Animation animation) {
		animation = new AlphaAnimation(0.0f, 1.0f);
		animation.setDuration(1000);
		animation.setFillAfter(true);
		return animation;
	}

	/*
	 * SurfaceHolder可以调用 SurfaceView播放视频
	 */

	private class SurfaceViewVideo implements SurfaceHolder.Callback {

		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {

		}

		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			if (postion == 0) {
				try {
					play();
					mediaPlayer.seekTo(postion);
					if (mediaPlayer.getDuration() >= 3600000) {
						totalTime.setText(hourFormatter.format(mediaPlayer
								.getDuration()));
						hourOrMin = true;
					} else {
						totalTime.setText(formatter.format(mediaPlayer
								.getDuration()));
						hourOrMin = false;
					}
					// totalTime.setText(formatter.format(3600000));
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (SecurityException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalStateException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}

		}

		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {

		}

	}

	@Override
	protected void onPause() {
		if (mediaPlayer.isPlaying()) {
			// 保存当前播放的位置
			postion = mediaPlayer.getCurrentPosition();
			mediaPlayer.stop();
		}
		super.onPause();
	}

	@Override
	protected void onDestroy() {
		if (thread != null) {
			threadRunning = false;
			thread = null;
		}
		if (mediaPlayer.isPlaying()) {
			mediaPlayer.stop();
		}
		mediaPlayer.release();

		super.onDestroy();
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.videoForward:
			mediaGo();
			break;
		case R.id.videoBack:
			mediaBack();
			break;
		case R.id.videoStart:
			mediaPlay();
			break;
		case R.id.videoReqort:
			mediaReport();
			break;
		default:
			break;
		}

	}

	// 视频快进
	private void mediaGo() {

	}

	// 视频快退
	private void mediaBack() {

	}

	// 视频举报
	private void mediaReport() {

	}

	private void startTimer() {
		i = 0;
		if (timer != null) {
			if (task != null) {
				task.cancel(); // 将原任务从队列中移除
				timer.cancel();
			}
		}
		task = new MyTimerTask(); // 新建一个任务
		timer = new Timer(true);
		timer.schedule(task, 1000, 1000); // 延时1000ms后执行,1000ms执行一次
	}

	// 视频播放
	private void mediaPlay() {
		if (isPlaying) {
			mediaPlayer.pause();
			videoStart.setImageResource(R.drawable.video_pause_style);
			isPlaying = false;
		} else {
			mediaPlayer.start();
			videoStart.setImageResource(R.drawable.video_start_style);
			isPlaying = true;
		}
	}

	// 定义遥控按键

	@Override
	public boolean dispatchKeyEvent(KeyEvent event) {
		// TODO Auto-generated method stub
		if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
				&& event.getAction() == KeyEvent.ACTION_DOWN && isVisible) {

			view = getCurrentFocus();
			seekLayout.setAnimation(animationAppear(animation_appear));
			isVisible = false;
			seekLayout.setVisibility(View.GONE);
			if (timer != null) {
				if (task != null) {
					task.cancel(); // 将原任务从队列中移除
					timer.cancel();
				}
			}
			return true;

		} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN
				&& event.getAction() == KeyEvent.ACTION_DOWN && !isVisible) {

			if (view != null) {
				view.setFocusable(true);
				view.requestFocus();
			}
			seekLayout.setAnimation(animationDiaappear(animation_daiappear));
			isVisible = true;
			seekLayout.setVisibility(View.VISIBLE);
			startTimer();
			return true;
		} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT
				&& event.getAction() == KeyEvent.ACTION_DOWN && isVisible) {
			startTimer();
		} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT
				&& event.getAction() == KeyEvent.ACTION_DOWN && isVisible) {
			startTimer();
		}
		return super.dispatchKeyEvent(event);
	}

	/**
	 * 
	 */

	private Runnable runnable = new Runnable() {

		@Override
		public void run() {

			while (threadRunning
					&& mediaPlayer.getCurrentPosition() < mediaPlayer
							.getDuration()) {
				Message msg = handler.obtainMessage();
				msg.what = PROGRESS_RATE;
				msg.obj = mediaPlayer.getCurrentPosition();
				Log.e("currentPosition", mediaPlayer.getCurrentPosition() + "");
				handler.sendMessage(msg);
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	};

	class MyTimerTask extends TimerTask {
		@Override
		public void run() {
			Message message = new Message();
			message.what = PROGRESS_VISUBLE;
			message.obj = ++i;
			handler.sendMessage(message);
		}
	}

}
自定义的ViewGroup:

import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;

/**
 * 
 * @author YiWei
 * TextMoveLayout用来放置显示时间的TextView,从而实现时间随进度条移动
 *
 */
public class TextMoveLayout extends ViewGroup {

	public TextMoveLayout(Context context) {
		super(context);
	}

	public TextMoveLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public TextMoveLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	/**
	 * onLayout用来布局子控件,实时调用onLayout就可以改变子布局位置
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {

	}

}

布局文件

<FrameLayout 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"
    tools:context=".MainActivity" >

    <SurfaceView
        android:id="@+id/videoSurfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    
    <LinearLayout
        android:id="@+id/seekLayout" 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center_horizontal"
        android:orientation="vertical"
        android:visibility="visible">
    
    <TextView 
        android:id="@+id/movieName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/movie_name_bottom"
        android:layout_marginLeft="@dimen/movie_name_left"
        android:textColor="@color/movie_name_color"
        android:textSize="@dimen/movie_name_size"
        android:shadowColor="@color/movie_name_back"
        android:shadowDx="4"
        android:shadowDy="4"
        android:shadowRadius="2"/>

    <include
        android:id="@+id/vedioProgress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/progress_bottom"
        android:layout_marginLeft="@dimen/movie_name_left"
        android:layout_marginRight="@dimen/progress_right"
        layout="@layout/video_progress_layout"
        android:background="@color/progress_back"
         />
    
    </LinearLayout>

</FrameLayout>

进度条布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:background="@color/progress_back"
    android:orientation="horizontal"
    android:weightSum="1668" >

    <ImageView
        android:id="@+id/videoBack"
        android:layout_width="@dimen/video_start_width"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/video_start_top"
        android:layout_weight="60"
        android:src="@drawable/video_back_style" />

    <ImageView
        android:id="@+id/videoStart"
        android:layout_width="@dimen/video_start_width"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/video_start_left"
        android:layout_marginTop="@dimen/video_start_top"
        android:layout_weight="60"
        android:src="@drawable/video_start_style" />

    <ImageView
        android:id="@+id/videoForward"
        android:layout_width="@dimen/video_start_width"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/video_start_left"
        android:layout_marginTop="@dimen/video_start_top"
        android:layout_weight="60"
        android:src="@drawable/video_forward_style" />

    <ImageView
        android:id="@+id/videoReqort"
        android:layout_width="@dimen/video_start_width"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/video_start_left"
        android:layout_marginTop="@dimen/video_start_top"
        android:layout_weight="60"
        android:src="@drawable/video_report_style" />

    <LinearLayout
        android:layout_width="@dimen/video_start_width"
        android:layout_height="wrap_content"
        android:layout_weight="1268"
        android:orientation="vertical" >

        <com.luluvideo.view.TextMoveLayout
            android:id="@+id/videoCurrent"
            android:layout_width="match_parent"
            android:layout_height="@dimen/text_move_height" />

        <ProgressBar
            android:id="@+id/videoProgress"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="@dimen/progressbar_height"
            android:layout_marginLeft="@dimen/progressbar_left"
            android:layout_marginRight="@dimen/progressbar_right"
            android:layout_marginTop="@dimen/progressbar_top"
            android:max="100"
            android:progressDrawable="@drawable/video_progress_style"
             />
    </LinearLayout>

    <TextView
        android:id="@+id/videoTotal"
        android:layout_width="@dimen/video_start_width"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="@dimen/video_total_time_left"
        android:layout_marginTop="@dimen/video_total_time_top"
        android:layout_weight="100"
        android:textColor="#ffffff"
        android:textSize="@dimen/video_total_time_size"/>

</LinearLayout>

由于特殊原因不能上传项目,把视频文放到raw文件下(最好MP4,有的格式MediaPlayer不识别),有不懂的可以回复交流。


版权声明:本文为博主原创文章,未经博主允许不得转载。

MediaPlayer+surfaceView实现视频播放器

标签:

原文地址:http://blog.csdn.net/beefandpotatoes/article/details/47614239

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!