Android視頻播放-SurfaceView和Mediaplayer


好幾天沒寫博客了,處理了一點個人私事加上平時加班,基本上時間不充裕,上篇文章講了一下用Mediaplayer來播放音樂,這次就講講使用Mediaplayer來和SurfaceView配合播放一個視頻流媒體。MediaPlayer不僅可以播放視頻,還可以與SurfaceView的配合,SurfaceView主要用於顯示MediaPlayer播放的視頻流媒體的畫面渲染,兩者可以一起協同播放視頻。

基礎維護

先來看下要實現的界面:

 

如果你看過上篇文章,就發現其實很簡單的就是多了一個進度條,還有一個就是SurfaceView,就是下面那塊黑色區域;

布局文件代碼:

<LinearLayout 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:orientation="vertical"
    tools:context="com.example.googlevideo.MainActivity" >

    <EditText
        android:id="@+id/edit_musicPath"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="輸入MV的路徑" />

    <SeekBar
        android:id="@+id/seekBar_video"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btn_Play"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="playEvent"
            android:text="播放" />

        <Button
            android:id="@+id/btn_Pause"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="pauseEvent"
            android:text="暫停" />

        <Button
            android:id="@+id/btn_Stop"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="stopEvent"
            android:text="停止" />

        <Button
            android:id="@+id/btn_Replay"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="replayEvent"
            android:text="重播" />
    </LinearLayout>

    <SurfaceView
        android:id="@+id/surface_video"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

 Demo實現

實現Demo之前應該講講視頻播放的原理,先確定視頻的格式,這個和解碼相關,不同的格式視頻編碼不同,然后通過編碼格式進行解碼,最后得到一幀一幀的圖像,並把這些圖像快速的顯示在界面上,即為播放一段視頻。SurfaceView在Android中就是完成這個功能的。SurfaceView是配合MediaPlayer使用的,MediaPlayer也提供了相應的方法設置SurfaceView顯示圖片,只需要為MediaPlayer指定SurfaceView顯示圖像即可。它的完整簽名:void setDisplay(SurfaceHolder sh)。它需要傳遞一個SurfaceHolder對象,SurfaceHolder可以理解為SurfaceView裝載需要顯示的一幀幀圖像的容器,它可以通過SurfaceHolder.getHolder()方法獲得。使用MediaPlayer配合SurfaceView播放視頻的步驟與播放使用MediaPlayer播放MP3大體一致,只需要額外設置顯示的SurfaceView即可。

先准備一段能播放的視頻:

 

播放視頻效果圖:

代碼如下:

	editText = (EditText) findViewById(R.id.edit_musicPath);
		 pathString = editText.getText().toString().trim();
		File file = new File(pathString);
		if (file.exists()) {
			try {
				mediaPlayer = new MediaPlayer();
				mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
				mediaPlayer.setDataSource(pathString);
				//通過SurfaceView獲取的Holder
				mediaPlayer.setDisplay(holder);
				mediaPlayer.prepare();
				mediaPlayer.start();
				btn_PlayButton.setEnabled(false);
				//設置Bar的最大值
				int max=mediaPlayer.getDuration();
				seekBarVideo.setMax(max);
				//定時器更新進度條
				timer=new  Timer();
				timeTask=new TimerTask() {
					
					@Override
					public void run() {
						// TODO Auto-generated method stub
						seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
					}
				};		
				timer.schedule(timeTask, 0, 500);
				//視頻播放完之后重新設置顯示
				mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
					
					@Override
					public void onCompletion(MediaPlayer mp) {
						// TODO Auto-generated method stub
						btn_PlayButton.setEnabled(true);
					}
				});

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else {
			Toast.makeText(this, "Sorry,你輸入的路徑有問題,請仔細檢查", Toast.LENGTH_SHORT)
					.show();
		}

   SeekBar的使用: 

	//設置Bar的最大值
				int max=mediaPlayer.getDuration();
				seekBarVideo.setMax(max);
				//定時器更新進度條
				timer=new  Timer();
				timeTask=new TimerTask() {
					
					@Override
					public void run() {
						// TODO Auto-generated method stub
						seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
					}
				};		
				timer.schedule(timeTask, 0, 500);

 其中holder是SurfaceHolder,在onCreate中獲取:

	surfaceView = (SurfaceView) findViewById(R.id.surface_video);
		holder = surfaceView.getHolder();
		//兼容4.0以后的手機版本,本身是不維護的
		holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

 如果正在播放視頻,最小化的時候是會有聲音的,需要在回調函數中處理一下:

		holder.addCallback(new Callback() {
			

			@Override
			public void surfaceDestroyed(SurfaceHolder holder) {
				// TODO Auto-generated method stub
				Log.i(tag, "銷毀了Holder");
				if (mediaPlayer!=null&&mediaPlayer.isPlaying()) {
					currentPosition=mediaPlayer.getCurrentPosition();
					mediaPlayer.stop();
					mediaPlayer.release();
					mediaPlayer=null;
					timer.cancel();
					timeTask.cancel();
					timer=null;
					timeTask=null;
				}
			}
			
			@Override
			public void surfaceCreated(SurfaceHolder holder) {
				// TODO Auto-generated method stub
				Log.i(tag,"創建了Holder");
				if (currentPosition>0) {
					try {
						mediaPlayer = new MediaPlayer();
						mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
						mediaPlayer.setDataSource(pathString);
						//通過SurfaceView獲取的Holder
						mediaPlayer.setDisplay(holder);
						mediaPlayer.prepare();
						mediaPlayer.start();
						mediaPlayer.seekTo(currentPosition);
						btn_PlayButton.setEnabled(false);
						//視頻播放完之后重新設置顯示
						mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

									@Override
									public void onCompletion(MediaPlayer mp) {
										// TODO Auto-generated method stub
										btn_PlayButton.setEnabled(true);
									}
								});
						
						int max=mediaPlayer.getDuration();
						seekBarVideo.setMax(max);
						//定時器更新進度條
						timer=new  Timer();
						timeTask=new TimerTask() {
							
							@Override
							public void run() {
								// TODO Auto-generated method stub
								seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
							}
						};		
						timer.schedule(timeTask, 0, 500);
					} catch (Exception e) {
						// TODO: handle exception
					}
				}
			}
			
			@Override
			public void surfaceChanged(SurfaceHolder holder, int format, int width,
					int height) {
				// TODO Auto-generated method stub
				Log.i(tag,"改變了Holder");
			}
		});

  進度條是SeekBar,如果需要快進或者后退的時候是需要將焦點賦值給mediaPlayer的:

	seekBarVideo=(SeekBar) findViewById(R.id.seekBar_video);
		seekBarVideo.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
			
			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
				// TODO Auto-generated method stub
				int position=seekBar.getProgress();
				if (mediaPlayer!=null&&mediaPlayer.isPlaying()) {
					mediaPlayer.seekTo(position);
				}
			}
			
			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void onProgressChanged(SeekBar seekBar, int progress,
					boolean fromUser) {
				// TODO Auto-generated method stub
				
			}
		});

  暫停事件:

	public void pauseEvent(View view) {
		if (btn_PauseButton.getText().equals("繼續")) {
			mediaPlayer.start();
			btn_PauseButton.setText("暫停");
			return;
		}
		if (mediaPlayer != null && mediaPlayer.isPlaying()) {
			mediaPlayer.pause();
			btn_PauseButton.setText("繼續");
		}
	}

 停止事件:

	public void stopEvent(View view) {
		if (mediaPlayer != null && mediaPlayer.isPlaying()) {
			btn_PlayButton.setEnabled(true);
			mediaPlayer.stop();
			// 釋放mediaplayer否則的話會占用內存
			mediaPlayer.release();
			mediaPlayer = null;
		}
		btn_PauseButton.setText("暫停");
		btn_PlayButton.setEnabled(true);
	}

  重播事件:

	public void replayEvent(View view) {
		surfaceView.setVisibility(View.VISIBLE);
		if (mediaPlayer != null && mediaPlayer.isPlaying()) {
			mediaPlayer.seekTo(0);
		} else {
			playEvent(view);
		}
		// 重播的時候應該設置播放的狀態
		btn_PlayButton.setEnabled(true);
	}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM