android之VideoView和視頻播放View的擴充

來源:互聯網
上載者:User

1.概念及擴充

  VideoView 是android 系統提供的一個媒體播放顯示和控制的控制項。其結構層次如下:

  原型:VideoView extends SurfaceView implements MediaController.MediaPlayerControl

  類結構:

      java.lang.Object
        ↳ android.view.View
          ↳ android.view.SurfaceView
            ↳ android.widget.VideoView

  通過VideoView 的原型可知:如果構建更為複雜和有特色個性的視頻View,需要繼承SurfaceView 和實現MediaPlayerControl介面。其中SurfaceView 為顯示提供支援,MediaPlayerControl則為媒體控制提供了支援。

2.案例

1)VideoView案例

(我們沒有管理MediaPalyer的各種狀態,這些狀態都讓VideoView給封裝了,並且,當VideoView建立的時候,MediaPalyer對象將會建立,當VideoView對象銷毀的時候,MediaPlayer對象將會釋放。)

布局檔案

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<VideoView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent"
android:layout_centerInParent="true" />
</LinearLayout>

主程式:

public class VideoPlayer extends Activity implements MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {
public static final String TAG = "VideoPlayer";
private VideoView mVideoView;
private Uri mUri;
private int mPositionWhenPaused = -1;

private MediaController mMediaController;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

//Set the screen to landscape.
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

mVideoView = (VideoView)findViewById(R.id.video_view);

//Video file
mUri = Uri.parse(Environment.getExternalStorageDirectory() + "/1.3gp");

//Create media controller,組件可以控制視頻的播放,暫停,回複,seek等操作,不需要你實現
mMediaController = new MediaController(this);
mVideoView.setMediaController(mMediaController);
}

public void onStart() {
// Play Video
mVideoView.setVideoURI(mUri);
mVideoView.start();

super.onStart();
}

public void onPause() {
// Stop video when the activity is pause.
mPositionWhenPaused = mVideoView.getCurrentPosition();
mVideoView.stopPlayback();

super.onPause();
}

public void onResume() {
// Resume video player
if(mPositionWhenPaused >= 0) {
mVideoView.seekTo(mPositionWhenPaused);
mPositionWhenPaused = -1;
}

super.onResume();
}

public boolean onError(MediaPlayer player, int arg1, int arg2) {
return false;
}

public void onCompletion(MediaPlayer mp) {
this.finish();
}
}

2)自訂VideoView

和VideoView實作類別似,繼承了SurfaceView並且實現了MediaPlayerControl。

public class CustomerVideoView extends SurfaceView implements 
MediaPlayerControl {
private static String TAG = "customer.videoplayer";
private boolean pause;
private boolean seekBackward;
private boolean seekForward;
private Uri videoUri;
private MediaPlayer mediaPlayer;
private Context context;
private OnPreparedListener onPreparedListener;
private int videoWidth;
private int videoHeight;
private MediaController mediaController;
protected SurfaceHolder surfaceHolder;
private Callback surfaceHolderCallback = new SurfaceHolder.Callback() {
public void surfaceChanged(SurfaceHolder holder, int format, int w,
int h) {
}
public void surfaceCreated(SurfaceHolder holder) {
surfaceHolder = holder;
if (mediaPlayer != null) {
mediaPlayer.setDisplay(surfaceHolder);
resume();
} else {
openVideo();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
surfaceHolder = null;
if (mediaController != null) {
mediaController.hide();
}
release(true);
}
};
private void release(boolean cleartargetstate) {
if (mediaPlayer != null) {
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
}
public void resume() {
if (surfaceHolder == null) {
return;
}
if (mediaPlayer != null) {
return;
}
openVideo();
}
public CustomerVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
this.initVideoView();
}
public CustomerVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.initVideoView();
}
public CustomerVideoView(Context context) {
super(context);
this.context = context;
this.initVideoView();
}
@Override
public boolean canPause() {
return this.pause;
}
@Override
public boolean canSeekBackward() {
return this.seekBackward;
}
@Override
public boolean canSeekForward() {
return this.seekForward;
}
@Override
public int getBufferPercentage() {
return 0;
}
@Override
public int getCurrentPosition() {
return mediaPlayer!=null?mediaPlayer.getCurrentPosition():0;
}
@Override
public int getDuration() {
return mediaPlayer!=null?mediaPlayer.getDuration():0;
}
@Override
public boolean isPlaying() {
return false;
}
@Override
public void pause() {
}
@Override
public void seekTo(int mSec) {
}
@Override
public void start() {
}
public void setVideoURI(Uri uri) {
this.videoUri = uri;
openVideo();
requestLayout();
invalidate();
}
private void openVideo() {
this.mediaPlayer = new MediaPlayer();
try {
this.mediaPlayer.setDataSource(this.context, this.videoUri);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
throw new RuntimeException(e);
}
this.mediaPlayer.prepareAsync();
this.mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
this.mediaPlayer.setOnPreparedListener(onPreparedListener);
attachMediaController();
}
private void attachMediaController() {
if (mediaPlayer != null && mediaController != null) {
mediaController.setMediaPlayer(this);
View anchorView = this.getParent() instanceof View ? (View) this
.getParent() : this;
mediaController.setAnchorView(anchorView);
mediaController.setEnabled(true);
}
}
public void setMediaController(MediaController controller) {
if (mediaController != null) {
mediaController.hide();
}
mediaController = controller;
attachMediaController();
}
public void setOnPreparedListener(OnPreparedListener onPreparedListener) {
this.onPreparedListener = onPreparedListener;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(videoWidth, widthMeasureSpec);
int height = getDefaultSize(videoHeight, heightMeasureSpec);
if (videoWidth > 0 && videoHeight > 0) {
if (videoWidth * height > width * videoHeight) {
height = width * videoHeight / videoWidth;
} else if (videoWidth * height < width * videoHeight) {
width = height * videoWidth / videoHeight;
}
}
Log.i(TAG, "setting size: " + width + ‘x’ + height);
setMeasuredDimension(width, height);
}
private void initVideoView() {
videoWidth = 0;
videoHeight = 0;
getHolder().addCallback(surfaceHolderCallback);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
}
}

  一般情況下,android介面的繪製和更新,要交給主ui線程來操作,通過Handler機制。但是播放視頻,需要比較優先和即時的改變和繪製介面。android提供了使用單獨線程繪製UI的機制,就是SurfaceView。使用SurfaceView,需要實現SurfaceHolder.Callback介面:

  • surfaceCreated,在Surface(SurfaceView內部包含一個Surface執行個體)建立後,會立即調用該方法,可在該方法中做繪製介面相關的初始化工作;
  • surfaceChanged,當Surface的狀態發生變化,比如大小,會調用該方法,在surfaceCreated方法調用過至少會調用一次該方法;
  • surfaceDestroyed,當銷毀Surface的時候調用。

  開發人員不能直接操作Surface執行個體,要通過SurfaceHandler,在SurfaceView中可以通過getHandler方法擷取到SurfaceHandler執行個體。
SurfaceHander有一些類型,用來標識Surface執行個體介面資料來源,可以通過setType來操作:

  • SURFACE_TYPE_NORMAL:RAM緩衝的原生資料
  • SURFACE_TYPE_HARDWARE:通過DMA,direct memory access,就是直接寫屏技術擷取到的資料,或者其他硬體加速的資料
  • SURFACE_TYPE_GPU:通過GPU加速的資料
  • SURFACE_TYPE_PUSH_BUFFERS:標識資料來源於其他對象,比如照相機,比如視頻播放伺服器(android內部有視頻播放的伺服器,所有播放視頻相當於用戶端)



  CustomerVideoView的構造方法,使用超類的構造方法。都會執行initVideoView()方法用來初始化介面和參數。另外一個主要的內容是openVideo()方法:

  • mediaPlayer.prepareAsync(),用來非同步準備播放,另外還有個prepare()方法,是同步的,也就是全部下載完畢才能播放,顯然,在播放網上視頻的時候需要用前者;
  • 通過attachMediaController()方法,把控制條附加到播放視頻的SurfaceView上,這裡實現的不完全,因此還不能使用,僅僅是把MediaPlayerControl執行個體通過setMediaPlayer方法設定一下,供OnPreparedListener用來得到載入成功的回調,另外供外面代碼調用得到視頻的時間長度和當前時間長度。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.