Android视频播放 的几种方式

来源:互联网 发布:mmd动作数据怎么用 编辑:程序博客网 时间:2024/06/16 01:20

在Android中,在做视频播放的时候,我们可以直接使用Android原生的VideoView来实现,也可以使用SurfaceView+MediaPlayer来实现,本文主要针对这两种方式进行实现。

一.VideoView实现

主要代码有:
设置VideoView的url和MediaController,然后调用start()方法,即可播放视频

videoView.setMediaController(new MediaController(this));videoView.setVideoPath(videoInfo.getFilePath());videoView.start();

可以看到非常简单,只需要短短的三行代码,就可以实现本地视频和网络视频的播放。
当然VideoView还提供一些控制视频播放的方法

pause() //让视频暂停
start() //播放开始播放
stop() //停止播放
以及一些监听方法
//缓冲进度的监听

//缓冲进度的监听videoView.setOnPreparedListener(new MyPlayOnPreparedListener());//播放完成回调videoView.setOnCompletionListener( new MyPlayerOnCompletionListener());class MyPlayerOnCompletionListener implements MediaPlayer.OnCompletionListener {        @Override        public void onCompletion(MediaPlayer mp) {            Toast.makeText( VideoViewActivity.this, "播放完成了", Toast.LENGTH_SHORT).show();        }    }    class MyPlayOnPreparedListener implements MediaPlayer.OnPreparedListener {        @Override        public void onPrepared(MediaPlayer mediaPlayer) {        }    }

使用VideoView播放视频如果视频的分辨率小于设备的屏幕分辨率,VideoVIew在播放视频的时候都是在左上角显示的,比较影响美观,解决办法也很简单,只需要在VideoView的外层嵌套一个相对布局同时设置VideoView的layout_centerInParent=”true”就可以了。

 <RelativeLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="@android:color/black">        <VideoView            android:id="@+id/videoview_view"            android:layout_centerInParent="true"            android:layout_gravity="center"            android:layout_width="match_parent"            android:layout_height="wrap_content"            /> </RelativeLayout>

效果如下:
这里写图片描述

首先是获取了本地的视频列表,左滑的话可以选择网络视频进行播放,只是加载网络视频需要费点时间,就不演示了,点击后用VideoView进行播放,可以看到VideoView本身提供了进度条,暂停,快进等功能,对于视频要求不是太大的情况下可以选择使用这种方式,使用起来比较简单
下面是完整的代码,
MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener{    private Button btVideo;    private Button btSurface;    private Button btTexture;    private TextView tvTitle;    private ViewPager viewPager;    private TabLayout tableLayout;    private String[] attr=new String[]{"本地视频","网络视频"};    private List<Fragment> fragments;    private FileFragment fileFragment;    private NetFragment netFragment;    private ViewPagerAdapter adapter;    public static int flag=0;    public static final int VIDEOVIEW_FLAG=0;    public static final int SURFACEVIEW_FLAG=1;    public static final int TEXTUREVIEW_FLAG=2;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();        initData();    }    private void initData() {        fragments=new ArrayList<>();        fileFragment=new FileFragment();        netFragment=new NetFragment();        fragments.add(fileFragment);        fragments.add(netFragment);        tableLayout.addTab(tableLayout.newTab().setText(attr[0]));        tableLayout.addTab(tableLayout.newTab().setText(attr[1]));        adapter=new ViewPagerAdapter(getSupportFragmentManager(),this,attr,fragments);        viewPager.setAdapter(adapter);        tableLayout.setupWithViewPager(viewPager);    }    private void initView() {        btVideo= (Button) findViewById(R.id.main_video);        btVideo.setOnClickListener(this);        btSurface= (Button) findViewById(R.id.main_surface);        btSurface.setOnClickListener(this);        btTexture= (Button) findViewById(R.id.main_texture);        btTexture.setOnClickListener(this);        tvTitle= (TextView) findViewById(R.id.main_title);        viewPager= (ViewPager) findViewById(R.id.main_viewpager);        tableLayout= (TabLayout) findViewById(R.id.main_tab);    }    @Override    public void onClick(View view) {        switch (view.getId()){            case R.id.main_video:                Toast.makeText(this,"切换到VideoVIew",Toast.LENGTH_SHORT).show();                flag=VIDEOVIEW_FLAG;                break;            case R.id.main_surface:                Toast.makeText(this,"切换到SurfaceView",Toast.LENGTH_SHORT).show();                flag=SURFACEVIEW_FLAG;                break;            case R.id.main_texture:                Toast.makeText(this,"切换到TextureView",Toast.LENGTH_SHORT).show();                flag=TEXTUREVIEW_FLAG;                break;        }    }}

MainActivity就是TabLayout+ViewPager 切换本地和网络视频,下面三个按钮是切换播放器。

public class FileFragment extends Fragment {    private List<VideoInfo> mData;    private VideoInfoAdapter adapter;    private RecyclerView recyclerView;    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {        View view=inflater.inflate(R.layout.fm_file,container,false);        initView(view);        initData();        return view;    }    private void initView(View view) {        recyclerView= view.findViewById(R.id.main_recycler);    }    private void initData() {        mData=new ArrayList<>();        String[] attr=new String[]{                MediaStore.MediaColumns.DATA,                BaseColumns._ID,                MediaStore.MediaColumns.TITLE,                MediaStore.MediaColumns.MIME_TYPE,                MediaStore.Video.VideoColumns.DURATION,                MediaStore.MediaColumns.SIZE        };        Cursor cursor=getActivity().getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,attr,                null,null,null);        if (cursor!=null){            while (cursor.moveToNext()){                VideoInfo info=new VideoInfo();                info.setFilePath(cursor.getString(cursor                        .getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)));                info.setMimeType(cursor.getString(cursor                        .getColumnIndexOrThrow(MediaStore.MediaColumns.MIME_TYPE)));                info.setTitle(cursor.getString(cursor                        .getColumnIndexOrThrow(MediaStore.MediaColumns.TITLE)));                info.setTime(CommTools.LongToHms(cursor.getInt(cursor                        .getColumnIndexOrThrow(MediaStore.Video.VideoColumns.DURATION))));                info.setSize(CommTools.LongToPoint(cursor                        .getLong(cursor                                .getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE))));                int id = cursor.getInt(cursor                        .getColumnIndexOrThrow(BaseColumns._ID));                BitmapFactory.Options options = new BitmapFactory.Options();                options.inDither = false;                options.inPreferredConfig = Bitmap.Config.ARGB_8888;                info.setB(MediaStore.Video.Thumbnails.getThumbnail(getActivity().getContentResolver(), id,                        MediaStore.Images.Thumbnails.MICRO_KIND, options));                mData.add(info);            }        }        adapter=new VideoInfoAdapter(getActivity(),mData);        recyclerView.setAdapter(adapter);        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));        adapter.setOnItemClickListener(new VideoInfoAdapter.OnItemClickListener() {            @Override            public void onItemClick(VideoInfo videoInfo,int position) {                Intent intent=new Intent();                intent.putExtra("VIDEO_INFO",videoInfo);                intent.putExtra("VIDEO_SORT",position+"/"+mData.size());                intent.putExtra("VIDEO_TYPE",0);                switch (MainActivity.flag){                    case MainActivity.VIDEOVIEW_FLAG:                        intent.setClass(getActivity(), VideoViewActivity.class);                        startActivity(intent);                        break;                    case MainActivity.SURFACEVIEW_FLAG:                        intent.setClass(getActivity(), SurfaceActivity.class);                        startActivity(intent);                        break;                    case MainActivity.TEXTUREVIEW_FLAG:                        break;                }            }        });    }}

主要是获取本地的视频列表集合,然后用一个RecyclerView显示。

二.SurfaceView+MediaPlayer

虽然使用ViedoView比较简单,但是如果遇上比较复杂的布局效果,自定义程度较高的话,就要用到SurfaceView+MediaPlayer这种了,使用这种方式进行视频播放可以更加灵活,使用SurfaceView进行显示,MediaPlayer和SurfaceView进行绑定,就可以显示出完整的视频了。
关于SurfaceView,从android 1.0就有了,一般来说,UI对刷新都需要在UI线程中完成,但是,surfaceview可以在非UI线程中完成刷新。拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面。由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行绘制。又由于不会占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不会导致用户输入得不到及时响应。
大神的链接,感兴趣的可以去了解一下
Android视图SurfaceView的实现原理分析

怎么使用,首先我们先设置需要播放的资源,
可以使文件、文件路径、或者URL。

 mediaPlayer.setDataSource(url);

然后设置SurfaceHolder,需要先创建SurfaceHolder,可以通过surfaceView.getHolder()取得,

holder=surfaceView.getHolder(); holder.addCallback(new SurfaceHolder.Callback() {            @Override            public void surfaceCreated(SurfaceHolder surfaceHolder) {                mediaPlayer.setDisplay(holder);            }            @Override            public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {            }            @Override            public void surfaceDestroyed(SurfaceHolder surfaceHolder) {            }        });

同时监听surfaceHolder,在surfaceholder被创建的时候,与MediaPlayer进行绑定
然后调用MediaPlayer.prepare()来准备。

 mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {        @Override        public void onPrepared(final MediaPlayer mediaPlayer) {                 /**装载完成,开始播放*/                 mediaPlayer.start();        } }

一般我们选择用异步的方式进行装载,然后在onPrePared方法里调用开始播放
下面是全部的代码,对SurfaceView进行了简单的封装,包括暂停,开始,播放进度,设置播放地址,全屏和半屏切换,状态栏的显示和隐藏等,
下面是完整的代码:

public class MysurfaceView extends SurfaceView implements        MediaPlayer.OnErrorListener        ,MediaPlayer.OnCompletionListener        ,MediaPlayer.OnVideoSizeChangedListener        ,SurfaceHolder.Callback{    private static final String TAG=MysurfaceView.class.getSimpleName();    private MediaPlayer mediaPlayer;    private SurfaceHolder holder;    /**视频播放的Url*/    private String url;    /**播放状态*/    private boolean isPlay;    /**横竖屏标识*/    private boolean screenDirection=true;    /**视频的宽高*/    private float videoHeight;    private float videoWidth;    /**系统屏幕的宽高*/    private float systemWidth;    private float systemHeight;    /**控件的宽高*/    private float surWidth;    private float surHeight;    private Context context;    public MysurfaceView(Context context) {        super(context);        init(context);    }    public MysurfaceView(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public MysurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context);    }    public interface  OnVideoPlayingListener{        void onVideoSizeChanged(int vWidth, int vHeight);        void onPlaying(int duration, int percent);        void onStart();        void onPlayOver();        void onVideoSize(int videoSize);    }    private OnVideoPlayingListener listener;    public void setOnVideoPlayingListener(OnVideoPlayingListener listener){        this.listener=listener;    }    /**设置监听*/    private void initEvent() {        /**注册当surfaceView创建、改变和销毁时应该执行的方法*/        holder.addCallback(this);        /**播放出错时的监听*/        mediaPlayer.setOnErrorListener(this);        /**播放结束时的监听*/        mediaPlayer.setOnCompletionListener(this);        /**视频尺寸的监听*/        mediaPlayer.setOnVideoSizeChangedListener(this);    }    /**初始化*/    private void init(Context context) {        this.context=context;        mediaPlayer=new MediaPlayer();        holder=this.getHolder();        /**         *  这里必须设置为SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS哦,意思         *  是创建一个push的'surface',主要的特点就是不进行缓冲         */        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);        DisplayMetrics dm = new DisplayMetrics();        ((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(dm);        systemWidth = dm.widthPixels;        systemHeight=dm.heightPixels;        initEvent();    }    /**设置全屏播放*/    public void setFullScreen(){        hideNavigationBar();        ((Activity)context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);        scaleChangeSize(systemHeight,systemWidth);    }    /**恢复半屏播放*/    public void setHalfScreen(){        showNavigationBar();        ((Activity)context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);        scaleChangeSize(surWidth,surHeight);    }    /**显示状态栏*/    private void showNavigationBar(){        View decorView =((Activity)context). getWindow().getDecorView();        decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);    }    /**隐藏状态栏*/    public void hideNavigationBar() {        int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN                | View.SYSTEM_UI_FLAG_FULLSCREEN; // hide status bar        ((Activity)context).getWindow().getDecorView().setSystemUiVisibility(uiFlags);    }    /**设置视频播放路径*/    public void setUrl(String url){        this.url=url;    }    /**暂停播放和继续播放*/    public void pause() {        if (mediaPlayer!=null){            if (mediaPlayer.isPlaying()&&isPlay==true){                mediaPlayer.pause();            }else {                mediaPlayer.start();            }        }    }    /**停止播放*/    public void stop(){        mediaPlayer.stop();    }    /**指定位置播放*/    public void seekTo(int progress){        if (mediaPlayer != null && mediaPlayer.isPlaying()) {            /**设置当前播放的位置*/            mediaPlayer.seekTo(progress);        }    }    /**销毁 回收资源*/    public void finishVideo(){        mediaPlayer.stop();        mediaPlayer.release();    }    /**等比例缩放视频*/    public void scaleChangeSize(float width,float height){        float xsca=width/videoWidth;        float ysca=height/videoHeight;        float r=min(xsca,ysca);        float w=videoWidth*r;        float h=videoHeight*r;        ViewGroup.LayoutParams params= getLayoutParams();        params.width= (int) w;        params.height= (int) h;        setLayoutParams(params);    }    /**开始播放*/    public void play(){        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);        try {            mediaPlayer.setDataSource(url);            /**异步装载*/            mediaPlayer.prepareAsync();            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {                @Override                public void onPrepared(final MediaPlayer mediaPlayer) {                    /**等比例缩放视频尺寸*/                    videoWidth=mediaPlayer.getVideoWidth();                    videoHeight=mediaPlayer.getVideoHeight();                    surWidth=getWidth();                    surHeight=getHeight();                    scaleChangeSize(surWidth,surHeight);                    mediaPlayer.start();                    listener.onVideoSize(mediaPlayer.getDuration());                    new Thread() {                        @Override                        public void run() {                            try {                                isPlay = true;                                while (isPlay) {                                    int current = mediaPlayer.getCurrentPosition();                                    Message message=Message.obtain();                                    message.what=1;                                    message.obj=current;                                    handler.sendMessage(message);                                    sleep(500);                                }                            } catch (Exception e) {                                e.printStackTrace();                            }                        }                    }.start();                    isPlay=true;                    listener.onStart();                }            });        } catch (IOException e) {            e.printStackTrace();        }    }    private Handler handler = new Handler() {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            if (msg.what == 1) {                if (listener != null ) {                    listener.onPlaying(mediaPlayer.getDuration(), (Integer) msg.obj);                    sendEmptyMessageDelayed(0, 1000);                }            }        }    };    /**播放结束的监听*/    @Override    public void onCompletion(MediaPlayer mediaPlayer) {        isPlay=false;        listener.onPlayOver();    }    /**播放错误的监听*/    @Override    public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {        isPlay=false;        return false;    }    /**视频尺寸的监听*/    @Override    public void onVideoSizeChanged(MediaPlayer mediaPlayer, int i, int i1) {        int videoW=mediaPlayer.getVideoWidth();        int videoH=mediaPlayer.getVideoHeight();        if (listener!=null){            listener.onVideoSizeChanged(videoW,videoH);        }    }    /**SurfaceHolder被创建*/    @Override    public void surfaceCreated(SurfaceHolder surfaceHolder) {        mediaPlayer.setDisplay(holder);    }    /**SurfaceHolder被改变*/    @Override    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {}    /**SurfaceHolder被销毁*/    @Override    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {}}

上面的注释都十分的详细,应该都可以看懂,对视频拉伸也做了处理,下面是Activity的代码:

public class TestSurfaceActivity extends AppCompatActivity implements View.OnClickListener{    private Intent intent;    private VideoInfo videoInfo;    private ImageView imgPlay;    private ImageView imgBack;    private SeekBar seekBar;    private TextView tvTotalTime;    private TextView tvPlayTime;    private ImageView ivAll;    private MysurfaceView mysurfaceView;    private boolean isFull;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_test_surface);        initView();        initData();        initEvent();    }    private void initEvent() {        mysurfaceView.setOnVideoPlayingListener(new MysurfaceView.OnVideoPlayingListener() {            @Override            public void onVideoSizeChanged(int vWidth, int vHeight) {            }            @Override            public void onPlaying(int duration, int percent) {                Log.i("surface","播放进度"+"总时长"+duration+" 当前播放进度"+percent);                seekBar.setMax(duration);                seekBar.setProgress(percent);                tvPlayTime.setText(CommTools.LongToHms(percent));            }            @Override            public void onStart() {                Toast.makeText(TestSurfaceActivity.this,"开始播放",Toast.LENGTH_SHORT).show();            }            @Override            public void onPlayOver() {                finish();            }            /**播放总时长*/            @Override            public void onVideoSize(int videoSize) {                tvTotalTime.setText(CommTools.LongToHms(videoSize));                seekBar.setMax(videoSize);            }        });        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {            @Override            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {            }            @Override            public void onStartTrackingTouch(SeekBar seekBar) {            }            @Override            public void onStopTrackingTouch(SeekBar seekBar) {                /**当进度条停止修改的时候触发*/                /**取得当前进度条的刻度*/                int progress = seekBar.getProgress();                /**设置当前播放的位置*/                mysurfaceView.seekTo(progress);                tvPlayTime.setText(""+CommTools.LongToHms(progress));            }        });    }    private void initData() {        intent=getIntent();        videoInfo=intent.getParcelableExtra("VIDEO_INFO");        mysurfaceView.setUrl(videoInfo.getFilePath());    }    private void initView() {        imgBack= (ImageView) findViewById(R.id.test_sur_iv_back);        imgBack.setOnClickListener(this);        imgPlay= (ImageView) findViewById(R.id.test_sur_iv_play);        imgPlay.setOnClickListener(this);        ivAll= (ImageView) findViewById(R.id.test_sur_iv_full);        ivAll.setOnClickListener(this);        seekBar= (SeekBar) findViewById(R.id.test_sur_seekbar);        tvTotalTime= (TextView) findViewById(R.id.test_sur_tv_total_time);        tvPlayTime= (TextView) findViewById(R.id.test_sur_tv_start_time);        mysurfaceView= (MysurfaceView) findViewById(R.id.test_sur_view);    }    @Override    protected void onResume() {        super.onResume();        mysurfaceView.setUrl(videoInfo.getFilePath());        mysurfaceView.play();    }    @Override    public void finish() {        super.finish();        mysurfaceView.finishVideo();    }    @Override    public void onClick(View view) {        switch (view.getId()){            case R.id.test_sur_iv_back:                finish();                break;            case R.id.test_sur_iv_play:                mysurfaceView.pause();                break;            case R.id.test_sur_iv_full:                isFull();                break;        }    }    public void isFull(){        if (isFull){            mysurfaceView.setHalfScreen();            isFull=false;        }else {            mysurfaceView.setFullScreen();            isFull=true;        }    }}

主要是对当前的播放时间和进度,进行实时监听,同时还有全屏切换的功能,
主要功能就是这些的,
下面是效果图
这里写图片描述

因为是模拟器,所以切横竖屏的时候屏幕会变成横向,演示的效果不会太好,
下面是完整的Demo:
http://download.csdn.net/download/tzl0322/9941551
有分的支持一下,没分的可以到我的GitHub上下载:
https://github.com/ZhiLiangT/AndroidVideo

原创粉丝点击