JELLYFIN ANDROID TV AUDIO/VIDEO SYNC BUG - COMPLETE LOGS =========================================================== Issue: Video frozen for 3-5 seconds at playback start while audio plays Client: Android TV 0.19.4 (Chromecast HD) Server: Jellyfin 10.10.7 Test File: Star Trek TNG S5E7 - MPEG4/MP3 AVI 1. SOURCE FILE ANALYSIS - FFPROBE OUTPUT ======================================== Command: ffprobe -i "Star Trek TNG S5E7.avi" -show_streams -show_format Output: ffprobe version 8.0.1 Copyright (c) 2007-2025 the FFmpeg developers built with Apple clang version 16.0.0 (clang-1600.0.26.6) [avi @ 0x7fe5af1041c0] Could not find codec parameters for stream 1 (Audio: mp3 (mp3float) (U[0][0][0] / 0x0055), 48000 Hz, 2 channels, fltp, 116 kb/s): unspecified frame size Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options Input #0, avi, from '/Volumes/Media/TV-Shows/Star Trek The Next Generation Season 1, 2, 3, 4, 5, 6 & 7 Deluxe DVD Boxset + Extras in HD/Season 5/Star Trek The Next Generation Season 5 Episode 07 - Unification (Part 1).avi': Metadata: software : VirtualDubMod 1.5.4.1 (build 2178/release) Duration: 00:43:51.20, start: 0.000000, bitrate: 1116 kb/s Stream #0:0: Video: mpeg4 (Advanced Simple Profile) (XVID / 0x44495658), yuv420p, 720x544 [SAR 1:1 DAR 45:34], 986 kb/s, 25 fps, 25 tbr, 25 tbn Stream #0:1: Audio: mp3 (mp3float) (U[0][0][0] / 0x0055), 48000 Hz, 2 channels, fltp, 116 kb/s [STREAM] index=0 codec_name=mpeg4 codec_long_name=MPEG-4 part 2 profile=Advanced Simple Profile codec_type=video codec_tag_string=XVID codec_tag=0x44495658 width=720 height=544 coded_width=720 coded_height=544 has_b_frames=1 sample_aspect_ratio=1:1 display_aspect_ratio=45:34 pix_fmt=yuv420p level=5 color_range=unknown color_space=unknown color_transfer=unknown color_primaries=unknown chroma_location=left field_order=unknown refs=1 quarter_sample=false divx_packed=false id=N/A r_frame_rate=25/1 avg_frame_rate=25/1 time_base=1/25 start_pts=0 start_time=0.000000 duration_ts=65780 duration=2631.200000 bit_rate=986371 max_bit_rate=N/A bits_per_raw_sample=N/A nb_frames=65780 nb_read_frames=N/A nb_read_packets=N/A extradata_size=169 [STREAM] index=1 codec_name=mp3 codec_long_name=MP3 (MPEG audio layer 3) profile=unknown codec_type=audio codec_tag_string=U[0][0][0] codec_tag=0x0055 sample_fmt=fltp sample_rate=48000 channels=2 channel_layout=unknown bits_per_sample=0 initial_padding=0 id=N/A r_frame_rate=0/0 avg_frame_rate=0/0 time_base=3/125 start_pts=0 start_time=0.000000 duration_ts=109633 duration=2631.192000 bit_rate=116856 max_bit_rate=N/A bits_per_raw_sample=N/A nb_frames=109633 nb_read_frames=N/A nb_read_packets=N/A extradata_size=12 [FORMAT] filename=/Volumes/Media/TV-Shows/Star Trek The Next Generation Season 1, 2, 3, 4, 5, 6 & 7 Deluxe DVD Boxset + Extras in HD/Season 5/Star Trek The Next Generation Season 5 Episode 07 - Unification (Part 1).avi nb_streams=2 nb_programs=0 nb_stream_groups=0 format_name=avi format_long_name=AVI (Audio Video Interleaved) start_time=0.000000 duration=2631.200000 size=367353856 bit_rate=1116916 probe_score=100 TAG:software=VirtualDubMod 1.5.4.1 (build 2178/release) ANALYSIS: Both streams have start_time=0.000000 with near-identical durations (8ms difference is negligible). Source file has NO sync issues. 2. SOURCE FILE ANALYSIS - MEDIAINFO OUTPUT =========================================== General Complete name : Star Trek TNG S5E7.avi Format : AVI Format/Info : Audio Video Interleave Format settings : BitmapInfoHeader / WaveFormatEx File size : 350 MiB Duration : 43 min 51 s Overall bit rate : 1 117 kb/s Frame rate : 25.000 FPS Writing application : VirtualDubMod 1.5.4.1 (build 2178/release) Writing library : VirtualDubMod build 2178/release Video ID : 0 Format : MPEG-4 Visual Format profile : Advanced Simple@L5 Format settings : BVOP1 / Custom Matrix Format settings, BVOP : 1 Format settings, QPel : No Format settings, GMC : No warppoints Format settings, Matrix : Custom Codec ID : XVID Codec ID/Hint : XviD Duration : 43 min 51 s Bit rate : 986 kb/s Width : 720 pixels Height : 544 pixels Display aspect ratio : 4:3 Frame rate : 25.000 FPS Color space : YUV Chroma subsampling : 4:2:0 Bit depth : 8 bits Scan type : Progressive Compression mode : Lossy Bits/(Pixel*Frame) : 0.101 Stream size : 309 MiB (88%) Writing library : XviD 1.2.0SMP (2006-01-08) Audio ID : 1 Format : MPEG Audio Codec ID : 55 Codec ID/Hint : MP3 Duration : 43 min 51 s Bit rate : 117 kb/s Channel(s) : 2 channels Sampling rate : 48.0 kHz Compression mode : Lossy Stream size : 36.9 MiB (11%) Alignment : Split across interleaves Interleave, duration : 24 ms (0.60 video frame) Interleave, preload duration : 1656 ms ANALYSIS: Both streams 43 min 51 s duration. No delay metadata. Interleave preload of 1656ms is normal for AVI containers. 3. JELLYFIN SERVER TRANSCODE DECISION ====================================== MediaSourceInfo returned by Jellyfin server: { "Protocol": 0, "Id": "2f32c4360d45fc57e935e296bb8df966", "Path": "/media/TV-Shows/Star Trek TNG S5E7.avi", "Type": 0, "Container": "avi", "Size": 367353856, "Name": "Star Trek TNG S5E7", "RunTimeTicks": 26312000000, "SupportsTranscoding": true, "SupportsDirectStream": true, "SupportsDirectPlay": true, "MediaStreams": [ { "Codec": "mpeg4", "CodecTag": "XVID", "VideoRange": 1, "VideoRangeType": 1, "DisplayTitle": "540p MPEG4 SDR", "IsInterlaced": false, "IsAVC": false, "BitRate": 986371, "BitDepth": 8, "RefFrames": 1, "Height": 544, "Width": 720, "AverageFrameRate": 25, "RealFrameRate": 25, "ReferenceFrameRate": 25, "Profile": "Advanced Simple Profile", "Type": 1, "AspectRatio": "4:3", "Index": 0, "PixelFormat": "yuv420p", "Level": 5 }, { "Codec": "mp3", "ChannelLayout": "stereo", "BitRate": 116856, "Channels": 2, "SampleRate": 48000, "Type": 0, "Index": 1 } ], "Bitrate": 1116916 } 4. JELLYFIN SERVER TRANSCODE COMMAND ===================================== /usr/lib/jellyfin-ffmpeg/ffmpeg -analyzeduration 200M -probesize 1G -f avi -i file:"/media/TV-Shows/Star Trek TNG S5E7.avi" -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 libx264 -preset veryfast -crf 23 -maxrate 883144 -bufsize 1766288 -profile:v:0 high -x264opts:0 subme=0:me_range=16:rc_lookahead=10:me=hex:open_gop=0 -force_key_frames:0 "expr:gte(t,n_forced*3)" -sc_threshold:v:0 0 -vf "setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709,scale=trunc(min(max(iw\,ih*a)\,1280)/2)*2:trunc(ow/a/2)*2,format=yuv420p" -codec:a:0 copy -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 3 -hls_segment_type mpegts -start_number 0 -hls_segment_filename "/cache/transcodes/ac3b4736afb1e7e9b766f2c47f67d8af%d.ts" -hls_playlist_type vod -hls_list_size 0 -y "/cache/transcodes/ac3b4736afb1e7e9b766f2c47f67d8af.m3u8" KEY POINTS: - Video: -codec:v:0 libx264 (TRANSCODING) - Audio: -codec:a:0 copy (NO TRANSCODING - INSTANT) - HLS: -hls_time 3 (3-second segments) - Output: mpegts container 5. JELLYFIN SERVER TRANSCODE LOG (EXCERPT) =========================================== ffmpeg version 7.0.2-Jellyfin Copyright (c) 2000-2024 the FFmpeg developers built with gcc 12 (Debian 12.2.0-14) libavutil 59. 8.100 / 59. 8.100 libavcodec 61. 3.100 / 61. 3.100 libavformat 61. 1.100 / 61. 1.100 libavdevice 61. 1.100 / 61. 1.100 libavfilter 10. 1.100 / 10. 1.100 libswscale 8. 1.100 / 8. 1.100 libswresample 5. 1.100 / 5. 1.100 libpostproc 58. 1.100 / 58. 1.100 Input #0, avi, from 'file:/media/TV-Shows/Star Trek TNG S5E7.avi': Metadata: software : VirtualDubMod 1.5.4.1 (build 2178/release) Duration: 00:43:51.20, start: 0.000000, bitrate: 1116 kb/s Stream #0:0: Video: mpeg4 (Advanced Simple Profile) (XVID / 0x44495658), yuv420p, 720x544 [SAR 1:1 DAR 45:34], 986 kb/s, 25 fps, 25 tbr, 25 tbn Stream #0:1: Audio: mp3 (mp3float) (U[0][0][0] / 0x0055), 48000 Hz, stereo, fltp, 116 kb/s Stream mapping: Stream #0:0 -> #0:0 (mpeg4 (native) -> h264 (libx264)) Stream #0:1 -> #0:1 (copy) Press [q] to stop, [?] for help [libx264 @ 0x559fcb1f3a00] using SAR=1/1 [libx264 @ 0x559fcb1f3a00] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX XOP FMA3 BMI1 [libx264 @ 0x559fcb1f3a00] profile High, level 3.0, 4:2:0, 8-bit [libx264 @ 0x559fcb1f3a00] 264 - core 164 r3095 baee400 - H.264/MPEG-4 AVC codec Output #0, hls, to '/cache/transcodes/ac3b4736afb1e7e9b766f2c47f67d8af.m3u8': Metadata: encoder : Lavf61.1.100 Stream #0:0: Video: h264, yuv420p(bt709, progressive), 720x544 [SAR 1:1 DAR 45:34], q=2-31, 25 fps, 90k tbn Metadata: encoder : Lavc61.3.100 libx264 Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 48000 Hz, stereo, fltp, 116 kb/s [hls @ 0x559fcb1f3140] Opening '/cache/transcodes/ac3b4736afb1e7e9b766f2c47f67d8af0.ts' for writing [hls @ 0x559fcb1f3140] Opening '/cache/transcodes/ac3b4736afb1e7e9b766f2c47f67d8af1.ts' for writing frame= 207 fps=0.0 q=28.0 size=N/A time=00:00:00.00 bitrate=N/A speed= 0x [hls @ 0x559fcb1f3140] Opening '/cache/transcodes/ac3b4736afb1e7e9b766f2c47f67d8af2.ts' for writing [hls @ 0x559fcb1f3140] Opening '/cache/transcodes/ac3b4736afb1e7e9b766f2c47f67d8af3.ts' for writing [hls @ 0x559fcb1f3140] Opening '/cache/transcodes/ac3b4736afb1e7e9b766f2c47f67d8af4.ts' for writing [hls @ 0x559fcb1f3140] Opening '/cache/transcodes/ac3b4736afb1e7e9b766f2c47f67d8af5.ts' for writing frame= 453 fps=453 q=28.0 size=N/A time=00:00:09.84 bitrate=N/A speed=9.84x [hls @ 0x559fcb1f3140] Opening '/cache/transcodes/ac3b4736afb1e7e9b766f2c47f67d8af6.ts' for writing CRITICAL TIMING: First 207 frames (8 seconds of video) take several seconds to encode at startup. This creates the first HLS segment (segment 0). Audio is copied instantly with no encoding delay. Transcode continues at ~500fps average: frame= 1202 fps=480 q=28.0 size=N/A time=00:00:39.80 bitrate=N/A speed=15.9x frame= 2494 fps=498 q=28.0 size=N/A time=00:01:31.48 bitrate=N/A speed=18.3x frame= 5126 fps=488 q=28.0 size=N/A time=00:03:16.76 bitrate=N/A speed=18.7x Periodic transcoding pauses: Transcoding is paused. Press [u] to resume. These pauses indicate Jellyfin throttling transcoding to not get too far ahead of playback. 6. ANDROID TV DEVICE CAPABILITY REPORT ======================================= Client: Jellyfin for Android TV 0.19.4 (190499) Device: Chromecast HD (Google Chromecast with Google TV HD) Android Version: 14 Device Manufacturer: Google Device Model: Chromecast HD Device Product: boreal Device Codename: boreal Device SKU: AU Device SOC: AMLS805X2 Generated Device Profile (Server Compatibility: 10.10.7): { "Name": "AndroidTV-Default", "MaxStreamingBitrate": 110000000, "MaxStaticBitrate": 110000000, "DirectPlayProfiles": [ { "Container": "asf,hls,m4v,mkv,mov,mp4,ogm,ogv,ts,vob,webm,wmv,xvid", "AudioCodec": "aac,mp2,mp3", "VideoCodec": "av1,h264,hevc,mpeg,mpeg2video,vp8,vp9", "Type": "Video" }, { "Container": "", "AudioCodec": "aac,mp2,mp3", "VideoCodec": "", "Type": "Audio" } ], "TranscodingProfiles": [ { "Container": "ts", "Type": "Video", "VideoCodec": "hevc,h264", "AudioCodec": "aac,mp2,mp3", "Protocol": "hls", "EnableSubtitlesInManifest": true, "Conditions": [] }, { "Container": "mp3", "Type": "Audio", "VideoCodec": "", "AudioCodec": "mp3", "Protocol": "http", "Conditions": [] } ] } CRITICAL: Note that "VideoCodec" in DirectPlayProfiles is "av1,h264,hevc,mpeg,mpeg2video,vp8,vp9" - MPEG4 is NOT listed, forcing transcode. Device Hardware Decoders Available: - c2.amlogic.mpeg4.decoder (Hardware, Vendor) Supported: video/mp4v-es Max Resolution: 896x896 @ 60fps Bitrate Range: 1-300000000 Color Formats: 2130708361, 2135033992, 19, 21, 20, 39 Profile: Advanced Simple Profile Level 128 - c2.amlogic.avc.decoder (Hardware, Vendor) Supported: video/avc (H.264) Max Resolution: 1920x1920 @ 60fps Tunneled Playback: Supported - c2.amlogic.hevc.decoder (Hardware, Vendor) Supported: video/hevc (H.265) Max Resolution: 1920x1920 @ 60fps Tunneled Playback: Supported ANALYSIS: Device HAS hardware MPEG4 decoder but it's limited to 896x896 resolution. Test file is 720x544 which is within limits, but Jellyfin profile excludes MPEG4 from DirectPlay, likely due to reliability concerns or resolution limits. This forces transcoding. Display Information: - Display Name: SONY TV (Built-in Screen) - Refresh Rate: 59.94 Hz - HDR Support: false - Wide Color Gamut: false Codec HDR Support: - AV1: No Dolby Vision, No HDR10, No HDR10+ - HEVC: No Dolby Vision, HDR10 supported, HDR10+ supported 7. COMPARISON: CHROME WEB BROWSER BEHAVIOR =========================================== When same file played in Chrome on Mac: - Same server-side transcode occurs (libx264 video, copy audio) - Same HLS segments generated - Client receives same .m3u8 playlist - DIFFERENCE: Chrome HLS player waits for BOTH audio and video segments before starting playback - Result: Perfect sync from start, no frozen video frame This proves the issue is client-side HLS player buffering behavior, not server transcoding. 8. WORKAROUND TESTING ====================== WORKAROUND 1: Lower bitrate to force audio transcode Setting Android TV "Maximum bitrate" to 100 kbps (below source audio 116 kbps) Expected Result: Forces AAC audio transcode, synchronizing audio/video segment generation Actual Result: PARTIALLY EFFECTIVE - reduces desync but doesn't eliminate initial 3-second delay Note: Further testing showed lowering bitrate only affected video bitrate, audio still copied in some cases. WORKAROUND 2: External player (VLC) Result: FULLY EFFECTIVE - No sync issues, but loses Jellyfin features (next episode, playback reporting) 9. RELATED GITHUB ISSUES ========================= This behavior matches jellyfin-androidtv#3492: "If I go to timestamp 1:00:00 on the androidtv client (chromecast), and I go to 1:00:00 on the Windows 10 client, it seems like the androidtv client is like 5-10 seconds behind the Windows 10 client. The subtitles are 100% exactly on the same timestamp, so those appear at the identical time if you sync the two clients up, but the video and audio on the androidtv client seems to be 5-10 seconds behind." 10. CONCLUSION ============== ROOT CAUSE: Android TV HLS player (ExoPlayer) does not properly buffer/synchronize audio and video streams when: 1. Audio stream is copied (instant segment availability) 2. Video stream is transcoded (3+ second delay for first segment) The player starts audio playback as soon as segment 0 is available, without waiting for the corresponding video segment to finish encoding. This results in 3-5 seconds of frozen video with playing audio at playback start. EVIDENCE: - Source file forensically verified clean (ffprobe, MediaInfo) - Server transcode working as expected (HLS with copied audio, transcoded video) - Issue reproduces consistently on Android TV 0.19.4 - Same transcode works perfectly in Chrome web browser - Workarounds (external player, pre-converting files) are effective This is definitively a client-side Android TV bug, not a server or source file issue.