Android使用TextureView播放视频

摘要:
2) 为了解决这个问题,Android 4.0中引入了TextureView。与SurfaceView相比,TextureView不会为绘制创建单独的曲面,这使其能够执行一些转换操作、设置透明度等,就像普通视图一样。此外,Textureview必须位于硬件加速打开的窗口中。项目中遇到的问题:1.使用SurfaceView播放视频时,从图片切换到视频时,屏幕将变黑。

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: 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    
    
    <ImageView
        android: 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="http://t.zoukankan.com/@drawable/ic_launcher"/>
</RelativeLayout>
放了一个TextureView跟一个ImageView  TextureView初始化显示ImageView...当视频播放的时候隐藏ImageView,并且切换过去的时候不会出现黑屏。


3.效果图

   播放之前显示的图片:                                                  播放之后显示的图片:

      Android使用TextureView播放视频第1张                        Android使用TextureView播放视频第2张


下载源码


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

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

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


免责声明:文章转载自《Android使用TextureView播放视频》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇在linux7环境下安装oracle的问题记录编译安装 openswan-2.6.34下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

转:Android Camera2 拍照(二)——使用TextureView

Android Camera2 拍照(二)——使用TextureView 原文:Android Camera2 拍照(二)——使用TextureView 上一篇博文简单介绍了使用Camera2 API拍摄照片,并使用SurfaceView作为预览界面。实际上,相对于SurfaceView, TextureView更适合用于视频和拍摄照片。SurfaceVi...

Android SurfaceView

一、SurfaceView简介SurfaceView可以在主线程之外的线程中向屏幕绘图上。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。在游戏开发中多用到SurfaceView,游戏中的背景、人物、动画等等尽量在画布canvas中画出。什么是Surface在这里要先说说什么是Surface。简单的说Surface对应了一块屏幕缓冲...

Android使用SurfaceView实现墨迹天气的风车效果

SurfaceView也是继承自View,它和我们以前接触到的View(Button、TextView等)最大的不同是,SurfaceView可以有一个单独的线程进行绘制,这个线程区别于UI线程(主线程),因此SurfaceView绘制并不占用主线程资源。 SurfaceView实现通常是自定义,继承SurfaceView并实现SurfaceHolder....

二维码扫描开源库ZXing定制化【转】

转自:http://www.cnblogs.com/sickworm/p/4562081.html 最近在用ZXing这个开源库做二维码的扫描模块,开发过程的一些代码修改和裁剪的经验和大家分享一下。 建议: 如果需要集成到自己的app上,而不是做一个demo,不推荐用ZXing的Android外围开发模块,只用核心的core目录的代码就好了。androi...

玩转Android Camera开发(二):使用TextureView和SurfaceTexture预览Camera 基础拍照demo

Google自Android4.0出了TextureView,为什么推出呢?就是为了弥补Surfaceview的不足,另外一方面也是为了平衡GlSurfaceView,当然这是本人揣度的。关于TextureView、Surfaceview、SurfaceTexture、GLSurfaceView的关系,待咱家推出GLSurfaceview预览Camera后...

Camera2使用textureView支持

SurfaceView 绘制会有独立窗口, TextureView 没有独立的窗口,可以像普通的 View 一样,更高效更方便 public class MainActivity extends AppCompatActivity { private TextureView textureView; private String TAG =...