|
|
|
|
@ -23,7 +23,7 @@ internal class CallVideoCodec(val format: CallVideoFormat, val bitrate: Int, nam
|
|
|
|
|
try { |
|
|
|
|
val media = MediaFormat.createVideoFormat(type.mime, format.width, format.height).apply { |
|
|
|
|
setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible) |
|
|
|
|
setInteger(MediaFormat.KEY_PROFILE, if (format.codec == 1) MediaCodecInfo.CodecProfileLevel.AVCProfileBaseline |
|
|
|
|
setInteger(MediaFormat.KEY_PROFILE, if (format.codec == 1) MediaCodecInfo.CodecProfileLevel.AVCProfileConstrainedBaseline |
|
|
|
|
else MediaCodecInfo.CodecProfileLevel.HEVCProfileMain) |
|
|
|
|
setInteger(MediaFormat.KEY_LEVEL, platformLevel(format.codec, format.level)) |
|
|
|
|
setInteger(MediaFormat.KEY_BIT_RATE, bitrate); setInteger(MediaFormat.KEY_FRAME_RATE, format.fps) |
|
|
|
|
@ -122,11 +122,11 @@ internal class CallVideoCodec(val format: CallVideoFormat, val bitrate: Int, nam
|
|
|
|
|
try { |
|
|
|
|
val f = CallVideoFormat(1, 1280, 720, codec = type.id, level = if (type.id == 1) 31 else 93) |
|
|
|
|
val caps = entry.getCapabilitiesForType(type.mime) |
|
|
|
|
if (!caps.videoCapabilities.areSizeAndRateSupported(1280, 720, 30.0) |
|
|
|
|
|| !caps.encoderCapabilities.isBitrateModeSupported(MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR)) continue |
|
|
|
|
if (caps.videoCapabilities?.areSizeAndRateSupported(1280, 720, 30.0) != true |
|
|
|
|
|| caps.encoderCapabilities?.isBitrateModeSupported(MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR) != true) continue |
|
|
|
|
CallVideoCodec(f, 1_000_000, entry.name).use { encoder -> |
|
|
|
|
val packets = mutableListOf<Packet>(); var input = 0 |
|
|
|
|
val deadline = System.nanoTime() + 2_000_000_000 |
|
|
|
|
val deadline = System.nanoTime() + 5_000_000_000 |
|
|
|
|
while (packets.size < 4 && System.nanoTime() < deadline) { |
|
|
|
|
if (input < 8 && encoder.submit(null, 1_000_000L + input * 33333, input == 0)) input++ |
|
|
|
|
packets += encoder.drain(); Thread.sleep(2) |
|
|
|
|
@ -182,19 +182,21 @@ internal class CallVideoCodec(val format: CallVideoFormat, val bitrate: Int, nam
|
|
|
|
|
} |
|
|
|
|
val bits = Bits(raw.toByteArray()) |
|
|
|
|
if (f.codec == 1) { |
|
|
|
|
check(bits.read(8) == 66 && bits.read(8) and 64 != 0) { "AVC is not Constrained Baseline" } |
|
|
|
|
check(bits.read(8) <= f.level); bits.ue(); bits.ue() |
|
|
|
|
val profile = bits.read(8); val constraints = bits.read(8); val level = bits.read(8) |
|
|
|
|
check(profile == 66 && constraints and 64 != 0) { "AVC profile=$profile constraints=$constraints level=$level SPS=${sps.joinToString { "%02x".format(it) }}" } |
|
|
|
|
check(level <= f.level); bits.ue(); bits.ue() |
|
|
|
|
when (bits.ue()) { 0 -> bits.ue(); 2 -> Unit; else -> error("Unsupported AVC POC") } |
|
|
|
|
check(bits.ue() <= 1) { "AVC uses more than one reference" } |
|
|
|
|
} else { |
|
|
|
|
bits.read(4); check(bits.read(3) == 0) { "HEVC temporal layers" }; bits.read(1) |
|
|
|
|
bits.read(2); check(bits.read(1) == 0 && bits.read(5) == 1) { "HEVC is not Main/Main tier" } |
|
|
|
|
bits.read(2); val tier = bits.read(1); val profile = bits.read(5) |
|
|
|
|
check(tier == 0 && profile == 1) { "HEVC profile=$profile tier=$tier SPS=${sps.joinToString { "%02x".format(it) }}" } |
|
|
|
|
repeat(10) { bits.read(8) }; check(bits.read(8) <= f.level) |
|
|
|
|
bits.ue(); check(bits.ue() == 1); bits.ue(); bits.ue() |
|
|
|
|
if (bits.read(1) != 0) repeat(4) { bits.ue() } |
|
|
|
|
check(bits.ue() == 0 && bits.ue() == 0); bits.ue(); bits.read(1) |
|
|
|
|
val dpb = bits.ue(); check(bits.ue() == 0) { "HEVC reordered frames" } |
|
|
|
|
check(dpb <= 1) { "HEVC requires more than two decoded pictures" } |
|
|
|
|
check(dpb <= 1) { "HEVC decoded pictures=${dpb + 1} SPS=${sps.joinToString { "%02x".format(it) }}" } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|