在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));
怎么了?有人能帮我吗?
从所提供的代码和字段的描述来看,我认为这是因为您没有为句柄包含空间。
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来替换。