关于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中的最大缓冲区数量?
我正在绘制一些图形,我想添加几个按钮.但是使用表面视图我们如何以编程方式添加这些按钮?
我从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) 我有一个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) 我正在尝试创建一个可以缩放和拖动的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) 我的项目基于surfaceView,直到现在我已经在onDraw中完成了所有渲染,而我已经覆盖了.一切似乎都没问题.
但是,我刚刚更新了我的SDK,现在它给了我一个错误告诉我:
可疑方法电话; 应该叫"画"而不是"onDraw"
有人可以解释这两者之间的区别吗?
我已经在网上阅读了一些类似的问题,但我没有找到我理解的解释.
谢谢
我有一个自定义相机应用程序,我想要任何预览尺寸以全屏模式显示它而不拉伸相机预览图像.对于这一点,我需要做的surfaceView大于屏幕,以保持宽高比,所以实际上用户将看到小于照相机实际拍摄.
出于某种原因,我无法使SurfaceView屏幕尺寸大于屏幕尺寸.
到目前为止我尝试过的:
调整surfaceChanged方法中的相机预览
调整on onMeasure方法中的相机预览
onLayout FLAG_LAYOUT_NO_LIMITS到活动 - 信息clipChildren 用于表面视图 - 信息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) 我想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) 这是我的示例代码:
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) 借助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使用Surface的ImageReader:
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)
然后我创建虚拟显示传递Surface到MediaProjection:
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)