summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gst/rtp/gstrtpjpegpay.c225
1 files changed, 132 insertions, 93 deletions
diff --git a/gst/rtp/gstrtpjpegpay.c b/gst/rtp/gstrtpjpegpay.c
index 81f044b06..33fe310dc 100644
--- a/gst/rtp/gstrtpjpegpay.c
+++ b/gst/rtp/gstrtpjpegpay.c
@@ -125,7 +125,6 @@ enum
};
typedef struct _RtpJpegHeader RtpJpegHeader;
-typedef struct _RtpQuantHeader RtpQuantHeader;
/*
* RtpJpegHeader:
@@ -174,12 +173,25 @@ struct _RtpJpegHeader
* | ... |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
-struct _RtpQuantHeader
+typedef struct
{
guint8 mbz;
guint8 precision;
guint16 length;
-};
+} RtpQuantHeader;
+
+typedef struct
+{
+ guint8 size;
+ const guint8 *data;
+} RtpQuantTable;
+
+typedef struct
+{
+ guint8 id;
+ guint8 samp;
+ guint8 qt;
+} CompInfo;
/* FIXME: restart marker header currently unsupported */
@@ -293,39 +305,44 @@ gst_rtp_jpeg_pay_header_size (const guint8 * data, guint offset)
static guint
gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint offset,
- const guint8 ** quantizer_table, RtpQuantHeader * qtable, guint8 index)
+ RtpQuantTable tables[])
{
- gint quant_size;
+ gint quant_size, size, result;
+ guint8 prec;
+ guint8 id;
- quant_size = gst_rtp_jpeg_pay_header_size (data, offset);
+ result = quant_size = gst_rtp_jpeg_pay_header_size (data, offset);
+ offset += 2;
+ quant_size -= 2;
- GST_LOG ("read quant table %d, size %d", index, quant_size);
+ while (quant_size > 0) {
+ prec = (data[offset] & 0xf0) >> 4;
+ id = data[offset] & 0xf;
- qtable->precision |= (data[offset + 2] & 0x10) ? (1 << index) : 0x00;
+ if (prec)
+ size = 128;
+ else
+ size = 64;
- /* ommit length and precision prefix from table */
- quantizer_table[index] = &data[offset + QUANT_PREFIX_LEN];
- quant_size -= QUANT_PREFIX_LEN;
+ GST_LOG ("read quant table %d, size %d, prec %02x", id, size, prec);
- qtable->length += quant_size;
+ tables[id].size = size;
+ tables[id].data = &data[offset + 1];
- return quant_size;
+ size += 1;
+ quant_size -= size;
+ offset += size;
+ }
+ return result;
}
-typedef struct
-{
- guint8 id;
- guint8 samp;
- guint8 qt;
-} CompInfo;
-
static gboolean
gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
- guint * offset, RtpJpegHeader * header)
+ guint * offset, CompInfo info[])
{
guint sof_size;
guint width, height, infolen;
- CompInfo elem, info[3], *cptr;
+ CompInfo elem;
gint i, j;
sof_size = gst_rtp_jpeg_pay_header_size (data, *offset);
@@ -354,9 +371,6 @@ gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
pay->height = height / 8;
pay->width = width / 8;
- header->width = pay->width;
- header->height = pay->height;
-
/* we only support 3 components */
if (data[(*offset)++] != 3)
goto bad_components;
@@ -378,25 +392,23 @@ gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
infolen++;
}
- /* see that the components are supported, the first component must use quant
- * table 0 */
- cptr = &info[0];
- if (cptr->samp == 0x21 && cptr->qt == 0)
+ /* see that the components are supported */
+ if (info[0].samp == 0x21)
pay->type = 0;
- else if (cptr->samp == 0x22 && cptr->qt == 0)
+ else if (info[0].samp == 0x22)
pay->type = 1;
else
goto invalid_comp;
- header->type = pay->type;
+ /* the other components are free to use any quant table but they have to
+ * have the same table id */
+ if (!(info[1].samp == 0x11))
+ goto invalid_comp;
- /* the other components are free to use quant table 0 or 1 */
- cptr = &info[1];
- if (!(cptr->samp == 0x11 && cptr->qt < 2))
+ if (!(info[2].samp == 0x11))
goto invalid_comp;
- cptr = &info[2];
- if (!(cptr->samp == 0x11 && cptr->qt < 2))
+ if (info[1].qt != info[2].qt)
goto invalid_comp;
return TRUE;
@@ -459,37 +471,32 @@ gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload,
GstFlowReturn ret = GST_FLOW_ERROR;
RtpJpegHeader jpeg_header;
RtpQuantHeader quant_header;
- const guint8 *jpeg_quantizer_table[Q_TABLE_MAX] = { NULL };
+ RtpQuantTable tables[15] = { {0, NULL}, };
+ CompInfo info[3] = { {0,}, };
+ guint quant_data_size;
guint8 *data;
- guint8 quant_table_index = 0;
guint size;
guint mtu;
guint bytes_left;
- guint quant_data_size = sizeof (quant_header);
guint jpeg_header_size = 0;
- guint offset = 0;
- gboolean frame_done = FALSE;
- gboolean sos_found = FALSE;
+ guint offset;
+ gboolean frame_done;
+ gboolean sos_found;
+ gint i;
pay = GST_RTP_JPEG_PAY (basepayload);
mtu = GST_BASE_RTP_PAYLOAD_MTU (pay);
- /* will be overwritten by SOF when present */
- jpeg_header.type_spec = 0;
- jpeg_header.offset = 0;
- jpeg_header.type = pay->type;
- jpeg_header.q = pay->quant;
- jpeg_header.width = pay->width;
- jpeg_header.height = pay->height;
-
size = GST_BUFFER_SIZE (buffer);
data = GST_BUFFER_DATA (buffer);
timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ offset = 0;
GST_LOG_OBJECT (pay, "got buffer size %u, timestamp %" GST_TIME_FORMAT, size,
GST_TIME_ARGS (timestamp));
/* parse the jpeg header for 'start of scan' and read quant tables if needed */
+ sos_found = FALSE;
while (!sos_found && (offset < size)) {
GST_LOG_OBJECT (pay, "checking from offset %u", offset);
switch (gst_rtp_jpeg_pay_scan_marker (data, size, &offset)) {
@@ -499,38 +506,18 @@ gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload,
offset += gst_rtp_jpeg_pay_header_size (data, offset);
break;
case JPEG_MARKER_SOF:
- if (!gst_rtp_jpeg_pay_read_sof (pay, data, &offset, &jpeg_header))
+ if (!gst_rtp_jpeg_pay_read_sof (pay, data, &offset, info))
goto invalid_format;
break;
case JPEG_MARKER_DQT:
{
GST_LOG ("DQT found");
- if ((jpeg_header.q >= 128) && (quant_table_index < Q_TABLE_MAX)) {
- if (!quant_table_index) {
- quant_header.length = 0;
- quant_header.precision = 0;
- quant_header.mbz = 0;
- }
- quant_data_size += gst_rtp_jpeg_pay_read_quant_table (data, offset,
- jpeg_quantizer_table, &quant_header, quant_table_index);
-
- quant_table_index++;
- }
- offset += gst_rtp_jpeg_pay_header_size (data, offset);
+ offset += gst_rtp_jpeg_pay_read_quant_table (data, offset, tables);
break;
}
case JPEG_MARKER_SOS:
{
sos_found = TRUE;
- if (quant_table_index == 1) {
- /* we only had one quant table, duplicate it. We always need 2 quant
- * tables for the Types we support */
- jpeg_quantizer_table[1] = jpeg_quantizer_table[0];
- quant_table_index++;
- quant_data_size += quant_header.length;
- quant_header.length += quant_header.length;
- quant_header.precision |= (quant_header.precision & 1) << 1;
- }
GST_LOG_OBJECT (pay, "SOS found");
jpeg_header_size = offset + gst_rtp_jpeg_pay_header_size (data, offset);
break;
@@ -545,7 +532,9 @@ gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload,
break;
}
}
- if (jpeg_header.width == 0 || jpeg_header.height == 0)
+ /* by now we should either have negotiated the width/height or the SOF header
+ * should have filled us in */
+ if (pay->width == 0 || pay->height == 0)
goto no_dimension;
GST_LOG_OBJECT (pay, "header size %u", jpeg_header_size);
@@ -554,9 +543,47 @@ gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload,
data += jpeg_header_size;
offset = 0;
+ /* prepare stuff for the jpeg header */
+ jpeg_header.type_spec = 0;
+ jpeg_header.type = pay->type;
+ jpeg_header.q = pay->quant;
+ jpeg_header.width = pay->width;
+ jpeg_header.height = pay->height;
+
+ /* collect the quant headers sizes */
+ quant_header.mbz = 0;
+ quant_header.precision = 0;
+ quant_header.length = 0;
+ quant_data_size = 0;
+
+ if (pay->quant > 127) {
+ /* for the Y and U component, look up the quant table and its size. quant
+ * tables for U and V should be the same */
+ for (i = 0; i < 2; i++) {
+ guint qsize;
+ guint qt;
+
+ qt = info[i].qt;
+ if (qt > 15)
+ goto invalid_quant;
+
+ qsize = tables[qt].size;
+ if (qsize == 0)
+ goto invalid_quant;
+
+ quant_header.precision |= (qsize == 64 ? 0 : (1 << i));
+ quant_data_size += qsize;
+ }
+ quant_header.length = g_htons (quant_data_size);
+ quant_data_size += sizeof (quant_header);
+ }
+
+ GST_LOG_OBJECT (pay, "quant_data size %u", quant_data_size);
+
bytes_left = sizeof (jpeg_header) + quant_data_size + size;
- while (!frame_done) {
+ frame_done = FALSE;
+ do {
GstBuffer *outbuf;
guint8 *payload;
guint payload_size = (bytes_left < mtu ? bytes_left : mtu);
@@ -572,34 +599,43 @@ gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload,
payload = gst_rtp_buffer_get_payload (outbuf);
+ /* update offset */
+#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
+ jpeg_header.offset = ((offset & 0x0000FF) << 16) |
+ ((offset & 0xFF0000) >> 16) | (offset & 0x00FF00);
+#else
+ jpeg_header.offset = offset;
+#endif
memcpy (payload, &jpeg_header, sizeof (jpeg_header));
payload += sizeof (jpeg_header);
payload_size -= sizeof (jpeg_header);
/* only send quant table with first packet */
if (G_UNLIKELY (quant_data_size > 0)) {
- guint8 index;
- const guint8 table_size = quant_header.length / quant_table_index;
-
- quant_header.length = g_htons (quant_header.length);
-
memcpy (payload, &quant_header, sizeof (quant_header));
payload += sizeof (quant_header);
- for (index = 0; index < quant_table_index; index++) {
- GST_LOG_OBJECT (pay, "sending quant data %d, size %d", index,
- table_size);
- memcpy (payload, jpeg_quantizer_table[index], table_size);
- payload += table_size;
- }
+ /* copy the quant tables for luma and chrominance */
+ for (i = 0; i < 2; i++) {
+ guint qsize;
+ guint qt;
+
+ qt = info[i].qt;
+ qsize = tables[qt].size;
+ memcpy (payload, tables[qt].data, qsize);
+
+ GST_LOG_OBJECT (pay, "component %d using quant %d, size %d", i, qt,
+ qsize);
+ payload += qsize;
+ }
payload_size -= quant_data_size;
bytes_left -= quant_data_size;
quant_data_size = 0;
}
GST_LOG_OBJECT (pay, "sending payload size %d", payload_size);
- memcpy (payload, &data[offset], payload_size);
+ memcpy (payload, data, payload_size);
ret = gst_basertppayload_push (basepayload, outbuf);
if (ret != GST_FLOW_OK)
@@ -607,14 +643,9 @@ gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload,
bytes_left -= payload_size;
offset += payload_size;
-
-#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
- jpeg_header.offset = ((offset & 0x0000FF) << 16) |
- ((offset & 0xFF0000) >> 16) | (offset & 0x00FF00);
-#else
- jpeg_header.offset = offset;
-#endif
+ data += payload_size;
}
+ while (!frame_done);
gst_buffer_unref (buffer);
@@ -624,11 +655,19 @@ gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload,
no_dimension:
{
GST_ELEMENT_ERROR (pay, STREAM, FORMAT, ("No size given"), (NULL));
+ gst_buffer_unref (buffer);
return GST_FLOW_NOT_NEGOTIATED;
}
invalid_format:
{
/* error was posted */
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
+ }
+invalid_quant:
+ {
+ GST_ELEMENT_ERROR (pay, STREAM, FORMAT, ("Invalid quant tables"), (NULL));
+ gst_buffer_unref (buffer);
return GST_FLOW_ERROR;
}
}