From 6406cb5abe1f1f0c0ff25541742eb2110598af76 Mon Sep 17 00:00:00 2001 From: Daniel Sass Date: Fri, 12 Jun 2026 22:21:25 +0700 Subject: [PATCH 1/5] Added support for adding [System.Flags] before enums that look like they are flags. --- .../Generation/EnumsGenerator.cs | 9 ++++++- .../Processing/EnumerationProcessor.cs | 25 ++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Generation/EnumsGenerator.cs b/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Generation/EnumsGenerator.cs index 08590874..c7f85a8b 100644 --- a/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Generation/EnumsGenerator.cs +++ b/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Generation/EnumsGenerator.cs @@ -1,4 +1,5 @@ -using FFmpeg.AutoGen.CppSharpUnsafeGenerator.Definitions; +using System.Linq; +using FFmpeg.AutoGen.CppSharpUnsafeGenerator.Definitions; namespace FFmpeg.AutoGen.CppSharpUnsafeGenerator.Generation; @@ -18,6 +19,12 @@ protected override void GenerateDefinition(EnumerationDefinition @enum) { this.WriteSummary(@enum); this.WriteObsoletion(@enum); + + // if every item in the enum is in the form 1 << n, then we will treat it + // as a flags enum + if (@enum.Items.All(test => test.Value.Contains("<<"))) + WriteLine("[System.Flags]"); + WriteLine($"public enum {@enum.Name} : {@enum.TypeName}"); using (BeginBlock()) diff --git a/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Processing/EnumerationProcessor.cs b/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Processing/EnumerationProcessor.cs index 315a70a6..1bce6c24 100644 --- a/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Processing/EnumerationProcessor.cs +++ b/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Processing/EnumerationProcessor.cs @@ -1,12 +1,13 @@ using System; using System.Linq; +using System.Text.RegularExpressions; using CppSharp.AST; using CppSharp.AST.Extensions; using FFmpeg.AutoGen.CppSharpUnsafeGenerator.Definitions; namespace FFmpeg.AutoGen.CppSharpUnsafeGenerator.Processing; -internal class EnumerationProcessor +internal partial class EnumerationProcessor { private readonly ProcessingContext _context; @@ -81,7 +82,7 @@ public void MakeDefinition(Enumeration enumeration, string name) new EnumerationItem { Name = x.Name, - Value = ConvertValue(x.Value, enumeration.BuiltinType.Type).ToString(), + Value = ConvertValue(x.Expression, x.Value, enumeration.BuiltinType.Type).ToString(), Content = x.Comment?.BriefText }) .ToArray() @@ -90,9 +91,24 @@ public void MakeDefinition(Enumeration enumeration, string name) _context.AddDefinition(definition); } - private static object ConvertValue(ulong value, PrimitiveType primitiveType) + // A regular expression that looks if the expression ends in "= 1 << n" (with any + // number of spaces between the elements. + [GeneratedRegex(@"=\s*1\s*<<\s*(\d+)\s*$")] + private static partial Regex CheckForBitExpression(); + + private static string ConvertValue(string expression, ulong value, PrimitiveType primitiveType) { - return primitiveType switch + // Check if the expression is of the form 1 << n. If it is, preserve the original definition + // instead of collapsing the value. + if (CheckForBitExpression().Match(expression) is { Success: true } match) + { + // Keep it as a 1 << n in the output. We will always + // return it in the form "1 << n" with that exact spacing. + return $"1 << {match.Groups[1].Value}"; + } + + // Otherwise, fallback on using the compiler's value + object compilerValue = primitiveType switch { PrimitiveType.Int => value > int.MaxValue ? (int)value : value, PrimitiveType.UInt => value, @@ -100,5 +116,6 @@ private static object ConvertValue(ulong value, PrimitiveType primitiveType) PrimitiveType.ULong => value, _ => throw new NotSupportedException() }; + return compilerValue.ToString(); } } From 57b948638a1d4a6c777ea92754d171cfe1370a09 Mon Sep 17 00:00:00 2001 From: Daniel Sass Date: Fri, 12 Jun 2026 22:11:25 +0700 Subject: [PATCH 2/5] Updated generated enums. --- .../generated/Enums.g.cs | 60 ++++++++++--------- FFmpeg.AutoGen/generated/Enums.g.cs | 60 ++++++++++--------- 2 files changed, 64 insertions(+), 56 deletions(-) diff --git a/FFmpeg.AutoGen.Abstractions/generated/Enums.g.cs b/FFmpeg.AutoGen.Abstractions/generated/Enums.g.cs index 4135fd8f..d2868eca 100644 --- a/FFmpeg.AutoGen.Abstractions/generated/Enums.g.cs +++ b/FFmpeg.AutoGen.Abstractions/generated/Enums.g.cs @@ -1051,10 +1051,11 @@ public enum AVFormatCommandID : int } /// Flags for frame cropping. +[System.Flags] public enum AvFrameCrop : int { /// Apply the maximum possible cropping, even if it requires setting the AVFrame.data[] entries to unaligned pointers. Passing unaligned data to FFmpeg API is generally not allowed, and causes undefined behavior (such as crashes). You can pass unaligned data only to FFmpeg APIs that are explicitly documented to accept it. Use this flag only if you absolutely know what you are doing. - @AV_FRAME_CROP_UNALIGNED = 1, + @AV_FRAME_CROP_UNALIGNED = 1 << 0, } /// @{ AVFrame is an abstraction for reference-counted raw multimedia data. @@ -1153,16 +1154,17 @@ public enum AVHWDeviceType : int } /// Flags to apply to frame mappings. +[System.Flags] public enum AvHwframeMap : int { /// The mapping must be readable. - @AV_HWFRAME_MAP_READ = 1, + @AV_HWFRAME_MAP_READ = 1 << 0, /// The mapping must be writeable. - @AV_HWFRAME_MAP_WRITE = 2, + @AV_HWFRAME_MAP_WRITE = 1 << 1, /// The mapped frame will be overwritten completely in subsequent operations, so the current frame data need not be loaded. Any values which are not overwritten are unspecified. - @AV_HWFRAME_MAP_OVERWRITE = 4, + @AV_HWFRAME_MAP_OVERWRITE = 1 << 2, /// The mapping must be direct. That is, there must not be any copying in the map or unmap steps. Note that performance of direct mappings may be much lower than normal memory. - @AV_HWFRAME_MAP_DIRECT = 8, + @AV_HWFRAME_MAP_DIRECT = 1 << 3, } public enum AVHWFrameTransferDirection : int @@ -2069,14 +2071,15 @@ public enum AVTimebaseSource : int @AVFMT_TBCF_R_FRAMERATE = 2, } +[System.Flags] public enum AVTimecodeFlag : int { /// timecode is drop frame - @AV_TIMECODE_FLAG_DROPFRAME = 1, + @AV_TIMECODE_FLAG_DROPFRAME = 1 << 0, /// timecode wraps after 24 hours - @AV_TIMECODE_FLAG_24HOURSMAX = 2, + @AV_TIMECODE_FLAG_24HOURSMAX = 1 << 1, /// negative time values are allowed - @AV_TIMECODE_FLAG_ALLOWNEGATIVE = 4, + @AV_TIMECODE_FLAG_ALLOWNEGATIVE = 1 << 2, } /// Dithering algorithms @@ -2143,48 +2146,49 @@ public enum SwsDither : int @SWS_DITHER_MAX_ENUM = 2147483647, } +[System.Flags] public enum SwsFlags : int { /// fast bilinear filtering - @SWS_FAST_BILINEAR = 1, + @SWS_FAST_BILINEAR = 1 << 0, /// bilinear filtering - @SWS_BILINEAR = 2, + @SWS_BILINEAR = 1 << 1, /// 2-tap cubic B-spline - @SWS_BICUBIC = 4, + @SWS_BICUBIC = 1 << 2, /// experimental - @SWS_X = 8, + @SWS_X = 1 << 3, /// nearest neighbor - @SWS_POINT = 16, + @SWS_POINT = 1 << 4, /// area averaging - @SWS_AREA = 32, + @SWS_AREA = 1 << 5, /// bicubic luma, bilinear chroma - @SWS_BICUBLIN = 64, + @SWS_BICUBLIN = 1 << 6, /// gaussian approximation - @SWS_GAUSS = 128, + @SWS_GAUSS = 1 << 7, /// unwindowed sinc - @SWS_SINC = 256, + @SWS_SINC = 1 << 8, /// 3-tap sinc/sinc - @SWS_LANCZOS = 512, + @SWS_LANCZOS = 1 << 9, /// cubic Keys spline - @SWS_SPLINE = 1024, + @SWS_SPLINE = 1 << 10, /// Return an error on underspecified conversions. Without this flag, unspecified fields are defaulted to sensible values. - @SWS_STRICT = 2048, + @SWS_STRICT = 1 << 11, /// Emit verbose log of scaling parameters. - @SWS_PRINT_INFO = 4096, + @SWS_PRINT_INFO = 1 << 12, /// Perform full chroma upsampling when upscaling to RGB. - @SWS_FULL_CHR_H_INT = 8192, + @SWS_FULL_CHR_H_INT = 1 << 13, /// Perform full chroma interpolation when downscaling RGB sources. - @SWS_FULL_CHR_H_INP = 16384, + @SWS_FULL_CHR_H_INP = 1 << 14, /// Force bit-exact output. This will prevent the use of platform-specific optimizations that may lead to slight difference in rounding, in favor of always maintaining exact bit output compatibility with the reference C code. - @SWS_ACCURATE_RND = 262144, + @SWS_ACCURATE_RND = 1 << 18, /// Force bit-exact output. This will prevent the use of platform-specific optimizations that may lead to slight difference in rounding, in favor of always maintaining exact bit output compatibility with the reference C code. - @SWS_BITEXACT = 524288, + @SWS_BITEXACT = 1 << 19, /// Allow using experimental new code paths. This may be faster, slower, or produce different output, with semantics subject to change at any point in time. For testing and debugging purposes only. - @SWS_UNSTABLE = 1048576, + @SWS_UNSTABLE = 1 << 20, /// This flag has no effect - @SWS_DIRECT_BGR = 32768, + @SWS_DIRECT_BGR = 1 << 15, /// Set `SwsContext.dither` instead - @SWS_ERROR_DIFFUSION = 8388608, + @SWS_ERROR_DIFFUSION = 1 << 23, } public enum SwsIntent : int diff --git a/FFmpeg.AutoGen/generated/Enums.g.cs b/FFmpeg.AutoGen/generated/Enums.g.cs index 55259abd..1bb2476a 100644 --- a/FFmpeg.AutoGen/generated/Enums.g.cs +++ b/FFmpeg.AutoGen/generated/Enums.g.cs @@ -1051,10 +1051,11 @@ public enum AVFormatCommandID : int } /// Flags for frame cropping. +[System.Flags] public enum AvFrameCrop : int { /// Apply the maximum possible cropping, even if it requires setting the AVFrame.data[] entries to unaligned pointers. Passing unaligned data to FFmpeg API is generally not allowed, and causes undefined behavior (such as crashes). You can pass unaligned data only to FFmpeg APIs that are explicitly documented to accept it. Use this flag only if you absolutely know what you are doing. - @AV_FRAME_CROP_UNALIGNED = 1, + @AV_FRAME_CROP_UNALIGNED = 1 << 0, } /// @{ AVFrame is an abstraction for reference-counted raw multimedia data. @@ -1153,16 +1154,17 @@ public enum AVHWDeviceType : int } /// Flags to apply to frame mappings. +[System.Flags] public enum AvHwframeMap : int { /// The mapping must be readable. - @AV_HWFRAME_MAP_READ = 1, + @AV_HWFRAME_MAP_READ = 1 << 0, /// The mapping must be writeable. - @AV_HWFRAME_MAP_WRITE = 2, + @AV_HWFRAME_MAP_WRITE = 1 << 1, /// The mapped frame will be overwritten completely in subsequent operations, so the current frame data need not be loaded. Any values which are not overwritten are unspecified. - @AV_HWFRAME_MAP_OVERWRITE = 4, + @AV_HWFRAME_MAP_OVERWRITE = 1 << 2, /// The mapping must be direct. That is, there must not be any copying in the map or unmap steps. Note that performance of direct mappings may be much lower than normal memory. - @AV_HWFRAME_MAP_DIRECT = 8, + @AV_HWFRAME_MAP_DIRECT = 1 << 3, } public enum AVHWFrameTransferDirection : int @@ -2069,14 +2071,15 @@ public enum AVTimebaseSource : int @AVFMT_TBCF_R_FRAMERATE = 2, } +[System.Flags] public enum AVTimecodeFlag : int { /// timecode is drop frame - @AV_TIMECODE_FLAG_DROPFRAME = 1, + @AV_TIMECODE_FLAG_DROPFRAME = 1 << 0, /// timecode wraps after 24 hours - @AV_TIMECODE_FLAG_24HOURSMAX = 2, + @AV_TIMECODE_FLAG_24HOURSMAX = 1 << 1, /// negative time values are allowed - @AV_TIMECODE_FLAG_ALLOWNEGATIVE = 4, + @AV_TIMECODE_FLAG_ALLOWNEGATIVE = 1 << 2, } /// Dithering algorithms @@ -2143,48 +2146,49 @@ public enum SwsDither : int @SWS_DITHER_MAX_ENUM = 2147483647, } +[System.Flags] public enum SwsFlags : int { /// fast bilinear filtering - @SWS_FAST_BILINEAR = 1, + @SWS_FAST_BILINEAR = 1 << 0, /// bilinear filtering - @SWS_BILINEAR = 2, + @SWS_BILINEAR = 1 << 1, /// 2-tap cubic B-spline - @SWS_BICUBIC = 4, + @SWS_BICUBIC = 1 << 2, /// experimental - @SWS_X = 8, + @SWS_X = 1 << 3, /// nearest neighbor - @SWS_POINT = 16, + @SWS_POINT = 1 << 4, /// area averaging - @SWS_AREA = 32, + @SWS_AREA = 1 << 5, /// bicubic luma, bilinear chroma - @SWS_BICUBLIN = 64, + @SWS_BICUBLIN = 1 << 6, /// gaussian approximation - @SWS_GAUSS = 128, + @SWS_GAUSS = 1 << 7, /// unwindowed sinc - @SWS_SINC = 256, + @SWS_SINC = 1 << 8, /// 3-tap sinc/sinc - @SWS_LANCZOS = 512, + @SWS_LANCZOS = 1 << 9, /// cubic Keys spline - @SWS_SPLINE = 1024, + @SWS_SPLINE = 1 << 10, /// Return an error on underspecified conversions. Without this flag, unspecified fields are defaulted to sensible values. - @SWS_STRICT = 2048, + @SWS_STRICT = 1 << 11, /// Emit verbose log of scaling parameters. - @SWS_PRINT_INFO = 4096, + @SWS_PRINT_INFO = 1 << 12, /// Perform full chroma upsampling when upscaling to RGB. - @SWS_FULL_CHR_H_INT = 8192, + @SWS_FULL_CHR_H_INT = 1 << 13, /// Perform full chroma interpolation when downscaling RGB sources. - @SWS_FULL_CHR_H_INP = 16384, + @SWS_FULL_CHR_H_INP = 1 << 14, /// Force bit-exact output. This will prevent the use of platform-specific optimizations that may lead to slight difference in rounding, in favor of always maintaining exact bit output compatibility with the reference C code. - @SWS_ACCURATE_RND = 262144, + @SWS_ACCURATE_RND = 1 << 18, /// Force bit-exact output. This will prevent the use of platform-specific optimizations that may lead to slight difference in rounding, in favor of always maintaining exact bit output compatibility with the reference C code. - @SWS_BITEXACT = 524288, + @SWS_BITEXACT = 1 << 19, /// Allow using experimental new code paths. This may be faster, slower, or produce different output, with semantics subject to change at any point in time. For testing and debugging purposes only. - @SWS_UNSTABLE = 1048576, + @SWS_UNSTABLE = 1 << 20, /// This flag has no effect - @SWS_DIRECT_BGR = 32768, + @SWS_DIRECT_BGR = 1 << 15, /// Set `SwsContext.dither` instead - @SWS_ERROR_DIFFUSION = 8388608, + @SWS_ERROR_DIFFUSION = 1 << 23, } public enum SwsIntent : int From 108c5bc3bd9b9334c5b61a29d226fa469c48e4b4 Mon Sep 17 00:00:00 2001 From: Daniel Sass Date: Fri, 12 Jun 2026 22:29:05 +0700 Subject: [PATCH 3/5] Properly handle non-integer enums. There doesn't seem to be any, but just in case they come up in the future. --- .../Processing/EnumerationProcessor.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Processing/EnumerationProcessor.cs b/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Processing/EnumerationProcessor.cs index 1bce6c24..c9754e46 100644 --- a/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Processing/EnumerationProcessor.cs +++ b/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Processing/EnumerationProcessor.cs @@ -104,7 +104,16 @@ private static string ConvertValue(string expression, ulong value, PrimitiveType { // Keep it as a 1 << n in the output. We will always // return it in the form "1 << n" with that exact spacing. - return $"1 << {match.Groups[1].Value}"; + var suffix = primitiveType switch + { + PrimitiveType.Int => "", + PrimitiveType.UInt => "u", + PrimitiveType.Long => "l", + PrimitiveType.ULong => "ul", + _ => throw new NotSupportedException() + }; + + return $"1{suffix} << {match.Groups[1].Value}"; } // Otherwise, fallback on using the compiler's value From e5d7247ae387fa12acee8fcbf1d3f72aa24f0595 Mon Sep 17 00:00:00 2001 From: Daniel Sass Date: Sat, 13 Jun 2026 01:02:44 +0700 Subject: [PATCH 4/5] Override Usings() to inject using System and use [Flags] instead of [System.Flags] --- .../Generation/EnumsGenerator.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Generation/EnumsGenerator.cs b/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Generation/EnumsGenerator.cs index c7f85a8b..d6f8722b 100644 --- a/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Generation/EnumsGenerator.cs +++ b/FFmpeg.AutoGen.CppSharpUnsafeGenerator/Generation/EnumsGenerator.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using FFmpeg.AutoGen.CppSharpUnsafeGenerator.Definitions; namespace FFmpeg.AutoGen.CppSharpUnsafeGenerator.Generation; @@ -9,6 +10,11 @@ public EnumsGenerator(string path, GenerationContext context) : base(path, conte { } + public override IEnumerable Usings() + { + yield return "System"; + } + public static void Generate(string path, GenerationContext context) { using var g = new EnumsGenerator(path, context); @@ -23,7 +29,7 @@ protected override void GenerateDefinition(EnumerationDefinition @enum) // if every item in the enum is in the form 1 << n, then we will treat it // as a flags enum if (@enum.Items.All(test => test.Value.Contains("<<"))) - WriteLine("[System.Flags]"); + WriteLine("[Flags]"); WriteLine($"public enum {@enum.Name} : {@enum.TypeName}"); From e3ef0ff9e30336663619bff215db146f3f5f5fff Mon Sep 17 00:00:00 2001 From: Daniel Sass Date: Sat, 13 Jun 2026 01:02:56 +0700 Subject: [PATCH 5/5] Updated generated enums. --- FFmpeg.AutoGen.Abstractions/generated/Enums.g.cs | 10 ++++++---- FFmpeg.AutoGen/generated/Enums.g.cs | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/FFmpeg.AutoGen.Abstractions/generated/Enums.g.cs b/FFmpeg.AutoGen.Abstractions/generated/Enums.g.cs index d2868eca..c273265d 100644 --- a/FFmpeg.AutoGen.Abstractions/generated/Enums.g.cs +++ b/FFmpeg.AutoGen.Abstractions/generated/Enums.g.cs @@ -1,3 +1,5 @@ +using System; + namespace FFmpeg.AutoGen.Abstractions; public enum AVActiveFormatDescription : int @@ -1051,7 +1053,7 @@ public enum AVFormatCommandID : int } /// Flags for frame cropping. -[System.Flags] +[Flags] public enum AvFrameCrop : int { /// Apply the maximum possible cropping, even if it requires setting the AVFrame.data[] entries to unaligned pointers. Passing unaligned data to FFmpeg API is generally not allowed, and causes undefined behavior (such as crashes). You can pass unaligned data only to FFmpeg APIs that are explicitly documented to accept it. Use this flag only if you absolutely know what you are doing. @@ -1154,7 +1156,7 @@ public enum AVHWDeviceType : int } /// Flags to apply to frame mappings. -[System.Flags] +[Flags] public enum AvHwframeMap : int { /// The mapping must be readable. @@ -2071,7 +2073,7 @@ public enum AVTimebaseSource : int @AVFMT_TBCF_R_FRAMERATE = 2, } -[System.Flags] +[Flags] public enum AVTimecodeFlag : int { /// timecode is drop frame @@ -2146,7 +2148,7 @@ public enum SwsDither : int @SWS_DITHER_MAX_ENUM = 2147483647, } -[System.Flags] +[Flags] public enum SwsFlags : int { /// fast bilinear filtering diff --git a/FFmpeg.AutoGen/generated/Enums.g.cs b/FFmpeg.AutoGen/generated/Enums.g.cs index 1bb2476a..962b59c6 100644 --- a/FFmpeg.AutoGen/generated/Enums.g.cs +++ b/FFmpeg.AutoGen/generated/Enums.g.cs @@ -1,3 +1,5 @@ +using System; + namespace FFmpeg.AutoGen; public enum AVActiveFormatDescription : int @@ -1051,7 +1053,7 @@ public enum AVFormatCommandID : int } /// Flags for frame cropping. -[System.Flags] +[Flags] public enum AvFrameCrop : int { /// Apply the maximum possible cropping, even if it requires setting the AVFrame.data[] entries to unaligned pointers. Passing unaligned data to FFmpeg API is generally not allowed, and causes undefined behavior (such as crashes). You can pass unaligned data only to FFmpeg APIs that are explicitly documented to accept it. Use this flag only if you absolutely know what you are doing. @@ -1154,7 +1156,7 @@ public enum AVHWDeviceType : int } /// Flags to apply to frame mappings. -[System.Flags] +[Flags] public enum AvHwframeMap : int { /// The mapping must be readable. @@ -2071,7 +2073,7 @@ public enum AVTimebaseSource : int @AVFMT_TBCF_R_FRAMERATE = 2, } -[System.Flags] +[Flags] public enum AVTimecodeFlag : int { /// timecode is drop frame @@ -2146,7 +2148,7 @@ public enum SwsDither : int @SWS_DITHER_MAX_ENUM = 2147483647, } -[System.Flags] +[Flags] public enum SwsFlags : int { /// fast bilinear filtering