fix(android): don't letterbox against the configure placeholder
H264Decoder.outputSize() reported the 320x240 configure() placeholder until the codec parsed the in-band SPS, so fitVideo sized the view to 1488x1116 (1.33 aspect) and the first rendered frame(s) of 2.4 content were visibly squished before the real size corrected it ~40ms later. Report no size until INFO_OUTPUT_FORMAT_CHANGED delivers the real one: the first frame renders into the fullscreen surface and the correct letterbox follows immediately. Validated live on the Fairphone 6 (the placeholder 'video size' line is gone from logcat; 25/25 JVM tests).
This commit is contained in:
@@ -330,6 +330,18 @@ list the phone at 192.168.178.29:5005; a 25s `--send --target monitor
|
|||||||
Note: with both the Pi and the phone on the LAN, plain `--send` refuses
|
Note: with both the Pi and the phone on the LAN, plain `--send` refuses
|
||||||
(two receivers found) — target the phone with `--peer`.
|
(two receivers found) — target the phone with `--peer`.
|
||||||
|
|
||||||
|
Follow-up from the same on-device session — startup squish eliminated:
|
||||||
|
`H264Decoder.outputSize()` previously reported the 320x240 configure()
|
||||||
|
placeholder until the codec parsed the SPS, so `fitVideo` sized the
|
||||||
|
TextureView 1488x1116 (1.33 aspect) and the first rendered frame(s) of
|
||||||
|
2.4 content were visibly squished. It now returns null until
|
||||||
|
`INFO_OUTPUT_FORMAT_CHANGED` fires; the first frame renders into the
|
||||||
|
fullscreen surface and the correct letterbox (2484x1035) follows within
|
||||||
|
~40ms. Validated live: no placeholder "video size" line in logcat.
|
||||||
|
|
||||||
|
Commits: 9a24933 (PROTOCOL_DNS_SD discovery fix + docs), plus the
|
||||||
|
outputSize fix (see git log).
|
||||||
|
|
||||||
Still open (accepted, needs a device or a new test dep):
|
Still open (accepted, needs a device or a new test dep):
|
||||||
|
|
||||||
- Untested on device: `setOutputSurface` mid-session (surface switch) and
|
- Untested on device: `setOutputSurface` mid-session (surface switch) and
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ class H264Decoder {
|
|||||||
|
|
||||||
private var codec: MediaCodec? = null
|
private var codec: MediaCodec? = null
|
||||||
private var configured = false
|
private var configured = false
|
||||||
|
// True once the codec parsed the in-band SPS (INFO_OUTPUT_FORMAT_CHANGED).
|
||||||
|
// Before that, outputFormat still carries the configure() placeholder and
|
||||||
|
// must not drive layout — sizing the view to it squishes the first frame(s).
|
||||||
|
@Volatile
|
||||||
|
private var realFormatSeen = false
|
||||||
@Volatile
|
@Volatile
|
||||||
private var renderSurface: Surface? = null
|
private var renderSurface: Surface? = null
|
||||||
|
|
||||||
@@ -57,6 +62,7 @@ class H264Decoder {
|
|||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
configured = true
|
configured = true
|
||||||
|
realFormatSeen = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Points the decoder at a (possibly new) render surface. */
|
/** Points the decoder at a (possibly new) render surface. */
|
||||||
@@ -117,6 +123,7 @@ class H264Decoder {
|
|||||||
}
|
}
|
||||||
index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED -> {
|
index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED -> {
|
||||||
// The codec parsed the SPS size; outputFormat is ready.
|
// The codec parsed the SPS size; outputFormat is ready.
|
||||||
|
realFormatSeen = true
|
||||||
android.util.Log.i(
|
android.util.Log.i(
|
||||||
"H264Decoder", "output format: " +
|
"H264Decoder", "output format: " +
|
||||||
c.outputFormat.getInteger(MediaFormat.KEY_WIDTH) +
|
c.outputFormat.getInteger(MediaFormat.KEY_WIDTH) +
|
||||||
@@ -141,10 +148,11 @@ class H264Decoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The decoded resolution once the first keyframe has configured the codec. */
|
/** The decoded resolution, once the first keyframe configured the codec. */
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun outputSize(): Pair<Int, Int>? {
|
fun outputSize(): Pair<Int, Int>? {
|
||||||
val c = codec ?: return null
|
val c = codec ?: return null
|
||||||
|
if (!realFormatSeen) return null // still the configure() placeholder
|
||||||
return try {
|
return try {
|
||||||
val format = c.outputFormat
|
val format = c.outputFormat
|
||||||
val width = format.getInteger(MediaFormat.KEY_WIDTH)
|
val width = format.getInteger(MediaFormat.KEY_WIDTH)
|
||||||
|
|||||||
Reference in New Issue
Block a user