Android SurfaceView+MediaPlayer 本地视频播放器

Android基础课程:原生视频播放器(播放网络资源) 在之前的博客中,我分析过本地音乐播放器的逻辑和写法,需要使用MediaPlayer类,对于多媒体音频可进行播放,暂停,切换,停止等操作。在本篇博客中,将继续使用MediaPlayer类,将其放置于SurfaceView上进行视频播放。 SurfaceView的介绍 直接从内存或者DMA等硬件接口取得图像数据,是个非常重要的绘图容器。 它的特性是:可以在主线程之外的线程中向屏幕绘图上。这样可以避... 阅读详情

功能情景:

       1.播放视频文件

       2.上一首,下一首

       3.卡拉ok功能(只是单纯的用系统mediaplayer切换声道,资源必须要含有三种声道的mkv文件(2,1,1))

           也就是特定资源才有用,虽然是播客对我来说只是月度总结,但我不想误导别人

       4.播放模式(顺序,随机,循环)

效果图


功能的实现:

       1.伴唱功能:(这里是mkv文件切换声道),伴唱转AUDIO,原唱转VIDEO。当然前提是先获得mkv文件的所有声道。

我在视频准备的时候获取所有声道,然后判断是否有这个声道我再转。

    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {
        //视频播放
        mMediaPlayer.start();
        //获取视屏的长度
        tv_video.setText(ProjectUtils.formatTime(mMediaPlayer.getDuration()));
        // mIsStopped = false;
        if (iv_play != null) {
            iv_play.setSelected(false);
        }

        //获取所有的音轨
        trackInfo = mMediaPlayer.getTrackInfo();

    }

       //伴唱与原唱
        RxView.clicks(iv_sing_state).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Action1<Void>() {
            @Override
            public void call(Void aVoid) {
                int pos = fileName.lastIndexOf('.');
                if (pos != -1) {
                    String indexName = fileName.substring(pos);
                    if (indexName.equalsIgnoreCase(".mkv")) {
                        if (trackInfo != null) {
                            Logger.i("fileName" + fileName);
                            mMediaPlayer.selectTrack(MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_AUDIO);

                        }
                        if (!iv_sing_state.isSelected()){
                            boolean flag=false;
                            for (int i = 0; i < trackInfo.length; i++) {
                                if (trackInfo[i].getTrackType()== MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_AUDIO){
                                    flag=true;
                                }
                            }
                            if (flag){
                                //切换音轨(伴唱)
                                if (mMediaPlayer!=null){
                                    mMediaPlayer.selectTrack(MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_AUDIO);
                                }
                            }
                            iv_sing_state.setSelected(true);
                            
                        }else{
                            boolean flag=false;
                            for (int i = 0; i < trackInfo.length; i++) {
                                if (trackInfo[i].getTrackType()== MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_VIDEO ){
                                    flag=true;
                                }
                            }

                            if (flag){
                                //原唱
                                if (mMediaPlayer!=null){
                                    mMediaPlayer.selectTrack(MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_VIDEO);
                                }
                            }
                            iv_sing_state.setSelected(false);

                        }
                        
                    }else{

                        Toast.makeText(VideoPalyActivity.this,"不是卡拉OK文件,不具备伴唱功能",Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });

2.播放模式

          随机模式的算法:当切换到随机模式时,先移除掉当前播放的数据,然后播放下一首的时候,从剩余的随机一条,然后再移除,再随机。知道没有数据,没有数据的时候再从新复制总数据。这里注意的是,可移除的数据集合必然是克隆原先数据集合的,而不是简单的复制(注意java的数据存储)

        //播放模式的切换
        RxView.clicks(iv_state).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Action1<Void>() {
            @Override
            public void call(Void aVoid) {

                if (playMode == 1) {
                    playMode = 2;//随机模式
                    Toast.makeText(VideoPalyActivity.this, "随机模式", Toast.LENGTH_SHORT).show();
                    iv_state.setImageResource(R.drawable.iv_state_suiji_press);
                } else if (playMode == 2) {
                    playMode = 3;//循环模式
                    Toast.makeText(VideoPalyActivity.this, "循环模式", Toast.LENGTH_SHORT).show();

                    iv_state.setImageResource(R.drawable.iv_state_xunhuan_press);
                } else if (playMode == 3) {
                    playMode = 1;//顺序模式
                    Toast.makeText(VideoPalyActivity.this, "顺序模式", Toast.LENGTH_SHORT).show();
                    iv_state.setImageResource(R.drawable.iv_state_shunxu_press);
                }

            }
        });


播放模式要有效果必然要在播放完成下写算法


 @Override
    public void onCompletion(MediaPlayer mp) {
        Toast.makeText(VideoPalyActivity.this, "播放完毕", Toast.LENGTH_SHORT).show();
        seekBar.setProgress(100);
        RxUtils.unsubscribe(seekBarSubscription);
        if (iv_play != null) {
            iv_play.setSelected(true);
        }
        
        if (playMode == 1) {
            Logger.i(TAG, "播放完毕进入顺序模式");
            if (currentPos < data.size()) {
                currentPos++;
                Logger.i("随机::666" + "currentPos=" + currentPos);

                if (currentPos<data.size()){
                    mVideoPath = data.get(currentPos).getAbsolutePath();
                    Logger.i("随机::666" + "mVideoPath=" + mVideoPath);
                    fileName = data.get(currentPos).getName();
                }

            }

        } else if (playMode == 2) {
            Logger.i(TAG, "播放完毕进入随机模式");

            if (copydata.size() != 0) {
                int pos = -1;
                for (int i = 0; i < copydata.size(); i++) {
                    if (copydata.get(i).getAbsolutePath().equals(mVideoPath)) {
                        pos = i;
                    }
                }

                if (pos != -1 && pos < copydata.size()) {
                    copydata.remove(pos);
                }

                int max = copydata.size();
                int min = 0;
                Random random = new Random();
                int rNum = random.nextInt(max) % (max - min + 1) + min;
                mVideoPath = copydata.get(rNum).getAbsolutePath();
                fileName = copydata.get(rNum).getName();

                // mVideoPath = copydata.get(rNum).getFilepath();
                for (int i = 0; i < data.size(); i++) {
                    if (data.get(i).getAbsolutePath().equals(copydata.get(rNum).getAbsolutePath())) {
                        currentPos = i;
                    }
                }
                Logger.i("随机::555" + "currentPos=" + currentPos);
                mVideoPath = data.get(currentPos).getAbsolutePath();
                fileName = data.get(currentPos).getName();
                Logger.i("随机::555" + "mVideoPath=" + mVideoPath);
                copydata.remove(rNum);

            } else {
                copydata = (ArrayList<File>) data.clone();
            }


        } else if (playMode == 3) {
            Logger.i(TAG, "播放完毕进入循环模式");
            Logger.i("随机::777" + "currentPos=" + currentPos);
            Logger.i("随机::777" + "mVideoPath=" + mVideoPath);

        }
        prepare();
    }



附件:完整代码:

package com.wyt.hcy.leyuanindustryproject;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.jakewharton.rxbinding.view.RxView;
import com.orhanobut.logger.Logger;
import com.wyt.db.bean.BrowseLog;

import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import database.DbUtils;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
import utils.ActivityUtils;
import utils.ProjectUtils;
import utils.RxUtils;

/**
 * 屏保不执行任何activity的生命周期
 */


public class VideoPalyActivity extends BaseActivity implements SurfaceHolder.Callback, MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener, MediaPlayer.OnBufferingUpdateListener {

    private ImageView iv_back;
    private ImageView iv_battery;
    private SurfaceView mSurfaceView;
    private MediaPlayer mMediaPlayer;
    private static final String TAG = "VideoPalyActivity";
    private String mVideoPath;
    private TextView tv_video;
    private ImageView iv_play;
    private ImageView iv_previous;
    private ImageView iv_next;
    private static int currentPos = 0;
    private ArrayList<File> data;
    private ArrayList<File> copydata;
    private ImageView iv_pb;
    private int playMode = 1;//默认为顺序模式
    private ImageView iv_state;
    private SeekBar seekBar;
    private Subscription seekBarSubscription, yinGUISubscription, nextMediaSubscription;
    private DbUtils dbUtils;
    private String module_name;
    private String fileName;
    private RelativeLayout rl_title, rl_bottom;
    private MyHandler myHandler;
    private ImageView iv_tf;
    private ImageView iv_sing_state;
    private MediaPlayer.TrackInfo[] trackInfo;
    private ImageView iv_wifi;
    private ActivityUtils activityUtils;
    private SurfaceHolder surfaceHolder;

    private RelativeLayout rl_root;

    private boolean threadFlag = false;
    private BroadcastReceiver receiver;
    private static int currentPosition = 0;


    // private boolean isChangeSingState=false;

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

        Logger.i("ViewState:onCreate");

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            //透明状态栏
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            //透明导航栏
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
        }
        setContentView(R.layout.activity_video_paly);


        ProjectUtils.stopBg();

        initUI();
        batteryState(iv_battery);
        tFCardListener(iv_tf);
        wifiListener(iv_wifi, VideoPalyActivity.this);


        IntentFilter intentFilter = new IntentFilter();

        intentFilter.addAction("com.yinghengke.homekey");

        if (receiver == null) {
            receiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (intent.getAction().equals("com.yinghengke.homekey")) {
                        release();
                        if (activityUtils != null) {
                            activityUtils.removeAllActivity();
                        }
                    }
                }
            };
        }

        registerReceiver(receiver, intentFilter);


        exchangeZhuti(rl_root);
        activityUtils = ActivityUtils.getIntance();

        activityUtils.putActivity("VideoPalyActivity", VideoPalyActivity.this);

        Bundle bundle = getIntent().getBundleExtra("bundle_data");

        currentPos = bundle.getInt("pos", 0);

        module_name = bundle.getString("module_name", "none");

        myHandler = new MyHandler(this);

        //Logger.i("数据库ok:" + module_name);


        data = (ArrayList<File>) bundle.getSerializable("data");
        copydata = new ArrayList<File>();


        dbUtils = DbUtils.getInstance(VideoPalyActivity.this);

        copydata = (ArrayList<File>) data.clone();

        // Logger.i("随机::" + "data=" + data.toString());

        mVideoPath = data.get(currentPos).getAbsolutePath();
        fileName = data.get(currentPos).getName();
        if (mRunnable != null) {
            threadFlag = true;
            myHandler.postDelayed(mRunnable, 5000);
        }
    }


    private void exchangeZhuti(RelativeLayout ll_root) {

        SharedPreferences sp = getSharedPreferences("setting", Context.MODE_PRIVATE);
        String theme = sp.getString("theme", "bgone");

        if (ll_root != null) {
            switch (theme) {
                case "bgone":
                    ll_root.setBackgroundResource(R.mipmap.bgone);
                    break;
                case "bgtwo":
                    ll_root.setBackgroundResource(R.mipmap.bgtwo);
                    break;
                case "bgthree":
                    ll_root.setBackgroundResource(R.mipmap.bgthree);
                    break;
            }
        }


    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Logger.i("ViewState:onRestart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Logger.i("ViewState:onResume");

    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        //Logger.i("按钮效果::" + keyCode);
        //Toast.makeText(VideoPalyActivity.this, "" + keyCode, Toast.LENGTH_SHORT).show();

        switch (keyCode) {
            case KeyEvent.KEYCODE_MEDIA_NEXT:
                //下一首
                Toast.makeText(VideoPalyActivity.this, "下一首", Toast.LENGTH_SHORT).show();
                if (playMode == 2) {
                    if (copydata.size() == 0) {
                        copydata = (ArrayList<File>) data.clone();
                    }
                    int max = copydata.size();
                    int min = 0;
                    Random random = new Random();

                    // do{
                    int rNum = random.nextInt(max) % (max - min + 1) + min;
                    // }while (rNum>=copydata.size());

                    //Logger.i("随机数::" + rNum);
                    // mVideoPath = copydata.get(rNum).getFilepath();
                    for (int i = 0; i < data.size(); i++) {
                        if (data.get(i).getAbsolutePath().equals(copydata.get(rNum).getAbsolutePath())) {
                            currentPos = i;
                        }
                    }

                    // Logger.i("随机::" + "currentPos=" + currentPos);
                    mVideoPath = data.get(currentPos).getAbsolutePath();
                    // Logger.i("随机::" + "mVideoPath=" + mVideoPath);
                    fileName = data.get(currentPos).getName();
                    copydata.remove(rNum);

                    prepare();
                } else {
                    // Logger.i("PPL" + "currentPos=" + currentPos);
                    ++currentPos;
                    if (currentPos < data.size()) {


                        // Logger.i("随机::2" + "currentPos=" + currentPos);
                        mVideoPath = data.get(currentPos).getAbsolutePath();
                        fileName = data.get(currentPos).getName();
                        //  Logger.i("随机::2" + "mVideoPath=" + mVideoPath);
                        prepare();

                    } else {
                        currentPos = data.size() - 1;
                        Toast.makeText(VideoPalyActivity.this, "已经到底了", Toast.LENGTH_SHORT).show();
                    }

                }
                break;
            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
                //上一首
                Toast.makeText(VideoPalyActivity.this, "上一首", Toast.LENGTH_SHORT).show();

                if (playMode == 2) {
                    if (copydata.size() == 0) {
                        copydata = (ArrayList<File>) data.clone();
                    }
                    int max = copydata.size();
                    int min = 0;
                    Random random = new Random();
                    int rNum = random.nextInt(max) % (max - min + 1) + min;
                    // Logger.i("随机数::" + rNum);
                    //mVideoPath = copydata.get(rNum).getFilepath();

                    // int pos=-1;

                    for (int i = 0; i < data.size(); i++) {
                        if (data.get(i).getAbsolutePath().equals(copydata.get(rNum).getAbsolutePath())) {
                            currentPos = i;
                        }
                    }
                    //  Logger.i("随机::4" + "currentPos=" + currentPos);

                    mVideoPath = data.get(currentPos).getAbsolutePath();
                    //  Logger.i("随机::4" + "mVideoPath=" + mVideoPath);
                    fileName = data.get(currentPos).getName();
                    copydata.remove(rNum);
                    prepare();
                } else {
                    currentPos--;
                    if (currentPos >= 0) {
                        //  Logger.i("随机::3" + "currentPos=" + currentPos);
                        mVideoPath = data.get(currentPos).getAbsolutePath();
                        // Logger.i("随机::3" + "mVideoPath=" + mVideoPath);
                        fileName = data.get(currentPos).getName();
                        prepare();
                    } else {
                        currentPos = 0;
                        Toast.makeText(VideoPalyActivity.this, "已经到底了", Toast.LENGTH_SHORT).show();
                    }

                }

                break;
            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
                //播放暂停
                if (iv_play != null) {
                    if (iv_play.isSelected()) {
                        if (mMediaPlayer != null) {
                            mMediaPlayer.start();
                            iv_play.setSelected(false);
                        }
                    } else {
                        if (mMediaPlayer != null) {
                            mMediaPlayer.pause();
                            //Toast.makeText(VideoPalyActivity.this,"DDD111",Toast.LENGTH_SHORT).show();
                            iv_play.setSelected(true);
                        }
                    }
                }
                break;
            case KeyEvent.KEYCODE_HOME:


                break;
        }

        return super.onKeyDown(keyCode, event);

    }

    private Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            if (threadFlag) {
                if (rl_bottom.getVisibility() == View.VISIBLE) {
                    rl_bottom.setVisibility(View.GONE);
                    if (rl_title.getVisibility() == View.VISIBLE) {
                        rl_title.setVisibility(View.GONE);
                    }
                }
            }
        }
    };


    private class MyHandler extends Handler {
        private WeakReference<Activity> weakReference;

        public MyHandler(Activity activity) {
            weakReference = new WeakReference<Activity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (weakReference.get() != null) {
                if (msg.what == 1000) {
                    //showOrHideController();
                }

                if (msg.what == 1001) {
                    rl_title.setVisibility(View.GONE);
                }
                if (msg.what == 1002) {
                    rl_bottom.setVisibility(View.GONE);
                }
            }
        }
    }


    @Override
    protected void onStop() {
        super.onStop();
        Logger.i("ViewState:onStop");
    }

    /**
     * 蓝牙进入OnPause状态
     */
    @Override
    protected void onPause() {
        super.onPause();
        Logger.i("ViewState:onPause");

       /* if (iv_sing_state.isSelected()) {
            iv_sing_state.setSelected(false);
        }
        try {
            if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
               // mMediaPlayer.pause();
                Toast.makeText(VideoPalyActivity.this,"DDD222",Toast.LENGTH_SHORT).show();

                isPlay = false;
            }
        } catch (IllegalStateException e) {
            mMediaPlayer = null;
            // mp = new MediaPlayer();
        }*/

    }

    private void initUI() {
        rl_root = (RelativeLayout) findViewById(R.id.rl_root);


        iv_sing_state = (ImageView) findViewById(R.id.iv_sing_state);

        iv_wifi = (ImageView) findViewById(R.id.iv_wifi);


        //伴唱与原唱
        RxView.clicks(iv_sing_state).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Action1<Void>() {
            @Override
            public void call(Void aVoid) {
                int pos = fileName.lastIndexOf('.');
                if (pos != -1) {
                    String indexName = fileName.substring(pos);
                    if (indexName.equalsIgnoreCase(".mkv")) {
                        if (trackInfo != null) {
                            //  Logger.i("fileName" + fileName);
                            mMediaPlayer.selectTrack(MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_AUDIO);

                        }
                        if (!iv_sing_state.isSelected()) {
                            boolean flag = false;
                            for (int i = 0; i < trackInfo.length; i++) {
                                if (trackInfo[i].getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_AUDIO) {
                                    flag = true;
                                }
                            }
                            if (flag) {
                                //切换音轨(伴唱)
                                //isChangeSingState=true;
                                if (mMediaPlayer != null) {
                                    mMediaPlayer.selectTrack(MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_AUDIO);
                                }
                            }
                            iv_sing_state.setSelected(true);

                        } else {
                            boolean flag = false;
                            for (int i = 0; i < trackInfo.length; i++) {
                                if (trackInfo[i].getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_VIDEO) {
                                    flag = true;
                                }
                            }

                            if (flag) {
                                //原唱
                                // isChangeSingState=false;
                                if (mMediaPlayer != null) {
                                    mMediaPlayer.selectTrack(MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_VIDEO);
                                }
                            }
                            iv_sing_state.setSelected(false);

                        }

                    } else {

                        Toast.makeText(VideoPalyActivity.this, "不是卡拉OK文件,不具备伴唱功能", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });

        rl_bottom = (RelativeLayout) findViewById(R.id.rl_bottom);

        rl_title = (RelativeLayout) findViewById(R.id.rl_title);


        iv_tf = (ImageView) findViewById(R.id.iv_tf);

        iv_back = (ImageView) findViewById(R.id.iv_back);
        iv_state = (ImageView) findViewById(R.id.iv_state);
        seekBar = (SeekBar) findViewById(R.id.seekbar);


        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser && mMediaPlayer != null) {
                    currentPosition = (int) (progress * mMediaPlayer.getDuration() / 100);
                    mMediaPlayer.seekTo(currentPosition);
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                threadFlag = false;

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                if (mRunnable != null) {
                    threadFlag = true;
                    myHandler.postDelayed(mRunnable, 5000);
                }
            }
        });


        rl_bottom.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Logger.i("TTYY::");
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    if (mRunnable != null) {
                        myHandler.removeCallbacks(mRunnable);
                        threadFlag = true;
                        myHandler.postDelayed(mRunnable, 5000);
                    }
                } else {

                    threadFlag = false;
                }
                return true;
            }
        });

        //播放模式的切换
        RxView.clicks(iv_state).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Action1<Void>() {
            @Override
            public void call(Void aVoid) {

                if (playMode == 1) {
                    playMode = 2;//随机模式
                    Toast.makeText(VideoPalyActivity.this, "随机模式", Toast.LENGTH_SHORT).show();
                    iv_state.setImageResource(R.drawable.iv_state_suiji_press);
                } else if (playMode == 2) {
                    playMode = 3;//循环模式
                    Toast.makeText(VideoPalyActivity.this, "循环模式", Toast.LENGTH_SHORT).show();

                    iv_state.setImageResource(R.drawable.iv_state_xunhuan_press);
                } else if (playMode == 3) {
                    playMode = 1;//顺序模式
                    Toast.makeText(VideoPalyActivity.this, "顺序模式", Toast.LENGTH_SHORT).show();
                    iv_state.setImageResource(R.drawable.iv_state_shunxu_press);
                }

            }
        });
        iv_battery = (ImageView) findViewById(R.id.iv_battery);
        tv_video = (TextView) findViewById(R.id.tv_video);

       /* RxView.clicks(iv_back).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Action1<Void>() {
            @Override
            public void call(Void aVoid) {


            }
        });*/


        iv_back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
        /*        threadFlag = false;
                if (surfaceHolder != null) {

                    surfaceHolder.getSurface().release();
                }

                release();*/
                finish();

            }
        });


        iv_previous = (ImageView) findViewById(R.id.iv_previous);
        iv_next = (ImageView) findViewById(R.id.iv_next);

        RxView.clicks(iv_next).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Action1<Void>() {
            @Override
            public void call(Void aVoid) {
                currentPosition = 0;
                if (playMode == 2) {
                    if (copydata.size() == 0) {
                        copydata = (ArrayList<File>) data.clone();
                    }
                    int max = copydata.size();
                    int min = 0;
                    Random random = new Random();

                    // do{
                    int rNum = random.nextInt(max) % (max - min + 1) + min;
                    // }while (rNum>=copydata.size());

                    // Logger.i("随机数::" + rNum);
                    // mVideoPath = copydata.get(rNum).getFilepath();
                    for (int i = 0; i < data.size(); i++) {
                        if (data.get(i).getAbsolutePath().equals(copydata.get(rNum).getAbsolutePath())) {
                            currentPos = i;
                        }
                    }

                    //     Logger.i("随机::" + "currentPos=" + currentPos);
                    mVideoPath = data.get(currentPos).getAbsolutePath();
                    //   Logger.i("随机::" + "mVideoPath=" + mVideoPath);
                    fileName = data.get(currentPos).getName();
                    copydata.remove(rNum);

                    prepare();
                } else {
                    Logger.i("PPL" + "currentPos=" + currentPos);
                    ++currentPos;
                    if (currentPos < data.size()) {


                        Logger.i("随机::2" + "currentPos=" + currentPos);
                        mVideoPath = data.get(currentPos).getAbsolutePath();
                        fileName = data.get(currentPos).getName();
                        Logger.i("随机::2" + "mVideoPath=" + mVideoPath);
                        prepare();

                    } else {
                        currentPos = data.size() - 1;
                        Toast.makeText(VideoPalyActivity.this, "已经到底了", Toast.LENGTH_SHORT).show();
                    }

                }


            }
        });

        RxView.clicks(iv_previous).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Action1<Void>() {
            @Override
            public void call(Void aVoid) {

                currentPosition = 0;
                if (playMode == 2) {
                    if (copydata.size() == 0) {
                        copydata = (ArrayList<File>) data.clone();
                    }
                    int max = copydata.size();
                    int min = 0;
                    Random random = new Random();
                    int rNum = random.nextInt(max) % (max - min + 1) + min;
                    // Logger.i("随机数::" + rNum);
                    //mVideoPath = copydata.get(rNum).getFilepath();

                    // int pos=-1;

                    for (int i = 0; i < data.size(); i++) {
                        if (data.get(i).getAbsolutePath().equals(copydata.get(rNum).getAbsolutePath())) {
                            currentPos = i;
                        }
                    }
                    //  Logger.i("随机::4" + "currentPos=" + currentPos);

                    mVideoPath = data.get(currentPos).getAbsolutePath();
                    // Logger.i("随机::4" + "mVideoPath=" + mVideoPath);
                    fileName = data.get(currentPos).getName();
                    copydata.remove(rNum);
                    prepare();
                } else {
                    currentPos--;
                    if (currentPos >= 0) {

                        //   Logger.i("随机::3" + "currentPos=" + currentPos);
                        mVideoPath = data.get(currentPos).getAbsolutePath();
                        //   Logger.i("随机::3" + "mVideoPath=" + mVideoPath);
                        fileName = data.get(currentPos).getName();
                        prepare();
                    } else {
                        currentPos = 0;
                        Toast.makeText(VideoPalyActivity.this, "已经到底了", Toast.LENGTH_SHORT).show();
                    }

                }

            }
        });

        mSurfaceView = (SurfaceView) findViewById(R.id.sv);

//        mSurfaceView.setZOrderOnTop(false);
//        mSurfaceView.setZOrderMediaOverlay(false);


        surfaceHolder = mSurfaceView.getHolder();

        surfaceHolder.addCallback(this);


        RxView.clicks(mSurfaceView).throttleFirst(500, TimeUnit.MILLISECONDS).subscribe(new Action1<Void>() {
            @Override
            public void call(Void aVoid) {
                Logger.i("TTYY22::");


                if (rl_title.getVisibility() == View.GONE) {

                    rl_title.setVisibility(View.VISIBLE);

                    rl_bottom.setVisibility(View.VISIBLE);

                    myHandler.removeCallbacks(mRunnable);

                    myHandler.postDelayed(mRunnable, 5000);
                } else {
                    myHandler.removeCallbacks(mRunnable);
                    rl_title.setVisibility(View.GONE);
                    rl_bottom.setVisibility(View.GONE);
                }
            }
        });


        iv_play = (ImageView) findViewById(R.id.iv_play);

        iv_pb = (ImageView) findViewById(R.id.iv_pb);

        RxView.clicks(iv_play).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Action1<Void>() {
            @Override
            public void call(Void aVoid) {

                if (iv_play.isSelected()) {
                    if (mMediaPlayer != null) {
                        mMediaPlayer.start();
                        iv_play.setSelected(false);
                    }
                } else {

                    if (mMediaPlayer != null) {
                        mMediaPlayer.pause();
                        //Toast.makeText(VideoPalyActivity.this,"DDD333",Toast.LENGTH_SHORT).show();

                        iv_play.setSelected(true);
                    }
                }

            }
        });
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        Logger.i("SurfaceViewState:surfaceCreated");


    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Logger.i("SurfaceViewState:surfaceChanged");
     /*   if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
            Logger.i("ViewState:onResume重播"+currentPosition);
            //
           // mMediaPlayer.start();
            mMediaPlayer.seekTo(currentPosition);

        } else if (mMediaPlayer == null) {
            prepare();
        }*/
        prepare();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // releaseWithoutStop();
        Logger.i("SurfaceViewState:surfaceDestroyed");

        if (iv_sing_state.isSelected()) {
            iv_sing_state.setSelected(false);
        }
        try {
            if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
                 mMediaPlayer.pause();
                //Toast.makeText(VideoPalyActivity.this,"DDD222",Toast.LENGTH_SHORT).show();

                isPlay = false;
            }
        } catch (IllegalStateException e) {
            mMediaPlayer = null;
            // mp = new MediaPlayer();
        }

        //surfaceHolder.removeCallback(this);
    }


    private void prepare() {
        Logger.i("播放器ViewState::prepare");

        if (mMediaPlayer != null) {
            release();
        }


        //Logger.i(TAG + "播放内容::" + mVideoPath);
        try {
            mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setOnPreparedListener(this);
            // mMediaPlayer.setOnVideoSizeChangedListener(this);
            mMediaPlayer.setOnCompletionListener(this);
            mMediaPlayer.setOnErrorListener(this);
            mMediaPlayer.setOnInfoListener(this);
            mMediaPlayer.setOnBufferingUpdateListener(this);
            mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
            mMediaPlayer.setDataSource(mVideoPath);
            mMediaPlayer.setDisplay(mSurfaceView.getHolder());
            mMediaPlayer.prepareAsync();
        } catch (UnsatisfiedLinkError e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {

        Logger.i("播放器ViewState:onPrepared");
        //视频播放
        isPlay = true;
        mMediaPlayer.start();
        if (currentPosition != 0) {
            mediaPlayer.seekTo(currentPosition);
        }
        //获取视屏的长度
        tv_video.setText(ProjectUtils.formatTime(mMediaPlayer.getDuration()));
        // mIsStopped = false;
        if (iv_play != null) {
            iv_play.setSelected(false);
        }


        RxUtils.unsubscribe(yinGUISubscription);
        yinGUISubscription = Observable.just(fileName).subscribeOn(Schedulers.io()).subscribe(new Subscriber<String>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(String fileNames) {
                //获取所有的音轨
                try {
                    int pos = fileNames.lastIndexOf('.');
                    if (pos != -1) {
                        String indexName = fileNames.substring(pos);
                        if (indexName.equalsIgnoreCase(".mkv")) {
                            trackInfo = mMediaPlayer.getTrackInfo();
                            /*if (isChangeSingState) {
                                if (mMediaPlayer != null) {
                                    mMediaPlayer.selectTrack(MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_AUDIO);
                                }
                            }*/
                        }
                    }
                } catch (RuntimeException ex) {
                    Toast.makeText(VideoPalyActivity.this, "音轨获取异常", Toast.LENGTH_SHORT).show();
                }
            }
        });


    }


    private boolean isPlay = true;

    @Override
    public void onCompletion(MediaPlayer mp) {
        Logger.i("播放器ViewState:onCompletion");
        if (isPlay) {
            Toast.makeText(VideoPalyActivity.this, "播放完毕", Toast.LENGTH_SHORT).show();
            seekBar.setProgress(100);
            RxUtils.unsubscribe(seekBarSubscription);
            if (iv_play != null) {
                iv_play.setSelected(true);
            }


            RxUtils.unsubscribe(nextMediaSubscription);
            nextMediaSubscription = Observable.just("").subscribeOn(Schedulers.io()).subscribe(new Subscriber<String>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onNext(String s) {
                    if (playMode == 1) {
                        //Logger.i(TAG, "播放完毕进入顺序模式");
                        if (currentPos < data.size()) {
                            currentPos++;
                            // Logger.i("随机::666" + "currentPos=" + currentPos);
                            if (currentPos < data.size()) {
                                mVideoPath = data.get(currentPos).getAbsolutePath();
                                //   Logger.i("随机::666" + "mVideoPath=" + mVideoPath);
                                fileName = data.get(currentPos).getName();
                            }
                        }

                    } else if (playMode == 2) {
                        //  Logger.i(TAG, "播放完毕进入随机模式");
                        if (copydata.size() != 0) {
                            int pos = -1;
                            for (int i = 0; i < copydata.size(); i++) {
                                if (copydata.get(i).getAbsolutePath().equals(mVideoPath)) {
                                    pos = i;
                                }
                            }
                            if (pos != -1 && pos < copydata.size()) {
                                copydata.remove(pos);
                            }
                            int max = copydata.size();
                            int min = 0;
                            Random random = new Random();
                            int rNum = random.nextInt(max) % (max - min + 1) + min;
                            mVideoPath = copydata.get(rNum).getAbsolutePath();
                            fileName = copydata.get(rNum).getName();
                            // mVideoPath = copydata.get(rNum).getFilepath();
                            for (int i = 0; i < data.size(); i++) {
                                if (data.get(i).getAbsolutePath().equals(copydata.get(rNum).getAbsolutePath())) {
                                    currentPos = i;
                                }
                            }
                            //Logger.i("随机::555" + "currentPos=" + currentPos);
                            if (currentPos < data.size()) {
                                mVideoPath = data.get(currentPos).getAbsolutePath();
                                fileName = data.get(currentPos).getName();
                                // Logger.i("随机::555" + "mVideoPath=" + mVideoPath);
                                copydata.remove(rNum);
                            }
                        } else {
                            copydata = (ArrayList<File>) data.clone();
                        }
                    } else if (playMode == 3) {
                        //   Logger.i(TAG, "播放完毕进入循环模式");
                        // Logger.i("随机::777" + "currentPos=" + currentPos);
                        //  Logger.i("随机::777" + "mVideoPath=" + mVideoPath);

                    }
                    currentPosition = 0;
                    prepare();
                }
            });


        }

    }



  /*  @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {

        release();

        return true;
    }*/


    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        Logger.i("播放器ViewState:onError");
        Logger.i(TAG + "播放错误:" + what + "?" + extra + "?" + mVideoPath);
        isPlay = false;

        if (!iv_play.isSelected()) {
            iv_play.setSelected(true);
            prepare();
            // release();
        }
        return true;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Logger.i("ViewState:onDestroy");
        release();
        RxUtils.unsubscribe(seekBarSubscription);
        RxUtils.unsubscribe(yinGUISubscription);
        RxUtils.unsubscribe(nextMediaSubscription);
        if (receiver != null) {
            unregisterReceiver(receiver);
        }
    }


    public void releaseWithoutStop() {
        if (mMediaPlayer != null) {
            mMediaPlayer.setDisplay(null);
        }
    }

    public void release() {
        try {
            if (mMediaPlayer != null) {
                mMediaPlayer.stop();
                mMediaPlayer.reset();
                mMediaPlayer.release();
                mMediaPlayer = null;
            }
        } catch (IllegalStateException e) {
            mMediaPlayer = null;
        }

    }

    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {

        Log.i(TAG, "OnInfo, what = " + what + ", extra = " + extra);
        switch (what) {
            case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                iv_pb.setVisibility(View.VISIBLE);
                break;
            case MediaPlayer.MEDIA_INFO_BUFFERING_END:
            case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
                iv_pb.setVisibility(View.GONE);
               /* HashMap<String, String> meta = mMediaPlayer.getMetadata();
                Log.i(TAG, "meta: " + meta.toString());*/


                BrowseLog browseLog = new BrowseLog(module_name, fileName, mVideoPath, System.currentTimeMillis() + "");

                //  Logger.i("数据库插入:" + "module_name:" + module_name);

                dbUtils.insertBrowseLog(browseLog);

                seekBarSubscription = RxUtils.countUpTime().subscribe(new Subscriber<String>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(String s) {
                        if (mMediaPlayer != null) {
                            long currentPosition = mMediaPlayer.getCurrentPosition();

                            int progress = (int) ((currentPosition / (float) mMediaPlayer
                                    .getDuration()) * 100);
                            //  Logger.i(TAG + "视频播放进度:" + progress);
                            seekBar.setProgress(progress);
                        }
                    }
                });
                break;

            default:
                break;
        }
        return true;
    }


    @Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {
        Log.d(TAG, "onBufferingUpdate: " + percent + "%");
    }


}





布局文件:



<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.wyt.hcy.leyuanindustryproject.VideoPalyActivity">


    <SurfaceView
        android:id="@+id/sv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


    <RelativeLayout
        android:id="@+id/rl_title"
        android:layout_width="match_parent"
        android:layout_height="98dp">
        <!--系统电池 wifi 返回-->
        <include layout="@layout/layout_taskbar"></include>

    </RelativeLayout>


    <!--LoadingView-->
    <ImageView
        android:id="@+id/iv_pb"
        android:layout_width="25dp"
        android:layout_height="25dp"
        android:layout_centerInParent="true"
        android:src="@drawable/progress_anim" />


    <!--视频播放工具栏-->
    <RelativeLayout
        android:id="@+id/rl_bottom"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_alignParentBottom="true"
        android:background="@mipmap/video_play_bg">

        <ImageView
            android:id="@+id/iv_previous"
            android:layout_width="72dp"
            android:layout_height="72dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="43dp"
            android:clickable="true"
            android:scaleType="fitCenter"
            android:src="@drawable/iv_previous_press" />

        <ImageView
            android:id="@+id/iv_play"
            android:layout_width="72dp"
            android:layout_height="72dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="25dp"
            android:layout_toRightOf="@+id/iv_previous"
            android:clickable="true"
            android:scaleType="fitCenter"
            android:src="@drawable/iv_play_press" />


        <ImageView
            android:id="@+id/iv_next"
            android:layout_width="72dp"
            android:layout_height="72dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="25dp"
            android:layout_toRightOf="@+id/iv_play"
            android:clickable="true"
            android:scaleType="fitCenter"
            android:src="@drawable/iv_next_press" />


        <ImageView
            android:id="@+id/iv_state"
            android:layout_width="72dp"
            android:layout_height="72dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="25dp"
            android:layout_toRightOf="@+id/iv_next"
            android:clickable="true"
            android:scaleType="fitCenter"
            android:src="@drawable/iv_state_shunxu_press" />


        <SeekBar
            android:id="@+id/seekbar"
            android:layout_width="312dp"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="20dp"
            android:layout_toRightOf="@+id/iv_state"
            android:max="100"
            android:maxHeight="15dp"
            android:progressDrawable="@drawable/seekbar_style_01"
            android:thumb="@drawable/seekbar_thumb_style_01" />


        <TextView
            android:id="@+id/tv_video"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="10px"
            android:layout_toRightOf="@+id/seekbar"
            android:gravity="center"
            android:text="00:00"
            android:textColor="#ffffff"
            android:textSize="15px" />


        <ImageView
            android:id="@+id/iv_sing_state"
            android:layout_width="72dp"
            android:layout_height="72dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="25dp"
            android:layout_toRightOf="@+id/tv_video"
            android:clickable="true"
            android:scaleType="fitCenter"
            android:src="@drawable/iv_singstate_press" />


        <ImageView
            android:id="@+id/iv_huatong"
            android:layout_width="72dp"
            android:layout_height="72dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="44dp"
            android:clickable="true"
            android:scaleType="fitCenter"
            android:src="@drawable/iv_huatong_press" />

    </RelativeLayout>

    
</RelativeLayout>


          










Android本地视频播放器开发教程 在playVideo()方法中,我们创建一个新的MediaPlayer对象,并将SurfaceHolder设置为显示视频画面的目标。此外,在真实的应用程序中,你还需要处理权限请求和运行时权限的相关逻辑。在项目创建过程中,请确保选择适当的最低API级别,并添加必要的权限,如读取存储权限。将你的视频文件复制到Android项目的assets文件夹中,并在代码中设置正确的视频文件路径。在这个布局中,我们使用了一个SurfaceView来显示视频画面,并添加了一个Play按钮。步骤 2:添加布局文件。 阅读详情

相关推荐

android学习笔记---44_在线视频播放器,网络视频解析器,SurfaceView 控件使用方法

44_在线视频播放器 ------------------------- 1.注意这里,在模拟器中,android2.2和android2.1视频是没有播放效果的,这个主要是因为模拟器的原因和程序代码无关 ----------------------------------------------------------------------------------------------

添柴程序猿的专栏 3793

MediaPlayer的核心-NuPlayer

之前整理过[Android MediaPlayer源码分析],知道MediaPlayer的核心是NuPlayer实现视频的解码、渲染、同步、输出,这篇深入分析NuPlayer相关的知识体系

Gaga246的博客 1609

腾讯会议视频过期了怎么办?亲测可用:用这个免费插件抢救你的会议录制与回放

本文提供了三种亲测有效的腾讯会议视频过期恢复方案,包括浏览器缓存提取、专业工具组合及预防性措施。特别推荐使用免费插件抢救过期会议录制与回放,帮助职场人解决重要视频资料丢失的难题。

weixin_33686714的博客 264

android MediaPlayer获取格式信息(getFormat() 在低于19的版本用不了)

private String mimeType = ""; private MediaPlayer mMediapPlayer = null; MediaPlayer.TrackInfo[] ti = mMediapPlayer.getTrackInfo(); MediaPlayer.TrackInfo videoInfo = null; for (int i = 0; i<t...

rjc_lihui的专栏 1018

深度学习笔记(3)——kernel(内核)与filter(滤波器)

本文仅仅简单介绍了kernel和filter的概念,介绍了确定filter和kernel个数的方法。

cs111211的博客 7136

Labview数据存储与读取——TDMS文件的创建与写入

Labview数据存储与读取——TDMS文件的创建与写入 你好,这是我在自学Labview编写软件过程中使用的一些功能。我在存储采集卡数据时,通过阅读大量他人的程序,发现TDM及TDMS文件十分适合波形数据的记录,TDMS文件比TDM文件在存储动态类型数据时读写速度更快,而且TDMS 文件没有容量限制,适合存储数据量庞大的测试数据。 前言少叙,书归正传 这一篇博客,说明一下如何使用基本的TDMS功能实现数据文件的存储。 所需要的控件如上图所示,在程序框图——编程——文件I\O——TDMS 中,写入TDMS

滑板小帅程序开发 2万+

MediaPlayer 同步加载字幕 与 手动解析字幕

通过把 字幕文件传给MediaPlayer  , media 可以在自动的适配字幕, 在正确的时间点, 给我们 当前应该显示的字幕回调 不过只能在 API 16 以上才能使用  mMediaPlayer = new MediaPlayer(); try { mMediaPlayer.addTimedTextSource(path, MediaPlayer.MEDIA_MIME

chen930724的专栏 9613

OpenModelica入门指南:从下载安装到第一个仿真模型(附常见问题解答)

本文提供OpenModelica开源项目的完整入门指南,涵盖从下载安装、界面熟悉到构建首个仿真模型的全过程。通过创建经典的阻尼震荡系统实例,详细讲解组件拖放、参数设置、仿真运行及结果分析,并附有常见问题解决方案,帮助工程师和研究人员快速上手这一强大的多领域物理系统建模与仿真工具。

weixin_29239279的博客 725

Android MediaPlayer 字幕同步

第一次写博客,逻辑有点乱,见谅~ Android从API16中更新对字幕追踪的支持,具体是下面几个方法。 Added in API level 16 public void addTimedTextSource (Context context, Uri uri, String mimeType) public void addTimedTextSource (String

ANDROID 笔记栈 9320

初识YUV,实战NV21格式数据转换为Bitmap

初识YUV,并使用YUV数据生成Bitmap图像一、初识YUV二、采样方式2.1、YUV 4:4:42.2、YUV 4:2:22.2、YUV 4:2:2 一、初识YUV 说到YUV我们就必须先从RGB说起了,如下图所示,请各位把每个色块当成一个像素点。通常一个像素点由RGB(Alpha我们先不考虑)三原色组成。 如下图中第一个像素点,其RGB值分别为(236,102,93),而这三个值就组成了我们看到的 红色 。 然而上图中除了RGB值外,我还标出了每个像素点的YUV的值,YUV的值是怎么来的呢?直接给公

乐翁龙 7125

《生化危机9:安魂曲》D加密免BIOS破解方案详解

数字版权管理(DRM)技术通过加密手段保护软件版权,Denuvo(D加密)作为主流方案常应用于3A游戏。其原理是通过实时验证机制阻止未授权访问,但可能影响性能表现。本文以《生化危机9》为例,解析一种免BIOS修改的D加密绕过方案,该方案通过授权启动器模拟正版验证流程,保持系统零侵入性。实测表明,该方法在GTX 1060至RTX 3070等多硬件平台均能稳定运行,支持MOD扩展且兼容Reshade画质增强,为玩家提供开箱即用的绿色版体验。

weixin_33898233的博客 924

Android MediaPlayer 设置音轨

因为很多视频流是包含多个音轨的,所以实现播放器的时候,需要考虑音轨选择的问题。 在android中,音频、视频统一被类TrackInfo描述,当然还不止这两类,可以看一下定义,还包含字幕等类型,都为Track信息。         public static final int MEDIA_TRACK_TYPE_UNKNOWN = 0;         public static final

jl2011的博客 1万+

亿佰特E77模块(STM32WLE5CCU6)LoRa通信实战指南:从配置到应用开发

本文详细介绍了亿佰特E77模块(STM32WLE5CCU6)的LoRa通信实战指南,从硬件配置到应用开发。基于ARM Cortex-M4内核的E77模块集成了LoRa射频前端,具备超低功耗和硬件级抗干扰特性,适用于智能农业、工业现场等场景。文章提供了开发环境搭建、LoRa参数配置、实战通信及性能优化等实用技巧,帮助开发者快速掌握LoRa通信技术。

weixin_29164185的博客 760

Android视频播放器

分为两部分,本地视频播放器,和在线视频播放器,与音乐播放器类似,主要是用到了提供的MediaPlayer对象,此处与音乐播放器不同是需要一个`SurfaceView`控件,来实现对视频画面的显示,并且要求当Activity不在前台时视频播放停止,当Activity回到前台时,视频播放继续。

上善若水 1538

iOS安全和逆向系列教程 第18篇:iOS应用脱壳技术详解与实战

iOS应用脱壳技术详解与实战 摘要: 本文深入剖析了iOS应用脱壳技术,首先解释了加壳(如FairPlay DRM)与脱壳的基本概念及必要性。通过otool命令可以检测应用的加密状态。文章详细介绍了三种主流脱壳工具:经典dumpdecrypted工具的使用方法、现代化Clutch工具的安装配置以及基于Frida的高级脱壳方案frida-ios-dump。针对特殊情况,还提供了使用LLDB手动dump内存的技术细节,包括查找基地址、计算dump范围和内存读取等操作。最后介绍了修复Mach-O文件头的Pytho

一个自学不成材的程序员 710

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

【亲测免费】 Android 视频播放器 Demo

本项目是一个基于 Android 平台的视频播放器 Demo,使用 `MediaPlayer` 和 `SurfaceView` 实现视频播放功能,并自定义了视频控制器,提供了基本的播放、暂停、进度条拖动等功能。 ## 功能特点 - **视频播放**:使用 `MediaPlayer` 播放本地或网络视频。 - **自定义控制器**:通过自定义控制器实现播放、暂停、进度条拖动等操作。 - **Su

gitblog_09810的博客 651

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

一个kotlin实现的视频播放器

一个kotlin实现的视频播放器

daxiangzaici的博客 357

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

【Code-Snippet】Video播放

概述 视频播放,有几中方式: 调用android自带的视频播放器 使用VideoView 使用SurfaceView结合MediaPlayer 第三方开源库 1. 调用android本地的视频播放器 // 0. 定义好视频的路径 Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath()+"/hehe...

weixin_33779515的博客 147

Android自定义音视频播放器

自定义View播放器已经实现了,但我们需要掌握MediaPlayer的初始化过程是怎么样的,MediaPlayer做了哪些工作,音视频数据如何渲染到SurfaceView上面的,这需要把MediaPlayer框架原理搞清楚。随着快手,抖音,西瓜视频等视频APP的崛起,视频播放已经成为主流,此时做为Android研发的你,想要提升本身的能力还不知道怎么开发视频播放器怎么行?等等,这些部分的播放器我们在开发过程中,使用过这些视频播放框架来播放本地视频或者网络视频,但不一定会满足业务需求的。

qq_31481093的博客 2333

简易视频播放器的制作

package com.example.videoplayer; import java.io.FileDescriptor; import android.app.Activity; import android.content.res.AssetFileDescriptor; import android.media.AudioManager; import android.media.Me

androiddeveloper的专栏 1722

探索Android视频播放的无限可能:Android视频播放器Demo

在移动应用开发中,视频播放功能是不可或缺的一部分。为了帮助开发者快速实现这一功能,我们推出了一个基于Android平台的视频播放器Demo。这个项目不仅展示了如何使用`MediaPlayer`和`SurfaceView`来实现视频播放,还通过自定义控制器提供了丰富的用户交互体验。无论是本地视频还是网络视频,这个Demo都能轻松应对,为你的应用增添一抹亮色。 ## 项目技术分析 ### 核心技术

gitblog_09778的博客 927

android播放视频

android播放视频用的是SurfaceView和MediaPlayer 具体实现和播放音乐一样 package com.example.videoplayer; import android.media.MediaPlayer; import android.os.Bundle; import android.app.Activity; import android.v...

weixin_34279246的博客 197

android视频播放(二) 利用android原生的MediaPlayer+SurfaceView

转载请注明地址: http://blog.youkuaiyun.com/shenxiaolei507

San石的博客 1万+

MediaPlayer配合SurfaceView或TextureView做视频播放器时的截图方法。

好久没写博客了,偷懒了半年。自从我下定决心辞职转行当程序员,开始投简历后就没写博客了。一直给自己找借口说太忙了没时间写。最近下定决心要重新开始写博客,虽然写的挫但是就当作一种学习记录吧。 今天有空就说写下最近遇到的难题,需要在应用内截取一个视频播放器的当前画面拿来分享。播放器是用Android本身的MediaPlayer+TextureView实现的,使用View中的buildDrawingCa...

weixin_30721077的博客 269

视频播放器(一)——简介篇

从这篇开始,详细讲解一下视频播放器的内容。由于在过程中,只是使用了surfaceView+MediaPlayer来播放视频,并没有使用软解码什么的,所以可能就只支持Android本身支持的视频格式。当然,也遗留了很多问题,毕竟我也是在一个学习的过程中,后边会贴出遗留的问题,希望懂的朋友指点一下。好了,下面先来说说实现了哪些功能: 1. 首先分类在线视频和本地视频两大模块 2. 支持播放/暂停,上

xingxing_yan的博客 3570

android中使用surfaceview+MediaPlayer播放视频

Android中播放视频主要有两种方式: 使用其自带的播放器。指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型 使用android自带的VideoView,这种方法太简单就不介绍了 使用SurfaceView+MediaPlayer,这种方式效果比较好,这里也重点介绍 SurfaceView从android 1.0就有了,十分好用。一般来说,UI对刷新都需要...

weixin_30750335的博客 120
上一篇: android 积累一些自定义view的知识
下一篇: Android 用surfaceview模拟帧动画的效果,解决帧动画的OOM问题
泡温泉的咸鱼
博客等级 码龄11年 39粉丝 48原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值