Android 视频播放工具类MediaPlayer+TextureView

该博客详细介绍了如何使用Android的TextureView和MediaPlayer类来创建一个视频播放器。它涵盖了从初始化播放器到处理播放、暂停、错误和完成事件的整个过程,并强调了播放网络视频需要的权限。同时,提供了回调接口用于处理播放状态的变化。
摘要由CSDN通过智能技术生成

package com.sdxw.floatbottle.utils.record;

import android.Manifest;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.view.Gravity;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ProgressBar;

import androidx.annotation.NonNull;

import com.sdxw.floatbottle.utils.L;

import java.io.FileDescriptor;
import java.io.IOException;

/**

  • @创建日志 2021-2-7 13:30

  • @描述 视频播放器 TextureView+MediaPlayer

  • @备注 播放网络视频需要添加权限 Manifest.permission.INTERNET
    */
    public class VideoPlayer implements TextureView.SurfaceTextureListener {
    private static VideoPlayer player;
    private MediaPlayer mediaPlayer;
    private FrameLayout frameLayout;
    private String playPath;// 播放路径
    private Callback callback;// 回调
    private Context context;
    private ProgressBar progressBar;

    public interface Callback {
    void onError(String msg);

     void onStarted();
    
     void onComplete();
    

    }

    private VideoPlayer() {
    }

    public static VideoPlayer getInstance() {
    if (player == null) {
    synchronized (VideoPlayer.class) {
    if (player == null) {
    player = new VideoPlayer();
    }
    }
    }
    return player;
    }

    /**

    • 播放视频

    • @param context

    • @param frameLayout

    • @param path
      */
      public void play(Context context, FrameLayout frameLayout, String path) {
      L.d(“VideoPlayer.play:” + path);
      this.context = context.getApplicationContext();
      this.playPath = path;
      this.frameLayout = frameLayout;
      if (frameLayout == null || path == null) return;
      for (int i = 0; i < frameLayout.getChildCount(); i++) {
      if (frameLayout.getChildAt(i) != null
      && (frameLayout.getChildAt(i) instanceof TextureView
      || frameLayout.getChildAt(i) instanceof ProgressBar)) {
      frameLayout.removeView(frameLayout.getChildAt(i));
      }
      }
      TextureView textureView = new TextureView(context);
      textureView.setSurfaceTextureListener(this);
      textureView.setLayoutParams(new FrameLayout.LayoutParams(
      FrameLayout.LayoutParams.MATCH_PARENT,
      FrameLayout.LayoutParams.MATCH_PARENT
      ));

      this.progressBar = new ProgressBar(context);
      FrameLayout.LayoutParams plp = new FrameLayout.LayoutParams(80, 80);
      plp.gravity = Gravity.CENTER;
      this.progressBar.setLayoutParams(plp);
      frameLayout.addView(textureView);
      frameLayout.addView(this.progressBar);
      }

    /**

    • 停止播放
      */
      public void stop() {
      if (mediaPlayer != null) {
      if (mediaPlayer.isPlaying()) {
      mediaPlayer.stop();
      }
      mediaPlayer.reset();
      mediaPlayer.release();
      mediaPlayer = null;
      }
      }

    /**

    • 是否循环播放-默认循环播放
    • @param isLoop
      */
      public void setLoop(boolean isLoop) {
      if (mediaPlayer != null) {
      mediaPlayer.setLooping(isLoop);
      }
      }

    /**

    • 设置回调
    • @param callback
      */
      public void setCallback(Callback callback) {
      this.callback = callback;
      }

    /**

    • 开始播放

    • @param surface
      */
      private void startPlay(Surface surface) {
      try {
      if (mediaPlayer == null)
      mediaPlayer = new MediaPlayer();

       mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
       mediaPlayer.setScreenOnWhilePlaying(true);
      
       if (playPath.startsWith("http:") || playPath.startsWith("https:")) {
           mediaPlayer.setDataSource(this.context, Uri.parse(playPath));
       } else {
           mediaPlayer.setDataSource(playPath);
       }
       mediaPlayer.setSurface(surface);
       mediaPlayer.prepareAsync();
       L.d("prepareAsync");
       mediaPlayer.setOnPreparedListener(mp -> {
           this.progressBar.setVisibility(View.GONE);
           mp.start();
           if (callback != null) {
               callback.onStarted();
           }
       });
      
       /**
        * Called to indicate an error.
        *
        * @param mp      the MediaPlayer the error pertains to
        * @param what    the type of error that has occurred:
        * <ul>
        * <li>{@link #MEDIA_ERROR_UNKNOWN 1}
        * <li>{@link #MEDIA_ERROR_SERVER_DIED 100} Media server died. In this case, the application must release the
        *      * MediaPlayer object and instantiate a new one.
        * </ul>
        * @param extra an extra code, specific to the error. Typically
        * implementation dependent.
        * <ul>
        * <li>{@link #MEDIA_ERROR_IO}
        * <li>{@link #MEDIA_ERROR_MALFORMED}
        * <li>{@link #MEDIA_ERROR_UNSUPPORTED}
        * <li>{@link #MEDIA_ERROR_TIMED_OUT}
        * <li><code>MEDIA_ERROR_SYSTEM (-2147483648)</code> - low-level system error.
        * </ul>
        * @return True if the method handled the error, false if it didn't.
        * Returning false, or not having an OnErrorListener at all, will
        * cause the OnCompletionListener to be called.
        */
       mediaPlayer.setOnErrorListener((mp, what, extra) -> {
           if (callback != null) {
               callback.onError("播放失败");
           }
           L.e("mediaPlayer-err:what=" + what + "::extra=" + extra);
           return false;
       });
       mediaPlayer.setOnInfoListener((mp, what, extra) -> {
           if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START && frameLayout != null) {
               frameLayout.setBackground(null);
           }
           return false;
       });
       mediaPlayer.setOnCompletionListener(mp -> {
           if (callback != null) {
               callback.onComplete();
           }
       });
       mediaPlayer.setLooping(true);
      

      } catch (IllegalStateException ie) {
      ie.printStackTrace();
      L.e(“mediaPlayer-IllegalStateException:” + ie.getMessage(), ie);
      if (callback != null) {
      callback.onError(“播放失败,播放器发生未知错误”);
      }
      } catch (IOException e) {
      e.printStackTrace();
      L.e(“mediaPlayer-IOException:” + e.getMessage(), e);
      if (callback != null) {
      callback.onError(“播放失败,播放器出错”);
      }
      }
      }

    @Override
    public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {// 初始化完成
    startPlay(new Surface(surface));
    }

    @Override
    public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
    stop();
    return false;
    }

    @Override
    public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

    }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值