hawkeye camera support(not tested)
This commit is contained in:
401
framework/Inspectron.HawkEye/RTSP/Server/CJOCh264bitstream.cs
Normal file
401
framework/Inspectron.HawkEye/RTSP/Server/CJOCh264bitstream.cs
Normal file
@@ -0,0 +1,401 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/*
|
||||
* CJOCh264bitstream.cpp
|
||||
*
|
||||
* Created on: Aug 23, 2014
|
||||
* Author: Jordi Cenzano (www.jordicenzano.name)
|
||||
*/
|
||||
|
||||
/*
|
||||
* CJOCh264bitstream.h
|
||||
*
|
||||
* Created on: Aug 23, 2014
|
||||
* Author: Jordi Cenzano (www.jordicenzano.name)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//! h264 bitstream class
|
||||
/*!
|
||||
It is used to create the h264 bit oriented stream, it contains different functions that helps you to create the h264 compliant stream (bit oriented, exp golomb coder)
|
||||
*/
|
||||
namespace Inspectron.HawkEye.RTSP.Server
|
||||
{
|
||||
public class CJOCh264bitstream : System.IDisposable
|
||||
{
|
||||
private const int BUFFER_SIZE_BITS = 24; //! Buffer size in bits used for emulation prevention
|
||||
//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:
|
||||
//ORIGINAL LINE: #define BUFFER_SIZE_BYTES (24/8)
|
||||
|
||||
private const int H264_EMULATION_PREVENTION_BYTE = 0x03; //! Emulation prevention byte
|
||||
|
||||
|
||||
/*! Buffer */
|
||||
private byte[] m_buffer = new byte[BUFFER_SIZE_BITS];
|
||||
|
||||
/*! Bit buffer index */
|
||||
private int m_nLastbitinbuffer;
|
||||
|
||||
/*! Starting byte indicator */
|
||||
private int m_nStartingbyte;
|
||||
|
||||
/*! Pointer to output file */
|
||||
//private FILE m_pOutFile;
|
||||
//Byte Array used for output
|
||||
private List<byte> m_pOutFile;
|
||||
|
||||
//! Clears the buffer
|
||||
private void clearbuffer()
|
||||
{
|
||||
//C++ TO C# CONVERTER TODO TASK: The memory management function 'memset' has no equivalent in C#:
|
||||
//memset(m_buffer, 0, sizeof(byte) * BUFFER_SIZE_BITS);
|
||||
System.Array.Clear(m_buffer, 0, BUFFER_SIZE_BITS);
|
||||
m_nLastbitinbuffer = 0;
|
||||
m_nStartingbyte = 0;
|
||||
}
|
||||
|
||||
//! Returns the nNumbit value (1 or 0) of lval
|
||||
/*!
|
||||
\param lval number to extract the nNumbit value
|
||||
\param nNumbit Bit position that we want to know if its 1 or 0 (from 0 to 63)
|
||||
\return bit value (1 or 0)
|
||||
*/
|
||||
private static int getbitnum(uint lval, int nNumbit)
|
||||
{
|
||||
int lrc = 0;
|
||||
|
||||
uint lmask = (uint) Math.Pow((uint)2,(uint)nNumbit);
|
||||
if ((lval & lmask) > 0)
|
||||
{
|
||||
lrc = 1;
|
||||
}
|
||||
|
||||
return lrc;
|
||||
}
|
||||
|
||||
//! Adds 1 bit to the end of h264 bitstream
|
||||
/*!
|
||||
\param nVal bit to add at the end of h264 bitstream
|
||||
*/
|
||||
private void addbittostream(int nVal)
|
||||
{
|
||||
if (m_nLastbitinbuffer >= BUFFER_SIZE_BITS)
|
||||
{
|
||||
//Must be aligned, no need to do dobytealign();
|
||||
savebufferbyte();
|
||||
}
|
||||
|
||||
//Use circular buffer of BUFFER_SIZE_BYTES
|
||||
int nBytePos = (m_nStartingbyte + (m_nLastbitinbuffer / 8)) % (24 / 8);
|
||||
//The first bit to add is on the left
|
||||
int nBitPosInByte = 7 - m_nLastbitinbuffer % 8;
|
||||
|
||||
//Get the byte value from buffer
|
||||
int nValTmp = m_buffer[nBytePos];
|
||||
|
||||
//Change the bit
|
||||
if (nVal > 0)
|
||||
{
|
||||
nValTmp = (nValTmp | (int) Math.Pow(2,nBitPosInByte));
|
||||
}
|
||||
else
|
||||
{
|
||||
nValTmp = (nValTmp & ~((int) Math.Pow(2,nBitPosInByte)));
|
||||
}
|
||||
|
||||
//Save the new byte value to the buffer
|
||||
m_buffer[nBytePos] = (byte) nValTmp;
|
||||
|
||||
m_nLastbitinbuffer++;
|
||||
}
|
||||
|
||||
//! Adds 8 bit to the end of h264 bitstream (it is optimized for byte aligned situations)
|
||||
/*!
|
||||
\param nVal byte to add at the end of h264 bitstream (from 0 to 255)
|
||||
*/
|
||||
private void addbytetostream(int nVal)
|
||||
{
|
||||
if (m_nLastbitinbuffer >= BUFFER_SIZE_BITS)
|
||||
{
|
||||
//Must be aligned, no need to do dobytealign();
|
||||
savebufferbyte();
|
||||
}
|
||||
|
||||
//Used circular buffer of BUFFER_SIZE_BYTES
|
||||
int nBytePos = (m_nStartingbyte + (m_nLastbitinbuffer / 8)) % (24 / 8);
|
||||
//The first bit to add is on the left
|
||||
int nBitPosInByte = 7 - m_nLastbitinbuffer % 8;
|
||||
|
||||
//Check if it is byte aligned
|
||||
if (nBitPosInByte != 7)
|
||||
{
|
||||
throw new System.Exception("Error: inserting not aligment byte");
|
||||
}
|
||||
|
||||
//Add all byte to buffer
|
||||
m_buffer[nBytePos] = (byte) nVal;
|
||||
|
||||
m_nLastbitinbuffer = m_nLastbitinbuffer + 8;
|
||||
}
|
||||
|
||||
//! Save all buffer to file
|
||||
/*!
|
||||
\param bemulationprevention Indicates if it will insert the emulation prevention byte or not (when it is needed)
|
||||
*/
|
||||
private void savebufferbyte(bool bemulationprevention = true)
|
||||
{
|
||||
bool bemulationpreventionexecuted = false;
|
||||
|
||||
if (m_pOutFile == null)
|
||||
{
|
||||
throw new System.Exception("Error: out file is NULL");
|
||||
}
|
||||
|
||||
//Check if the last bit in buffer is multiple of 8
|
||||
if ((m_nLastbitinbuffer % 8) != 0)
|
||||
{
|
||||
throw new System.Exception("Error: Save to file must be byte aligned");
|
||||
}
|
||||
|
||||
if ((m_nLastbitinbuffer / 8) <= 0)
|
||||
{
|
||||
throw new System.Exception("Error: NO bytes to save");
|
||||
}
|
||||
|
||||
if (bemulationprevention == true)
|
||||
{
|
||||
//Emulation prevention will be used:
|
||||
/*As per h.264 spec,
|
||||
rbsp_data shouldn't contain
|
||||
- 0x 00 00 00
|
||||
- 0x 00 00 01
|
||||
- 0x 00 00 02
|
||||
- 0x 00 00 03
|
||||
|
||||
rbsp_data shall be in the following way
|
||||
- 0x 00 00 03 00
|
||||
- 0x 00 00 03 01
|
||||
- 0x 00 00 03 02
|
||||
- 0x 00 00 03 03
|
||||
*/
|
||||
|
||||
//Check if emulation prevention is needed (emulation prevention is byte align defined)
|
||||
if ( (m_buffer[((m_nStartingbyte + 0) % (24 / 8))] == 0x00)
|
||||
&& (m_buffer[((m_nStartingbyte + 1) % (24 / 8))] == 0x00)
|
||||
&& ((m_buffer[((m_nStartingbyte + 2) % (24 / 8))] == 0x00)
|
||||
|| (m_buffer[((m_nStartingbyte + 2) % (24 / 8))] == 0x01)
|
||||
|| (m_buffer[((m_nStartingbyte + 2) % (24 / 8))] == 0x02)
|
||||
|| (m_buffer[((m_nStartingbyte + 2) % (24 / 8))] == 0x03)))
|
||||
{
|
||||
int nbuffersaved = 0;
|
||||
byte cEmulationPreventionByte = H264_EMULATION_PREVENTION_BYTE;
|
||||
|
||||
//Save 1st byte
|
||||
fwrite(m_buffer[((m_nStartingbyte + nbuffersaved) % (24 / 8))], 1, 1, m_pOutFile);
|
||||
nbuffersaved++;
|
||||
|
||||
//Save 2st byte
|
||||
fwrite(m_buffer[((m_nStartingbyte + nbuffersaved) % (24 / 8))], 1, 1, m_pOutFile);
|
||||
nbuffersaved++;
|
||||
|
||||
//Save emulation prevention byte
|
||||
fwrite(cEmulationPreventionByte, 1, 1, m_pOutFile);
|
||||
|
||||
//Save the rest of bytes (usually 1)
|
||||
while (nbuffersaved < (24 / 8))
|
||||
{
|
||||
fwrite(m_buffer[((m_nStartingbyte + nbuffersaved) % (24 / 8))], 1, 1, m_pOutFile);
|
||||
nbuffersaved++;
|
||||
}
|
||||
|
||||
//All bytes in buffer are saved, so clear the buffer
|
||||
clearbuffer();
|
||||
|
||||
bemulationpreventionexecuted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bemulationpreventionexecuted == false)
|
||||
{
|
||||
//No emulation prevention was used
|
||||
|
||||
//Save the oldest byte in buffer
|
||||
fwrite(m_buffer[m_nStartingbyte], 1, 1, m_pOutFile);
|
||||
|
||||
//Move the index
|
||||
m_buffer[m_nStartingbyte] = 0;
|
||||
m_nStartingbyte++;
|
||||
m_nStartingbyte = m_nStartingbyte % (24 / 8);
|
||||
m_nLastbitinbuffer = m_nLastbitinbuffer - 8;
|
||||
}
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
/*!
|
||||
\param pOutBinaryFile The output file pointer
|
||||
*/
|
||||
public CJOCh264bitstream(List<byte> pOutBinaryFile)
|
||||
{
|
||||
clearbuffer();
|
||||
|
||||
//C++ TO C# CONVERTER TODO TASK: C# does not have an equivalent to pointers to variables (in C#, the variable no longer points to the original when the original variable is re-assigned):
|
||||
//ORIGINAL LINE: m_pOutFile = pOutBinaryFile;
|
||||
m_pOutFile = pOutBinaryFile;
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
public virtual void Dispose()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
//! Add 4 bytes to h264 bistream without taking into acount the emulation prevention. Used to add the NAL header to the h264 bistream
|
||||
/*!
|
||||
\param nVal The 32b value to add
|
||||
\param bDoAlign Indicates if the function will insert 0 in order to create a byte aligned stream before adding nVal 4 bytes to stream. If you try to call this function and the stream is not byte aligned an exception will be thrown
|
||||
*/
|
||||
public void add4bytesnoemulationprevention(uint nVal, bool bDoAlign = false)
|
||||
{
|
||||
//Used to add NAL header stream
|
||||
//Remember: NAL header is byte oriented
|
||||
|
||||
if (bDoAlign == true)
|
||||
{
|
||||
dobytealign();
|
||||
}
|
||||
|
||||
if ((m_nLastbitinbuffer % 8) != 0)
|
||||
{
|
||||
throw new System.Exception("Error: Save to file must be byte aligned");
|
||||
}
|
||||
|
||||
while (m_nLastbitinbuffer != 0)
|
||||
{
|
||||
savebufferbyte();
|
||||
}
|
||||
|
||||
byte cbyte = (byte)((nVal & 0xFF000000) >> 24);
|
||||
fwrite(cbyte, 1, 1, m_pOutFile);
|
||||
|
||||
cbyte = (byte)((nVal & 0x00FF0000) >> 16);
|
||||
fwrite(cbyte, 1, 1, m_pOutFile);
|
||||
|
||||
cbyte = (byte)((nVal & 0x0000FF00) >> 8);
|
||||
fwrite(cbyte, 1, 1, m_pOutFile);
|
||||
|
||||
cbyte = (byte)(nVal & 0x000000FF);
|
||||
fwrite(cbyte, 1, 1, m_pOutFile);
|
||||
}
|
||||
|
||||
//! Adds nNumbits of lval to the end of h264 bitstream
|
||||
/*!
|
||||
\param nVal value to add at the end of the h264 stream (only the LAST nNumbits will be added)
|
||||
\param nNumbits number of bits of lval that will be added to h264 stream (counting from left)
|
||||
*/
|
||||
|
||||
//Public functions
|
||||
|
||||
public void addbits(uint lval, int nNumbits)
|
||||
{
|
||||
if ((nNumbits <= 0) || (nNumbits > 64))
|
||||
{
|
||||
throw new System.Exception("Error: numbits must be between 1 ... 64");
|
||||
}
|
||||
|
||||
int nBit = 0;
|
||||
int n = nNumbits - 1;
|
||||
while (n >= 0)
|
||||
{
|
||||
nBit = getbitnum(lval, n);
|
||||
n--;
|
||||
|
||||
addbittostream(nBit);
|
||||
}
|
||||
}
|
||||
|
||||
//! Adds lval to the end of h264 bitstream using exp golomb coding for unsigned values
|
||||
/*!
|
||||
\param nVal value to add at the end of the h264 stream
|
||||
*/
|
||||
public void addexpgolombunsigned(uint lval)
|
||||
{
|
||||
//it implements unsigned exp golomb coding
|
||||
|
||||
uint lvalint = lval + 1;
|
||||
int nnumbits = (int)(Math.Log(lvalint,2) + 1);
|
||||
|
||||
for (int n = 0; n < (nnumbits - 1); n++)
|
||||
{
|
||||
addbits(0, 1);
|
||||
}
|
||||
|
||||
addbits(lvalint, nnumbits);
|
||||
}
|
||||
|
||||
//! Adds lval to the end of h264 bitstream using exp golomb coding for signed values
|
||||
/*!
|
||||
\param nVal value to add at the end of the h264 stream
|
||||
*/
|
||||
public void addexpgolombsigned(int lval)
|
||||
{
|
||||
//it implements a signed exp golomb coding
|
||||
|
||||
uint lvalint = (uint)(Math.Abs(lval) * 2 - 1);
|
||||
if (lval <= 0)
|
||||
{
|
||||
lvalint = (uint)(2 * Math.Abs(lval));
|
||||
}
|
||||
|
||||
addexpgolombunsigned(lvalint);
|
||||
}
|
||||
|
||||
//! Adds 0 to the end of h264 bistream in order to leave a byte aligned stream (It will insert seven 0 maximum)
|
||||
public void dobytealign()
|
||||
{
|
||||
//Check if the last bit in buffer is multiple of 8
|
||||
int nr = m_nLastbitinbuffer % 8;
|
||||
if ((nr % 8) != 0)
|
||||
{
|
||||
m_nLastbitinbuffer = m_nLastbitinbuffer + (8 - nr);
|
||||
}
|
||||
}
|
||||
|
||||
//! Adds cByte (8 bits) to the end of h264 bitstream. This function it is optimized in byte aligned streams.
|
||||
/*!
|
||||
\param cByte value to add at the end of the h264 stream (from 0 to 255)
|
||||
*/
|
||||
public void addbyte(byte cByte)
|
||||
{
|
||||
//Byte alignment optimization
|
||||
if ((m_nLastbitinbuffer % 8) == 0)
|
||||
{
|
||||
addbytetostream(cByte);
|
||||
}
|
||||
else
|
||||
{
|
||||
addbits(cByte, 8);
|
||||
}
|
||||
}
|
||||
|
||||
//! Close the h264 stream saving to disk the last remaing bits in buffer
|
||||
public void close()
|
||||
{
|
||||
//Flush the data in stream buffer
|
||||
|
||||
dobytealign();
|
||||
|
||||
while (m_nLastbitinbuffer != 0)
|
||||
{
|
||||
savebufferbyte();
|
||||
}
|
||||
}
|
||||
|
||||
// 'writing' to memory
|
||||
private void fwrite(byte b, int x, int y, List<byte>data)
|
||||
{
|
||||
data.Add(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user