desktop: fix stretched video preview and playback for AV1 videos (#7391)

* desktop: fix stretched video preview and playback for AV1 videos

libvlc passes the padded size the decoder allocated to the buffer format
callback, not the size of the picture. dav1d pads to a multiple of 128, so
a 1920x1080 AV1 video arrives as 1920x1152, and vlc scales the picture to
fill it - the preview sent with the message, and desktop playback, were
6.7% too tall. H264 pads much less, so it was barely visible there.

Ask for the size of the track being played instead. It is already populated
when the buffer format is negotiated, and matching the track that is playing
matters for files with more than one video track, where the first track is
not necessarily the one being decoded. Falls back to the previous behaviour
when the track is not known.

* plans: desktop video preview aspect ratio
This commit is contained in:
Narasimha-sc authored and GitHub committed 2026-08-19 14:34:07 +01:00
1 parent 222fc4ad99
commit 11c7a62a38
2 files changed
+86 -3

No files matched your search

@@ -23,6 +23,7 @@ import javax.swing.SwingUtilities
internal class SkiaBitmapVideoSurface : VideoSurface(VideoSurfaceAdapters.getVideoSurfaceAdapter()) {
private val videoSurface = SkiaBitmapVideoSurface()
@Volatile private var mediaPlayer: MediaPlayer? = null
private lateinit var imageInfo: ImageInfo
private lateinit var frameBytes: ByteArray
private val skiaBitmap: Bitmap = Bitmap()
@@ -31,6 +32,7 @@ internal class SkiaBitmapVideoSurface : VideoSurface(VideoSurfaceAdapters.getVid
val bitmap: State<ImageBitmap?> = composeBitmap
override fun attach(mediaPlayer: MediaPlayer) {
this.mediaPlayer = mediaPlayer
videoSurface.attach(mediaPlayer)
}
@@ -39,9 +41,17 @@ internal class SkiaBitmapVideoSurface : VideoSurface(VideoSurfaceAdapters.getVid
private var sourceHeight: Int = 0
override fun getBufferFormat(sourceWidth: Int, sourceHeight: Int): BufferFormat {
this.sourceWidth = sourceWidth
this.sourceHeight = sourceHeight
return RV32BufferFormat(sourceWidth, sourceHeight)
// libvlc passes the size the decoder padded the picture to, not the size of the picture (dav1d
// pads to a multiple of 128, so 1920x1080 arrives as 1920x1152), and vlc stretches the picture to
// fill whatever size is returned. Ask for the size of the track being played instead. The format
// is negotiated more than once, and vlc has not selected the track yet on the first calls
val player = mediaPlayer
val tracks = player?.media()?.info()?.videoTracks()
val playingTrack = player?.video()?.track()
val track = tracks?.firstOrNull { it.id() == playingTrack } ?: tracks?.singleOrNull()
this.sourceWidth = track?.width()?.takeIf { it > 0 } ?: sourceWidth
this.sourceHeight = track?.height()?.takeIf { it > 0 } ?: sourceHeight
return RV32BufferFormat(this.sourceWidth, this.sourceHeight)
}
override fun allocatedBuffers(buffers: Array<ByteBuffer>) {