use heuristic to work around some qsv av desync cases (#2829)

* check for multiple h264 profiles using qsv decoding

* fix build

* update changelog

* pass cancellation token
This commit is contained in:
Jason Dove
2026-02-16 12:37:40 -06:00
committed by GitHub
parent 31b07305ef
commit 3e3bfbd5f5
6 changed files with 106 additions and 3 deletions
@@ -233,6 +233,16 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
scanKind = await ProbeScanKind(ffmpegPath, videoVersion.MediaItem, cancellationToken);
}
HardwareAccelerationMode hwAccel = GetHardwareAccelerationMode(playbackSettings);
// QSV may have sync issues with h264 files that have multiple profiles
// check and flag here so software decoding can be used if needed
bool hasMultipleProfiles = false;
if (hwAccel is HardwareAccelerationMode.Qsv && videoStream.Codec is VideoFormat.H264)
{
hasMultipleProfiles = await ProbeHasMultipleProfiles(ffmpegPath, videoVersion.MediaItem, cancellationToken);
}
var ffmpegVideoStream = new VideoStream(
videoStream.Index,
videoStream.Codec,
@@ -248,7 +258,10 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
videoVersion.MediaVersion.DisplayAspectRatio,
new FrameRate(videoVersion.MediaVersion.RFrameRate),
videoPath != audioPath, // still image when paths are different
scanKind);
scanKind)
{
HasMultipleProfiles = hasMultipleProfiles
};
var videoInputFile = new VideoInputFile(
videoPath,
@@ -405,8 +418,6 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
graphicsElementContexts.AddRange(watermarks.Map(wm => new WatermarkElementContext(wm)));
}
HardwareAccelerationMode hwAccel = GetHardwareAccelerationMode(playbackSettings);
string videoFormat = GetVideoFormat(playbackSettings);
Option<string> maybeVideoProfile = GetVideoProfile(videoFormat, channel.FFmpegProfile.VideoProfile);
Option<string> maybeVideoPreset = GetVideoPreset(
@@ -652,6 +663,19 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
return result;
}
private async Task<bool> ProbeHasMultipleProfiles(
string ffmpegPath,
MediaItem mediaItem,
CancellationToken cancellationToken)
{
_logger.LogDebug("Will probe for h264 profile count");
Option<int> profileCount =
await _localStatisticsProvider.GetProfileCount(ffmpegPath, mediaItem, cancellationToken);
return await profileCount.IfNoneAsync(1) > 1;
}
public async Task<Command> ForError(
string ffmpegPath,
Channel channel,