Android使用TextureView播放视频

标签: 视频Android视频播放TextureView
17491人阅读 评论(10) 收藏 举报
分类:

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开发者必关注公众号,每周都有原创干货


5
2

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:365016次
    • 积分:4293
    • 等级:
    • 排名:第7417名
    • 原创:79篇
    • 转载:21篇
    • 译文:1篇
    • 评论:216条
    关于我

    QQ群: 202928390

    我的微信公众号

    长期推送Android开发文章、最新动态、开源项目,让你各种涨姿势。欢迎大家扫码关注。
    友情链接
    最新评论