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

View file

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

View file

@ -134,6 +134,7 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf,
case '\n':
case '\t':
case ' ':
mngr->info.fields |= GST_PNM_INFO_FIELDS_WIDTH;
mngr->state = GST_PNM_INFO_MNGR_STATE_WHITE_SPACE;
mngr->data_offset += 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 += buf[i++] - 0x030;
mngr->info.fields |= GST_PNM_INFO_FIELDS_WIDTH;
mngr->data_offset += i;
return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i);
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 '\t':
case ' ':
mngr->info.fields |= GST_PNM_INFO_FIELDS_HEIGHT;
mngr->state = GST_PNM_INFO_MNGR_STATE_WHITE_SPACE;
mngr->data_offset += 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 += buf[i++] - 0x030;
mngr->info.fields |= GST_PNM_INFO_FIELDS_HEIGHT;
mngr->data_offset += i;
return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i);
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 '\t':
case ' ':
mngr->info.fields |= GST_PNM_INFO_FIELDS_MAX;
mngr->data_offset += i + 1;
return GST_PNM_INFO_MNGR_RESULT_FINISHED;
default:
@ -178,7 +179,6 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf,
}
mngr->info.max *= 10;
mngr->info.max += buf[i++] - 0x030;
mngr->info.fields |= GST_PNM_INFO_FIELDS_MAX;
mngr->data_offset += i;
return gst_pnm_info_mngr_scan (mngr, buf + i, buf_len - i);
}