【发布时间】:2016-08-04 09:04:38
【问题描述】:
我正在就使用Grafika's CameraCaptureActivity 代码时遇到的问题寻求帮助。我想构建一个可以记录相机并显示预览的应用程序,所以这个示例和代码看起来正是我想要的,到目前为止它很棒,这个问题 appart。
我遇到的问题是,当相机预览大小与我用来显示预览的 GLSurfaceView 的确切大小不匹配时,它会显示拉伸预览。
它的外观如下:
您可以看到它被水平拉伸,因为便条纸是一个完美的正方形。
对于三星 Galaxy S4 上的这个精确示例,相机预览尺寸为1280x720(使用Camera2 API 从可用预览尺寸中提取),GLSurfaceView 为1920x1080 以覆盖整个屏幕。
什么时候出现?
与相机输出相比,当 SurfaceView 放大时会出现问题,即使我始终确保比例保持正确 (1920x1080 = 1,5 * 1280x720)。
您使用的是什么代码?
我使用Grafika的代码,包括:
一些日志?
SurfaceFlinger 转储如下所示:
Hardware Composer state (version 01030000):
mDebugForceFakeVSync=0
Display[0] configurations (* current):
* 0: 1080x1920, xdpi=442.450989, ydpi=439.351013, secure=1 refresh=16666667
numHwLayers=3, flags=00000000
type | handle | hint | flag | tr | blnd | format | source crop(l,t,r,b) | frame | dirtyRect | name
------------+----------+----------+----------+----+-------+----------+-----------------------------------+---------------------------+-------------------
HWC | b3b12ba0 | 0002 | 0000 | 00 | 0100 | RGB_888 | 0.0, 0.0, 1080.0, 1920.0 | 0, 0, 1080, 1920 | [ 0, 0, 1080, 1920] | SurfaceView
HWC | b3d12740 | 0002 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 1065.0, 1905.0 | 0, 0, 1065, 1905 | [ 0, 0, 1065, 1905] | com.mybundle.myapp/com.mybundle.myapp.activity.MyActivity
FB TARGET | b6a55c40 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 1080.0, 1920.0 | 0, 0, 1080, 1920 | [ 0, 0, 0, 0] | HWC_FRAMEBUFFER_TARGET
Layer 0xb4094000 (SurfaceView)
Region transparentRegion (this=0xb4094160, count=1)
[ 0, 0, 0, 0]
Region visibleRegion (this=0xb4094008, count=1)
[ 0, 0, 1920, 1080]
layerStack= 0, z= 21015, pos=(0,0), size=(1920,1080), crop=( 0, 0,1920,1080), isOpaque=1, invalidate=0, alpha=0xff, flags=0x00000002, tr=[1.00, 0.00][0.00, 1.00]
client=0xb66190c0
format= 4, activeBuffer=[1080x1920:1536, 3], queued-frames=0, mRefreshPending=0
mTexName=116 mCurrentTexture=0
mCurrentCrop=[0,0,0,0] mCurrentTransform=0x7
mAbandoned=0
-BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1920x1080], default-format=4, transform-hint=04, FIFO(0)={}
>[00:0xb1c18500] state=ACQUIRED, 0xb3b12ba0 [1080x1920:1536, 3]
相机预览尺寸代码?
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
// Retrieve display size
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point displaySize = new Point();
display.getSize(displaySize);
// Choose the sizes for camera preview
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
displaySize.x, displaySize.y, captureWidth, captureHeight);
private static Size chooseOptimalSize(Size[] choices, int screenWidth, int screenHeight, int captureWidth, int captureHeight)
{
// Collect the supported resolutions that are at least as big as the screen && wanted capture size
List<Size> bigEnough = new ArrayList<>();
// Collect the supported resolutions that are at least as big as the wanted capture size but < to screensize
List<Size> smallerButEnough = new ArrayList<>();
for (Size option : choices) {
if (option.getHeight() == option.getWidth() * captureHeight / captureWidth) {
if( option.getWidth() >= screenWidth && option.getHeight() >= screenHeight )
{
bigEnough.add(option);
}
else
{
smallerButEnough.add(option);
}
}
}
// Pick the smallest of those, assuming we found any
if (bigEnough.size() > 0)
{
return Collections.min(bigEnough, new CompareSizesByArea());
}
// Pick the biggest of those, assuming we found any
else if( smallerButEnough.size() > 0 )
{
return Collections.max(smallerButEnough, new CompareSizesByArea());
}
else
{
Log.e(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}
你尝试过什么?
我一开始以为是Camera2 的问题,所以我尝试只使用旧的Camera API,但结果是一样的。
然后我认为这是一个比例问题,但正如您所见,这里的比例在水平和垂直方向上都可以。
我敢打赌,在调整 Surface 大小时会应用 OpenGL 转换,但我是 OpenGL 中的纯菜鸟,所以我找不到任何可行的方法。我尝试添加这些行,但没有帮助:
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.d(TAG, "onSurfaceChanged " + width + "x" + height);
gl.glViewport(0, 0, width, height);
gl.glClear(GLES10.GL_COLOR_BUFFER_BIT | GLES10.GL_DEPTH_BUFFER_BIT);
}
另一个例子,来自 Grafika:
这是另一个问题示例,来自 Grafika 应用程序。
电话:Galaxy S3 Neo (GT-I9301L) - Android 4.4.2
手机有1280x720屏幕,相机以640x480分辨率打开,显示在573x430。下面是它的外观:
SurfaceFlinger 日志:
Hardware Composer state (version 1030000):
mDebugForceFakeVSync=0
Display[0] : 720x1280, xdpi=304.799011, ydpi=306.716003, refresh=16666667
numHwLayers=4, flags=00000000
type | handle | hints | flags | tr | blend | format | source crop | frame name
------------+----------+----------+----------+----+-------+----------+---------------------------------+--------------------------------
HWC | b84a3d18 | 00000002 | 00000000 | 00 | 00100 | 00000002 | [ 0.0, 0.0, 430.0, 573.0] | [ 32, 353, 462, 926] SurfaceView
HWC | b841b080 | 00000002 | 00000000 | 00 | 00105 | 00000001 | [ 0.0, 0.0, 670.0, 1280.0] | [ 0, 0, 670, 1280] com.android.grafika/com.android.grafika.CameraCaptureActivity
HWC | b8423250 | 00000002 | 00000000 | 00 | 00105 | 00000001 | [ 0.0, 0.0, 50.0, 1280.0] | [ 670, 0, 720, 1280] StatusBar
FB TARGET | b8412d50 | 00000000 | 00000000 | 00 | 00105 | 00000001 | [ 0.0, 0.0, 720.0, 1280.0] | [ 0, 0, 720, 1280] HWC_FRAMEBUFFER_TARGET
+ Layer 0xb8416080 (SurfaceView) id=112
Region transparentRegion (this=0xb84169d0, count=1)
[ 0, 0, 0, 0]
Region visibleRegion (this=0xb8416088, count=1)
[353, 258, 926, 688]
layerStack= 0, z= 21015, pos=(353,258), size=( 573, 430), crop=( 0, 0, 573, 430), isOpaque=1, invalidate=0, alpha=0xff, flags=0x00000000, tr=[1.00, 0.00][0.00, 1.00]
client=0xb841d7c8
format= 4, activeBuffer=[ 430x 573: 448, 2], queued-frames=0, mRefreshPending=0
mTexName=95 mCurrentTexture=1
mCurrentCrop=[0,0,0,0] mCurrentTransform=0x7
mAbandoned=0
-BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[573x430], default-format=4, transform-hint=04, FIFO(0)={}
[00:0xb84439a8] state=FREE , 0xb849a528 [ 430x 573: 448, 2]
>[01:0xb8421128] state=ACQUIRED, 0xb84a3d18 [ 430x 573: 448, 2]
[02:0xb84238e8] state=FREE , 0xb84432f8 [ 430x 573: 448, 2]
Grafika 的应用日志:
04-18 18:06:49.954 14383-14383/com.android.grafika D/Grafika: onCreate complete: com.android.grafika.CameraCaptureActivity@42adc288
04-18 18:06:49.954 14383-14383/com.android.grafika D/Grafika: onResume -- acquiring camera
04-18 18:06:50.064 14383-14383/com.android.grafika D/Grafika: Camera preferred preview size for video is 1920x1080
04-18 18:06:50.064 14383-14383/com.android.grafika D/Grafika-AFL: Setting aspect ratio to 1.3333333333333333 (was -1.0)
04-18 18:06:50.064 14383-14383/com.android.grafika D/Grafika: onResume complete: com.android.grafika.CameraCaptureActivity@42adc288
04-18 18:06:50.064 14383-32312/com.android.grafika D/Grafika: setCameraPreviewSize
04-18 18:06:50.094 14383-14383/com.android.grafika D/Grafika-AFL: onMeasure target=1.3333333333333333 width=[MeasureSpec: EXACTLY 1216] height=[MeasureSpec: EXACTLY 526]
04-18 18:06:50.094 14383-14383/com.android.grafika D/Grafika-AFL: new size=701x526 + padding 0x0
04-18 18:06:50.094 14383-14383/com.android.grafika D/Grafika-AFL: onMeasure target=1.3333333333333333 width=[MeasureSpec: EXACTLY 1216] height=[MeasureSpec: EXACTLY 430]
04-18 18:06:50.094 14383-14383/com.android.grafika D/Grafika-AFL: new size=573x430 + padding 0x0
04-18 18:06:50.124 14383-32312/com.android.grafika D/Grafika: onSurfaceCreated
04-18 18:06:50.134 14383-32312/com.android.grafika D/Grafika: Created program 3 (TEXTURE_EXT)
04-18 18:06:50.144 14383-32312/com.android.grafika D/Grafika: onSurfaceChanged 573x430
04-18 18:06:50.144 14383-32312/com.android.grafika D/Grafika: Updating filter to 0
04-18 18:06:50.154 14383-14383/com.android.grafika D/Grafika: onItemSelected: 0
04-18 18:06:50.154 14383-14383/com.android.grafika D/Grafika: CameraHandler [Handler (com.android.grafika.CameraCaptureActivity$CameraHandler) {42aeec70}]: what=0
04-18 18:06:50.514 14383-14383/com.android.grafika D/Grafika-AFL: onMeasure target=1.3333333333333333 width=[MeasureSpec: EXACTLY 1216] height=[MeasureSpec: EXACTLY 526]
04-18 18:06:50.514 14383-14383/com.android.grafika D/Grafika-AFL: new size=701x526 + padding 0x0
04-18 18:06:50.514 14383-14383/com.android.grafika D/Grafika-AFL: onMeasure target=1.3333333333333333 width=[MeasureSpec: EXACTLY 1216] height=[MeasureSpec: EXACTLY 430]
04-18 18:06:50.514 14383-14383/com.android.grafika D/Grafika-AFL: new size=573x430 + padding 0x0
04-18 18:06:50.544 14383-14383/com.android.grafika D/AbsListView: onVisibilityChanged() is called, visibility : 4
04-18 18:06:50.544 14383-14383/com.android.grafika D/AbsListView: unregisterIRListener() is called
那么...
如果你们当中有人知道如何让它发挥作用,我很想听听他的意见。
谢谢!
【问题讨论】:
-
我猜有些东西没有使用您认为它正在使用的分辨率。解决这个问题的一种方法是使用
adb shell dumpsys SurfaceFlinger转储 HardwareComposer 层;这将显示应用于 SurfaceView 表面的转换。 source.android.com/devices/graphics/… 有一个您应该查看的部分的示例(使用来自 Grafika 的视频播放器)。 GLES 变换不应该是相关的,因为您只是用视口大小的矩形绘制整个框架。你看到 Grafika 本身有什么失真吗? -
@fadden 我在我的回答中添加了
adb shell dumpsys SurfaceFlinger的日志:#36617782。你看到什么奇怪的东西了吗? -
HWC 输出以 1080x1920 显示所有内容,因此您的 SurfaceView 配置没有任何问题。这留下了相机配置。你能展示你用来配置预览大小的代码吗?
-
@fadden 帖子使用
camera2代码进行编辑以获取预览大小。感谢您的帮助 -
你从
mPreviewSize.getWidth()/mPreviewSize.getHeight()得到什么值?
标签: android opengl-es android-camera glsurfaceview grafika