From f270259cc8b08c0123b76f7e235ae9a24dbafb81 Mon Sep 17 00:00:00 2001 From: Lutz Mueller Date: Wed, 16 Sep 2009 08:22:19 +0200 Subject: pnm: Support ASCII format for encoding and handle unsupported formats better in the decoder Fixes bug #595215. --- gst/pnm/gstpnm.c | 9 ++--- gst/pnm/gstpnmdec.c | 25 +++++++++----- gst/pnm/gstpnmenc.c | 93 ++++++++++++++++++++++++++++++++++++++++++++------- gst/pnm/gstpnmutils.c | 45 ++++++++----------------- gst/pnm/gstpnmutils.h | 22 +++++++----- 5 files changed, 127 insertions(+), 67 deletions(-) diff --git a/gst/pnm/gstpnm.c b/gst/pnm/gstpnm.c index d40ce14e9..c2dc26866 100644 --- a/gst/pnm/gstpnm.c +++ b/gst/pnm/gstpnm.c @@ -57,16 +57,13 @@ gst_my_typefind_function (GstTypeFind * tf, gpointer d) return; case GST_PNM_INFO_MNGR_RESULT_FINISHED: switch (mngr.info.type) { - case GST_PNM_TYPE_BITMAP_ASCII: - case GST_PNM_TYPE_BITMAP_RAW: + case GST_PNM_TYPE_BITMAP: gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, BITMAP_CAPS); return; - case GST_PNM_TYPE_GRAYMAP_ASCII: - case GST_PNM_TYPE_GRAYMAP_RAW: + case GST_PNM_TYPE_GRAYMAP: gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, GRAYMAP_CAPS); return; - case GST_PNM_TYPE_PIXMAP_ASCII: - case GST_PNM_TYPE_PIXMAP_RAW: + case GST_PNM_TYPE_PIXMAP: gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, PIXMAP_CAPS); return; } diff --git a/gst/pnm/gstpnmdec.c b/gst/pnm/gstpnmdec.c index 4b6b15f04..bd28eaea7 100644 --- a/gst/pnm/gstpnmdec.c +++ b/gst/pnm/gstpnmdec.c @@ -68,8 +68,7 @@ gst_pnmdec_push (GstPnmdec * s, GstPad * src, GstBuffer * buf) GstBuffer *obuf; guint i; - if (s->mngr.info.type == GST_PNM_TYPE_PIXMAP_RAW || - s->mngr.info.type == GST_PNM_TYPE_PIXMAP_ASCII) { + if (s->mngr.info.type == GST_PNM_TYPE_PIXMAP) { i_rowstride = 3 * s->mngr.info.width; o_rowstride = GST_ROUND_UP_4 (i_rowstride); } else { @@ -115,17 +114,25 @@ gst_pnmdec_chain (GstPad * pad, GstBuffer * data) goto out; case GST_PNM_INFO_MNGR_RESULT_FINISHED: offset = s->mngr.data_offset; + if (s->mngr.info.encoding == GST_PNM_ENCODING_ASCII) { + GST_DEBUG_OBJECT (s, "FIXME: ASCII encoding not implemented!"); + gst_buffer_unref (data); + r = GST_FLOW_ERROR; + goto out; + } caps = gst_caps_copy (gst_pad_get_pad_template_caps (src)); switch (s->mngr.info.type) { - case GST_PNM_TYPE_BITMAP_RAW: - case GST_PNM_TYPE_BITMAP_ASCII: - case GST_PNM_TYPE_GRAYMAP_RAW: - case GST_PNM_TYPE_GRAYMAP_ASCII: + case GST_PNM_TYPE_BITMAP: + GST_DEBUG_OBJECT (s, "FIXME: BITMAP format not implemented!"); + gst_caps_unref (caps); + gst_buffer_unref (data); + r = GST_FLOW_ERROR; + goto out; + case GST_PNM_TYPE_GRAYMAP: gst_caps_remove_structure (caps, 0); s->size = s->mngr.info.width * s->mngr.info.height * 1; break; - case GST_PNM_TYPE_PIXMAP_RAW: - case GST_PNM_TYPE_PIXMAP_ASCII: + case GST_PNM_TYPE_PIXMAP: gst_caps_remove_structure (caps, 1); s->size = s->mngr.info.width * s->mngr.info.height * 3; break; @@ -136,6 +143,7 @@ gst_pnmdec_chain (GstPad * pad, GstBuffer * data) GST_TYPE_FRACTION, 0, 1, NULL); if (!gst_pad_set_caps (src, caps)) { gst_caps_unref (caps); + gst_buffer_unref (data); r = GST_FLOW_ERROR; goto out; } @@ -144,6 +152,7 @@ gst_pnmdec_chain (GstPad * pad, GstBuffer * data) } if (offset == GST_BUFFER_SIZE (data)) { + gst_buffer_unref (data); r = GST_FLOW_OK; goto out; } diff --git a/gst/pnm/gstpnmenc.c b/gst/pnm/gstpnmenc.c index 3a9a98a84..ae2395f3b 100644 --- a/gst/pnm/gstpnmenc.c +++ b/gst/pnm/gstpnmenc.c @@ -19,13 +19,15 @@ /** * SECTION:element-pnmenc * - * Encodes pnm images. + * Encodes pnm images. This plugin supports both raw and ASCII encoding. + * To enable ASCII encoding, set the parameter ascii to TRUE. If you omit + * the parameter or set it to FALSE, the output will be raw encoded. * * * Example launch line * |[ - * gst-launch videotestsrc num_buffers=1 ! pnmenc ! ffmpegcolorspace ! "video/x-raw-gray" ! pnmenc ! filesink location=test.pnm - * ]| The above pipeline writes a test pnm file. + * gst-launch videotestsrc num_buffers=1 ! ffmpegcolorspace ! "video/x-raw-gray" ! pnmenc ascii=true ! filesink location=test.pnm + * ]| The above pipeline writes a test pnm file (ASCII encoding). * */ @@ -41,6 +43,13 @@ #include +enum +{ + GST_PNMENC_PROP_0, + GST_PNMENC_PROP_ASCII + /* Add here. */ +}; + static GstElementDetails pnmenc_details = GST_ELEMENT_DETAILS ("PNM converter", "Codec/Encoder/Image", "Encodes in PNM format", @@ -57,6 +66,42 @@ static GstStaticPadTemplate src_pad_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS (MIME_ALL)); +static void +gst_pnmenc_set_property (GObject * object, guint prop_id, const GValue * value, + GParamSpec * pspec) +{ + GstPnmenc *s = GST_PNMENC (object); + + switch (prop_id) { + case GST_PNMENC_PROP_ASCII: + if (g_value_get_boolean (value)) + s->info.encoding = GST_PNM_ENCODING_ASCII; + else + s->info.encoding = GST_PNM_ENCODING_RAW; + s->info.fields |= GST_PNM_INFO_FIELDS_ENCODING; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_pnmenc_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstPnmenc *s = GST_PNMENC (object); + + switch (prop_id) { + case GST_PNMENC_PROP_ASCII: + g_value_set_boolean (value, s->info.encoding == GST_PNM_ENCODING_ASCII); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static GstFlowReturn gst_pnmenc_chain (GstPad * pad, GstBuffer * buf) { @@ -65,14 +110,10 @@ gst_pnmenc_chain (GstPad * pad, GstBuffer * buf) gchar *header; GstBuffer *out; - if (s->info.fields != GST_PNM_INFO_FIELDS_ALL) { - r = GST_FLOW_NOT_NEGOTIATED; - goto out; - } - /* Assumption: One buffer, one image. That is, always first write header. */ header = g_strdup_printf ("P%i\n%i %i\n%i\n", - s->info.type, s->info.width, s->info.height, s->info.max); + s->info.type + 3 * (1 - s->info.encoding), s->info.width, s->info.height, + s->info.max); out = gst_buffer_new (); gst_buffer_set_data (out, (guchar *) header, strlen (header)); gst_buffer_set_caps (out, GST_PAD_CAPS (s->src)); @@ -86,7 +127,7 @@ gst_pnmenc_chain (GstPad * pad, GstBuffer * buf) GstBuffer *obuf; guint i; - if (s->info.type == GST_PNM_TYPE_PIXMAP_RAW) { + if (s->info.type == GST_PNM_TYPE_PIXMAP) { o_rowstride = 3 * s->info.width; i_rowstride = GST_ROUND_UP_4 (o_rowstride); } else { @@ -104,6 +145,25 @@ gst_pnmenc_chain (GstPad * pad, GstBuffer * buf) /* Pass through the data. */ buf = gst_buffer_make_metadata_writable (buf); } + + /* We might need to convert to ASCII... */ + if (s->info.encoding == GST_PNM_ENCODING_ASCII) { + GstBuffer *obuf; + guint i, o; + + obuf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) * (4 + 1 / 20.)); + for (i = o = 0; i < GST_BUFFER_SIZE (buf); i++) { + g_snprintf ((char *) GST_BUFFER_DATA (obuf) + o, 4, "%3i", + GST_BUFFER_DATA (buf)[i]); + o += 3; + GST_BUFFER_DATA (obuf)[o++] = ' '; + if (!(i % 20)) + GST_BUFFER_DATA (obuf)[o++] = '\n'; + } + gst_buffer_unref (buf); + buf = obuf; + } + gst_buffer_set_caps (buf, GST_PAD_CAPS (s->src)); r = gst_pad_push (s->src, buf); @@ -127,10 +187,10 @@ gst_pnmenc_setcaps_func_sink (GstPad * pad, GstCaps * caps) /* Set caps on the source. */ if (!strcmp (mime, "video/x-raw-rgb")) { - s->info.type = GST_PNM_TYPE_PIXMAP_RAW; + s->info.type = GST_PNM_TYPE_PIXMAP; srccaps = gst_caps_from_string (MIME_PM); } else if (!strcmp (mime, "video/x-raw-gray")) { - s->info.type = GST_PNM_TYPE_GRAYMAP_RAW; + s->info.type = GST_PNM_TYPE_GRAYMAP; srccaps = gst_caps_from_string (MIME_GM); } else { r = FALSE; @@ -187,7 +247,14 @@ gst_pnmenc_base_init (gpointer g_class) static void gst_pnmenc_class_init (GstPnmencClass * klass) { - /* Nothing to see here. Move along. */ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = gst_pnmenc_set_property; + gobject_class->get_property = gst_pnmenc_get_property; + + g_object_class_install_property (gobject_class, GST_PNMENC_PROP_ASCII, + g_param_spec_boolean ("ascii", "ASCII Encoding", "The output will be " + "ASCII encoded", FALSE, G_PARAM_READWRITE)); } GST_BOILERPLATE (GstPnmenc, gst_pnmenc, GstElement, GST_TYPE_ELEMENT) diff --git a/gst/pnm/gstpnmutils.c b/gst/pnm/gstpnmutils.c index a0c8f384c..2773430a9 100644 --- a/gst/pnm/gstpnmutils.c +++ b/gst/pnm/gstpnmutils.c @@ -94,27 +94,34 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf, case GST_PNM_INFO_MNGR_STATE_DATA_TYPE: switch (buf[i++]) { case '1': - mngr->info.type = GST_PNM_TYPE_BITMAP_ASCII; + mngr->info.type = GST_PNM_TYPE_BITMAP; + mngr->info.encoding = GST_PNM_ENCODING_ASCII; break; case '2': - mngr->info.type = GST_PNM_TYPE_GRAYMAP_ASCII; + mngr->info.type = GST_PNM_TYPE_GRAYMAP; + mngr->info.encoding = GST_PNM_ENCODING_ASCII; break; case '3': - mngr->info.type = GST_PNM_TYPE_PIXMAP_ASCII; + mngr->info.type = GST_PNM_TYPE_PIXMAP; + mngr->info.encoding = GST_PNM_ENCODING_ASCII; break; case '4': - mngr->info.type = GST_PNM_TYPE_BITMAP_RAW; + mngr->info.type = GST_PNM_TYPE_BITMAP; + mngr->info.encoding = GST_PNM_ENCODING_RAW; break; case '5': - mngr->info.type = GST_PNM_TYPE_GRAYMAP_RAW; + mngr->info.type = GST_PNM_TYPE_GRAYMAP; + mngr->info.encoding = GST_PNM_ENCODING_RAW; break; case '6': - mngr->info.type = GST_PNM_TYPE_PIXMAP_RAW; + mngr->info.type = GST_PNM_TYPE_PIXMAP; + mngr->info.encoding = GST_PNM_ENCODING_RAW; break; default: return GST_PNM_INFO_MNGR_RESULT_FAILED; } - mngr->info.fields |= GST_PNM_INFO_FIELDS_TYPE; + mngr->info.fields |= + GST_PNM_INFO_FIELDS_TYPE | GST_PNM_INFO_FIELDS_ENCODING; mngr->state = GST_PNM_INFO_MNGR_STATE_WHITE_SPACE; if (i == buf_len) return GST_PNM_INFO_MNGR_RESULT_READING; @@ -177,27 +184,3 @@ gst_pnm_info_mngr_scan (GstPnmInfoMngr * mngr, const guint8 * buf, } return GST_PNM_INFO_MNGR_RESULT_FAILED; } - -GType -gst_pnm_type_get_type (void) -{ - static GType etype = 0; - - if (etype == 0) { - static const GEnumValue values[] = { - {GST_PNM_TYPE_BITMAP_RAW, "GST_PNM_TYPE_BITMAP_RAW", MIME_BM " (ascii)"}, - {GST_PNM_TYPE_GRAYMAP_ASCII, "GST_PNM_TYPE_BITMAP_ASCII", - MIME_BM " (raw)"}, - {GST_PNM_TYPE_GRAYMAP_RAW, "GST_PNM_TYPE_GRAYMAP_RAW", - MIME_GM " (ascii)"}, - {GST_PNM_TYPE_GRAYMAP_ASCII, "GST_PNM_TYPE_GRAYMAP_ASCII", - MIME_GM " (raw)"}, - {GST_PNM_TYPE_PIXMAP_RAW, "GST_PNM_TYPE_PIXMAP_RAW", MIME_PM " (ascii)"}, - {GST_PNM_TYPE_PIXMAP_ASCII, "GST_PNM_TYPE_PIXMAP_ASCII", - MIME_PM " (raw)"}, - {0, NULL, NULL} - }; - etype = g_enum_register_static ("GstPnmdecType", values); - } - return etype; -} diff --git a/gst/pnm/gstpnmutils.h b/gst/pnm/gstpnmutils.h index b0afb5fc2..75b3caa96 100644 --- a/gst/pnm/gstpnmutils.h +++ b/gst/pnm/gstpnmutils.h @@ -33,26 +33,30 @@ typedef enum GST_PNM_INFO_FIELDS_TYPE = 1 << 0, GST_PNM_INFO_FIELDS_WIDTH = 1 << 1, GST_PNM_INFO_FIELDS_HEIGHT = 1 << 2, - GST_PNM_INFO_FIELDS_MAX = 1 << 3 + GST_PNM_INFO_FIELDS_MAX = 1 << 3, + GST_PNM_INFO_FIELDS_ENCODING = 1 << 4 } GstPnmInfoFields; -#define GST_PNM_INFO_FIELDS_ALL (GST_PNM_INFO_FIELDS_TYPE | GST_PNM_INFO_FIELDS_WIDTH | GST_PNM_INFO_FIELDS_HEIGHT | GST_PNM_INFO_FIELDS_MAX) +#define GST_PNM_INFO_FIELDS_ALL (GST_PNM_INFO_FIELDS_TYPE | GST_PNM_INFO_FIELDS_WIDTH | GST_PNM_INFO_FIELDS_HEIGHT | GST_PNM_INFO_FIELDS_MAX | GST_PNM_INFO_FIELDS_ENCODING) typedef enum { - GST_PNM_TYPE_BITMAP_ASCII = 1, - GST_PNM_TYPE_GRAYMAP_ASCII = 2, - GST_PNM_TYPE_PIXMAP_ASCII = 3, - GST_PNM_TYPE_BITMAP_RAW = 4, - GST_PNM_TYPE_GRAYMAP_RAW = 5, - GST_PNM_TYPE_PIXMAP_RAW = 6 + GST_PNM_TYPE_BITMAP = 1, + GST_PNM_TYPE_GRAYMAP = 2, + GST_PNM_TYPE_PIXMAP = 3 } GstPnmType; -GType gst_pnm_type_get_type (void); + +typedef enum +{ + GST_PNM_ENCODING_RAW = 0, + GST_PNM_ENCODING_ASCII = 1 +} GstPnmEncoding; typedef struct { GstPnmInfoFields fields; GstPnmType type; + GstPnmEncoding encoding; guint width, height, max; } GstPnmInfo; -- cgit v1.2.3