From 219fa09aa666ffae36f8c8c0c625e9550857ed40 Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Wed, 5 Mar 2025 22:47:04 +0100
Subject: [PATCH 01/13] Flatbuffers and other Capture Method for high res
Code still not perfect tho. Needs more testing and some more work and love.
+using high res screen capture via libsec-video-capture
+sending yuv images directly via flatbuffers removes rgb conversion overhead and is way better for hdr content
-needs some more research on the inner workings of libsec-video-capture
-needs more performance adjustments
-needs reimplementation of using the config values from the ui
-needs some stability improvements
---
HyperTizen/Directory.Build.targets | 42 ++--
HyperTizen/Flatbuffers/Clear.cs | 50 +++++
HyperTizen/Flatbuffers/Color.cs | 55 +++++
HyperTizen/Flatbuffers/Command.cs | 46 +++++
HyperTizen/Flatbuffers/Image.cs | 63 ++++++
HyperTizen/Flatbuffers/ImageType.cs | 38 ++++
HyperTizen/Flatbuffers/NV12Image.cs | 99 +++++++++
HyperTizen/Flatbuffers/RawImage.cs | 72 +++++++
HyperTizen/Flatbuffers/Register.cs | 62 ++++++
HyperTizen/Flatbuffers/Reply.cs | 69 +++++++
HyperTizen/Flatbuffers/Request.cs | 63 ++++++
HyperTizen/Globals.cs | 43 ++++
HyperTizen/HyperTizen.csproj | 3 +
HyperTizen/HyperTizen.csproj.user | 4 +
HyperTizen/Networking.cs | 179 +++++++++++++++++
HyperTizen/WebSocket/HyperionClient.cs | 266 ++++++++++++++++++-------
HyperTizen/tizen-manifest.xml | 7 +-
HyperTizen/tizen_dotnet_project.yaml | 18 +-
18 files changed, 1076 insertions(+), 103 deletions(-)
create mode 100644 HyperTizen/Flatbuffers/Clear.cs
create mode 100644 HyperTizen/Flatbuffers/Color.cs
create mode 100644 HyperTizen/Flatbuffers/Command.cs
create mode 100644 HyperTizen/Flatbuffers/Image.cs
create mode 100644 HyperTizen/Flatbuffers/ImageType.cs
create mode 100644 HyperTizen/Flatbuffers/NV12Image.cs
create mode 100644 HyperTizen/Flatbuffers/RawImage.cs
create mode 100644 HyperTizen/Flatbuffers/Register.cs
create mode 100644 HyperTizen/Flatbuffers/Reply.cs
create mode 100644 HyperTizen/Flatbuffers/Request.cs
create mode 100644 HyperTizen/Globals.cs
create mode 100644 HyperTizen/HyperTizen.csproj.user
create mode 100644 HyperTizen/Networking.cs
diff --git a/HyperTizen/Directory.Build.targets b/HyperTizen/Directory.Build.targets
index 3e8f209..cf6c1a9 100644
--- a/HyperTizen/Directory.Build.targets
+++ b/HyperTizen/Directory.Build.targets
@@ -1,21 +1,21 @@
-
-
-
-
-
-
-
- $([System.IO.Path]::GetDirectoryName($(MSBuildProjectDirectory)))
-
-
-
-
-
-
+
+
+
+
+
+
+
+ $([System.IO.Path]::GetDirectoryName($(MSBuildProjectDirectory)))
+
+
+
+
+
+
diff --git a/HyperTizen/Flatbuffers/Clear.cs b/HyperTizen/Flatbuffers/Clear.cs
new file mode 100644
index 0000000..2f56c4c
--- /dev/null
+++ b/HyperTizen/Flatbuffers/Clear.cs
@@ -0,0 +1,50 @@
+//
+// automatically generated by the FlatBuffers compiler, do not modify
+//
+
+namespace hyperhdrnet
+{
+
+using global::System;
+using global::System.Collections.Generic;
+using global::Google.FlatBuffers;
+
+public struct Clear : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); }
+ public static Clear GetRootAsClear(ByteBuffer _bb) { return GetRootAsClear(_bb, new Clear()); }
+ public static Clear GetRootAsClear(ByteBuffer _bb, Clear obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Clear __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int Priority { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+
+ public static Offset CreateClear(FlatBufferBuilder builder,
+ int priority = 0) {
+ builder.StartTable(1);
+ Clear.AddPriority(builder, priority);
+ return Clear.EndClear(builder);
+ }
+
+ public static void StartClear(FlatBufferBuilder builder) { builder.StartTable(1); }
+ public static void AddPriority(FlatBufferBuilder builder, int priority) { builder.AddInt(0, priority, 0); }
+ public static Offset EndClear(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset(o);
+ }
+}
+
+
+static public class ClearVerify
+{
+ static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos)
+ {
+ return verifier.VerifyTableStart(tablePos)
+ && verifier.VerifyField(tablePos, 4 /*Priority*/, 4 /*int*/, 4, false)
+ && verifier.VerifyTableEnd(tablePos);
+ }
+}
+
+}
diff --git a/HyperTizen/Flatbuffers/Color.cs b/HyperTizen/Flatbuffers/Color.cs
new file mode 100644
index 0000000..ca062f9
--- /dev/null
+++ b/HyperTizen/Flatbuffers/Color.cs
@@ -0,0 +1,55 @@
+//
+// automatically generated by the FlatBuffers compiler, do not modify
+//
+
+namespace hyperhdrnet
+{
+
+using global::System;
+using global::System.Collections.Generic;
+using global::Google.FlatBuffers;
+
+public struct Color : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); }
+ public static Color GetRootAsColor(ByteBuffer _bb) { return GetRootAsColor(_bb, new Color()); }
+ public static Color GetRootAsColor(ByteBuffer _bb, Color obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Color __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int Data { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)-1; } }
+ public int Duration { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)-1; } }
+
+ public static Offset CreateColor(FlatBufferBuilder builder,
+ int data = -1,
+ int duration = -1) {
+ builder.StartTable(2);
+ Color.AddDuration(builder, duration);
+ Color.AddData(builder, data);
+ return Color.EndColor(builder);
+ }
+
+ public static void StartColor(FlatBufferBuilder builder) { builder.StartTable(2); }
+ public static void AddData(FlatBufferBuilder builder, int data) { builder.AddInt(0, data, -1); }
+ public static void AddDuration(FlatBufferBuilder builder, int duration) { builder.AddInt(1, duration, -1); }
+ public static Offset EndColor(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset(o);
+ }
+}
+
+
+static public class ColorVerify
+{
+ static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos)
+ {
+ return verifier.VerifyTableStart(tablePos)
+ && verifier.VerifyField(tablePos, 4 /*Data*/, 4 /*int*/, 4, false)
+ && verifier.VerifyField(tablePos, 6 /*Duration*/, 4 /*int*/, 4, false)
+ && verifier.VerifyTableEnd(tablePos);
+ }
+}
+
+}
diff --git a/HyperTizen/Flatbuffers/Command.cs b/HyperTizen/Flatbuffers/Command.cs
new file mode 100644
index 0000000..e3c99af
--- /dev/null
+++ b/HyperTizen/Flatbuffers/Command.cs
@@ -0,0 +1,46 @@
+//
+// automatically generated by the FlatBuffers compiler, do not modify
+//
+
+namespace hyperhdrnet
+{
+
+public enum Command : byte
+{
+ NONE = 0,
+ Color = 1,
+ Image = 2,
+ Clear = 3,
+ Register = 4,
+};
+
+
+
+static public class CommandVerify
+{
+ static public bool Verify(Google.FlatBuffers.Verifier verifier, byte typeId, uint tablePos)
+ {
+ bool result = true;
+ switch((Command)typeId)
+ {
+ case Command.Color:
+ result = hyperhdrnet.ColorVerify.Verify(verifier, tablePos);
+ break;
+ case Command.Image:
+ result = hyperhdrnet.ImageVerify.Verify(verifier, tablePos);
+ break;
+ case Command.Clear:
+ result = hyperhdrnet.ClearVerify.Verify(verifier, tablePos);
+ break;
+ case Command.Register:
+ result = hyperhdrnet.RegisterVerify.Verify(verifier, tablePos);
+ break;
+ default: result = true;
+ break;
+ }
+ return result;
+ }
+}
+
+
+}
diff --git a/HyperTizen/Flatbuffers/Image.cs b/HyperTizen/Flatbuffers/Image.cs
new file mode 100644
index 0000000..989e803
--- /dev/null
+++ b/HyperTizen/Flatbuffers/Image.cs
@@ -0,0 +1,63 @@
+//
+// automatically generated by the FlatBuffers compiler, do not modify
+//
+
+namespace hyperhdrnet
+{
+
+using global::System;
+using global::System.Collections.Generic;
+using global::Google.FlatBuffers;
+
+public struct Image : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); }
+ public static Image GetRootAsImage(ByteBuffer _bb) { return GetRootAsImage(_bb, new Image()); }
+ public static Image GetRootAsImage(ByteBuffer _bb, Image obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Image __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public hyperhdrnet.ImageType DataType { get { int o = __p.__offset(4); return o != 0 ? (hyperhdrnet.ImageType)__p.bb.Get(o + __p.bb_pos) : hyperhdrnet.ImageType.NONE; } }
+ public TTable? Data() where TTable : struct, IFlatbufferObject { int o = __p.__offset(6); return o != 0 ? (TTable?)__p.__union(o + __p.bb_pos) : null; }
+ public hyperhdrnet.RawImage DataAsRawImage() { return Data().Value; }
+ public hyperhdrnet.NV12Image DataAsNV12Image() { return Data().Value; }
+ public int Duration { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)-1; } }
+
+ public static Offset CreateImage(FlatBufferBuilder builder,
+ hyperhdrnet.ImageType data_type = hyperhdrnet.ImageType.NONE,
+ int dataOffset = 0,
+ int duration = -1) {
+ builder.StartTable(3);
+ Image.AddDuration(builder, duration);
+ Image.AddData(builder, dataOffset);
+ Image.AddDataType(builder, data_type);
+ return Image.EndImage(builder);
+ }
+
+ public static void StartImage(FlatBufferBuilder builder) { builder.StartTable(3); }
+ public static void AddDataType(FlatBufferBuilder builder, hyperhdrnet.ImageType dataType) { builder.AddByte(0, (byte)dataType, 0); }
+ public static void AddData(FlatBufferBuilder builder, int dataOffset) { builder.AddOffset(1, dataOffset, 0); }
+ public static void AddDuration(FlatBufferBuilder builder, int duration) { builder.AddInt(2, duration, -1); }
+ public static Offset EndImage(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ builder.Required(o, 6); // data
+ return new Offset(o);
+ }
+}
+
+
+static public class ImageVerify
+{
+ static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos)
+ {
+ return verifier.VerifyTableStart(tablePos)
+ && verifier.VerifyField(tablePos, 4 /*DataType*/, 1 /*hyperhdrnet.ImageType*/, 1, false)
+ && verifier.VerifyUnion(tablePos, 4, 6 /*Data*/, hyperhdrnet.ImageTypeVerify.Verify, true)
+ && verifier.VerifyField(tablePos, 8 /*Duration*/, 4 /*int*/, 4, false)
+ && verifier.VerifyTableEnd(tablePos);
+ }
+}
+
+}
diff --git a/HyperTizen/Flatbuffers/ImageType.cs b/HyperTizen/Flatbuffers/ImageType.cs
new file mode 100644
index 0000000..f81a569
--- /dev/null
+++ b/HyperTizen/Flatbuffers/ImageType.cs
@@ -0,0 +1,38 @@
+//
+// automatically generated by the FlatBuffers compiler, do not modify
+//
+
+namespace hyperhdrnet
+{
+
+public enum ImageType : byte
+{
+ NONE = 0,
+ RawImage = 1,
+ NV12Image = 2,
+};
+
+
+
+static public class ImageTypeVerify
+{
+ static public bool Verify(Google.FlatBuffers.Verifier verifier, byte typeId, uint tablePos)
+ {
+ bool result = true;
+ switch((ImageType)typeId)
+ {
+ case ImageType.RawImage:
+ result = hyperhdrnet.RawImageVerify.Verify(verifier, tablePos);
+ break;
+ case ImageType.NV12Image:
+ result = hyperhdrnet.NV12ImageVerify.Verify(verifier, tablePos);
+ break;
+ default: result = true;
+ break;
+ }
+ return result;
+ }
+}
+
+
+}
diff --git a/HyperTizen/Flatbuffers/NV12Image.cs b/HyperTizen/Flatbuffers/NV12Image.cs
new file mode 100644
index 0000000..1931eee
--- /dev/null
+++ b/HyperTizen/Flatbuffers/NV12Image.cs
@@ -0,0 +1,99 @@
+//
+// automatically generated by the FlatBuffers compiler, do not modify
+//
+
+namespace hyperhdrnet
+{
+
+using global::System;
+using global::System.Collections.Generic;
+using global::Google.FlatBuffers;
+
+public struct NV12Image : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); }
+ public static NV12Image GetRootAsNV12Image(ByteBuffer _bb) { return GetRootAsNV12Image(_bb, new NV12Image()); }
+ public static NV12Image GetRootAsNV12Image(ByteBuffer _bb, NV12Image obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public NV12Image __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public byte DataY(int j) { int o = __p.__offset(4); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
+ public int DataYLength { get { int o = __p.__offset(4); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span GetDataYBytes() { return __p.__vector_as_span(4, 1); }
+#else
+ public ArraySegment? GetDataYBytes() { return __p.__vector_as_arraysegment(4); }
+#endif
+ public byte[] GetDataYArray() { return __p.__vector_as_array(4); }
+ public byte DataUv(int j) { int o = __p.__offset(6); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
+ public int DataUvLength { get { int o = __p.__offset(6); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span GetDataUvBytes() { return __p.__vector_as_span(6, 1); }
+#else
+ public ArraySegment? GetDataUvBytes() { return __p.__vector_as_arraysegment(6); }
+#endif
+ public byte[] GetDataUvArray() { return __p.__vector_as_array(6); }
+ public int Width { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+ public int Height { get { int o = __p.__offset(10); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+ public int StrideY { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+ public int StrideUv { get { int o = __p.__offset(14); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+
+ public static Offset CreateNV12Image(FlatBufferBuilder builder,
+ VectorOffset data_yOffset = default(VectorOffset),
+ VectorOffset data_uvOffset = default(VectorOffset),
+ int width = 0,
+ int height = 0,
+ int stride_y = 0,
+ int stride_uv = 0) {
+ builder.StartTable(6);
+ NV12Image.AddStrideUv(builder, stride_uv);
+ NV12Image.AddStrideY(builder, stride_y);
+ NV12Image.AddHeight(builder, height);
+ NV12Image.AddWidth(builder, width);
+ NV12Image.AddDataUv(builder, data_uvOffset);
+ NV12Image.AddDataY(builder, data_yOffset);
+ return NV12Image.EndNV12Image(builder);
+ }
+
+ public static void StartNV12Image(FlatBufferBuilder builder) { builder.StartTable(6); }
+ public static void AddDataY(FlatBufferBuilder builder, VectorOffset dataYOffset) { builder.AddOffset(0, dataYOffset.Value, 0); }
+ public static VectorOffset CreateDataYVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateDataYVectorBlock(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); }
+ public static VectorOffset CreateDataYVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(1, data.Count, 1); builder.Add(data); return builder.EndVector(); }
+ public static VectorOffset CreateDataYVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); }
+ public static void StartDataYVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+ public static void AddDataUv(FlatBufferBuilder builder, VectorOffset dataUvOffset) { builder.AddOffset(1, dataUvOffset.Value, 0); }
+ public static VectorOffset CreateDataUvVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateDataUvVectorBlock(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); }
+ public static VectorOffset CreateDataUvVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(1, data.Count, 1); builder.Add(data); return builder.EndVector(); }
+ public static VectorOffset CreateDataUvVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); }
+ public static void StartDataUvVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+ public static void AddWidth(FlatBufferBuilder builder, int width) { builder.AddInt(2, width, 0); }
+ public static void AddHeight(FlatBufferBuilder builder, int height) { builder.AddInt(3, height, 0); }
+ public static void AddStrideY(FlatBufferBuilder builder, int strideY) { builder.AddInt(4, strideY, 0); }
+ public static void AddStrideUv(FlatBufferBuilder builder, int strideUv) { builder.AddInt(5, strideUv, 0); }
+ public static Offset EndNV12Image(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset(o);
+ }
+}
+
+
+static public class NV12ImageVerify
+{
+ static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos)
+ {
+ return verifier.VerifyTableStart(tablePos)
+ && verifier.VerifyVectorOfData(tablePos, 4 /*DataY*/, 1 /*byte*/, false)
+ && verifier.VerifyVectorOfData(tablePos, 6 /*DataUv*/, 1 /*byte*/, false)
+ && verifier.VerifyField(tablePos, 8 /*Width*/, 4 /*int*/, 4, false)
+ && verifier.VerifyField(tablePos, 10 /*Height*/, 4 /*int*/, 4, false)
+ && verifier.VerifyField(tablePos, 12 /*StrideY*/, 4 /*int*/, 4, false)
+ && verifier.VerifyField(tablePos, 14 /*StrideUv*/, 4 /*int*/, 4, false)
+ && verifier.VerifyTableEnd(tablePos);
+ }
+}
+
+}
diff --git a/HyperTizen/Flatbuffers/RawImage.cs b/HyperTizen/Flatbuffers/RawImage.cs
new file mode 100644
index 0000000..a3e14e5
--- /dev/null
+++ b/HyperTizen/Flatbuffers/RawImage.cs
@@ -0,0 +1,72 @@
+//
+// automatically generated by the FlatBuffers compiler, do not modify
+//
+
+namespace hyperhdrnet
+{
+
+using global::System;
+using global::System.Collections.Generic;
+using global::Google.FlatBuffers;
+
+public struct RawImage : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); }
+ public static RawImage GetRootAsRawImage(ByteBuffer _bb) { return GetRootAsRawImage(_bb, new RawImage()); }
+ public static RawImage GetRootAsRawImage(ByteBuffer _bb, RawImage obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public RawImage __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public byte Data(int j) { int o = __p.__offset(4); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
+ public int DataLength { get { int o = __p.__offset(4); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span GetDataBytes() { return __p.__vector_as_span(4, 1); }
+#else
+ public ArraySegment? GetDataBytes() { return __p.__vector_as_arraysegment(4); }
+#endif
+ public byte[] GetDataArray() { return __p.__vector_as_array(4); }
+ public int Width { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)-1; } }
+ public int Height { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)-1; } }
+
+ public static Offset CreateRawImage(FlatBufferBuilder builder,
+ VectorOffset dataOffset = default(VectorOffset),
+ int width = -1,
+ int height = -1) {
+ builder.StartTable(3);
+ RawImage.AddHeight(builder, height);
+ RawImage.AddWidth(builder, width);
+ RawImage.AddData(builder, dataOffset);
+ return RawImage.EndRawImage(builder);
+ }
+
+ public static void StartRawImage(FlatBufferBuilder builder) { builder.StartTable(3); }
+ public static void AddData(FlatBufferBuilder builder, VectorOffset dataOffset) { builder.AddOffset(0, dataOffset.Value, 0); }
+ public static VectorOffset CreateDataVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateDataVectorBlock(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); }
+ public static VectorOffset CreateDataVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(1, data.Count, 1); builder.Add(data); return builder.EndVector(); }
+ public static VectorOffset CreateDataVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); }
+ public static void StartDataVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+ public static void AddWidth(FlatBufferBuilder builder, int width) { builder.AddInt(1, width, -1); }
+ public static void AddHeight(FlatBufferBuilder builder, int height) { builder.AddInt(2, height, -1); }
+ public static Offset EndRawImage(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset(o);
+ }
+}
+
+
+static public class RawImageVerify
+{
+ static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos)
+ {
+ return verifier.VerifyTableStart(tablePos)
+ && verifier.VerifyVectorOfData(tablePos, 4 /*Data*/, 1 /*byte*/, false)
+ && verifier.VerifyField(tablePos, 6 /*Width*/, 4 /*int*/, 4, false)
+ && verifier.VerifyField(tablePos, 8 /*Height*/, 4 /*int*/, 4, false)
+ && verifier.VerifyTableEnd(tablePos);
+ }
+}
+
+}
diff --git a/HyperTizen/Flatbuffers/Register.cs b/HyperTizen/Flatbuffers/Register.cs
new file mode 100644
index 0000000..c6d4e32
--- /dev/null
+++ b/HyperTizen/Flatbuffers/Register.cs
@@ -0,0 +1,62 @@
+//
+// automatically generated by the FlatBuffers compiler, do not modify
+//
+
+namespace hyperhdrnet
+{
+
+using global::System;
+using global::System.Collections.Generic;
+using global::Google.FlatBuffers;
+
+public struct Register : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); }
+ public static Register GetRootAsRegister(ByteBuffer _bb) { return GetRootAsRegister(_bb, new Register()); }
+ public static Register GetRootAsRegister(ByteBuffer _bb, Register obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Register __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public string Origin { get { int o = __p.__offset(4); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
+#if ENABLE_SPAN_T
+ public Span GetOriginBytes() { return __p.__vector_as_span(4, 1); }
+#else
+ public ArraySegment? GetOriginBytes() { return __p.__vector_as_arraysegment(4); }
+#endif
+ public byte[] GetOriginArray() { return __p.__vector_as_array(4); }
+ public int Priority { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+
+ public static Offset CreateRegister(FlatBufferBuilder builder,
+ StringOffset originOffset = default(StringOffset),
+ int priority = 0) {
+ builder.StartTable(2);
+ Register.AddPriority(builder, priority);
+ Register.AddOrigin(builder, originOffset);
+ return Register.EndRegister(builder);
+ }
+
+ public static void StartRegister(FlatBufferBuilder builder) { builder.StartTable(2); }
+ public static void AddOrigin(FlatBufferBuilder builder, StringOffset originOffset) { builder.AddOffset(0, originOffset.Value, 0); }
+ public static void AddPriority(FlatBufferBuilder builder, int priority) { builder.AddInt(1, priority, 0); }
+ public static Offset EndRegister(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ builder.Required(o, 4); // origin
+ return new Offset(o);
+ }
+}
+
+
+static public class RegisterVerify
+{
+ static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos)
+ {
+ return verifier.VerifyTableStart(tablePos)
+ && verifier.VerifyString(tablePos, 4 /*Origin*/, true)
+ && verifier.VerifyField(tablePos, 6 /*Priority*/, 4 /*int*/, 4, false)
+ && verifier.VerifyTableEnd(tablePos);
+ }
+}
+
+}
diff --git a/HyperTizen/Flatbuffers/Reply.cs b/HyperTizen/Flatbuffers/Reply.cs
new file mode 100644
index 0000000..5f9d88a
--- /dev/null
+++ b/HyperTizen/Flatbuffers/Reply.cs
@@ -0,0 +1,69 @@
+//
+// automatically generated by the FlatBuffers compiler, do not modify
+//
+
+namespace hyperhdrnet
+{
+
+using global::System;
+using global::System.Collections.Generic;
+using global::Google.FlatBuffers;
+
+public struct Reply : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); }
+ public static Reply GetRootAsReply(ByteBuffer _bb) { return GetRootAsReply(_bb, new Reply()); }
+ public static Reply GetRootAsReply(ByteBuffer _bb, Reply obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public static bool VerifyReply(ByteBuffer _bb) {Google.FlatBuffers.Verifier verifier = new Google.FlatBuffers.Verifier(_bb); return verifier.VerifyBuffer("", false, ReplyVerify.Verify); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Reply __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public string Error { get { int o = __p.__offset(4); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
+#if ENABLE_SPAN_T
+ public Span GetErrorBytes() { return __p.__vector_as_span(4, 1); }
+#else
+ public ArraySegment? GetErrorBytes() { return __p.__vector_as_arraysegment(4); }
+#endif
+ public byte[] GetErrorArray() { return __p.__vector_as_array(4); }
+ public int Video { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)-1; } }
+ public int Registered { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)-1; } }
+
+ public static Offset CreateReply(FlatBufferBuilder builder,
+ StringOffset errorOffset = default(StringOffset),
+ int video = -1,
+ int registered = -1) {
+ builder.StartTable(3);
+ Reply.AddRegistered(builder, registered);
+ Reply.AddVideo(builder, video);
+ Reply.AddError(builder, errorOffset);
+ return Reply.EndReply(builder);
+ }
+
+ public static void StartReply(FlatBufferBuilder builder) { builder.StartTable(3); }
+ public static void AddError(FlatBufferBuilder builder, StringOffset errorOffset) { builder.AddOffset(0, errorOffset.Value, 0); }
+ public static void AddVideo(FlatBufferBuilder builder, int video) { builder.AddInt(1, video, -1); }
+ public static void AddRegistered(FlatBufferBuilder builder, int registered) { builder.AddInt(2, registered, -1); }
+ public static Offset EndReply(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset(o);
+ }
+ public static void FinishReplyBuffer(FlatBufferBuilder builder, Offset offset) { builder.Finish(offset.Value); }
+ public static void FinishSizePrefixedReplyBuffer(FlatBufferBuilder builder, Offset offset) { builder.FinishSizePrefixed(offset.Value); }
+}
+
+
+static public class ReplyVerify
+{
+ static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos)
+ {
+ return verifier.VerifyTableStart(tablePos)
+ && verifier.VerifyString(tablePos, 4 /*Error*/, false)
+ && verifier.VerifyField(tablePos, 6 /*Video*/, 4 /*int*/, 4, false)
+ && verifier.VerifyField(tablePos, 8 /*Registered*/, 4 /*int*/, 4, false)
+ && verifier.VerifyTableEnd(tablePos);
+ }
+}
+
+}
diff --git a/HyperTizen/Flatbuffers/Request.cs b/HyperTizen/Flatbuffers/Request.cs
new file mode 100644
index 0000000..6f26360
--- /dev/null
+++ b/HyperTizen/Flatbuffers/Request.cs
@@ -0,0 +1,63 @@
+//
+// automatically generated by the FlatBuffers compiler, do not modify
+//
+
+namespace hyperhdrnet
+{
+
+using global::System;
+using global::System.Collections.Generic;
+using global::Google.FlatBuffers;
+
+public struct Request : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); }
+ public static Request GetRootAsRequest(ByteBuffer _bb) { return GetRootAsRequest(_bb, new Request()); }
+ public static Request GetRootAsRequest(ByteBuffer _bb, Request obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public static bool VerifyRequest(ByteBuffer _bb) {Google.FlatBuffers.Verifier verifier = new Google.FlatBuffers.Verifier(_bb); return verifier.VerifyBuffer("", false, RequestVerify.Verify); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Request __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public hyperhdrnet.Command CommandType { get { int o = __p.__offset(4); return o != 0 ? (hyperhdrnet.Command)__p.bb.Get(o + __p.bb_pos) : hyperhdrnet.Command.NONE; } }
+ public TTable? Command() where TTable : struct, IFlatbufferObject { int o = __p.__offset(6); return o != 0 ? (TTable?)__p.__union(o + __p.bb_pos) : null; }
+ public hyperhdrnet.Color CommandAsColor() { return Command().Value; }
+ public hyperhdrnet.Image CommandAsImage() { return Command().Value; }
+ public hyperhdrnet.Clear CommandAsClear() { return Command().Value; }
+ public hyperhdrnet.Register CommandAsRegister() { return Command().Value; }
+
+ public static Offset CreateRequest(FlatBufferBuilder builder,
+ hyperhdrnet.Command command_type = hyperhdrnet.Command.NONE,
+ int commandOffset = 0) {
+ builder.StartTable(2);
+ Request.AddCommand(builder, commandOffset);
+ Request.AddCommandType(builder, command_type);
+ return Request.EndRequest(builder);
+ }
+
+ public static void StartRequest(FlatBufferBuilder builder) { builder.StartTable(2); }
+ public static void AddCommandType(FlatBufferBuilder builder, hyperhdrnet.Command commandType) { builder.AddByte(0, (byte)commandType, 0); }
+ public static void AddCommand(FlatBufferBuilder builder, int commandOffset) { builder.AddOffset(1, commandOffset, 0); }
+ public static Offset EndRequest(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ builder.Required(o, 6); // command
+ return new Offset(o);
+ }
+ public static void FinishRequestBuffer(FlatBufferBuilder builder, Offset offset) { builder.Finish(offset.Value); }
+ public static void FinishSizePrefixedRequestBuffer(FlatBufferBuilder builder, Offset offset) { builder.FinishSizePrefixed(offset.Value); }
+}
+
+
+static public class RequestVerify
+{
+ static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos)
+ {
+ return verifier.VerifyTableStart(tablePos)
+ && verifier.VerifyField(tablePos, 4 /*CommandType*/, 1 /*hyperhdrnet.Command*/, 1, false)
+ && verifier.VerifyUnion(tablePos, 4, 6 /*Command*/, hyperhdrnet.CommandVerify.Verify, true)
+ && verifier.VerifyTableEnd(tablePos);
+ }
+}
+
+}
diff --git a/HyperTizen/Globals.cs b/HyperTizen/Globals.cs
new file mode 100644
index 0000000..0db133b
--- /dev/null
+++ b/HyperTizen/Globals.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HyperTizen
+{
+ public sealed class Globals
+ {
+ private static readonly Globals instance = new Globals();
+
+ // Explicit static constructor to tell C# compiler
+ // not to mark type as beforefieldinit
+ static Globals()
+ {
+ }
+
+ private Globals()
+ {
+ }
+
+ public static Globals Instance
+ {
+ get
+ {
+ return instance;
+ }
+ }
+ public void SetConfig()
+ {
+ ServerIp = "192.168.69.200";//25
+ ServerPort = 19400;
+ Width = 480;
+ Height = 270;
+ }
+
+ public string ServerIp; //IP of hyperhdr server
+ public int ServerPort; //Port of hyperhdr server
+ public int Width; //Capture Width
+ public int Height; //Capture Height
+ }
+}
diff --git a/HyperTizen/HyperTizen.csproj b/HyperTizen/HyperTizen.csproj
index 327e540..173dfb1 100644
--- a/HyperTizen/HyperTizen.csproj
+++ b/HyperTizen/HyperTizen.csproj
@@ -4,6 +4,7 @@
Exe
tizen90
+ true
@@ -19,9 +20,11 @@
+
+
diff --git a/HyperTizen/HyperTizen.csproj.user b/HyperTizen/HyperTizen.csproj.user
new file mode 100644
index 0000000..0f14913
--- /dev/null
+++ b/HyperTizen/HyperTizen.csproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/HyperTizen/Networking.cs b/HyperTizen/Networking.cs
new file mode 100644
index 0000000..d7485ee
--- /dev/null
+++ b/HyperTizen/Networking.cs
@@ -0,0 +1,179 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading.Tasks;
+using Google.FlatBuffers;
+using hyperhdrnet;
+
+namespace HyperTizen
+{
+ public static class Networking
+ {
+ public static TcpClient client;
+ public static NetworkStream stream;
+
+ public static void SendRegister()
+ {
+ client = new TcpClient(Globals.Instance.ServerIp, Globals.Instance.ServerPort);
+ stream = Networking.client.GetStream();
+ byte[] registrationMessage = Networking.CreateRegistrationMessage(true);
+ var header = new byte[4];
+ header[0] = (byte)((registrationMessage.Length >> 24) & 0xFF);
+ header[1] = (byte)((registrationMessage.Length >> 16) & 0xFF);
+ header[2] = (byte)((registrationMessage.Length >> 8) & 0xFF);
+ header[3] = (byte)((registrationMessage.Length) & 0xFF);
+ stream.Write(header, 0, header.Length);
+ stream.Write(registrationMessage, 0, registrationMessage.Length);
+ ReadRegisterReply();
+ Debug.WriteLine("Sent Registration");
+ }
+
+ public static void SendImage(byte[] yData, byte[] uvData, int width, int height)
+ {
+ //if (!client.Connected)
+ // return;
+ byte[] message = CreateFlatBufferMessage(yData, uvData, width, height);
+ SendMessageAndReceiveReply(message);
+ }
+
+ static byte[] CreateFlatBufferMessage(byte[] yData, byte[] uvData, int width, int height)
+ {
+ if (!client.Connected)
+ return null;
+ var builder = new FlatBufferBuilder(yData.Length + uvData.Length + 100);
+
+ // Erstelle FlatBuffer Vektoren für Y- und UV-Daten
+ var yVector = NV12Image.CreateDataYVector(builder, yData);
+ var uvVector = NV12Image.CreateDataUvVector(builder, uvData);
+
+ // NV12Image Struktur erstellen
+ NV12Image.StartNV12Image(builder);
+ NV12Image.AddDataY(builder, yVector);
+ NV12Image.AddDataUv(builder, uvVector);
+ NV12Image.AddWidth(builder, width);
+ NV12Image.AddHeight(builder, height);
+ NV12Image.AddStrideY(builder, width); // Falls kein spezieller Stride nötig ist
+ NV12Image.AddStrideUv(builder, width);
+ var nv12Image = NV12Image.EndNV12Image(builder);
+
+ // Image union mit NV12Image erstellen
+ Image.StartImage(builder);
+ Image.AddDataType(builder, ImageType.NV12Image);
+ Image.AddData(builder, nv12Image.Value);
+ Image.AddDuration(builder, -1); // Falls eine bestimmte Dauer nötig ist, ändern
+ var imageOffset = Image.EndImage(builder);
+
+ // Request mit Image als Kommando erstellen
+ Request.StartRequest(builder);
+ Request.AddCommandType(builder, Command.Image);
+ Request.AddCommand(builder, imageOffset.Value);
+ var requestOffset = Request.EndRequest(builder);
+
+ // FlatBuffer fertigstellen
+ builder.Finish(requestOffset.Value);
+ return builder.SizedByteArray();
+ }
+
+ static Reply ParseReply(byte[] receivedData)
+ {
+ // FlatBuffer aus empfangenen Daten parsen
+ var byteBuffer = new ByteBuffer(receivedData,4); //shift for header
+ return Reply.GetRootAsReply(byteBuffer);
+ }
+
+ public static byte[] CreateRegistrationMessage(bool subscribe)
+ {
+ if (!client.Connected)
+ return null;
+
+ var builder = new FlatBufferBuilder(256);
+
+ var originOffset = builder.CreateString("HyperTizen");
+
+ // Registrierungsstruktur erstellen
+ Register.StartRegister(builder);
+ Register.AddPriority(builder, 123);
+ Register.AddOrigin(builder, originOffset);
+ var registerOffset = Register.EndRegister(builder);
+
+ // Request mit Register-Kommando erstellen
+ Request.StartRequest(builder);
+ Request.AddCommandType(builder, Command.Register);
+ Request.AddCommand(builder, registerOffset.Value);
+ var requestOffset = Request.EndRequest(builder);
+
+ // FlatBuffer-Nachricht fertigstellen
+ builder.Finish(requestOffset.Value);
+ return builder.SizedByteArray();
+ }
+
+ public static void ReadRegisterReply()
+ {
+ if (!client.Connected)
+ return;
+
+ byte[] buffer = new byte[1024];
+ int bytesRead = stream.Read(buffer, 0, buffer.Length);
+ if (bytesRead > 0)
+ {
+ byte[] replyData = new byte[bytesRead];
+ Array.Copy(buffer, replyData, bytesRead);
+
+ Reply reply = ParseReply(replyData);
+ Debug.WriteLine($"Registered: {reply.Registered}");
+ }
+ }
+
+ static void SendMessageAndReceiveReply(byte[] message)
+ {
+ try
+ {
+ if (!client.Connected)
+ return;
+ {
+
+ var header = new byte[4];
+ header[0] = (byte)((message.Length >> 24) & 0xFF);
+ header[1] = (byte)((message.Length >> 16) & 0xFF);
+ header[2] = (byte)((message.Length >> 8) & 0xFF);
+ header[3] = (byte)((message.Length) & 0xFF);
+ stream.Write(header, 0, header.Length);
+
+ Debug.WriteLine(message.Length);
+ stream.Write(message, 0, message.Length);
+ Debug.WriteLine("Data sent. Waiting for Answer");
+
+ // Antwort empfangen
+ byte[] buffer = new byte[1024];
+ int bytesRead = stream.Read(buffer, 0, buffer.Length);
+ if (bytesRead > 0)
+ {
+
+ byte[] replyData = new byte[bytesRead];
+ Array.Copy(buffer, replyData, bytesRead);
+ string test = BitConverter.ToString(replyData);
+ // Antwort mit FlatBuffers parsen
+ Reply reply = ParseReply(replyData);
+
+ // Antwort ausgeben
+ Debug.WriteLine($"Error: {reply.Error}");
+ Debug.WriteLine($"Video: {reply.Video}");
+ Debug.WriteLine($"Registered: {reply.Registered}");
+ }
+ else
+ {
+ Debug.WriteLine("No Answer from Server.");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine("Error Sending/Receiving: " + ex.Message);
+ }
+ }
+
+ }
+}
diff --git a/HyperTizen/WebSocket/HyperionClient.cs b/HyperTizen/WebSocket/HyperionClient.cs
index bc940b5..499a66d 100644
--- a/HyperTizen/WebSocket/HyperionClient.cs
+++ b/HyperTizen/WebSocket/HyperionClient.cs
@@ -1,72 +1,196 @@
-using Newtonsoft.Json;
-using System.Threading.Tasks;
-using Tizen.Applications;
-using HyperTizen.WebSocket.DataTypes;
-using System.Net.WebSockets;
-using System.Text;
-using System;
-using System.Threading;
-
-namespace HyperTizen.WebSocket
-{
- internal class HyperionClient
- {
- WebSocketClient client;
- public HyperionClient()
- {
- if (!Preference.Contains("rpcServer")) return;
- client = new WebSocketClient(Preference.Get("rpcServer"));
- Task.Run(() => client.ConnectAsync());
- Task.Run(() => Start());
- }
-
- public void UpdateURI(string uri)
- {
- if (client?.client != null && client.client.State == WebSocketState.Open)
- {
- client.client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
- }
-
- client = new WebSocketClient(uri);
- Task.Run(() => client.ConnectAsync());
- }
-
- public async Task Start(bool shouldStart = false)
- {
- if (client != null && Capturer.GetCondition())
- {
- while (App.Configuration.Enabled || shouldStart)
- {
- Color[] colors = Capturer.GetColors();
- string image = Capturer.ToImage(colors);
-
- if (client?.client?.State == WebSocketState.Open)
- {
- ImageCommand imgCmd = new ImageCommand(image);
- string message = JsonConvert.SerializeObject(imgCmd);
- var buffer = Encoding.UTF8.GetBytes(message);
- await client.client.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
- }
-
- if (App.Configuration.Enabled && shouldStart) shouldStart = false;
- else if (!App.Configuration.Enabled && shouldStart) App.Configuration.Enabled = true;
- }
- }
- }
-
- public async Task Stop()
- {
- if (App.Configuration.Enabled) App.Configuration.Enabled = false;
- Color[] colors = Capturer.GetColors();
- string image = Capturer.ToImage(colors);
-
- if (client?.client?.State == WebSocketState.Open)
- {
- ImageCommand imgCmd = new ImageCommand(image);
- string message = JsonConvert.SerializeObject(imgCmd);
- var buffer = Encoding.UTF8.GetBytes(message);
- await client.client.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
- }
- }
- }
+using Newtonsoft.Json;
+using System.Threading.Tasks;
+using Tizen.Applications;
+using HyperTizen.WebSocket.DataTypes;
+using System.Net.WebSockets;
+using System.Text;
+using System;
+using System.Threading;
+using System.Runtime.InteropServices;
+using SkiaSharp;
+using Tizen.NUI;
+using System.Diagnostics;
+using System.Linq;
+using Tizen.Uix.Tts;
+using System.Net.Sockets;
+using Tizen.Applications.RPCPort;
+using System.IO;
+using Tizen.Messaging.Messages;
+using System.Linq.Expressions;
+
+namespace HyperTizen.WebSocket
+{
+ public static class VideoCapture
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Info_t
+ {
+ public Int32 iGivenBufferSize1 { get; set; } //a6[0] = 0 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize2
+ public Int32 iGivenBufferSize2 { get; set; } //a6[1] = 4 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize1
+ public Int32 iWidth { get; set; } //a6[2] = 8 //ref: IceWater "caputre_param.ret_width"
+ public Int32 iHeight { get; set; } //a6[3] = 12 //ref: IceWater "caputre_param.ret_height"
+ public IntPtr pImageY { get; set; } //a6[4] // = 16 dest of memcopy copys v31 in adress with sizeof(needed buffer size(i think)) into this
+ public IntPtr pImageUV { get; set; } //a6[5] // = 20 use this! dest of memcopy copys v223 in adress with sizeof(needed buffer size) into this
+ public Int32 iRetColorFormat { get; set; } //a6[6] // = 24 //ref: IceWater "color format is"(YUV420 = 0, YUV422 = 1, YUV444 = 2 , None = 3, Everything else = Error)
+ public Int32 unknown2 { get; set; } //a6[7] // = 28
+ public Int32 capture3DMode { get; set; } // = 32 //ref: "Capture 3D Mode is DRM_SDP_3D_2D [%d:%s]" (DRM_SDP_3D_2D = 0, DRM_SDP_3D_FRAMEPACKING = 1, DRM_SDP_3D_FRAMESEQ = 2, DRM_SDP_3D_TOPBOTTOM = 3, DRM_SDP_3D_SIDEBYSIDE = 4)
+ //unk3 a6[15] // = 60
+ }
+ //int (__fastcall *)(_DWORD, _DWORD, _DWORD)
+ [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen")] //record with ui
+ unsafe private static extern int CaptureScreen(int w, int h, ref Info_t pInfo);
+ [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_video_only")] // without ui
+ private static extern int CaptureScreenVideo(int w, int h, ref Info_t pInfo);
+ [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_video_only_crop")] // cropped
+ private static extern int CaptureScreenCrop(int w, int h, ref Info_t pInfo, int iCapture3DMode, int cropW, int cropH);
+ //Main Func Errors:
+ //-1 "Input Pram is Wrong"
+ //-1,-2,-3,-5...negative numbers without 4 "Failed scaler_capture"
+
+ //Sub Func Errors
+ //-2 Error: capture type %s, plane %s video only %d
+ //-1 req size less or equal that crop size or non video for videoonly found
+ //-1 Home Screen & yt crop size, capture lock, video info related
+ //-4 Netflix/ Widevine Drm Stuff
+
+ unsafe public static void DoCapture()
+ {
+ //HookManager.HookDLog(); //https://github.com/lolp1/Process.NET/tree/master
+ var width = 480;//480 960
+ var height = 270;//270 540
+
+ var yBufferSize = width * height * 2;
+
+ var uvBufferSizeYUV420 = (width / 2) * (height / 2);
+ var uvBufferSizeYUV422 = (width / 2) * height;
+ var uvBufferSizeYUV444 = width * height;
+
+ int NV12ySize = Globals.Instance.Width * Globals.Instance.Height;
+ int NV12uvSize = (Globals.Instance.Width * Globals.Instance.Height) / 2; // UV-Plane ist halb so groß wie Y-Plane in NV12
+
+ Info_t info = new Info_t();
+ info.iGivenBufferSize1 = NV12ySize;
+ info.iGivenBufferSize2 = NV12uvSize;
+ //info.iWidth = width;
+ //info.iHeight = height;
+ info.pImageY = Marshal.AllocHGlobal(NV12ySize);
+ info.pImageUV = Marshal.AllocHGlobal(NV12uvSize);
+ //info.iRetColorFormat = 0;
+ //info.capture3DMode = 0;
+
+ //int result = CaptureScreenCrop(width, height, ref info,0, width+10, height+10);
+ int result = CaptureScreen(Globals.Instance.Width, Globals.Instance.Height, ref info);
+ if (result < 0)
+ {
+ switch (result)
+ {
+ case -4:
+ Debug.WriteLine("CaptureScreen Result: -4 [Netflix/ Widevine Drm Error]");
+ break;
+ case -1:
+ Debug.WriteLine("CaptureScreen Result: -1 [Input Pram is Wrong / req size less or equal that crop size / non video for videoonly found]");
+ break;
+ case -2:
+ Debug.WriteLine("CaptureScreen Result: -2 [capture type %s, plane %s video only %d / Failed scaler_capture]");
+ break;
+ default:
+ throw new Exception("New Exception. Please Report! With result:" + result.ToString());
+ break;
+ }
+
+ return;
+ }
+
+
+ byte[] managedArrayY = new byte[NV12ySize];
+ Marshal.Copy(info.pImageY, managedArrayY, 0, NV12ySize);
+
+ byte[] managedArrayUV = new byte[NV12uvSize];
+ Marshal.Copy(info.pImageUV, managedArrayUV, 0, NV12uvSize);
+
+ bool hasAllZeroes1 = managedArrayY.All(singleByte => singleByte == 0);
+ bool hasAllZeroes2 = managedArrayUV.All(singleByte => singleByte == 0);
+ if (hasAllZeroes1 && hasAllZeroes2)
+ throw new Exception("Sanity check Error");
+
+ /*
+ var stringByte1 = Convert.ToBase64String(managedArray1);
+ var stringByte2 = Convert.ToBase64String(managedArray2);
+ Debug.WriteLine(stringByte1);
+ Debug.WriteLine(stringByte2);
+ */
+ //(managedArrayY, managedArrayUV) = GenerateDummyYUVColor(Globals.Instance.Width, Globals.Instance.Height);
+
+ Networking.SendImage(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height);
+
+
+ }
+
+ public static (byte[] yData, byte[] uvData) GenerateDummyYUVRandom(int width, int height)
+ {
+ int ySize = width * height;
+ int uvSize = (width * height) / 2; // UV-Plane ist halb so groß wie Y-Plane in NV12
+
+ byte[] yData = new byte[ySize]; // Y-Plane
+ byte[] uvData = new byte[uvSize]; // Interleaved UV-Plane (VU VU VU ...)
+
+ Random rnd = new Random();
+ rnd.NextBytes(yData); // Zufallswerte für Y (Helligkeit)
+ rnd.NextBytes(uvData); // Zufallswerte für UV (Farbinformation)
+
+ return (yData, uvData);
+ }
+
+ public static (byte[] yData, byte[] uvData) GenerateDummyYUVColor(int width, int height)
+ {
+ int ySize = width * height;
+ int uvSize = (width * height) / 2; // UV-Plane ist halb so groß wie Y-Plane in NV12
+
+ byte[] yData = new byte[ySize]; // Y-Plane
+ byte[] uvData = new byte[uvSize]; // Interleaved UV-Plane (VU VU VU ...)
+
+ // Set Y (luminance) to a value that represents brightness
+ for (int i = 0; i < ySize; i++)
+ {
+ yData[i] = 128; // You can adjust this value for darker or brighter green
+ }
+
+ // Set U and V values for green
+ for (int i = 0; i < uvSize; i += 2)
+ {
+ uvData[i] = 128; // U component (no red)
+ uvData[i + 1] = 255; // V component (max green)
+ }
+
+ return (yData, uvData);
+ }
+
+ }
+
+ internal class HyperionClient
+ {
+ public HyperionClient()
+ {
+ Task.Run(() => Start());
+ }
+
+ public void UpdateURI(string uri)
+ {
+
+ }
+
+ public async Task Start(bool shouldStart = false)
+ {
+ Globals.Instance.SetConfig();
+ if (Networking.client == null || Networking.client.Connected)
+ Networking.SendRegister();
+ while (Networking.client.Connected)
+ VideoCapture.DoCapture();
+ }
+
+ public async Task Stop()
+ {
+
+ }
+ }
}
\ No newline at end of file
diff --git a/HyperTizen/tizen-manifest.xml b/HyperTizen/tizen-manifest.xml
index 59fe390..03949fe 100644
--- a/HyperTizen/tizen-manifest.xml
+++ b/HyperTizen/tizen-manifest.xml
@@ -1,8 +1,8 @@
-
+
Reis Can
-
+
HyperTizen.png
@@ -11,6 +11,9 @@
http://tizen.org/privilege/notification
http://tizen.org/privilege/internet
+ http://developer.samsung.com/privilege/drmplay
+ http://developer.samsung.com/privilege/drminfo
+ http://developer.samsung.com/privilege/esplay
diff --git a/HyperTizen/tizen_dotnet_project.yaml b/HyperTizen/tizen_dotnet_project.yaml
index c9c52c1..798149d 100644
--- a/HyperTizen/tizen_dotnet_project.yaml
+++ b/HyperTizen/tizen_dotnet_project.yaml
@@ -1,9 +1,9 @@
-# csproj file path
-csproj_file: HyperTizen.csproj
-
-# files monitored for dirty/modified status
-files:
- - HyperTizen.csproj
- - HyperTizen_App.cs
- - tizen-manifest.xml
- - shared/res/HyperTizen.png
\ No newline at end of file
+# csproj file path
+csproj_file: HyperTizen.csproj
+
+# files monitored for dirty/modified status
+files:
+ - HyperTizen.csproj
+ - HyperTizen_App.cs
+ - tizen-manifest.xml
+ - shared/res/HyperTizen.png
From 30d40bae710f71e5bdf1f05a99f8df2ae2ce73fe Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Wed, 5 Mar 2025 23:56:28 +0100
Subject: [PATCH 02/13] Cleanup and fix hardcoded stuff
translated code comment
removed old code
named classes right
removed hardcoded config stuff to use the ui values
added notifications on error
---
HyperTizen/Globals.cs | 5 +-
HyperTizen/HyperTizen_App.cs | 8 --
HyperTizen/HyperionClient.cs | 50 +++++++++
HyperTizen/VideoCapture.cs | 201 +++++++++++++++++++++++++++++++++++
4 files changed, 255 insertions(+), 9 deletions(-)
create mode 100644 HyperTizen/HyperionClient.cs
create mode 100644 HyperTizen/VideoCapture.cs
diff --git a/HyperTizen/Globals.cs b/HyperTizen/Globals.cs
index 0db133b..0d44138 100644
--- a/HyperTizen/Globals.cs
+++ b/HyperTizen/Globals.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Tizen.Applications;
namespace HyperTizen
{
@@ -29,8 +30,9 @@ public static Globals Instance
}
public void SetConfig()
{
- ServerIp = "192.168.69.200";//25
+ ServerIp = Preference.Contains("rpcServer") ? Preference.Get("rpcServer") : null; //"192.168.69.200";
ServerPort = 19400;
+ Enabled = bool.Parse(Preference.Get("enabled"));
Width = 480;
Height = 270;
}
@@ -39,5 +41,6 @@ public void SetConfig()
public int ServerPort; //Port of hyperhdr server
public int Width; //Capture Width
public int Height; //Capture Height
+ public bool Enabled; //Is the service enabled
}
}
diff --git a/HyperTizen/HyperTizen_App.cs b/HyperTizen/HyperTizen_App.cs
index f3e148c..037657a 100644
--- a/HyperTizen/HyperTizen_App.cs
+++ b/HyperTizen/HyperTizen_App.cs
@@ -1,7 +1,6 @@
using Tizen.Applications;
using Tizen.Applications.Notifications;
using Tizen.System;
-using HyperTizen.WebSocket;
using System.Threading.Tasks;
namespace HyperTizen
@@ -13,7 +12,6 @@ protected override void OnCreate()
{
base.OnCreate();
if (!Preference.Contains("enabled")) Preference.Set("enabled", "false");
- Task.Run(() => WebSocketServer.StartServerAsync());
Display.StateChanged += Display_StateChanged;
client = new HyperionClient();
}
@@ -25,7 +23,6 @@ private void Display_StateChanged(object sender, DisplayStateChangedEventArgs e)
Task.Run(() => client.Stop());
} else if (e.State == DisplayState.Normal)
{
- Configuration.Enabled = bool.Parse(Preference.Get("enabled"));
Task.Run(() => client.Start());
}
}
@@ -71,10 +68,5 @@ static void Main(string[] args)
app.Run(args);
}
- public static class Configuration
- {
- public static string RPCServer = Preference.Contains("rpcServer") ? Preference.Get("rpcServer") : null;
- public static bool Enabled = bool.Parse(Preference.Get("enabled"));
- }
}
}
diff --git a/HyperTizen/HyperionClient.cs b/HyperTizen/HyperionClient.cs
new file mode 100644
index 0000000..d843844
--- /dev/null
+++ b/HyperTizen/HyperionClient.cs
@@ -0,0 +1,50 @@
+using Newtonsoft.Json;
+using System.Threading.Tasks;
+using Tizen.Applications;
+using System.Net.WebSockets;
+using System.Text;
+using System;
+using System.Threading;
+using System.Runtime.InteropServices;
+using SkiaSharp;
+using Tizen.NUI;
+using System.Diagnostics;
+using System.Linq;
+using Tizen.Uix.Tts;
+using System.Net.Sockets;
+using Tizen.Applications.RPCPort;
+using System.IO;
+using Tizen.Messaging.Messages;
+using System.Linq.Expressions;
+using Tizen.Applications.Notifications;
+
+namespace HyperTizen
+{
+
+ internal class HyperionClient
+ {
+ public HyperionClient()
+ {
+ Task.Run(() => Start());
+ }
+
+ public async Task Start()
+ {
+
+ Globals.Instance.SetConfig();
+ while (Globals.Instance.Enabled)
+ {
+ if(Networking.client != null && Networking.client.Connected)
+ VideoCapture.DoCapture();
+ else
+ Networking.SendRegister();
+ }
+
+ }
+
+ public async Task Stop()
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/HyperTizen/VideoCapture.cs b/HyperTizen/VideoCapture.cs
new file mode 100644
index 0000000..a502c75
--- /dev/null
+++ b/HyperTizen/VideoCapture.cs
@@ -0,0 +1,201 @@
+using Newtonsoft.Json;
+using System.Threading.Tasks;
+using Tizen.Applications;
+using System.Net.WebSockets;
+using System.Text;
+using System;
+using System.Threading;
+using System.Runtime.InteropServices;
+using SkiaSharp;
+using Tizen.NUI;
+using System.Diagnostics;
+using System.Linq;
+using Tizen.Uix.Tts;
+using System.Net.Sockets;
+using Tizen.Applications.RPCPort;
+using System.IO;
+using Tizen.Messaging.Messages;
+using System.Linq.Expressions;
+using Tizen.Applications.Notifications;
+
+namespace HyperTizen
+{
+ public static class VideoCapture
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Info_t
+ {
+ public Int32 iGivenBufferSize1 { get; set; } //a6[0] = 0 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize2
+ public Int32 iGivenBufferSize2 { get; set; } //a6[1] = 4 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize1
+ public Int32 iWidth { get; set; } //a6[2] = 8 //ref: IceWater "caputre_param.ret_width"
+ public Int32 iHeight { get; set; } //a6[3] = 12 //ref: IceWater "caputre_param.ret_height"
+ public IntPtr pImageY { get; set; } //a6[4] // = 16 dest of memcopy copys v31 in adress with sizeof(needed buffer size(i think)) into this
+ public IntPtr pImageUV { get; set; } //a6[5] // = 20 use this! dest of memcopy copys v223 in adress with sizeof(needed buffer size) into this
+ public Int32 iRetColorFormat { get; set; } //a6[6] // = 24 //ref: IceWater "color format is"(YUV420 = 0, YUV422 = 1, YUV444 = 2 , None = 3, Everything else = Error)
+ public Int32 unknown2 { get; set; } //a6[7] // = 28
+ public Int32 capture3DMode { get; set; } // = 32 //ref: "Capture 3D Mode is DRM_SDP_3D_2D [%d:%s]" (DRM_SDP_3D_2D = 0, DRM_SDP_3D_FRAMEPACKING = 1, DRM_SDP_3D_FRAMESEQ = 2, DRM_SDP_3D_TOPBOTTOM = 3, DRM_SDP_3D_SIDEBYSIDE = 4)
+ //unk3 a6[15] // = 60
+ }
+ //int (__fastcall *)(_DWORD, _DWORD, _DWORD)
+ [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen")] //record with ui
+ unsafe private static extern int CaptureScreen(int w, int h, ref Info_t pInfo);
+ [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_video_only")] // without ui
+ private static extern int CaptureScreenVideo(int w, int h, ref Info_t pInfo);
+ [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_video_only_crop")] // cropped
+ private static extern int CaptureScreenCrop(int w, int h, ref Info_t pInfo, int iCapture3DMode, int cropW, int cropH);
+ //Main Func Errors:
+ //-1 "Input Pram is Wrong"
+ //-1,-2,-3,-5...negative numbers without 4 "Failed scaler_capture"
+
+ //Sub Func Errors
+ //-2 Error: capture type %s, plane %s video only %d
+ //-1 req size less or equal that crop size or non video for videoonly found
+ //-1 Home Screen & yt crop size, capture lock, video info related
+ //-4 Netflix/ Widevine Drm Stuff
+
+ static bool isRunning = true;
+ unsafe public static void DoCapture()
+ {
+ //These lines need to stay here somehow - they arent used but when i delete them the service breaks ??? weird tizen stuff...
+ var width = 480;//480 960
+ var height = 270;//270 540
+
+ var yBufferSize = width * height * 2;
+
+ var uvBufferSizeYUV420 = (width / 2) * (height / 2);
+ var uvBufferSizeYUV422 = (width / 2) * height;
+ var uvBufferSizeYUV444 = width * height;
+
+ int NV12ySize = Globals.Instance.Width * Globals.Instance.Height;
+ int NV12uvSize = (Globals.Instance.Width * Globals.Instance.Height) / 2; // UV-Plane ishalf as big as Y-Plane in NV12
+
+ Info_t info = new Info_t();
+ info.iGivenBufferSize1 = NV12ySize;
+ info.iGivenBufferSize2 = NV12uvSize;
+ //info.iWidth = width;
+ //info.iHeight = height;
+ info.pImageY = Marshal.AllocHGlobal(NV12ySize);
+ info.pImageUV = Marshal.AllocHGlobal(NV12uvSize);
+ //info.iRetColorFormat = 0;
+ //info.capture3DMode = 0;
+
+ //int result = CaptureScreenCrop(width, height, ref info,0, width+10, height+10);
+ int result = CaptureScreen(Globals.Instance.Width, Globals.Instance.Height, ref info);
+ if (result < 0 && isRunning) //only send Notification once
+ {
+ switch (result)
+ {
+ case -4:
+ Debug.WriteLine("CaptureScreen Result: -4 [Netflix/ Widevine Drm Error]");
+ Notification notification4 = new Notification
+ {
+ Title = "HyperTizen",
+ Content = "Capture Error: Seems like you are watching DRM protected content",
+ Count = 1
+ };
+ NotificationManager.Post(notification4);
+ break;
+ case -1:
+ Debug.WriteLine("CaptureScreen Result: -1 [Input Pram is wrong / req size less or equal that crop size / non video for videoonly found]");
+ Notification notification1 = new Notification
+ {
+ Title = "HyperTizen",
+ Content = "Capture Error: Input Pram seems wrong",
+ Count = 1
+ };
+ NotificationManager.Post(notification1);
+ break;
+ case -2:
+ Debug.WriteLine("CaptureScreen Result: -2 [capture type %s, plane %s video only %d / Failed scaler_capture]");
+ Notification notification2 = new Notification
+ {
+ Title = "HyperTizen",
+ Content = "Capture Error: Failed scaler",
+ Count = 1
+ };
+ NotificationManager.Post(notification2);
+ break;
+ default:
+ Notification notificationN = new Notification
+ {
+ Title = "HyperTizen",
+ Content = "Capture Error: New Error occured. Please report ID:"+ result,
+ Count = 1
+ };
+ NotificationManager.Post(notificationN);
+ break;
+ }
+ isRunning = false;
+
+ return;
+ }
+
+ isRunning = true;
+
+
+ byte[] managedArrayY = new byte[NV12ySize];
+ Marshal.Copy(info.pImageY, managedArrayY, 0, NV12ySize);
+
+ byte[] managedArrayUV = new byte[NV12uvSize];
+ Marshal.Copy(info.pImageUV, managedArrayUV, 0, NV12uvSize);
+
+ bool hasAllZeroes1 = managedArrayY.All(singleByte => singleByte == 0);
+ bool hasAllZeroes2 = managedArrayUV.All(singleByte => singleByte == 0);
+ if (hasAllZeroes1 && hasAllZeroes2)
+ throw new Exception("Sanity check Error");
+
+ /*
+ var stringByte1 = Convert.ToBase64String(managedArray1);
+ var stringByte2 = Convert.ToBase64String(managedArray2);
+ Debug.WriteLine(stringByte1);
+ Debug.WriteLine(stringByte2);
+ */
+ //(managedArrayY, managedArrayUV) = GenerateDummyYUVColor(Globals.Instance.Width, Globals.Instance.Height);
+
+ Networking.SendImage(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height);
+
+
+ }
+
+ public static (byte[] yData, byte[] uvData) GenerateDummyYUVRandom(int width, int height)
+ {
+ int ySize = width * height;
+ int uvSize = (width * height) / 2; // UV-Plane ist halb so groß wie Y-Plane in NV12
+
+ byte[] yData = new byte[ySize]; // Y-Plane
+ byte[] uvData = new byte[uvSize]; // Interleaved UV-Plane (VU VU VU ...)
+
+ Random rnd = new Random();
+ rnd.NextBytes(yData); // Zufallswerte für Y (Helligkeit)
+ rnd.NextBytes(uvData); // Zufallswerte für UV (Farbinformation)
+
+ return (yData, uvData);
+ }
+
+ public static (byte[] yData, byte[] uvData) GenerateDummyYUVColor(int width, int height)
+ {
+ int ySize = width * height;
+ int uvSize = (width * height) / 2; // UV-Plane ist halb so groß wie Y-Plane in NV12
+
+ byte[] yData = new byte[ySize]; // Y-Plane
+ byte[] uvData = new byte[uvSize]; // Interleaved UV-Plane (VU VU VU ...)
+
+ // Set Y (luminance) to a value that represents brightness
+ for (int i = 0; i < ySize; i++)
+ {
+ yData[i] = 128; // You can adjust this value for darker or brighter green
+ }
+
+ // Set U and V values for green
+ for (int i = 0; i < uvSize; i += 2)
+ {
+ uvData[i] = 128; // U component (no red)
+ uvData[i + 1] = 255; // V component (max green)
+ }
+
+ return (yData, uvData);
+ }
+
+ }
+
+}
\ No newline at end of file
From db53ad128ac154cbefd9ac5103b276865267777b Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Wed, 5 Mar 2025 23:58:41 +0100
Subject: [PATCH 03/13] Delete HyperTizen/WebSocket/DataTypes.cs
---
HyperTizen/WebSocket/DataTypes.cs | 80 -------------------------------
1 file changed, 80 deletions(-)
delete mode 100644 HyperTizen/WebSocket/DataTypes.cs
diff --git a/HyperTizen/WebSocket/DataTypes.cs b/HyperTizen/WebSocket/DataTypes.cs
deleted file mode 100644
index bf22851..0000000
--- a/HyperTizen/WebSocket/DataTypes.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using System.Collections.Generic;
-
-namespace HyperTizen.WebSocket.DataTypes
-{
- public enum Event
- {
- SetConfig,
- ReadConfig,
- ReadConfigResult,
- ScanSSDP,
- SSDPScanResult
- }
-
- public class BasicEvent
- {
- public Event Event { get; set; }
- }
-
- public class SetConfigEvent : BasicEvent
- {
- public string key { get; set; }
- public string value { get; set; }
- }
-
- public class ReadConfigEvent : BasicEvent
- {
- public string key { get; set; }
- }
-
- public class ReadConfigResultEvent : BasicEvent
- {
- public ReadConfigResultEvent(bool error, string key, object value)
- {
- this.Event = Event.ReadConfigResult;
- this.error = error;
- this.value = value;
- this.key = key;
- }
-
- public bool error { get; set; }
- public string key { get; set; }
- public object value { get; set; }
- }
-
- public class SSDPScanResultEvent : BasicEvent
- {
- public SSDPScanResultEvent(List devices)
- {
- this.devices = devices;
- this.Event = Event.SSDPScanResult;
- }
- public List devices { get; set; }
- public class SSDPDevice
- {
- public string FriendlyName { get; set; }
- public string UrlBase { get; set; }
-
- public SSDPDevice(string friendlyName, string urlBase)
- {
- FriendlyName = friendlyName;
- UrlBase = urlBase;
- }
- }
- }
-
- public class ImageCommand
- {
- public ImageCommand(string image)
- {
- imagedata = image;
- }
-
- public string command { get; set; } = "image";
- public string imagedata { get; set; }
- public string name { get; set; } = "HyperTizen Data";
- public string format { get; set; } = "auto";
- public byte priority { get; set; } = 99;
- public string origin { get; set; } = "HyperTizen";
- }
-}
From b222996d597574e20e6c65fe1eea1acf79891785 Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Wed, 5 Mar 2025 23:58:57 +0100
Subject: [PATCH 04/13] Delete HyperTizen/WebSocket directory
---
HyperTizen/WebSocket/HyperionClient.cs | 196 -----------------------
HyperTizen/WebSocket/WebSocket.cs | 212 -------------------------
2 files changed, 408 deletions(-)
delete mode 100644 HyperTizen/WebSocket/HyperionClient.cs
delete mode 100644 HyperTizen/WebSocket/WebSocket.cs
diff --git a/HyperTizen/WebSocket/HyperionClient.cs b/HyperTizen/WebSocket/HyperionClient.cs
deleted file mode 100644
index 499a66d..0000000
--- a/HyperTizen/WebSocket/HyperionClient.cs
+++ /dev/null
@@ -1,196 +0,0 @@
-using Newtonsoft.Json;
-using System.Threading.Tasks;
-using Tizen.Applications;
-using HyperTizen.WebSocket.DataTypes;
-using System.Net.WebSockets;
-using System.Text;
-using System;
-using System.Threading;
-using System.Runtime.InteropServices;
-using SkiaSharp;
-using Tizen.NUI;
-using System.Diagnostics;
-using System.Linq;
-using Tizen.Uix.Tts;
-using System.Net.Sockets;
-using Tizen.Applications.RPCPort;
-using System.IO;
-using Tizen.Messaging.Messages;
-using System.Linq.Expressions;
-
-namespace HyperTizen.WebSocket
-{
- public static class VideoCapture
- {
- [StructLayout(LayoutKind.Sequential)]
- public struct Info_t
- {
- public Int32 iGivenBufferSize1 { get; set; } //a6[0] = 0 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize2
- public Int32 iGivenBufferSize2 { get; set; } //a6[1] = 4 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize1
- public Int32 iWidth { get; set; } //a6[2] = 8 //ref: IceWater "caputre_param.ret_width"
- public Int32 iHeight { get; set; } //a6[3] = 12 //ref: IceWater "caputre_param.ret_height"
- public IntPtr pImageY { get; set; } //a6[4] // = 16 dest of memcopy copys v31 in adress with sizeof(needed buffer size(i think)) into this
- public IntPtr pImageUV { get; set; } //a6[5] // = 20 use this! dest of memcopy copys v223 in adress with sizeof(needed buffer size) into this
- public Int32 iRetColorFormat { get; set; } //a6[6] // = 24 //ref: IceWater "color format is"(YUV420 = 0, YUV422 = 1, YUV444 = 2 , None = 3, Everything else = Error)
- public Int32 unknown2 { get; set; } //a6[7] // = 28
- public Int32 capture3DMode { get; set; } // = 32 //ref: "Capture 3D Mode is DRM_SDP_3D_2D [%d:%s]" (DRM_SDP_3D_2D = 0, DRM_SDP_3D_FRAMEPACKING = 1, DRM_SDP_3D_FRAMESEQ = 2, DRM_SDP_3D_TOPBOTTOM = 3, DRM_SDP_3D_SIDEBYSIDE = 4)
- //unk3 a6[15] // = 60
- }
- //int (__fastcall *)(_DWORD, _DWORD, _DWORD)
- [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen")] //record with ui
- unsafe private static extern int CaptureScreen(int w, int h, ref Info_t pInfo);
- [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_video_only")] // without ui
- private static extern int CaptureScreenVideo(int w, int h, ref Info_t pInfo);
- [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_video_only_crop")] // cropped
- private static extern int CaptureScreenCrop(int w, int h, ref Info_t pInfo, int iCapture3DMode, int cropW, int cropH);
- //Main Func Errors:
- //-1 "Input Pram is Wrong"
- //-1,-2,-3,-5...negative numbers without 4 "Failed scaler_capture"
-
- //Sub Func Errors
- //-2 Error: capture type %s, plane %s video only %d
- //-1 req size less or equal that crop size or non video for videoonly found
- //-1 Home Screen & yt crop size, capture lock, video info related
- //-4 Netflix/ Widevine Drm Stuff
-
- unsafe public static void DoCapture()
- {
- //HookManager.HookDLog(); //https://github.com/lolp1/Process.NET/tree/master
- var width = 480;//480 960
- var height = 270;//270 540
-
- var yBufferSize = width * height * 2;
-
- var uvBufferSizeYUV420 = (width / 2) * (height / 2);
- var uvBufferSizeYUV422 = (width / 2) * height;
- var uvBufferSizeYUV444 = width * height;
-
- int NV12ySize = Globals.Instance.Width * Globals.Instance.Height;
- int NV12uvSize = (Globals.Instance.Width * Globals.Instance.Height) / 2; // UV-Plane ist halb so groß wie Y-Plane in NV12
-
- Info_t info = new Info_t();
- info.iGivenBufferSize1 = NV12ySize;
- info.iGivenBufferSize2 = NV12uvSize;
- //info.iWidth = width;
- //info.iHeight = height;
- info.pImageY = Marshal.AllocHGlobal(NV12ySize);
- info.pImageUV = Marshal.AllocHGlobal(NV12uvSize);
- //info.iRetColorFormat = 0;
- //info.capture3DMode = 0;
-
- //int result = CaptureScreenCrop(width, height, ref info,0, width+10, height+10);
- int result = CaptureScreen(Globals.Instance.Width, Globals.Instance.Height, ref info);
- if (result < 0)
- {
- switch (result)
- {
- case -4:
- Debug.WriteLine("CaptureScreen Result: -4 [Netflix/ Widevine Drm Error]");
- break;
- case -1:
- Debug.WriteLine("CaptureScreen Result: -1 [Input Pram is Wrong / req size less or equal that crop size / non video for videoonly found]");
- break;
- case -2:
- Debug.WriteLine("CaptureScreen Result: -2 [capture type %s, plane %s video only %d / Failed scaler_capture]");
- break;
- default:
- throw new Exception("New Exception. Please Report! With result:" + result.ToString());
- break;
- }
-
- return;
- }
-
-
- byte[] managedArrayY = new byte[NV12ySize];
- Marshal.Copy(info.pImageY, managedArrayY, 0, NV12ySize);
-
- byte[] managedArrayUV = new byte[NV12uvSize];
- Marshal.Copy(info.pImageUV, managedArrayUV, 0, NV12uvSize);
-
- bool hasAllZeroes1 = managedArrayY.All(singleByte => singleByte == 0);
- bool hasAllZeroes2 = managedArrayUV.All(singleByte => singleByte == 0);
- if (hasAllZeroes1 && hasAllZeroes2)
- throw new Exception("Sanity check Error");
-
- /*
- var stringByte1 = Convert.ToBase64String(managedArray1);
- var stringByte2 = Convert.ToBase64String(managedArray2);
- Debug.WriteLine(stringByte1);
- Debug.WriteLine(stringByte2);
- */
- //(managedArrayY, managedArrayUV) = GenerateDummyYUVColor(Globals.Instance.Width, Globals.Instance.Height);
-
- Networking.SendImage(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height);
-
-
- }
-
- public static (byte[] yData, byte[] uvData) GenerateDummyYUVRandom(int width, int height)
- {
- int ySize = width * height;
- int uvSize = (width * height) / 2; // UV-Plane ist halb so groß wie Y-Plane in NV12
-
- byte[] yData = new byte[ySize]; // Y-Plane
- byte[] uvData = new byte[uvSize]; // Interleaved UV-Plane (VU VU VU ...)
-
- Random rnd = new Random();
- rnd.NextBytes(yData); // Zufallswerte für Y (Helligkeit)
- rnd.NextBytes(uvData); // Zufallswerte für UV (Farbinformation)
-
- return (yData, uvData);
- }
-
- public static (byte[] yData, byte[] uvData) GenerateDummyYUVColor(int width, int height)
- {
- int ySize = width * height;
- int uvSize = (width * height) / 2; // UV-Plane ist halb so groß wie Y-Plane in NV12
-
- byte[] yData = new byte[ySize]; // Y-Plane
- byte[] uvData = new byte[uvSize]; // Interleaved UV-Plane (VU VU VU ...)
-
- // Set Y (luminance) to a value that represents brightness
- for (int i = 0; i < ySize; i++)
- {
- yData[i] = 128; // You can adjust this value for darker or brighter green
- }
-
- // Set U and V values for green
- for (int i = 0; i < uvSize; i += 2)
- {
- uvData[i] = 128; // U component (no red)
- uvData[i + 1] = 255; // V component (max green)
- }
-
- return (yData, uvData);
- }
-
- }
-
- internal class HyperionClient
- {
- public HyperionClient()
- {
- Task.Run(() => Start());
- }
-
- public void UpdateURI(string uri)
- {
-
- }
-
- public async Task Start(bool shouldStart = false)
- {
- Globals.Instance.SetConfig();
- if (Networking.client == null || Networking.client.Connected)
- Networking.SendRegister();
- while (Networking.client.Connected)
- VideoCapture.DoCapture();
- }
-
- public async Task Stop()
- {
-
- }
- }
-}
\ No newline at end of file
diff --git a/HyperTizen/WebSocket/WebSocket.cs b/HyperTizen/WebSocket/WebSocket.cs
deleted file mode 100644
index 876c83f..0000000
--- a/HyperTizen/WebSocket/WebSocket.cs
+++ /dev/null
@@ -1,212 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Net;
-using System.Net.WebSockets;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Newtonsoft.Json;
-using HyperTizen.WebSocket.DataTypes;
-using Rssdp;
-using Tizen.Applications;
-using static HyperTizen.WebSocket.DataTypes.SSDPScanResultEvent;
-
-namespace HyperTizen.WebSocket
-{
- public class WSServer
- {
- private HttpListener _httpListener;
- private List usnList = new List()
- {
- "urn:hyperion-project.org:device:basic:1",
- "urn:hyperhdr.eu:device:basic:1"
- };
-
- public WSServer(string uriPrefix)
- {
- _httpListener = new HttpListener();
- _httpListener.Prefixes.Add(uriPrefix);
- }
-
- public async Task StartAsync()
- {
- _httpListener.Start();
- while (true)
- {
- var httpContext = await _httpListener.GetContextAsync();
- if (httpContext.Request.IsWebSocketRequest)
- {
- var wsContext = await httpContext.AcceptWebSocketAsync(null);
- _ = HandleWebSocketAsync(wsContext.WebSocket);
- }
- else
- {
- httpContext.Response.StatusCode = 400;
- httpContext.Response.Close();
- }
- }
- }
-
- private async Task HandleWebSocketAsync(System.Net.WebSockets.WebSocket webSocket)
- {
- var buffer = new byte[1024 * 4];
- var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None);
-
- while (result.MessageType != WebSocketMessageType.Close)
- {
- var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
- await OnMessageAsync(webSocket, message);
- result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None);
- }
-
- await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
- }
-
- protected async Task OnMessageAsync(System.Net.WebSockets.WebSocket webSocket, string message)
- {
- BasicEvent data = JsonConvert.DeserializeObject(message);
-
- switch (data.Event)
- {
- case Event.ScanSSDP:
- {
- var devices = await ScanSSDPAsync();
- string resultEvent = JsonConvert.SerializeObject(new SSDPScanResultEvent(devices));
- await SendAsync(webSocket, resultEvent);
- break;
- }
-
- case Event.ReadConfig:
- {
- ReadConfigEvent readConfigEvent = JsonConvert.DeserializeObject(message);
- string result = await ReadConfigAsync(readConfigEvent);
- await SendAsync(webSocket, result);
- break;
- }
-
- case Event.SetConfig:
- {
- SetConfigEvent setConfigEvent = JsonConvert.DeserializeObject(message);
- SetConfiguration(setConfigEvent);
- break;
- }
- }
- }
-
- private async Task> ScanSSDPAsync()
- {
- var devices = new List();
- using (var deviceLocator = new SsdpDeviceLocator())
- {
- var foundDevices = await deviceLocator.SearchAsync();
- foreach (var foundDevice in foundDevices)
- {
- if (!usnList.Contains(foundDevice.NotificationType)) continue;
-
- var fullDevice = await foundDevice.GetDeviceInfo();
- Uri descLocation = foundDevice.DescriptionLocation;
- devices.Add(new SSDPDevice(fullDevice.FriendlyName, descLocation.OriginalString.Replace(descLocation.PathAndQuery, "")));
- }
- }
- return devices;
- }
-
- private async Task ReadConfigAsync(ReadConfigEvent readConfigEvent)
- {
- string result;
- if (!Preference.Contains(readConfigEvent.key))
- {
- result = JsonConvert.SerializeObject(new ReadConfigResultEvent(true, readConfigEvent.key, "Key doesn't exist."));
- }
- else
- {
- string value = Preference.Get(readConfigEvent.key);
- result = JsonConvert.SerializeObject(new ReadConfigResultEvent(false, readConfigEvent.key, value));
- }
- return result;
- }
-
- private async Task SendAsync(System.Net.WebSockets.WebSocket webSocket, string message)
- {
- var buffer = Encoding.UTF8.GetBytes(message);
- await webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
- }
-
- void SetConfiguration(SetConfigEvent setConfigEvent)
- {
- switch (setConfigEvent.key)
- {
- case "rpcServer":
- {
- App.Configuration.RPCServer = setConfigEvent.value;
- App.client.UpdateURI(setConfigEvent.value);
- break;
- }
- case "enabled":
- {
- bool value = bool.Parse(setConfigEvent.value);
- if (!App.Configuration.Enabled && value)
- {
- App.Configuration.Enabled = value;
- Task.Run(() => App.client.Start(value));
- }
- else App.Configuration.Enabled = value;
- break;
- }
- }
-
- Preference.Set(setConfigEvent.key, setConfigEvent.value);
- }
- }
-
- public static class WebSocketServer
- {
- public static async Task StartServerAsync()
- {
- var wsServer = new WSServer("http://+:8086/");
- await wsServer.StartAsync();
- }
- }
-
- public class WebSocketClient
- {
- private string uri;
- public ClientWebSocket client;
- private byte errorTimes = 0;
-
- public WebSocketClient(string uri)
- {
- this.uri = uri;
- client = new ClientWebSocket();
- }
-
- public async Task ConnectAsync()
- {
- await client.ConnectAsync(new Uri(uri), CancellationToken.None);
- _ = ReceiveMessagesAsync();
- }
-
- private async Task ReceiveMessagesAsync()
- {
- var buffer = new byte[1024 * 4];
- while (client.State == WebSocketState.Open)
- {
- var result = await client.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None);
- if (result.MessageType == WebSocketMessageType.Close)
- {
- await client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
- }
- else
- {
- var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
- OnMessage(message);
- }
- }
- }
-
- private void OnMessage(string message)
- {
-
- }
- }
-}
\ No newline at end of file
From 835f7be27f21e4334d22ae8e1ccd0ddbdeb9f42c Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Wed, 5 Mar 2025 23:59:40 +0100
Subject: [PATCH 05/13] Delete HyperTizen/Capturer.cs
---
HyperTizen/Capturer.cs | 275 -----------------------------------------
1 file changed, 275 deletions(-)
delete mode 100644 HyperTizen/Capturer.cs
diff --git a/HyperTizen/Capturer.cs b/HyperTizen/Capturer.cs
deleted file mode 100644
index 588ed70..0000000
--- a/HyperTizen/Capturer.cs
+++ /dev/null
@@ -1,275 +0,0 @@
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Threading;
-using SkiaSharp;
-using Tizen.Applications.Notifications;
-using Tizen.System;
-
-namespace HyperTizen
-{
- public static class Capturer
- {
- private static Condition _condition;
-
- private static bool IsTizen7OrHigher
- {
- get
- {
- string version;
- Information.TryGetValue("http://tizen.org/feature/platform.version", out version);
- if (int.Parse(version.Split('.')[0]) >= 7)
- {
- return true;
- } else
- {
- return false;
- }
- }
- }
-
- private static CapturePoint[] _capturedPoints = new CapturePoint[] {
- new CapturePoint(0.21, 0.05),
- new CapturePoint(0.45, 0.05),
- new CapturePoint(0.7, 0.05),
- new CapturePoint(0.93, 0.07),
- new CapturePoint(0.95, 0.275),
- new CapturePoint(0.95, 0.5),
- new CapturePoint(0.95, 0.8),
- new CapturePoint(0.79, 0.95),
- new CapturePoint(0.65, 0.95),
- new CapturePoint(0.35, 0.95),
- new CapturePoint(0.15, 0.95),
- new CapturePoint(0.05, 0.725),
- new CapturePoint(0.05, 0.4),
- new CapturePoint(0.05, 0.2),
- new CapturePoint(0.35, 0.5),
- new CapturePoint(0.65, 0.5)
- };
-
- [DllImport("/usr/lib/libvideoenhance.so", CallingConvention = CallingConvention.Cdecl, EntryPoint = "cs_ve_get_rgb_measure_condition")]
- private static extern int MeasureCondition(out Condition unknown);
-
- [DllImport("/usr/lib/libvideoenhance.so", CallingConvention = CallingConvention.Cdecl, EntryPoint = "cs_ve_set_rgb_measure_position")]
- private static extern int MeasurePosition(int i, int x, int y);
-
- [DllImport("/usr/lib/libvideoenhance.so", CallingConvention = CallingConvention.Cdecl, EntryPoint = "cs_ve_get_rgb_measure_pixel")]
- private static extern int MeasurePixel(int i, out Color color);
-
- [DllImport("/usr/lib/libvideoenhance.so", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ve_get_rgb_measure_condition")]
- private static extern int MeasureCondition7(out Condition unknown);
-
- [DllImport("/usr/lib/libvideoenhance.so", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ve_set_rgb_measure_position")]
- private static extern int MeasurePosition7(int i, int x, int y);
-
- [DllImport("/usr/lib/libvideoenhance.so", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ve_get_rgb_measure_pixel")]
- private static extern int MeasurePixel7(int i, out Color color);
-
- public static bool GetCondition()
- {
- int res = -1;
- try
- {
- if (!IsTizen7OrHigher)
- {
- res = MeasureCondition(out _condition);
- } else
- {
- res = MeasureCondition7(out _condition);
- }
- } catch
- {
- Notification notification = new Notification
- {
- Title = "HyperTizen",
- Content = "Your TV does not support the required functions for HyperTizen.",
- Count = 1
- };
-
- NotificationManager.Post(notification);
- }
- if (res < 0)
- {
- return false;
- } else
- {
- return true;
- }
- }
-
- public static void SetCapturePoints(CapturePoint[] capturePoints)
- {
- _capturedPoints = capturePoints;
- }
-
- public static Color[] GetColors()
- {
- Color[] colorData = new Color[_capturedPoints.Length];
- int[] updatedIndexes = new int[_condition.ScreenCapturePoints];
-
- int i = 0;
- while (i < _capturedPoints.Length)
- {
- if (_condition.ScreenCapturePoints == 0) break;
- for (int j = 0; j < _condition.ScreenCapturePoints; j++)
- {
- updatedIndexes[j] = i;
- int x = (int)(_capturedPoints[i].X * (double)_condition.Width) - _condition.PixelDensityX / 2;
- int y = (int)(_capturedPoints[i].Y * (double)_condition.Height) - _condition.PixelDensityY / 2;
- x = (x >= _condition.Width - _condition.PixelDensityX) ? _condition.Width - (_condition.PixelDensityX + 1) : x;
- y = (y >= _condition.Height - _condition.PixelDensityY) ? (_condition.Height - _condition.PixelDensityY + 1) : y;
- int res;
- if (!IsTizen7OrHigher)
- {
- res = MeasurePosition(j, x, y);
- } else
- {
- res = MeasurePosition7(j, x, y);
- }
-
- i++;
- if (res < 0)
- {
- // This should not happen, handle it.
- }
- }
-
- if (_condition.SleepMS > 0)
- {
- Thread.Sleep(_condition.SleepMS);
- }
- int k = 0;
- while (k < _condition.ScreenCapturePoints)
- {
- Color color;
-
- int res;
-
- if (!IsTizen7OrHigher)
- {
- res = MeasurePixel(k, out color);
- } else
- {
- res = MeasurePixel7(k, out color);
- }
-
- if (res < 0)
- {
- // This should not happen, handle it.
- } else
- {
- bool invalidColorData = color.R > 1023 || color.G > 1023 || color.B > 1023;
-
- if (invalidColorData)
- {
- // This should not happen, handle it.
- } else
- {
- colorData[i - _condition.ScreenCapturePoints + k] = color;
- k++;
- }
- }
- }
- }
- return colorData;
- }
-
- public static string ToImage(Color[] colors)
- {
- using (var image = new SKBitmap(64, 48))
- {
- for (int x = 0; x < 64; x++)
- {
- Color color = colors[x / 16];
- SKColor sKColor = ClampColor(color);
- for (int y = 0; y < 4; y++)
- {
- image.SetPixel(x, y, sKColor);
- }
- }
-
- for (int x = 0; x < 64; x++)
- {
- Color color = colors[x / 16 + 7];
- SKColor sKColor = ClampColor(color);
- for (int y = 44; y < 48; y++)
- {
- image.SetPixel(x, y, sKColor);
- }
- }
-
- for (int y = 0; y < 48; y++)
- {
- Color color = colors[11 + y / 16];
- SKColor sKColor = ClampColor(color);
- for (int x = 0; x < 3; x++)
- {
- image.SetPixel(x, y, sKColor);
- }
- }
-
- for (int y = 0; y < 48; y++)
- {
- Color color = colors[4 + y / 16];
- SKColor sKColor = ClampColor(color);
- for (int x = 61; x < 64; x++)
- {
- image.SetPixel(x, y, sKColor);
- }
- }
-
- using (var memoryStream = new MemoryStream())
- {
- using (var data = SKImage.FromBitmap(image).Encode(SKEncodedImageFormat.Png, 100))
- {
- data.SaveTo(memoryStream);
- }
- byte[] imageBytes = memoryStream.ToArray();
- string base64String = Convert.ToBase64String(imageBytes);
- return base64String;
- }
- }
- }
-
- static SKColor ClampColor(Color color)
- {
- byte r = (byte)Math.Min(color.R, 255);
- byte g = (byte)Math.Min(color.G, 255);
- byte b = (byte)Math.Min(color.B, 255);
- return new SKColor(r, g, b);
- }
- }
-
- public struct Color
- {
- public int R;
- public int G;
- public int B;
- }
-
- public struct Condition
- {
- public int ScreenCapturePoints;
-
- public int PixelDensityX;
-
- public int PixelDensityY;
-
- public int SleepMS;
-
- public int Width;
-
- public int Height;
- }
-
- public struct CapturePoint
- {
- public CapturePoint(double x, double y) {
- this.X = x;
- this.Y = y;
- }
-
- public double X;
- public double Y;
- }
-}
From 42578a53b59847cbb2d1c11b6235dc366f989e08 Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Thu, 6 Mar 2025 00:56:22 +0100
Subject: [PATCH 06/13] Fixed deleted ssdp discorvery
---
HyperTizen/HyperTizen_App.cs | 10 +-
HyperTizen/WebSocket/DataTypes.cs | 80 +++++++++++
HyperTizen/WebSocket/WebSocket.cs | 212 ++++++++++++++++++++++++++++++
3 files changed, 300 insertions(+), 2 deletions(-)
create mode 100644 HyperTizen/WebSocket/DataTypes.cs
create mode 100644 HyperTizen/WebSocket/WebSocket.cs
diff --git a/HyperTizen/HyperTizen_App.cs b/HyperTizen/HyperTizen_App.cs
index 037657a..cde7f36 100644
--- a/HyperTizen/HyperTizen_App.cs
+++ b/HyperTizen/HyperTizen_App.cs
@@ -2,6 +2,7 @@
using Tizen.Applications.Notifications;
using Tizen.System;
using System.Threading.Tasks;
+using HyperTizen.WebSocket;
namespace HyperTizen
{
@@ -11,7 +12,8 @@ class App : ServiceApplication
protected override void OnCreate()
{
base.OnCreate();
- if (!Preference.Contains("enabled")) Preference.Set("enabled", "false");
+ if (!Preference.Contains("enabled")) Preference.Set("enabled", "false");
+ Task.Run(() => WebSocketServer.StartServerAsync());
Display.StateChanged += Display_StateChanged;
client = new HyperionClient();
}
@@ -67,6 +69,10 @@ static void Main(string[] args)
App app = new App();
app.Run(args);
}
-
+ public static class Configuration
+ {
+ public static string RPCServer = Preference.Contains("rpcServer") ? Preference.Get("rpcServer") : null;
+ public static bool Enabled = bool.Parse(Preference.Get("enabled"));
+ }
}
}
diff --git a/HyperTizen/WebSocket/DataTypes.cs b/HyperTizen/WebSocket/DataTypes.cs
new file mode 100644
index 0000000..bf22851
--- /dev/null
+++ b/HyperTizen/WebSocket/DataTypes.cs
@@ -0,0 +1,80 @@
+using System.Collections.Generic;
+
+namespace HyperTizen.WebSocket.DataTypes
+{
+ public enum Event
+ {
+ SetConfig,
+ ReadConfig,
+ ReadConfigResult,
+ ScanSSDP,
+ SSDPScanResult
+ }
+
+ public class BasicEvent
+ {
+ public Event Event { get; set; }
+ }
+
+ public class SetConfigEvent : BasicEvent
+ {
+ public string key { get; set; }
+ public string value { get; set; }
+ }
+
+ public class ReadConfigEvent : BasicEvent
+ {
+ public string key { get; set; }
+ }
+
+ public class ReadConfigResultEvent : BasicEvent
+ {
+ public ReadConfigResultEvent(bool error, string key, object value)
+ {
+ this.Event = Event.ReadConfigResult;
+ this.error = error;
+ this.value = value;
+ this.key = key;
+ }
+
+ public bool error { get; set; }
+ public string key { get; set; }
+ public object value { get; set; }
+ }
+
+ public class SSDPScanResultEvent : BasicEvent
+ {
+ public SSDPScanResultEvent(List devices)
+ {
+ this.devices = devices;
+ this.Event = Event.SSDPScanResult;
+ }
+ public List devices { get; set; }
+ public class SSDPDevice
+ {
+ public string FriendlyName { get; set; }
+ public string UrlBase { get; set; }
+
+ public SSDPDevice(string friendlyName, string urlBase)
+ {
+ FriendlyName = friendlyName;
+ UrlBase = urlBase;
+ }
+ }
+ }
+
+ public class ImageCommand
+ {
+ public ImageCommand(string image)
+ {
+ imagedata = image;
+ }
+
+ public string command { get; set; } = "image";
+ public string imagedata { get; set; }
+ public string name { get; set; } = "HyperTizen Data";
+ public string format { get; set; } = "auto";
+ public byte priority { get; set; } = 99;
+ public string origin { get; set; } = "HyperTizen";
+ }
+}
diff --git a/HyperTizen/WebSocket/WebSocket.cs b/HyperTizen/WebSocket/WebSocket.cs
new file mode 100644
index 0000000..d845ef2
--- /dev/null
+++ b/HyperTizen/WebSocket/WebSocket.cs
@@ -0,0 +1,212 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.WebSockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+using HyperTizen.WebSocket.DataTypes;
+using Rssdp;
+using Tizen.Applications;
+using static HyperTizen.WebSocket.DataTypes.SSDPScanResultEvent;
+
+namespace HyperTizen.WebSocket
+{
+ public class WSServer
+ {
+ private HttpListener _httpListener;
+ private List usnList = new List()
+ {
+ "urn:hyperion-project.org:device:basic:1",
+ "urn:hyperhdr.eu:device:basic:1"
+ };
+
+ public WSServer(string uriPrefix)
+ {
+ _httpListener = new HttpListener();
+ _httpListener.Prefixes.Add(uriPrefix);
+ }
+
+ public async Task StartAsync()
+ {
+ _httpListener.Start();
+ while (true)
+ {
+ var httpContext = await _httpListener.GetContextAsync();
+ if (httpContext.Request.IsWebSocketRequest)
+ {
+ var wsContext = await httpContext.AcceptWebSocketAsync(null);
+ _ = HandleWebSocketAsync(wsContext.WebSocket);
+ }
+ else
+ {
+ httpContext.Response.StatusCode = 400;
+ httpContext.Response.Close();
+ }
+ }
+ }
+
+ private async Task HandleWebSocketAsync(System.Net.WebSockets.WebSocket webSocket)
+ {
+ var buffer = new byte[1024 * 4];
+ var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None);
+
+ while (result.MessageType != WebSocketMessageType.Close)
+ {
+ var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
+ await OnMessageAsync(webSocket, message);
+ result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None);
+ }
+
+ await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
+ }
+
+ protected async Task OnMessageAsync(System.Net.WebSockets.WebSocket webSocket, string message)
+ {
+ BasicEvent data = JsonConvert.DeserializeObject(message);
+
+ switch (data.Event)
+ {
+ case Event.ScanSSDP:
+ {
+ var devices = await ScanSSDPAsync();
+ string resultEvent = JsonConvert.SerializeObject(new SSDPScanResultEvent(devices));
+ await SendAsync(webSocket, resultEvent);
+ break;
+ }
+
+ case Event.ReadConfig:
+ {
+ ReadConfigEvent readConfigEvent = JsonConvert.DeserializeObject(message);
+ string result = await ReadConfigAsync(readConfigEvent);
+ await SendAsync(webSocket, result);
+ break;
+ }
+
+ case Event.SetConfig:
+ {
+ SetConfigEvent setConfigEvent = JsonConvert.DeserializeObject(message);
+ SetConfiguration(setConfigEvent);
+ break;
+ }
+ }
+ }
+
+ private async Task> ScanSSDPAsync()
+ {
+ var devices = new List();
+ using (var deviceLocator = new SsdpDeviceLocator())
+ {
+ var foundDevices = await deviceLocator.SearchAsync();
+ foreach (var foundDevice in foundDevices)
+ {
+ if (!usnList.Contains(foundDevice.NotificationType)) continue;
+
+ var fullDevice = await foundDevice.GetDeviceInfo();
+ Uri descLocation = foundDevice.DescriptionLocation;
+ devices.Add(new SSDPDevice(fullDevice.FriendlyName, descLocation.OriginalString.Replace(descLocation.PathAndQuery, "")));
+ }
+ }
+ return devices;
+ }
+
+ private async Task ReadConfigAsync(ReadConfigEvent readConfigEvent)
+ {
+ string result;
+ if (!Preference.Contains(readConfigEvent.key))
+ {
+ result = JsonConvert.SerializeObject(new ReadConfigResultEvent(true, readConfigEvent.key, "Key doesn't exist."));
+ }
+ else
+ {
+ string value = Preference.Get(readConfigEvent.key);
+ result = JsonConvert.SerializeObject(new ReadConfigResultEvent(false, readConfigEvent.key, value));
+ }
+ return result;
+ }
+
+ private async Task SendAsync(System.Net.WebSockets.WebSocket webSocket, string message)
+ {
+ var buffer = Encoding.UTF8.GetBytes(message);
+ await webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
+ }
+
+ void SetConfiguration(SetConfigEvent setConfigEvent)
+ {
+ switch (setConfigEvent.key)
+ {
+ case "rpcServer":
+ {
+ App.Configuration.RPCServer = setConfigEvent.value;
+ //App.client.UpdateURI(setConfigEvent.value);
+ break;
+ }
+ case "enabled":
+ {
+ bool value = bool.Parse(setConfigEvent.value);
+ if (!App.Configuration.Enabled && value)
+ {
+ App.Configuration.Enabled = value;
+ Task.Run(() => App.client.Start());
+ }
+ else App.Configuration.Enabled = value;
+ break;
+ }
+ }
+
+ Preference.Set(setConfigEvent.key, setConfigEvent.value);
+ }
+ }
+
+ public static class WebSocketServer
+ {
+ public static async Task StartServerAsync()
+ {
+ var wsServer = new WSServer("http://+:8086/");
+ await wsServer.StartAsync();
+ }
+ }
+
+ public class WebSocketClient
+ {
+ private string uri;
+ public ClientWebSocket client;
+ private byte errorTimes = 0;
+
+ public WebSocketClient(string uri)
+ {
+ this.uri = uri;
+ client = new ClientWebSocket();
+ }
+
+ public async Task ConnectAsync()
+ {
+ await client.ConnectAsync(new Uri(uri), CancellationToken.None);
+ _ = ReceiveMessagesAsync();
+ }
+
+ private async Task ReceiveMessagesAsync()
+ {
+ var buffer = new byte[1024 * 4];
+ while (client.State == WebSocketState.Open)
+ {
+ var result = await client.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None);
+ if (result.MessageType == WebSocketMessageType.Close)
+ {
+ await client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
+ }
+ else
+ {
+ var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
+ OnMessage(message);
+ }
+ }
+ }
+
+ private void OnMessage(string message)
+ {
+
+ }
+ }
+}
\ No newline at end of file
From f32963d12b0e0eb9e3c85c70728a37a8d6055044 Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Thu, 6 Mar 2025 11:42:22 +0100
Subject: [PATCH 07/13] Cleaned Comments
---
HyperTizen/HyperTizen_App.cs | 154 +++++++++++++++++-----------------
HyperTizen/Networking.cs | 22 ++---
HyperTizen/VideoCapture.cs | 38 ++++-----
HyperTizen/tizen-manifest.xml | 4 +-
4 files changed, 100 insertions(+), 118 deletions(-)
diff --git a/HyperTizen/HyperTizen_App.cs b/HyperTizen/HyperTizen_App.cs
index cde7f36..355658a 100644
--- a/HyperTizen/HyperTizen_App.cs
+++ b/HyperTizen/HyperTizen_App.cs
@@ -1,78 +1,78 @@
-using Tizen.Applications;
-using Tizen.Applications.Notifications;
-using Tizen.System;
-using System.Threading.Tasks;
-using HyperTizen.WebSocket;
-
-namespace HyperTizen
-{
- class App : ServiceApplication
- {
- public static HyperionClient client;
- protected override void OnCreate()
- {
- base.OnCreate();
+using Tizen.Applications;
+using Tizen.Applications.Notifications;
+using Tizen.System;
+using System.Threading.Tasks;
+using HyperTizen.WebSocket;
+
+namespace HyperTizen
+{
+ class App : ServiceApplication
+ {
+ public static HyperionClient client;
+ protected override void OnCreate()
+ {
+ base.OnCreate();
if (!Preference.Contains("enabled")) Preference.Set("enabled", "false");
- Task.Run(() => WebSocketServer.StartServerAsync());
- Display.StateChanged += Display_StateChanged;
- client = new HyperionClient();
- }
-
- private void Display_StateChanged(object sender, DisplayStateChangedEventArgs e)
- {
- if (e.State == DisplayState.Off)
- {
- Task.Run(() => client.Stop());
- } else if (e.State == DisplayState.Normal)
- {
- Task.Run(() => client.Start());
- }
- }
-
- protected override void OnAppControlReceived(AppControlReceivedEventArgs e)
- {
- base.OnAppControlReceived(e);
- }
-
- protected override void OnDeviceOrientationChanged(DeviceOrientationEventArgs e)
- {
- base.OnDeviceOrientationChanged(e);
- }
-
- protected override void OnLocaleChanged(LocaleChangedEventArgs e)
- {
- base.OnLocaleChanged(e);
- }
-
- protected override void OnLowBattery(LowBatteryEventArgs e)
- {
- base.OnLowBattery(e);
- }
-
- protected override void OnLowMemory(LowMemoryEventArgs e)
- {
- base.OnLowMemory(e);
- }
-
- protected override void OnRegionFormatChanged(RegionFormatChangedEventArgs e)
- {
- base.OnRegionFormatChanged(e);
- }
-
- protected override void OnTerminate()
- {
- base.OnTerminate();
- }
-
- static void Main(string[] args)
- {
- App app = new App();
- app.Run(args);
- }
- public static class Configuration
- {
- public static string RPCServer = Preference.Contains("rpcServer") ? Preference.Get("rpcServer") : null;
- public static bool Enabled = bool.Parse(Preference.Get("enabled"));
- }
- }
-}
+ Task.Run(() => WebSocketServer.StartServerAsync());
+ Display.StateChanged += Display_StateChanged;
+ client = new HyperionClient();
+ }
+
+ private void Display_StateChanged(object sender, DisplayStateChangedEventArgs e)
+ {
+ if (e.State == DisplayState.Off)
+ {
+ Task.Run(() => client.Stop());
+ } else if (e.State == DisplayState.Normal)
+ {
+ Task.Run(() => client.Start());
+ }
+ }
+
+ protected override void OnAppControlReceived(AppControlReceivedEventArgs e)
+ {
+ base.OnAppControlReceived(e);
+ }
+
+ protected override void OnDeviceOrientationChanged(DeviceOrientationEventArgs e)
+ {
+ base.OnDeviceOrientationChanged(e);
+ }
+
+ protected override void OnLocaleChanged(LocaleChangedEventArgs e)
+ {
+ base.OnLocaleChanged(e);
+ }
+
+ protected override void OnLowBattery(LowBatteryEventArgs e)
+ {
+ base.OnLowBattery(e);
+ }
+
+ protected override void OnLowMemory(LowMemoryEventArgs e)
+ {
+ base.OnLowMemory(e);
+ }
+
+ protected override void OnRegionFormatChanged(RegionFormatChangedEventArgs e)
+ {
+ base.OnRegionFormatChanged(e);
+ }
+
+ protected override void OnTerminate()
+ {
+ base.OnTerminate();
+ }
+
+ static void Main(string[] args)
+ {
+ App app = new App();
+ app.Run(args);
+ }
+ public static class Configuration
+ {
+ public static string RPCServer = Preference.Contains("rpcServer") ? Preference.Get("rpcServer") : null;
+ public static bool Enabled = bool.Parse(Preference.Get("enabled"));
+ }
+ }
+}
diff --git a/HyperTizen/Networking.cs b/HyperTizen/Networking.cs
index d7485ee..7993c07 100644
--- a/HyperTizen/Networking.cs
+++ b/HyperTizen/Networking.cs
@@ -33,8 +33,8 @@ public static void SendRegister()
public static void SendImage(byte[] yData, byte[] uvData, int width, int height)
{
- //if (!client.Connected)
- // return;
+ if (!client.Connected)
+ return;
byte[] message = CreateFlatBufferMessage(yData, uvData, width, height);
SendMessageAndReceiveReply(message);
}
@@ -45,41 +45,35 @@ static byte[] CreateFlatBufferMessage(byte[] yData, byte[] uvData, int width, in
return null;
var builder = new FlatBufferBuilder(yData.Length + uvData.Length + 100);
- // Erstelle FlatBuffer Vektoren für Y- und UV-Daten
var yVector = NV12Image.CreateDataYVector(builder, yData);
var uvVector = NV12Image.CreateDataUvVector(builder, uvData);
- // NV12Image Struktur erstellen
NV12Image.StartNV12Image(builder);
NV12Image.AddDataY(builder, yVector);
NV12Image.AddDataUv(builder, uvVector);
NV12Image.AddWidth(builder, width);
NV12Image.AddHeight(builder, height);
- NV12Image.AddStrideY(builder, width); // Falls kein spezieller Stride nötig ist
+ NV12Image.AddStrideY(builder, width); //TODO: Check if this is correct
NV12Image.AddStrideUv(builder, width);
var nv12Image = NV12Image.EndNV12Image(builder);
- // Image union mit NV12Image erstellen
Image.StartImage(builder);
Image.AddDataType(builder, ImageType.NV12Image);
Image.AddData(builder, nv12Image.Value);
- Image.AddDuration(builder, -1); // Falls eine bestimmte Dauer nötig ist, ändern
+ Image.AddDuration(builder, -1);
var imageOffset = Image.EndImage(builder);
- // Request mit Image als Kommando erstellen
Request.StartRequest(builder);
Request.AddCommandType(builder, Command.Image);
Request.AddCommand(builder, imageOffset.Value);
var requestOffset = Request.EndRequest(builder);
- // FlatBuffer fertigstellen
builder.Finish(requestOffset.Value);
return builder.SizedByteArray();
}
static Reply ParseReply(byte[] receivedData)
{
- // FlatBuffer aus empfangenen Daten parsen
var byteBuffer = new ByteBuffer(receivedData,4); //shift for header
return Reply.GetRootAsReply(byteBuffer);
}
@@ -93,19 +87,16 @@ public static byte[] CreateRegistrationMessage(bool subscribe)
var originOffset = builder.CreateString("HyperTizen");
- // Registrierungsstruktur erstellen
Register.StartRegister(builder);
Register.AddPriority(builder, 123);
Register.AddOrigin(builder, originOffset);
var registerOffset = Register.EndRegister(builder);
- // Request mit Register-Kommando erstellen
Request.StartRequest(builder);
Request.AddCommandType(builder, Command.Register);
Request.AddCommand(builder, registerOffset.Value);
var requestOffset = Request.EndRequest(builder);
- // FlatBuffer-Nachricht fertigstellen
builder.Finish(requestOffset.Value);
return builder.SizedByteArray();
}
@@ -146,7 +137,6 @@ static void SendMessageAndReceiveReply(byte[] message)
stream.Write(message, 0, message.Length);
Debug.WriteLine("Data sent. Waiting for Answer");
- // Antwort empfangen
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
if (bytesRead > 0)
@@ -155,10 +145,10 @@ static void SendMessageAndReceiveReply(byte[] message)
byte[] replyData = new byte[bytesRead];
Array.Copy(buffer, replyData, bytesRead);
string test = BitConverter.ToString(replyData);
- // Antwort mit FlatBuffers parsen
+
+
Reply reply = ParseReply(replyData);
- // Antwort ausgeben
Debug.WriteLine($"Error: {reply.Error}");
Debug.WriteLine($"Video: {reply.Video}");
Debug.WriteLine($"Registered: {reply.Registered}");
diff --git a/HyperTizen/VideoCapture.cs b/HyperTizen/VideoCapture.cs
index a502c75..898e390 100644
--- a/HyperTizen/VideoCapture.cs
+++ b/HyperTizen/VideoCapture.cs
@@ -57,8 +57,8 @@ public struct Info_t
unsafe public static void DoCapture()
{
//These lines need to stay here somehow - they arent used but when i delete them the service breaks ??? weird tizen stuff...
- var width = 480;//480 960
- var height = 270;//270 540
+ var width = 480;
+ var height = 270;
var yBufferSize = width * height * 2;
@@ -67,7 +67,7 @@ unsafe public static void DoCapture()
var uvBufferSizeYUV444 = width * height;
int NV12ySize = Globals.Instance.Width * Globals.Instance.Height;
- int NV12uvSize = (Globals.Instance.Width * Globals.Instance.Height) / 2; // UV-Plane ishalf as big as Y-Plane in NV12
+ int NV12uvSize = (Globals.Instance.Width * Globals.Instance.Height) / 2; // UV-Plane is half as big as Y-Plane in NV12
Info_t info = new Info_t();
info.iGivenBufferSize1 = NV12ySize;
@@ -79,7 +79,6 @@ unsafe public static void DoCapture()
//info.iRetColorFormat = 0;
//info.capture3DMode = 0;
- //int result = CaptureScreenCrop(width, height, ref info,0, width+10, height+10);
int result = CaptureScreen(Globals.Instance.Width, Globals.Instance.Height, ref info);
if (result < 0 && isRunning) //only send Notification once
{
@@ -144,12 +143,6 @@ unsafe public static void DoCapture()
if (hasAllZeroes1 && hasAllZeroes2)
throw new Exception("Sanity check Error");
- /*
- var stringByte1 = Convert.ToBase64String(managedArray1);
- var stringByte2 = Convert.ToBase64String(managedArray2);
- Debug.WriteLine(stringByte1);
- Debug.WriteLine(stringByte2);
- */
//(managedArrayY, managedArrayUV) = GenerateDummyYUVColor(Globals.Instance.Width, Globals.Instance.Height);
Networking.SendImage(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height);
@@ -160,14 +153,14 @@ unsafe public static void DoCapture()
public static (byte[] yData, byte[] uvData) GenerateDummyYUVRandom(int width, int height)
{
int ySize = width * height;
- int uvSize = (width * height) / 2; // UV-Plane ist halb so groß wie Y-Plane in NV12
+ int uvSize = (width * height) / 2;
- byte[] yData = new byte[ySize]; // Y-Plane
- byte[] uvData = new byte[uvSize]; // Interleaved UV-Plane (VU VU VU ...)
+ byte[] yData = new byte[ySize];
+ byte[] uvData = new byte[uvSize];
Random rnd = new Random();
- rnd.NextBytes(yData); // Zufallswerte für Y (Helligkeit)
- rnd.NextBytes(uvData); // Zufallswerte für UV (Farbinformation)
+ rnd.NextBytes(yData);
+ rnd.NextBytes(uvData);
return (yData, uvData);
}
@@ -175,22 +168,21 @@ public static (byte[] yData, byte[] uvData) GenerateDummyYUVRandom(int width, in
public static (byte[] yData, byte[] uvData) GenerateDummyYUVColor(int width, int height)
{
int ySize = width * height;
- int uvSize = (width * height) / 2; // UV-Plane ist halb so groß wie Y-Plane in NV12
+ int uvSize = (width * height) / 2;
+
+ byte[] yData = new byte[ySize];
+ byte[] uvData = new byte[uvSize];
- byte[] yData = new byte[ySize]; // Y-Plane
- byte[] uvData = new byte[uvSize]; // Interleaved UV-Plane (VU VU VU ...)
- // Set Y (luminance) to a value that represents brightness
for (int i = 0; i < ySize; i++)
{
- yData[i] = 128; // You can adjust this value for darker or brighter green
+ yData[i] = 128;
}
- // Set U and V values for green
for (int i = 0; i < uvSize; i += 2)
{
- uvData[i] = 128; // U component (no red)
- uvData[i + 1] = 255; // V component (max green)
+ uvData[i] = 128;
+ uvData[i + 1] = 255;
}
return (yData, uvData);
diff --git a/HyperTizen/tizen-manifest.xml b/HyperTizen/tizen-manifest.xml
index 03949fe..2ee86b8 100644
--- a/HyperTizen/tizen-manifest.xml
+++ b/HyperTizen/tizen-manifest.xml
@@ -1,8 +1,8 @@
-
+
Reis Can
-
+
HyperTizen.png
From fb504c76c4afdeebab914b3e81745b44de1c5521 Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Wed, 19 Mar 2025 01:36:37 +0100
Subject: [PATCH 08/13] Use Public Cert & fps performance increase (x2)
removed privileges where partner cert was needed (for now-could be necessary in the future)
sent flatbuffer messages multithreaded for better fps
-more to come
---
HyperTizen/Globals.cs | 8 +--
HyperTizen/HyperionClient.cs | 3 +-
HyperTizen/Networking.cs | 10 ++--
HyperTizen/SDK/SecVideoCapture.cs | 47 +++++++++++++++
HyperTizen/SDK/SystemInfo.cs | 76 +++++++++++++++++++++++++
HyperTizen/VideoCapture.cs | 95 +++++++++++++------------------
HyperTizen/tizen-manifest.xml | 3 +-
7 files changed, 175 insertions(+), 67 deletions(-)
create mode 100644 HyperTizen/SDK/SecVideoCapture.cs
create mode 100644 HyperTizen/SDK/SystemInfo.cs
diff --git a/HyperTizen/Globals.cs b/HyperTizen/Globals.cs
index 0d44138..9540b49 100644
--- a/HyperTizen/Globals.cs
+++ b/HyperTizen/Globals.cs
@@ -30,11 +30,11 @@ public static Globals Instance
}
public void SetConfig()
{
- ServerIp = Preference.Contains("rpcServer") ? Preference.Get("rpcServer") : null; //"192.168.69.200";
+ ServerIp = "192.168.69.200";//Preference.Contains("rpcServer") ? Preference.Get("rpcServer") : null;
ServerPort = 19400;
- Enabled = bool.Parse(Preference.Get("enabled"));
- Width = 480;
- Height = 270;
+ Enabled = true;//bool.Parse(Preference.Get("enabled"));
+ Width = 3840/8;
+ Height = 2160/8;
}
public string ServerIp; //IP of hyperhdr server
diff --git a/HyperTizen/HyperionClient.cs b/HyperTizen/HyperionClient.cs
index d843844..c80ce2c 100644
--- a/HyperTizen/HyperionClient.cs
+++ b/HyperTizen/HyperionClient.cs
@@ -30,8 +30,9 @@ public HyperionClient()
public async Task Start()
{
-
Globals.Instance.SetConfig();
+ VideoCapture.InitCapture();
+
while (Globals.Instance.Enabled)
{
if(Networking.client != null && Networking.client.Connected)
diff --git a/HyperTizen/Networking.cs b/HyperTizen/Networking.cs
index 7993c07..8d23e97 100644
--- a/HyperTizen/Networking.cs
+++ b/HyperTizen/Networking.cs
@@ -31,12 +31,12 @@ public static void SendRegister()
Debug.WriteLine("Sent Registration");
}
- public static void SendImage(byte[] yData, byte[] uvData, int width, int height)
+ public static async Task SendImageAsync(byte[] yData, byte[] uvData, int width, int height)
{
if (!client.Connected)
return;
byte[] message = CreateFlatBufferMessage(yData, uvData, width, height);
- SendMessageAndReceiveReply(message);
+ await SendMessageAndReceiveReplyAsync(message);
}
static byte[] CreateFlatBufferMessage(byte[] yData, byte[] uvData, int width, int height)
@@ -118,7 +118,7 @@ public static void ReadRegisterReply()
}
}
- static void SendMessageAndReceiveReply(byte[] message)
+ static async Task SendMessageAndReceiveReplyAsync(byte[] message)
{
try
{
@@ -131,10 +131,10 @@ static void SendMessageAndReceiveReply(byte[] message)
header[1] = (byte)((message.Length >> 16) & 0xFF);
header[2] = (byte)((message.Length >> 8) & 0xFF);
header[3] = (byte)((message.Length) & 0xFF);
- stream.Write(header, 0, header.Length);
+ await stream.WriteAsync(header, 0, header.Length);
Debug.WriteLine(message.Length);
- stream.Write(message, 0, message.Length);
+ await stream.WriteAsync(message, 0, message.Length);
Debug.WriteLine("Data sent. Waiting for Answer");
byte[] buffer = new byte[1024];
diff --git a/HyperTizen/SDK/SecVideoCapture.cs b/HyperTizen/SDK/SecVideoCapture.cs
new file mode 100644
index 0000000..4b4dc35
--- /dev/null
+++ b/HyperTizen/SDK/SecVideoCapture.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HyperTizen.SDK
+{
+ public static class SecVideoCapture
+ {
+ [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_unlock")]
+ unsafe public static extern int CaptureScreenUnlock();
+ [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen")] //record with ui
+ unsafe public static extern int CaptureScreen(int w, int h, ref Info_t pInfo);
+ [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_video_only")] // without ui
+ unsafe public static extern int CaptureScreenVideo(int w, int h, ref Info_t pInfo);
+ [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_video_only_crop")] // cropped
+ unsafe public static extern int CaptureScreenCrop(int w, int h, ref Info_t pInfo, int iCapture3DMode, int cropW, int cropH);
+ [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_no_lock_no_copy")] // unknown
+ unsafe public static extern int CaptureScreenNoLocknoCopy(int w, int h, ref Info_t pInfo);
+ //Main Func Errors:
+ //-1 "Input Pram is Wrong"
+ //-1,-2,-3,-5...negative numbers without 4 "Failed scaler_capture"
+
+ //Sub Func Errors
+ //-2 Error: capture type %s, plane %s video only %d
+ //-1 req size less or equal that crop size or non video for videoonly found
+ //-1 Home Screen & yt crop size, capture lock, video info related
+ //-4 Netflix/ Widevine Drm Stuff
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Info_t
+ {
+ public Int32 iGivenBufferSize1 { get; set; } //a6[0] = 0 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize2
+ public Int32 iGivenBufferSize2 { get; set; } //a6[1] = 4 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize1
+ public Int32 iWidth { get; set; } //a6[2] = 8 //ref: IceWater "caputre_param.ret_width"
+ public Int32 iHeight { get; set; } //a6[3] = 12 //ref: IceWater "caputre_param.ret_height"
+ public IntPtr pImageY { get; set; } //a6[4] // = 16 dest of memcopy copys v31 in adress with sizeof(needed buffer size(i think)) into this
+ public IntPtr pImageUV { get; set; } //a6[5] // = 20 use this! dest of memcopy copys v223 in adress with sizeof(needed buffer size) into this
+ public Int32 iRetColorFormat { get; set; } //a6[6] // = 24 //ref: IceWater "color format is"(YUV420 = 0, YUV422 = 1, YUV444 = 2 , None = 3, Everything else = Error)
+ public Int32 unknown2 { get; set; } //a6[7] // = 28
+ public Int32 capture3DMode { get; set; } // = 32 //ref: "Capture 3D Mode is DRM_SDP_3D_2D [%d:%s]" (DRM_SDP_3D_2D = 0, DRM_SDP_3D_FRAMEPACKING = 1, DRM_SDP_3D_FRAMESEQ = 2, DRM_SDP_3D_TOPBOTTOM = 3, DRM_SDP_3D_SIDEBYSIDE = 4)
+ //unk3 a6[15] // = 60
+ }
+ }
+}
diff --git a/HyperTizen/SDK/SystemInfo.cs b/HyperTizen/SDK/SystemInfo.cs
new file mode 100644
index 0000000..b515211
--- /dev/null
+++ b/HyperTizen/SDK/SystemInfo.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HyperTizen.SDK
+{
+ public static class SystemInfo
+ {
+ public static int TizenVersionMajor
+ {
+ get
+ {
+ string version;
+ Tizen.System.Information.TryGetValue("http://tizen.org/feature/platform.version", out version);
+ return int.Parse(version.Split('.')[0]);
+ }
+ }
+ public static int TizenVersionMinor
+ {
+ get
+ {
+ string version;
+ Tizen.System.Information.TryGetValue("http://tizen.org/feature/platform.version", out version);
+ return int.Parse(version.Split('.')[1]);
+ }
+ }
+ public static bool ImageCapture
+ {
+ get
+ {
+ bool isSupported;
+ Tizen.System.Information.TryGetValue("http://tizen.org/feature/media.image_capture", out isSupported);
+ return isSupported;
+ }
+ }
+ public static bool VideoRecording
+ {
+ get
+ {
+ bool isSupported;
+ Tizen.System.Information.TryGetValue("http://tizen.org/feature/media.video_recording", out isSupported);
+ return isSupported;
+ }
+ }
+ public static int ScreenWidth
+ {
+ get
+ {
+ int width;
+ Tizen.System.Information.TryGetValue("http://tizen.org/feature/screen.width", out width);
+ return width;
+ }
+ }
+ public static int ScreenHeight
+ {
+ get
+ {
+ int height;
+ Tizen.System.Information.TryGetValue("http://tizen.org/feature/screen.height", out height);
+ return height;
+ }
+ }
+
+ public static string ModelName
+ {
+ get
+ {
+ string name;
+ Tizen.System.Information.TryGetValue("http://tizen.org/system/model_name", out name);
+ return name;
+ }
+ }
+ }
+}
diff --git a/HyperTizen/VideoCapture.cs b/HyperTizen/VideoCapture.cs
index 898e390..2e2e04e 100644
--- a/HyperTizen/VideoCapture.cs
+++ b/HyperTizen/VideoCapture.cs
@@ -1,57 +1,46 @@
-using Newtonsoft.Json;
-using System.Threading.Tasks;
-using Tizen.Applications;
-using System.Net.WebSockets;
-using System.Text;
-using System;
-using System.Threading;
-using System.Runtime.InteropServices;
-using SkiaSharp;
-using Tizen.NUI;
+using System;
using System.Diagnostics;
using System.Linq;
-using Tizen.Uix.Tts;
-using System.Net.Sockets;
-using Tizen.Applications.RPCPort;
-using System.IO;
-using Tizen.Messaging.Messages;
-using System.Linq.Expressions;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+using HyperTizen.SDK;
using Tizen.Applications.Notifications;
+
namespace HyperTizen
{
+
+
+
+
public static class VideoCapture
{
- [StructLayout(LayoutKind.Sequential)]
- public struct Info_t
+ public static void InitCapture()
{
- public Int32 iGivenBufferSize1 { get; set; } //a6[0] = 0 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize2
- public Int32 iGivenBufferSize2 { get; set; } //a6[1] = 4 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize1
- public Int32 iWidth { get; set; } //a6[2] = 8 //ref: IceWater "caputre_param.ret_width"
- public Int32 iHeight { get; set; } //a6[3] = 12 //ref: IceWater "caputre_param.ret_height"
- public IntPtr pImageY { get; set; } //a6[4] // = 16 dest of memcopy copys v31 in adress with sizeof(needed buffer size(i think)) into this
- public IntPtr pImageUV { get; set; } //a6[5] // = 20 use this! dest of memcopy copys v223 in adress with sizeof(needed buffer size) into this
- public Int32 iRetColorFormat { get; set; } //a6[6] // = 24 //ref: IceWater "color format is"(YUV420 = 0, YUV422 = 1, YUV444 = 2 , None = 3, Everything else = Error)
- public Int32 unknown2 { get; set; } //a6[7] // = 28
- public Int32 capture3DMode { get; set; } // = 32 //ref: "Capture 3D Mode is DRM_SDP_3D_2D [%d:%s]" (DRM_SDP_3D_2D = 0, DRM_SDP_3D_FRAMEPACKING = 1, DRM_SDP_3D_FRAMESEQ = 2, DRM_SDP_3D_TOPBOTTOM = 3, DRM_SDP_3D_SIDEBYSIDE = 4)
- //unk3 a6[15] // = 60
+ try
+ {
+ Marshal.PrelinkAll(typeof(SDK.SecVideoCapture));
+ }
+ catch
+ {
+ Debug.WriteLine("VideoCapture InitCapture Error: Libarys not found");
+ Notification notification4 = new Notification
+ {
+ Title = "HyperTizen",
+ Content = "VideoCapture InitCapture Error: Libarys not found. Check if your Tizenversion is supported",
+ Count = 1
+ };
+ NotificationManager.Post(notification4);
+ }
+
+ int TizenVersionMajor = SystemInfo.TizenVersionMajor;
+ int TizenVersionMinor = SystemInfo.TizenVersionMinor;
+ bool ImageCapture = SystemInfo.ImageCapture;
+ bool VideoRecording = SystemInfo.VideoRecording;
+ int ScreenWidth = SystemInfo.ScreenWidth;
+ int ScreenHeight = SystemInfo.ScreenHeight;
+ string ModelName = SystemInfo.ModelName;
}
- //int (__fastcall *)(_DWORD, _DWORD, _DWORD)
- [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen")] //record with ui
- unsafe private static extern int CaptureScreen(int w, int h, ref Info_t pInfo);
- [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_video_only")] // without ui
- private static extern int CaptureScreenVideo(int w, int h, ref Info_t pInfo);
- [DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_video_only_crop")] // cropped
- private static extern int CaptureScreenCrop(int w, int h, ref Info_t pInfo, int iCapture3DMode, int cropW, int cropH);
- //Main Func Errors:
- //-1 "Input Pram is Wrong"
- //-1,-2,-3,-5...negative numbers without 4 "Failed scaler_capture"
-
- //Sub Func Errors
- //-2 Error: capture type %s, plane %s video only %d
- //-1 req size less or equal that crop size or non video for videoonly found
- //-1 Home Screen & yt crop size, capture lock, video info related
- //-4 Netflix/ Widevine Drm Stuff
static bool isRunning = true;
unsafe public static void DoCapture()
@@ -59,17 +48,13 @@ unsafe public static void DoCapture()
//These lines need to stay here somehow - they arent used but when i delete them the service breaks ??? weird tizen stuff...
var width = 480;
var height = 270;
-
- var yBufferSize = width * height * 2;
-
var uvBufferSizeYUV420 = (width / 2) * (height / 2);
- var uvBufferSizeYUV422 = (width / 2) * height;
- var uvBufferSizeYUV444 = width * height;
+
int NV12ySize = Globals.Instance.Width * Globals.Instance.Height;
int NV12uvSize = (Globals.Instance.Width * Globals.Instance.Height) / 2; // UV-Plane is half as big as Y-Plane in NV12
- Info_t info = new Info_t();
+ SDK.SecVideoCapture.Info_t info = new SDK.SecVideoCapture.Info_t();
info.iGivenBufferSize1 = NV12ySize;
info.iGivenBufferSize2 = NV12uvSize;
//info.iWidth = width;
@@ -79,7 +64,7 @@ unsafe public static void DoCapture()
//info.iRetColorFormat = 0;
//info.capture3DMode = 0;
- int result = CaptureScreen(Globals.Instance.Width, Globals.Instance.Height, ref info);
+ int result = SDK.SecVideoCapture.CaptureScreen(Globals.Instance.Width, Globals.Instance.Height, ref info); //call itself takes 35-40ms in debug mode so it should be 28-25fps
if (result < 0 && isRunning) //only send Notification once
{
switch (result)
@@ -143,11 +128,11 @@ unsafe public static void DoCapture()
if (hasAllZeroes1 && hasAllZeroes2)
throw new Exception("Sanity check Error");
+ //Debug.WriteLine(Convert.ToBase64String(managedArrayY));
+ //Debug.WriteLine(Convert.ToBase64String(managedArrayUV));
//(managedArrayY, managedArrayUV) = GenerateDummyYUVColor(Globals.Instance.Width, Globals.Instance.Height);
-
- Networking.SendImage(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height);
-
-
+
+ Task.Run( ()=>Networking.SendImageAsync(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height)); //100-150ms in debug mode (TODO:make async)
}
public static (byte[] yData, byte[] uvData) GenerateDummyYUVRandom(int width, int height)
diff --git a/HyperTizen/tizen-manifest.xml b/HyperTizen/tizen-manifest.xml
index 2ee86b8..27e981d 100644
--- a/HyperTizen/tizen-manifest.xml
+++ b/HyperTizen/tizen-manifest.xml
@@ -1,5 +1,5 @@
-
+
Reis Can
@@ -12,7 +12,6 @@
http://tizen.org/privilege/notification
http://tizen.org/privilege/internet
http://developer.samsung.com/privilege/drmplay
- http://developer.samsung.com/privilege/drminfo
http://developer.samsung.com/privilege/esplay
From 1f0fbf0fc58c67ab4774d021aaf7ea36e429d2e2 Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Wed, 19 Mar 2025 04:52:06 +0100
Subject: [PATCH 09/13] some fixes
---
HyperTizen/Globals.cs | 1 +
HyperTizen/HyperionClient.cs | 5 +-
HyperTizen/Networking.cs | 60 +++++++++++------
HyperTizen/SDK/SecVideoCapture.cs | 20 +++---
HyperTizen/VideoCapture.cs | 104 +++++++++++++++---------------
HyperTizen/tizen-manifest.xml | 6 +-
6 files changed, 108 insertions(+), 88 deletions(-)
diff --git a/HyperTizen/Globals.cs b/HyperTizen/Globals.cs
index 9540b49..e067411 100644
--- a/HyperTizen/Globals.cs
+++ b/HyperTizen/Globals.cs
@@ -42,5 +42,6 @@ public void SetConfig()
public int Width; //Capture Width
public int Height; //Capture Height
public bool Enabled; //Is the service enabled
+ public uint SessionId; //Used for detection if some Threads are executed beacuse of the last Session -> if so ignore these
}
}
diff --git a/HyperTizen/HyperionClient.cs b/HyperTizen/HyperionClient.cs
index c80ce2c..ba5244b 100644
--- a/HyperTizen/HyperionClient.cs
+++ b/HyperTizen/HyperionClient.cs
@@ -25,10 +25,11 @@ internal class HyperionClient
{
public HyperionClient()
{
- Task.Run(() => Start());
+ //Task.Run(() => Start());
+ Start();
}
- public async Task Start()
+ public void Start()
{
Globals.Instance.SetConfig();
VideoCapture.InitCapture();
diff --git a/HyperTizen/Networking.cs b/HyperTizen/Networking.cs
index 8d23e97..77e0cac 100644
--- a/HyperTizen/Networking.cs
+++ b/HyperTizen/Networking.cs
@@ -15,6 +15,17 @@ public static class Networking
public static TcpClient client;
public static NetworkStream stream;
+ public static void DisconnectClient()
+ {
+ if (stream != null)
+ {
+ stream.Flush();
+ stream.Close(500);
+ }
+
+ client.Close();
+ }
+
public static void SendRegister()
{
client = new TcpClient(Globals.Instance.ServerIp, Globals.Instance.ServerPort);
@@ -28,12 +39,12 @@ public static void SendRegister()
stream.Write(header, 0, header.Length);
stream.Write(registrationMessage, 0, registrationMessage.Length);
ReadRegisterReply();
- Debug.WriteLine("Sent Registration");
+ Debug.WriteLine("SendRegister: Data sent");
}
public static async Task SendImageAsync(byte[] yData, byte[] uvData, int width, int height)
{
- if (!client.Connected)
+ if (client == null || !client.Connected)
return;
byte[] message = CreateFlatBufferMessage(yData, uvData, width, height);
await SendMessageAndReceiveReplyAsync(message);
@@ -41,9 +52,9 @@ public static async Task SendImageAsync(byte[] yData, byte[] uvData, int width,
static byte[] CreateFlatBufferMessage(byte[] yData, byte[] uvData, int width, int height)
{
- if (!client.Connected)
+ if (client == null || !client.Connected)
return null;
- var builder = new FlatBufferBuilder(yData.Length + uvData.Length + 100);
+ var builder = new FlatBufferBuilder(yData.Length + uvData.Length + 1000);//TODO:Check how to calculate correctly: changed from +100 to +1000 and crashes in the first sec got fixed
var yVector = NV12Image.CreateDataYVector(builder, yData);
var uvVector = NV12Image.CreateDataUvVector(builder, uvData);
@@ -80,10 +91,10 @@ static Reply ParseReply(byte[] receivedData)
public static byte[] CreateRegistrationMessage(bool subscribe)
{
- if (!client.Connected)
+ if (client == null || !client.Connected)
return null;
- var builder = new FlatBufferBuilder(256);
+ var builder = new FlatBufferBuilder(256 + 1000); //TODO:Check how to calculate correctly
var originOffset = builder.CreateString("HyperTizen");
@@ -103,7 +114,7 @@ public static byte[] CreateRegistrationMessage(bool subscribe)
public static void ReadRegisterReply()
{
- if (!client.Connected)
+ if (client == null || !client.Connected)
return;
byte[] buffer = new byte[1024];
@@ -114,7 +125,7 @@ public static void ReadRegisterReply()
Array.Copy(buffer, replyData, bytesRead);
Reply reply = ParseReply(replyData);
- Debug.WriteLine($"Registered: {reply.Registered}");
+ Debug.WriteLine($"ReadRegisterReply: Reply_Registered: {reply.Registered}");
}
}
@@ -122,8 +133,8 @@ static async Task SendMessageAndReceiveReplyAsync(byte[] message)
{
try
{
- if (!client.Connected)
- return;
+ if (client == null || !client.Connected)
+ return;
{
var header = new byte[4];
@@ -133,35 +144,42 @@ static async Task SendMessageAndReceiveReplyAsync(byte[] message)
header[3] = (byte)((message.Length) & 0xFF);
await stream.WriteAsync(header, 0, header.Length);
- Debug.WriteLine(message.Length);
+ Debug.WriteLine("SendMessageAndReceiveReply: message.Length; " + message.Length);
await stream.WriteAsync(message, 0, message.Length);
- Debug.WriteLine("Data sent. Waiting for Answer");
+ Debug.WriteLine("SendMessageAndReceiveReply: Data sent");
byte[] buffer = new byte[1024];
- int bytesRead = stream.Read(buffer, 0, buffer.Length);
+ int bytesRead = stream.ReadAsync(buffer, 0, buffer.Length).Result;
if (bytesRead > 0)
{
byte[] replyData = new byte[bytesRead];
Array.Copy(buffer, replyData, bytesRead);
- string test = BitConverter.ToString(replyData);
-
-
Reply reply = ParseReply(replyData);
- Debug.WriteLine($"Error: {reply.Error}");
- Debug.WriteLine($"Video: {reply.Video}");
- Debug.WriteLine($"Registered: {reply.Registered}");
+
+ Debug.WriteLine($"SendMessageAndReceiveReply: Reply_Video: {reply.Video}");
+ Debug.WriteLine($"SendMessageAndReceiveReply: Reply_Registered: {reply.Registered}");
+ if (!string.IsNullOrEmpty(reply.Error))
+ {
+ Debug.WriteLine("SendMessageAndReceiveReply: (closing tcp client now) Reply_Error: " + reply.Error);
+ DisconnectClient();
+ return;
+ }
}
else
{
- Debug.WriteLine("No Answer from Server.");
+ Debug.WriteLine("SendMessageAndReceiveReply: (closing tcp client now) No Answer from Server.");
+ DisconnectClient();
+ return;
}
}
}
catch (Exception ex)
{
- Debug.WriteLine("Error Sending/Receiving: " + ex.Message);
+ Debug.WriteLine("SendMessageAndReceiveReply: Exception (closing tcp client now) Sending/Receiving: " + ex.Message);
+ DisconnectClient();
+ return;
}
}
diff --git a/HyperTizen/SDK/SecVideoCapture.cs b/HyperTizen/SDK/SecVideoCapture.cs
index 4b4dc35..dd14aa5 100644
--- a/HyperTizen/SDK/SecVideoCapture.cs
+++ b/HyperTizen/SDK/SecVideoCapture.cs
@@ -30,17 +30,17 @@ public static class SecVideoCapture
//-4 Netflix/ Widevine Drm Stuff
[StructLayout(LayoutKind.Sequential)]
- public struct Info_t
+ unsafe public struct Info_t
{
- public Int32 iGivenBufferSize1 { get; set; } //a6[0] = 0 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize2
- public Int32 iGivenBufferSize2 { get; set; } //a6[1] = 4 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize1
- public Int32 iWidth { get; set; } //a6[2] = 8 //ref: IceWater "caputre_param.ret_width"
- public Int32 iHeight { get; set; } //a6[3] = 12 //ref: IceWater "caputre_param.ret_height"
- public IntPtr pImageY { get; set; } //a6[4] // = 16 dest of memcopy copys v31 in adress with sizeof(needed buffer size(i think)) into this
- public IntPtr pImageUV { get; set; } //a6[5] // = 20 use this! dest of memcopy copys v223 in adress with sizeof(needed buffer size) into this
- public Int32 iRetColorFormat { get; set; } //a6[6] // = 24 //ref: IceWater "color format is"(YUV420 = 0, YUV422 = 1, YUV444 = 2 , None = 3, Everything else = Error)
- public Int32 unknown2 { get; set; } //a6[7] // = 28
- public Int32 capture3DMode { get; set; } // = 32 //ref: "Capture 3D Mode is DRM_SDP_3D_2D [%d:%s]" (DRM_SDP_3D_2D = 0, DRM_SDP_3D_FRAMEPACKING = 1, DRM_SDP_3D_FRAMESEQ = 2, DRM_SDP_3D_TOPBOTTOM = 3, DRM_SDP_3D_SIDEBYSIDE = 4)
+ unsafe public Int32 iGivenBufferSize1 { get; set; } //a6[0] = 0 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize2
+ unsafe public Int32 iGivenBufferSize2 { get; set; } //a6[1] = 4 //ref: "C Buffer Size is too small. needed %d bytes but given %d bytes [%d:%s]" needs to be = iGivenBufferSize1
+ unsafe public Int32 iWidth { get; set; } //a6[2] = 8 //ref: IceWater "caputre_param.ret_width"
+ unsafe public Int32 iHeight { get; set; } //a6[3] = 12 //ref: IceWater "caputre_param.ret_height"
+ unsafe public IntPtr pImageY { get; set; } //a6[4] // = 16 dest of memcopy copys v31 in adress with sizeof(needed buffer size(i think)) into this
+ unsafe public IntPtr pImageUV { get; set; } //a6[5] // = 20 use this! dest of memcopy copys v223 in adress with sizeof(needed buffer size) into this
+ unsafe public Int32 iRetColorFormat { get; set; } //a6[6] // = 24 //ref: IceWater "color format is"(YUV420 = 0, YUV422 = 1, YUV444 = 2 , None = 3, Everything else = Error)
+ unsafe public Int32 unknown2 { get; set; } //a6[7] // = 28
+ unsafe public Int32 capture3DMode { get; set; } // = 32 //ref: "Capture 3D Mode is DRM_SDP_3D_2D [%d:%s]" (DRM_SDP_3D_2D = 0, DRM_SDP_3D_FRAMEPACKING = 1, DRM_SDP_3D_FRAMESEQ = 2, DRM_SDP_3D_TOPBOTTOM = 3, DRM_SDP_3D_SIDEBYSIDE = 4)
//unk3 a6[15] // = 60
}
}
diff --git a/HyperTizen/VideoCapture.cs b/HyperTizen/VideoCapture.cs
index 2e2e04e..6c157bb 100644
--- a/HyperTizen/VideoCapture.cs
+++ b/HyperTizen/VideoCapture.cs
@@ -10,9 +10,6 @@
namespace HyperTizen
{
-
-
-
public static class VideoCapture
{
public static void InitCapture()
@@ -48,7 +45,7 @@ unsafe public static void DoCapture()
//These lines need to stay here somehow - they arent used but when i delete them the service breaks ??? weird tizen stuff...
var width = 480;
var height = 270;
- var uvBufferSizeYUV420 = (width / 2) * (height / 2);
+ var uvBufferSizeYUV420 = (width / 2) * (height / 2);
int NV12ySize = Globals.Instance.Width * Globals.Instance.Height;
@@ -65,58 +62,57 @@ unsafe public static void DoCapture()
//info.capture3DMode = 0;
int result = SDK.SecVideoCapture.CaptureScreen(Globals.Instance.Width, Globals.Instance.Height, ref info); //call itself takes 35-40ms in debug mode so it should be 28-25fps
- if (result < 0 && isRunning) //only send Notification once
+ if (result < 0) //only send Notification once
{
- switch (result)
- {
- case -4:
- Debug.WriteLine("CaptureScreen Result: -4 [Netflix/ Widevine Drm Error]");
- Notification notification4 = new Notification
- {
- Title = "HyperTizen",
- Content = "Capture Error: Seems like you are watching DRM protected content",
- Count = 1
- };
- NotificationManager.Post(notification4);
- break;
- case -1:
- Debug.WriteLine("CaptureScreen Result: -1 [Input Pram is wrong / req size less or equal that crop size / non video for videoonly found]");
- Notification notification1 = new Notification
- {
- Title = "HyperTizen",
- Content = "Capture Error: Input Pram seems wrong",
- Count = 1
- };
- NotificationManager.Post(notification1);
- break;
- case -2:
- Debug.WriteLine("CaptureScreen Result: -2 [capture type %s, plane %s video only %d / Failed scaler_capture]");
- Notification notification2 = new Notification
- {
- Title = "HyperTizen",
- Content = "Capture Error: Failed scaler",
- Count = 1
- };
- NotificationManager.Post(notification2);
- break;
- default:
- Notification notificationN = new Notification
- {
- Title = "HyperTizen",
- Content = "Capture Error: New Error occured. Please report ID:"+ result,
- Count = 1
- };
- NotificationManager.Post(notificationN);
- break;
- }
+ if(isRunning)
+ switch (result)
+ {
+ case -4:
+ Debug.WriteLine("CaptureScreen Result: -4 [Netflix/ Widevine Drm Error]");
+ Notification notification4 = new Notification
+ {
+ Title = "HyperTizen",
+ Content = "Capture Error: Seems like you are watching DRM protected content",
+ Count = 1
+ };
+ NotificationManager.Post(notification4);
+ break;
+ case -1:
+ Debug.WriteLine("CaptureScreen Result: -1 [Input Pram is wrong / req size less or equal that crop size / non video for videoonly found]");
+ Notification notification1 = new Notification
+ {
+ Title = "HyperTizen",
+ Content = "Capture Error: Input Pram seems wrong",
+ Count = 1
+ };
+ NotificationManager.Post(notification1);
+ break;
+ case -2:
+ Debug.WriteLine("CaptureScreen Result: -2 [capture type %s, plane %s video only %d / Failed scaler_capture]");
+ Notification notification2 = new Notification
+ {
+ Title = "HyperTizen",
+ Content = "Capture Error: Failed scaler",
+ Count = 1
+ };
+ NotificationManager.Post(notification2);
+ break;
+ default:
+ Notification notificationN = new Notification
+ {
+ Title = "HyperTizen",
+ Content = "Capture Error: New Error occured. Please report ID:" + result,
+ Count = 1
+ };
+ NotificationManager.Post(notificationN);
+ break;
+ }
isRunning = false;
-
return;
}
isRunning = true;
-
byte[] managedArrayY = new byte[NV12ySize];
Marshal.Copy(info.pImageY, managedArrayY, 0, NV12ySize);
@@ -128,11 +124,17 @@ unsafe public static void DoCapture()
if (hasAllZeroes1 && hasAllZeroes2)
throw new Exception("Sanity check Error");
+ Debug.WriteLine("DoCapture: NV12ySize: " + managedArrayY.Length);
+ //Debug.WriteLine(Convert.ToBase64String(managedArrayY).Length);
//Debug.WriteLine(Convert.ToBase64String(managedArrayY));
//Debug.WriteLine(Convert.ToBase64String(managedArrayUV));
//(managedArrayY, managedArrayUV) = GenerateDummyYUVColor(Globals.Instance.Width, Globals.Instance.Height);
-
- Task.Run( ()=>Networking.SendImageAsync(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height)); //100-150ms in debug mode (TODO:make async)
+
+ Task.Run( ()=>Networking.SendImageAsync(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height));
+ //Networking.SendImageAsync(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height); //100-150ms in debug mode
+
+ int test = 3;
+ return;
}
public static (byte[] yData, byte[] uvData) GenerateDummyYUVRandom(int width, int height)
diff --git a/HyperTizen/tizen-manifest.xml b/HyperTizen/tizen-manifest.xml
index 27e981d..b145920 100644
--- a/HyperTizen/tizen-manifest.xml
+++ b/HyperTizen/tizen-manifest.xml
@@ -1,8 +1,8 @@
-
+
Reis Can
-
+
HyperTizen.png
@@ -11,8 +11,6 @@
http://tizen.org/privilege/notification
http://tizen.org/privilege/internet
- http://developer.samsung.com/privilege/drmplay
- http://developer.samsung.com/privilege/esplay
From 6559d33f8bae2aa519d36479d59949465c732138 Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Mon, 24 Mar 2025 02:29:49 +0100
Subject: [PATCH 10/13] Performance + Stability fixes
---
HyperTizen/Globals.cs | 3 +-
HyperTizen/Helper/Log.cs | 53 +++++++++++++++++
HyperTizen/HyperionClient.cs | 19 ++++--
HyperTizen/Networking.cs | 112 +++++++++++++++++++++--------------
HyperTizen/VideoCapture.cs | 97 +++++++++++++++---------------
5 files changed, 182 insertions(+), 102 deletions(-)
create mode 100644 HyperTizen/Helper/Log.cs
diff --git a/HyperTizen/Globals.cs b/HyperTizen/Globals.cs
index e067411..ebe501e 100644
--- a/HyperTizen/Globals.cs
+++ b/HyperTizen/Globals.cs
@@ -30,7 +30,7 @@ public static Globals Instance
}
public void SetConfig()
{
- ServerIp = "192.168.69.200";//Preference.Contains("rpcServer") ? Preference.Get("rpcServer") : null;
+ ServerIp = Preference.Contains("rpcServer") ? Preference.Get("rpcServer") : null; //"192.168.69.200"
ServerPort = 19400;
Enabled = true;//bool.Parse(Preference.Get("enabled"));
Width = 3840/8;
@@ -42,6 +42,5 @@ public void SetConfig()
public int Width; //Capture Width
public int Height; //Capture Height
public bool Enabled; //Is the service enabled
- public uint SessionId; //Used for detection if some Threads are executed beacuse of the last Session -> if so ignore these
}
}
diff --git a/HyperTizen/Helper/Log.cs b/HyperTizen/Helper/Log.cs
new file mode 100644
index 0000000..07da707
--- /dev/null
+++ b/HyperTizen/Helper/Log.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tizen.Applications.Notifications;
+
+namespace HyperTizen.Helper
+{
+ public enum eLogType
+ {
+ Debug,
+ Info,
+ Warning,
+ Error,
+ Performance
+ }
+ public static class Log
+ {
+ public static void Write(eLogType type,string message)
+ {
+ switch (type)
+ {
+ case eLogType.Debug:
+ Debug.WriteLine(message);
+ break;
+ case eLogType.Info:
+ //Debug.WriteLine(message);
+ break;
+ case eLogType.Warning:
+ Debug.WriteLine(message);
+ break;
+ case eLogType.Error:
+ Debug.WriteLine(message);
+ {
+ Notification notification = new Notification
+ {
+ Title = "HyperTizen Error!",
+ Content = message,
+ Count = 1
+ };
+ NotificationManager.Post(notification);
+ }
+ break;
+ case eLogType.Performance:
+ //Debug.WriteLine(message);
+ break;
+ }
+
+ }
+ }
+}
diff --git a/HyperTizen/HyperionClient.cs b/HyperTizen/HyperionClient.cs
index ba5244b..562a00c 100644
--- a/HyperTizen/HyperionClient.cs
+++ b/HyperTizen/HyperionClient.cs
@@ -25,21 +25,28 @@ internal class HyperionClient
{
public HyperionClient()
{
- //Task.Run(() => Start());
- Start();
+ Task.Run(() => Start());
}
- public void Start()
+ public async Task Start()
{
Globals.Instance.SetConfig();
VideoCapture.InitCapture();
while (Globals.Instance.Enabled)
{
- if(Networking.client != null && Networking.client.Connected)
- VideoCapture.DoCapture();
+ if(Networking.client != null && Networking.client.Client.Connected)
+ {
+ var watchFPS = System.Diagnostics.Stopwatch.StartNew();
+ await Task.Run(() =>VideoCapture.DoCapture()); //VideoCapture.DoDummyCapture();
+ watchFPS.Stop();
+ var elapsedFPS = 1 / watchFPS.Elapsed.TotalSeconds;
+ Helper.Log.Write(Helper.eLogType.Performance, "VideoCapture.DoCapture() FPS: " + elapsedFPS);
+ Helper.Log.Write(Helper.eLogType.Performance, "VideoCapture.DoCapture() elapsed ms: " + watchFPS.ElapsedMilliseconds);
+ }
+
else
- Networking.SendRegister();
+ await Task.Run(() => Networking.SendRegister());
}
}
diff --git a/HyperTizen/Networking.cs b/HyperTizen/Networking.cs
index 77e0cac..5bc5bf9 100644
--- a/HyperTizen/Networking.cs
+++ b/HyperTizen/Networking.cs
@@ -7,6 +7,7 @@
using System.Threading.Tasks;
using Google.FlatBuffers;
using hyperhdrnet;
+using Tizen.Messaging.Messages;
namespace HyperTizen
{
@@ -29,8 +30,14 @@ public static void DisconnectClient()
public static void SendRegister()
{
client = new TcpClient(Globals.Instance.ServerIp, Globals.Instance.ServerPort);
+ if (client == null)
+ return;
stream = Networking.client.GetStream();
- byte[] registrationMessage = Networking.CreateRegistrationMessage(true);
+ if (stream == null)
+ return;
+ byte[] registrationMessage = Networking.CreateRegistrationMessage();
+ if (registrationMessage == null)
+ return;
var header = new byte[4];
header[0] = (byte)((registrationMessage.Length >> 24) & 0xFF);
header[1] = (byte)((registrationMessage.Length >> 16) & 0xFF);
@@ -39,22 +46,27 @@ public static void SendRegister()
stream.Write(header, 0, header.Length);
stream.Write(registrationMessage, 0, registrationMessage.Length);
ReadRegisterReply();
- Debug.WriteLine("SendRegister: Data sent");
+ Helper.Log.Write(Helper.eLogType.Info, "SendRegister: Data sent");
}
public static async Task SendImageAsync(byte[] yData, byte[] uvData, int width, int height)
{
- if (client == null || !client.Connected)
+ if (client == null || !client.Connected || stream == null)
return;
byte[] message = CreateFlatBufferMessage(yData, uvData, width, height);
- await SendMessageAndReceiveReplyAsync(message);
- }
+ if (message == null)
+ return;
+ var watchFPS = System.Diagnostics.Stopwatch.StartNew();
+ _ = SendMessageAndReceiveReplyAsync(message);
+ watchFPS.Stop();
+ Helper.Log.Write(Helper.eLogType.Performance, "SendImageAsync elapsed ms: " + watchFPS.ElapsedMilliseconds);
+ }
static byte[] CreateFlatBufferMessage(byte[] yData, byte[] uvData, int width, int height)
{
- if (client == null || !client.Connected)
+ if (client == null || !client.Connected || stream == null)
return null;
- var builder = new FlatBufferBuilder(yData.Length + uvData.Length + 1000);//TODO:Check how to calculate correctly: changed from +100 to +1000 and crashes in the first sec got fixed
+ var builder = new FlatBufferBuilder(yData.Length + uvData.Length + 100);
var yVector = NV12Image.CreateDataYVector(builder, yData);
var uvVector = NV12Image.CreateDataUvVector(builder, uvData);
@@ -85,16 +97,16 @@ static byte[] CreateFlatBufferMessage(byte[] yData, byte[] uvData, int width, in
static Reply ParseReply(byte[] receivedData)
{
- var byteBuffer = new ByteBuffer(receivedData,4); //shift for header
+ var byteBuffer = new ByteBuffer(receivedData, 4); //shift for header
return Reply.GetRootAsReply(byteBuffer);
}
- public static byte[] CreateRegistrationMessage(bool subscribe)
+ public static byte[] CreateRegistrationMessage()
{
- if (client == null || !client.Connected)
+ if (client == null || !client.Connected || stream == null)
return null;
- var builder = new FlatBufferBuilder(256 + 1000); //TODO:Check how to calculate correctly
+ var builder = new FlatBufferBuilder(256); //TODO:Check how to calculate correctly
var originOffset = builder.CreateString("HyperTizen");
@@ -114,7 +126,7 @@ public static byte[] CreateRegistrationMessage(bool subscribe)
public static void ReadRegisterReply()
{
- if (client == null || !client.Connected)
+ if (client == null || !client.Connected || stream == null)
return;
byte[] buffer = new byte[1024];
@@ -125,7 +137,40 @@ public static void ReadRegisterReply()
Array.Copy(buffer, replyData, bytesRead);
Reply reply = ParseReply(replyData);
- Debug.WriteLine($"ReadRegisterReply: Reply_Registered: {reply.Registered}");
+ Helper.Log.Write(Helper.eLogType.Info, $"ReadRegisterReply: Reply_Registered: {reply.Registered}");
+ }
+ }
+
+ public static async Task ReadImageReply()
+ {
+ if (client == null || !client.Connected || stream == null)
+ return;
+
+ byte[] buffer = new byte[1024];
+ int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
+ if (bytesRead > 0)
+ {
+
+ byte[] replyData = new byte[bytesRead];
+ Array.Copy(buffer, replyData, bytesRead);
+ Reply reply = ParseReply(replyData);
+
+
+ Helper.Log.Write(Helper.eLogType.Info, $"SendMessageAndReceiveReply: Reply_Video: {reply.Video}");
+ Helper.Log.Write(Helper.eLogType.Info, $"SendMessageAndReceiveReply: Reply_Registered: {reply.Registered}");
+ if (!string.IsNullOrEmpty(reply.Error))
+ {
+ Helper.Log.Write(Helper.eLogType.Error, "SendMessageAndReceiveReply: (closing tcp client now) Reply_Error: " + reply.Error);
+ //Debug.WriteLine("SendMessageAndReceiveReply: Faulty msg(size:" + message.Length + "): " + BitConverter.ToString(message));
+ DisconnectClient();
+ return;
+ }
+ }
+ else
+ {
+ Helper.Log.Write(Helper.eLogType.Error, "SendMessageAndReceiveReply: (closing tcp client now) No Answer from Server.");
+ DisconnectClient();
+ return;
}
}
@@ -133,51 +178,28 @@ static async Task SendMessageAndReceiveReplyAsync(byte[] message)
{
try
{
- if (client == null || !client.Connected)
+ if (client == null || !client.Connected || stream == null)
return;
{
-
+
var header = new byte[4];
header[0] = (byte)((message.Length >> 24) & 0xFF);
header[1] = (byte)((message.Length >> 16) & 0xFF);
header[2] = (byte)((message.Length >> 8) & 0xFF);
header[3] = (byte)((message.Length) & 0xFF);
await stream.WriteAsync(header, 0, header.Length);
-
- Debug.WriteLine("SendMessageAndReceiveReply: message.Length; " + message.Length);
+
+ Helper.Log.Write(Helper.eLogType.Info, "SendMessageAndReceiveReply: message.Length; " + message.Length);
await stream.WriteAsync(message, 0, message.Length);
- Debug.WriteLine("SendMessageAndReceiveReply: Data sent");
-
- byte[] buffer = new byte[1024];
- int bytesRead = stream.ReadAsync(buffer, 0, buffer.Length).Result;
- if (bytesRead > 0)
- {
-
- byte[] replyData = new byte[bytesRead];
- Array.Copy(buffer, replyData, bytesRead);
- Reply reply = ParseReply(replyData);
-
-
- Debug.WriteLine($"SendMessageAndReceiveReply: Reply_Video: {reply.Video}");
- Debug.WriteLine($"SendMessageAndReceiveReply: Reply_Registered: {reply.Registered}");
- if (!string.IsNullOrEmpty(reply.Error))
- {
- Debug.WriteLine("SendMessageAndReceiveReply: (closing tcp client now) Reply_Error: " + reply.Error);
- DisconnectClient();
- return;
- }
- }
- else
- {
- Debug.WriteLine("SendMessageAndReceiveReply: (closing tcp client now) No Answer from Server.");
- DisconnectClient();
- return;
- }
+ await stream.FlushAsync();
+ Helper.Log.Write(Helper.eLogType.Info, "SendMessageAndReceiveReply: Data sent");
+ _ = ReadImageReply();
+
}
}
catch (Exception ex)
{
- Debug.WriteLine("SendMessageAndReceiveReply: Exception (closing tcp client now) Sending/Receiving: " + ex.Message);
+ Helper.Log.Write(Helper.eLogType.Error, "SendMessageAndReceiveReply: Exception (closing tcp client now) Sending/Receiving: " + ex.Message);
DisconnectClient();
return;
}
diff --git a/HyperTizen/VideoCapture.cs b/HyperTizen/VideoCapture.cs
index 6c157bb..7c1af57 100644
--- a/HyperTizen/VideoCapture.cs
+++ b/HyperTizen/VideoCapture.cs
@@ -1,17 +1,29 @@
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using HyperTizen.SDK;
+using Tizen.Applications;
using Tizen.Applications.Notifications;
namespace HyperTizen
{
+ public class ImageData
+ {
+ public byte[] yData { get; set; }
+ public byte[] uvData { get; set; }
+ }
+
public static class VideoCapture
{
+ private static IntPtr pImageY;
+ private static IntPtr pImageUV;
+ private static byte[] managedArrayY;
+ private static byte[] managedArrayUV;
public static void InitCapture()
{
try
@@ -20,16 +32,16 @@ public static void InitCapture()
}
catch
{
- Debug.WriteLine("VideoCapture InitCapture Error: Libarys not found");
- Notification notification4 = new Notification
- {
- Title = "HyperTizen",
- Content = "VideoCapture InitCapture Error: Libarys not found. Check if your Tizenversion is supported",
- Count = 1
- };
- NotificationManager.Post(notification4);
+ Helper.Log.Write(Helper.eLogType.Error, "VideoCapture.InitCapture() Error: Libarys not found. Check if your Tizenversion is supported");
}
+ int NV12ySize = Globals.Instance.Width * Globals.Instance.Height;
+ int NV12uvSize = (Globals.Instance.Width * Globals.Instance.Height) / 2; // UV-Plane is half as big as Y-Plane in NV12
+ pImageY = Marshal.AllocHGlobal(NV12ySize);
+ pImageUV = Marshal.AllocHGlobal(NV12uvSize);
+ managedArrayY = new byte[NV12ySize];
+ managedArrayUV = new byte[NV12uvSize];
+
int TizenVersionMajor = SystemInfo.TizenVersionMajor;
int TizenVersionMinor = SystemInfo.TizenVersionMinor;
bool ImageCapture = SystemInfo.ImageCapture;
@@ -37,6 +49,7 @@ public static void InitCapture()
int ScreenWidth = SystemInfo.ScreenWidth;
int ScreenHeight = SystemInfo.ScreenHeight;
string ModelName = SystemInfo.ModelName;
+
}
static bool isRunning = true;
@@ -56,55 +69,33 @@ unsafe public static void DoCapture()
info.iGivenBufferSize2 = NV12uvSize;
//info.iWidth = width;
//info.iHeight = height;
- info.pImageY = Marshal.AllocHGlobal(NV12ySize);
- info.pImageUV = Marshal.AllocHGlobal(NV12uvSize);
+ info.pImageY = pImageY;
+ info.pImageUV = pImageUV;
//info.iRetColorFormat = 0;
//info.capture3DMode = 0;
-
+ var watchFPS = System.Diagnostics.Stopwatch.StartNew();
int result = SDK.SecVideoCapture.CaptureScreen(Globals.Instance.Width, Globals.Instance.Height, ref info); //call itself takes 35-40ms in debug mode so it should be 28-25fps
+ watchFPS.Stop();
+ var elapsedFPS = 1 / watchFPS.Elapsed.TotalSeconds;
+ Helper.Log.Write(Helper.eLogType.Performance, "SDK.SecVideoCapture.CaptureScreen FPS: " + elapsedFPS);
+ Helper.Log.Write(Helper.eLogType.Performance, "SDK.SecVideoCapture.CaptureScreen elapsed ms: " + watchFPS.ElapsedMilliseconds);
if (result < 0) //only send Notification once
{
if(isRunning)
switch (result)
{
case -4:
- Debug.WriteLine("CaptureScreen Result: -4 [Netflix/ Widevine Drm Error]");
- Notification notification4 = new Notification
- {
- Title = "HyperTizen",
- Content = "Capture Error: Seems like you are watching DRM protected content",
- Count = 1
- };
- NotificationManager.Post(notification4);
+ Helper.Log.Write(Helper.eLogType.Error, "SDK.SecVideoCapture.CaptureScreen Result: -4 [Netflix/ Widevine Drm Error]. Seems like you are watching DRM protected content. Capture is not supported for that yet");
break;
case -1:
- Debug.WriteLine("CaptureScreen Result: -1 [Input Pram is wrong / req size less or equal that crop size / non video for videoonly found]");
- Notification notification1 = new Notification
- {
- Title = "HyperTizen",
- Content = "Capture Error: Input Pram seems wrong",
- Count = 1
- };
- NotificationManager.Post(notification1);
+ Helper.Log.Write(Helper.eLogType.Error, "SDK.SecVideoCapture.CaptureScreen Result: -1 [Input Pram is wrong / req size less or equal that crop size / non video for videoonly found]. This can occur when Settings or Video Inputs of the TV change. Check in HyperHDR if the Live-View is still showing an image.");
break;
case -2:
- Debug.WriteLine("CaptureScreen Result: -2 [capture type %s, plane %s video only %d / Failed scaler_capture]");
- Notification notification2 = new Notification
- {
- Title = "HyperTizen",
- Content = "Capture Error: Failed scaler",
- Count = 1
- };
- NotificationManager.Post(notification2);
+ Helper.Log.Write(Helper.eLogType.Error, "SDK.SecVideoCapture.CaptureScreen Result: -2 [capture type %s, plane %s video only %d / Failed scaler_capture]. Please try restarting the TV (coldboot)");
+ //Application.Current.Exit();
break;
default:
- Notification notificationN = new Notification
- {
- Title = "HyperTizen",
- Content = "Capture Error: New Error occured. Please report ID:" + result,
- Count = 1
- };
- NotificationManager.Post(notificationN);
+ Helper.Log.Write(Helper.eLogType.Error, "SDK.SecVideoCapture.CaptureScreen Result: "+ result + " New Error Occured. Please report the shown Number on Github. Also enable every Log Option in the UI, run the Service in Debug Mode and send the Logs.");
break;
}
isRunning = false;
@@ -113,10 +104,8 @@ unsafe public static void DoCapture()
isRunning = true;
- byte[] managedArrayY = new byte[NV12ySize];
- Marshal.Copy(info.pImageY, managedArrayY, 0, NV12ySize);
- byte[] managedArrayUV = new byte[NV12uvSize];
+ Marshal.Copy(info.pImageY, managedArrayY, 0, NV12ySize);
Marshal.Copy(info.pImageUV, managedArrayUV, 0, NV12uvSize);
bool hasAllZeroes1 = managedArrayY.All(singleByte => singleByte == 0);
@@ -124,16 +113,26 @@ unsafe public static void DoCapture()
if (hasAllZeroes1 && hasAllZeroes2)
throw new Exception("Sanity check Error");
- Debug.WriteLine("DoCapture: NV12ySize: " + managedArrayY.Length);
+ Helper.Log.Write(Helper.eLogType.Info, "DoCapture: NV12ySize: " + managedArrayY.Length);
//Debug.WriteLine(Convert.ToBase64String(managedArrayY).Length);
//Debug.WriteLine(Convert.ToBase64String(managedArrayY));
//Debug.WriteLine(Convert.ToBase64String(managedArrayUV));
- //(managedArrayY, managedArrayUV) = GenerateDummyYUVColor(Globals.Instance.Width, Globals.Instance.Height);
- Task.Run( ()=>Networking.SendImageAsync(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height));
+ //Networking.SendImage(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height);
+ //Task.Run( ()=>Networking.SendImageAsync(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height)); doenst work after a few sec
//Networking.SendImageAsync(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height); //100-150ms in debug mode
+ _ = Networking.SendImageAsync(managedArrayY, managedArrayUV,Globals.Instance.Width, Globals.Instance.Height);
+ return;
+ }
- int test = 3;
+ unsafe public static void DoDummyCapture()
+ {
+ int NV12ySize = Globals.Instance.Width * Globals.Instance.Height;
+ int NV12uvSize = (Globals.Instance.Width * Globals.Instance.Height) / 2; // UV-Plane is half as big as Y-Plane in NV12
+ byte[] managedArrayY = new byte[NV12ySize];
+ byte[] managedArrayUV = new byte[NV12uvSize];
+ (managedArrayY, managedArrayUV) = GenerateDummyYUVColor(Globals.Instance.Width, Globals.Instance.Height);
+ _ = Networking.SendImageAsync(managedArrayY, managedArrayUV, Globals.Instance.Width, Globals.Instance.Height);
return;
}
From 1e7bf029b216b08ec62cf39a242ef5dc2048a8fc Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Mon, 24 Mar 2025 02:32:09 +0100
Subject: [PATCH 11/13] Update README.md
---
docs/README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/README.md b/docs/README.md
index f73be93..b224f3d 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -4,7 +4,7 @@ HyperTizen is a Hyperion / HyperHDR capturer for Tizen TVs.
# Installation
-To install HyperTizen, you need to have a Samsung TV (Tizen) that has at least Tizen 6.5 (2022+).
+To install HyperTizen, you need to have a Samsung TV (Tizen).
You'll need Tizen Studio to install the app on your TV. You can download it from the [official website](https://developer.samsung.com/smarttv/develop/getting-started/setting-up-sdk/installing-tv-sdk.html).
@@ -39,4 +39,4 @@ tizen package -t tpk -s YourProfileName -o path/to/output/dir -- path/to/io.gh.r
# tizen package -t tpk -s HyperTizen -o release -- io.gh.reisxd.HyperTizen.tpk
```
-4. You should now be able to install the package.
\ No newline at end of file
+4. You should now be able to install the package.
From 2077f60c4d8aed5ae96ba385da07545910ab86bf Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Wed, 27 Aug 2025 22:42:38 +0200
Subject: [PATCH 12/13] putt ssdp discovery into service
not using the UI at all rn
---
HyperTizen/Globals.cs | 6 +-
HyperTizen/Helper/SsdpDiscovery.cs | 70 ++++++++++++++++++++
HyperTizen/HyperTizen_App.cs | 2 -
HyperTizen/SDK/Filestealer.cs | 100 +++++++++++++++++++++++++++++
4 files changed, 174 insertions(+), 4 deletions(-)
create mode 100644 HyperTizen/Helper/SsdpDiscovery.cs
create mode 100644 HyperTizen/SDK/Filestealer.cs
diff --git a/HyperTizen/Globals.cs b/HyperTizen/Globals.cs
index ebe501e..270cea1 100644
--- a/HyperTizen/Globals.cs
+++ b/HyperTizen/Globals.cs
@@ -30,8 +30,10 @@ public static Globals Instance
}
public void SetConfig()
{
- ServerIp = Preference.Contains("rpcServer") ? Preference.Get("rpcServer") : null; //"192.168.69.200"
- ServerPort = 19400;
+ (string ip, int port) = Helper.SsdpDiscovery.GetHyperIpAndPort();
+ ServerIp = ip; //ServerIp = "192.168.69.200";
+ ServerPort = port; //ServerPort = 19400;
+
Enabled = true;//bool.Parse(Preference.Get("enabled"));
Width = 3840/8;
Height = 2160/8;
diff --git a/HyperTizen/Helper/SsdpDiscovery.cs b/HyperTizen/Helper/SsdpDiscovery.cs
new file mode 100644
index 0000000..a2b0253
--- /dev/null
+++ b/HyperTizen/Helper/SsdpDiscovery.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace HyperTizen.Helper
+{
+ public static class SsdpDiscovery
+ {
+ public static (string ip, int port) GetHyperIpAndPort()
+ {
+ string searchTarget = "urn:hyperhdr.eu:device:basic:1";
+ string ssdpRequest =
+$@"M-SEARCH * HTTP/1.1
+HOST: 239.255.255.250:1900
+MAN: ""ssdp:discover""
+MX: 2
+ST: {searchTarget}
+
+";
+
+ try
+ {
+ using (UdpClient udpClient = new UdpClient())
+ {
+ udpClient.Client.ReceiveTimeout = 5000;
+
+ IPEndPoint multicastEndpoint = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900);
+ byte[] requestBytes = Encoding.UTF8.GetBytes(ssdpRequest.Replace("\n", "\r\n"));
+
+ udpClient.Send(requestBytes, requestBytes.Length, multicastEndpoint);
+
+ DateTime start = DateTime.Now;
+ TimeSpan timeout = TimeSpan.FromSeconds(5);
+
+ while (DateTime.Now - start < timeout)
+ {
+ if (udpClient.Available > 0)
+ {
+ IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
+ byte[] responseBytes = udpClient.Receive(ref remoteEP);
+ string response = Encoding.UTF8.GetString(responseBytes);
+
+ if (response.ToLower().Contains(searchTarget.ToLower()))
+ {
+ Match locationMatch = Regex.Match(response, @"LOCATION:\s*(http://[^\s]+)", RegexOptions.IgnoreCase);
+ Match portMatch = Regex.Match(response, @"HYPERHDR-FBS-PORT:\s*(\d+)", RegexOptions.IgnoreCase);
+
+ if (locationMatch.Success && portMatch.Success)
+ {
+ Uri locationUri = new Uri(locationMatch.Groups[1].Value);
+ string ip = locationUri.Host;
+ int port = int.Parse(portMatch.Groups[1].Value);
+ return (ip, port);
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Helper.Log.Write(Helper.eLogType.Error, "SsdpDiscovery.GetHyperIpAndPort() Exception: " + ex.Message);
+ }
+
+ return (null, 0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/HyperTizen/HyperTizen_App.cs b/HyperTizen/HyperTizen_App.cs
index 355658a..0903473 100644
--- a/HyperTizen/HyperTizen_App.cs
+++ b/HyperTizen/HyperTizen_App.cs
@@ -2,7 +2,6 @@
using Tizen.Applications.Notifications;
using Tizen.System;
using System.Threading.Tasks;
-using HyperTizen.WebSocket;
namespace HyperTizen
{
@@ -13,7 +12,6 @@ protected override void OnCreate()
{
base.OnCreate();
if (!Preference.Contains("enabled")) Preference.Set("enabled", "false");
- Task.Run(() => WebSocketServer.StartServerAsync());
Display.StateChanged += Display_StateChanged;
client = new HyperionClient();
}
diff --git a/HyperTizen/SDK/Filestealer.cs b/HyperTizen/SDK/Filestealer.cs
new file mode 100644
index 0000000..20f8fac
--- /dev/null
+++ b/HyperTizen/SDK/Filestealer.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HyperTizen.Helper;
+
+namespace HyperTizen.SDK
+{
+ //Credits to Leonardo Rodrigues for this way to download Tizen Operating System files to USB
+ //Tested only on Tizen 8 yet
+ public static class Filestealer
+ {
+ private static void ScanDirectory(string dir, [NotNull] Action action)
+ {
+ try
+ {
+ foreach (string file in Directory.EnumerateFiles(dir))
+ {
+ try
+ {
+ FileInfo fileInfo = new FileInfo(file);
+
+ if ((fileInfo.Attributes & FileAttributes.ReparsePoint) != 0)
+ {
+ action(file + ".symlink", null);
+
+ continue;
+ }
+
+ action(file, File.ReadAllBytes(file));
+ }
+ catch
+ {
+ action(file + ".blocked", null);
+ }
+ }
+
+ foreach (string subDir in Directory.EnumerateDirectories(dir))
+ {
+ DirectoryInfo fileInfo = new DirectoryInfo(subDir);
+
+ if ((fileInfo.Attributes & FileAttributes.ReparsePoint) != 0)
+ {
+ continue;
+ }
+
+ ScanDirectory(subDir, action);
+ }
+ }
+ catch { }
+ }
+ public static void CopyToUsb()
+ {
+ _ = Task.Run(() =>
+ {
+
+ try
+ {
+ ScanDirectory("/usr/bin", (file, bytes) =>
+ {
+ try
+ {
+ Log.Write(eLogType.Debug,$"- Downloading: {file}");
+
+ string fileRelative = file.TrimStart(Path.DirectorySeparatorChar);
+ string fileTarget = Path.Combine(
+ "/opt/media/USBDriveA1",
+ fileRelative
+ );
+
+ string fileTargetDir = Path.GetDirectoryName(fileTarget);
+
+ if (!Directory.Exists(fileTargetDir))
+ {
+ _ = Directory.CreateDirectory(fileTargetDir);
+ }
+
+ File.WriteAllBytes(fileTarget, bytes);
+ }
+ catch (Exception ex)
+ {
+ Log.Write(eLogType.Debug,ex.ToString());
+ }
+ }
+ );
+
+ Log.Write(eLogType.Debug, "Scan finished!");
+ }
+ catch (Exception ex)
+ {
+ Log.Write(eLogType.Debug, ex.ToString());
+ }
+ });
+ }
+ }
+}
From ba959ff12b1a0153a624a5c6e502b7a7b2700dad Mon Sep 17 00:00:00 2001
From: SryEyes <102036089+SryEyes@users.noreply.github.com>
Date: Wed, 27 Aug 2025 23:50:38 +0200
Subject: [PATCH 13/13] T8 test
---
HyperTizen/SDK/SecVideoCapture.cs | 64 ++++++++++++++++++++++++++++++-
1 file changed, 62 insertions(+), 2 deletions(-)
diff --git a/HyperTizen/SDK/SecVideoCapture.cs b/HyperTizen/SDK/SecVideoCapture.cs
index dd14aa5..14220e8 100644
--- a/HyperTizen/SDK/SecVideoCapture.cs
+++ b/HyperTizen/SDK/SecVideoCapture.cs
@@ -4,10 +4,11 @@
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
+using static HyperTizen.SDK.SecVideoCapture;
namespace HyperTizen.SDK
{
- public static class SecVideoCapture
+ public static unsafe class SecVideoCaptureT7 //for Tizen 7 and below
{
[DllImport("/usr/lib/libsec-video-capture.so.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "secvideo_api_capture_screen_unlock")]
unsafe public static extern int CaptureScreenUnlock();
@@ -29,6 +30,64 @@ public static class SecVideoCapture
//-1 Home Screen & yt crop size, capture lock, video info related
//-4 Netflix/ Widevine Drm Stuff
+ }
+
+ public static unsafe class SecVideoCaptureT8 //for Tizen 8 and above
+ {
+
+ [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
+ public unsafe delegate int CaptureScreenDelegate(IntPtr @this, int w, int h, ref Info_t pInfo);
+ public unsafe struct IVideoCapture
+ {
+ public IntPtr* vtable;
+ }
+
+ private static IVideoCapture* instance;
+ private static CaptureScreenDelegate captureScreen;
+
+ // Muss importiert sein, wenn getInstance exportiert wird
+ [DllImport("/usr/lib/libvideo-capture.so.0.1.0", CallingConvention = CallingConvention.Cdecl, EntryPoint = "getInstance")]
+ private static extern IVideoCapture* GetInstance();
+
+ public static void Init()
+ {
+ instance = GetInstance();
+
+ if (instance == null)
+ Helper.Log.Write(Helper.eLogType.Error, "IVideoCapture instance is null");
+
+ const int CaptureScreenVTableIndex = 3;//
+
+ IntPtr fp = instance->vtable[CaptureScreenVTableIndex];
+ captureScreen = (CaptureScreenDelegate)Marshal.GetDelegateForFunctionPointer(fp, typeof(CaptureScreenDelegate));
+ }
+
+ public static int CaptureScreen(int w, int h, ref Info_t pInfo)
+ {
+ if (captureScreen == null)
+ Helper.Log.Write(Helper.eLogType.Error, "SecVideoCaptureNew not initialized");
+
+ return captureScreen((IntPtr)instance, w, h, ref pInfo);
+ }
+
+ }
+
+ public static class SecVideoCapture
+ {
+
+ public static unsafe int CaptureScreen(int w, int h, ref Info_t pInfo)
+ {
+ if (SystemInfo.TizenVersionMajor >= 8)
+ {
+ // Init should only be done once
+ SecVideoCaptureT8.Init();
+ return SecVideoCaptureT8.CaptureScreen(w, h, ref pInfo);
+ }
+ else
+ {
+ return SecVideoCaptureT7.CaptureScreen(w, h, ref pInfo);
+ }
+ }
[StructLayout(LayoutKind.Sequential)]
unsafe public struct Info_t
{
@@ -41,7 +100,8 @@ unsafe public struct Info_t
unsafe public Int32 iRetColorFormat { get; set; } //a6[6] // = 24 //ref: IceWater "color format is"(YUV420 = 0, YUV422 = 1, YUV444 = 2 , None = 3, Everything else = Error)
unsafe public Int32 unknown2 { get; set; } //a6[7] // = 28
unsafe public Int32 capture3DMode { get; set; } // = 32 //ref: "Capture 3D Mode is DRM_SDP_3D_2D [%d:%s]" (DRM_SDP_3D_2D = 0, DRM_SDP_3D_FRAMEPACKING = 1, DRM_SDP_3D_FRAMESEQ = 2, DRM_SDP_3D_TOPBOTTOM = 3, DRM_SDP_3D_SIDEBYSIDE = 4)
- //unk3 a6[15] // = 60
+ //unk3 a6[15] // = 60
}
+
}
}