hawkeye camera support(not tested)
This commit is contained in:
209
framework/Inspectron.HawkEye/RTSP/Server/TestCard.cs
Normal file
209
framework/Inspectron.HawkEye/RTSP/Server/TestCard.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
||||
// (c) Roger Hardiman 2016
|
||||
|
||||
// This class uses a System Timer to generate a YUV image at regular intervals
|
||||
// The ReceivedYUVFrame event is fired for each new YUV image
|
||||
|
||||
namespace Inspectron.HawkEye.RTSP.Server
|
||||
{
|
||||
public class TestCard
|
||||
{
|
||||
|
||||
// Events that applications can receive
|
||||
public event ReceivedYUVFrameHandler ReceivedYUVFrame;
|
||||
|
||||
// Delegated functions (essentially the function prototype)
|
||||
public delegate void ReceivedYUVFrameHandler(uint timestamp, int width, int height, byte[] data);
|
||||
|
||||
|
||||
// Local variables
|
||||
private System.Timers.Timer frame_timer;
|
||||
private int fps = 0;
|
||||
private Stopwatch stopwatch;
|
||||
private byte[] yuv_frame = null;
|
||||
private int x_position = 0;
|
||||
private int y_position = 0;
|
||||
private int width = 0;
|
||||
private int height = 0;
|
||||
private Object generate_lock = new Object();
|
||||
private long count = 0;
|
||||
|
||||
// ASCII Font
|
||||
// Created by Roger Hardiman using an online generation tool
|
||||
// http://www.riyas.org/2013/12/online-led-matrix-font-generator-with.html
|
||||
|
||||
byte[] ascii_0 = { 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c };
|
||||
byte[] ascii_1 = { 0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x3e };
|
||||
byte[] ascii_2 = { 0x00, 0x3e, 0x42, 0x02, 0x0c, 0x30, 0x40, 0x7e };
|
||||
byte[] ascii_3 = { 0x00, 0x7c, 0x02, 0x02, 0x3c, 0x02, 0x02, 0x7c };
|
||||
byte[] ascii_4 = { 0x00, 0x0c, 0x14, 0x24, 0x44, 0x7e, 0x04, 0x04 };
|
||||
byte[] ascii_5 = { 0x00, 0x7e, 0x40, 0x40, 0x7c, 0x02, 0x02, 0x7c };
|
||||
byte[] ascii_6 = { 0x00, 0x3e, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x3c };
|
||||
byte[] ascii_7 = { 0x00, 0x7e, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20 };
|
||||
byte[] ascii_8 = { 0x00, 0x3c, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x3c };
|
||||
byte[] ascii_9 = { 0x00, 0x3c, 0x42, 0x42, 0x3c, 0x02, 0x02, 0x3e };
|
||||
byte[] ascii_colon = { 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00 };
|
||||
byte[] ascii_space = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
byte[] ascii_dot = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00 };
|
||||
|
||||
// Constructor
|
||||
public TestCard(int width, int height, int fps)
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.fps = fps;
|
||||
|
||||
// YUV size
|
||||
int y_size = width * height;
|
||||
int u_size = (width >> 1) * (height >> 1);
|
||||
int v_size = (width >> 1) * (height >> 1);
|
||||
yuv_frame = new byte[y_size + u_size + v_size];
|
||||
|
||||
// Set all values to 127
|
||||
for (int x = 0; x < yuv_frame.Length; x++)
|
||||
{
|
||||
yuv_frame[x] = 127;
|
||||
}
|
||||
|
||||
stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
|
||||
// Start timer. The Timer will generate each YUV frame
|
||||
frame_timer = new System.Timers.Timer();
|
||||
frame_timer.Interval = 1; // on first pass timer will fire straight away (cannot have zero interval)
|
||||
frame_timer.AutoReset = false; // do not restart timer after the time has elapsed
|
||||
frame_timer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) =>
|
||||
{
|
||||
// send a frame
|
||||
Send_YUV_Frame();
|
||||
count++;
|
||||
|
||||
// Some CPU cycles will have been used in Sending the YUV Frame.
|
||||
// Compute the delay required (the Timer Interval) before sending the next YUV frame
|
||||
long time_for_next_tick_ms = (count * 1000) / fps;
|
||||
long time_to_wait = time_for_next_tick_ms - stopwatch.ElapsedMilliseconds;
|
||||
if (time_to_wait <= 0) time_to_wait = 1; // cannot have negative or zero intervals
|
||||
frame_timer.Interval = time_to_wait;
|
||||
frame_timer.Start();
|
||||
};
|
||||
frame_timer.Start();
|
||||
|
||||
}
|
||||
|
||||
// Dispose
|
||||
public void Disconnect()
|
||||
{
|
||||
// Stop the frame timer
|
||||
frame_timer.Stop();
|
||||
frame_timer.Dispose();
|
||||
}
|
||||
|
||||
|
||||
private void Send_YUV_Frame()
|
||||
{
|
||||
lock (generate_lock)
|
||||
{
|
||||
// Get the current time
|
||||
DateTime now_utc = DateTime.UtcNow;
|
||||
DateTime now_local = now_utc.ToLocalTime();
|
||||
|
||||
|
||||
long timestamp_ms = ((long)(now_utc.Ticks / TimeSpan.TicksPerMillisecond));
|
||||
|
||||
// Generate the String to write
|
||||
char[] overlay = null;
|
||||
|
||||
if (width >= 96)
|
||||
{
|
||||
// Need 12 characters of 8x8 pixels. 12*8 = 96
|
||||
// HH:MM:SS.mmm
|
||||
String overlay_str = now_local.ToString("HH:mm:ss.fff", CultureInfo.InvariantCulture); // do not replace : or . by local formats
|
||||
overlay = overlay_str.ToCharArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Min for most video formats is 16x16, enough for 2 characters
|
||||
String overlay_str = now_local.ToString("ss", CultureInfo.InvariantCulture); // do not replace : or . by local formats
|
||||
overlay = overlay_str.ToCharArray();
|
||||
}
|
||||
|
||||
// process each character
|
||||
int start_row = ((height / 2) - 4); // start 4 pixels above the centre row (4 is half the font height)
|
||||
for (int c = 0; c < overlay.Length; c++)
|
||||
{
|
||||
byte[] font = ascii_space;
|
||||
if (overlay[c] == '0') font = ascii_0;
|
||||
if (overlay[c] == '1') font = ascii_1;
|
||||
if (overlay[c] == '2') font = ascii_2;
|
||||
if (overlay[c] == '3') font = ascii_3;
|
||||
if (overlay[c] == '4') font = ascii_4;
|
||||
if (overlay[c] == '5') font = ascii_5;
|
||||
if (overlay[c] == '6') font = ascii_6;
|
||||
if (overlay[c] == '7') font = ascii_7;
|
||||
if (overlay[c] == '8') font = ascii_8;
|
||||
if (overlay[c] == '9') font = ascii_9;
|
||||
if (overlay[c] == ' ') font = ascii_space;
|
||||
if (overlay[c] == ':') font = ascii_colon;
|
||||
if (overlay[c] == '.') font = ascii_dot;
|
||||
|
||||
// process the font character
|
||||
for (int rows = 0; rows < 8; rows++)
|
||||
{
|
||||
int y_plane_pos = (start_row * width) + (rows * width) + (c * 8);
|
||||
byte row_byte = font[rows];
|
||||
// bit shift the row byte into individual pixels where the font On/Off maps to Y intensity 50 or 200
|
||||
for (int bits = 0; bits < 8; bits++)
|
||||
{
|
||||
if ((row_byte & 0x80) == 0x80)
|
||||
{
|
||||
// Pixel On
|
||||
yuv_frame[y_plane_pos] = 200;
|
||||
}
|
||||
else
|
||||
{
|
||||
yuv_frame[y_plane_pos] = 50;
|
||||
}
|
||||
y_plane_pos++;
|
||||
row_byte = (byte)(row_byte << 1); // shift up so the next 'bit' to process is the most significant bit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Toggle the pixel value
|
||||
byte pixel_value = yuv_frame[(y_position * width) + x_position];
|
||||
|
||||
// change brightness of pixel
|
||||
if (pixel_value > 128) pixel_value = 30;
|
||||
else pixel_value = 230;
|
||||
|
||||
yuv_frame[(y_position * width) + x_position] = pixel_value;
|
||||
|
||||
// move the x and y position
|
||||
x_position = x_position + 5;
|
||||
if (x_position >= width)
|
||||
{
|
||||
x_position = 0;
|
||||
y_position = y_position + 1;
|
||||
}
|
||||
|
||||
if (y_position >= height)
|
||||
{
|
||||
y_position = 0;
|
||||
}
|
||||
|
||||
// fire the Event
|
||||
if (ReceivedYUVFrame != null)
|
||||
{
|
||||
ReceivedYUVFrame((uint)stopwatch.ElapsedMilliseconds, width, height, yuv_frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user