• 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 欢迎大家的加入.


  • 相关阅读:
    luoguP1080 国王游戏 题解(NOIP2012)(贪心+高精)
    luoguP1079 Vigenère 密码 题解(NOIP2012)
    luoguP2184 贪婪大陆 题解(树状数组)
    luoguP2680 运输计划 题解(二分答案+树上差分)
    树链剖分总结
    树上差分总结
    luoguP3258 [JLOI2014]松鼠的新家 题解(树上差分)
    简单差分(保证你一看就懂)
    luoguP3128 [USACO15DEC]最大流Max Flow 题解(树上差分)
    luoguP1541 乌龟棋 题解(NOIP2010)
  • 原文地址:https://www.cnblogs.com/yishaochu/p/5078621.html
Copyright © 2020-2023  润新知