How to Read Meta-Tags of a MP4-File?

CodeGuy85 0 Reputation points
2024-10-15T06:50:30.5766667+00:00

In Windows 11 you can modify Meta-Tags of MP4-Files. Are there libraries for .net core 8 web api available which are able to modify these? Is there a posibility to do that over API-Calls?

I already get to know to the library taglib but this one seems not cover alle my needs, I also can't read out the Subtitle.

.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,873 questions
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,568 questions
Windows 11
Windows 11
A Microsoft operating system designed for productivity, creativity, and ease of use.
9,709 questions
{count} votes

Accepted answer
  1. Castorix31 85,451 Reputation points
    2024-10-15T08:24:05.35+00:00

    With Win32 API/Intefaces, it is done with IPropertyStore

    Test reading/writing Subtitle on a random .mp4 :

    {
        string sFileName = @"E:\Phone265.mp4";
        IPropertyStore pPropertyStore = null;
        Guid PropertyStoreGuid = typeof(IPropertyStore).GUID;
        HRESULT hr = SHGetPropertyStoreFromParsingName(sFileName, IntPtr.Zero, GETPROPERTYSTOREFLAGS.GPS_READWRITE, ref PropertyStoreGuid, out pPropertyStore);
        if (hr == HRESULT.S_OK)
        {
            var pv = new PROPVARIANT();
            hr = pPropertyStore.GetValue(PKEY_Title, out pv);
            if (hr == HRESULT.S_OK)
            {
                string sTitle = Marshal.PtrToStringUni(pv.pwszVal);
                Console.WriteLine("Original Title : {0}", sTitle);
            }
            hr = pPropertyStore.GetValue(PKEY_Media_SubTitle, out pv);
            if (hr == HRESULT.S_OK)
            {
                string sSubTitle = Marshal.PtrToStringUni(pv.pwszVal);
                Console.WriteLine("Original SubTitle : {0}", sSubTitle);
            }
    
            string sNewSubTitle = "New SubTitle";
            PROPVARIANT pvNewSubTitle = new PROPVARIANT();
            pvNewSubTitle.varType = (ushort)VARENUM.VT_LPWSTR;
            pvNewSubTitle.pwszVal = Marshal.StringToHGlobalUni(sNewSubTitle);
            hr = pPropertyStore.SetValue(PKEY_Media_SubTitle, pvNewSubTitle);
            if (hr == HRESULT.S_OK)
                hr = pPropertyStore.Commit();
    
            if (hr == HRESULT.S_OK)
            {
                hr = pPropertyStore.GetValue(PKEY_Media_SubTitle, out pv);
                string sSubTitle = Marshal.PtrToStringUni(pv.pwszVal);
                Console.WriteLine("New SubTitle : {0}", sSubTitle);
            }
    
            Marshal.ReleaseComObject(pPropertyStore);
        }
    }
    

    With declarations :

    public enum HRESULT : int
    {
        S_OK = 0,
        S_FALSE = 1,
        E_NOINTERFACE = unchecked((int)0x80004002),
        E_NOTIMPL = unchecked((int)0x80004001),
        E_FAIL = unchecked((int)0x80004005),
        E_UNEXPECTED = unchecked((int)0x8000FFFFL)
    }
    
    [DllImport("Shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern HRESULT SHGetPropertyStoreFromParsingName(string pszPath, IntPtr pbc, GETPROPERTYSTOREFLAGS flags, ref Guid iid, [MarshalAs(UnmanagedType.Interface)] out IPropertyStore propertyStore);
    
    public enum GETPROPERTYSTOREFLAGS
    {
        GPS_DEFAULT = 0,
        GPS_HANDLERPROPERTIESONLY = 0x1,
        GPS_READWRITE = 0x2,
        GPS_TEMPORARY = 0x4,
        GPS_FASTPROPERTIESONLY = 0x8,
        GPS_OPENSLOWITEM = 0x10,
        GPS_DELAYCREATION = 0x20,
        GPS_BESTEFFORT = 0x40,
        GPS_NO_OPLOCK = 0x80,
        GPS_PREFERQUERYPROPERTIES = 0x100,
        GPS_EXTRINSICPROPERTIES = 0x200,
        GPS_EXTRINSICPROPERTIESONLY = 0x400,
        GPS_VOLATILEPROPERTIES = 0x800,
        GPS_VOLATILEPROPERTIESONLY = 0x1000,
        GPS_MASK_VALID = 0x1FFF
    }
    
    [ComImport, Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IPropertyStore
    {
        HRESULT GetCount([Out] out uint propertyCount);
        HRESULT GetAt([In] uint propertyIndex, [Out, MarshalAs(UnmanagedType.Struct)] out PROPERTYKEY key);
        HRESULT GetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [Out, MarshalAs(UnmanagedType.Struct)] out PROPVARIANT pv);
        HRESULT SetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [In, MarshalAs(UnmanagedType.Struct)] ref PROPVARIANT pv);
        HRESULT Commit();
    }
    
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct PROPERTYKEY
    {
        private readonly Guid _fmtid;
        private readonly uint _pid;
    
        public PROPERTYKEY(Guid fmtid, uint pid)
        {
            _fmtid = fmtid;
            _pid = pid;
        }
    }
    
    public static readonly PROPERTYKEY PKEY_Title = new PROPERTYKEY(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 2);
    public static readonly PROPERTYKEY PKEY_Keywords = new PROPERTYKEY(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 5);
    public static readonly PROPERTYKEY PKEY_Media_SubTitle = new PROPERTYKEY(new Guid("56A3372E-CE9C-11D2-9F0E-006097C686F6"), 38);
    
    [StructLayout(LayoutKind.Sequential, Pack = 0)]
    public struct PROPARRAY
    {
        public UInt32 cElems;
        public IntPtr pElems;
    }
    
    [StructLayout(LayoutKind.Explicit, Pack = 1)]
    public struct PROPVARIANT
    {
        [FieldOffset(0)]
        public ushort varType;
        [FieldOffset(2)]
        public ushort wReserved1;
        [FieldOffset(4)]
        public ushort wReserved2;
        [FieldOffset(6)]
        public ushort wReserved3;
    
        [FieldOffset(8)]
        public byte bVal;
        [FieldOffset(8)]
        public sbyte cVal;
        [FieldOffset(8)]
        public ushort uiVal;
        [FieldOffset(8)]
        public short iVal;
        [FieldOffset(8)]
        public UInt32 uintVal;
        [FieldOffset(8)]
        public Int32 intVal;
        [FieldOffset(8)]
        public UInt64 ulVal;
        [FieldOffset(8)]
        public Int64 lVal;
        [FieldOffset(8)]
        public float fltVal;
        [FieldOffset(8)]
        public double dblVal;
        [FieldOffset(8)]
        public short boolVal;
        [FieldOffset(8)]
        public IntPtr pclsidVal; // GUID ID pointer  
        [FieldOffset(8)]
        public IntPtr pszVal; // Ansi string pointer  
        [FieldOffset(8)]
        public IntPtr pwszVal; // Unicode string pointer  
        [FieldOffset(8)]
        public IntPtr punkVal; // punkVal (interface pointer)  
        [FieldOffset(8)]
        public PROPARRAY ca;
        [FieldOffset(8)]
        public System.Runtime.InteropServices.ComTypes.FILETIME filetime;
    }
    
    public enum VARENUM
    {
        VT_EMPTY = 0,
        VT_NULL = 1,
        VT_I2 = 2,
        VT_I4 = 3,
        VT_R4 = 4,
        VT_R8 = 5,
        VT_CY = 6,
        VT_DATE = 7,
        VT_BSTR = 8,
        VT_DISPATCH = 9,
        VT_ERROR = 10,
        VT_BOOL = 11,
        VT_VARIANT = 12,
        VT_UNKNOWN = 13,
        VT_DECIMAL = 14,
        VT_I1 = 16,
        VT_UI1 = 17,
        VT_UI2 = 18,
        VT_UI4 = 19,
        VT_I8 = 20,
        VT_UI8 = 21,
        VT_INT = 22,
        VT_UINT = 23,
        VT_VOID = 24,
        VT_HRESULT = 25,
        VT_PTR = 26,
        VT_SAFEARRAY = 27,
        VT_CARRAY = 28,
        VT_USERDEFINED = 29,
        VT_LPSTR = 30,
        VT_LPWSTR = 31,
        VT_RECORD = 36,
        VT_INT_PTR = 37,
        VT_UINT_PTR = 38,
        VT_FILETIME = 64,
        VT_BLOB = 65,
        VT_STREAM = 66,
        VT_STORAGE = 67,
        VT_STREAMED_OBJECT = 68,
        VT_STORED_OBJECT = 69,
        VT_BLOB_OBJECT = 70,
        VT_CF = 71,
        VT_CLSID = 72,
        VT_VERSIONED_STREAM = 73,
        VT_BSTR_BLOB = 0xfff,
        VT_VECTOR = 0x1000,
        VT_ARRAY = 0x2000,
        VT_BYREF = 0x4000,
        VT_RESERVED = 0x8000,
        VT_ILLEGAL = 0xffff,
        VT_ILLEGALMASKED = 0xfff,
        VT_TYPEMASK = 0xfff
    };
    
    
    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.