mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-17 22:06:41 +00:00
rtpjpeg: Use gst_memory_map() instead of gst_buffer_map()
gst_buffer_map () results in memcopying when a GstBuffer contains more than one GstMemory. This has quite an impact on performance on systems with limited amount of resources. With this patch the whole GstBuffer will not be mapped at once, instead each individual GstMemory will be iterated and mapped separately.
This commit is contained in:
parent
54b6ee0c55
commit
586fc57e55
3 changed files with 491 additions and 90 deletions
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
#include "gstrtpjpegpay.h"
|
#include "gstrtpjpegpay.h"
|
||||||
#include "gstrtputils.h"
|
#include "gstrtputils.h"
|
||||||
|
#include "gstbuffermemory.h"
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtp_jpeg_pay_sink_template =
|
static GstStaticPadTemplate gst_rtp_jpeg_pay_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
|
@ -383,45 +384,76 @@ invalid_framerate:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get uint16 value from current position in mapped memory.
|
||||||
|
* the memory offset will be increased with 2.
|
||||||
|
*/
|
||||||
static guint
|
static guint
|
||||||
gst_rtp_jpeg_pay_header_size (const guint8 * data, guint offset)
|
parse_mem_inc_offset_guint16 (GstBufferMemoryMap * memory)
|
||||||
{
|
{
|
||||||
return data[offset] << 8 | data[offset + 1];
|
guint data;
|
||||||
|
|
||||||
|
g_return_val_if_fail (memory->total_size > (memory->offset + 1), 0);
|
||||||
|
|
||||||
|
data = ((guint) * memory->data) << 8;
|
||||||
|
gst_buffer_memory_advance_bytes (memory, 1);
|
||||||
|
data = data | (*memory->data);
|
||||||
|
gst_buffer_memory_advance_bytes (memory, 1);
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get uint8 value from current position in mapped memory.
|
||||||
|
* the memory offset will be increased with 1.
|
||||||
|
*/
|
||||||
static guint
|
static guint
|
||||||
gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint size,
|
parse_mem_inc_offset_guint8 (GstBufferMemoryMap * memory)
|
||||||
guint offset, RtpQuantTable tables[])
|
{
|
||||||
|
guint data;
|
||||||
|
|
||||||
|
g_return_val_if_fail (memory->total_size > memory->offset, 0);
|
||||||
|
|
||||||
|
data = (*memory->data);
|
||||||
|
gst_buffer_memory_advance_bytes (memory, 1);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtp_jpeg_pay_read_quant_table (GstBufferMemoryMap * memory,
|
||||||
|
RtpQuantTable tables[])
|
||||||
{
|
{
|
||||||
guint quant_size, tab_size;
|
guint quant_size, tab_size;
|
||||||
guint8 prec;
|
guint8 prec;
|
||||||
guint8 id;
|
guint8 id;
|
||||||
|
|
||||||
if (offset + 2 > size)
|
if (memory->total_size <= (memory->offset + 1))
|
||||||
goto too_small;
|
goto too_small;
|
||||||
|
|
||||||
quant_size = gst_rtp_jpeg_pay_header_size (data, offset);
|
quant_size = parse_mem_inc_offset_guint16 (memory);
|
||||||
if (quant_size < 2)
|
if (quant_size < 2)
|
||||||
goto small_quant_size;
|
goto small_quant_size;
|
||||||
|
|
||||||
/* clamp to available data */
|
/* clamp to available data */
|
||||||
if (offset + quant_size > size)
|
if (memory->offset + quant_size > memory->total_size)
|
||||||
quant_size = size - offset;
|
quant_size = memory->total_size - memory->offset;
|
||||||
|
|
||||||
offset += 2;
|
|
||||||
quant_size -= 2;
|
quant_size -= 2;
|
||||||
|
|
||||||
while (quant_size > 0) {
|
while (quant_size > 0) {
|
||||||
|
guint8 data;
|
||||||
/* not enough to read the id */
|
/* not enough to read the id */
|
||||||
if (offset + 1 > size)
|
if (memory->offset + 1 > memory->total_size)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
id = data[offset] & 0x0f;
|
data = parse_mem_inc_offset_guint8 (memory);
|
||||||
|
id = data & 0x0f;
|
||||||
if (id == 15)
|
if (id == 15)
|
||||||
/* invalid id received - corrupt data */
|
/* invalid id received - corrupt data */
|
||||||
goto invalid_id;
|
goto invalid_id;
|
||||||
|
|
||||||
prec = (data[offset] & 0xf0) >> 4;
|
prec = (data & 0xf0) >> 4;
|
||||||
if (prec)
|
if (prec)
|
||||||
tab_size = 128;
|
tab_size = 128;
|
||||||
else
|
else
|
||||||
|
@ -434,25 +466,26 @@ gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint size,
|
||||||
GST_LOG ("read quant table %d, tab_size %d, prec %02x", id, tab_size, prec);
|
GST_LOG ("read quant table %d, tab_size %d, prec %02x", id, tab_size, prec);
|
||||||
|
|
||||||
tables[id].size = tab_size;
|
tables[id].size = tab_size;
|
||||||
tables[id].data = &data[offset + 1];
|
tables[id].data = memory->data;
|
||||||
|
|
||||||
tab_size += 1;
|
quant_size -= (tab_size + 1);
|
||||||
quant_size -= tab_size;
|
if (!gst_buffer_memory_advance_bytes (memory, tab_size)) {
|
||||||
offset += tab_size;
|
goto too_small;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
return offset + quant_size;
|
return;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
too_small:
|
too_small:
|
||||||
{
|
{
|
||||||
GST_WARNING ("not enough data");
|
GST_WARNING ("not enough data");
|
||||||
return size;
|
return;
|
||||||
}
|
}
|
||||||
small_quant_size:
|
small_quant_size:
|
||||||
{
|
{
|
||||||
GST_WARNING ("quant_size too small (%u < 2)", quant_size);
|
GST_WARNING ("quant_size too small (%u < 2)", quant_size);
|
||||||
return size;
|
return;
|
||||||
}
|
}
|
||||||
invalid_id:
|
invalid_id:
|
||||||
{
|
{
|
||||||
|
@ -468,38 +501,31 @@ no_table:
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
|
gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, GstBufferMemoryMap * memory,
|
||||||
guint size, guint * offset, CompInfo info[], RtpQuantTable tables[],
|
CompInfo info[], RtpQuantTable tables[], gulong tables_elements)
|
||||||
gulong tables_elements)
|
|
||||||
{
|
{
|
||||||
guint sof_size, off;
|
guint sof_size, off;
|
||||||
guint width, height, infolen;
|
guint width, height, infolen;
|
||||||
CompInfo elem;
|
CompInfo elem;
|
||||||
gint i, j;
|
gint i, j;
|
||||||
|
|
||||||
off = *offset;
|
off = memory->offset;
|
||||||
|
|
||||||
/* we need at least 17 bytes for the SOF */
|
/* we need at least 17 bytes for the SOF */
|
||||||
if (off + 17 > size)
|
if (off + 17 > memory->total_size)
|
||||||
goto wrong_size;
|
goto wrong_size;
|
||||||
|
|
||||||
sof_size = gst_rtp_jpeg_pay_header_size (data, off);
|
sof_size = parse_mem_inc_offset_guint16 (memory);
|
||||||
if (sof_size < 17)
|
if (sof_size < 17)
|
||||||
goto wrong_length;
|
goto wrong_length;
|
||||||
|
|
||||||
*offset += sof_size;
|
|
||||||
|
|
||||||
/* skip size */
|
|
||||||
off += 2;
|
|
||||||
|
|
||||||
/* precision should be 8 */
|
/* precision should be 8 */
|
||||||
if (data[off++] != 8)
|
if (parse_mem_inc_offset_guint8 (memory) != 8)
|
||||||
goto bad_precision;
|
goto bad_precision;
|
||||||
|
|
||||||
/* read dimensions */
|
/* read dimensions */
|
||||||
height = data[off] << 8 | data[off + 1];
|
height = parse_mem_inc_offset_guint16 (memory);
|
||||||
width = data[off + 2] << 8 | data[off + 3];
|
width = parse_mem_inc_offset_guint16 (memory);
|
||||||
off += 4;
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (pay, "got dimensions %ux%u", height, width);
|
GST_LOG_OBJECT (pay, "got dimensions %ux%u", height, width);
|
||||||
|
|
||||||
|
@ -525,14 +551,14 @@ gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we only support 3 components */
|
/* we only support 3 components */
|
||||||
if (data[off++] != 3)
|
if (parse_mem_inc_offset_guint8 (memory) != 3)
|
||||||
goto bad_components;
|
goto bad_components;
|
||||||
|
|
||||||
infolen = 0;
|
infolen = 0;
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
elem.id = data[off++];
|
elem.id = parse_mem_inc_offset_guint8 (memory);
|
||||||
elem.samp = data[off++];
|
elem.samp = parse_mem_inc_offset_guint8 (memory);
|
||||||
elem.qt = data[off++];
|
elem.qt = parse_mem_inc_offset_guint8 (memory);
|
||||||
GST_LOG_OBJECT (pay, "got comp %d, samp %02x, qt %d", elem.id, elem.samp,
|
GST_LOG_OBJECT (pay, "got comp %d, samp %02x, qt %d", elem.id, elem.samp,
|
||||||
elem.qt);
|
elem.qt);
|
||||||
/* insertion sort from the last element to the first */
|
/* insertion sort from the last element to the first */
|
||||||
|
@ -565,7 +591,8 @@ gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
|
||||||
wrong_size:
|
wrong_size:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
|
GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
|
||||||
("Wrong size %u (needed %u).", size, off + 17), (NULL));
|
("Wrong size %u (needed %u).", (guint) memory->total_size, off + 17),
|
||||||
|
(NULL));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
wrong_length:
|
wrong_length:
|
||||||
|
@ -600,57 +627,81 @@ invalid_comp:
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_rtp_jpeg_pay_read_dri (GstRtpJPEGPay * pay, const guint8 * data,
|
gst_rtp_jpeg_pay_read_dri (GstRtpJPEGPay * pay, GstBufferMemoryMap * memory,
|
||||||
guint size, guint * offset, RtpRestartMarkerHeader * dri)
|
RtpRestartMarkerHeader * dri)
|
||||||
{
|
{
|
||||||
guint dri_size, off;
|
guint dri_size, restart_interval;
|
||||||
|
|
||||||
off = *offset;
|
|
||||||
|
|
||||||
/* we need at least 4 bytes for the DRI */
|
/* we need at least 4 bytes for the DRI */
|
||||||
if (off + 4 > size)
|
if (memory->offset + 4 > memory->total_size)
|
||||||
goto wrong_size;
|
goto wrong_size;
|
||||||
|
|
||||||
dri_size = gst_rtp_jpeg_pay_header_size (data, off);
|
dri_size = parse_mem_inc_offset_guint16 (memory);
|
||||||
if (dri_size < 4)
|
if (dri_size < 4)
|
||||||
goto wrong_length;
|
goto wrong_length;
|
||||||
|
|
||||||
*offset += dri_size;
|
restart_interval = parse_mem_inc_offset_guint16 (memory);
|
||||||
off += 2;
|
dri->restart_interval = g_htons (restart_interval);
|
||||||
|
|
||||||
dri->restart_interval = g_htons ((data[off] << 8) | (data[off + 1]));
|
|
||||||
dri->restart_count = g_htons (0xFFFF);
|
dri->restart_count = g_htons (0xFFFF);
|
||||||
|
if (!gst_buffer_memory_advance_bytes (memory, dri_size - 4)) {
|
||||||
|
goto wrong_size;
|
||||||
|
}
|
||||||
|
|
||||||
return dri->restart_interval > 0;
|
return dri->restart_interval > 0;
|
||||||
|
|
||||||
wrong_size:
|
wrong_size:
|
||||||
{
|
{
|
||||||
GST_WARNING ("not enough data for DRI");
|
GST_WARNING ("not enough data for DRI");
|
||||||
*offset = size;
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
wrong_length:
|
wrong_length:
|
||||||
{
|
{
|
||||||
GST_WARNING ("DRI size too small (%u)", dri_size);
|
GST_WARNING ("DRI size too small (%u)", dri_size);
|
||||||
*offset += dri_size;
|
/* offset got incremented by two when dri_size was parsed. */
|
||||||
|
if (dri_size > 2)
|
||||||
|
gst_buffer_memory_advance_bytes (memory, dri_size - 2);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static RtpJpegMarker
|
static void
|
||||||
gst_rtp_jpeg_pay_scan_marker (const guint8 * data, guint size, guint * offset)
|
gst_rtp_jpeg_pay_skipping_marker (GstBufferMemoryMap * memory)
|
||||||
{
|
{
|
||||||
while ((data[(*offset)++] != JPEG_MARKER) && ((*offset) < size));
|
guint skip;
|
||||||
|
|
||||||
if (G_UNLIKELY ((*offset) >= size)) {
|
if (G_UNLIKELY (((memory->offset + 1) >= memory->total_size))) {
|
||||||
|
goto wrong_size;
|
||||||
|
}
|
||||||
|
skip = parse_mem_inc_offset_guint16 (memory);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (((skip - 2 + memory->offset) > memory->total_size))) {
|
||||||
|
goto wrong_size;
|
||||||
|
}
|
||||||
|
if (skip > 2) {
|
||||||
|
gst_buffer_memory_advance_bytes (memory, skip - 2);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
wrong_size:
|
||||||
|
{
|
||||||
|
GST_WARNING ("not enough data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static RtpJpegMarker
|
||||||
|
gst_rtp_jpeg_pay_scan_marker (GstBufferMemoryMap * memory)
|
||||||
|
{
|
||||||
|
guint8 marker = parse_mem_inc_offset_guint8 (memory);
|
||||||
|
|
||||||
|
while (marker != JPEG_MARKER && ((memory->offset) < memory->total_size)) {
|
||||||
|
marker = parse_mem_inc_offset_guint8 (memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (G_UNLIKELY ((memory->offset) >= memory->total_size)) {
|
||||||
GST_LOG ("found EOI marker");
|
GST_LOG ("found EOI marker");
|
||||||
return JPEG_MARKER_EOI;
|
return JPEG_MARKER_EOI;
|
||||||
} else {
|
} else {
|
||||||
guint8 marker;
|
marker = parse_mem_inc_offset_guint8 (memory);
|
||||||
|
|
||||||
marker = data[*offset];
|
|
||||||
GST_LOG ("found 0x%02x marker at offset %u", marker, *offset);
|
|
||||||
(*offset)++;
|
|
||||||
return marker;
|
return marker;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -670,9 +721,6 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
||||||
RtpQuantTable tables[15] = { {0, NULL}, };
|
RtpQuantTable tables[15] = { {0, NULL}, };
|
||||||
CompInfo info[3] = { {0,}, };
|
CompInfo info[3] = { {0,}, };
|
||||||
guint quant_data_size;
|
guint quant_data_size;
|
||||||
GstMapInfo map;
|
|
||||||
guint8 *data;
|
|
||||||
gsize size;
|
|
||||||
guint mtu, max_payload_size;
|
guint mtu, max_payload_size;
|
||||||
guint bytes_left;
|
guint bytes_left;
|
||||||
guint jpeg_header_size = 0;
|
guint jpeg_header_size = 0;
|
||||||
|
@ -682,19 +730,19 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
||||||
gint i;
|
gint i;
|
||||||
GstBufferList *list = NULL;
|
GstBufferList *list = NULL;
|
||||||
gboolean discont;
|
gboolean discont;
|
||||||
|
GstBufferMemoryMap memory;
|
||||||
|
|
||||||
pay = GST_RTP_JPEG_PAY (basepayload);
|
pay = GST_RTP_JPEG_PAY (basepayload);
|
||||||
mtu = GST_RTP_BASE_PAYLOAD_MTU (pay);
|
mtu = GST_RTP_BASE_PAYLOAD_MTU (pay);
|
||||||
|
|
||||||
gst_buffer_map (buffer, &map, GST_MAP_READ);
|
gst_buffer_memory_map (buffer, &memory);
|
||||||
data = map.data;
|
|
||||||
size = map.size;
|
|
||||||
timestamp = GST_BUFFER_PTS (buffer);
|
timestamp = GST_BUFFER_PTS (buffer);
|
||||||
offset = 0;
|
|
||||||
discont = GST_BUFFER_IS_DISCONT (buffer);
|
discont = GST_BUFFER_IS_DISCONT (buffer);
|
||||||
|
|
||||||
GST_LOG_OBJECT (pay, "got buffer size %" G_GSIZE_FORMAT
|
GST_LOG_OBJECT (pay, "got buffer size %" G_GSIZE_FORMAT
|
||||||
" , timestamp %" GST_TIME_FORMAT, size, GST_TIME_ARGS (timestamp));
|
" , timestamp %" GST_TIME_FORMAT, memory.total_size,
|
||||||
|
GST_TIME_ARGS (timestamp));
|
||||||
|
|
||||||
/* parse the jpeg header for 'start of scan' and read quant tables if needed */
|
/* parse the jpeg header for 'start of scan' and read quant tables if needed */
|
||||||
sos_found = FALSE;
|
sos_found = FALSE;
|
||||||
|
@ -702,33 +750,35 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
||||||
sof_found = FALSE;
|
sof_found = FALSE;
|
||||||
dri_found = FALSE;
|
dri_found = FALSE;
|
||||||
|
|
||||||
while (!sos_found && (offset < size)) {
|
while (!sos_found && (memory.offset < memory.total_size)) {
|
||||||
gint marker;
|
gint marker;
|
||||||
|
|
||||||
GST_LOG_OBJECT (pay, "checking from offset %u", offset);
|
GST_LOG_OBJECT (pay, "checking from offset %u", memory.offset);
|
||||||
switch ((marker = gst_rtp_jpeg_pay_scan_marker (data, size, &offset))) {
|
marker = gst_rtp_jpeg_pay_scan_marker (&memory);
|
||||||
|
switch (marker) {
|
||||||
case JPEG_MARKER_JFIF:
|
case JPEG_MARKER_JFIF:
|
||||||
case JPEG_MARKER_CMT:
|
case JPEG_MARKER_CMT:
|
||||||
case JPEG_MARKER_DHT:
|
case JPEG_MARKER_DHT:
|
||||||
case JPEG_MARKER_H264:
|
case JPEG_MARKER_H264:
|
||||||
GST_LOG_OBJECT (pay, "skipping marker");
|
GST_LOG_OBJECT (pay, "skipping marker");
|
||||||
offset += gst_rtp_jpeg_pay_header_size (data, offset);
|
gst_rtp_jpeg_pay_skipping_marker (&memory);
|
||||||
break;
|
break;
|
||||||
case JPEG_MARKER_SOF:
|
case JPEG_MARKER_SOF:
|
||||||
if (!gst_rtp_jpeg_pay_read_sof (pay, data, size, &offset, info, tables,
|
if (!gst_rtp_jpeg_pay_read_sof (pay, &memory, info, tables,
|
||||||
G_N_ELEMENTS (tables)))
|
G_N_ELEMENTS (tables)))
|
||||||
goto invalid_format;
|
goto invalid_format;
|
||||||
sof_found = TRUE;
|
sof_found = TRUE;
|
||||||
break;
|
break;
|
||||||
case JPEG_MARKER_DQT:
|
case JPEG_MARKER_DQT:
|
||||||
GST_LOG ("DQT found");
|
GST_LOG ("DQT found");
|
||||||
offset = gst_rtp_jpeg_pay_read_quant_table (data, size, offset, tables);
|
gst_rtp_jpeg_pay_read_quant_table (&memory, tables);
|
||||||
dqt_found = TRUE;
|
dqt_found = TRUE;
|
||||||
break;
|
break;
|
||||||
case JPEG_MARKER_SOS:
|
case JPEG_MARKER_SOS:
|
||||||
sos_found = TRUE;
|
sos_found = TRUE;
|
||||||
GST_LOG_OBJECT (pay, "SOS found");
|
GST_LOG_OBJECT (pay, "SOS found");
|
||||||
jpeg_header_size = offset + gst_rtp_jpeg_pay_header_size (data, offset);
|
jpeg_header_size =
|
||||||
|
memory.offset + parse_mem_inc_offset_guint16 (&memory);
|
||||||
break;
|
break;
|
||||||
case JPEG_MARKER_EOI:
|
case JPEG_MARKER_EOI:
|
||||||
GST_WARNING_OBJECT (pay, "EOI reached before SOS!");
|
GST_WARNING_OBJECT (pay, "EOI reached before SOS!");
|
||||||
|
@ -738,8 +788,7 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
||||||
break;
|
break;
|
||||||
case JPEG_MARKER_DRI:
|
case JPEG_MARKER_DRI:
|
||||||
GST_LOG_OBJECT (pay, "DRI found");
|
GST_LOG_OBJECT (pay, "DRI found");
|
||||||
if (gst_rtp_jpeg_pay_read_dri (pay, data, size, &offset,
|
if (gst_rtp_jpeg_pay_read_dri (pay, &memory, &restart_marker_header))
|
||||||
&restart_marker_header))
|
|
||||||
dri_found = TRUE;
|
dri_found = TRUE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -747,8 +796,9 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
||||||
(marker >= JPEG_MARKER_JPG0 && marker <= JPEG_MARKER_JPG13) ||
|
(marker >= JPEG_MARKER_JPG0 && marker <= JPEG_MARKER_JPG13) ||
|
||||||
(marker >= JPEG_MARKER_APP0 && marker <= JPEG_MARKER_APP15)) {
|
(marker >= JPEG_MARKER_APP0 && marker <= JPEG_MARKER_APP15)) {
|
||||||
GST_LOG_OBJECT (pay, "skipping marker");
|
GST_LOG_OBJECT (pay, "skipping marker");
|
||||||
offset += gst_rtp_jpeg_pay_header_size (data, offset);
|
gst_rtp_jpeg_pay_skipping_marker (&memory);
|
||||||
} else {
|
} else {
|
||||||
|
/* no need to do anything, gst_rtp_jpeg_pay_scan_marker will go on */
|
||||||
GST_FIXME_OBJECT (pay, "unhandled marker 0x%02x", marker);
|
GST_FIXME_OBJECT (pay, "unhandled marker 0x%02x", marker);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -765,8 +815,6 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
||||||
|
|
||||||
GST_LOG_OBJECT (pay, "header size %u", jpeg_header_size);
|
GST_LOG_OBJECT (pay, "header size %u", jpeg_header_size);
|
||||||
|
|
||||||
size -= jpeg_header_size;
|
|
||||||
data += jpeg_header_size;
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
if (dri_found)
|
if (dri_found)
|
||||||
|
@ -778,7 +826,6 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
||||||
jpeg_header.q = pay->quant;
|
jpeg_header.q = pay->quant;
|
||||||
jpeg_header.width = pay->width;
|
jpeg_header.width = pay->width;
|
||||||
jpeg_header.height = pay->height;
|
jpeg_header.height = pay->height;
|
||||||
|
|
||||||
/* collect the quant headers sizes */
|
/* collect the quant headers sizes */
|
||||||
quant_header.mbz = 0;
|
quant_header.mbz = 0;
|
||||||
quant_header.precision = 0;
|
quant_header.precision = 0;
|
||||||
|
@ -809,7 +856,9 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
||||||
|
|
||||||
GST_LOG_OBJECT (pay, "quant_data size %u", quant_data_size);
|
GST_LOG_OBJECT (pay, "quant_data size %u", quant_data_size);
|
||||||
|
|
||||||
bytes_left = sizeof (jpeg_header) + quant_data_size + size;
|
bytes_left =
|
||||||
|
sizeof (jpeg_header) + quant_data_size + memory.total_size -
|
||||||
|
jpeg_header_size;
|
||||||
|
|
||||||
if (dri_found)
|
if (dri_found)
|
||||||
bytes_left += sizeof (restart_marker_header);
|
bytes_left += sizeof (restart_marker_header);
|
||||||
|
@ -912,14 +961,12 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
||||||
|
|
||||||
bytes_left -= payload_size;
|
bytes_left -= payload_size;
|
||||||
offset += payload_size;
|
offset += payload_size;
|
||||||
data += payload_size;
|
|
||||||
}
|
}
|
||||||
while (!frame_done);
|
while (!frame_done);
|
||||||
|
|
||||||
/* push the whole buffer list at once */
|
/* push the whole buffer list at once */
|
||||||
ret = gst_rtp_base_payload_push_list (basepayload, list);
|
ret = gst_rtp_base_payload_push_list (basepayload, list);
|
||||||
|
|
||||||
gst_buffer_unmap (buffer, &map);
|
gst_buffer_memory_unmap (&memory);
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -928,28 +975,28 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
||||||
unsupported_jpeg:
|
unsupported_jpeg:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Unsupported JPEG"), (NULL));
|
GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Unsupported JPEG"), (NULL));
|
||||||
gst_buffer_unmap (buffer, &map);
|
gst_buffer_memory_unmap (&memory);
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
no_dimension:
|
no_dimension:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("No size given"), (NULL));
|
GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("No size given"), (NULL));
|
||||||
gst_buffer_unmap (buffer, &map);
|
gst_buffer_memory_unmap (&memory);
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
invalid_format:
|
invalid_format:
|
||||||
{
|
{
|
||||||
/* error was posted */
|
/* error was posted */
|
||||||
gst_buffer_unmap (buffer, &map);
|
gst_buffer_memory_unmap (&memory);
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
invalid_quant:
|
invalid_quant:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Invalid quant tables"), (NULL));
|
GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Invalid quant tables"), (NULL));
|
||||||
gst_buffer_unmap (buffer, &map);
|
gst_buffer_memory_unmap (&memory);
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
353
tests/check/elements/rtpjpeg.c
Normal file
353
tests/check/elements/rtpjpeg.c
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
/* GStreamer RTP jpeg unit test
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Kristofer Bjorkstrom <at axis dot com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gst/check/check.h>
|
||||||
|
#include <gst/app/app.h>
|
||||||
|
#include <gst/rtp/gstrtpbuffer.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* one complete blank jpeg 1x1 */
|
||||||
|
static const guint8 rtp_jpeg_frame_data[] =
|
||||||
|
{ /* SOI */ 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46,
|
||||||
|
0x00, 0x01, 0x01, 0x01, 0x00, 0x60,
|
||||||
|
0x00, 0x60, 0x00, 0x00, /* DQT */ 0xff, 0xdb, 0x00, 0x43, 0x00, 0x08, 0x06,
|
||||||
|
0x06, 0x07, 0x06, 0x05, 0x08,
|
||||||
|
0x07, 0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0d, 0x0c, 0x0b, 0x0b,
|
||||||
|
0x0c, 0x19, 0x12,
|
||||||
|
0x13, 0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c, 0x1c, 0x20, 0x24,
|
||||||
|
0x2e, 0x27, 0x20,
|
||||||
|
0x22, 0x2c, 0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30, 0x31, 0x34, 0x34,
|
||||||
|
0x34, 0x1f, 0x27,
|
||||||
|
0x39, 0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0xff, 0xdb, 0x00, 0x43,
|
||||||
|
0x01, 0x09, 0x09,
|
||||||
|
0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0d, 0x0d, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32,
|
||||||
|
0x32, 0x32, 0x32,
|
||||||
|
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
|
||||||
|
0x32, 0x32, 0x32,
|
||||||
|
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
|
||||||
|
0x32, 0x32, 0x32,
|
||||||
|
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
|
||||||
|
0x32, /* SOF */ 0xff, 0xc0,
|
||||||
|
0x00, 0x11, 0x08, 0x00, 0x01, 0x00, 0x01, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11,
|
||||||
|
0x01, 0x03, 0x11,
|
||||||
|
0x01, 0xff, 0xc4, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||||
|
0x07, 0x08, 0x09,
|
||||||
|
0x0a, 0x0b, 0xff, 0xc4, 0x00, 0xb5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
|
||||||
|
0x04, 0x03, 0x05,
|
||||||
|
0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11,
|
||||||
|
0x05, 0x12, 0x21,
|
||||||
|
0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91,
|
||||||
|
0xa1, 0x08, 0x23,
|
||||||
|
0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09,
|
||||||
|
0x0a, 0x16, 0x17,
|
||||||
|
0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
|
||||||
|
0x38, 0x39, 0x3a,
|
||||||
|
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||||
|
0x58, 0x59, 0x5a,
|
||||||
|
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||||
|
0x78, 0x79, 0x7a,
|
||||||
|
0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
|
||||||
|
0x97, 0x98, 0x99,
|
||||||
|
0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
|
||||||
|
0xb5, 0xb6, 0xb7,
|
||||||
|
0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
|
||||||
|
0xd3, 0xd4, 0xd5,
|
||||||
|
0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
|
||||||
|
0xe9, 0xea, 0xf1,
|
||||||
|
0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc4, 0x00, 0x1f,
|
||||||
|
0x01, 0x00, 0x03,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x01,
|
||||||
|
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0xff, 0xc4, 0x00,
|
||||||
|
0xb5, 0x11, 0x00,
|
||||||
|
0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01,
|
||||||
|
0x02, 0x77, 0x00,
|
||||||
|
0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07,
|
||||||
|
0x61, 0x71, 0x13,
|
||||||
|
0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33,
|
||||||
|
0x52, 0xf0, 0x15,
|
||||||
|
0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
|
||||||
|
0x1a, 0x26, 0x27,
|
||||||
|
0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
|
||||||
|
0x47, 0x48, 0x49,
|
||||||
|
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
|
||||||
|
0x67, 0x68, 0x69,
|
||||||
|
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85,
|
||||||
|
0x86, 0x87, 0x88,
|
||||||
|
0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
|
||||||
|
0xa4, 0xa5, 0xa6,
|
||||||
|
0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
|
||||||
|
0xc2, 0xc3, 0xc4,
|
||||||
|
0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
|
||||||
|
0xd9, 0xda, 0xe2,
|
||||||
|
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
|
||||||
|
0xf7, 0xf8, 0xf9,
|
||||||
|
0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00,
|
||||||
|
0x3f, 0x00, 0xf7,
|
||||||
|
0xfa, 0x28, 0xa2, 0x80, 0x3f, 0xff, 0xd9
|
||||||
|
};
|
||||||
|
|
||||||
|
/* first slice of one complete blank jpeg 1x1 */
|
||||||
|
static const guint8 rtp_jpeg_frame_data_s1[] = {
|
||||||
|
/* SOI */ 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00,
|
||||||
|
0x01, 0x01, 0x01, 0x00, 0x60,
|
||||||
|
0x00, 0x60, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
/* second slice of one complete blank jpeg 1x1 */
|
||||||
|
static const guint8 rtp_jpeg_frame_data_s2[] = {
|
||||||
|
0x00, /* DQT */ 0xff, 0xdb, 0x00, 0x43, 0x00, 0x08, 0x06, 0x06, 0x07, 0x06,
|
||||||
|
0x05, 0x08,
|
||||||
|
0x07, 0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0d, 0x0c, 0x0b, 0x0b,
|
||||||
|
0x0c, 0x19, 0x12,
|
||||||
|
0x13, 0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c, 0x1c, 0x20, 0x24,
|
||||||
|
0x2e, 0x27, 0x20,
|
||||||
|
0x22, 0x2c, 0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30, 0x31, 0x34, 0x34,
|
||||||
|
0x34, 0x1f, 0x27,
|
||||||
|
0x39, 0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0xff, 0xdb, 0x00, 0x43,
|
||||||
|
0x01, 0x09, 0x09,
|
||||||
|
0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0d, 0x0d, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32,
|
||||||
|
0x32, 0x32, 0x32,
|
||||||
|
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
|
||||||
|
0x32, 0x32, 0x32
|
||||||
|
};
|
||||||
|
|
||||||
|
/* third slice of one complete blank jpeg 1x1 */
|
||||||
|
static const guint8 rtp_jpeg_frame_data_s3[] = {
|
||||||
|
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
|
||||||
|
0x32, 0x32, 0x32,
|
||||||
|
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
|
||||||
|
0x32, /* SOF */ 0xff, 0xc0,
|
||||||
|
0x00, 0x11, 0x08, 0x00, 0x01, 0x00, 0x01, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11,
|
||||||
|
0x01, 0x03, 0x11,
|
||||||
|
0x01, 0xff, 0xc4, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x01, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||||
|
0x07, 0x08, 0x09,
|
||||||
|
0x0a, 0x0b
|
||||||
|
};
|
||||||
|
|
||||||
|
/* fourth slice of one complete blank jpeg 1x1 */
|
||||||
|
static const guint8 rtp_jpeg_frame_data_s4[] = {
|
||||||
|
0xff, 0xc4, 0x00, 0xb5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
|
||||||
|
0x05,
|
||||||
|
0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11,
|
||||||
|
0x05, 0x12, 0x21,
|
||||||
|
0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91,
|
||||||
|
0xa1, 0x08, 0x23,
|
||||||
|
0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09,
|
||||||
|
0x0a, 0x16, 0x17,
|
||||||
|
0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
|
||||||
|
0x38, 0x39, 0x3a,
|
||||||
|
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||||
|
0x58, 0x59, 0x5a,
|
||||||
|
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||||
|
0x78, 0x79, 0x7a,
|
||||||
|
0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
|
||||||
|
0x97, 0x98, 0x99,
|
||||||
|
0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
|
||||||
|
0xb5, 0xb6, 0xb7,
|
||||||
|
0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
|
||||||
|
0xd3, 0xd4, 0xd5,
|
||||||
|
0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
|
||||||
|
0xe9, 0xea, 0xf1,
|
||||||
|
0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
/* fifth and last slice of one complete blank jpeg 1x1 */
|
||||||
|
static const guint8 rtp_jpeg_frame_data_s5[] = {
|
||||||
|
0xc4, 0x00, 0x1f, 0x01, 0x00, 0x03,
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x01,
|
||||||
|
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0xff, 0xc4, 0x00,
|
||||||
|
0xb5, 0x11, 0x00,
|
||||||
|
0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01,
|
||||||
|
0x02, 0x77, 0x00,
|
||||||
|
0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07,
|
||||||
|
0x61, 0x71, 0x13,
|
||||||
|
0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33,
|
||||||
|
0x52, 0xf0, 0x15,
|
||||||
|
0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
|
||||||
|
0x1a, 0x26, 0x27,
|
||||||
|
0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
|
||||||
|
0x47, 0x48, 0x49,
|
||||||
|
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
|
||||||
|
0x67, 0x68, 0x69,
|
||||||
|
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85,
|
||||||
|
0x86, 0x87, 0x88,
|
||||||
|
0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
|
||||||
|
0xa4, 0xa5, 0xa6,
|
||||||
|
0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
|
||||||
|
0xc2, 0xc3, 0xc4,
|
||||||
|
0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
|
||||||
|
0xd9, 0xda, 0xe2,
|
||||||
|
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
|
||||||
|
0xf7, 0xf8, 0xf9,
|
||||||
|
0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00,
|
||||||
|
0x3f, 0x00, 0xf7,
|
||||||
|
0xfa, 0x28, 0xa2, 0x80, 0x3f, 0xff, 0xd9
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rfc2435 3.1. JPEG header
|
||||||
|
*
|
||||||
|
* Each packet contains a special JPEG header which immediately follows
|
||||||
|
* the RTP header. The first 8 bytes of this header, called the "main
|
||||||
|
* JPEG header", are as follows:
|
||||||
|
*
|
||||||
|
* 0 1 2 3
|
||||||
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | Type-specific | Fragment Offset |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | Type | Q | Width | Height |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
GST_START_TEST (test_rtpjpegpay_1_slice)
|
||||||
|
{
|
||||||
|
GstFlowReturn ret;
|
||||||
|
GstBuffer *buffer;
|
||||||
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
||||||
|
GstCaps *caps = gst_caps_from_string ("video/x-jpeg,height=1,width=1");
|
||||||
|
gchar *s = g_strdup_printf ("rtpjpegpay");
|
||||||
|
GstHarness *h = gst_harness_new_parse (s);
|
||||||
|
guint8 *payload;
|
||||||
|
|
||||||
|
gst_harness_set_src_caps (h, caps);
|
||||||
|
g_free (s);
|
||||||
|
|
||||||
|
buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
|
||||||
|
(guint8 *) rtp_jpeg_frame_data, sizeof (rtp_jpeg_frame_data), 0,
|
||||||
|
sizeof (rtp_jpeg_frame_data), NULL, NULL);
|
||||||
|
|
||||||
|
ret = gst_harness_push (h, buffer);
|
||||||
|
fail_unless_equals_int (ret, GST_FLOW_OK);
|
||||||
|
|
||||||
|
fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1);
|
||||||
|
|
||||||
|
buffer = gst_harness_pull (h);
|
||||||
|
fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
|
||||||
|
fail_unless (payload = gst_rtp_buffer_get_payload (&rtp));
|
||||||
|
|
||||||
|
/* verify JPEG header */
|
||||||
|
fail_unless (GST_READ_UINT24_BE (&payload[1]) == 0); /* offset */
|
||||||
|
fail_unless (payload[4] == 1); /* type */
|
||||||
|
fail_unless (payload[6] == 1); /* Width */
|
||||||
|
fail_unless (payload[7] == 1); /* Height */
|
||||||
|
|
||||||
|
fail_unless (gst_rtp_buffer_get_marker (&rtp));
|
||||||
|
gst_rtp_buffer_unmap (&rtp);
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
|
gst_harness_teardown (h);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_rtpjpegpay_5_slices)
|
||||||
|
{
|
||||||
|
GstFlowReturn ret;
|
||||||
|
GstBuffer *buffer;
|
||||||
|
GstBuffer *buffer_s1;
|
||||||
|
GstBuffer *buffer_s2;
|
||||||
|
GstBuffer *buffer_s3;
|
||||||
|
GstBuffer *buffer_s4;
|
||||||
|
GstBuffer *buffer_s5;
|
||||||
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
||||||
|
GstCaps *caps = gst_caps_from_string ("video/x-jpeg,height=1,width=1");
|
||||||
|
gchar *s = g_strdup_printf ("rtpjpegpay");
|
||||||
|
GstHarness *h = gst_harness_new_parse (s);
|
||||||
|
guint8 *payload;
|
||||||
|
|
||||||
|
gst_harness_set_src_caps (h, caps);
|
||||||
|
g_free (s);
|
||||||
|
|
||||||
|
buffer_s1 = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
|
||||||
|
(guint8 *) rtp_jpeg_frame_data_s1, sizeof (rtp_jpeg_frame_data_s1), 0,
|
||||||
|
sizeof (rtp_jpeg_frame_data_s1), NULL, NULL);
|
||||||
|
buffer_s2 =
|
||||||
|
gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
|
||||||
|
(guint8 *) rtp_jpeg_frame_data_s2, sizeof (rtp_jpeg_frame_data_s2), 0,
|
||||||
|
sizeof (rtp_jpeg_frame_data_s2), NULL, NULL);
|
||||||
|
buffer_s3 =
|
||||||
|
gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
|
||||||
|
(guint8 *) rtp_jpeg_frame_data_s3, sizeof (rtp_jpeg_frame_data_s3), 0,
|
||||||
|
sizeof (rtp_jpeg_frame_data_s3), NULL, NULL);
|
||||||
|
buffer_s4 =
|
||||||
|
gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
|
||||||
|
(guint8 *) rtp_jpeg_frame_data_s4, sizeof (rtp_jpeg_frame_data_s4), 0,
|
||||||
|
sizeof (rtp_jpeg_frame_data_s4), NULL, NULL);
|
||||||
|
buffer_s5 =
|
||||||
|
gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
|
||||||
|
(guint8 *) rtp_jpeg_frame_data_s5, sizeof (rtp_jpeg_frame_data_s5), 0,
|
||||||
|
sizeof (rtp_jpeg_frame_data_s5), NULL, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
buffer = gst_buffer_append (buffer_s1, buffer_s2);
|
||||||
|
buffer = gst_buffer_append (buffer, buffer_s3);
|
||||||
|
buffer = gst_buffer_append (buffer, buffer_s4);
|
||||||
|
buffer = gst_buffer_append (buffer, buffer_s5);
|
||||||
|
|
||||||
|
ret = gst_harness_push (h, buffer);
|
||||||
|
fail_unless_equals_int (ret, GST_FLOW_OK);
|
||||||
|
|
||||||
|
fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1);
|
||||||
|
|
||||||
|
buffer = gst_harness_pull (h);
|
||||||
|
fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
|
||||||
|
fail_unless (payload = gst_rtp_buffer_get_payload (&rtp));
|
||||||
|
|
||||||
|
/* verify JPEG header */
|
||||||
|
fail_unless (GST_READ_UINT24_BE (&payload[1]) == 0); /* offset */
|
||||||
|
fail_unless (payload[4] == 1); /* type */
|
||||||
|
fail_unless (payload[6] == 1); /* Width */
|
||||||
|
fail_unless (payload[7] == 1); /* Height */
|
||||||
|
|
||||||
|
fail_unless (gst_rtp_buffer_get_marker (&rtp));
|
||||||
|
gst_rtp_buffer_unmap (&rtp);
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
|
gst_harness_teardown (h);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
|
||||||
|
static Suite *
|
||||||
|
rtpjpeg_suite (void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create ("rtpjpeg");
|
||||||
|
TCase *tc_chain;
|
||||||
|
|
||||||
|
tc_chain = tcase_create ("rtpjpegpay_memory_slices");
|
||||||
|
suite_add_tcase (s, tc_chain);
|
||||||
|
|
||||||
|
tcase_add_test (tc_chain, test_rtpjpegpay_1_slice);
|
||||||
|
tcase_add_test (tc_chain, test_rtpjpegpay_5_slices);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_CHECK_MAIN (rtpjpeg);
|
|
@ -71,6 +71,7 @@ good_tests = [
|
||||||
[ 'elements/rtpcollision' ],
|
[ 'elements/rtpcollision' ],
|
||||||
[ 'elements/rtpfunnel' ],
|
[ 'elements/rtpfunnel' ],
|
||||||
[ 'elements/rtpjitterbuffer' ],
|
[ 'elements/rtpjitterbuffer' ],
|
||||||
|
[ 'elements/rtpjpeg' ],
|
||||||
|
|
||||||
[ 'elements/rtptimerqueue', false, [gstrtp_dep],
|
[ 'elements/rtptimerqueue', false, [gstrtp_dep],
|
||||||
['../../gst/rtpmanager/rtptimerqueue.c']],
|
['../../gst/rtpmanager/rtptimerqueue.c']],
|
||||||
|
|
Loading…
Reference in a new issue