Keep codec mode probes consistent with live encoding
This commit is contained in:
1 parent
7be4b8884c
commit
c0d5db318f
3 files changed
+36
-17
No files matched your search
@@ -25,8 +25,8 @@ object CallVideoHevcProbe {
|
||||
}
|
||||
|
||||
@JvmStatic fun main(args: Array<String>) {
|
||||
require(args.size in 1..2 && (args.size == 1 || args[1] in listOf("parameters", "call"))) {
|
||||
"Expected output directory [parameters|call]"
|
||||
require(args.size in 1..2 && (args.size == 1 || args[1] in listOf("parameters", "call", "receive"))) {
|
||||
"Expected output directory [parameters|call|receive]"
|
||||
}
|
||||
check(Build.VERSION.SDK_INT >= 29) { "Hardware codec enumeration requires API 29" }
|
||||
val directory = File(args[0]); check(directory.isDirectory || directory.mkdirs())
|
||||
@@ -39,6 +39,22 @@ object CallVideoHevcProbe {
|
||||
!it.isEncoder && it.isHardwareAccelerated && "video/hevc" in it.supportedTypes
|
||||
}
|
||||
report("start encoder=${encoder.name} decoder=${decoder.name} frames=$FRAMES")
|
||||
if (args.getOrNull(1) == "receive") {
|
||||
val decoders = checkNotNull(CallVideoCodec.probeDecoders()[2]) { "No verified HEVC decoder" }
|
||||
val files = directory.listFiles()!!.filter { it.extension == "key" }.sortedBy { it.name }
|
||||
check(files.isNotEmpty()) { "No remote KEY files in $directory" }
|
||||
for (file in files) {
|
||||
val bytes = file.readBytes(); val inspected = checkNotNull(CallVideoNative.inspect(2, bytes))
|
||||
val format = CallVideoFormat(1, inspected[0].toInt(), inspected[1].toInt(), codec = 2,
|
||||
level = inspected[2].toInt(), profile = inspected[3].toInt())
|
||||
val implementation = checkNotNull(decoders.modes.firstOrNull { it.supports(format) })
|
||||
CallVideoCodec.verifyDecode(format, List(FRAMES) { CallVideoCodec.Packet(1_000_000L + it * 33333, true, bytes) },
|
||||
implementation.name)
|
||||
report("remote PASSED file=${file.name} format=$format decoder=${implementation.name}")
|
||||
}
|
||||
report("remote finished files=${files.size}")
|
||||
return
|
||||
}
|
||||
if (args.getOrNull(1) == "call") {
|
||||
val encoders = CallVideoCodec.probe()
|
||||
val decoders = CallVideoCodec.probeDecoders()
|
||||
|
||||
@@ -290,20 +290,22 @@ internal class CallVideoCodec(requested: CallVideoFormat, bitrate: Int, val name
|
||||
var profiles = 0; var pipeline = 0; var maximumLevel = 0
|
||||
for (profile in listOf(1, 2)) {
|
||||
try {
|
||||
val level = if (type.id == 1) { if (size.width > 1280) 40 else 31 }
|
||||
else if (size.width > 1280 || profile == 2) 120 else 93
|
||||
var profilePipeline = 0
|
||||
for (portrait in listOf(false, true)) {
|
||||
val w = if (portrait) size.height else size.width; val h = if (portrait) size.width else size.height
|
||||
check(caps.videoCapabilities?.areSizeAndRateSupported(w, h, 30.0) == true) { "Decoder geometry unsupported: ${w}x$h" }
|
||||
val f = CallVideoFormat(1, w, h, codec = type.id, level = level, profile = profile)
|
||||
val key = checkNotNull(CallVideoNative.probeKey(type.id, profile, w, h))
|
||||
validateKey(key, f)
|
||||
profilePipeline = maxOf(profilePipeline, verifyDecode(f, List(8) { Packet(1_000_000L + it * 33333, true, key) },
|
||||
entry.name, true))
|
||||
}
|
||||
profiles = profiles or profile; maximumLevel = maxOf(maximumLevel, level)
|
||||
pipeline = maxOf(pipeline, profilePipeline)
|
||||
val level = if (type.id == 1) { if (size.width > 1280) 40 else 31 }
|
||||
else if (size.width > 1280 || profile == 2) 120 else 93
|
||||
var profilePipeline = 0
|
||||
for (portrait in listOf(false, true)) {
|
||||
val w = if (portrait) size.height else size.width; val h = if (portrait) size.width else size.height
|
||||
check(caps.videoCapabilities?.areSizeAndRateSupported(w, h, 30.0) == true) {
|
||||
"Decoder geometry unsupported: ${w}x$h"
|
||||
}
|
||||
val f = CallVideoFormat(1, w, h, codec = type.id, level = level, profile = profile)
|
||||
val key = checkNotNull(CallVideoNative.probeKey(type.id, profile, w, h))
|
||||
validateKey(key, f)
|
||||
profilePipeline = maxOf(profilePipeline,
|
||||
verifyDecode(f, List(8) { Packet(1_000_000L + it * 33333, true, key) }, entry.name, true))
|
||||
}
|
||||
profiles = profiles or profile; maximumLevel = maxOf(maximumLevel, level)
|
||||
pipeline = maxOf(pipeline, profilePipeline)
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("WARN", "call", "video decoder profile probe rejected name=${entry.name} " +
|
||||
"codec=${type.id} profile=$profile size=$size: ${e.message}")
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
|
||||
// Профиль и envelope задаются явно: автоматический выбор level при смене bitrate запрещён.
|
||||
bool CallVideoEncoder::open(const call_video_format& format, uint32_t bitrate, const QString& backend) {
|
||||
if (!call_video_format_valid(&format) || bitrate < CALL_VIDEO_RATE_MIN_BPS || bitrate > format.maximum_bps) {
|
||||
if (!call_video_format_valid(&format) || bitrate < CALL_VIDEO_RATE_MIN_BPS || bitrate > format.maximum_bps
|
||||
|| (format.codec == CALL_VIDEO_H265 && format.profile != CALL_VIDEO_MAIN)) {
|
||||
m_error = "Invalid call video encoder configuration";
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "call video open invalid generation=%llu codec=%u level=%u bitrate=%u cap=%u profile=%u",
|
||||
(unsigned long long)format.generation, format.codec, format.level, bitrate, format.maximum_bps, format.profile); return false;
|
||||
|
||||
Reference in new issue
Block a user