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; - } -} 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..270cea1 --- /dev/null +++ b/HyperTizen/Globals.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tizen.Applications; + +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() + { + (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; + } + + public string ServerIp; //IP of hyperhdr server + 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/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/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.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/HyperTizen_App.cs b/HyperTizen/HyperTizen_App.cs index f3e148c..0903473 100644 --- a/HyperTizen/HyperTizen_App.cs +++ b/HyperTizen/HyperTizen_App.cs @@ -1,80 +1,76 @@ -using Tizen.Applications; -using Tizen.Applications.Notifications; -using Tizen.System; -using HyperTizen.WebSocket; -using System.Threading.Tasks; - -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) - { - Configuration.Enabled = bool.Parse(Preference.Get("enabled")); - 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")); - } - } -} +using Tizen.Applications; +using Tizen.Applications.Notifications; +using Tizen.System; +using System.Threading.Tasks; + +namespace HyperTizen +{ + class App : ServiceApplication + { + public static HyperionClient client; + protected override void OnCreate() + { + base.OnCreate(); + if (!Preference.Contains("enabled")) Preference.Set("enabled", "false"); + 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/HyperionClient.cs b/HyperTizen/HyperionClient.cs new file mode 100644 index 0000000..562a00c --- /dev/null +++ b/HyperTizen/HyperionClient.cs @@ -0,0 +1,59 @@ +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(); + VideoCapture.InitCapture(); + + while (Globals.Instance.Enabled) + { + 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 + await Task.Run(() => Networking.SendRegister()); + } + + } + + public async Task Stop() + { + + } + } +} \ No newline at end of file diff --git a/HyperTizen/Networking.cs b/HyperTizen/Networking.cs new file mode 100644 index 0000000..5bc5bf9 --- /dev/null +++ b/HyperTizen/Networking.cs @@ -0,0 +1,209 @@ +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; +using Tizen.Messaging.Messages; + +namespace HyperTizen +{ + 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); + if (client == null) + return; + stream = Networking.client.GetStream(); + 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); + 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(); + 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 || stream == null) + return; + byte[] message = CreateFlatBufferMessage(yData, uvData, width, height); + 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 || stream == null) + return null; + var builder = new FlatBufferBuilder(yData.Length + uvData.Length + 100); + + var yVector = NV12Image.CreateDataYVector(builder, yData); + var uvVector = NV12Image.CreateDataUvVector(builder, uvData); + + NV12Image.StartNV12Image(builder); + NV12Image.AddDataY(builder, yVector); + NV12Image.AddDataUv(builder, uvVector); + NV12Image.AddWidth(builder, width); + NV12Image.AddHeight(builder, height); + NV12Image.AddStrideY(builder, width); //TODO: Check if this is correct + NV12Image.AddStrideUv(builder, width); + var nv12Image = NV12Image.EndNV12Image(builder); + + Image.StartImage(builder); + Image.AddDataType(builder, ImageType.NV12Image); + Image.AddData(builder, nv12Image.Value); + Image.AddDuration(builder, -1); + var imageOffset = Image.EndImage(builder); + + Request.StartRequest(builder); + Request.AddCommandType(builder, Command.Image); + Request.AddCommand(builder, imageOffset.Value); + var requestOffset = Request.EndRequest(builder); + + builder.Finish(requestOffset.Value); + return builder.SizedByteArray(); + } + + static Reply ParseReply(byte[] receivedData) + { + var byteBuffer = new ByteBuffer(receivedData, 4); //shift for header + return Reply.GetRootAsReply(byteBuffer); + } + + public static byte[] CreateRegistrationMessage() + { + if (client == null || !client.Connected || stream == null) + return null; + + var builder = new FlatBufferBuilder(256); //TODO:Check how to calculate correctly + + var originOffset = builder.CreateString("HyperTizen"); + + Register.StartRegister(builder); + Register.AddPriority(builder, 123); + Register.AddOrigin(builder, originOffset); + var registerOffset = Register.EndRegister(builder); + + Request.StartRequest(builder); + Request.AddCommandType(builder, Command.Register); + Request.AddCommand(builder, registerOffset.Value); + var requestOffset = Request.EndRequest(builder); + + builder.Finish(requestOffset.Value); + return builder.SizedByteArray(); + } + + public static void ReadRegisterReply() + { + if (client == null || !client.Connected || stream == null) + 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); + 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; + } + } + + static async Task SendMessageAndReceiveReplyAsync(byte[] message) + { + try + { + 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); + + Helper.Log.Write(Helper.eLogType.Info, "SendMessageAndReceiveReply: message.Length; " + message.Length); + await stream.WriteAsync(message, 0, message.Length); + await stream.FlushAsync(); + Helper.Log.Write(Helper.eLogType.Info, "SendMessageAndReceiveReply: Data sent"); + _ = ReadImageReply(); + + } + } + catch (Exception ex) + { + Helper.Log.Write(Helper.eLogType.Error, "SendMessageAndReceiveReply: Exception (closing tcp client now) Sending/Receiving: " + ex.Message); + DisconnectClient(); + return; + } + } + + } +} 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()); + } + }); + } + } +} diff --git a/HyperTizen/SDK/SecVideoCapture.cs b/HyperTizen/SDK/SecVideoCapture.cs new file mode 100644 index 0000000..14220e8 --- /dev/null +++ b/HyperTizen/SDK/SecVideoCapture.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using static HyperTizen.SDK.SecVideoCapture; + +namespace HyperTizen.SDK +{ + 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(); + [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 + + } + + 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 + { + 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/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 new file mode 100644 index 0000000..7c1af57 --- /dev/null +++ b/HyperTizen/VideoCapture.cs @@ -0,0 +1,179 @@ +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 + { + Marshal.PrelinkAll(typeof(SDK.SecVideoCapture)); + } + catch + { + 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; + bool VideoRecording = SystemInfo.VideoRecording; + int ScreenWidth = SystemInfo.ScreenWidth; + int ScreenHeight = SystemInfo.ScreenHeight; + string ModelName = SystemInfo.ModelName; + + } + + 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; + var height = 270; + var uvBufferSizeYUV420 = (width / 2) * (height / 2); + + + 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 + + SDK.SecVideoCapture.Info_t info = new SDK.SecVideoCapture.Info_t(); + info.iGivenBufferSize1 = NV12ySize; + info.iGivenBufferSize2 = NV12uvSize; + //info.iWidth = width; + //info.iHeight = height; + 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: + 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: + 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: + 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: + 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; + return; + } + + isRunning = true; + + + Marshal.Copy(info.pImageY, managedArrayY, 0, NV12ySize); + 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"); + + 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)); + + //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; + } + + 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; + } + + public static (byte[] yData, byte[] uvData) GenerateDummyYUVRandom(int width, int height) + { + int ySize = width * height; + int uvSize = (width * height) / 2; + + byte[] yData = new byte[ySize]; + byte[] uvData = new byte[uvSize]; + + Random rnd = new Random(); + rnd.NextBytes(yData); + rnd.NextBytes(uvData); + + return (yData, uvData); + } + + public static (byte[] yData, byte[] uvData) GenerateDummyYUVColor(int width, int height) + { + int ySize = width * height; + int uvSize = (width * height) / 2; + + byte[] yData = new byte[ySize]; + byte[] uvData = new byte[uvSize]; + + + for (int i = 0; i < ySize; i++) + { + yData[i] = 128; + } + + for (int i = 0; i < uvSize; i += 2) + { + uvData[i] = 128; + uvData[i + 1] = 255; + } + + return (yData, uvData); + } + + } + +} \ No newline at end of file diff --git a/HyperTizen/WebSocket/HyperionClient.cs b/HyperTizen/WebSocket/HyperionClient.cs deleted file mode 100644 index bc940b5..0000000 --- a/HyperTizen/WebSocket/HyperionClient.cs +++ /dev/null @@ -1,72 +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; - -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); - } - } - } -} \ No newline at end of file diff --git a/HyperTizen/WebSocket/WebSocket.cs b/HyperTizen/WebSocket/WebSocket.cs index 876c83f..d845ef2 100644 --- a/HyperTizen/WebSocket/WebSocket.cs +++ b/HyperTizen/WebSocket/WebSocket.cs @@ -139,7 +139,7 @@ void SetConfiguration(SetConfigEvent setConfigEvent) case "rpcServer": { App.Configuration.RPCServer = setConfigEvent.value; - App.client.UpdateURI(setConfigEvent.value); + //App.client.UpdateURI(setConfigEvent.value); break; } case "enabled": @@ -148,7 +148,7 @@ void SetConfiguration(SetConfigEvent setConfigEvent) if (!App.Configuration.Enabled && value) { App.Configuration.Enabled = value; - Task.Run(() => App.client.Start(value)); + Task.Run(() => App.client.Start()); } else App.Configuration.Enabled = value; break; diff --git a/HyperTizen/tizen-manifest.xml b/HyperTizen/tizen-manifest.xml index 59fe390..b145920 100644 --- a/HyperTizen/tizen-manifest.xml +++ b/HyperTizen/tizen-manifest.xml @@ -1,8 +1,8 @@  - + Reis Can - + HyperTizen.png 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 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.