Use available encoder profiles when the preferred video profile is absent
This commit is contained in:
1 parent
643420b644
commit
499ce21cfc
3 files changed
+7
-5
No files matched your search
@@ -11,7 +11,8 @@ import android.os.Build
|
|||||||
data class StreamCaptureMode(val camera: String, val width: Int, val height: Int, val fps: Int,
|
data class StreamCaptureMode(val camera: String, val width: Int, val height: Int, val fps: Int,
|
||||||
val minimumFps: Int, val highSpeed: Boolean, val codec: String, val bitrate: Int,
|
val minimumFps: Int, val highSpeed: Boolean, val codec: String, val bitrate: Int,
|
||||||
val videoCodec: StreamVideoCodec = StreamVideoCodec.H264,
|
val videoCodec: StreamVideoCodec = StreamVideoCodec.H264,
|
||||||
val minimumBitrate: Int = 1, val maximumBitrate: Int = Int.MAX_VALUE) {
|
val minimumBitrate: Int = 1, val maximumBitrate: Int = Int.MAX_VALUE,
|
||||||
|
val encoderProfile: Int? = videoCodec.profile) {
|
||||||
val label get() = "${width}×${height} · $fps fps"
|
val label get() = "${width}×${height} · $fps fps"
|
||||||
}
|
}
|
||||||
data class StreamCamera(val id: String, val lens: LensOption, val modes: List<StreamCaptureMode>)
|
data class StreamCamera(val id: String, val lens: LensOption, val modes: List<StreamCaptureMode>)
|
||||||
@@ -39,14 +40,14 @@ object StreamCameraModes {
|
|||||||
if (highSpeed && Build.VERSION.SDK_INT >= 29 && !codec.isHardwareAccelerated) continue
|
if (highSpeed && Build.VERSION.SDK_INT >= 29 && !codec.isHardwareAccelerated) continue
|
||||||
val caps = codec.getCapabilitiesForType(type.mime)
|
val caps = codec.getCapabilitiesForType(type.mime)
|
||||||
val video = caps.videoCapabilities
|
val video = caps.videoCapabilities
|
||||||
|
val profile = type.encoderProfile(caps.profileLevels.map { it.profile }.toIntArray())
|
||||||
if (!caps.colorFormats.contains(MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface) ||
|
if (!caps.colorFormats.contains(MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface) ||
|
||||||
(type.profile != null && caps.profileLevels.none { it.profile == type.profile }) ||
|
|
||||||
!video.areSizeAndRateSupported(width, height, fps.toDouble())) continue
|
!video.areSizeAndRateSupported(width, height, fps.toDouble())) continue
|
||||||
val bitrate = (width.toLong() * height * fps / 14).coerceIn(512_000L, 16_000_000L).toInt()
|
val bitrate = (width.toLong() * height * fps / 14).coerceIn(512_000L, 16_000_000L).toInt()
|
||||||
modes.add(StreamCaptureMode(lens.cameraId, width, height, fps, lower, highSpeed, codec.name,
|
modes.add(StreamCaptureMode(lens.cameraId, width, height, fps, lower, highSpeed, codec.name,
|
||||||
video.bitrateRange.clamp(bitrate), type, video.bitrateRange.lower, video.bitrateRange.upper))
|
video.bitrateRange.clamp(bitrate), type, video.bitrateRange.lower, video.bitrateRange.upper, profile))
|
||||||
LogManager.addLog("INFO", "video", "camera mode camera=${lens.cameraId} ${width}x$height fps=$lower..$fps " +
|
LogManager.addLog("INFO", "video", "camera mode camera=${lens.cameraId} ${width}x$height fps=$lower..$fps " +
|
||||||
"highSpeed=$highSpeed type=${type.label} encoder=${codec.name} bitrate=${modes.last().bitrate} " +
|
"highSpeed=$highSpeed type=${type.label} encoder=${codec.name} profile=$profile bitrate=${modes.last().bitrate} " +
|
||||||
"range=${video.bitrateRange} achievable=${video.getAchievableFrameRatesFor(width, height)}")
|
"range=${video.bitrateRange} achievable=${video.getAchievableFrameRatesFor(width, height)}")
|
||||||
break
|
break
|
||||||
} catch (e: Exception) { LogManager.addLog("WARN", "video", "codec probe ${codec.name}: ${e.message}") }
|
} catch (e: Exception) { LogManager.addLog("WARN", "video", "codec probe ${codec.name}: ${e.message}") }
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class StreamCaptureEngine(
|
|||||||
if (switchStartedNs == 0L) switchStartedNs = reportNs
|
if (switchStartedNs == 0L) switchStartedNs = reportNs
|
||||||
val format = MediaFormat.createVideoFormat(mode.videoCodec.mime, mode.width, mode.height).apply {
|
val format = MediaFormat.createVideoFormat(mode.videoCodec.mime, mode.width, mode.height).apply {
|
||||||
setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
|
setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
|
||||||
mode.videoCodec.profile?.let { setInteger(MediaFormat.KEY_PROFILE, it) }
|
mode.encoderProfile?.let { setInteger(MediaFormat.KEY_PROFILE, it) }
|
||||||
setInteger(MediaFormat.KEY_BIT_RATE, config.bitrate)
|
setInteger(MediaFormat.KEY_BIT_RATE, config.bitrate)
|
||||||
setInteger(MediaFormat.KEY_FRAME_RATE, mode.fps); setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1)
|
setInteger(MediaFormat.KEY_FRAME_RATE, mode.fps); setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1)
|
||||||
if (Build.VERSION.SDK_INT >= 29) setInteger(MediaFormat.KEY_MAX_B_FRAMES, 0)
|
if (Build.VERSION.SDK_INT >= 29) setInteger(MediaFormat.KEY_MAX_B_FRAMES, 0)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ enum class StreamVideoCodec(val id: Int, val label: String, val mime: String, va
|
|||||||
require(bytes.isNotEmpty() && bytes.size <= H264AnnexB.MAX_FRAME)
|
require(bytes.isNotEmpty() && bytes.size <= H264AnnexB.MAX_FRAME)
|
||||||
return if (annexB) H264AnnexB.normalize(bytes) else bytes.copyOf()
|
return if (annexB) H264AnnexB.normalize(bytes) else bytes.copyOf()
|
||||||
}
|
}
|
||||||
|
fun encoderProfile(available: IntArray): Int? = profile?.takeIf { it in available } ?: available.firstOrNull()
|
||||||
/** Parameter sets могут прийти отдельными CODEC_CONFIG callbacks; сохраняем полный набор текущей revision. */
|
/** Parameter sets могут прийти отдельными CODEC_CONFIG callbacks; сохраняем полный набор текущей revision. */
|
||||||
fun mergeConfig(previous: ByteArray, update: ByteArray): ByteArray {
|
fun mergeConfig(previous: ByteArray, update: ByteArray): ByteArray {
|
||||||
val next = normalize(update)
|
val next = normalize(update)
|
||||||
|
|||||||
Reference in new issue
Block a user