pnm: Handle ASCII encoded PNM data that is split over multiple buffers

Also:
- unref buffers after gst_buffer_span
- fix scanning of header if header data is split over several buffers

Fixes bug #595700.
This commit is contained in:
Lutz Mueller 2009-09-22 08:11:36 +02:00 committed by Sebastian Dröge
parent 960f418378
commit a744f8136b
3 changed files with 51 additions and 16 deletions

View file

@ -95,6 +95,7 @@ static GstFlowReturn
gst_pnmdec_chain_raw (GstPnmdec * s, GstPad * src, GstBuffer * buf) gst_pnmdec_chain_raw (GstPnmdec * s, GstPad * src, GstBuffer * buf)
{ {
GstFlowReturn r = GST_FLOW_OK; GstFlowReturn r = GST_FLOW_OK;
GstBuffer *out;
/* If we got the whole image, just push the buffer. */ /* If we got the whole image, just push the buffer. */
if (GST_BUFFER_SIZE (buf) == s->size) { if (GST_BUFFER_SIZE (buf) == s->size) {
@ -108,10 +109,11 @@ gst_pnmdec_chain_raw (GstPnmdec * s, GstPad * src, GstBuffer * buf)
if (!s->buf) { if (!s->buf) {
s->buf = buf; s->buf = buf;
} else { } else {
buf = gst_buffer_span (s->buf, 0, buf, out = gst_buffer_span (s->buf, 0, buf,
GST_BUFFER_SIZE (s->buf) + GST_BUFFER_SIZE (buf)); GST_BUFFER_SIZE (s->buf) + GST_BUFFER_SIZE (buf));
gst_buffer_unref (buf);
gst_buffer_unref (s->buf); gst_buffer_unref (s->buf);
s->buf = buf; s->buf = out;
} }
if (!s->buf) if (!s->buf)
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
@ -132,16 +134,46 @@ static GstFlowReturn
gst_pnmdec_chain_ascii (GstPnmdec * s, GstPad * src, GstBuffer * buf) gst_pnmdec_chain_ascii (GstPnmdec * s, GstPad * src, GstBuffer * buf)
{ {
GScanner *scanner; GScanner *scanner;
GstBuffer *out = gst_buffer_new_and_alloc (s->size); GstBuffer *out;
guint i = 0; guint i = 0;
gchar *b = (gchar *) GST_BUFFER_DATA (buf);
guint bs = GST_BUFFER_SIZE (buf);
guint target = s->size - (s->buf ? GST_BUFFER_SIZE (s->buf) : 0);
if (!bs) {
gst_buffer_unref (buf);
return GST_FLOW_OK;
}
if (s->last_byte) {
while (*b >= '0' && *b <= '9') {
s->last_byte = 10 * s->last_byte + *b - '0';
b++;
if (!--bs) {
gst_buffer_unref (buf);
return GST_FLOW_OK;
}
}
if (s->last_byte > 255) {
gst_buffer_unref (buf);
GST_DEBUG_OBJECT (s, "Corrupt ASCII encoded PNM file.");
return GST_FLOW_ERROR;
}
}
out = gst_buffer_new_and_alloc (target);
if (s->last_byte) {
GST_BUFFER_DATA (out)[i++] = s->last_byte;
s->last_byte = 0;
}
scanner = g_scanner_new (NULL); scanner = g_scanner_new (NULL);
g_scanner_input_text (scanner, (gchar *) GST_BUFFER_DATA (buf), g_scanner_input_text (scanner, b, bs);
GST_BUFFER_SIZE (buf));
while (!g_scanner_eof (scanner)) { while (!g_scanner_eof (scanner)) {
switch (g_scanner_get_next_token (scanner)) { switch (g_scanner_get_next_token (scanner)) {
case G_TOKEN_INT: case G_TOKEN_INT:
if (i == s->size) { if (i == target) {
GST_DEBUG_OBJECT (s, "PNM file contains too much data."); GST_DEBUG_OBJECT (s, "PNM file contains too much data.");
gst_buffer_unref (buf); gst_buffer_unref (buf);
gst_buffer_unref (out); gst_buffer_unref (out);
@ -154,15 +186,18 @@ gst_pnmdec_chain_ascii (GstPnmdec * s, GstPad * src, GstBuffer * buf)
} }
} }
g_scanner_destroy (scanner); g_scanner_destroy (scanner);
gst_buffer_unref (buf);
if (i < s->size) { /* If we didn't get the whole image, handle the last byte with care. */
GST_DEBUG_OBJECT (s, "FIXME: Decoding of ASCII encoded files split " if (i < target && b[bs - 1] > '0' && b[bs - 1] <= '9')
"over several buffers is not implemented!"); s->last_byte = GST_BUFFER_DATA (out)[--i];
gst_buffer_unref (buf);
if (!i) {
gst_buffer_unref (out); gst_buffer_unref (out);
return GST_FLOW_ERROR; return GST_FLOW_OK;
} }
GST_BUFFER_SIZE (out) = i;
return gst_pnmdec_chain_raw (s, src, out); return gst_pnmdec_chain_raw (s, src, out);
} }
@ -175,7 +210,7 @@ gst_pnmdec_chain (GstPad * pad, GstBuffer * data)
GstFlowReturn r = GST_FLOW_OK; GstFlowReturn r = GST_FLOW_OK;
guint offset = 0; guint offset = 0;
if (!(s->mngr.info.fields & GST_PNM_INFO_FIELDS_ALL)) { if (s->mngr.info.fields != GST_PNM_INFO_FIELDS_ALL) {
switch (gst_pnm_info_mngr_scan (&s->mngr, GST_BUFFER_DATA (data), switch (gst_pnm_info_mngr_scan (&s->mngr, GST_BUFFER_DATA (data),
GST_BUFFER_SIZE (data))) { GST_BUFFER_SIZE (data))) {
case GST_PNM_INFO_MNGR_RESULT_FAILED: case GST_PNM_INFO_MNGR_RESULT_FAILED:

View file

@ -39,7 +39,7 @@ struct _GstPnmdec
GstElement element; GstElement element;
GstPnmInfoMngr mngr; GstPnmInfoMngr mngr;
guint size; guint size, last_byte;
GstBuffer *buf; GstBuffer *buf;
}; };

View file

@ -134,6 +134,7 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf,
case '\n': case '\n':
case '\t': case '\t':
case ' ': case ' ':
mngr->info.fields |= GST_PNM_INFO_FIELDS_WIDTH;
mngr->state = GST_PNM_INFO_MNGR_STATE_WHITE_SPACE; mngr->state = GST_PNM_INFO_MNGR_STATE_WHITE_SPACE;
mngr->data_offset += i; mngr->data_offset += i;
return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i); return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i);
@ -143,7 +144,6 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf,
} }
mngr->info.width *= 10; mngr->info.width *= 10;
mngr->info.width += buf[i++] - 0x030; mngr->info.width += buf[i++] - 0x030;
mngr->info.fields |= GST_PNM_INFO_FIELDS_WIDTH;
mngr->data_offset += i; mngr->data_offset += i;
return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i); return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i);
case GST_PNM_INFO_MNGR_STATE_DATA_HEIGHT: case GST_PNM_INFO_MNGR_STATE_DATA_HEIGHT:
@ -152,6 +152,7 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf,
case '\n': case '\n':
case '\t': case '\t':
case ' ': case ' ':
mngr->info.fields |= GST_PNM_INFO_FIELDS_HEIGHT;
mngr->state = GST_PNM_INFO_MNGR_STATE_WHITE_SPACE; mngr->state = GST_PNM_INFO_MNGR_STATE_WHITE_SPACE;
mngr->data_offset += i; mngr->data_offset += i;
return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i); return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i);
@ -161,7 +162,6 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf,
} }
mngr->info.height *= 10; mngr->info.height *= 10;
mngr->info.height += buf[i++] - 0x030; mngr->info.height += buf[i++] - 0x030;
mngr->info.fields |= GST_PNM_INFO_FIELDS_HEIGHT;
mngr->data_offset += i; mngr->data_offset += i;
return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i); return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i);
case GST_PNM_INFO_MNGR_STATE_DATA_MAX: case GST_PNM_INFO_MNGR_STATE_DATA_MAX:
@ -170,6 +170,7 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf,
case '\n': case '\n':
case '\t': case '\t':
case ' ': case ' ':
mngr->info.fields |= GST_PNM_INFO_FIELDS_MAX;
mngr->data_offset += i + 1; mngr->data_offset += i + 1;
return GST_PNM_INFO_MNGR_RESULT_FINISHED; return GST_PNM_INFO_MNGR_RESULT_FINISHED;
default: default:
@ -178,7 +179,6 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf,
} }
mngr->info.max *= 10; mngr->info.max *= 10;
mngr->info.max += buf[i++] - 0x030; mngr->info.max += buf[i++] - 0x030;
mngr->info.fields |= GST_PNM_INFO_FIELDS_MAX;
mngr->data_offset += i; mngr->data_offset += i;
return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i); return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i);
} }