zoukankan      html  css  js  c++  java
  • android之VideoView和视频播放View的扩展

    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用来得到加载成功的回调,另外供外面代码调用得到视频的时长和当前时长。
  • 相关阅读:
    苹果一体机发射Wi-Fi
    iphone 屏蔽系统自动更新,消除设置上的小红点
    data parameter is nil 异常处理
    copy与mutableCopy的区别总结
    java axis2 webservice
    mysql 远程 ip访问
    mysql 存储过程小问题
    mysql游标错误
    is not writable or has an invalid setter method错误的解决
    Struts2中关于"There is no Action mapped for namespace / and action name"的总结
  • 原文地址:https://www.cnblogs.com/chengzhengfu/p/4579041.html
Copyright © 2011-2022 走看看