mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-10-31 02:27:18 -04:00 
			
		
		
		
	Merge pull request #13194 from gnattu/av1-videotoolbox
Enable VideoToolbox AV1 decode
This commit is contained in:
		
						commit
						476a0d6932
					
				| @ -6621,6 +6621,7 @@ namespace MediaBrowser.Controller.MediaEncoding | ||||
|                 || string.Equals("yuv420p12le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase) | ||||
|                 || string.Equals("yuv422p12le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase) | ||||
|                 || string.Equals("yuv444p12le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); | ||||
|             var isAv1SupportedSwFormatsVt = is8_10bitSwFormatsVt || string.Equals("yuv420p12le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); | ||||
| 
 | ||||
|             // The related patches make videotoolbox hardware surface working is only available in jellyfin-ffmpeg 7.0.1 at the moment. | ||||
|             bool useHwSurface = (_mediaEncoder.EncoderVersion >= _minFFmpegWorkingVtHwSurface) && IsVideoToolboxFullSupported(); | ||||
| @ -6654,6 +6655,13 @@ namespace MediaBrowser.Controller.MediaEncoding | ||||
|                 { | ||||
|                     return GetHwaccelType(state, options, "hevc", bitDepth, useHwSurface); | ||||
|                 } | ||||
| 
 | ||||
|                 if (string.Equals("av1", videoStream.Codec, StringComparison.OrdinalIgnoreCase) | ||||
|                     && isAv1SupportedSwFormatsVt | ||||
|                     && _mediaEncoder.IsVideoToolboxAv1DecodeAvailable) | ||||
|                 { | ||||
|                     return GetHwaccelType(state, options, "av1", bitDepth, useHwSurface); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return null; | ||||
|  | ||||
| @ -75,6 +75,12 @@ namespace MediaBrowser.Controller.MediaEncoding | ||||
|         /// <value><c>true</c> if the Vaapi device supports vulkan drm interop, <c>false</c> otherwise.</value> | ||||
|         bool IsVaapiDeviceSupportVulkanDrmInterop { get; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Gets a value indicating whether av1 decoding is available via VideoToolbox. | ||||
|         /// </summary> | ||||
|         /// <value><c>true</c> if the av1 is available via VideoToolbox, <c>false</c> otherwise.</value> | ||||
|         bool IsVideoToolboxAv1DecodeAvailable { get; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Whether given encoder codec is supported. | ||||
|         /// </summary> | ||||
|  | ||||
							
								
								
									
										87
									
								
								MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								MediaBrowser.MediaEncoding/Encoder/ApplePlatformHelper.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | ||||
| #pragma warning disable CA1031 | ||||
| 
 | ||||
| using System; | ||||
| using System.Linq; | ||||
| using System.Runtime.InteropServices; | ||||
| using System.Runtime.Versioning; | ||||
| using Microsoft.Extensions.Logging; | ||||
| 
 | ||||
| namespace MediaBrowser.MediaEncoding.Encoder; | ||||
| 
 | ||||
| /// <summary> | ||||
| /// Helper class for Apple platform specific operations. | ||||
| /// </summary> | ||||
| [SupportedOSPlatform("macos")] | ||||
| public static class ApplePlatformHelper | ||||
| { | ||||
|     private static readonly string[] _av1DecodeBlacklistedCpuClass = ["M1", "M2"]; | ||||
| 
 | ||||
|     private static string GetSysctlValue(ReadOnlySpan<byte> name) | ||||
|     { | ||||
|         IntPtr length = IntPtr.Zero; | ||||
|         // Get length of the value | ||||
|         int osStatus = SysctlByName(name, IntPtr.Zero, ref length, IntPtr.Zero, 0); | ||||
| 
 | ||||
|         if (osStatus != 0) | ||||
|         { | ||||
|             throw new NotSupportedException($"Failed to get sysctl value for {System.Text.Encoding.UTF8.GetString(name)} with error {osStatus}"); | ||||
|         } | ||||
| 
 | ||||
|         IntPtr buffer = Marshal.AllocHGlobal(length.ToInt32()); | ||||
|         try | ||||
|         { | ||||
|             osStatus = SysctlByName(name, buffer, ref length, IntPtr.Zero, 0); | ||||
|             if (osStatus != 0) | ||||
|             { | ||||
|                 throw new NotSupportedException($"Failed to get sysctl value for {System.Text.Encoding.UTF8.GetString(name)} with error {osStatus}"); | ||||
|             } | ||||
| 
 | ||||
|             return Marshal.PtrToStringAnsi(buffer) ?? string.Empty; | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             Marshal.FreeHGlobal(buffer); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static int SysctlByName(ReadOnlySpan<byte> name, IntPtr oldp, ref IntPtr oldlenp, IntPtr newp, uint newlen) | ||||
|     { | ||||
|         return NativeMethods.SysctlByName(name.ToArray(), oldp, ref oldlenp, newp, newlen); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// Check if the current system has hardware acceleration for AV1 decoding. | ||||
|     /// </summary> | ||||
|     /// <param name="logger">The logger used for error logging.</param> | ||||
|     /// <returns>Boolean indicates the hwaccel support.</returns> | ||||
|     public static bool HasAv1HardwareAccel(ILogger logger) | ||||
|     { | ||||
|         if (!RuntimeInformation.OSArchitecture.Equals(Architecture.Arm64)) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         try | ||||
|         { | ||||
|             string cpuBrandString = GetSysctlValue("machdep.cpu.brand_string"u8); | ||||
|             return !_av1DecodeBlacklistedCpuClass.Any(blacklistedCpuClass => cpuBrandString.Contains(blacklistedCpuClass, StringComparison.OrdinalIgnoreCase)); | ||||
|         } | ||||
|         catch (NotSupportedException e) | ||||
|         { | ||||
|             logger.LogError("Error getting CPU brand string: {Message}", e.Message); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             logger.LogError("Unknown error occured: {Exception}", e); | ||||
|         } | ||||
| 
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     private static class NativeMethods | ||||
|     { | ||||
|         [DllImport("libc", EntryPoint = "sysctlbyname", SetLastError = true)] | ||||
|         [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] | ||||
|         internal static extern int SysctlByName(byte[] name, IntPtr oldp, ref IntPtr oldlenp, IntPtr newp, uint newlen); | ||||
|     } | ||||
| } | ||||
| @ -5,6 +5,7 @@ using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Globalization; | ||||
| using System.Linq; | ||||
| using System.Runtime.Versioning; | ||||
| using System.Text.RegularExpressions; | ||||
| using Microsoft.Extensions.Logging; | ||||
| 
 | ||||
| @ -437,6 +438,12 @@ namespace MediaBrowser.MediaEncoding.Encoder | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         [SupportedOSPlatform("macos")] | ||||
|         public bool CheckIsVideoToolboxAv1DecodeAvailable() | ||||
|         { | ||||
|             return ApplePlatformHelper.HasAv1HardwareAccel(_logger); | ||||
|         } | ||||
| 
 | ||||
|         private IEnumerable<string> GetHwaccelTypes() | ||||
|         { | ||||
|             string? output = null; | ||||
|  | ||||
| @ -83,6 +83,8 @@ namespace MediaBrowser.MediaEncoding.Encoder | ||||
|         private bool _isVaapiDeviceSupportVulkanDrmModifier = false; | ||||
|         private bool _isVaapiDeviceSupportVulkanDrmInterop = false; | ||||
| 
 | ||||
|         private bool _isVideoToolboxAv1DecodeAvailable = false; | ||||
| 
 | ||||
|         private static string[] _vulkanImageDrmFmtModifierExts = | ||||
|         { | ||||
|             "VK_EXT_image_drm_format_modifier", | ||||
| @ -159,6 +161,8 @@ namespace MediaBrowser.MediaEncoding.Encoder | ||||
|         /// <inheritdoc /> | ||||
|         public bool IsVaapiDeviceSupportVulkanDrmInterop => _isVaapiDeviceSupportVulkanDrmInterop; | ||||
| 
 | ||||
|         public bool IsVideoToolboxAv1DecodeAvailable => _isVideoToolboxAv1DecodeAvailable; | ||||
| 
 | ||||
|         [GeneratedRegex(@"[^\/\\]+?(\.[^\/\\\n.]+)?$")]
 | ||||
|         private static partial Regex FfprobePathRegex(); | ||||
| 
 | ||||
| @ -261,6 +265,12 @@ namespace MediaBrowser.MediaEncoding.Encoder | ||||
|                         _logger.LogInformation("VAAPI device {RenderNodePath} supports Vulkan DRM interop", options.VaapiDevice); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 // Check if VideoToolbox supports AV1 decode | ||||
|                 if (OperatingSystem.IsMacOS() && SupportsHwaccel("videotoolbox")) | ||||
|                 { | ||||
|                     _isVideoToolboxAv1DecodeAvailable = validator.CheckIsVideoToolboxAv1DecodeAvailable(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             _logger.LogInformation("FFmpeg: {FfmpegPath}", _ffmpegPath ?? string.Empty); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user