hawkeye camera support(not tested)
This commit is contained in:
166
framework/Inspectron.HawkEye/RTSP/Server/TinyH264Encoder.cs
Normal file
166
framework/Inspectron.HawkEye/RTSP/Server/TinyH264Encoder.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
// Tiny H264 Encoder
|
||||
// World's Smallest h.264 Encoder, by Ben Mesander.
|
||||
// https://cardinalpeak.com/blog/worlds-smallest-h-264-encoder/
|
||||
//
|
||||
// Ported to C# by Roger Hardiman www.rjh.org.uk
|
||||
|
||||
// Input: YUV image that must be 128x96
|
||||
// Output: H264 NAL
|
||||
//
|
||||
// This is a very simple lossless H264 encoder. No compression is used and so the output NAL data is as
|
||||
// large as the input YUV data.
|
||||
// It is used for a quick example of H264 encoding in pure .Net without needing OS specific APIs
|
||||
// or cross compiled C libraries.
|
||||
//
|
||||
// The H264 SPS/PPS data includes the image size. As the SPS/PPS is hard coded in this example the YUV
|
||||
// image size must be 128 x 96
|
||||
|
||||
namespace Inspectron.HawkEye.RTSP.Server
|
||||
{
|
||||
public class TinyH264Encoder
|
||||
{
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int uv_width = 0;
|
||||
int uv_height = 0;
|
||||
int y_size = 0;
|
||||
int u_size = 0;
|
||||
int v_size = 0;
|
||||
|
||||
byte[] sps = { 0x67, 0x42, 0x00, 0x0a, 0xf8, 0x41, 0xa2 };
|
||||
//byte[] sps_b = { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x0a, 0xf8, 0x41, 0xa2 }; // Annex B
|
||||
//byte[] sps32 = { 0x00, 0x00, 0x00, 0x07, 0x67, 0x42, 0x00, 0x0a, 0xf8, 0x41, 0xa2 }; // 32 bit size
|
||||
|
||||
byte[] pps = { 0x68, 0xce, 0x38, 0x80 };
|
||||
//byte[] pps_b = { 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x38, 0x80 }; // Annex B
|
||||
//byte[] pps32 = { 0x00, 0x00, 0x00, 0x04, 0x68, 0xce, 0x38, 0x80 }; // 32 bit size
|
||||
|
||||
byte[] slice_header = { 0x05, 0x88, 0x84, 0x21, 0xa0 };
|
||||
//byte[] slice_header_b = { 0x00, 0x00, 0x00, 0x01, 0x05, 0x88, 0x84, 0x21, 0xa0 };
|
||||
//byte[] slice_header_32 = { 0x00, 0x00, 0x00, 0x00, 0x05, 0x88, 0x84, 0x21, 0xa0 }; // must replace size bytes
|
||||
byte[] slice_end = { 0x80 };
|
||||
byte[] macroblock_header = { 0x0d, 0x00 };
|
||||
|
||||
List<byte> nal = new List<byte>();
|
||||
|
||||
// Constuctor
|
||||
public TinyH264Encoder()
|
||||
{
|
||||
this.width = 128; // Hard coded size that is embedded in the SPS/PPS data
|
||||
this.height = 96; // Hard coded size that is embedded in the SPS/PPS data
|
||||
this.uv_width = width >> 1;
|
||||
this.uv_height = height >> 1;
|
||||
this.y_size = width * height;
|
||||
this.u_size = (width >> 1) * (height >> 1);
|
||||
this.v_size = (width >> 1) * (height >> 1);
|
||||
}
|
||||
|
||||
public byte[] GetRawSPS()
|
||||
{
|
||||
return sps.ToArray();
|
||||
}
|
||||
|
||||
public byte[] GetRawPPS()
|
||||
{
|
||||
return pps.ToArray();
|
||||
}
|
||||
|
||||
public byte[] CompressFrame(byte[] yuv_data)
|
||||
{
|
||||
// we can only do 128 x 96
|
||||
if (width != 128) return null;
|
||||
if (height != 96) return null;
|
||||
|
||||
// check size
|
||||
if (yuv_data.Length < (y_size + u_size + v_size))
|
||||
{
|
||||
// the yuv image is too small.
|
||||
return null;
|
||||
}
|
||||
|
||||
nal.Clear();
|
||||
|
||||
// Slice Header
|
||||
foreach (byte b in slice_header) nal.Add(b);
|
||||
|
||||
// Add each macro block
|
||||
for (int i = 0; i < (height / 16); i++) {
|
||||
for (int j = 0; j < (width / 16); j++) {
|
||||
macroblock(i, j, yuv_data);
|
||||
}
|
||||
}
|
||||
|
||||
// Add slice end
|
||||
foreach (byte b in slice_end) nal.Add(b);
|
||||
|
||||
byte[] nal_array = nal.ToArray();
|
||||
|
||||
return nal_array;
|
||||
}
|
||||
|
||||
/* Write a macroblock's worth of YUV data in I_PCM mode */
|
||||
private void macroblock(int i, int j, byte[] frame)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
if (!((i == 0) && (j == 0)))
|
||||
{
|
||||
foreach (byte b in macroblock_header) nal.Add(b);
|
||||
}
|
||||
|
||||
for (x = i * 16; x < ((i + 1) * 16); x++)
|
||||
{
|
||||
for (y = j * 16; y < ((j + 1) * 16); y++)
|
||||
{
|
||||
nal.Add(frame[(x * width) + y]);
|
||||
}
|
||||
}
|
||||
for (x = i * 8; x < (i + 1) * 8; x++)
|
||||
{
|
||||
for (y = j * 8; y < (j + 1) * 8; y++)
|
||||
{
|
||||
nal.Add(frame[y_size + (x * uv_width) + y]);
|
||||
}
|
||||
}
|
||||
for (x = i * 8; x < (i + 1) * 8; x++)
|
||||
{
|
||||
for (y = j * 8; y < (j + 1) * 8; y++)
|
||||
{
|
||||
nal.Add(frame[y_size + u_size + (x * uv_width) + y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ChangeAnnexBto32BitSize(byte[] data)
|
||||
{
|
||||
|
||||
if (data.Length < 4) return;
|
||||
|
||||
// change data from 0x00 0x00 0x00 0x01 format to 32 bit size
|
||||
int len = data.Length - 4;// subtract Annex B header size
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
data[0] = (byte)((len >> 24) & 0xFF);
|
||||
data[1] = (byte)((len >> 16) & 0xFF);
|
||||
data[2] = (byte)((len >> 8) & 0xFF);
|
||||
data[3] = (byte)((len << 0) & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
data[0] = (byte)((len >> 0) & 0xFF);
|
||||
data[1] = (byte)((len >> 8) & 0xFF);
|
||||
data[2] = (byte)((len >> 16) & 0xFF);
|
||||
data[3] = (byte)((len >> 24) & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user