昨天,在网上找了好多资料,终于做了一个自定义的播发器。

视频播放方式

在Android中播放视频的方式有两种:
1、使用MediaPlayer结合SurfaceView进行播放。其中通过SurfaceView显示视频的画面,通过MediaPlayer来设置播放参数、并控制视频的播放操作。
该方式的好处是灵活性强,可随意定制。缺点是编码复杂,连开始/暂停的按钮都要自己实现。
2、使用VideoView结合MediaController进行播放。VideoView其实是从SurfaceView扩展而来,并在内部集成了MediaPlayer,从而实现视频画面与视频操作的统一管理;而MediaController则是一个简单的播放控制条,它实现了基本的控制按钮,如开始/暂停按钮、上一个/下一个按钮、快进/快退按钮,以及进度条等控件;把VideoView与MediaController关联起来,便是一个类似于Window Media Player的精简版播放器。
该方式的好处是简单易用,编码容易。缺点是可定制差,难以扩展,想给按钮换个样式都不行。

一。自定义一个activity继承SurfaceHolder和SeekBarMediaPlayer的所以接口。然后初始化界面。

package com.mymp4player;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.HashMap;

/**
 * 创建:dongshuaijun
 * 日期:2016/7/1
 * 注释:视屏播放
 */
public class MainActivity extends Activity implements SurfaceHolder.Callback, View.OnClickListener
        , SeekBar.OnSeekBarChangeListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener,
        MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnSeekCompleteListener {//surfaceView
    private SurfaceView surfaceView;
    //视频最外层layout
    private RelativeLayout videoLayout;
    //控制台layout
    private LinearLayout controlLayout;
    //播放、全屏button
    private ImageButton playBtn, screenBtn;
    //进度条
    private SeekBar seekBar;
    //加载视频进度progressBar
    private ProgressBar progressBar;
    //当前时间,总时间
    private TextView currTime, countTime;
    //surface holder
    private SurfaceHolder mHolder;
    //媒体控制 mediaPlayer
    private MediaPlayer mediaPlayer;
    //是否全屏
    private boolean isFullScreen = false;
    //是否正在播放
    private boolean isPlay = false;
    //控制台是否显示
    private boolean isControl = false;
    //是否正在拖动seekBar
    private boolean isSetProgress = false;
    //是否播放完成
    private boolean isPlayCom = false;
    //是否是第一次加载视频
    private boolean isFirstLoadVideo = true;
    //是否销毁activity
    private boolean isOnDestroy = false;
    //是否可见
    private boolean isPause = false;
    //媒体音量管理
    private AudioManager audioManager;
    //点击纵坐标
    private float dY = 0;
    //点击横坐标
    private float dX = 0;
    //抬起纵坐标
    private float uY = 0;
    //抬起横坐标
    private float uX = 0;
    //屏幕当前亮度
    private float f = 0;
    //手机当前亮度模式 0 1
    private int countLight;
    //系统当前亮度 1-255
    private int currLight;

    private String width, height;

    private static final int HIDE_CONTROL_LAYOUT = -1;
    //这个地址是我抓的某平台的,我发现这个地址是变化的,所以有可能不能使用,如果不能播放,换个正常的就可以运行了,不要用模拟器运行
    private static final String BASE_STORAGE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
    public static final String RECORD_VIDEO_PATH = BASE_STORAGE_PATH + "/p2pviewcam/videos/";
    private static final String VIDEO_URL = RECORD_VIDEO_PATH+"BZWYZN-031016-CBGTK_2017_06_12_17_01_37_CH_1.mp4";
    private Handler handler = new Handler() {@Override
        public void handleMessage(Message msg) {super.handleMessage(msg);
            if (msg.what == HIDE_CONTROL_LAYOUT) {refreshControlLayout();
            } else {currTime.setText(formatTime(msg.what));
                seekBar.setProgress(msg.what);
            }}};

    @Override
    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initVideoSize();
        initSurface();
        setListener();

    }private void initView() {surfaceView = (SurfaceView) findViewById(R.id.surface_view);
        videoLayout = (RelativeLayout) findViewById(R.id.video_layout);
        controlLayout = (LinearLayout) findViewById(R.id.control_layout);
        playBtn = (ImageButton) findViewById(R.id.playBtn);
        screenBtn = (ImageButton) findViewById(R.id.screenBtn);
        seekBar = (SeekBar) findViewById(R.id.seekBar);
        progressBar = (ProgressBar) findViewById(R.id.load_bar);
        currTime = (TextView) findViewById(R.id.curr_time);
        countTime = (TextView) findViewById(R.id.count_time);
        mHolder = surfaceView.getHolder();
        mediaPlayer = new MediaPlayer();
        audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        initScreenLight();
        refreshControlLayout();
    }//初始化屏幕亮度
    private void initScreenLight() {try {//获取亮度模式 0:手动 1:自动
            countLight = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE);
            //设置手动设置
            Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
            //获取屏幕亮度,获取失败则返回255
            currLight = android.provider.Settings.System.getInt(getContentResolver(),
                    android.provider.Settings.System.SCREEN_BRIGHTNESS,
                    255);
            f = currLight / 255f;
        } catch (Settings.SettingNotFoundException e) {e.printStackTrace();
        }}//刷新控制台 显示则隐藏 隐藏则显示 并5S之后隐藏
    private void refreshControlLayout() {if (isControl) {controlLayout.setVisibility(View.INVISIBLE);
            isControl = false;
        } else {controlLayout.setVisibility(View.VISIBLE);
            isControl = true;
            handler.removeMessages(HIDE_CONTROL_LAYOUT);
            handler.sendEmptyMessageDelayed(HIDE_CONTROL_LAYOUT, 5000);
        }}private void setListener() {playBtn.setOnClickListener(this);
        screenBtn.setOnClickListener(this);
        seekBar.setOnSeekBarChangeListener(this);
        mediaPlayer.setOnCompletionListener(this);
        mediaPlayer.setOnErrorListener(this);
        mediaPlayer.setOnBufferingUpdateListener(this);
        mediaPlayer.setOnPreparedListener(this);
        mediaPlayer.setOnSeekCompleteListener(this);
        surfaceView.setOnTouchListener(new View.OnTouchListener() {@Override
            public boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:dX = event.getX();
                        dY = event.getY();
                        refreshControlLayout();
                        break;
                    case MotionEvent.ACTION_UP:break;
                    case MotionEvent.ACTION_MOVE:if (isFullScreen) {uY = event.getY();
                            if (dX > getWidth() / 2) {//声音控制
                                if (Math.abs(uY - dY) > 25)setVolume(uY - dY);
                            } else if (dX <= getWidth() / 2) {//亮度控制
                                setLight(dY - uY);
                            }}break;
                }return true;
            }});

    }//手势调节音量
    private void setVolume(float vol) {if (vol < 0) {//增大音量
            audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE,
                    AudioManager.FX_FOCUS_NAVIGATION_UP);
        } else if (vol > 0) {//降低音量
            audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER,
                    AudioManager.FX_FOCUS_NAVIGATION_UP);
        }}/**
     * 手势设置屏幕亮度
     * 设置当前的屏幕亮度值,及时生效 0.004-1
     * 该方法仅对当前应用屏幕亮度生效
     */
    private void setLight(float vol) {Window localWindow = getWindow();
        WindowManager.LayoutParams localLayoutParams = localWindow.getAttributes();
        f += vol / getWidth();
        if (f > 1) {f = 1f;
        } else if (f <= 0) {f = 0.004f;
        }localLayoutParams.screenBrightness = f;
        localWindow.setAttributes(localLayoutParams);
    }//初始化surfaceView
    private void initSurface() {//设置回调参数
        mHolder.addCallback(this);
        //设置SurfaceView自己不管理的缓冲区
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        //显示的分辨率,不设置为视频默认
//        mHolder.setFixedSize(320, 220);
    }private void playUrl(String url) {try {//使mediaPlayer重新进入ide状态
            mediaPlayer.reset();
            //设置媒体类型
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            //将影像输出到surfaceView
            mediaPlayer.setDisplay(mHolder);
            //设置 视频资源 可以是本地视频 也可是网络资源
//            mediaPlayer.setDataSource("/storage/sdcard1/DCIM/Camera/VID_20160629_164144.mp4");
            mediaPlayer.setDataSource(url);
            //同步准备
//            mediaPlayer.prepare();
            //因为是网络视频 这里用异步准备
            mediaPlayer.prepareAsync();
        } catch (IOException e) {e.printStackTrace();
        }}//初始化视频显示的大小
    private void initVideoSize() {RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        getPlayTime(VIDEO_URL);

//        params.height = getWidth() / 10 * 6;
        if (width!=null && height!=null){params.height = getWidth() *Integer.parseInt(height)/Integer.parseInt(width);
        }else {params.height = getWidth() / 10 * 6;
        }params.addRule(RelativeLayout.CENTER_IN_PARENT);
        surfaceView.setLayoutParams(params);
    }//surfaceView创建完成
    @Override
    public void surfaceCreated(SurfaceHolder holder) {Log.e("TAG", "surfaceCreated");
        //等surfaceView创建完成再开始播放视频
        if (!isPause) {playUrl(VIDEO_URL);
        } else {isPause = false;
            mediaPlayer.setDisplay(holder);
            if (isPlay) mediaPlayer.start();
        }}//surfaceView改变
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {Log.e("TAG", "surfaceChanged");
    }//surfaceView销毁
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {Log.e("TAG", "surfaceDestroyed");
    }@Override
    public void onClick(View v) {isControl = false;
        refreshControlLayout();
        if (isFirstLoadVideo) {return;
        }switch (v.getId()) {case R.id.playBtn:if (mediaPlayer.isPlaying()) {mediaPlayer.pause();
                    isPlay = false;
                    playBtn.setBackgroundResource(R.mipmap.play);
                } else if (isPlayCom) {mediaPlayer.seekTo(0);
                    isPlay = true;
                    isPlayCom = false;
                    playBtn.setBackgroundResource(R.mipmap.pause);
                } else {mediaPlayer.start();
                    isPlay = true;
                    playBtn.setBackgroundResource(R.mipmap.pause);
                }break;
            case R.id.screenBtn:if (isFullScreen) {smallScreen();
                    screenBtn.setBackgroundResource(R.mipmap.large_screen);
                } else {fullScreen();
                    screenBtn.setBackgroundResource(R.mipmap.small_screen);
                }break;
        }}//横竖屏切换
    @Override
    public void onConfigurationChanged(Configuration newConfig) {if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {Log.e("TAG", "当前屏幕为横屏");
            isFullScreen = true;
            fullScreen();
            screenBtn.setBackgroundResource(R.mipmap.small_screen);
        } else {Log.e("TAG", "当前屏幕为竖屏");
            isFullScreen = false;
            smallScreen();
            screenBtn.setBackgroundResource(R.mipmap.large_screen);
        }super.onConfigurationChanged(newConfig);
    }//全屏
    private void fullScreen() {getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//设置成全屏模式
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//强制为横屏
        showFullSurface();
    }//竖屏
    private void smallScreen() {getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//强制为竖屏
        showSmallSurface();
    }private void showFullSurface() {RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        params.width=getHeight() *Integer.parseInt(width)/Integer.parseInt(height);
        params.addRule(RelativeLayout.CENTER_IN_PARENT);
        surfaceView.setLayoutParams(params);
    }private void showSmallSurface() {RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
//        params.height = getWidth() / 10 * 6;
        if (width!=null && height!=null){params.height = getWidth() *Integer.parseInt(height)/Integer.parseInt(width);
        }else {params.height = getWidth() / 10 * 6;
        }params.addRule(RelativeLayout.CENTER_IN_PARENT);
        surfaceView.setLayoutParams(params);
    }//进度改变
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {currTime.setText(formatTime(seekBar.getProgress()));
        if (isSetProgress) {Log.e("TAG", "onProgressChanged:refreshControlLayout");
            isControl = false;
            refreshControlLayout();
        }}//开始拖动
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {currTime.setText(formatTime(seekBar.getProgress()));
        isSetProgress = true;
        isControl = false;
        refreshControlLayout();
    }//停止拖动
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {isSetProgress = false;
        isControl = false;
        refreshControlLayout();
        if (isFirstLoadVideo) {return;
        }mediaPlayer.seekTo(seekBar.getProgress());
        currTime.setText(formatTime(seekBar.getProgress()));
    }public int getWidth() {WindowManager manager = getWindowManager();
        DisplayMetrics outMetrics = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }public int getHeight() {WindowManager manager = getWindowManager();
        DisplayMetrics outMetrics = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.heightPixels;
    }//更新进度
    private void updateSeekBar() {new Thread(new Runnable() {@Override
            public void run() {while (!isOnDestroy) { //结束线程标示

                    if (isPlay && !isPause) {try {Message message = new Message();
                            message.what = mediaPlayer.getCurrentPosition();
                            handler.sendMessage(message);
                            Log.e("TAG", "while");
                            Thread.sleep(1000);
                        } catch (Exception e) {e.printStackTrace();
                        }}}}}).start();
    }//播放完成
    @Override
    public void onCompletion(MediaPlayer mp) {
//        Log.e("TAG", "播放完成");
        playBtn.setBackgroundResource(R.mipmap.play);
        isPlay = false;
        isPlayCom = true;
        isControl = false;
        Message message = new Message();
        message.what = mediaPlayer.getDuration();
        handler.sendMessage(message);
        refreshControlLayout();
    }//播放出错
    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {isPlay = false;
        return false;
    }private String formatTime(long time) {SimpleDateFormat format = new SimpleDateFormat("mm:ss");
        return format.format(time);
    }@Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {Log.e("TAG", "onBufferingUpdate" + ",percent:" + percent);
    }//准备完成
    @Override
    public void onPrepared(MediaPlayer mp) {//设置最大进度
        seekBar.setMax(mediaPlayer.getDuration());
        //设置按钮背景图片
        playBtn.setBackgroundResource(R.mipmap.pause);
        //设置视频最大时间
        countTime.setText(formatTime(mediaPlayer.getDuration()));
        //隐藏加载进度条
        progressBar.setVisibility(View.INVISIBLE);
        //开始播放
        mediaPlayer.start();
        //更改播放状态
        isPlay = true;
        //更改状态
        if (isFirstLoadVideo)isFirstLoadVideo = false;
        //开启线程更新进度
        updateSeekBar();
    }@Override
    protected void onDestroy() {Log.e("TAG", "onDestroy");
        isOnDestroy = true;
        if (mediaPlayer.isPlaying()) {mediaPlayer.stop();
            isPlay = false;
        }mediaPlayer.release();
        super.onDestroy();
    }//seekTo()是异步的方法 在此监听是否执行完毕
    @Override
    public void onSeekComplete(MediaPlayer mp) {Log.e("TAG", "onSeekComplete");
        if (!isPlay) {mediaPlayer.pause();
        } else {mediaPlayer.start();
        }}//监听返回键 如果是全屏状态则返回竖屏 否则直接返回
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {if (isFullScreen) {smallScreen();
            return false;
        }return super.onKeyDown(keyCode, event);
    }@Override
    protected void onPause() {Log.e("TAG", "onPause");
        isPause = true;
        if (mediaPlayer.isPlaying()) {mediaPlayer.pause();
        }super.onPause();
    }@Override
    protected void onResume() {super.onResume();
        if (isPause && isPlay && mHolder.getSurface().isValid()) {isPause = false;
            mediaPlayer.start();
        }}private void  getPlayTime(String mUri){android.media.MediaMetadataRetriever mmr = new android.media.MediaMetadataRetriever();
        try {if (mUri != null){HashMap<String, String> headers = null;
                if (headers == null){headers = new HashMap<String, String>();
                    headers.put("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.4.2; zh-CN; MW-KW-001 Build/JRO03C) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/1.0.0.001 U4/0.8.0 Mobile Safari/533.1");
                }mmr.setDataSource(mUri, headers);
            } else
            {//mmr.setDataSource(mFD, mOffset, mLength);
            }String duration = mmr.extractMetadata(android.media.MediaMetadataRetriever.METADATA_KEY_DURATION);//时长(毫秒)
            width = mmr.extractMetadata(android.media.MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);//宽
            height = mmr.extractMetadata(android.media.MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);//高

            Toast.makeText(MainActivity.this, "playtime:"+ duration+"w="+width+"h="+height, Toast.LENGTH_SHORT).show();

        } catch (Exception ex){Log.e("TAG", "MediaMetadataRetriever exception " + ex);
        } finally {mmr.release();
        }}}

这里我是用的MediaPlayer结合SurfaceView进行播放,首先,定义一个SurfaceView,SurfaceHolder,MediaPlayer,这个是视频播放用到的关键技术。

由于activity继承了SurfaceHolder.Callback,所以必须实现三个接口代码。

 //surfaceView创建完成@Overridepublic void surfaceCreated(SurfaceHolder holder) {Log.e("TAG", "surfaceCreated");//等surfaceView创建完成再开始播放视频if (!isPause) {playUrl(VIDEO_URL);} else {isPause = false;mediaPlayer.setDisplay(holder);if (isPlay) mediaPlayer.start();}}//surfaceView改变@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {Log.e("TAG", "surfaceChanged");}//surfaceView销毁@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {Log.e("TAG", "surfaceDestroyed");}

这里当SurfaceHolder初始化完成时,调用surfaceCreated代码,然后把MediaPlayer与SurfaceHolder进行关联,通过代码

mediaPlayer.setDisplay(mHolder);
            mediaPlayer.setDataSource(url);               //设置播放的路径

然后调用了mediaPlayer.prepareAsync();这个会回调public void onPrepared(MediaPlayer mp) ,在这个代码里,

//准备完成
@Override
public void onPrepared(MediaPlayer mp) {//设置最大进度
    seekBar.setMax(mediaPlayer.getDuration());
    //设置按钮背景图片
    playBtn.setBackgroundResource(R.mipmap.pause);
    //设置视频最大时间
    countTime.setText(formatTime(mediaPlayer.getDuration()));
    //隐藏加载进度条
    progressBar.setVisibility(View.INVISIBLE);
    //开始播放
    mediaPlayer.start();
    //更改播放状态
    isPlay = true;
    //更改状态
    if (isFirstLoadVideo)isFirstLoadVideo = false;
    //开启线程更新进度
    updateSeekBar();
}

就进行了视频的播放。

这个内容讲起来比较麻烦,自己也感觉没有讲明白,大家有兴趣可以自己查找资料。

源码下载:http://download.csdn.net/detail/bzlj2912009596/9868742

这是第一次上传源码,资源分比较贵,大家需要就下载。

android 自定义MP4播放器就讲完了。

就这么简单。




android 自定义MP4播放器相关推荐

  1. Android 自定义音乐播放器实现

    Android自定义音乐播放器 一:首先介绍用了哪些Android的知识点: 1 MediaPlayer工具来播放音乐 2 Handle.因为存在定时任务(歌词切换,动画,歌词进度条变换等)需要由Ha ...

  2. Android自定义一个播放器控件

    介绍 最近要使用播放器做一个简单的视频播放功能,开始学习VideoView,在横竖屏切换的时候碰到了点麻烦,不过在查阅资料后总算是解决了.在写VideoView播放视频时候定义控制的代码全写在Actv ...

  3. Android开发笔记(一百二十六)自定义音乐播放器

    MediaRecorder/MediaPlayer 在Android手机上面,音频的处理比视频还要复杂,这真是出人意料.在前面的博文< Android开发笔记(五十七)录像录音与播放>中, ...

  4. android 调用系统播放器

    今天,简单讲讲android如何调用手机自带的播放器. 昨天,从服务器下载一个AVI的视频,下载后需要进行播放,所以想调用系统自带的播放器.但是由于很少用到,所以自己当时不知道怎么写,于是在网上查找资 ...

  5. android集成EasyPlayer播放器播放实时流媒体视屏

    android集成EasyPlayer播放器播放实时流媒体视屏 最近公司项目需要实现一个rtsp实时流媒体视频的播放,在移动端尝试了多个第三方能播放rtsp流实时视频的软件后发现EasyPlayer的 ...

  6. 自定义高性能播放器, 实现边下边播缓存等功能

    VideoPlayerDemo 项目地址:Zhaoss/VideoPlayerDemo  简介:自定义高性能播放器, 实现边下边播缓存等功能 更多:作者   提 Bug 标签: 本项目使用播放器是ij ...

  7. H5 实现自定义video播放器,快来点我吧

    效果 要实现自定义video播放器需要熟悉video的相关操作 视频播放它有哪些操作         1. 播放 play()         2. 暂停 pause()         3. 判断当 ...

  8. JS 用CANVAS自定义VIDEO播放器

    JS 用CANVAS自定义VIDEO播放器 概述 CANVAS绘制核心代码 播放器代码 使用页面HTML代码 使用页面JS代码 使用示例 概述 HTML5用规范的VIDEO标签取代了以往需要借助外部控 ...

  9. android 音乐播放器 获取sd卡所有音乐文件,Android Studio音乐播放器无法读取SD卡,只有内部存储器...

    我很抱歉,如果这原来是一个愚蠢的问题,它可能会成为一个快速修复,但我只是无法弄清楚.我在android studio中创建了音乐播放器,并且没有任何sdcard上的歌曲不会显示在列表视图中,只有内部内 ...

最新文章

  1. Docker 底层原理浅析
  2. 在android平板上取位置和天气的实现方式
  3. 分布式监控系统Zabbix3.2对数据库的连接数预警
  4. Activity的用法(一):Notification Activity
  5. zabbix安装报错
  6. mysql搭建主主_mysql主主配置
  7. 无需predetermine一条路
  8. mybatis jar包_springboot2整合mybatis-plus3踩到的坑
  9. vs连接oracle数据库报错,用VS连接oracle数据库时ORA-12504错误
  10. usermod命令,用户密码管理,mkpasswd命令
  11. spring和redis的整合-超越昨天的自己系列(7)
  12. MIT 18.03 写给初学者的微积分校对活动 | ApacheCN
  13. RedHat7安装及小红帽硬盘分区建议
  14. C语言(B站比特鹏哥)笔记
  15. #IP实验室,第二周复盘
  16. 做好拼多多的几个小技巧-拼多多出评技巧
  17. uniapp 在h5 模式下扫码
  18. 完成清除工作,可以Destory窗口标志
  19. 前端面试合集,20k+已经是妥妥的了
  20. Netty源码剖析之内存池和对象池设计流程

热门文章

  1. java操作Excel之POI(3)
  2. QT5的exe的发布
  3. Python初识与简介【开篇】
  4. stripslashes和addslashes的区别
  5. 弱类型、强类型、动态类型、静态类型语言的区别
  6. 关于linux中的 秘钥认证 ,最清晰解读
  7. RabbitMQ 交换器、持久化
  8. 在CDH上用外部Spark2.2.1安装和配置 CarbonData
  9. HTML 传输 字符转换 进制转换 15位 18位 时间戳 转换
  10. python文件和目录操作方法