Android中使用TextureView播放视频

如果你想显示一段在线视频或者任意的数据流比如视频或者OpenGL 场景,你可以用android中的SurfaceView或者TextureView做到。

1).TextureView的兄弟SurfaceView

应用程序的视频或者opengl内容往往是显示在一个特别的UI控件中:SurfaceView。

SurfaceView的工作方式是创建一个置于应用窗口之后的新窗口。这种 方式的效率非常高,因为SurfaceView窗口刷新的时候不需要重绘应用程序的窗口(android普通窗口的视图绘制机制是一层一层的,任何一个子元素或者 是局部的刷新都会导致整个视图结构全部重绘一次,因此效率非常低下,不过满足普通应用界面的需求还是绰绰有余),但是SurfaceView也有一些非常  不便的限制。

因为SurfaceView的内容不在应用窗口上,所以不能使用变换(平移、缩放、旋转等)。也难以放在ListView或者ScrollView中,不能使用UI控件的一些特性比如View.setAlpha()。

2).Android 4.0中的TextureView。

为了解决这个问上面那个我们刚说到的问题Android 4.0中引入了TextureView;

TextureView与SurfaceView相比,TextureView并没有创建一个单独的Surface用来绘制,这使得它可以像一般的View一样执行一些变换操作,设置透明度等。

另外,Textureview必须在硬件加速开启的窗口中。

项目中碰到的问题:

1.之前用SurfaceView播放视频的时候,从图片切换到播放视频,会出现黑屏的现象。

2.SurfaceView灵活性没有TextureView好。

下面是实现源码,大家参考一下

MainActivity.java文件

package com.example.textureviewvideo; 

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream; 

import android.app.Activity;
import android.content.res.AssetManager;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.TextureView.SurfaceTextureListener;
import android.widget.ImageView; 

public class MainActivity extends Activity implements SurfaceTextureListener{
// private TextureView textureView;
  private MediaPlayer mMediaPlayer;
  private Surface surface; 

  private ImageView videoImage; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    TextureView textureView=(TextureView) findViewById(R.id.textureview);
    textureView.setSurfaceTextureListener(this);//设置监听函数 重写4个方法 

//   textureView=new TextureViewTest(this);
//   setContentView(textureView);
    videoImage=(ImageView) findViewById(R.id.video_image);
  } 

  @Override
  public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,int height) {
    System.out.println("onSurfaceTextureAvailable onSurfaceTextureAvailable");
    surface=new Surface(surfaceTexture);
    new PlayerVideo().start();//开启一个线程去播放视频
  }
  @Override
  public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,int height) {
    System.out.println("onSurfaceTextureSizeChanged onSurfaceTextureSizeChanged");
  } 

  @Override
  public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
    System.out.println("onSurfaceTextureDestroyed onSurfaceTextureDestroyed");
    surfaceTexture=null;
    surface=null;
    mMediaPlayer.stop();
    mMediaPlayer.release();
    return true;
  } 

  @Override
  public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
//   System.out.println("onSurfaceTextureUpdated onSurfaceTextureUpdated");
  } 

  private class PlayerVideo extends Thread{
    @Override
    public void run(){
       try {
         File file=new File(Environment.getExternalStorageDirectory()+"/ansen.mp4");
         if(!file.exists()){//文件不存在
           copyFile();
         }
         mMediaPlayer= new MediaPlayer();
         mMediaPlayer.setDataSource(file.getAbsolutePath());
         mMediaPlayer.setSurface(surface);
         mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
         mMediaPlayer.setOnPreparedListener(new OnPreparedListener() {
          @Override
          public void onPrepared(MediaPlayer mp){
            videoImage.setVisibility(View.GONE);
            mMediaPlayer.start();
          }
         });
         mMediaPlayer.prepare();
       } catch (Exception e) {
         e.printStackTrace();
       }
    }
  } 

  public interface PlayerController{
    public void play();
  } 

  /**
   * 如果sdcard没有文件就复制过去
   */
  private void copyFile() {
    AssetManager assetManager = this.getAssets();
    InputStream in = null;
    OutputStream out = null;
    try {
      in = assetManager.open("ansen.mp4");
      String newFileName = Environment.getExternalStorageDirectory()+"/ansen.mp4";
      out = new FileOutputStream(newFileName);
      byte[] buffer = new byte[1024];
      int read;
      while ((read = in.read(buffer)) != -1) {
        out.write(buffer, 0, read);
      }
      in.close();
      in = null;
      out.flush();
      out.close();
      out = null;
    } catch (Exception e) {
      Log.e("tag", e.getMessage());
    }
  }
}

TextureView创建的时显示图片,然后初始化播放器,预加载视频,如果视频文件不存在,从assets下copy一份到sdcard目录下,视频加载完毕隐藏图片,我这边图片默认显示的是android项目自带的图片,你们可以根据需求显示想要的图片。

activity_main.xml布局文件

<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" > 

  <TextureView
    android:id="@+id/textureview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/> 

  <ImageView
    android:id="@+id/video_image"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/ic_launcher"/>
</RelativeLayout> 

放了一个TextureView跟一个ImageView  TextureView初始化显示ImageView...当视频播放的时候隐藏ImageView,并且切换过去的时候不会出现黑屏。

如果播放在线视频出现闪屏的问题,需要开启一个线程异步播放视频,然后再用handle延时隐藏图片。我用的是延时300毫秒

private void sendEmpryMessage(){
  handler.sendEmptyMessageDelayed(0,300);//给主线程发送一个隐藏图片的消息
} 

最终效果

Demo源码下载

您可能感兴趣的文章:

  • Android截屏SurfaceView黑屏问题的解决办法
  • Android切换至SurfaceView时闪屏(黑屏闪一下)以及黑屏移动问题的解决方法
  • Android基于OpenGL的GLSurfaceView创建一个Activity实现方法
  • Android SurfaceView运行机制剖析--处理切换到后台再重新进入程序时的异常
  • Android App中使用SurfaceView制作多线程动画的实例讲解
  • Android中TextureView与SurfaceView用法区别总结
(0)

相关推荐

  • Android截屏SurfaceView黑屏问题的解决办法

    最近项目中有截屏的需求,普通的view截屏方法网上一搜一大把,但是SurfaceView截屏黑屏问题很多文章说的并不清楚,自己参考了一些别的博客,再加上自己的思考,算是找到了一种解决方案. 1.首先看我们一般是怎么用SurfaceView的 public class SuperSurfaceView extends SurfaceView implements SurfaceHolder.Callback { SurfaceHolder surfaceHolder; public SuperSu

  • Android切换至SurfaceView时闪屏(黑屏闪一下)以及黑屏移动问题的解决方法

    1.最近的项目中,有一个Activity用到Fragment+ViewPager,其中一个fragment中实现了视频播放的功能,包含有SurfaceView.结果,每次打开程序第一次进入到该Activity时都会闪屏黑一下.原因就出在SurfaceView. 详解: I think I found the reason for the black flash. In my case I'm using a SurfaceView inside a Fragment and dynamicall

  • Android App中使用SurfaceView制作多线程动画的实例讲解

    1. SurfaceView的定义 通常情况程序的View和用户响应都是在同一个线程中处理的,这也是为什么处理长时间事件(例如访问网络)需要放到另外的线程中去(防止阻塞当前UI线程的操作和绘制).但是在其他线程中却不能修改UI元素,例如用后台线程更新自定义View(调用View的在自定义View中的onDraw函数)是不允许的. 如果需要在另外的线程绘制界面.需要迅速的更新界面或则渲染UI界面需要较长的时间,这种情况就要使用SurfaceView了.SurfaceView中包含一个Surface

  • Android中TextureView与SurfaceView用法区别总结

    SurfaceView和TextureView均继承于android.view.View 与其它View不同的是,两者都能在独立的线程中绘制和渲染,在专用的GPU线程中大大提高渲染的性能. 一.SurfaceView专门提供了嵌入视图层级的绘制界面,开发者可以控制该界面像Size等的形式,能保证界面在屏幕上的正确位置. 但也有局限: 由于是独立的一层View,更像是独立的一个Window,不能加上动画.平移.缩放: 两个SurfaceView不能相互覆盖. 二.TextureView更像是一般的

  • Android基于OpenGL的GLSurfaceView创建一个Activity实现方法

    本文实例讲述了Android基于OpenGL的GLSurfaceView创建一个Activity实现方法.分享给大家供大家参考,具体如下: Android提供了两个基本的类让我们使用OpenGL ES API来创建和操纵图形:GLSurfaceView和 GLSurfaceView.Renderer.因此我们首先需要了解这两个类. 1. GLSurfaceView: 这是一个视图类,你可以调用OpenGL API在上面绘制图形和操纵物体,功能和SurfaceView相似.我们可以创建一个GLSu

  • Android SurfaceView运行机制剖析--处理切换到后台再重新进入程序时的异常

    有不少朋友都遇到过这种问题,程序执行时切换到后台,然后再重新进入会报异常,本文就这种问题全面讲解下SurfaceView的运行机制,了解了这些原理你就能自己解决这些问题了. 我们通常会通过单击HOME按键或返回按键等操作切换到后台,之后可能会再次进入程序,这个时候就有可能报异常.这里SurfaceView可能报的异常主要有两点,如下: 一.提交画布异常.如下图(模拟器错误提示,以及Logcat Detail) Java代码 public void draw() { try { canvas =

  • Android中使用TextureView播放视频

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

  • Android中SurfaceTexture TextureView SurfaceView GLSurfaceView的区别

    目录 SurfaceView GLSurfaceView SurfaceTexture TextureView 实例解读 SurfaceView, GLSurfaceView, SurfaceTexture以及TextureView是Android当中名字比较绕,关系又比较密切的几个类.本文基于Android 5.0(Lollipop)的代码理一下它们的基本原理,联系与区别. SurfaceView SurfaceView从Android 1.0(API level 1)时就有 .它继承自类Vi

  • React中使用react-player 播放视频或直播的方法

    业务中需要播放视频,寻来寻去,找到了react-player 初次点击,甚是眼熟,思来想去,竟是钉钉同款 如果使用react框架 先安装 npm install --save video-react react react-dom redux 1.引入video-react以及CSS css一定不要忘记引用 否则会出现样式丢失和奇奇怪怪的情况 切记 import "video-react/dist/video-react.css"; import { Player, ControlBa

  • 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 ViewPager中显示图片与播放视频的填坑记录

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

  • Android DragVideo实现播放视频时任意拖拽的方法

    Android DragVideo实现播放视频时任意拖拽 DragVideo A Method to Drag the Video When Playing Video 一种在播放视频时,能够拖拽的方案 为什么有这个工程 经常在爱奇艺网站上看电影,看到如果滑动掩盖了播放窗口后,就后在最下面有一个小播放界面.并且这个播放界面,是可以任意拖拽的.感觉很酷 既然web端能实现,就想了想在移动端设备上,是否也能实现这个效果,于是就有了- 效果图: ------> 实现思路:1.播放视频的view选择Te

  • 一个html5播放视频的video控件只支持android的默认格式mp4和3gp

    复制代码 代码如下: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body>

  • Android提高之MediaPlayer播放网络视频的实现方法

    前面讲解了MediaPlayer播放网络音频,主要介绍了MediaPlayer关于网络音频的缓冲和进度条控制的方法,本文再来讲解一下MediaPlayer播放网络视频的方法.播放网络视频比播放网络音频需要多一个SurfaceView而已,在已经熟悉了MediaPlayer播放网络音频之后,相信大家对本文所述的播放网络视频也能很快地掌握. 先来看看本文程序运行截图,如下所示: 本文程序的视频来自http://daily3gp.com,大家可以替换程序中的视频链接,试试其他影片. main.xml的

  • Android开发中听筒无法播放音乐的解决方法

    本文实例讲述了Android开发中听筒无法播放音乐的解决方法.分享给大家供大家参考,具体如下: 这个问题让我蛋疼了,既然百度也木有资料. 耗时的主要原因是因为权限不足时,而没有终止程序,只用了一小行日志提醒,没有看到 用听筒播放很简单 AudioManager.setMode(AudioManager.MODE_IN_CALL) //设定为通话中即可 还是这一句代码的事,不过记得要加上权限 Android.permission.MODIFY_AUDIO_SETTINGS 不然会像我一样蛋疼半天

随机推荐