在LibMP4v2中编写MP4TagsFetch方法的c#包装器

本文关键字:包装 方法 MP4TagsFetch LibMP4v2 | 更新日期: 2023-09-27 18:09:01

我将使用LibMP4v2库编写一个读取MP4文件的类,但是c++不是我最喜欢的编程语言。

The library contains following structure definitions:
 /** Enumeration of possible MP4TagArtwork::type values. */
typedef enum MP4TagArtworkType_e
{
    MP4_ART_UNDEFINED = 0,
    MP4_ART_BMP       = 1,
    MP4_ART_GIF       = 2,
    MP4_ART_JPEG      = 3,
    MP4_ART_PNG       = 4
} MP4TagArtworkType;
/** Data object representing a single piece of artwork. */
typedef struct MP4TagArtwork_s
{
    void*             data; /**< raw picture data */
    uint32_t          size; /**< data size in bytes */
    MP4TagArtworkType type; /**< data type */
} MP4TagArtwork;
typedef struct MP4TagTrack_s
{
    uint16_t index;
    uint16_t total;
} MP4TagTrack;
typedef struct MP4TagDisk_s
{
    uint16_t index;
    uint16_t total;
} MP4TagDisk;
/** Tags <b>convenience</b> structure.
 *
 *  This structure is used in the tags convenience API which allows for
 *  simplified retrieval and modification of the majority of known tags.
 *
 *  This is a read-only structure and each tag is present if and only if the
 *  pointer is a <b>non-NULL</b> value. The actual data is backed by a hidden
 *  data cache which is only updated when the appropriate metadata <b>set</b>
 *  function is used, or if MP4TagsFetch() is invoked. Thus, if other API
 *  is used to manipulate relevent atom structure of the MP4 file, the user
 *  is responsible for re-fetching the data in this structure.
 */
typedef struct MP4Tags_s
{
    void* __handle; /* internal use only */
    const char*        name;
    const char*        artist;
    const char*        albumArtist; 
    const char*        album;
    const char*        grouping;
    const char*        composer;
    const char*        comments;
    const char*        genre;
    const uint16_t*    genreType;
    const char*        releaseDate;
    const MP4TagTrack* track;
    const MP4TagDisk*  disk;
    const uint16_t*    tempo;
    const uint8_t*     compilation;
    const char*     tvShow;
    const char*     tvNetwork;
    const char*     tvEpisodeID;
    const uint32_t* tvSeason;
    const uint32_t* tvEpisode;
    const char* description;
    const char* longDescription;
    const char* lyrics;
    const char* sortName;
    const char* sortArtist;
    const char* sortAlbumArtist;
    const char* sortAlbum;
    const char* sortComposer;
    const char* sortTVShow;
    const MP4TagArtwork* artwork;
    uint32_t             artworkCount;
    const char* copyright;
    const char* encodingTool;
    const char* encodedBy;
    const char* purchaseDate;
    const uint8_t* podcast;
    const char*    keywords;  /* TODO: Needs testing */
    const char*    category;    
    const uint8_t* hdVideo;
    const uint8_t* mediaType;
    const uint8_t* contentRating;
    const uint8_t* gapless;
    const char*     iTunesAccount;
    const uint8_t*  iTunesAccountType;
    const uint32_t* iTunesCountry;
    const uint32_t* contentID;
    const uint32_t* artistID;
    const uint64_t* playlistID;
    const uint32_t* genreID;
    const uint32_t* composerID;
    const char*     xid;
} MP4Tags;
我的c#代码是:
[DllImport("libmp4v2.dll", CharSet = CharSet.Ansi)]
private extern static IntPtr MP4Read([MarshalAs(UnmanagedType.LPStr)] string filePath);
[DllImport("libmp4v2.dll", CharSet = CharSet.Ansi)]
private extern static bool MP4TagsFetch(IntPtr tags, IntPtr fileHandle);
[DllImport("libmp4v2.dll", CharSet = CharSet.Ansi)]
private extern static IntPtr MP4TagsAlloc();
[DllImport("libmp4v2.dll", CharSet = CharSet.Ansi)]
private extern static IntPtr MP4FileInfo([MarshalAs(UnmanagedType.LPStr)] string filePath, uint trackId);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MP4TagTrack
{
   public ushort Index;
   public ushort Total;
}
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct MP4TagDisk
        {
            public ushort Index;
            public ushort Total;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct CoverArtBox
        {
            public byte[] data; /**< raw picture data */
            public uint size; /**< data size in bytes */
            public MP4TagArtworkType type; /**< data type */
        }
        public enum MP4TagArtworkType
        {
            MP4_ART_UNDEFINED = 0,
            MP4_ART_BMP = 1,
            MP4_ART_GIF = 2,
            MP4_ART_JPEG = 3,
            MP4_ART_PNG = 4
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct MP4Tags
        {
            public string Name;
            public string Artist;
            public string AlbumArtist;
            public string Album;
            public string Grouping;
            public string Composer;
            public string Comments;
            public string Genre;
            public byte[] GenreType;
            public string ReleaseDate;
            //public MP4TagTrack Track;
            //public MP4TagDisk Disk;
            public uint Tempo;
            public uint Compilation;
            public string TVShow;
            public string TVEpisodeID;
            public string TVNetwork;
            public uint TVSeason;
            public uint TVEpisode;
            public string SortName;
            public string SortArtist;
            public string SortAlbumArtist;
            public string SortAlbum;
            public string SortComposer;
            public string SortTVShow;
            public string Description;
            public string LongDescription;
            public string Lyrics;
            public CoverArtBox[] Artwork;
            public uint ArtworkCount;
            public string Copyright;
            public string EncodingTool;
            public string EncodedBy;
            public string PurchaseDate;
            public uint Podcast;
            public string Keywords;
            public string Category;
            public uint HDVideo;
            public uint MediaType;
            public uint ContentRating;
            public uint Gapless;
            public string iTunesAccount;
            public byte iTunesAccountType;
            public uint iTunesCountry;
            public uint ContentID;
            public uint ArtistID;
            public ulong PlaylistID;
            public uint GenreID;
            public uint ComposerID;
            public string Xid;
            public bool HasMetadata;
        }

调用外部方法MP4TagsFetch并将IntPtr转换为我的结构后,相同的字段填充了其他字段的数据:

IntPtr fileHandle = MP4Read(FilePath);
IntPtr tags = MP4TagsAlloc();
if (fileHandle != IntPtr.Zero && MP4TagsFetch(tags, fileHandle))
    MP4Tags val = (MP4Tags)Marshal.PtrToStructure(tags, typeof(MP4Tags));

怎么了?有人能帮我吗?

在LibMP4v2中编写MP4TagsFetch方法的c#包装器

从所提供的代码和字段的描述来看,我认为这是因为您没有为句柄包含空间。

void* __handle; /* internal use only */ 

因此,添加如下:

public struct MP4Tags          
{              
    public IntPtr Handle;  <-----------------------
    public string Name;
    public string Artist;
    public string AlbumArtist;  
    etc

您应该能够将该字段设置为私有以更好地保护它(因为它被注释为仅供内部使用),尽管我没有测试过。

EDIT1

我也不认为这是正确的:

public byte iTunesAccountType; 

C声明是这样的:

const uint8_t*  iTunesAccountType;

这是一个指针(4字节假设32位应用程序)。

我实际上会用IntPtr字段重新定义您的结构,用于您认为编组不工作的任何字段,并迭代地将它们带回来以帮助隔离哪个是罪魁祸首。这个API看起来像是在使用指向数据字段的整个指针,所以每个指针都可以用IntPtr来替换。