Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
HatsuneMikuFansYSQ
LYAVFoundation
提交
d13fe800
L
LYAVFoundation
项目概览
HatsuneMikuFansYSQ
/
LYAVFoundation
通知
10
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
L
LYAVFoundation
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
d13fe800
编写于
3月 04, 2022
作者:
杨
杨时权
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
【需求】新增加Camera2 Android采集接口。
上级
fb2ecda5
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
448 addition
and
18 deletion
+448
-18
project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/capture/VideoCapture2.java
...m/ly/avfoundation/avfoundation/capture/VideoCapture2.java
+395
-0
project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/fragment/CaptureFragment.java
...in/java/com/ly/avfoundation/fragment/CaptureFragment.java
+53
-18
未找到文件。
project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/capture/VideoCapture2.java
0 → 100644
浏览文件 @
d13fe800
package
com.ly.avfoundation.avfoundation.capture
;
import
android.Manifest
;
import
android.app.Activity
;
import
android.content.Context
;
import
android.content.pm.PackageManager
;
import
android.graphics.ImageFormat
;
import
android.graphics.Point
;
import
android.graphics.SurfaceTexture
;
import
android.hardware.camera2.CameraAccessException
;
import
android.hardware.camera2.CameraCaptureSession
;
import
android.hardware.camera2.CameraCharacteristics
;
import
android.hardware.camera2.CameraDevice
;
import
android.hardware.camera2.CameraManager
;
import
android.hardware.camera2.CameraMetadata
;
import
android.hardware.camera2.CaptureFailure
;
import
android.hardware.camera2.CaptureRequest
;
import
android.hardware.camera2.CaptureResult
;
import
android.hardware.camera2.TotalCaptureResult
;
import
android.hardware.camera2.params.OutputConfiguration
;
import
android.hardware.camera2.params.SessionConfiguration
;
import
android.hardware.camera2.params.StreamConfigurationMap
;
import
android.os.Build
;
import
android.os.Handler
;
import
android.os.HandlerThread
;
import
android.util.Log
;
import
android.util.Size
;
import
android.view.Surface
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.RequiresApi
;
import
androidx.core.app.ActivityCompat
;
import
java.lang.reflect.Array
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.concurrent.Executor
;
import
static
android
.
hardware
.
camera2
.
params
.
SessionConfiguration
.
SESSION_REGULAR
;
@RequiresApi
(
api
=
Build
.
VERSION_CODES
.
LOLLIPOP
)
public
class
VideoCapture2
{
public
static
final
String
TAG
=
"VideoCapture2"
;
/**
* ID of the current {@link CameraDevice}
*/
private
String
mCameraid
;
/**
* A {@link CameraCaptureSession} for camera preview
*/
private
CameraCaptureSession
mSession
;
/**
* A reference to the opened {@link CameraDevice}
*/
private
CameraDevice
mCameraDevice
;
/**
* {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.
*/
private
final
CameraDevice
.
StateCallback
mStateCallback
=
new
CameraDevice
.
StateCallback
()
{
@Override
public
void
onOpened
(
@NonNull
CameraDevice
cameraDevice
)
{
mCameraDevice
=
cameraDevice
;
startPreview
();
Log
.
i
(
TAG
,
"onOpened device="
+
cameraDevice
);
}
@Override
public
void
onDisconnected
(
@NonNull
CameraDevice
cameraDevice
)
{
if
(
mCameraDevice
==
cameraDevice
)
{
mCameraDevice
.
close
();
mCameraDevice
=
null
;
}
Log
.
i
(
TAG
,
"onDisconnected device="
+
cameraDevice
);
}
@Override
public
void
onError
(
@NonNull
CameraDevice
cameraDevice
,
int
i
)
{
cameraDevice
.
close
();
Log
.
e
(
TAG
,
"onError device="
+
cameraDevice
+
" error="
+
i
);
}
};
/**
* An additional thread for running tasks that shouldn't block the UI.
*/
private
HandlerThread
mCameraHandlerThread
;
/**
* A {@link Handler} for running tasks in the background
*/
private
Handler
mCameraHandler
;
/**
* {@link CaptureRequest} generated by {@link #mCaptureRequestBuilder}
*/
private
CaptureRequest
mCaptureRequest
=
null
;
/**
* {@link CaptureRequest.Builder} for the camera preview.
*/
private
CaptureRequest
.
Builder
mCaptureRequestBuilder
=
null
;
public
static
class
Configuration
{
public
int
width
;
public
int
height
;
public
int
facingType
;
public
int
angle
;
public
Configuration
()
{
this
(
1280
,
720
);
}
public
Configuration
(
int
w
,
int
h
)
{
this
(
w
,
h
,
FacingType
.
FRONT
);
}
public
Configuration
(
int
w
,
int
h
,
int
facingType
)
{
this
.
width
=
w
;
this
.
height
=
h
;
this
.
facingType
=
facingType
;
}
}
/**
* A {@link Configuration} for preview config to {@link #mSession}
*/
private
Configuration
mConfiguration
=
null
;
/**
* A {@link SurfaceTexture} fro preview render object
*/
private
SurfaceTexture
mSurfaceTexture
=
null
;
/**
* The {@link Size} of camera preview.
*/
private
Size
mPreviewSize
;
private
int
mSensorOrientation
;
private
Activity
mActivity
=
null
;
public
static
class
FacingType
{
public
static
final
int
FRONT
=
0
;
public
static
final
int
BACK
=
1
;
}
/**
* Compares two {@code Size}s based on their areas.
*/
static
class
CompareSizeByArea
implements
Comparator
<
Size
>
{
@Override
public
int
compare
(
Size
lhs
,
Size
rhs
)
{
// We cast here to ensure the multiplications won't overflow
return
Long
.
signum
((
long
)
lhs
.
getWidth
()
*
lhs
.
getHeight
()
-
(
long
)
rhs
.
getWidth
()
*
rhs
.
getHeight
());
}
}
public
interface
OnPreviewSizeChangeListener
{
void
onPreviewSizeChange
(
int
width
,
int
height
);
}
public
OnPreviewSizeChangeListener
mPreviewSizeChangeListener
=
null
;
public
void
setPreviewSizeChangeListener
(
OnPreviewSizeChangeListener
listener
)
{
mPreviewSizeChangeListener
=
listener
;
}
private
CameraCaptureSession
.
CaptureCallback
mCaptureCallback
=
new
CameraCaptureSession
.
CaptureCallback
()
{
};
public
VideoCapture2
(
Activity
activity
)
{
mActivity
=
activity
;
startCameraThread
();
}
public
void
openCamera
(
Configuration
configuration
)
{
mConfiguration
=
configuration
;
// setup camera to get cameraid
setupCamera
(
mConfiguration
.
width
,
mConfiguration
.
height
,
mConfiguration
.
facingType
);
// create camera by cameraid
if
(!
openCamera
())
{
throw
new
RuntimeException
(
"open camera error!"
);
}
}
public
void
setSurfaceTexture
(
SurfaceTexture
st
)
{
mSurfaceTexture
=
st
;
startPreview
();
}
public
void
releaseCamera
()
{
if
(
mSession
!=
null
)
{
mSession
.
close
();
mSession
=
null
;
}
if
(
mCameraDevice
!=
null
)
{
mCameraDevice
.
close
();
mCameraDevice
=
null
;
}
}
private
void
startCameraThread
()
{
mCameraHandlerThread
=
new
HandlerThread
(
"CameraThread"
);
mCameraHandlerThread
.
start
();
mCameraHandler
=
new
Handler
(
mCameraHandlerThread
.
getLooper
());
}
private
String
setupCamera
(
int
w
,
int
h
,
int
facingType
)
{
CameraManager
manager
=
(
CameraManager
)
mActivity
.
getSystemService
(
Context
.
CAMERA_SERVICE
);
try
{
for
(
String
id
:
manager
.
getCameraIdList
())
{
CameraCharacteristics
characteristics
=
manager
.
getCameraCharacteristics
(
id
);
Integer
facing
=
characteristics
.
get
(
CameraCharacteristics
.
LENS_FACING
);
if
(
facing
!=
null
&&
characteristics
.
get
(
CameraCharacteristics
.
LENS_FACING
)
!=
facingType
)
{
continue
;
}
StreamConfigurationMap
map
=
characteristics
.
get
(
CameraCharacteristics
.
SCALER_STREAM_CONFIGURATION_MAP
);
if
(
map
==
null
)
continue
;
int
displayRotation
=
mActivity
.
getWindowManager
().
getDefaultDisplay
().
getRotation
();
mSensorOrientation
=
characteristics
.
get
(
CameraCharacteristics
.
SENSOR_ORIENTATION
);
boolean
swappedDimensions
=
false
;
switch
(
displayRotation
)
{
case
Surface
.
ROTATION_0
:
case
Surface
.
ROTATION_180
:
if
(
mSensorOrientation
==
90
||
mSensorOrientation
==
270
)
{
swappedDimensions
=
true
;
}
break
;
case
Surface
.
ROTATION_90
:
case
Surface
.
ROTATION_270
:
if
(
mSensorOrientation
==
0
||
mSensorOrientation
==
180
)
{
swappedDimensions
=
true
;
}
break
;
default
:
Log
.
e
(
TAG
,
"Display rotation is invalid: "
+
displayRotation
);
}
Point
displaySize
=
new
Point
();
mActivity
.
getWindowManager
().
getDefaultDisplay
().
getSize
(
displaySize
);
int
rotatePreviewWidth
=
w
;
int
rotatePreviewHeight
=
h
;
int
maxPreviewWidth
=
displaySize
.
x
;
int
maxPreviewHeight
=
displaySize
.
y
;
if
(
swappedDimensions
)
{
rotatePreviewWidth
=
h
;
rotatePreviewHeight
=
w
;
maxPreviewWidth
=
displaySize
.
y
;
maxPreviewHeight
=
displaySize
.
x
;
}
if
(
maxPreviewWidth
>=
1920
)
maxPreviewWidth
=
1920
;
if
(
maxPreviewHeight
>=
720
)
maxPreviewHeight
=
720
;
Size
largest
=
Collections
.
max
(
Arrays
.
asList
(
map
.
getOutputSizes
(
ImageFormat
.
JPEG
)),
new
CompareSizeByArea
());
mPreviewSize
=
chooseOptimalSize
(
map
.
getOutputSizes
(
SurfaceTexture
.
class
),
rotatePreviewWidth
,
rotatePreviewHeight
,
maxPreviewWidth
,
maxPreviewHeight
,
largest
);
mCameraid
=
id
;
if
(
mPreviewSizeChangeListener
!=
null
)
mPreviewSizeChangeListener
.
onPreviewSizeChange
(
mPreviewSize
.
getWidth
(),
mPreviewSize
.
getHeight
());
Log
.
i
(
TAG
,
"setupCamera id="
+
mCameraid
+
" previewW="
+
mPreviewSize
.
getWidth
()
+
" previewH="
+
mPreviewSize
.
getHeight
());
}
}
catch
(
CameraAccessException
e
)
{
e
.
printStackTrace
();
}
return
mCameraid
;
}
public
void
startPreview
()
{
if
(
mCameraDevice
==
null
||
mSurfaceTexture
==
null
)
{
return
;
}
try
{
mSurfaceTexture
.
setDefaultBufferSize
(
mPreviewSize
.
getWidth
(),
mPreviewSize
.
getHeight
());
Surface
previewSurface
=
new
Surface
(
mSurfaceTexture
);
mCaptureRequestBuilder
=
mCameraDevice
.
createCaptureRequest
(
CameraDevice
.
TEMPLATE_PREVIEW
);
mCaptureRequestBuilder
.
addTarget
(
previewSurface
);
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
P
)
{
Executor
executor
=
new
Executor
()
{
@Override
public
void
execute
(
Runnable
runnable
)
{
runnable
.
run
();
}
};
CameraCaptureSession
.
StateCallback
ccs
=
new
CameraCaptureSession
.
StateCallback
()
{
@Override
public
void
onConfigured
(
@NonNull
CameraCaptureSession
cameraCaptureSession
)
{
if
(
mCameraDevice
==
null
)
{
return
;
}
try
{
mSession
=
cameraCaptureSession
;
// mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
mCaptureRequest
=
mCaptureRequestBuilder
.
build
();
mSession
.
setRepeatingRequest
(
mCaptureRequest
,
mCaptureCallback
,
mCameraHandler
);
}
catch
(
CameraAccessException
exp
)
{
exp
.
printStackTrace
();
}
}
@Override
public
void
onConfigureFailed
(
@NonNull
CameraCaptureSession
cameraCaptureSession
)
{
Log
.
e
(
TAG
,
"onConfigureFailed!!!"
);
}
};
OutputConfiguration
configuration
=
new
OutputConfiguration
(
previewSurface
);
mCameraDevice
.
createCaptureSession
(
new
SessionConfiguration
(
SESSION_REGULAR
,
Arrays
.
asList
(
configuration
),
executor
,
ccs
));
}
}
catch
(
CameraAccessException
exp
)
{
exp
.
printStackTrace
();
}
}
public
boolean
openCamera
()
{
CameraManager
manager
=
(
CameraManager
)
mActivity
.
getSystemService
(
Context
.
CAMERA_SERVICE
);
try
{
if
(
ActivityCompat
.
checkSelfPermission
(
mActivity
,
Manifest
.
permission
.
CAMERA
)
!=
PackageManager
.
PERMISSION_GRANTED
)
{
return
false
;
}
manager
.
openCamera
(
mCameraid
,
mStateCallback
,
mCameraHandler
);
}
catch
(
CameraAccessException
e
)
{
e
.
printStackTrace
();
return
false
;
}
return
true
;
}
/**
* Given {@code choices} of {@code Size}s supported by a camera, choose the smallest one that
* is at least as large as the respective texture view size, and that is at most as large as the
* respective max size, and whose aspect ratio matches with the specified value. If such size
* doesn't exist, choose the largest one that is at most as large as the respective max size,
* and whose aspect ratio matches with the specified value.
*
* @param choices The list of sizes that the camera supports for the intended output
* class
* @param textureViewWidth The width of the texture view relative to sensor coordinate
* @param textureViewHeight The height of the texture view relative to sensor coordinate
* @param maxWidth The maximum width that can be chosen
* @param maxHeight The maximum height that can be chosen
* @param aspectRatio The aspect ratio
* @return The optimal {@code Size}, or an arbitrary one if none were big enough
*/
private
static
Size
chooseOptimalSize
(
Size
[]
choices
,
int
textureViewWidth
,
int
textureViewHeight
,
int
maxWidth
,
int
maxHeight
,
Size
aspectRatio
)
{
// Collect the supported resolutions that are at least as big as the preview Surface
List
<
Size
>
bigEnough
=
new
ArrayList
<>();
// Collect the supported resolutions that are smaller than the preview Surface
List
<
Size
>
notBigEnough
=
new
ArrayList
<>();
int
w
=
aspectRatio
.
getWidth
();
int
h
=
aspectRatio
.
getHeight
();
for
(
Size
option
:
choices
)
{
if
(
option
.
getWidth
()
<=
maxWidth
&&
option
.
getHeight
()
<=
maxHeight
&&
option
.
getHeight
()
==
option
.
getWidth
()
*
h
/
w
)
{
if
(
option
.
getWidth
()
>=
textureViewWidth
&&
option
.
getHeight
()
>=
textureViewHeight
)
{
bigEnough
.
add
(
option
);
}
else
{
notBigEnough
.
add
(
option
);
}
}
}
// Pick the smallest of those big enough. If there is no one big enough, pick the
// largest of those not big enough.
if
(
bigEnough
.
size
()
>
0
)
{
return
Collections
.
min
(
bigEnough
,
new
CompareSizeByArea
());
}
else
if
(
notBigEnough
.
size
()
>
0
)
{
return
Collections
.
max
(
notBigEnough
,
new
CompareSizeByArea
());
}
else
{
Log
.
e
(
TAG
,
"Couldn't find any suitable preview size"
);
return
choices
[
0
];
}
}
}
project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/fragment/CaptureFragment.java
浏览文件 @
d13fe800
...
...
@@ -4,6 +4,7 @@ import android.app.Activity;
import
android.content.Context
;
import
android.graphics.PixelFormat
;
import
android.graphics.SurfaceTexture
;
import
android.os.Build
;
import
android.os.Bundle
;
import
android.text.Editable
;
import
android.text.TextWatcher
;
...
...
@@ -20,10 +21,11 @@ import androidx.fragment.app.Fragment;
import
com.ly.avfoundation.R
;
import
com.ly.avfoundation.avfoundation.capture.VideoCapture
;
import
com.ly.avfoundation.avfoundation.capture.VideoCapture2
;
import
com.ly.avfoundation.avfoundation.render.CameraSurfaceRenderer
;
public
class
CaptureFragment
extends
Fragment
implements
View
.
OnClickListener
,
VideoCapture
.
OnPreviewSizeChangeListener
,
TextWatcher
,
CameraSurfaceRenderer
.
OnSurfaceRenderListener
{
VideoCapture
.
OnPreviewSizeChangeListener
,
TextWatcher
,
CameraSurfaceRenderer
.
OnSurfaceRenderListener
,
VideoCapture2
.
OnPreviewSizeChangeListener
{
private
static
final
String
TAG
=
"[CaptureFragment]"
;
private
Context
mActivity
=
null
;
...
...
@@ -31,6 +33,8 @@ public class CaptureFragment extends Fragment implements View.OnClickListener,
private
VideoCapture
mCapture
;
private
VideoCapture
.
Configuration
mConfiguration
;
private
VideoCapture2
mCapture2
;
private
VideoCapture2
.
Configuration
mConfiguration2
;
private
SurfaceTexture
mSurfaceTexture
;
private
Boolean
mStartCapture
;
...
...
@@ -43,6 +47,8 @@ public class CaptureFragment extends Fragment implements View.OnClickListener,
private
Button
mStopBtn
;
private
int
mSelectInputType
;
private
Boolean
mUseCamera2
=
Boolean
.
TRUE
;
public
static
CaptureFragment
newInstance
(
Bundle
saveInstanceState
)
{
Bundle
bundle
=
new
Bundle
();
CaptureFragment
fragment
=
new
CaptureFragment
();
...
...
@@ -100,11 +106,15 @@ public class CaptureFragment extends Fragment implements View.OnClickListener,
});
mSelectInputType
=
VideoCapture
.
FactingType
.
FRONT
;
mCapture
=
new
VideoCapture
();
mConfiguration
=
new
VideoCapture
.
Configuration
(
0
,
0
,
0
,
90
);
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
LOLLIPOP
&&
mUseCamera2
)
{
mCapture2
=
new
VideoCapture2
((
Activity
)
mActivity
);
mConfiguration2
=
new
VideoCapture2
.
Configuration
(
0
,
0
,
0
);
}
else
{
mCapture
=
new
VideoCapture
();
mConfiguration
=
new
VideoCapture
.
Configuration
(
0
,
0
,
0
,
90
);
}
mStartCapture
=
false
;
return
view
;
}
...
...
@@ -114,7 +124,6 @@ public class CaptureFragment extends Fragment implements View.OnClickListener,
// to open capture
if
(
mStartCapture
)
{
}
}
...
...
@@ -124,7 +133,6 @@ public class CaptureFragment extends Fragment implements View.OnClickListener,
// to close capture
if
(
mStartCapture
)
{
}
}
...
...
@@ -183,23 +191,50 @@ public class CaptureFragment extends Fragment implements View.OnClickListener,
width
=
Integer
.
parseInt
(
widthStr
);
height
=
Integer
.
parseInt
(
heightStr
);
mConfiguration
.
width
=
width
;
mConfiguration
.
height
=
height
;
mConfiguration
.
angle
=
0
;
mConfiguration
.
facingType
=
mSelectInputType
;
mCapture
.
setPreviewSizeChangeListener
(
this
);
mCapture
.
openCamera
(
mConfiguration
);
mCapture
.
setSurfaceTexture
(
mSurfaceTexture
);
if
(
mSelectInputType
==
VideoCapture
.
FactingType
.
FRONT
)
{
mRender
.
setAngle
(
90
);
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
LOLLIPOP
&&
mUseCamera2
)
{
mConfiguration2
.
width
=
width
;
mConfiguration2
.
height
=
height
;
mConfiguration2
.
angle
=
0
;
switch
(
mSelectInputType
)
{
case
VideoCapture
.
FactingType
.
FRONT
:
mConfiguration2
.
facingType
=
VideoCapture2
.
FacingType
.
FRONT
;
break
;
case
VideoCapture
.
FactingType
.
REAR
:
mConfiguration2
.
facingType
=
VideoCapture2
.
FacingType
.
BACK
;
break
;
}
mCapture2
.
setPreviewSizeChangeListener
(
this
);
mCapture2
.
openCamera
(
mConfiguration2
);
mCapture2
.
setSurfaceTexture
(
mSurfaceTexture
);
if
(
mSelectInputType
==
VideoCapture
.
FactingType
.
FRONT
)
{
mRender
.
setAngle
(
90
);
}
else
{
mRender
.
setAngle
(
270
);
}
}
else
{
mRender
.
setAngle
(
270
);
mConfiguration
.
width
=
width
;
mConfiguration
.
height
=
height
;
mConfiguration
.
angle
=
0
;
mConfiguration
.
facingType
=
mSelectInputType
;
mCapture
.
setPreviewSizeChangeListener
(
this
);
mCapture
.
openCamera
(
mConfiguration
);
mCapture
.
setSurfaceTexture
(
mSurfaceTexture
);
if
(
mSelectInputType
==
VideoCapture
.
FactingType
.
FRONT
)
{
mRender
.
setAngle
(
90
);
}
else
{
mRender
.
setAngle
(
270
);
}
}
}
private
void
handleStopBtn
()
{
mStartCapture
=
Boolean
.
FALSE
;
mCapture
.
releaseCamera
();
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
LOLLIPOP
&&
mUseCamera2
)
{
mCapture2
.
releaseCamera
();
}
else
{
mCapture
.
releaseCamera
();
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录