Reputation: 36
I am trying to use following C struct in managed application
typedef struct libvlc_media_track_t
{
uint32_t i_codec;
uint32_t i_original_fourcc;
int i_id;
libvlc_track_type_t i_type;
int i_profile;
int i_level;
union {
libvlc_audio_track_t *audio;
libvlc_video_track_t *video;
libvlc_subtitle_track_t *subtitle;
};
unsigned int i_bitrate;
char *psz_language;
char *psz_description;
} libvlc_media_track_t;
typedef struct libvlc_audio_track_t
{
unsigned i_channels;
unsigned i_rate;
} libvlc_audio_track_t;
typedef struct libvlc_video_track_t
{
unsigned i_height;
unsigned i_width;
unsigned i_sar_num;
unsigned i_sar_den;
unsigned i_frame_rate_num;
unsigned i_frame_rate_den;
} libvlc_video_track_t;
typedef struct libvlc_subtitle_track_t
{
char *psz_encoding;
} libvlc_subtitle_track_t;
unsigned libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t ***tracks );
And .NET version looks like this:
[StructLayout(LayoutKind.Explicit)]
public struct libvlc_media_track_t
{
[FieldOffset(0)]
public uint i_codec;
[FieldOffset(4)]
public uint i_original_fourcc;
[FieldOffset(8)]
public int i_id;
[FieldOffset(12)]
public libvlc_track_type_t i_type;
[FieldOffset(16)]
public int i_profile;
[FieldOffset(20)]
public int i_level;
[FieldOffset(24)]
public libvlc_audio_track_t audio;
[FieldOffset(24)]
public libvlc_video_track_t video;
[FieldOffset(24)]
public libvlc_subtitle_track_t subtitle;
[FieldOffset(48)]
public uint i_bitrate;
[FieldOffset(52)]
public IntPtr psz_language;
[FieldOffset(56)]
public IntPtr psz_description;
}
[StructLayout(LayoutKind.Sequential)]
public struct libvlc_audio_track_t
{
public uint i_channels;
public uint i_rate;
}
[StructLayout(LayoutKind.Sequential)]
public struct libvlc_video_track_t
{
public uint i_height;
public uint i_width;
public uint i_sar_num;
public uint i_sar_den;
public uint i_frame_rate_num;
public uint i_frame_rate_den;
}
[StructLayout(LayoutKind.Sequential)]
public struct libvlc_subtitle_track_t
{
public IntPtr psz_encoding;
}
[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern int libvlc_media_tracks_get(IntPtr media, libvlc_media_track_t*** ppTracks);
unsafe
{
libvlc_media_track_t** ppTracks;
int num = LibVlcMethods.libvlc_media_tracks_get(m_hMedia, &ppTracks);
if (num == 0 || ppTracks == null)
{
throw new Exception();
}
for (int i = 0; i < num; i++)
{
libvlc_media_track_t* pTrackInfo = ppTracks[i];
}
LibVlcMethods.libvlc_media_tracks_release(ppTracks, num);
}
The code works without any exception but I get garbage data in most of the structure/union fields.
Please advise, Thanks in advance
Edit: I tried the following also, but it had the same result
[StructLayout(LayoutKind.Sequential)]
public struct libvlc_media_track_t
{
public uint i_codec;
public uint i_original_fourcc;
public int i_id;
public libvlc_track_type_t i_type;
public int i_profile;
public int i_level;
public MediaVariant media;
public uint i_bitrate;
public IntPtr psz_language;
public IntPtr psz_description;
}
[StructLayout(LayoutKind.Explicit)]
public struct MediaVariant
{
[FieldOffset(0)]
public libvlc_audio_track_t audio;
[FieldOffset(0)]
public libvlc_video_track_t video;
[FieldOffset(0)]
public libvlc_subtitle_track_t subtitle;
}
Upvotes: 1
Views: 474
Reputation: 613372
You've translated the union incorrectly. I suspect that when you say:
I get garbage data in most of the structure/union fields.
that what you mean is that the data is fine before the union, and garbage after. Let's take a look at the union. It is:
union {
libvlc_audio_track_t *audio;
libvlc_video_track_t *video;
libvlc_subtitle_track_t *subtitle;
};
The union contains pointers. But you have translated it by putting the structs in the union. Your C# translation is equivalent to:
union {
libvlc_audio_track_t audio;
libvlc_video_track_t video;
libvlc_subtitle_track_t subtitle;
};
So, simply replace the union with IntPtr
and you'll be good.
[StructLayout(LayoutKind.Sequential)]
public struct libvlc_media_track_t
{
public uint i_codec;
public uint i_original_fourcc;
public int i_id;
public libvlc_track_type_t i_type;
public int i_profile;
public int i_level;
public IntPtr media;
public uint i_bitrate;
public IntPtr psz_language;
public IntPtr psz_description;
}
As an aside it would be quite easy to avoid using unsafe
if you wanted. Although, if there's no downside for you then being able to use pointers will make the code easier to write.
Upvotes: 1