在LibMP4v2中为方法MP4TagsFetch编写C#包装器

时间:2011-09-18 20:56:42

标签: c# c++

我将使用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));

出了什么问题?任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:0)

从提供的代码和关闭字段的描述中,我说;这是因为你没有包含句柄的空间。

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字段重新定义你的结构,你认为编组不使用的任何字段,并迭代地将它们重新用于帮助isoltae哪一个是罪魁祸首。 API看起来像是使用指向数据字段的整个指针,因此每个指针都可以用IntPtr替换。