Using CameraX 1.4.0-alpha03.
Code like this:
val preview = Preview.Builder()
.setResolutionSelector(
ResolutionSelector.Builder()
.setAllowedResolutionMode(PREFER_HIGHER_RESOLUTION_OVER_CAPTURE_RATE)
.setAspectRatioStrategy(AspectRatioStrategy.RATIO_16_9_FALLBACK_AUTO_STRATEGY)
.setResolutionStrategy(
ResolutionStrategy(
Size(1920, 1080),
ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER
)
).build()
)
val cameraSelector = CameraSelector.Builder()
.addCameraFilter(ExternalCameraFilter(camera.id))
.build()
val qualitySelector = QualitySelector.fromOrderedList(
listOf(Quality.FHD, Quality.HD, Quality.SD),
FallbackStrategy.higherQualityOrLowerThan(
Quality.SD
)
)
val recorder = Recorder.Builder().setQualitySelector(qualitySelector).build()
val videoCapture = VideoCapture.withOutput(recorder)
val useCaseGroup =
UseCaseGroup.Builder()
.addUseCase(preview!!)
.addUseCase(videoCapture)
.setViewPort(view!!.viewPort!!)
.build()
val cameraProvider = provider.get()
cameraProvider.unbindAll()
preview?.setSurfaceProvider(view!!.surfaceProvider)
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup)
ExternalCameraFilter:
@SuppressLint("UnsafeOptInUsageError")
override fun filter(cameraInfos: MutableList<CameraInfo>): MutableList<CameraInfo> {
return cameraInfos.filter { camInfo ->
isExternalCamera(camInfo)
}.filter {
try {
Camera2CameraInfo.from(it).cameraId == cameraId
} catch (e: Exception) {
e.printStackTrace()
false
}
}.toMutableList()
}
@SuppressLint("UnsafeOptInUsageError")
private fun isExternalCamera(cameraInfo: CameraInfo): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try {
Camera2CameraInfo.from(cameraInfo).getCameraCharacteristic(
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL
) == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL
} catch (e: Exception) {
e.printStackTrace()
false
}
} else {
false
}
}
I got a very low resolution: 640x442.
If remove the videoCapture use-case, then got correct 1080P.
Some Logs here:
19:59:33.261 CapabilitiesByQuality E No supported EncoderProfiles
19:59:33.262 VideoConfigUtil D No EncoderProfiles present. May rely on fallback defaults to derive VIDEO settings [chosen mime type: video/avc, dynamic range: DynamicRange@2080ac3{encoding=SDR, bitDepth=8}]
19:59:33.262 UseCaseAttachState D Active and attached use case: [] for camera: 102
19:59:33.262 VidEncCfgDefaultRslvr D Default resolved frame rate: 30fps. [Expected operating range: <UNSPECIFIED>]
19:59:33.262 D Resolved VIDEO frame rate: 30fps
19:59:33.262 D Using fallback VIDEO bitrate
19:59:33.263 VideoConfigUtil D Base Bitrate(14000000bps) * Bit Depth Ratio (8 / 8) * Frame Rate Ratio(30 / 30) * Width Ratio(640 / 1280) * Height Ratio(442 / 720) = 4297222
19:59:33.263 Camera2CameraImpl D {Camera@4890b0c[id=102]} Use case androidx.camera.core.streamsharing.StreamSharing-73ab81ad-8aee-43c8-8758-02fc986545c579779905 ACTIVE
19:59:33.263 UseCaseAttachState D Active and attached use case: [] for camera: 102
19:59:33.263 VideoConfigUtil W Unsupported mime type video/avc or profile level -1. Data space is unspecified.
19:59:33.283 VideoCapabilities W Unrecognized profile/level 0/3 for video/mpeg2
19:59:33.295 CCodec D allocate(c2.rk.avc.encoder)
19:59:33.296 Codec2Client I Available Codec2 services: "default" "software"
19:59:33.297 CCodec I setting up 'default' as default (vendor) store
19:59:33.302 I Created component [c2.rk.avc.encoder]
19:59:33.302 CCodecConfig D read media type: video/avc
19:59:33.304 ReflectedParamUpdater D extent() != 1 for single value type: algo.buffers.max-count.values
19:59:33.304 D extent() != 1 for single value type: output.subscribed-indices.values
19:59:33.304 D extent() != 1 for single value type: input.buffers.allocator-ids.values
19:59:33.305 D extent() != 1 for single value type: output.buffers.allocator-ids.values
19:59:33.305 D extent() != 1 for single value type: algo.buffers.allocator-ids.values
19:59:33.305 D extent() != 1 for single value type: output.buffers.pool-ids.values
19:59:33.305 D extent() != 1 for single value type: algo.buffers.pool-ids.values
19:59:33.306 D ignored struct field coding.gop.values
19:59:33.306 D ignored struct field coding.qp.values
19:59:33.307 CCodecConfig D ignoring local param raw.color (0xc2001809) as it is already supported
19:59:33.308 I query failed after returning 14 values (BAD_INDEX)
19:59:33.309 D c2 config diff is Dict {
c2::u32 algo.bitrate-mode.value = 3
c2::u32 coded.bitrate.value = 64000
c2::float coded.frame-rate.value = 1
c2::u32 coded.pl.level = 20489
c2::u32 coded.pl.profile = 20480
c2::u32 coded.vui.color.matrix = 0
c2::u32 coded.vui.color.primaries = 0
c2::u32 coded.vui.color.range = 0
c2::u32 coded.vui.color.transfer = 0
c2::u32 coding.intra-refresh.mode = 0
c2::float coding.intra-refresh.period = 0
c2::u32 coding.request-sync-frame.value = 0
c2::i64 coding.sync-frame-interval.value = 1000000
Buffer coding.temporal-layering = {
00000000: 10 00 00 00 07 20 01 52 00 00 00 00 00 00 00 00 ..... .R........
}
c2::u32 input.delay.value = 0
string input.media-type.value = "video/raw"
string output.media-type.value = "video/avc"
c2::u32 raw.color.matrix = 0
c2::u32 raw.color.primaries = 0
c2::u32 raw.color.range = 0
c2::u32 raw.color.transfer = 0
c2::u32 raw.size.height = 144
c2::u32 raw.size.width = 176
}
19:59:33.309 ColorUtils W expected specified color aspects (0:0:0:0)
19:59:33.313 hw-BpHwBinder I onLastStrongRef automatically unlinking death recipients
19:59:33.314 CameraOrientationUtil D getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=0, isOppositeFacing=false, result=0
19:59:33.314 VideoCapture D camera timebase = UPTIME, processing timebase = UPTIME
19:59:33.314 DeferrableSurface D Surface created[total_surfaces=9, used_surfaces=3](androidx.camera.core.processing.SurfaceEdge$SettableSurface@497ae85}
19:59:33.315 D Surface created[total_surfaces=10, used_surfaces=3](androidx.camera.core.SurfaceRequest$2@129ae01}
19:59:33.316 D New surface in use[total_surfaces=10, used_surfaces=4](androidx.camera.core.SurfaceRequest$2@129ae01}
19:59:33.316 D use count+1, useCount=1 androidx.camera.core.SurfaceRequest$2@129ae01
19:59:33.316 Recorder D Surface is requested in state: CONFIGURING, Current surface: 0
19:59:33.317 CameraOrientationUtil D getRelativeImageRotation: destRotationDegrees=0, sourceRotationDegrees=0, isOppositeFacing=false, result=0
19:59:33.317 CapabilitiesByQuality E No supported EncoderProfiles
19:59:33.318 Recorder D Using supported quality of ConstantQuality{value=-1, name=NONE, typicalSizes=[]} for surface size 640x442
19:59:33.318 D Try to safely release video encoder: null
19:59:33.319 D Video source has transitioned to state: ACTIVE_NON_STREAMING
If list supported resolutions by CamcorderProfileResolutionQuirk, got this:
[640x480, 720x480, 720x576, 800x600, 1280x720, 1024x768, 1360x768, 1280x960, 1280x1024, 1920x1080]
I tried to get more info by:
Recorder.getVideoCapabilities(
this.cameraInfo,
Recorder.VIDEO_CAPABILITIES_SOURCE_CAMCORDER_PROFILE
).apply {
getSupportedQualities(DynamicRange.SDR).apply {
Timber.d("getSupportedQualities ${this}")
}
Timber.d("supportedDynamicRanges ${supportedDynamicRanges}")
Timber.d(
"Profiles FHD: ${
getProfiles(
Quality.FHD,
DynamicRange.SDR
)?.videoProfiles
}"
)
}
And here the result:
D getSupportedQualities []
D supportedDynamicRanges []
D Profiles FHD: null
It says supported qualities for video is empty, dynamic ranges either, and profile for FHD is null. Can any one tell me what's wrong here.
Get high resolution with VideoCapture.
Edit:
Sorry for missing some code here,
There is a OverlayEffect left:
val overlayEffect = OverlayEffect(
CameraEffect.PREVIEW or CameraEffect.VIDEO_CAPTURE or CameraEffect.IMAGE_CAPTURE,
0,
Handler(),
{})
...
val useCaseGroup =
UseCaseGroup.Builder()
.addUseCase(preview!!)
.addUseCase(videoCapture)
.addEffect(overlayEffect)
.setViewPort(view!!.viewPort!!)
.build()
That's the reason why CameraX chose a low resolution.
If adding the OverlayEffect, low resolution presented.
If not, high resolution is picked.
That might be an issue for CameraX 1.4.0-alpha03.
Finally I build my own camerax module from the newest androidx codebase following onboarding docs, then the issue gone.
So, close this question.