Make built-in subtitles to be fixed into video size #140

Closed
opened 2025-09-27 18:02:50 +00:00 by uddhav-m · 3 comments
uddhav-m commented 2025-09-27 18:02:50 +00:00 (Migrated from github.com)

This is the bug that i found with built-in subs, when scaled into cover & fill mode they end up inside the scaled video & get cropped -

Image
This is the bug that i found with built-in subs, when scaled into cover & fill mode they end up inside the scaled video & get cropped - <img width="2400" height="1080" alt="Image" src="https://github.com/user-attachments/assets/5cfaf17a-cde3-4790-957b-7551c5490e38" />
AdityasahuX07 commented 2025-09-27 18:20:15 +00:00 (Migrated from github.com)

+1

+1
tapframe commented 2025-09-28 11:08:09 +00:00 (Migrated from github.com)

VLClib limitations. Can’t do much about it.

VLClib limitations. Can’t do much about it.
uddhav-m commented 2025-09-28 18:49:53 +00:00 (Migrated from github.com)

VLClib limitations. Can’t do much about it.

damn that sucks :(
i tried asking claude about this, it gave me these options -

This is a common issue when using VLC library for Android with built-in subtitles in scaled video modes. Here are several solutions you can implement:

Instead of relying on VLC's built-in subtitle rendering, extract and render subtitles separately:

// Disable VLC's built-in subtitle rendering
mediaPlayer.setVideoTrackEnabled(false) // for subtitle track

// Extract subtitle data
private fun extractSubtitles() {
    val subtitleTrack = mediaPlayer.spuTracks
    // Parse subtitle data and render externally
}

// Custom subtitle overlay
private fun setupSubtitleOverlay() {
    val subtitleView = TextView(context).apply {
        setTextColor(Color.WHITE)
        setBackgroundColor(Color.parseColor("#80000000"))
        gravity = Gravity.CENTER
        textSize = 16f
    }
    
    // Add subtitle view on top of video view
    val layoutParams = FrameLayout.LayoutParams(
        FrameLayout.LayoutParams.MATCH_PARENT,
        FrameLayout.LayoutParams.WRAP_CONTENT
    ).apply {
        gravity = Gravity.BOTTOM
        bottomMargin = 50 // Adjust as needed
    }
    
    parentLayout.addView(subtitleView, layoutParams)
}

Solution 2: Adjust VLC Subtitle Position

Try modifying VLC's subtitle rendering parameters:

// Set subtitle position outside the video area
mediaPlayer.setVideoSubtitleDelay(0)

// Adjust subtitle position - values in percentage
// This might work depending on VLC version
val options = arrayListOf<String>()
options.add("--sub-margin=10") // Margin from bottom
options.add("--subsdec-encoding=UTF-8")
options.add("--sub-source=file")

libVLC = LibVLC(context, options)

Solution 3: Use TextureView with Custom Layout

Switch from SurfaceView to TextureView for better control:

class CustomVideoView : FrameLayout {
    private lateinit var textureView: TextureView
    private lateinit var subtitleOverlay: TextView
    
    private fun setupViews() {
        // Video texture view
        textureView = TextureView(context)
        addView(textureView)
        
        // Subtitle overlay positioned outside video bounds
        subtitleOverlay = TextView(context).apply {
            setTextColor(Color.WHITE)
            setBackgroundResource(R.drawable.subtitle_background)
        }
        
        val params = LayoutParams(
            LayoutParams.MATCH_PARENT,
            LayoutParams.WRAP_CONTENT
        ).apply {
            gravity = Gravity.BOTTOM
        }
        
        addView(subtitleOverlay, params)
    }
}

Solution 4: Calculate Video Bounds and Position Subtitles

Dynamically calculate the actual video rendering area:

private fun positionSubtitles() {
    val videoWidth = mediaPlayer.videoTrack?.width ?: 0
    val videoHeight = mediaPlayer.videoTrack?.height ?: 0
    val viewWidth = videoView.width
    val viewHeight = videoView.height
    
    // Calculate actual video bounds based on scale mode
    val videoBounds = calculateVideoBounds(
        videoWidth, videoHeight, 
        viewWidth, viewHeight, 
        scaleMode
    )
    
    // Position subtitle below video area
    val subtitleY = videoBounds.bottom + 20
    subtitleView.y = subtitleY
}

private fun calculateVideoBounds(
    videoWidth: Int, videoHeight: Int,
    viewWidth: Int, viewHeight: Int,
    scaleMode: ScaleMode
): Rect {
    return when (scaleMode) {
        ScaleMode.FIT_SCREEN -> {
            // Calculate letterbox/pillarbox bounds
            val videoRatio = videoWidth.toFloat() / videoHeight
            val viewRatio = viewWidth.toFloat() / viewHeight
            
            if (videoRatio > viewRatio) {
                // Letterbox (black bars top/bottom)
                val scaledHeight = (viewWidth / videoRatio).toInt()
                val offsetY = (viewHeight - scaledHeight) / 2
                Rect(0, offsetY, viewWidth, offsetY + scaledHeight)
            } else {
                // Pillarbox (black bars left/right)
                val scaledWidth = (viewHeight * videoRatio).toInt()
                val offsetX = (viewWidth - scaledWidth) / 2
                Rect(offsetX, 0, offsetX + scaledWidth, viewHeight)
            }
        }
        ScaleMode.FILL -> Rect(0, 0, viewWidth, viewHeight)
        // Add other scale modes as needed
    }
}

Solution 5: External Subtitle Library

Consider using a dedicated subtitle library alongside VLC:

dependencies {
    implementation 'com.github.rubensousa:subtitle-view:1.0.0'
}

// In your activity/fragment
private fun setupExternalSubtitles() {
    val subtitleView = SubtitleView(context)
    
    // Load subtitle file
    val subtitleFile = File("path/to/subtitle.srt")
    subtitleView.setSubtitleFile(subtitleFile)
    
    // Sync with video playback
    mediaPlayer.setTimeChangeListener { time ->
        subtitleView.setCurrentTime(time)
    }
}

Recommendation

I'd suggest implementing Solution 1 (Custom Subtitle Rendering) as it gives you complete control over subtitle positioning and styling, avoiding VLC's limitations entirely. You can extract subtitle timing and text data, then render them in a separate overlay that stays outside the video bounds regardless of scaling mode.

This approach also allows for better subtitle customization (fonts, colors, positioning) and works consistently across different devices and VLC versions

> VLClib limitations. Can’t do much about it. damn that sucks :( i tried asking claude about this, **it gave me these options -** This is a common issue when using VLC library for Android with built-in subtitles in scaled video modes. Here are several solutions you can implement: ## Solution 1: Custom Subtitle Rendering (Recommended) Instead of relying on VLC's built-in subtitle rendering, extract and render subtitles separately: ```kotlin // Disable VLC's built-in subtitle rendering mediaPlayer.setVideoTrackEnabled(false) // for subtitle track // Extract subtitle data private fun extractSubtitles() { val subtitleTrack = mediaPlayer.spuTracks // Parse subtitle data and render externally } // Custom subtitle overlay private fun setupSubtitleOverlay() { val subtitleView = TextView(context).apply { setTextColor(Color.WHITE) setBackgroundColor(Color.parseColor("#80000000")) gravity = Gravity.CENTER textSize = 16f } // Add subtitle view on top of video view val layoutParams = FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT ).apply { gravity = Gravity.BOTTOM bottomMargin = 50 // Adjust as needed } parentLayout.addView(subtitleView, layoutParams) } ``` ## Solution 2: Adjust VLC Subtitle Position Try modifying VLC's subtitle rendering parameters: ```kotlin // Set subtitle position outside the video area mediaPlayer.setVideoSubtitleDelay(0) // Adjust subtitle position - values in percentage // This might work depending on VLC version val options = arrayListOf<String>() options.add("--sub-margin=10") // Margin from bottom options.add("--subsdec-encoding=UTF-8") options.add("--sub-source=file") libVLC = LibVLC(context, options) ``` ## Solution 3: Use TextureView with Custom Layout Switch from SurfaceView to TextureView for better control: ```kotlin class CustomVideoView : FrameLayout { private lateinit var textureView: TextureView private lateinit var subtitleOverlay: TextView private fun setupViews() { // Video texture view textureView = TextureView(context) addView(textureView) // Subtitle overlay positioned outside video bounds subtitleOverlay = TextView(context).apply { setTextColor(Color.WHITE) setBackgroundResource(R.drawable.subtitle_background) } val params = LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT ).apply { gravity = Gravity.BOTTOM } addView(subtitleOverlay, params) } } ``` ## Solution 4: Calculate Video Bounds and Position Subtitles Dynamically calculate the actual video rendering area: ```kotlin private fun positionSubtitles() { val videoWidth = mediaPlayer.videoTrack?.width ?: 0 val videoHeight = mediaPlayer.videoTrack?.height ?: 0 val viewWidth = videoView.width val viewHeight = videoView.height // Calculate actual video bounds based on scale mode val videoBounds = calculateVideoBounds( videoWidth, videoHeight, viewWidth, viewHeight, scaleMode ) // Position subtitle below video area val subtitleY = videoBounds.bottom + 20 subtitleView.y = subtitleY } private fun calculateVideoBounds( videoWidth: Int, videoHeight: Int, viewWidth: Int, viewHeight: Int, scaleMode: ScaleMode ): Rect { return when (scaleMode) { ScaleMode.FIT_SCREEN -> { // Calculate letterbox/pillarbox bounds val videoRatio = videoWidth.toFloat() / videoHeight val viewRatio = viewWidth.toFloat() / viewHeight if (videoRatio > viewRatio) { // Letterbox (black bars top/bottom) val scaledHeight = (viewWidth / videoRatio).toInt() val offsetY = (viewHeight - scaledHeight) / 2 Rect(0, offsetY, viewWidth, offsetY + scaledHeight) } else { // Pillarbox (black bars left/right) val scaledWidth = (viewHeight * videoRatio).toInt() val offsetX = (viewWidth - scaledWidth) / 2 Rect(offsetX, 0, offsetX + scaledWidth, viewHeight) } } ScaleMode.FILL -> Rect(0, 0, viewWidth, viewHeight) // Add other scale modes as needed } } ``` ## Solution 5: External Subtitle Library Consider using a dedicated subtitle library alongside VLC: ```kotlin dependencies { implementation 'com.github.rubensousa:subtitle-view:1.0.0' } // In your activity/fragment private fun setupExternalSubtitles() { val subtitleView = SubtitleView(context) // Load subtitle file val subtitleFile = File("path/to/subtitle.srt") subtitleView.setSubtitleFile(subtitleFile) // Sync with video playback mediaPlayer.setTimeChangeListener { time -> subtitleView.setCurrentTime(time) } } ``` ## Recommendation I'd suggest implementing **Solution 1** (Custom Subtitle Rendering) as it gives you complete control over subtitle positioning and styling, avoiding VLC's limitations entirely. You can extract subtitle timing and text data, then render them in a separate overlay that stays outside the video bounds regardless of scaling mode. This approach also allows for better subtitle customization (fonts, colors, positioning) and works consistently across different devices and VLC versions
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Creepso/NuvioStreaming_backup_24-10-25#140
No description provided.