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 } + } }