У меня был разъем RTP Stream, принимающий поток JPEG, от сетевой камеры Samsung.
Я не знаю много о том, как работает формат JPEG, но я знаю, что этот входящий поток JFIF или JPEG дает мне заголовок JPEG
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type-specific | Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Q | Width | Height |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
and then
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Restart Interval |F|L| Restart Count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
and then in the first packet, there is this header
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| MBZ | Precision | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Quantization Table Data |
| ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Я думаю, что я их правильно проанализировал, и это фрагмент кода, как я СОХРАНЯЮ один пакет JPEG Stream.
int extraOff=0;
public bool Decode(byte* data, int offset)
{
if (_initialized == false)
{
type_specific = data[offset + 0];
_frag[0] = data[offset + 3];
_frag[1] = data[offset + 2];
_frag[2] = data[offset + 1];
_frag[3] = 0x0;
fragment_offset = System.BitConverter.ToInt32(_frag, 0);
jpeg_type = data[offset + 4];
q = data[offset + 5];
width = data[offset + 6];
height = data[offset + 7];
_frag[0] = data[offset + 8];
_frag[1] = data[offset + 9];
restart_interval = (ushort)(System.BitConverter.ToUInt16(_frag, 0) & 0x3FF);
if (width == 0) /** elphel 333 full image size more than just one byte less that < 256 **/
width = 256;
byte jpegMBZ = (byte)(data[offset + 12]);
byte jpegPrecision = (byte)(data[offset + 13]);
int jpegLength = (int)((data[offset + 14]) * 256 + data[offset + 15]);
byte[] tableData1 = new byte[64];
byte[] tableData2 = new byte[64];
for (int i = 0; i < 64; ++i)
{
tableData1[i] = data[offset + 16 + i];
tableData2[i] = data[offset + 16+64 + i];
}
byte[] tmp = new byte[1024];
_offset = Utils.MakeHeaders(tmp,jpeg_type, width, height, tableData1, tableData2, 0);
qtable = new byte[_offset];
Array.Copy(tmp, 0, _buffer, 0, _offset);
_initialized = true;
tmp = null;
GC.Collect();
extraOff = jpegLength + 4 ;
}
else
{
_frag[0] = data[15]; //12 + 3
_frag[1] = data[14]; //12 + 2
_frag[2] = data[13]; //12 + 1]
_frag[3] = 0x0;
fragment_offset = System.BitConverter.ToInt32(_frag, 0);
_frag[0] = data[offset + 8];
_frag[1] = data[offset + 9];
restart_interval = (ushort)(System.BitConverter.ToUInt16(_frag, 0) & 0x3FF);
extraOff = 0;
}
return (next_fragment_offset == fragment_offset);
}
public unsafe bool Write(byte* data, int size, out bool sync) //Write(ref byte[] data, int size,out bool sync)
{
if (Decode(data, 12))
{
for (int i = 24 + extraOff; i < size; )
buffer_ptr[_offset++] = data[i++];
size -= 24+extraOff;
next_fragment_offset += size;
sync = true;
return ((data[1] >> 7) == 1);
}
else
{
_initialized = false;
_offset = qtable.Length;
next_fragment_offset = 0;
sync = false;
return false;
}
}
Проблема, которую я получаю, заключается в том, что файл JPEG, который я успешно сохранил на своем жестком диске в результате объединения потоков JPEG, не показывает весь поток должным образом, все средства предварительного просмотра изображений показывают ПЕРВЫЕ ДВА входных пакета, но оставляют остальные СЕРЫЕ, Я считаю, что это означает, что данные от третьего до последнего пакета RTP не анализируются или сохраняются должным образом.
это кадр, который я получил
http://rectsoft.net/ideerge/zzz.jpg
отредактировано: так я вызвал функцию записи
size = rawBuffer.Length;
if (sync == true)
{
unsafe
{
fixed (byte* p = rawBuffer)
{
if (_frame.Write(p, size, out sync)) //if (_frame.Write(ref _buffer, size, out sync))
{
// i save my buffer to file here
}
}
}
}
else if ((rawBuffer[1] >> 7) == 1)
{
sync = true;
}
rawBuffer заполняется моей функцией приема UDP, он ведет себя точно так же, как я обрабатываю свой поток h264, и выглядит на 100% как то, что я записал с WIRESHARK на VLC.