TextureView SurfaceTexture

TextureView

Texture更像是一般的View,像TextView那样能被缩放、平移,也能加上动画。TextureView只能在开启了硬件加速的Window中使用,并且消费的内存要比SurfaceView多,并伴随着1-3帧的延迟.

TextureView是在4.0(API level 14)引入的,用于承载显示‘数据流’的View, 如本地Camera采集的预览数据流和视频通话模块从网络包里解出实时视频‘数据流’。

TextureView可用于显示内容流。例如视频获取OpenGL,内容流可来自应用程序进程或者远程进程。

 

TextureSurface

图像流可以来自相机预览或视频解码。甲表面纹理来代替SurfaceHolder的指定的输出目的地时,

SurfaceTexture 类是在 Android 3.0 中推出的。就像 SurfaceView 是 Surface 和 View 的组合一样,SurfaceTexture 是 Surface 和 GLES 纹理的粗略组合(包含几个注意事项)。

当您创建 SurfaceTexture 时,会创建一个应用是其消耗方的 BufferQueue。如果生产方将新的缓冲区加入队列,您的应用便会通过回调 (onFrameAvailable()) 获得通知。应用调用 updateTexImage()(这会释放先前保留的缓冲区),从队列中获取新的缓冲区,然后发出一些 EGL 调用,让缓冲区可作为外部纹理供 GLES 使用。

 

外部纹理 (GL_TEXTURE_EXTERNAL_OES) 与 GLES (GL_TEXTURE_2D) 创建的纹理并不完全相同:您对渲染器的配置必须有所不同,而且有一些操作是不能对外部纹理执行的。关键是,您可以直接从 BufferQueue 接收到的数据中渲染纹理多边形。gralloc 支持各种格式,因此我们需要保证缓冲区中数据的格式是 GLES 可以识别的格式。为此,当 SurfaceTexture 创建 BufferQueue 时,它将消耗方用法标记设置为 GRALLOC_USAGE_HW_TEXTURE,确保由 gralloc 创建的缓冲区均可供 GLES 使用。

由于 SurfaceTexture 会与 EGL 上下文交互,因此您必须小心地从正确的会话中调用其方法(详见类文档)。

 

如果您深入阅读类文档,您会看到两个奇怪的调用。一个调用会检索时间戳,而另一个调用是转换矩阵,每个调用的值都通过事先调用 updateTexImage() 来设置。事实证明,BufferQueue 不只是向消耗方传递缓冲区句柄。每个缓冲区都附有时间戳和转换参数。

提供转换是为了提高效率。在某些情况下,源数据可能以错误的方向传递给消耗方;但是,我们可以按照数据的当前方向发送数据并使用转换对其进行更正,而不是在发送数据之前对其进行旋转。在使用数据时,转换矩阵可以与其他转换合并,从而最大限度降低开销。

时间戳对于某些缓冲区来源非常有用。例如,假设您将生产方接口连接到相机的输出端(使用 setPreviewTexture())。要创建视频,您需要为每个帧设置演示时间戳;不过您需要根据截取帧的时间(而不是应用收到缓冲区的时间)来设置该时间戳。随缓冲区提供的时间戳由相机代码设置,从而获得一系列更一致的时间戳。

dome:

import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.TextureView;

import com.example.zhangyadong.test.R;

public class TextrueActivity extends Activity implements TextureView.SurfaceTextureListener, SurfaceTexture.OnFrameAvailableListener,Runnable {

    private static final String TAG = SurfaceActivity.class.getSimpleName();
    private static final int REFRESH = 100;
    private TextureView mTextureView;
    private Path mPath;
    private Paint mPaint;

    private boolean mIsDrawing=true;
    /**
     * 每30帧刷新一次屏幕
     **/
    public static final int TIME_IN_FRAME = 300;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_texture);
        mPath = new Path();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(20);
        mPaint.setStyle(Paint.Style.STROKE);
        mTextureView = findViewById(R.id.texture);
        mTextureView.setSurfaceTextureListener(this);

    }


    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        Log.d(TAG, "onSurfaceTextureAvailable,width=" + width + ",height=" + height);
       new Thread(this).start();
        //surface 创建成功
        //        SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
        //        surfaceTexture.setOnFrameAvailableListener(this);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        Log.d(TAG, "onSurfaceTextureSizeChanged,width=" + width + ",height=" + height);
        //surface 大小发生变化
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        Log.d(TAG, "onSurfaceTextureDestroyed");
        mIsDrawing=false;
        //surface 被销毁
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        Log.d(TAG, "onSurfaceTextureUpdated");
        //surface 更新
    }


    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
        //用于通知TextureView内容流有新图象到来
    }

    @Override
    public void run() {
        while (mIsDrawing) {
            long startTime = System.currentTimeMillis();
            synchronized (mTextureView) {
                Canvas canvas = mTextureView.lockCanvas();
                float x = (int) (1 + Math.random() * (canvas.getWidth()));
                float y = (int) (1 + Math.random() * (canvas.getHeight()));
                mPath.lineTo(x, y);
                canvas.drawPath(mPath, mPaint);
                mTextureView.unlockCanvasAndPost(canvas);
            }
            /**取得更新结束的时间**/
            long endTime = System.currentTimeMillis();

            /**计算出一次更新的毫秒数**/
            int diffTime = (int) (endTime - startTime);

            /**确保每次更新时间为30帧**/
            while (diffTime <= TIME_IN_FRAME) {
                diffTime = (int) (System.currentTimeMillis() - startTime);
                /**线程等待**/
                Thread.yield();
            }
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值