SurfaceView播放视频发送弹幕并实现滚动歌词

本文实例为大家分享了SurfaceView播放视频发送弹幕,并实现滚动歌词,供大家参考,具体内容如下

SurfaceView使用步骤

使用SurfaceView的步骤:

  • 首先要继承SurfaceView,实现SurfaceHolder.Callback接口。
  • 重写方法:surfaceChanged:surface大小或格式发生变化时触发,在surfaceCreated调用后该函数至少会被调用一次。
  • surfaceCreated:Surface创建时触发,一般在这个函数开启绘图线程(新的线程,不要再这个线程中绘制Surface)。
  • surfaceDestroyed:销毁时触发,一般不可见时就会销毁。
  • 利用getHolder()获取SurfaceHolder对象,调用SurfaceHolder.addCallback添加回调
  • SurfaceHolder.lockCanvas 获取Canvas对象并锁定画布,调用Canvas绘图,SurfaceHolder.unlockCanvasAndPost 结束锁定画布,提交改变。

SurfaceHolder

SurfaceHolder回调自己的三个生命周期:

  • surfaceCreated(SurfaceHolder holder)创建时
  • surfaceChanged(SurfaceHolder holder, int format, int width, int height)改变时
  • surfaceDestroyed(SurfaceHolder holder)销毁时

SurfaceView播放视频并可以发送弹幕

需要准备两个SurfaceView,一个是负责播放视频,一个负责展示弹幕。弹幕是展示在视频上面的,所以我们要给展示弹幕的SurfaceView设置两个方法:
surfaceView_danmu.setZOrderOnTop(true); ——置于上方
surfaceView_danmuHolder.setFormat(PixelFormat.TRANSPARENT); ——背景透明

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {

  public static final int PROGRESS = 101;

  SurfaceView surfaceView,surfaceView_danmu;
  SurfaceHolder surfaceHolder,surfaceView_danmuHolder;
  MediaPlayer mediaPlayer = new MediaPlayer();
  String path = "/sdcard/aa.mp4";
  SeekBar seekBar;
  Timer timer;
  EditText editText;
  Button button,bt_start,bt_stop;
  int x = 0;

  ArrayList<DanMu> list = new ArrayList<>();
  Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
      super.handleMessage(msg);
      if (msg.what == PROGRESS){
        seekBar.setProgress((Integer) msg.obj);
        mediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
          @Override
          public void onSeekComplete(MediaPlayer mp) {
            Toast.makeText(MainActivity.this, "播放完毕!", Toast.LENGTH_SHORT).show();
          }
        });
      }
    }
  };

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

    surfaceView = findViewById(R.id.sufaceview);
    surfaceView_danmu = findViewById(R.id.sufaceview_danmu);
    editText = findViewById(R.id.et);
    button = findViewById(R.id.bt_send);
    seekBar = findViewById(R.id.bar);
    bt_start = findViewById(R.id.bt_start);
    bt_stop = findViewById(R.id.bt_stop);

    surfaceHolder = surfaceView.getHolder();
    surfaceHolder.addCallback(this);

    surfaceView_danmuHolder = surfaceView_danmu.getHolder();
    surfaceView_danmuHolder.addCallback(this);
    surfaceView_danmu.setZOrderOnTop(true);
    surfaceView_danmuHolder.setFormat(PixelFormat.TRANSPARENT);

    if (mediaPlayer!=null) {
      try {
        mediaPlayer.setDataSource(path);
        mediaPlayer.prepareAsync();
        mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
          @Override
          public void onPrepared(MediaPlayer mp) {
            mediaPlayer.start();

            int duration = mediaPlayer.getDuration();
            seekBar.setMax(duration);

            timer = new Timer();
            timer.schedule(new TimerTask() {
              @Override
              public void run() {
                int currentPosition = mediaPlayer.getCurrentPosition();
                Message message = Message.obtain();
                message.what = PROGRESS;
                message.obj = currentPosition;
                handler.sendMessage(message);
              }
            },0,1000);
          }
        });

        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
          @Override
          public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
          }

          @Override
          public void onStartTrackingTouch(SeekBar seekBar) {

          }

          @Override
          public void onStopTrackingTouch(SeekBar seekBar) {
            int progress = seekBar.getProgress();
            mediaPlayer.seekTo(progress);
          }
        });
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    button.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        String s = editText.getText().toString();
        int y= (int) (Math.random()*300);
        list.add(new DanMu(0,y,s,Color.RED));
      }
    });

    bt_start.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        mediaPlayer.start();
      }
    });

    bt_stop.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        mediaPlayer.pause();
      }
    });
  }

  @Override
  public void surfaceCreated(SurfaceHolder holder) {
    if (holder == surfaceHolder) {
      mediaPlayer.setDisplay(holder);
    }else if (holder == surfaceView_danmuHolder) {
      new MyDanMuThread().start();
    }
  }

  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

  }

  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {

  }

  class MyDanMuThread extends Thread {
    @Override
    public void run() {
      super.run();
      Paint paint = new Paint();
      paint.setColor(Color.RED);
      paint.setTextSize(40);
      while (true) {
        try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        Canvas canvas = surfaceView_danmuHolder.lockCanvas();
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        for (int i=0;i<list.size();i++) {
          DanMu danMu = list.get(i);
          x = danMu.getX();
          danMu.setX(x+=10);
          canvas.drawText(danMu.getText(),danMu.getX(),danMu.getY(),paint);
        }
        surfaceView_danmuHolder.unlockCanvasAndPost(canvas);
      }
    }
  }
}

实现滚动歌词

要准备一个装有时间和歌词的集合,准备一个Timer计时器和一个该展示第几个歌词。每隔一秒去拿该歌词的下一个歌词时间与进度匹配,如果进度>=该时间,那么就画该歌词在SurfaceView上;<则不画该歌词

一定要写SD卡读写权限!!!!!

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback{
  SurfaceView surfaceView;
  SurfaceHolder surfaceHolder;
  MediaPlayer mediaPlayer = new MediaPlayer();
  ArrayList<Music> list=new ArrayList<>();
  Timer timer;
  int count = 0;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    surfaceView = findViewById(R.id.sv);

    surfaceHolder=surfaceView.getHolder();
    surfaceHolder.addCallback(this);

    timer = new Timer();
    timer.schedule(new TimerTask() {
      @Override
      public void run() {
        int currentPosition = mediaPlayer.getCurrentPosition();
        if(list.size()>0){
          if(currentPosition>=list.get(count+1).getTime()){
            count++;
          }
        }

      }
    },0,500);

    try {
      mediaPlayer.setDataSource("/sdcard/凤凰传奇 - 最炫民族风(Live).mp3");
      mediaPlayer.prepareAsync();
      mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
          mediaPlayer.start();
        }
      });
    } catch (IOException e) {
      e.printStackTrace();
    }

    try {
      StringBuffer stringBuffer = new StringBuffer();
      FileInputStream fileInputStream = new FileInputStream("/sdcard/最炫民族风");
      byte[] bytes = new byte[1024];
      int len = 0;
      while ((len=fileInputStream.read(bytes))!=-1) {
        stringBuffer.append(new String(bytes,0,len));
      }

      Gson gson = new Gson();
      JavaBean javaBean = gson.fromJson(stringBuffer.toString(), JavaBean.class);
      JavaBean.LrcBean lrc = javaBean.getLrc();
      String lyric = lrc.getLyric();

      String[] split = lyric.split("\n");
      for(int i=0;i<split.length;i++){
        String trim = split[i].trim();
        String[] split1 = trim.split("]");
        if(split.length>=2){
          String s = split1[0];
          String substring1 = s.substring(1, 3);
          String substring2 = s.substring(4, 6);
          String substring3 = s.substring(7, 10);
          long start = Integer.parseInt(substring1)*60*1000+Integer.parseInt(substring2)*1000+Integer.parseInt(substring3);
          String text = split1[1];
          list.add(new Music(text,start));
        }
      }
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  @Override
  public void surfaceCreated(SurfaceHolder holder) {
    new MyThread().start();
  }

  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

  }

  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {

  }

  class MyThread extends Thread {
    @Override
    public void run() {
      super.run();
      Paint paint = new Paint();
      paint.setColor(Color.RED);
      paint.setTextSize(50);
      while (true){
        try {
          Thread.sleep(100);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        Canvas canvas = surfaceHolder.lockCanvas();
        if(canvas==null){
          break;
        }
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        if(list.size()>0){
          canvas.drawText(list.get(count).getTitle(),100,100,paint);
        }
        surfaceHolder.unlockCanvasAndPost(canvas);
      }
    }
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android实现歌词滚动效果

    本文实例为大家分享了Android实现歌词滚动效果的具体代码,供大家参考,具体内容如下 自定义TextView public class VerticalScrollTextView extends TextView { private Paint mPaint; private float mX; private Paint mPathPaint; public int index = 0; private List<Sentence> list; public float mTouchHi

  • Android实现视频弹幕功能

    本文实例为大家分享了Android视频弹幕的具体代码,供大家参考,具体内容如下 效果图: 上图:代码随机生成的弹幕及弹幕输入栏 下图:绿色框的弹幕为用户手动添加发送的弹幕 1.准备工作 准备一个视频文件,将该视频文件放到res/raw目录下. 需要将视频设置为横屏播放,即往配置文件中添加android:screenOrientation="landscape": <activity android:name=".MainActivity" android:co

  • Android 基于RecyclerView实现的歌词滚动自定义控件

    本文介绍了Android 基于RecyclerView实现的歌词滚动自定义控件,分享给大家,具体如下: 先来几张效果图: 这几天打算做一个控件,来让自己复习一下自定义 view 的知识以及事件分发机制的原理与应用.对于这个控件,我已经封装好了,只要调用就可以了. 本来是想放上 gitHub 和 添加依赖的.但是提交 github 出了问题一直不会弄,所以就只能先等等了.((:′⌒`)) 接下来说一下实现原理: 该控件分为以下几个部分: 歌词自动滚动 歌词颜色字体变化 触碰屏幕歌词不滚动,高亮显示

  • android实现歌词自动滚动效果

    最近在做Android 的MP3播放的项目,要实现歌词的自动滚动,以及同步显示. lyric的歌词解析主要用yoyoplayer里面的,显示部分参考了这里 ,这里只是模拟MP3歌词的滚动. 先上一下效果图: 滚动实现的代码其实也简单.显示画出当前时间点的歌词,然后再分别画出改歌词后面和前面的歌词,前面的部分往上推移,后面的部分往下推移,这样就保持了当前时间歌词在中间. 代码如下 LyricView,相关信息在注释了标明了. package ru.org.piaozhiye.lyric; impo

  • 比较完整的android MP3 LRC歌词滚动高亮显示(附源码)

    1.以前的滚动只是安行来刷新,现在不是按行来滚动了,其实就是在一定时间内整体往上移动,比如说在1S内刷新10次,由于认得肉眼看起来像是滚动. 关键代码如下: 复制代码 代码如下: float plus = currentDunringTime == 0 ? 30                : 30                        + (((float) currentTime - (float) sentenctTime) / (float) currentDunringTim

  • 使用SurfaceView实现视频弹幕

    本文实例为大家分享了SurfaceView视频弹幕展示的具体代码,供大家参考,具体内容如下 全部代码如下: package com.example.app2; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff; imp

  • SurfaceView播放视频发送弹幕并实现滚动歌词

    本文实例为大家分享了SurfaceView播放视频发送弹幕,并实现滚动歌词,供大家参考,具体内容如下 SurfaceView使用步骤 使用SurfaceView的步骤: 首先要继承SurfaceView,实现SurfaceHolder.Callback接口. 重写方法:surfaceChanged:surface大小或格式发生变化时触发,在surfaceCreated调用后该函数至少会被调用一次. surfaceCreated:Surface创建时触发,一般在这个函数开启绘图线程(新的线程,不要

  • Android中使用TextureView播放视频

    如果你想显示一段在线视频或者任意的数据流比如视频或者OpenGL 场景,你可以用android中的SurfaceView或者TextureView做到. 1).TextureView的兄弟SurfaceView 应用程序的视频或者opengl内容往往是显示在一个特别的UI控件中:SurfaceView. SurfaceView的工作方式是创建一个置于应用窗口之后的新窗口.这种 方式的效率非常高,因为SurfaceView窗口刷新的时候不需要重绘应用程序的窗口(android普通窗口的视图绘制机制

  • android使用surfaceview+MediaPlayer播放视频

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

  • android surfaceView实现播放视频功能

    本文实例为大家分享了android surfaceView实现播放视频的具体代码,供大家参考,具体内容如下 RelativeLayout <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.an

  • 微信小程序实现视频播放器发送弹幕

    本文实例为大家分享了微信小程序实现视频播放器发送弹幕的具体代码,供大家参考,具体内容如下 一.视频播放器 video-detail 视频播放器 select-color 发送弹幕 1. 页面制作 2. 选择弹幕颜色 3. Video插件的使用 4. 相关代码 app.json //app.json { "pages":[ "pages/video-detail/video-detail", "pages/select-color/select-color&

  • Android多媒体教程之播放视频的四种方法

    本文主要给大家介绍的是关于Android播放视频的四种方法,分享出来供大家参考学习,下面来一起看看详细的介绍: 一.通过intent的方式,调用系统自带的播放器 Uri uri = Uri.parse("/storage/emulated/0/DCIM/Camera/20170521_200117.mp4"); //调用系统自带的播放器 Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(uri,

  • Android播放视频的三种方式

    在Android中,我们有三种方式来实现视频的播放: 1).使用其自带的播放器.指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型. 2).使用VideoView来播放.在布局文件中使用VideoView结合MediaController来实现对其控制. 3).使用MediaPlayer类和SurfaceView来实现,这种方式很灵活. 1.调用其自带的播放器: Uriuri = Uri.parse(Environment.getExternalStorageD

  • 代码详解iOS视频直播弹幕功能

    本篇内容通过步骤详细给大家讲解了iOS视频直播弹幕的原理以及实现代码分析,以下就是全部内容: 1.弹幕的实现性分析 首先,从视觉上明确当前弹幕所具有的功能 从屏幕右侧滑入左侧,直至完全消失 不管是长的弹幕,还是短的弹幕,速度一致(可能有的需求是依据弹幕长度,调整速度) 有弹幕轨道,不是随机产生的弹幕 弹幕不会进行重叠 接下来从功能角度思考需要做什么 重用机制,类似tableView有一个重用池,每个弹幕就是一个cell,当有弹幕发送的时候,如果当前的重用池没有控件,则创建一个新的控件,如果重用池

  • Android ViewPager中显示图片与播放视频的填坑记录

    ViewPager介绍 ViewPager的功能就是可以使视图滑动,就像Lanucher左右滑动那样. ViewPager用于实现多页面的切换效果,该类存在于Google的兼容包android-support-v4.jar里面. ViewPager: 1)ViewPager类直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的view类. 2)ViewPager类需要一个PagerAdapter适配器类给它提供数据. 3)ViewPager经常和Fragment一起使用,并且

  • 使用Go基于WebSocket构建千万级视频直播弹幕系统的代码详解

    (1)业务复杂度介绍 开门见山,假设一个直播间同时500W人在线,那么1秒钟1000条弹幕,那么弹幕系统的推送频率就是: 500W * 1000条/秒=50亿条/秒 ,想想B站2019跨年晚会那次弹幕系统得是多么的NB,况且一个大型网站不可能只有一个直播间! 使用Go做WebSocket开发无非就是三种情况: 使用Go原生自带的库,也就是 golang.org/x/net ,但是这个官方库真是出了奇Bug多 使用GitHub大佬 gorilla/websocket 库,可以结合到某些Web开发框

随机推荐