Skip to content

Commit

Permalink
feat: implement Packet.CreateString, GetString, GetBytes (#1102)
Browse files Browse the repository at this point in the history
  • Loading branch information
homuler committed Jan 3, 2024
1 parent 251ebd3 commit 84181bf
Show file tree
Hide file tree
Showing 5 changed files with 294 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,52 @@ public static Packet CreateIntAt(int value, long timestampMicrosec)
}
}

/// <summary>
/// Create a string Packet.
/// </summary>
public static Packet CreateString(string value)
{
UnsafeNativeMethods.mp__MakeStringPacket__PKc(value ?? "", out var ptr).Assert();

return new Packet(ptr, true);
}

/// <summary>
/// Create a string Packet.
/// </summary>
public static Packet CreateString(byte[] value)
{
UnsafeNativeMethods.mp__MakeStringPacket__PKc_i(value, value?.Length ?? 0, out var ptr).Assert();

return new Packet(ptr, true);
}

/// <summary>
/// Create a string Packet.
/// </summary>
/// <param name="timestampMicrosec">
/// The timestamp of the packet.
/// </param>
public static Packet CreateStringAt(string value, long timestampMicrosec)
{
UnsafeNativeMethods.mp__MakeStringPacket_At__PKc_ll(value ?? "", timestampMicrosec, out var ptr).Assert();

return new Packet(ptr, true);
}

/// <summary>
/// Create a string Packet.
/// </summary>
/// <param name="timestampMicrosec">
/// The timestamp of the packet.
/// </param>
public static Packet CreateStringAt(byte[] value, long timestampMicrosec)
{
UnsafeNativeMethods.mp__MakeStringPacket_At__PKc_i_ll(value, value?.Length ?? 0, timestampMicrosec, out var ptr).Assert();

return new Packet(ptr, true);
}

/// <summary>
/// Get the content of the <see cref="Packet"/> as a boolean.
/// </summary>
Expand Down Expand Up @@ -347,6 +393,56 @@ public void GetBoolList(List<bool> value)
structArray.Dispose();
}

/// <summary>
/// Get the content of the <see cref="Packet"/> as <see cref="byte[]"/>.
/// </summary>
/// <remarks>
/// On some platforms (e.g. Windows), it will abort the process when <see cref="MediaPipeException"/> should be thrown.
/// </remarks>
/// <exception cref="MediaPipeException">
/// If the <see cref="Packet"/> doesn't contain <see cref="string"/> data.
/// </exception>
public byte[] GetBytes()
{
UnsafeNativeMethods.mp_Packet__GetByteString(mpPtr, out var strPtr, out var size).Assert();
GC.KeepAlive(this);

var bytes = new byte[size];
Marshal.Copy(strPtr, bytes, 0, size);
UnsafeNativeMethods.delete_array__PKc(strPtr);

return bytes;
}

/// <summary>
/// Get the content of the <see cref="Packet"/> as <see cref="byte[]"/>.
/// </summary>
/// <remarks>
/// On some platforms (e.g. Windows), it will abort the process when <see cref="MediaPipeException"/> should be thrown.
/// </remarks>
/// <param name="value">
/// The <see cref="byte[]"/> to be filled with the content of the <see cref="Packet"/>.
/// If the length of <paramref name="value"/> is not enough to store the content of the <see cref="Packet"/>,
/// the rest of the content will be discarded.
/// </param>
/// <returns>
/// The number of written elements in <paramref name="value" />.
/// </returns>
/// <exception cref="MediaPipeException">
/// If the <see cref="Packet"/> doesn't contain <see cref="string"/> data.
/// </exception>
public int GetBytes(byte[] value)
{
UnsafeNativeMethods.mp_Packet__GetByteString(mpPtr, out var strPtr, out var size).Assert();
GC.KeepAlive(this);

var length = Math.Min(size, value.Length);
Marshal.Copy(strPtr, value, 0, length);
UnsafeNativeMethods.delete_array__PKc(strPtr);

return length;
}

/// <summary>
/// Get the content of the <see cref="Packet"/> as a double.
/// </summary>
Expand Down Expand Up @@ -646,6 +742,23 @@ public void GetDetectionList(List<Detection> outs)
outs.RemoveRange(size, outs.Count - size);
}

/// <summary>
/// Get the content of the <see cref="Packet"/> as a string.
/// </summary>
/// <remarks>
/// On some platforms (e.g. Windows), it will abort the process when <see cref="MediaPipeException"/> should be thrown.
/// </remarks>
/// <exception cref="MediaPipeException">
/// If the <see cref="Packet"/> doesn't contain <see cref="string"/> data.
/// </exception>
public string GetString()
{
UnsafeNativeMethods.mp_Packet__GetString(mpPtr, out var ptr).Assert();

GC.KeepAlive(this);
return MarshalStringFromNative(ptr);
}

/// <summary>
/// Validate if the content of the <see cref="Packet"/> is a boolean.
/// </summary>
Expand Down Expand Up @@ -785,5 +898,19 @@ public void ValidateAsProtoMessageLite()
GC.KeepAlive(this);
AssertStatusOk(statusPtr);
}

/// <summary>
/// Validate if the content of the <see cref="Packet"/> is a string.
/// </summary>
/// <exception cref="BadStatusException">
/// If the <see cref="Packet"/> doesn't contain string.
/// </exception>
public void ValidateAsString()
{
UnsafeNativeMethods.mp_Packet__ValidateAsString(mpPtr, out var statusPtr).Assert();

GC.KeepAlive(this);
AssertStatusOk(statusPtr);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,18 @@ internal static partial class UnsafeNativeMethods
[DllImport(MediaPipeLibrary, ExactSpelling = true)]
public static extern MpReturnCode mp__MakeStringPacket_At__PKc_Rt(string value, IntPtr timestamp, out IntPtr packet);

[DllImport(MediaPipeLibrary, ExactSpelling = true)]
public static extern MpReturnCode mp__MakeStringPacket_At__PKc_ll(string value, long timestampMicrosec, out IntPtr packet);

[DllImport(MediaPipeLibrary, ExactSpelling = true)]
public static extern MpReturnCode mp__MakeStringPacket__PKc_i(byte[] bytes, int size, out IntPtr packet);

[DllImport(MediaPipeLibrary, ExactSpelling = true)]
public static extern MpReturnCode mp__MakeStringPacket_At__PKc_i_Rt(byte[] bytes, int size, IntPtr timestamp, out IntPtr packet);

[DllImport(MediaPipeLibrary, ExactSpelling = true)]
public static extern MpReturnCode mp__MakeStringPacket_At__PKc_i_ll(byte[] bytes, int size, long timestampMicrosec, out IntPtr packet);

[DllImport(MediaPipeLibrary, ExactSpelling = true)]
public static extern MpReturnCode mp_Packet__GetString(IntPtr packet, out IntPtr value);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,151 @@ public void CreateProtoAt_ShouldReturnNewProtoPacket()
}
#endregion


#region String
[Test]
public void CreateString_ShouldReturnNewStringPacket_When_ValueIsNullString()
{
using var packet = Packet.CreateString((string)null);

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.IsNull(packet.GetString());

using var unsetTimestamp = Timestamp.Unset();
Assert.AreEqual(unsetTimestamp.Microseconds(), packet.TimestampMicroseconds());
}

[Test]
public void CreateString_ShouldReturnNewStringPacket_When_ValueIsEmptyString()
{
using var packet = Packet.CreateString("");

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.IsNull(packet.GetString());

using var unsetTimestamp = Timestamp.Unset();
Assert.AreEqual(unsetTimestamp.Microseconds(), packet.TimestampMicroseconds());
}

[TestCase("hello")]
public void CreateString_ShouldReturnNewStringPacket_When_StringIsGiven(string value)
{
using var packet = Packet.CreateString(value);

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.AreEqual(value, packet.GetString());

using var unsetTimestamp = Timestamp.Unset();
Assert.AreEqual(unsetTimestamp.Microseconds(), packet.TimestampMicroseconds());
}

[Test]
public void CreateString_ShouldReturnNewStringPacket_When_ValueIsNullArray()
{
using var packet = Packet.CreateString((byte[])null);

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.IsEmpty(packet.GetBytes());

using var unsetTimestamp = Timestamp.Unset();
Assert.AreEqual(unsetTimestamp.Microseconds(), packet.TimestampMicroseconds());
}

[Test]
public void CreateString_ShouldReturnNewStringPacket_When_ValueIsEmptyArray()
{
var value = new byte[] { };
using var packet = Packet.CreateString(value);

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.IsEmpty(packet.GetBytes());

using var unsetTimestamp = Timestamp.Unset();
Assert.AreEqual(unsetTimestamp.Microseconds(), packet.TimestampMicroseconds());
}

[Test]
public void CreateString_ShouldReturnNewStringPacket_When_ByteArrayIsGiven()
{
var value = new byte[] { 1, 2, 3 };
using var packet = Packet.CreateString(value);

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.AreEqual(value, packet.GetBytes());

using var unsetTimestamp = Timestamp.Unset();
Assert.AreEqual(unsetTimestamp.Microseconds(), packet.TimestampMicroseconds());
}

[Test]
public void CreateStringAt_ShouldReturnNewStringPacket_When_ValueIsNullString()
{
var timestamp = 1;
using var packet = Packet.CreateStringAt((string)null, timestamp);

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.IsNull(packet.GetString());
Assert.AreEqual(timestamp, packet.TimestampMicroseconds());
}

[Test]
public void CreateStringAt_ShouldReturnNewStringPacket_When_ValueIsEmptyString()
{
var timestamp = 1;
using var packet = Packet.CreateStringAt("", timestamp);

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.IsNull(packet.GetString());
Assert.AreEqual(timestamp, packet.TimestampMicroseconds());
}

[TestCase("hello")]
public void CreateStringAt_ShouldReturnNewStringPacket_When_StringIsGiven(string value)
{
var timestamp = 1;
using var packet = Packet.CreateStringAt(value, timestamp);

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.AreEqual(value, packet.GetString());
Assert.AreEqual(timestamp, packet.TimestampMicroseconds());
}

[Test]
public void CreateStringAt_ShouldReturnNewStringPacket_When_ValueIsNullArray()
{
var timestamp = 1;
using var packet = Packet.CreateStringAt((byte[])null, timestamp);

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.IsEmpty(packet.GetBytes());
Assert.AreEqual(timestamp, packet.TimestampMicroseconds());
}

[Test]
public void CreateStringAt_ShouldReturnNewStringPacket_When_ValueIsEmptyArray()
{
var timestamp = 1;
var value = new byte[] { };
using var packet = Packet.CreateStringAt(value, timestamp);

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.IsEmpty(packet.GetBytes());
Assert.AreEqual(timestamp, packet.TimestampMicroseconds());
}

[Test]
public void CreateStringAt_ShouldReturnNewStringPacket_When_ByteArrayIsGiven()
{
var timestamp = 1;
var value = new byte[] { 1, 2, 3 };
using var packet = Packet.CreateStringAt(value, timestamp);

Assert.DoesNotThrow(packet.ValidateAsString);
Assert.AreEqual(value, packet.GetBytes());
Assert.AreEqual(timestamp, packet.TimestampMicroseconds());
}
#endregion

#region #Validate
[Test]
public void ValidateAsBool_ShouldThrow_When_ValueIsNotSet()
Expand Down
14 changes: 14 additions & 0 deletions mediapipe_api/framework/packet.cc
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,13 @@ MpReturnCode mp__MakeStringPacket_At__PKc_Rt(const char* str, mediapipe::Timesta
CATCH_EXCEPTION
}

MpReturnCode mp__MakeStringPacket_At__PKc_ll(const char* str, int64 timestampMicrosec, mediapipe::Packet** packet_out) {
TRY
*packet_out = new mediapipe::Packet{mediapipe::MakePacket<std::string>(std::string(str)).At(mediapipe::Timestamp(timestampMicrosec))};
RETURN_CODE(MpReturnCode::Success);
CATCH_EXCEPTION
}

MpReturnCode mp__MakeStringPacket__PKc_i(const char* str, int size, mediapipe::Packet** packet_out) {
TRY
*packet_out = new mediapipe::Packet{mediapipe::MakePacket<std::string>(std::string(str, size))};
Expand All @@ -313,6 +320,13 @@ MpReturnCode mp__MakeStringPacket_At__PKc_i_Rt(const char* str, int size, mediap
CATCH_EXCEPTION
}

MpReturnCode mp__MakeStringPacket_At__PKc_i_ll(const char* str, int size, int64 timestampMicrosec, mediapipe::Packet** packet_out) {
TRY
*packet_out = new mediapipe::Packet{mediapipe::MakePacket<std::string>(std::string(str, size)).At(mediapipe::Timestamp(timestampMicrosec))};
RETURN_CODE(MpReturnCode::Success);
CATCH_EXCEPTION
}

MpReturnCode mp_Packet__GetString(mediapipe::Packet* packet, const char** value_out) {
TRY_ALL
*value_out = strcpy_to_heap(packet->Get<std::string>());
Expand Down
2 changes: 2 additions & 0 deletions mediapipe_api/framework/packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,10 @@ MP_CAPI(MpReturnCode) mp_Packet__ValidateAsInt(mediapipe::Packet* packet, absl::
// String
MP_CAPI(MpReturnCode) mp__MakeStringPacket__PKc(const char* str, mediapipe::Packet** packet_out);
MP_CAPI(MpReturnCode) mp__MakeStringPacket_At__PKc_Rt(const char* str, mediapipe::Timestamp* timestamp, mediapipe::Packet** packet_out);
MP_CAPI(MpReturnCode) mp__MakeStringPacket_At__PKc_ll(const char* str, int64 timestampMicrosec, mediapipe::Packet** packet_out);
MP_CAPI(MpReturnCode) mp__MakeStringPacket__PKc_i(const char* str, int size, mediapipe::Packet** packet_out);
MP_CAPI(MpReturnCode) mp__MakeStringPacket_At__PKc_i_Rt(const char* str, int size, mediapipe::Timestamp* timestamp, mediapipe::Packet** packet_out);
MP_CAPI(MpReturnCode) mp__MakeStringPacket_At__PKc_i_ll(const char* str, int size, int64 timestampMicrosec, mediapipe::Packet** packet_out);
MP_CAPI(MpReturnCode) mp_Packet__GetString(mediapipe::Packet* packet, const char** value_out);
MP_CAPI(MpReturnCode) mp_Packet__GetByteString(mediapipe::Packet* packet, const char** value_out, int* size_out);
MP_CAPI(MpReturnCode) mp_Packet__ConsumeString(mediapipe::Packet* packet, absl::Status** status_out, const char** value_out);
Expand Down

0 comments on commit 84181bf

Please sign in to comment.