标签: surfaceview

最小化Android GLSurfaceView滞后

关于Stack Overflow的其他一些问题,我已经从这里阅读了Android Surfaces,SurfaceViews等内部指南:

https://source.android.com/devices/graphics/architecture.html

该指南让我对Android上所有不同部分的组合方式有了更好的理解.它介绍了eglSwapBuffers如何将渲染帧推送到队列中,当它准备下一帧显示时,SurfaceFlinger将使用该队列.如果队列已满,那么它将等到缓冲区在返回之前可用于下一帧.上面的文档将其描述为"填充队列"并依赖交换缓冲区的"反压"来限制渲染到显示的vsync.这是使用GLSurfaceView的默认连续渲染模式发生的情况.

如果你的渲染是简单的并且在比帧周期少得多的情况下完成,那么这是由BufferQueue引起的额外延迟,因为SwapBuffers上的等待直到队列满了才发生,因此我们'重新渲染始终位于队列的后面,因此不会立即显示在下一个vsync上,因为队列中可能存在缓冲区.

相比之下,按需渲染的发生频率通常比显示更新速率低得多,因此通常这些视图的BufferQueues为空,因此推送到这些队列的任何更新都将被SurfaceFlinger在下一个vsync上抓取.

所以问题在于:如何设置连续渲染器,但延迟最小?目标是每个vsync开始时缓冲区队列为空,我在16ms内渲染我的内容,将其推送到队列(缓冲区计数= 1),然后由SurfaceFlinger在下一个vsync(缓冲区计数)上使用它= 0),重复一遍.队列中的缓冲区数量可以在systrace中看到,因此目标是在0和1之间交替使用.

我上面提到的文档介绍了Choreographer作为在每个vsync上获得回调的方法.但是我不相信这足以让我能够实现我追求的最小滞后行为.我已经测试了在vsync回调上使用非常小的onDrawFrame()执行requestRender(),它确实展示了0/1缓冲区计数行为.但是,如果SurfaceFlinger无法在一个帧周期内完成所有工作(可能是通知弹出或其他),该怎么办?在这种情况下,我希望我的渲染器很乐意为每个vsync生成1帧,但该BufferQueue的消费者端已经丢弃了一帧.结果:我们现在在队列中交替使用1到2个缓冲区,并且我们在渲染和查看帧之间获得了一段滞后.

该文档似乎建议查看报告的vsync时间与回调运行时间之间的时间偏差.我可以看到,如果你的回调由于你的主线程由于布局传递或其他东西而延迟传递,那会有什么帮助.但是我认为这不会允许检测到SurfaceFlinger跳过节拍并且不能消耗帧.应用程序是否有任何方法可以解决SurfaceFlinger丢帧的问题?似乎无法告诉队列的长度打破了使用vsync时间进行游戏状态更新的想法,因为在您实际渲染的渲染之前,队列中存在未知数量的帧.

减少队列的最大长度并依赖背压将是实现此目的的一种方法,但我认为没有API来设置GLSurfaceView BufferQueue中的最大缓冲区数量?

android lag surfaceview

25
推荐指数
1
解决办法
5155
查看次数

Android:如何在曲面视图中添加按钮

我正在绘制一些图形,我想添加几个按钮.但是使用表面视图我们如何以编程方式添加这些按钮?

android surfaceview

24
推荐指数
4
解决办法
5万
查看次数

Android相机无法使用.startPreview失败

我从LogCat收到这些错误:

10-30 00:31:51.494: D/CameraHal(1205): CameraHal setOverlay/1/00000000/00000000
10-30 00:31:51.494: E/CameraHal(1205): Trying to set overlay, but overlay is null!, line:3472
10-30 00:31:51.494: W/CameraService(1205): Overlay create failed - retrying
...
10-30 00:31:52.526: E/CameraService(1205): Overlay Creation Failed!
...
10-30 00:31:52.588: E/AndroidRuntime(5040): FATAL EXCEPTION: main
10-30 00:31:52.588: E/AndroidRuntime(5040): java.lang.RuntimeException: startPreview failed
10-30 00:31:52.588: E/AndroidRuntime(5040):     at android.hardware.Camera.startPreview(Native Method)
10-30 00:31:52.588: E/AndroidRuntime(5040):     at com.matthewmitchell.nightcam.CameraSurfaceView.surfaceCreated(CameraSurfaceView.java:47)
10-30 00:31:52.588: E/AndroidRuntime(5040):     at android.view.SurfaceView.updateWindow(SurfaceView.java:544)
10-30 00:31:52.588: E/AndroidRuntime(5040):     at android.view.SurfaceView.dispatchDraw(SurfaceView.java:341)
10-30 00:31:52.588: E/AndroidRuntime(5040):     at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
10-30 00:31:52.588: E/AndroidRuntime(5040):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
10-30 00:31:52.588: E/AndroidRuntime(5040): …
Run Code Online (Sandbox Code Playgroud)

java android surfaceview android-camera surfaceholder

24
推荐指数
4
解决办法
7万
查看次数

将相机预览适合大于显示器的SurfaceView

我有一个Android应用程序需要全屏一个摄像头预览,无论预设大小getSupportedPreviewSizes()没有失真.我希望这可以在高度或宽度上裁剪一些预算,但这并不关心我.我寻求这样做的原因是因为某些安卓摄像头(例如三星Galaxy SII前置摄像头)不会返回任何与显示器具有相同宽高比的预览,因此需要拉伸和剪裁.

是否可以将相机预览完全增加到大于显示尺寸的视图?通过简单地将曲面视图的布局参数设置为match_parent,可以使SurfaceView大于返回的预览像素尺寸,但这会导致某些方向的失真,并且只有在预览填充显示之前才可能.这似乎表明在显示器外部进行预览是不可能的,并且硬件(或OS)限制了这种行为.

关于这个主题还有另一个问题,但是这个问题声称不可能创建一个大于屏幕尺寸的SurfaceView,这是错误的,正如我在日志记录中发现的那样.然而,似乎情况是相机预览无法增长到庞大的SurfaceView的全尺寸.

我的尝试:

我有一个相对布局,在它内部是一个FrameLayout,在其中我创建了一个SurfaceView.整个相对布局的宽度设置在635dp以下,这是设备屏幕尺寸的两倍.FrameLayout匹配此大小,SurfaceView也是如此(稍后以编程方式添加)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/camera_activity_layout"
    android:layout_width="635dp"
    android:layout_height="match_parent" >

    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>

</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

以下是获取和设置预览大小的代码.在这里,我想让相机预览展开以填充整个FrameLayout(屏幕宽度的两倍).视图完全正常显示和破坏,因此我删除与此特定问题无关的代码,因为它分散了基本问题,并且我尝试轻松简单地将视图扩展为大于显示大小的视图.

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    ...

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        Camera.Parameters parameters = mCamera.getParameters();
        final DisplayMetrics dm = this.getResources().getDisplayMetrics();
            //getBestPreviewSize returns the best preview size, don't worry
            //but some devices do not return one for all camera matching the aspect ratio
        cameraSize = getBestPreviewSize(parameters, dm.heightPixels, dm.widthPixels); …
Run Code Online (Sandbox Code Playgroud)

android surfaceview android-layout android-camera

23
推荐指数
1
解决办法
2万
查看次数

SurfaceView中的缩放和拖动功能

我正在尝试创建一个可以缩放和拖动的SurfaceView.它实现了一个直接绘制到画布的HTTP图像流

我已经尝试了以下代码,它有点工作......但它给我带来了边界问题.不知道原因.有帮助吗?

全流:

全流图像

缩放图像:

缩放图像

在第二个图像中,您可以看到多个不需要在那里的绿线.

这是处理此流的类:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Display;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.SurfaceView;
import android.view.WindowManager;

/**
 * Created by fil on 07/12/15.
 */
public class ZoomSurfaceView extends SurfaceView {
    //These two constants specify the minimum and maximum zoom
    private static float MIN_ZOOM = 1f;
    private static float MAX_ZOOM = 5f;

    private float scaleFactor = 1.f;
    private ScaleGestureDetector detector;

    //These …
Run Code Online (Sandbox Code Playgroud)

android stream surfaceview

22
推荐指数
1
解决办法
2131
查看次数

覆盖onDraw()或draw()?

我的项目基于surfaceView,直到现在我已经在onDraw中完成了所有渲染,而我已经覆盖了.一切似乎都没问题.

但是,我刚刚更新了我的SDK,现在它给了我一个错误告诉我:

可疑方法电话; 应该叫"画"而不是"onDraw"

有人可以解释这两者之间的区别吗?

我已经在网上阅读了一些类似的问题,但我没有找到我理解的解释.

谢谢

android draw surfaceview ondraw

21
推荐指数
3
解决办法
2万
查看次数

使SurfaceView大于屏幕(将相机预览适合大于显示器的SurfaceView)

我有一个自定义相机应用程序,我想要任何预览尺寸以全屏模式显示它而不拉伸相机预览图像.对于这一点,我需要做的surfaceView大于屏幕,以保持宽高比,所以实际上用户将看到小于照相机实际拍摄.

出于某种原因,我无法使SurfaceView屏幕尺寸大于屏幕尺寸.

到目前为止我尝试过的:

  • 调整surfaceChanged方法中的相机预览

  • 调整on onMeasure方法中的相机预览

  • 方法中调整大小onLayout
  • 添加FLAG_LAYOUT_NO_LIMITS到活动 - 信息
  • 添加android:clipChildren 用于表面视图 - 信息
  • 在xml中设置宽度: android:layout_width="852px"
  • getWindow().setLayout(852, 1280); 在活动中

但是没有任何成功 - 每次的行为都是一样的:它看起来好一秒钟,然后就会拉长.

这是代码:

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private static final int CAMERA_ROTATE_ANGLE = 90;

    private SurfaceHolder cameraHolder;
    private Camera androidHardCamera;
    private Context context;

    public CameraPreview(Context context) {
        super(context);
        this.context = context;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is …
Run Code Online (Sandbox Code Playgroud)

android surfaceview android-camera android-fullscreen

20
推荐指数
1
解决办法
2万
查看次数

自定义相机android

我想camera preview在一个活动中使用.我想添加图像(表面视图上的透明框架).我尝试了以下代码,以便我可以轻松地自定义xml布局:

package com.demo;


import java.io.IOException;

import android.app.Activity;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;

public class CameraDemoActivity extends Activity implements SurfaceHolder.Callback{
    /** Called when the activity is first created. */
     Camera camera;
     SurfaceView surfaceView;
     SurfaceHolder surfaceHolder;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        getWindow().setFormat(PixelFormat.UNKNOWN);
        surfaceView = (SurfaceView)findViewById(R.id.surfaceview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        camera = Camera.open();
        if(camera!=null){

            try {
             camera.setPreviewDisplay(surfaceHolder);
             camera.startPreview();
            } catch (IOException e) {
             Toast.makeText(this, (CharSequence) e, Toast.LENGTH_LONG).show();
            }

        } …
Run Code Online (Sandbox Code Playgroud)

camera android surfaceview android-camera

19
推荐指数
1
解决办法
5万
查看次数

Android相机教程(使用surfaceview)

这是我的示例代码:

package newslab.video.server;

import android.app.Activity;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class VideoServer extends Activity implements SurfaceHolder.Callback {
    TextView testView;

    Camera camera;
    SurfaceView surfaceView;
    SurfaceHolder surfaceHolder;

    private final String tag = "VideoServer";

    Button start, stop;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        start = (Button)findViewById(R.id.btn_start);
        start.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View arg0) {
                start_camera();
            }
        });

        stop = (Button)findViewById(R.id.btn_stop); …
Run Code Online (Sandbox Code Playgroud)

android surfaceview

19
推荐指数
2
解决办法
9万
查看次数

使用MediaProjection截取屏幕截图

借助MediaProjectionAndroid L中提供的API,可以实现

将主屏幕的内容(默认显示)捕获到Surface对象中,然后您的应用可以通过网络发送该对象

我已经设法让VirtualDisplay工作,我SurfaceView正确显示屏幕的内容.

我想要做的是捕获显示在其中的框架Surface,并将其打印到文件.我尝试过以下内容,但我得到的只是一个黑色文件:

Bitmap bitmap = Bitmap.createBitmap
    (surfaceView.getWidth(), surfaceView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
surfaceView.draw(canvas);
printBitmapToFile(bitmap);
Run Code Online (Sandbox Code Playgroud)

有关如何从中检索显示数据的任何想法Surface

编辑

因此,作为@j__m建议,现在我的设置VirtualDisplay使用SurfaceImageReader:

Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
displayWidth = size.x;
displayHeight = size.y;

imageReader = ImageReader.newInstance(displayWidth, displayHeight, ImageFormat.JPEG, 5);
Run Code Online (Sandbox Code Playgroud)

然后我创建虚拟显示传递SurfaceMediaProjection:

int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;

DisplayMetrics metrics = getResources().getDisplayMetrics();
int density = metrics.densityDpi;

mediaProjection.createVirtualDisplay("test", …
Run Code Online (Sandbox Code Playgroud)

android bitmap surfaceview

18
推荐指数
4
解决办法
2万
查看次数