Android使用TextureView播放视频

Posted 安辉就是我

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android使用TextureView播放视频相关的知识,希望对你有一定的参考价值。

1.引言

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


1).TextureView的兄弟SurfaceView

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

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



2).为了解决这个问题 Android 4.0中引入了TextureView。

TextureView与SurfaceView相比,TextureView并没有创建一个单独的Surface用来绘制,这使得它可以像一般的View一样执行一些变换操作,设置透明度等。另外,Textureview必须在硬件加速开启的窗口中。


项目中碰到的问题:1.之前用SurfaceView播放视频的时候,从图片切换到播放视频,会出现黑屏的现象。

                                 2.SurfaceView灵活性没有TextureView好。




2.项目源码

MainActivity.java文件

<span style="font-size:14px;">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());
	    
	
</span>

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,并且切换过去的时候不会出现黑屏。


3.效果图

 

                     


下载源码


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

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

推荐下自己创建的android QQ群:202928390 欢迎大家的加入.

推荐一个Android开发者必关注公众号,每周都有原创干货


以上是关于Android使用TextureView播放视频的主要内容,如果未能解决你的问题,请参考以下文章

Android 视频播放

Android 视频播放

TextureView/SurfaceView/GLSurfaceView/VideoView渲染视频(点播播放器)

在 TextureView 上播放视频

在recyclerview中使用textureview播放视频

旋转 90 时如何将 TextureView 大小调整为全屏?