Commit a9ed1790 authored by Martin Finkel's avatar Martin Finkel

Fix media track marshalling and tests

parent 4ad78708
......@@ -101,7 +101,8 @@ namespace LibVLCSharp.Tests
{
var media = new Media(new LibVLC(), RealMp3Path);
media.Parse();
Assert.AreEqual(1, media.Tracks);
Assert.AreEqual(media.Tracks.Single().Data.Audio.Channels, 2);
Assert.AreEqual(media.Tracks.Single().Data.Audio.Rate, 44100);
}
[Test]
......
......@@ -54,10 +54,47 @@ namespace LibVLCSharp.Shared.Helpers
/// </summary>
/// <param name="s">TrackDescriptionStructure from interop</param>
/// <returns>public TrackDescription to be consumed by the user</returns>
internal static MediaTrack Build(this MediaTrackStructure s) =>
new MediaTrack(s.Codec, s.OriginalFourcc, s.Id, s.TrackType, s.Profile, s.Level, s.Data, s.Bitrate,
Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Language) as string,
Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Description) as string);
internal static MediaTrack Build(this MediaTrackStructure s)
{
AudioTrack audioTrack = default;
VideoTrack videoTrack = default;
SubtitleTrack subtitleTrack = default;
switch (s.TrackType)
{
case TrackType.Audio:
audioTrack = MarshalUtils.PtrToStructure<AudioTrack>(s.TrackData);
break;
case TrackType.Video:
videoTrack = MarshalUtils.PtrToStructure<VideoTrack>(s.TrackData);
break;
case TrackType.Text:
subtitleTrack = MarshalUtils.PtrToStructure<SubtitleTrackStructure>(s.TrackData).Build();
break;
case TrackType.Unknown:
break;
}
var language = Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Language) as string;
var des = Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Description) as string;
return new MediaTrack(s.Codec,
s.OriginalFourcc,
s.Id,
s.TrackType,
s.Profile,
s.Level,
new MediaTrackData(audioTrack, videoTrack, subtitleTrack), s.Bitrate,
language,
des);
}
/// <summary>
/// Helper method that creates a user friendly type from the internal interop structure.
/// </summary>
/// <param name="s">SubtitleTrackStructure from interop</param>
/// <returns>public SubtitleTrack to be consumed by the user</returns>
internal static SubtitleTrack Build(this SubtitleTrackStructure s) => new SubtitleTrack(Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Encoding) as string);
/// <summary>
/// Helper method that creates a user friendly type from the internal interop structure.
......
......@@ -74,13 +74,13 @@ namespace LibVLCSharp.Shared.Helpers
return resultList.ToArray();
}
internal static TU[] Retrieve<T, TU>(IntPtr nativeRef, Func<IntPtr, IntPtr, uint> getRef, Func<IntPtr, T> retrieve,
internal static TU[] Retrieve<T, TU>(IntPtr nativeRef, ArrayOut getRef, Func<IntPtr, T> retrieve,
Func<T, TU> create, Action<IntPtr, uint> releaseRef)
where T : struct
where TU : struct
{
var arrayPtr = IntPtr.Zero;
var count = getRef(nativeRef, arrayPtr);
var count = getRef(nativeRef, out arrayPtr);
if(count == 0)
{
#if NETSTANDARD1_1 || NET40
......@@ -142,9 +142,10 @@ namespace LibVLCSharp.Shared.Helpers
return resultList.ToArray();
}
internal delegate ulong CategoryArrayRef<T>(IntPtr nativeRef, T enumType, out IntPtr array) where T : Enum;
internal delegate ulong CategoryArrayOut<T>(IntPtr nativeRef, T enumType, out IntPtr array) where T : Enum;
internal delegate uint ArrayOut(IntPtr nativeRef, out IntPtr array);
internal static TU[] Retrieve<T, TU, TE>(IntPtr nativeRef, TE extraParam, CategoryArrayRef<TE> getRef, Func<IntPtr, T> retrieve,
internal static TU[] Retrieve<T, TU, TE>(IntPtr nativeRef, TE extraParam, CategoryArrayOut<TE> getRef, Func<IntPtr, T> retrieve,
Func<T, TU> create, Action<IntPtr, ulong> releaseRef)
where T : struct
where TU : struct
......
......@@ -31,14 +31,14 @@ namespace LibVLCSharp.Shared.Helpers
return ptr;
}
public object MarshalNativeToManaged(IntPtr pNativeData)
public object MarshalNativeToManaged(IntPtr ptr)
{
if (pNativeData == IntPtr.Zero)
if (ptr == IntPtr.Zero)
return null;
List<byte> bytes = new List<byte>();
for (int offset = 0; ; offset++)
{
byte b = Marshal.ReadByte(pNativeData, offset);
byte b = Marshal.ReadByte(ptr, offset);
if (b == 0)
break;
else bytes.Add(b);
......
......@@ -124,7 +124,7 @@ namespace LibVLCSharp.Shared
[DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "libvlc_media_tracks_get")]
internal static extern uint LibVLCMediaTracksGet(IntPtr media, ref IntPtr tracksPtr);
internal static extern uint LibVLCMediaTracksGet(IntPtr media, out IntPtr tracksPtr);
[DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "libvlc_media_tracks_release")]
......@@ -148,7 +148,7 @@ namespace LibVLCSharp.Shared
[DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "libvlc_media_slaves_get")]
internal static extern uint LibVLCMediaGetSlaves(IntPtr media, ref IntPtr slaves);
internal static extern uint LibVLCMediaGetSlaves(IntPtr media, out IntPtr slaves);
[DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "libvlc_media_slaves_release")]
......@@ -559,7 +559,7 @@ namespace LibVLCSharp.Shared
/// <para>Not doing this will result in an empty array.</para>
/// <para>LibVLC 2.1.0 and later.</para>
/// </remarks>
public MediaTrack[] Tracks => MarshalUtils.Retrieve(NativeReference, (nativeRef, arrayPtr) => Native.LibVLCMediaTracksGet(nativeRef, ref arrayPtr),
public MediaTrack[] Tracks => MarshalUtils.Retrieve(NativeReference, (IntPtr nativeRef, out IntPtr array) => Native.LibVLCMediaTracksGet(nativeRef, out array),
MarshalUtils.PtrToStructure<MediaTrackStructure>,
m => m.Build(),
Native.LibVLCMediaTracksRelease);
......@@ -609,10 +609,10 @@ namespace LibVLCSharp.Shared
/// <para>LibVLC 3.0.0 and later.</para>
/// <para>libvlc_media_slaves_add</para>
/// </remarks>
public MediaSlave[] Slaves => MarshalUtils.Retrieve(NativeReference, (nativeRef, arrayPtr) => Native.LibVLCMediaGetSlaves(nativeRef, ref arrayPtr),
MarshalUtils.PtrToStructure<MediaSlaveStructure>,
s => s.Build(),
Native.LibVLCMediaReleaseSlaves);
public MediaSlave[] Slaves => MarshalUtils.Retrieve(NativeReference, (IntPtr nativeRef, out IntPtr array) => Native.LibVLCMediaGetSlaves(nativeRef, out array),
MarshalUtils.PtrToStructure<MediaSlaveStructure>,
s => s.Build(),
Native.LibVLCMediaReleaseSlaves);
public override bool Equals(object obj)
{
......
namespace LibVLCSharp.Shared
{
public readonly struct AudioTrack
{
public readonly uint Channels;
public readonly uint Rate;
}
}
......@@ -12,12 +12,107 @@ namespace LibVLCSharp.Shared
internal readonly TrackType TrackType;
internal readonly int Profile;
internal readonly int Level;
internal readonly MediaTrackData Data;
internal readonly IntPtr TrackData;
internal readonly uint Bitrate;
internal readonly IntPtr Language;
internal readonly IntPtr Description;
}
internal readonly struct SubtitleTrackStructure
{
internal readonly IntPtr Encoding;
}
/// <summary>
/// Audio track
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct AudioTrack
{
internal AudioTrack(uint channels, uint rate)
{
Channels = channels;
Rate = rate;
}
/// <summary>
/// Audio track channels
/// </summary>
public readonly uint Channels;
/// <summary>
/// Audio track rate
/// </summary>
public readonly uint Rate;
}
/// <summary>
/// Video track
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct VideoTrack
{
/// <summary>
/// Video height
/// </summary>
public readonly uint Height;
/// <summary>
/// Video Width
/// </summary>
public readonly uint Width;
/// <summary>
/// Video SarNum
/// </summary>
public readonly uint SarNum;
/// <summary>
/// Video SarDen
/// </summary>
public readonly uint SarDen;
/// <summary>
/// Video frame rate num
/// </summary>
public readonly uint FrameRateNum;
/// <summary>
/// Video frame rate den
/// </summary>
public readonly uint FrameRateDen;
/// <summary>
/// Video orientation
/// </summary>
public readonly VideoOrientation Orientation;
/// <summary>
/// Video projection
/// </summary>
public readonly VideoProjection Projection;
/// <summary>
/// Video viewpoint
/// </summary>
public readonly VideoViewpoint Pose;
}
/// <summary>
/// Subtitle track
/// </summary>
public readonly struct SubtitleTrack
{
internal SubtitleTrack(string encoding)
{
Encoding = encoding;
}
/// <summary>
/// Subtitle encoding
/// </summary>
public readonly string Encoding;
}
/// <summary>
/// Media track information
/// </summary>
......
......@@ -5,6 +5,12 @@
/// </summary>
public readonly struct MediaTrackData
{
internal MediaTrackData(AudioTrack audio, VideoTrack video, SubtitleTrack subtitle)
{
Audio = audio;
Video = video;
Subtitle = subtitle;
}
/// <summary>
/// Audio track
/// </summary>
......@@ -20,4 +26,4 @@
/// </summary>
public readonly SubtitleTrack Subtitle;
}
}
}
\ No newline at end of file
using System;
namespace LibVLCSharp.Shared
{
public readonly struct SubtitleTrack
{
public readonly IntPtr Encoding;
}
}
namespace LibVLCSharp.Shared
{
public readonly struct VideoTrack
{
public readonly uint Height;
public readonly uint Width;
public readonly uint SarNum;
public readonly uint SarDen;
public readonly uint FrameRateNum;
public readonly uint FrameRateDen;
public readonly VideoOrientation Orientation;
public readonly VideoProjection Projection;
public readonly VideoViewpoint Pose;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment