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用来得到加载成功的回调,另外供外面代码调用得到视频的时长和当前时长。
  • 相关阅读:
    EntityFramework Core Raw Query再叙注意事项后续
    EntityFramework Core 1.1有哪些新特性呢?我们需要知道
    ASP.NET Core MVC/WebAPi如何构建路由?
    EntityFramework Core解决并发详解
    EntityFramework Core Raw Query再叙注意事项
    EntityFramework Core Raw SQL
    ASP.NET Core MVC/WebAPi 模型绑定探索
    EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
    EntityFramework Core 1.1是如何创建DbContext实例的呢?
    神马玩意,EntityFramework Core 1.1又更新了?走,赶紧去围观
  • 原文地址:https://www.cnblogs.com/chengzhengfu/p/4579041.html
Copyright © 2011-2022 走看看