diff options
Diffstat (limited to 'ext/metadata')
-rw-r--r-- | ext/metadata/Makefile.am | 9 | ||||
-rw-r--r-- | ext/metadata/TODO | 10 | ||||
-rw-r--r-- | ext/metadata/gstmetadata.c | 6 | ||||
-rw-r--r-- | ext/metadata/gstmetadatacommon.c | 631 | ||||
-rw-r--r-- | ext/metadata/gstmetadatacommon.h | 96 | ||||
-rw-r--r-- | ext/metadata/gstmetadatademux.c (renamed from ext/metadata/gstmetadataparse.c) | 890 | ||||
-rw-r--r-- | ext/metadata/gstmetadatademux.h (renamed from ext/metadata/gstmetadataparse.h) | 54 | ||||
-rw-r--r-- | ext/metadata/gstmetadatamux.c | 759 | ||||
-rw-r--r-- | ext/metadata/gstmetadatamux.h | 16 | ||||
-rw-r--r-- | ext/metadata/metadataexif.c | 273 | ||||
-rw-r--r-- | ext/metadata/metadatatags.c | 106 | ||||
-rw-r--r-- | ext/metadata/test/metadata_editor.c | 64 |
12 files changed, 1294 insertions, 1620 deletions
diff --git a/ext/metadata/Makefile.am b/ext/metadata/Makefile.am index 753aceff..aa6fac48 100644 --- a/ext/metadata/Makefile.am +++ b/ext/metadata/Makefile.am @@ -1,7 +1,8 @@ plugin_LTLIBRARIES = libgstmetadata.la libgstmetadata_la_SOURCES = gstmetadata.c \ - gstmetadataparse.c \ + gstmetadatacommon.c \ + gstmetadatademux.c \ metadata.c \ metadataparsejpeg.c \ metadatamuxjpeg.c \ @@ -15,11 +16,15 @@ libgstmetadata_la_SOURCES = gstmetadata.c \ gstmetadatamux.c \ metadatatags.c +libgstmetadata_ladir = $(includedir)/gstreamer-@GST_MAJORMINOR@/metadata +libgstmetadata_la_HEADERS = metadatatags.h + libgstmetadata_la_CFLAGS = $(METADATA_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) libgstmetadata_la_LIBADD = $(METADATA_LIBS) -lgsttag-@GST_MAJORMINOR@ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) libgstmetadata_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = gstmetadataparse.h \ +noinst_HEADERS = gstmetadatademux.h \ + gstmetadatacommon.h \ metadata.h \ metadataparsejpeg.h \ metadatamuxjpeg.h \ diff --git a/ext/metadata/TODO b/ext/metadata/TODO index 8b51c871..d44c2f33 100644 --- a/ext/metadata/TODO +++ b/ext/metadata/TODO @@ -4,10 +4,9 @@ This file contains a list of things to be done as well some open issues (questio TODO: 1- Add individual tags IPTC and XMP (and more for EXIF) -2- Use GST_TYPE_FRACTION for Rational and SRational (metadataexif.c) -3- Get properties like 'width' and 'height' from caps -4- Review the code (in order to move to gst-plugins-good) -5- Document how the plugin works (atchitecture and interaction beteween modules) +2- Get properties like 'width' and 'height' from caps +3- Review the code (in order to move to gst-plugins-good) +4- Document how the plugin works (atchitecture and interaction beteween modules) OPEN ISSUES: @@ -15,4 +14,7 @@ OPEN ISSUES: 2- How to change metadata when the orignal image was modified. ex: file.jpeg has XMP, then we do filesrc ! metadataparse ! jpegdec ! pngenc ! metadatamux ! files is the metadata still valid? which fields are no valid anymore? +3- Add GST_TYPE_FRACTION support for GStreamer TAGS +4- Have parse, demux and mux? (or just demux and must) see issue (5) +5- After decided issue (4) put more things to gstmetadatacommon (or else create a Class) diff --git a/ext/metadata/gstmetadata.c b/ext/metadata/gstmetadata.c index 4b150a26..2e729252 100644 --- a/ext/metadata/gstmetadata.c +++ b/ext/metadata/gstmetadata.c @@ -49,7 +49,7 @@ #include "metadatatags.h" -extern gboolean gst_metadata_parse_plugin_init (GstPlugin * plugin); +extern gboolean gst_metadata_demux_plugin_init (GstPlugin * plugin); extern gboolean gst_metadata_mux_plugin_init (GstPlugin * plugin); GST_DEBUG_CATEGORY_EXTERN (gst_metadata_exif_debug); @@ -71,7 +71,7 @@ plugin_init (GstPlugin * plugin) metadata_tags_register (); - ret = gst_metadata_parse_plugin_init (plugin); + ret = gst_metadata_demux_plugin_init (plugin); ret = ret && gst_metadata_mux_plugin_init (plugin); @@ -82,5 +82,5 @@ plugin_init (GstPlugin * plugin) GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "metadata", - "Metadata (EXIF, IPTC and XMP) image (JPEG, TIFF) parser and muxer", + "Metadata (EXIF, IPTC and XMP) image (JPEG, TIFF) demuxer and muxer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/ext/metadata/gstmetadatacommon.c b/ext/metadata/gstmetadatacommon.c new file mode 100644 index 00000000..07704ce4 --- /dev/null +++ b/ext/metadata/gstmetadatacommon.c @@ -0,0 +1,631 @@ +/* + * GStreamer + * Copyright 2007 Edgard Lima <edgard.lima@indt.org.br> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:metadatamux-metadata + * + * <refsect2> + * <title>Example launch line</title> + * <para> + * <programlisting> + * gst-launch -v -m filesrc location=./test.jpeg ! metadatamux ! fakesink silent=TRUE + * </programlisting> + * </para> + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + +/* + * static functions declaration + */ + +#include "gstmetadatacommon.h" + +/* + * offset - offset of buffer in original stream + * size - size of buffer + * seg_offset - offset of segment in original stream + * seg_size - size of segment + * boffset - offset inside buffer where segment starts (-1 for no intersection) + * bsize - size of intersection + * seg_binter - if segment start inside buffer is zero. if segment start before + * buffer and intersect, it is the offset inside segment. + * + * ret: + * -1 - segment before buffer + * 0 - segment intersects + * 1 - segment after buffer + */ + +static int +gst_metadata_common_get_strip_seg (const gint64 offset, guint32 size, + const gint64 seg_offset, const guint32 seg_size, + gint64 * boffset, guint32 * bsize, guint32 * seg_binter) +{ + int ret = -1; + + *boffset = -1; + *bsize = 0; + *seg_binter = -1; + + /* all segment after buffer */ + if (seg_offset >= offset + size) { + ret = 1; + goto done; + } + + if (seg_offset < offset) { + /* segment start somewhere before buffer */ + + /* all segment before buffer */ + if (seg_offset + seg_size <= offset) { + ret = -1; + goto done; + } + + *seg_binter = offset - seg_offset; + *boffset = 0; + + /* FIXME : optimize to >= size -> = size */ + if (seg_offset + seg_size >= offset + size) { + /* segment cover all buffer */ + *bsize = size; + } else { + /* segment goes from start of buffer to somewhere before end */ + *bsize = seg_size - *seg_binter; + } + + ret = 0; + + } else { + /* segment start somewhere into buffer */ + + *boffset = seg_offset - offset; + *seg_binter = 0; + + if (seg_offset + seg_size <= offset + size) { + /* all segment into buffer */ + *bsize = seg_size; + } else { + *bsize = size - *boffset; + } + + ret = 0; + + } + +done: + + return ret; + +} + +/* + * extern functions declaration + */ + +void +gst_metadata_common_init (GstMetadataCommon * common, gboolean parse, + guint8 options) +{ + metadata_init (&common->metadata, parse, options); +} + +void +gst_metadata_common_dispose (GstMetadataCommon * common) +{ + if (common->append_buffer) { + gst_buffer_unref (common->append_buffer); + common->append_buffer = NULL; + } + metadata_dispose (&common->metadata); +} + +/* + +/* + * TRUE -> buffer striped or injeted + * FALSE -> buffer unmodified + */ + +gboolean +gst_metadata_common_strip_push_buffer (GstMetadataCommon * common, + gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf) +{ + MetadataChunk *strip = common->metadata.strip_chunks.chunk; + MetadataChunk *inject = common->metadata.inject_chunks.chunk; + const gsize strip_len = common->metadata.strip_chunks.len; + const gsize inject_len = common->metadata.inject_chunks.len; + + gboolean buffer_reallocated = FALSE; + + guint32 size_buf_in = GST_BUFFER_SIZE (*buf); + + gint64 *boffset_strip = NULL; + guint32 *bsize_strip = NULL; + guint32 *seg_binter_strip = NULL; + + int i, j; + gboolean need_free_strip = FALSE; + + guint32 striped_bytes = 0; + guint32 injected_bytes = 0; + + guint32 prepend_size = prepend && *prepend ? GST_BUFFER_SIZE (*prepend) : 0; + + if (inject_len) { + + for (i = 0; i < inject_len; ++i) { + int res; + + if (inject[i].offset_orig >= offset_orig) { + if (inject[i].offset_orig < offset_orig + size_buf_in) { + injected_bytes += inject[i].size; + } else { + /* segment is after size (segments are sorted) */ + break; + } + } + } + + } + + /* + * strip segments + */ + + if (strip_len == 0) + goto inject; + + if (G_UNLIKELY (strip_len > 16)) { + boffset_strip = g_new (gint64, strip_len); + bsize_strip = g_new (guint32, strip_len); + seg_binter_strip = g_new (guint32, strip_len); + need_free_strip = TRUE; + } else { + boffset_strip = g_alloca (sizeof (boffset_strip[0]) * strip_len); + bsize_strip = g_alloca (sizeof (bsize_strip[0]) * strip_len); + seg_binter_strip = g_alloca (sizeof (seg_binter_strip[0]) * strip_len); + } + + memset (bsize_strip, 0x00, sizeof (bsize_strip[0]) * strip_len); + + for (i = 0; i < strip_len; ++i) { + int res; + + res = gst_metadata_common_get_strip_seg (offset_orig, size_buf_in, + strip[i].offset_orig, strip[i].size, &boffset_strip[i], &bsize_strip[i], + &seg_binter_strip[i]); + + /* segment is after size (segments are sorted) */ + striped_bytes += bsize_strip[i]; + if (res > 0) { + break; + } + + } + + if (striped_bytes) { + + guint8 *data; + + if (!buffer_reallocated) { + buffer_reallocated = TRUE; + if (injected_bytes + prepend_size > striped_bytes) { + GstBuffer *new_buf = + gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes + + prepend_size - striped_bytes); + + memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf), + GST_BUFFER_SIZE (*buf)); + + gst_buffer_unref (*buf); + *buf = new_buf; + + } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) { + GstBuffer *new_buf = gst_buffer_copy (*buf); + + gst_buffer_unref (*buf); + *buf = new_buf; + GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY); + GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes; + } + } + + data = GST_BUFFER_DATA (*buf); + + striped_bytes = 0; + for (i = 0; i < strip_len; ++i) { + /* intersect */ + if (bsize_strip[i]) { + memmove (data + boffset_strip[i] - striped_bytes, + data + boffset_strip[i] + bsize_strip[i] - striped_bytes, + size_buf_in - boffset_strip[i] - bsize_strip[i]); + striped_bytes += bsize_strip[i]; + } + } + size_buf_in -= striped_bytes; + + } + +inject: + + /* + * inject segments + */ + + if (inject_len) { + + guint8 *data; + guint32 striped_so_far; + + if (!buffer_reallocated) { + buffer_reallocated = TRUE; + if (injected_bytes + prepend_size > striped_bytes) { + GstBuffer *new_buf = + gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes + + prepend_size - striped_bytes); + + memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf), + GST_BUFFER_SIZE (*buf)); + + gst_buffer_unref (*buf); + *buf = new_buf; + + } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) { + GstBuffer *new_buf = gst_buffer_copy (*buf); + + gst_buffer_unref (*buf); + *buf = new_buf; + GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY); + GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes; + } + } + + data = GST_BUFFER_DATA (*buf); + + injected_bytes = 0; + striped_so_far = 0; + j = 0; + for (i = 0; i < inject_len; ++i) { + int res; + + while (j < strip_len) { + if (strip[j].offset_orig < inject[i].offset_orig) + striped_so_far += bsize_strip[j++]; + else + break; + } + + if (inject[i].offset_orig >= offset_orig) { + if (inject[i].offset_orig < + offset_orig + size_buf_in + striped_bytes - injected_bytes) { + /* insert */ + guint32 buf_off = + inject[i].offset_orig - offset_orig - striped_so_far + + injected_bytes; + memmove (data + buf_off + inject[i].size, data + buf_off, + size_buf_in - buf_off); + memcpy (data + buf_off, inject[i].data, inject[i].size); + injected_bytes += inject[i].size; + size_buf_in += inject[i].size; + } else { + /* segment is after size (segments are sorted) */ + break; + } + } + } + + } + + +done: + + if (prepend_size) { + if (injected_bytes == 0 && striped_bytes == 0) { + GstBuffer *new_buf = + gst_buffer_new_and_alloc (size_buf_in + prepend_size); + + memcpy (GST_BUFFER_DATA (new_buf) + prepend_size, GST_BUFFER_DATA (*buf), + size_buf_in); + + gst_buffer_unref (*buf); + *buf = new_buf; + } else { + memmove (GST_BUFFER_DATA (*buf) + prepend_size, GST_BUFFER_DATA (*buf), + size_buf_in); + } + memcpy (GST_BUFFER_DATA (*buf), GST_BUFFER_DATA (*prepend), prepend_size); + gst_buffer_unref (*prepend); + *prepend = NULL; + } + + GST_BUFFER_SIZE (*buf) = size_buf_in + prepend_size; + + if (need_free_strip) { + g_free (boffset_strip); + g_free (bsize_strip); + g_free (seg_binter_strip); + } + + return injected_bytes || striped_bytes; + +} + +/* + * pos - position in stream striped + * orig_pos - position in original stream + * return TRUE - position in original buffer + * FALSE - position in inserted chunk + */ +gboolean +gst_metadata_common_translate_pos_to_orig (GstMetadataCommon * common, + gint64 pos, gint64 * orig_pos, GstBuffer ** buf) +{ + MetadataChunk *strip = common->metadata.strip_chunks.chunk; + MetadataChunk *inject = common->metadata.inject_chunks.chunk; + const gsize strip_len = common->metadata.strip_chunks.len; + const gsize inject_len = common->metadata.inject_chunks.len; + const gint64 duration_orig = common->duration_orig; + const gint64 duration = common->duration; + + int i; + gboolean ret = TRUE; + guint64 new_buf_size = 0; + guint64 injected_before = 0; + + if (G_UNLIKELY (pos == -1)) { + *orig_pos = -1; + return TRUE; + } else if (G_UNLIKELY (pos >= duration)) { + /* this should never happen */ + *orig_pos = duration_orig; + return TRUE; + } + + /* calculate for injected */ + + /* just calculate size */ + *orig_pos = pos; /* save pos */ + for (i = 0; i < inject_len; ++i) { + /* check if pos in inside chunk */ + if (inject[i].offset <= pos) { + if (pos < inject[i].offset + inject[i].size) { + /* orig pos points after insert chunk */ + new_buf_size += inject[i].size; + /* put pos after current chunk */ + pos = inject[i].offset + inject[i].size; + ret = FALSE; + } else { + /* in case pos is not inside a injected chunk */ + injected_before += inject[i].size; + } + } else { + break; + } + } + + /* alloc buffer and calcute original pos */ + if (buf && ret == FALSE) { + guint8 *data; + + if (*buf) + gst_buffer_unref (*buf); + *buf = gst_buffer_new_and_alloc (new_buf_size); + data = GST_BUFFER_DATA (*buf); + pos = *orig_pos; /* recover saved pos */ + for (i = 0; i < inject_len; ++i) { + if (inject[i].offset > pos) { + break; + } + if (inject[i].offset <= pos && pos < inject[i].offset + inject[i].size) { + memcpy (data, inject[i].data, inject[i].size); + data += inject[i].size; + pos = inject[i].offset + inject[i].size; + /* out position after insert chunk orig */ + *orig_pos = inject[i].offset_orig + inject[i].size; + } + } + } + + if (ret == FALSE) { + /* if it inside a injected is already done */ + goto done; + } + + /* calculate for striped */ + + *orig_pos = pos - injected_before; + for (i = 0; i < strip_len; ++i) { + if (strip[i].offset_orig > pos) { + break; + } + *orig_pos += strip[i].size; + } + +done: + + if (G_UNLIKELY (*orig_pos >= duration_orig)) { + *orig_pos = duration_orig - 1; + } + + return ret; + +} + +/* + * return: + * -1 -> error + * 0 -> succeded + * 1 -> need more data + */ + +gboolean +gst_metadata_common_calculate_offsets (GstMetadataCommon * common) +{ + int i, j; + guint32 append_size; + guint32 bytes_striped, bytes_inject; + MetadataChunk *strip = common->metadata.strip_chunks.chunk; + MetadataChunk *inject = common->metadata.inject_chunks.chunk; + gsize strip_len; + gsize inject_len; + + if (common->state != MT_STATE_PARSED) + return FALSE; + + metadata_lazy_update (&common->metadata); + + strip_len = common->metadata.strip_chunks.len; + inject_len = common->metadata.inject_chunks.len; + + bytes_striped = 0; + bytes_inject = 0; + + /* calculate the new position off injected chunks */ + j = 0; + for (i = 0; i < inject_len; ++i) { + for (; j < strip_len; ++j) { + if (strip[j].offset_orig >= inject[i].offset_orig) { + break; + } + bytes_striped += strip[j].size; + } + inject[i].offset = inject[i].offset_orig - bytes_striped + bytes_inject; + bytes_inject += inject[i].size; + } + + /* calculate append (doesnt make much sense, but, anyway..) */ + append_size = 0; + for (i = inject_len - 1; i >= 0; --i) { + if (inject[i].offset_orig == common->duration_orig) + append_size += inject[i].size; + else + break; + } + if (append_size) { + guint8 *data; + + common->append_buffer = gst_buffer_new_and_alloc (append_size); + GST_BUFFER_FLAG_SET (common->append_buffer, GST_BUFFER_FLAG_READONLY); + data = GST_BUFFER_DATA (common->append_buffer); + for (i = inject_len - 1; i >= 0; --i) { + if (inject[i].offset_orig == common->duration_orig) { + memcpy (data, inject[i].data, inject[i].size); + data += inject[i].size; + } else { + break; + } + } + } + + if (common->duration_orig) { + common->duration = common->duration_orig; + for (i = 0; i < inject_len; ++i) { + common->duration += inject[i].size; + } + for (i = 0; i < strip_len; ++i) { + common->duration -= strip[i].size; + } + } + + return TRUE; + +} + +void +gst_metadata_common_update_segment_with_new_buffer (GstMetadataCommon * common, + guint8 ** buf, guint32 * size, MetadataChunkType type) +{ + int i; + MetadataChunk *inject = common->metadata.inject_chunks.chunk; + const gsize inject_len = common->metadata.inject_chunks.len; + + if (!(buf && size)) + goto done; + if (*buf == 0) + goto done; + if (*size == 0) + goto done; + + for (i = 0; i < inject_len; ++i) { + if (inject[i].type == type) { + inject[i].size = *size; + if (inject[i].data) + g_free (inject[i].data); + inject[i].data = *buf; + *size = 0; + *buf = 0; + break; + } + } + +done: + + return; + +} + +const gchar * +gst_metadata_common_get_type_name (int img_type) +{ + gchar *type_name = NULL; + + switch (img_type) { + case IMG_JPEG: + type_name = "jpeg"; + break; + case IMG_PNG: + type_name = "png"; + break; + default: + type_name = "invalid type"; + break; + } + return type_name; +} diff --git a/ext/metadata/gstmetadatacommon.h b/ext/metadata/gstmetadatacommon.h new file mode 100644 index 00000000..7f2169c0 --- /dev/null +++ b/ext/metadata/gstmetadatacommon.h @@ -0,0 +1,96 @@ +/* + * GStreamer + * Copyright 2007 Edgard Lima <edgard.lima@indt.org.br> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_METADATA_COMMON_H__ +#define __GST_METADATA_COMMON_H__ + +#include "metadata.h" + +G_BEGIN_DECLS + +typedef struct _GstMetadataCommon GstMetadataCommon; + +typedef enum _tag_MetadataState +{ + MT_STATE_NULL, /* still need to check media type */ + MT_STATE_PARSED +} MetadataState; + +struct _GstMetadataCommon { + + MetaData metadata; + gint64 duration_orig; /* durarion of stream */ + gint64 duration; /* durarion of modified stream */ + + GstBuffer * append_buffer; + MetadataState state; + +}; + +extern void +gst_metadata_common_init(GstMetadataCommon *common, gboolean parse, guint8 options); + +extern void +gst_metadata_common_dispose(GstMetadataCommon *common); + +extern gboolean +gst_metadata_common_strip_push_buffer (GstMetadataCommon *common, gint64 offset_orig, + GstBuffer ** prepend, GstBuffer ** buf); + +extern gboolean +gst_metadata_common_translate_pos_to_orig (GstMetadataCommon *common, + gint64 pos, gint64 * orig_pos, GstBuffer ** buf); + +extern gboolean +gst_metadata_common_calculate_offsets (GstMetadataCommon *common); + +extern void +gst_metadata_common_update_segment_with_new_buffer (GstMetadataCommon *common, + guint8 ** buf, guint32 * size, MetadataChunkType type); + +extern const gchar * +gst_metadata_common_get_type_name (int img_type); + +G_END_DECLS +#endif /* __GST_METADATA_COMMON_H__ */ diff --git a/ext/metadata/gstmetadataparse.c b/ext/metadata/gstmetadatademux.c index d95a9399..9e53be54 100644 --- a/ext/metadata/gstmetadataparse.c +++ b/ext/metadata/gstmetadatademux.c @@ -42,13 +42,13 @@ */ /** - * SECTION:metadataparse-metadata + * SECTION:metadatademux-metadata * * <refsect2> * <title>Example launch line</title> * <para> * <programlisting> - * gst-launch -v -m filesrc location=./test.jpeg ! metadataparse ! fakesink silent=TRUE + * gst-launch -v -m filesrc location=./test.jpeg ! metadatademux ! fakesink silent=TRUE * </programlisting> * </para> * </refsect2> @@ -60,7 +60,7 @@ #include <gst/gst.h> -#include "gstmetadataparse.h" +#include "gstmetadatademux.h" #include "metadataexif.h" @@ -70,8 +70,8 @@ #include <string.h> -GST_DEBUG_CATEGORY_STATIC (gst_metadata_parse_debug); -#define GST_CAT_DEFAULT gst_metadata_parse_debug +GST_DEBUG_CATEGORY_STATIC (gst_metadata_demux_debug); +#define GST_CAT_DEFAULT gst_metadata_demux_debug #define GOTO_DONE_IF_NULL(ptr) do { if ( NULL == (ptr) ) goto done; } while(FALSE) #define GOTO_DONE_IF_NULL_AND_FAIL(ptr, ret) do { if ( NULL == (ptr) ) { (ret) = FALSE; goto done; } } while(FALSE) @@ -107,83 +107,69 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", "image/png, " "tags-extracted = (bool) true") ); -GST_BOILERPLATE (GstMetadataParse, gst_metadata_parse, GstElement, +GST_BOILERPLATE (GstMetadataDemux, gst_metadata_demux, GstElement, GST_TYPE_ELEMENT); -static GstMetadataParseClass *metadata_parent_class = NULL; +static GstMetadataDemuxClass *metadata_parent_class = NULL; -static void gst_metadata_parse_dispose (GObject * object); +static void gst_metadata_demux_dispose (GObject * object); -static void gst_metadata_parse_finalize (GObject * object); +static void gst_metadata_demux_finalize (GObject * object); -static void gst_metadata_parse_set_property (GObject * object, guint prop_id, +static void gst_metadata_demux_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_metadata_parse_get_property (GObject * object, guint prop_id, +static void gst_metadata_demux_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static GstStateChangeReturn -gst_metadata_parse_change_state (GstElement * element, +gst_metadata_demux_change_state (GstElement * element, GstStateChange transition); -static GstCaps *gst_metadata_parse_get_caps (GstPad * pad); -static gboolean gst_metadata_parse_set_caps (GstPad * pad, GstCaps * caps); -static gboolean gst_metadata_parse_src_event (GstPad * pad, GstEvent * event); -static gboolean gst_metadata_parse_sink_event (GstPad * pad, GstEvent * event); +static GstCaps *gst_metadata_demux_get_caps (GstPad * pad); +static gboolean gst_metadata_demux_set_caps (GstPad * pad, GstCaps * caps); +static gboolean gst_metadata_demux_src_event (GstPad * pad, GstEvent * event); +static gboolean gst_metadata_demux_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_metadata_parse_chain (GstPad * pad, GstBuffer * buf); +static GstFlowReturn gst_metadata_demux_chain (GstPad * pad, GstBuffer * buf); -static gboolean gst_metadata_parse_checkgetrange (GstPad * srcpad); +static gboolean gst_metadata_demux_checkgetrange (GstPad * srcpad); static GstFlowReturn -gst_metadata_parse_get_range (GstPad * pad, guint64 offset_orig, guint size, +gst_metadata_demux_get_range (GstPad * pad, guint64 offset_orig, guint size, GstBuffer ** buf); -static gboolean gst_metadata_parse_sink_activate (GstPad * pad); +static gboolean gst_metadata_demux_sink_activate (GstPad * pad); static gboolean -gst_metadata_parse_src_activate_pull (GstPad * pad, gboolean active); +gst_metadata_demux_src_activate_pull (GstPad * pad, gboolean active); -static gboolean gst_metadata_parse_pull_range_parse (GstMetadataParse * filter); +static gboolean gst_metadata_demux_pull_range_demux (GstMetadataDemux * filter); -static void gst_metadata_parse_init_members (GstMetadataParse * filter); -static void gst_metadata_parse_dispose_members (GstMetadataParse * filter); +static void gst_metadata_demux_init_members (GstMetadataDemux * filter); +static void gst_metadata_demux_dispose_members (GstMetadataDemux * filter); static gboolean -gst_metadata_parse_configure_srccaps (GstMetadataParse * filter); -static gboolean gst_metadata_parse_configure_caps (GstMetadataParse * filter); - -static int -gst_metadata_parse_parse (GstMetadataParse * filter, const guint8 * buf, - guint32 size); - -static void gst_metadata_parse_send_tags (GstMetadataParse * filter); - +gst_metadata_demux_configure_srccaps (GstMetadataDemux * filter); +static gboolean gst_metadata_demux_configure_caps (GstMetadataDemux * filter); static int -gst_metadata_parse_get_strip_seg (const gint64 offset, guint32 size, - const gint64 seg_offset, const guint32 seg_size, - gint64 * boffset, guint32 * bsize, guint32 * seg_binter); - -static gboolean -gst_metadata_parse_strip_push_buffer (GstMetadataParse * filter, - gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf); +gst_metadata_demux_parse (GstMetadataDemux * filter, const guint8 * buf, + guint32 size); -static gboolean -gst_metadata_parse_translate_pos_to_orig (GstMetadataParse * filter, gint64 pos, - gint64 * orig_pos, GstBuffer ** buf); +static void gst_metadata_demux_send_tags (GstMetadataDemux * filter); -static const GstQueryType *gst_metadata_parse_get_query_types (GstPad * pad); +static const GstQueryType *gst_metadata_demux_get_query_types (GstPad * pad); -static gboolean gst_metadata_parse_src_query (GstPad * pad, GstQuery * query); +static gboolean gst_metadata_demux_src_query (GstPad * pad, GstQuery * query); static void -gst_metadata_parse_base_init (gpointer gclass) +gst_metadata_demux_base_init (gpointer gclass) { static GstElementDetails element_details = { - "Metadata parser", - "Parser/Extracter/Metadata", - "Send metadata tags (EXIF, IPTC and XMP) while passing throught the contents", + "Metadata demuxr", + "Demuxr/Extracter/Metadata", + "Send metadata tags (EXIF, IPTC and XMP) and remove metadata chunks from stream", "Edgard Lima <edgard.lima@indt.org.br>" }; GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); @@ -197,7 +183,7 @@ gst_metadata_parse_base_init (gpointer gclass) /* initialize the plugin's class */ static void -gst_metadata_parse_class_init (GstMetadataParseClass * klass) +gst_metadata_demux_class_init (GstMetadataDemuxClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; @@ -207,11 +193,11 @@ gst_metadata_parse_class_init (GstMetadataParseClass * klass) metadata_parent_class = g_type_class_peek_parent (klass); - gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_metadata_parse_dispose); - gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_metadata_parse_finalize); + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_metadata_demux_dispose); + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_metadata_demux_finalize); - gobject_class->set_property = gst_metadata_parse_set_property; - gobject_class->get_property = gst_metadata_parse_get_property; + gobject_class->set_property = gst_metadata_demux_set_property; + gobject_class->get_property = gst_metadata_demux_get_property; g_object_class_install_property (gobject_class, ARG_EXIF, g_param_spec_boolean ("exif", "EXIF", "Send EXIF metadata ?", @@ -225,7 +211,7 @@ gst_metadata_parse_class_init (GstMetadataParseClass * klass) g_param_spec_boolean ("xmp", "XMP", "Send XMP metadata ?", TRUE, G_PARAM_READWRITE)); - gstelement_class->change_state = gst_metadata_parse_change_state; + gstelement_class->change_state = gst_metadata_demux_change_state; } @@ -235,8 +221,8 @@ gst_metadata_parse_class_init (GstMetadataParseClass * klass) * initialize structure */ static void -gst_metadata_parse_init (GstMetadataParse * filter, - GstMetadataParseClass * gclass) +gst_metadata_demux_init (GstMetadataDemux * filter, + GstMetadataDemuxClass * gclass) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); @@ -246,14 +232,14 @@ gst_metadata_parse_init (GstMetadataParse * filter, gst_pad_new_from_template (gst_element_class_get_pad_template (klass, "sink"), "sink"); gst_pad_set_setcaps_function (filter->sinkpad, - GST_DEBUG_FUNCPTR (gst_metadata_parse_set_caps)); + GST_DEBUG_FUNCPTR (gst_metadata_demux_set_caps)); gst_pad_set_getcaps_function (filter->sinkpad, - GST_DEBUG_FUNCPTR (gst_metadata_parse_get_caps)); - gst_pad_set_event_function (filter->sinkpad, gst_metadata_parse_sink_event); + GST_DEBUG_FUNCPTR (gst_metadata_demux_get_caps)); + gst_pad_set_event_function (filter->sinkpad, gst_metadata_demux_sink_event); gst_pad_set_chain_function (filter->sinkpad, - GST_DEBUG_FUNCPTR (gst_metadata_parse_chain)); + GST_DEBUG_FUNCPTR (gst_metadata_demux_chain)); gst_pad_set_activate_function (filter->sinkpad, - gst_metadata_parse_sink_activate); + gst_metadata_demux_sink_activate); /* source pad */ @@ -261,20 +247,20 @@ gst_metadata_parse_init (GstMetadataParse * filter, gst_pad_new_from_template (gst_element_class_get_pad_template (klass, "src"), "src"); gst_pad_set_getcaps_function (filter->srcpad, - GST_DEBUG_FUNCPTR (gst_metadata_parse_get_caps)); - gst_pad_set_event_function (filter->srcpad, gst_metadata_parse_src_event); + GST_DEBUG_FUNCPTR (gst_metadata_demux_get_caps)); + gst_pad_set_event_function (filter->srcpad, gst_metadata_demux_src_event); gst_pad_set_query_function (filter->srcpad, - GST_DEBUG_FUNCPTR (gst_metadata_parse_src_query)); + GST_DEBUG_FUNCPTR (gst_metadata_demux_src_query)); gst_pad_set_query_type_function (filter->srcpad, - GST_DEBUG_FUNCPTR (gst_metadata_parse_get_query_types)); + GST_DEBUG_FUNCPTR (gst_metadata_demux_get_query_types)); gst_pad_use_fixed_caps (filter->srcpad); gst_pad_set_checkgetrange_function (filter->srcpad, - GST_DEBUG_FUNCPTR (gst_metadata_parse_checkgetrange)); - gst_pad_set_getrange_function (filter->srcpad, gst_metadata_parse_get_range); + GST_DEBUG_FUNCPTR (gst_metadata_demux_checkgetrange)); + gst_pad_set_getrange_function (filter->srcpad, gst_metadata_demux_get_range); gst_pad_set_activatepull_function (filter->srcpad, - GST_DEBUG_FUNCPTR (gst_metadata_parse_src_activate_pull)); + GST_DEBUG_FUNCPTR (gst_metadata_demux_src_activate_pull)); /* addind pads */ gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); @@ -285,15 +271,15 @@ gst_metadata_parse_init (GstMetadataParse * filter, filter->options = META_OPT_EXIF | META_OPT_IPTC | META_OPT_XMP; - gst_metadata_parse_init_members (filter); + gst_metadata_demux_init_members (filter); } static void -gst_metadata_parse_set_property (GObject * object, guint prop_id, +gst_metadata_demux_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstMetadataParse *filter = GST_METADATA_PARSE (object); + GstMetadataDemux *filter = GST_METADATA_DEMUX (object); switch (prop_id) { case ARG_EXIF: @@ -321,10 +307,10 @@ gst_metadata_parse_set_property (GObject * object, guint prop_id, } static void -gst_metadata_parse_get_property (GObject * object, guint prop_id, +gst_metadata_demux_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstMetadataParse *filter = GST_METADATA_PARSE (object); + GstMetadataDemux *filter = GST_METADATA_DEMUX (object); switch (prop_id) { case ARG_EXIF: @@ -345,14 +331,14 @@ gst_metadata_parse_get_property (GObject * object, guint prop_id, /* GstElement vmethod implementations */ static GstCaps * -gst_metadata_parse_get_caps (GstPad * pad) +gst_metadata_demux_get_caps (GstPad * pad) { - GstMetadataParse *filter = NULL; + GstMetadataDemux *filter = NULL; GstPad *otherpad; GstCaps *caps_new = NULL; GstCaps *caps_otherpad_peer = NULL; - filter = GST_METADATA_PARSE (gst_pad_get_parent (pad)); + filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad)); (filter->srcpad == pad) ? (otherpad = filter->sinkpad) : (otherpad = filter->srcpad); @@ -415,12 +401,12 @@ done: } static gboolean -gst_metadata_parse_src_event (GstPad * pad, GstEvent * event) +gst_metadata_demux_src_event (GstPad * pad, GstEvent * event) { - GstMetadataParse *filter = NULL; + GstMetadataDemux *filter = NULL; gboolean ret = FALSE; - filter = GST_METADATA_PARSE (gst_pad_get_parent (pad)); + filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: @@ -433,8 +419,8 @@ gst_metadata_parse_src_event (GstPad * pad, GstEvent * event) GstSeekType stop_type; gint64 stop; - /* we don't know where are the chunks to be stripped before parse */ - if (filter->state != MT_STATE_PARSED) + /* we don't know where are the chunks to be stripped before demux */ + if (filter->common.state != MT_STATE_PARSED) goto done; gst_event_parse_seek (event, &rate, &format, &flags, @@ -444,10 +430,10 @@ gst_metadata_parse_src_event (GstPad * pad, GstEvent * event) case GST_FORMAT_BYTES: break; case GST_FORMAT_PERCENT: - if (filter->duration < 0) + if (filter->common.duration < 0) goto done; - start = start * filter->duration / 100; - stop = stop * filter->duration / 100; + start = start * filter->common.duration / 100; + stop = stop * filter->common.duration / 100; break; default: goto done; @@ -457,9 +443,9 @@ gst_metadata_parse_src_event (GstPad * pad, GstEvent * event) if (start_type == GST_SEEK_TYPE_CUR) start = filter->offset + start; else if (start_type == GST_SEEK_TYPE_END) { - if (filter->duration < 0) + if (filter->common.duration < 0) goto done; - start = filter->duration + start; + start = filter->common.duration + start; } start_type == GST_SEEK_TYPE_SET; @@ -470,20 +456,21 @@ gst_metadata_parse_src_event (GstPad * pad, GstEvent * event) /* FIXME: related to append */ filter->offset = start; - gst_metadata_parse_translate_pos_to_orig (filter, start, &start, + gst_metadata_common_translate_pos_to_orig (&filter->common, start, &start, &filter->prepend_buffer); filter->offset_orig = start; if (stop_type == GST_SEEK_TYPE_CUR) stop = filter->offset + stop; else if (stop_type == GST_SEEK_TYPE_END) { - if (filter->duration < 0) + if (filter->common.duration < 0) goto done; - stop = filter->duration + stop; + stop = filter->common.duration + stop; } stop_type == GST_SEEK_TYPE_SET; - gst_metadata_parse_translate_pos_to_orig (filter, stop, &stop, NULL); + gst_metadata_common_translate_pos_to_orig (&filter->common, stop, &stop, + NULL); gst_event_unref (event); event = gst_event_new_seek (rate, format, flags, @@ -511,12 +498,12 @@ done: } static gboolean -gst_metadata_parse_sink_event (GstPad * pad, GstEvent * event) +gst_metadata_demux_sink_event (GstPad * pad, GstEvent * event) { - GstMetadataParse *filter = NULL; + GstMetadataDemux *filter = NULL; gboolean ret = FALSE; - filter = GST_METADATA_PARSE (gst_pad_get_parent (pad)); + filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: @@ -540,30 +527,29 @@ gst_metadata_parse_sink_event (GstPad * pad, GstEvent * event) } static void -gst_metadata_parse_dispose (GObject * object) +gst_metadata_demux_dispose (GObject * object) { - GstMetadataParse *filter = NULL; + GstMetadataDemux *filter = NULL; - filter = GST_METADATA_PARSE (object); + filter = GST_METADATA_DEMUX (object); - gst_metadata_parse_dispose_members (filter); + gst_metadata_demux_dispose_members (filter); metadataparse_xmp_dispose (); G_OBJECT_CLASS (metadata_parent_class)->dispose (object); - } static void -gst_metadata_parse_finalize (GObject * object) +gst_metadata_demux_finalize (GObject * object) { G_OBJECT_CLASS (metadata_parent_class)->finalize (object); } static void -gst_metadata_parse_dispose_members (GstMetadataParse * filter) +gst_metadata_demux_dispose_members (GstMetadataDemux * filter) { - metadata_dispose (&filter->parse_data); + gst_metadata_common_dispose (&filter->common); if (filter->adapter_parsing) { gst_object_unref (filter->adapter_parsing); @@ -575,11 +561,6 @@ gst_metadata_parse_dispose_members (GstMetadataParse * filter) filter->adapter_holding = NULL; } - if (filter->append_buffer) { - gst_buffer_unref (filter->append_buffer); - filter->append_buffer = NULL; - } - if (filter->prepend_buffer) { gst_buffer_unref (filter->prepend_buffer); filter->prepend_buffer = NULL; @@ -587,7 +568,7 @@ gst_metadata_parse_dispose_members (GstMetadataParse * filter) } static void -gst_metadata_parse_init_members (GstMetadataParse * filter) +gst_metadata_demux_init_members (GstMetadataDemux * filter) { filter->need_send_tag = FALSE; @@ -597,21 +578,17 @@ gst_metadata_parse_init_members (GstMetadataParse * filter) filter->next_size = 0; filter->img_type = IMG_NONE; filter->offset_orig = 0; - filter->duration_orig = 0; filter->offset = 0; - filter->duration = 0; - filter->state = MT_STATE_NULL; filter->need_more_data = FALSE; - filter->append_buffer = NULL; filter->prepend_buffer = NULL; - memset (&filter->parse_data, 0x00, sizeof (MetaData)); + memset (&filter->common, 0x00, sizeof (filter->common)); } static gboolean -gst_metadata_parse_configure_srccaps (GstMetadataParse * filter) +gst_metadata_demux_configure_srccaps (GstMetadataDemux * filter) { GstCaps *caps = NULL; gboolean ret = FALSE; @@ -647,7 +624,7 @@ done: } static gboolean -gst_metadata_parse_configure_caps (GstMetadataParse * filter) +gst_metadata_demux_configure_caps (GstMetadataDemux * filter) { GstCaps *caps = NULL; gboolean ret = FALSE; @@ -694,15 +671,15 @@ done: /* this function handles the link with other elements */ static gboolean -gst_metadata_parse_set_caps (GstPad * pad, GstCaps * caps) +gst_metadata_demux_set_caps (GstPad * pad, GstCaps * caps) { - GstMetadataParse *filter = NULL; + GstMetadataDemux *filter = NULL; GstStructure *structure = NULL; const gchar *mime = NULL; gboolean ret = FALSE; - gboolean parsed = TRUE; + gboolean demuxd = TRUE; - filter = GST_METADATA_PARSE (gst_pad_get_parent (pad)); + filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad)); structure = gst_caps_get_structure (caps, 0); @@ -717,14 +694,14 @@ gst_metadata_parse_set_caps (GstPad * pad, GstCaps * caps) goto done; } - if (gst_structure_get_boolean (structure, "tags-extracted", &parsed)) { - if (parsed == TRUE) { + if (gst_structure_get_boolean (structure, "tags-extracted", &demuxd)) { + if (demuxd == TRUE) { ret = FALSE; goto done; } } - ret = gst_metadata_parse_configure_srccaps (filter); + ret = gst_metadata_demux_configure_srccaps (filter); done: @@ -733,27 +710,8 @@ done: return ret; } -static const gchar * -gst_metadata_parse_get_type_name (int img_type) -{ - gchar *type_name = NULL; - - switch (img_type) { - case IMG_JPEG: - type_name = "jpeg"; - break; - case IMG_PNG: - type_name = "png"; - break; - default: - type_name = "invalid type"; - break; - } - return type_name; -} - static void -gst_metadata_parse_send_tags (GstMetadataParse * filter) +gst_metadata_demux_send_tags (GstMetadataDemux * filter) { GstMessage *msg; @@ -762,13 +720,13 @@ gst_metadata_parse_send_tags (GstMetadataParse * filter) if (filter->options & META_OPT_EXIF) metadataparse_exif_tag_list_add (taglist, GST_TAG_MERGE_KEEP, - filter->parse_data.exif_adapter, METADATA_TAG_MAP_WHOLECHUNK); + filter->common.metadata.exif_adapter, METADATA_TAG_MAP_WHOLECHUNK); if (filter->options & META_OPT_IPTC) metadataparse_iptc_tag_list_add (taglist, GST_TAG_MERGE_KEEP, - filter->parse_data.iptc_adapter, METADATA_TAG_MAP_WHOLECHUNK); + filter->common.metadata.iptc_adapter, METADATA_TAG_MAP_WHOLECHUNK); if (filter->options & META_OPT_XMP) metadataparse_xmp_tag_list_add (taglist, GST_TAG_MERGE_KEEP, - filter->parse_data.xmp_adapter, METADATA_TAG_MAP_WHOLECHUNK); + filter->common.metadata.xmp_adapter, METADATA_TAG_MAP_WHOLECHUNK); if (taglist && !gst_tag_list_is_empty (taglist)) { @@ -786,13 +744,13 @@ gst_metadata_parse_send_tags (GstMetadataParse * filter) if (filter->options & META_OPT_EXIF) metadataparse_exif_tag_list_add (taglist, GST_TAG_MERGE_KEEP, - filter->parse_data.exif_adapter, METADATA_TAG_MAP_INDIVIDUALS); + filter->common.metadata.exif_adapter, METADATA_TAG_MAP_INDIVIDUALS); if (filter->options & META_OPT_IPTC) metadataparse_iptc_tag_list_add (taglist, GST_TAG_MERGE_KEEP, - filter->parse_data.iptc_adapter, METADATA_TAG_MAP_INDIVIDUALS); + filter->common.metadata.iptc_adapter, METADATA_TAG_MAP_INDIVIDUALS); if (filter->options & META_OPT_XMP) metadataparse_xmp_tag_list_add (taglist, GST_TAG_MERGE_KEEP, - filter->parse_data.xmp_adapter, METADATA_TAG_MAP_INDIVIDUALS); + filter->common.metadata.xmp_adapter, METADATA_TAG_MAP_INDIVIDUALS); if (taglist && !gst_tag_list_is_empty (taglist)) { @@ -808,24 +766,24 @@ gst_metadata_parse_send_tags (GstMetadataParse * filter) } static const GstQueryType * -gst_metadata_parse_get_query_types (GstPad * pad) +gst_metadata_demux_get_query_types (GstPad * pad) { - static const GstQueryType gst_metadata_parse_src_query_types[] = { + static const GstQueryType gst_metadata_demux_src_query_types[] = { GST_QUERY_POSITION, GST_QUERY_DURATION, GST_QUERY_FORMATS, 0 }; - return gst_metadata_parse_src_query_types; + return gst_metadata_demux_src_query_types; } static gboolean -gst_metadata_parse_src_query (GstPad * pad, GstQuery * query) +gst_metadata_demux_src_query (GstPad * pad, GstQuery * query) { gboolean ret = FALSE; GstFormat format; - GstMetadataParse *filter = GST_METADATA_PARSE (gst_pad_get_parent (pad)); + GstMetadataDemux *filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad)); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_POSITION: @@ -837,14 +795,15 @@ gst_metadata_parse_src_query (GstPad * pad, GstQuery * query) } break; case GST_QUERY_DURATION: - if (filter->state != MT_STATE_PARSED) + if (filter->common.state != MT_STATE_PARSED) goto done; gst_query_parse_duration (query, &format, NULL); if (format == GST_FORMAT_BYTES) { - if (filter->duration >= 0) { - gst_query_set_duration (query, GST_FORMAT_BYTES, filter->duration); + if (filter->common.duration >= 0) { + gst_query_set_duration (query, GST_FORMAT_BYTES, + filter->common.duration); ret = TRUE; } } @@ -865,72 +824,6 @@ done: } -static void -gst_metadata_parse_calculate_offsets (GstMetadataParse * filter) -{ - int i, j; - guint32 append_size; - guint32 bytes_striped, bytes_inject; - MetadataChunk *strip = filter->parse_data.strip_chunks.chunk; - MetadataChunk *inject = filter->parse_data.inject_chunks.chunk; - const gsize strip_len = filter->parse_data.strip_chunks.len; - const gsize inject_len = filter->parse_data.inject_chunks.len; - - bytes_striped = 0; - bytes_inject = 0; - - /* calculate the new position off injected chunks */ - j = 0; - for (i = 0; i < inject_len; ++i) { - for (; j < strip_len; ++j) { - if (strip[j].offset_orig >= inject[i].offset_orig) { - break; - } - bytes_striped += strip[j].size; - } - inject[i].offset = inject[i].offset_orig - bytes_striped + bytes_inject; - bytes_inject += inject[i].size; - } - - /* calculate append (doesnt make much sense, but, anyway..) */ - append_size = 0; - for (i = inject_len - 1; i >= 0; --i) { - if (inject[i].offset_orig == filter->duration_orig) - append_size += inject[i].size; - else - break; - } - if (append_size) { - guint8 *data; - - filter->append_buffer = gst_buffer_new_and_alloc (append_size); - GST_BUFFER_FLAG_SET (filter->append_buffer, GST_BUFFER_FLAG_READONLY); - data = GST_BUFFER_DATA (filter->append_buffer); - for (i = inject_len - 1; i >= 0; --i) { - if (inject[i].offset_orig == filter->duration_orig) { - memcpy (data, inject[i].data, inject[i].size); - data += inject[i].size; - } else { - break; - } - } - } - - /* do nothing but just call for consistence */ - metadata_lazy_update (&filter->parse_data); - - if (filter->duration_orig) { - filter->duration = filter->duration_orig; - for (i = 0; i < inject_len; ++i) { - filter->duration += inject[i].size; - } - for (i = 0; i < strip_len; ++i) { - filter->duration -= strip[i].size; - } - } - -} - /* * Do parsing step-by-step and reconfigure caps if need * return: @@ -940,7 +833,7 @@ gst_metadata_parse_calculate_offsets (GstMetadataParse * filter) */ static int -gst_metadata_parse_parse (GstMetadataParse * filter, const guint8 * buf, +gst_metadata_demux_parse (GstMetadataDemux * filter, const guint8 * buf, guint32 size) { @@ -949,11 +842,11 @@ gst_metadata_parse_parse (GstMetadataParse * filter, const guint8 * buf, filter->next_offset = 0; filter->next_size = 0; - ret = metadata_parse (&filter->parse_data, buf, size, + ret = metadata_parse (&filter->common.metadata, buf, size, &filter->next_offset, &filter->next_size); if (ret == META_PARSING_ERROR) { - if (META_DATA_IMG_TYPE (filter->parse_data) == IMG_NONE) { + if (META_DATA_IMG_TYPE (filter->common.metadata) == IMG_NONE) { /* image type not recognized */ GST_ELEMENT_ERROR (filter, STREAM, TYPE_NOT_FOUND, (NULL), ("Only jpeg and png are supported")); @@ -962,20 +855,19 @@ gst_metadata_parse_parse (GstMetadataParse * filter, const guint8 * buf, } else if (ret == META_PARSING_NEED_MORE_DATA) { filter->need_more_data = TRUE; } else { - gst_metadata_parse_calculate_offsets (filter); - - filter->state = MT_STATE_PARSED; + filter->common.state = MT_STATE_PARSED; + gst_metadata_common_calculate_offsets (&filter->common); filter->need_more_data = FALSE; filter->need_send_tag = TRUE; } - /* reconfigure caps if it is different from type detected by 'metadata_parse' function */ - if (filter->img_type != META_DATA_IMG_TYPE (filter->parse_data)) { - filter->img_type = META_DATA_IMG_TYPE (filter->parse_data); - if (!gst_metadata_parse_configure_caps (filter)) { + /* reconfigure caps if it is different from type detected by 'metadata_demux' function */ + if (filter->img_type != META_DATA_IMG_TYPE (filter->common.metadata)) { + filter->img_type = META_DATA_IMG_TYPE (filter->common.metadata); + if (!gst_metadata_demux_configure_caps (filter)) { GST_ELEMENT_ERROR (filter, STREAM, FORMAT, (NULL), ("Couldn't reconfigure caps for %s", - gst_metadata_parse_get_type_name (filter->img_type))); + gst_metadata_common_get_type_name (filter->img_type))); ret = META_PARSING_ERROR; goto done; } @@ -992,23 +884,23 @@ done: */ /* FIXME */ -/* Current parse is just done before is pull mode could be activated */ -/* may be it is possible to parse in chain mode by doing some trick with gst-adapter */ +/* Current demux is just done before is pull mode could be activated */ +/* may be it is possible to demux in chain mode by doing some trick with gst-adapter */ /* the pipeline below would be a test for that case */ -/* gst-launch-0.10 filesrc location=Exif.jpg ! queue ! metadataparse ! filesink location=gen3.jpg */ +/* gst-launch-0.10 filesrc location=Exif.jpg ! queue ! metadatademux ! filesink location=gen3.jpg */ static GstFlowReturn -gst_metadata_parse_chain (GstPad * pad, GstBuffer * buf) +gst_metadata_demux_chain (GstPad * pad, GstBuffer * buf) { - GstMetadataParse *filter = NULL; + GstMetadataDemux *filter = NULL; GstFlowReturn ret = GST_FLOW_ERROR; guint32 buf_size = 0; guint32 new_buf_size = 0; gboolean append = FALSE; - filter = GST_METADATA_PARSE (gst_pad_get_parent (pad)); + filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad)); - if (filter->state != MT_STATE_PARSED) { + if (filter->common.state != MT_STATE_PARSED) { guint32 adpt_size = gst_adapter_available (filter->adapter_parsing); if (filter->next_offset) { @@ -1049,7 +941,7 @@ gst_metadata_parse_chain (GstPad * pad, GstBuffer * buf) const guint8 *new_buf = gst_adapter_peek (filter->adapter_parsing, adpt_size); - if (gst_metadata_parse_parse (filter, new_buf, + if (gst_metadata_demux_parse (filter, new_buf, adpt_size) == META_PARSING_ERROR) { ret = GST_FLOW_ERROR; goto done; @@ -1057,7 +949,7 @@ gst_metadata_parse_chain (GstPad * pad, GstBuffer * buf) } } - if (filter->state == MT_STATE_PARSED) { + if (filter->common.state == MT_STATE_PARSED) { if (filter->adapter_holding) { gst_adapter_push (filter->adapter_holding, buf); @@ -1068,15 +960,16 @@ gst_metadata_parse_chain (GstPad * pad, GstBuffer * buf) } if (filter->need_send_tag) { - gst_metadata_parse_send_tags (filter); + gst_metadata_demux_send_tags (filter); } - if (filter->offset_orig + GST_BUFFER_SIZE (buf) == filter->duration_orig) + if (filter->offset_orig + GST_BUFFER_SIZE (buf) == + filter->common.duration_orig) append = TRUE; buf_size = GST_BUFFER_SIZE (buf); - gst_metadata_parse_strip_push_buffer (filter, filter->offset_orig, + gst_metadata_common_strip_push_buffer (&filter->common, filter->offset_orig, &filter->prepend_buffer, &buf); if (buf) { /* may be all buffer has been striped */ @@ -1091,11 +984,11 @@ gst_metadata_parse_chain (GstPad * pad, GstBuffer * buf) ret = GST_FLOW_OK; } - if (append && filter->append_buffer) { - gst_buffer_set_caps (filter->append_buffer, + if (append && filter->common.append_buffer) { + gst_buffer_set_caps (filter->common.append_buffer, GST_PAD_CAPS (filter->srcpad)); - gst_buffer_ref (filter->append_buffer); - ret = gst_pad_push (filter->srcpad, filter->append_buffer); + gst_buffer_ref (filter->common.append_buffer); + ret = gst_pad_push (filter->srcpad, filter->common.append_buffer); if (ret != GST_FLOW_OK) goto done; } @@ -1104,7 +997,7 @@ gst_metadata_parse_chain (GstPad * pad, GstBuffer * buf) filter->offset += new_buf_size; } else { - /* just store while still not parsed */ + /* just store while still not demuxd */ if (!filter->adapter_holding) filter->adapter_holding = gst_adapter_new (); gst_adapter_push (filter->adapter_holding, buf); @@ -1128,7 +1021,7 @@ done: } static gboolean -gst_metadata_parse_pull_range_parse (GstMetadataParse * filter) +gst_metadata_demux_pull_range_demux (GstMetadataDemux * filter) { int res; @@ -1143,7 +1036,8 @@ gst_metadata_parse_pull_range_parse (GstMetadataParse * filter) ret = TRUE; goto done; } - filter->duration_orig = duration; + filter->common.duration_orig = duration; + if (format != GST_FORMAT_BYTES) { /* this should never happen, but try chain anyway */ ret = TRUE; @@ -1157,7 +1051,7 @@ gst_metadata_parse_pull_range_parse (GstMetadataParse * filter) offset += filter->next_offset; /* 'filter->next_size' only says the minimum required number of bytes. - We try provided more bytes (4096) just to avoid a lot of calls to 'metadata_parse' + We try provided more bytes (4096) just to avoid a lot of calls to 'metadata_demux' returning META_PARSING_NEED_MORE_DATA */ if (filter->next_size < 4096) { if (duration - offset < 4096) { @@ -1177,7 +1071,7 @@ gst_metadata_parse_pull_range_parse (GstMetadataParse * filter) } res = - gst_metadata_parse_parse (filter, GST_BUFFER_DATA (buf), + gst_metadata_demux_parse (filter, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); if (res == META_PARSING_ERROR) { ret = FALSE; @@ -1195,24 +1089,24 @@ done: } static gboolean -gst_metadata_parse_sink_activate (GstPad * pad) +gst_metadata_demux_sink_activate (GstPad * pad) { - GstMetadataParse *filter = NULL; + GstMetadataDemux *filter = NULL; gboolean ret = TRUE; - filter = GST_METADATA_PARSE (GST_PAD_PARENT (pad)); + filter = GST_METADATA_DEMUX (GST_PAD_PARENT (pad)); if (!gst_pad_check_pull_range (pad) || !gst_pad_activate_pull (filter->sinkpad, TRUE)) { - /* FIXME: currently it is not possible to parse in chain. Fail here ? */ + /* FIXME: currently it is not possible to demux in chain. Fail here ? */ /* nothing to be done by now, activate push mode */ return gst_pad_activate_push (pad, TRUE); } - /* try to parse */ - if (filter->state == MT_STATE_NULL) { - ret = gst_metadata_parse_pull_range_parse (filter); + /* try to demux */ + if (filter->common.state == MT_STATE_NULL) { + ret = gst_metadata_demux_pull_range_demux (filter); } done: @@ -1230,457 +1124,53 @@ done: } -/* - * offset - offset of buffer in original stream - * size - size of buffer - * seg_offset - offset of segment in original stream - * seg_size - size of segment - * boffset - offset inside buffer where segment starts (-1 for no intersection) - * bsize - size of intersection - * seg_binter - if segment start inside buffer is zero. if segment start before - * buffer and intersect, it is the offset inside segment. - * - * ret: - * -1 - segment before buffer - * 0 - segment intersects - * 1 - segment after buffer - */ - -static int -gst_metadata_parse_get_strip_seg (const gint64 offset, guint32 size, - const gint64 seg_offset, const guint32 seg_size, - gint64 * boffset, guint32 * bsize, guint32 * seg_binter) -{ - int ret = -1; - - *boffset = -1; - *bsize = 0; - *seg_binter = -1; - - /* all segment after buffer */ - if (seg_offset >= offset + size) { - ret = 1; - goto done; - } - - if (seg_offset < offset) { - /* segment start somewhere before buffer */ - - /* all segment before buffer */ - if (seg_offset + seg_size <= offset) { - ret = -1; - goto done; - } - - *seg_binter = offset - seg_offset; - *boffset = 0; - - /* FIXME : optimize to >= size -> = size */ - if (seg_offset + seg_size >= offset + size) { - /* segment cover all buffer */ - *bsize = size; - } else { - /* segment goes from start of buffer to somewhere before end */ - *bsize = seg_size - *seg_binter; - } - - ret = 0; - - } else { - /* segment start somewhere into buffer */ - - *boffset = seg_offset - offset; - *seg_binter = 0; - - if (seg_offset + seg_size <= offset + size) { - /* all segment into buffer */ - *bsize = seg_size; - } else { - *bsize = size - *boffset; - } - - ret = 0; - - } - -done: - - return ret; - -} - -/* - * TRUE -> buffer striped or injeted - * FALSE -> buffer unmodified - */ - -static gboolean -gst_metadata_parse_strip_push_buffer (GstMetadataParse * filter, - gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf) -{ - MetadataChunk *strip = filter->parse_data.strip_chunks.chunk; - MetadataChunk *inject = filter->parse_data.inject_chunks.chunk; - const gsize strip_len = filter->parse_data.strip_chunks.len; - const gsize inject_len = filter->parse_data.inject_chunks.len; - gboolean buffer_reallocated = FALSE; - - guint32 size_buf_in = GST_BUFFER_SIZE (*buf); - - gint64 *boffset_strip = NULL; - guint32 *bsize_strip = NULL; - guint32 *seg_binter_strip = NULL; - - int i, j; - gboolean need_free_strip = FALSE; - - guint32 striped_bytes = 0; - guint32 injected_bytes = 0; - - guint32 prepend_size = prepend && *prepend ? GST_BUFFER_SIZE (*prepend) : 0; - - if (inject_len) { - - for (i = 0; i < inject_len; ++i) { - int res; - - if (inject[i].offset_orig >= offset_orig) { - if (inject[i].offset_orig < offset_orig + size_buf_in) { - injected_bytes += inject[i].size; - } else { - /* segment is after size (segments are sorted) */ - break; - } - } - } - - } - - /* - * strip segments - */ - - if (strip_len == 0) - goto inject; - - if (G_UNLIKELY (strip_len > 16)) { - boffset_strip = g_new (gint64, strip_len); - bsize_strip = g_new (guint32, strip_len); - seg_binter_strip = g_new (guint32, strip_len); - need_free_strip = TRUE; - } else { - boffset_strip = g_alloca (sizeof (boffset_strip[0]) * strip_len); - bsize_strip = g_alloca (sizeof (bsize_strip[0]) * strip_len); - seg_binter_strip = g_alloca (sizeof (seg_binter_strip[0]) * strip_len); - } - - memset (bsize_strip, 0x00, sizeof (bsize_strip[0]) * strip_len); - - for (i = 0; i < strip_len; ++i) { - int res; - - res = gst_metadata_parse_get_strip_seg (offset_orig, size_buf_in, - strip[i].offset_orig, strip[i].size, &boffset_strip[i], &bsize_strip[i], - &seg_binter_strip[i]); - - /* segment is after size (segments are sorted) */ - striped_bytes += bsize_strip[i]; - if (res > 0) { - break; - } - - } - - if (striped_bytes) { - - guint8 *data; - - if (!buffer_reallocated) { - buffer_reallocated = TRUE; - if (injected_bytes + prepend_size > striped_bytes) { - GstBuffer *new_buf = - gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes + - prepend_size - striped_bytes); - - memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf), - GST_BUFFER_SIZE (*buf)); - - gst_buffer_unref (*buf); - *buf = new_buf; - - } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) { - GstBuffer *new_buf = gst_buffer_copy (*buf); - - gst_buffer_unref (*buf); - *buf = new_buf; - GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY); - GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes; - } - } - - data = GST_BUFFER_DATA (*buf); - - striped_bytes = 0; - for (i = 0; i < strip_len; ++i) { - /* intersect */ - if (bsize_strip[i]) { - memmove (data + boffset_strip[i] - striped_bytes, - data + boffset_strip[i] + bsize_strip[i] - striped_bytes, - size_buf_in - boffset_strip[i] - bsize_strip[i]); - striped_bytes += bsize_strip[i]; - } - } - size_buf_in -= striped_bytes; - - } - -inject: - - /* - * inject segments - */ - - if (inject_len) { - - guint8 *data; - guint32 striped_so_far; - - if (!buffer_reallocated) { - buffer_reallocated = TRUE; - if (injected_bytes + prepend_size > striped_bytes) { - GstBuffer *new_buf = - gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes + - prepend_size - striped_bytes); - - memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf), - GST_BUFFER_SIZE (*buf)); - - gst_buffer_unref (*buf); - *buf = new_buf; - - } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) { - GstBuffer *new_buf = gst_buffer_copy (*buf); - - gst_buffer_unref (*buf); - *buf = new_buf; - GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY); - GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes; - } - } - - data = GST_BUFFER_DATA (*buf); - - injected_bytes = 0; - striped_so_far = 0; - j = 0; - for (i = 0; i < inject_len; ++i) { - int res; - - while (j < strip_len) { - if (strip[j].offset_orig < inject[i].offset_orig) - striped_so_far += bsize_strip[j++]; - else - break; - } - - if (inject[i].offset_orig >= offset_orig) { - if (inject[i].offset_orig < - offset_orig + size_buf_in + striped_bytes - injected_bytes) { - /* insert */ - guint32 buf_off = - inject[i].offset_orig - offset_orig - striped_so_far + - injected_bytes; - memmove (data + buf_off + inject[i].size, data + buf_off, - size_buf_in - buf_off); - memcpy (data + buf_off, inject[i].data, inject[i].size); - injected_bytes += inject[i].size; - size_buf_in += inject[i].size; - } else { - /* segment is after size (segments are sorted) */ - break; - } - } - } - - } - - -done: - - if (prepend_size) { - if (injected_bytes == 0 && striped_bytes == 0) { - GstBuffer *new_buf = - gst_buffer_new_and_alloc (size_buf_in + prepend_size); - - memcpy (GST_BUFFER_DATA (new_buf) + prepend_size, GST_BUFFER_DATA (*buf), - size_buf_in); - - gst_buffer_unref (*buf); - *buf = new_buf; - } else { - memmove (GST_BUFFER_DATA (*buf) + prepend_size, GST_BUFFER_DATA (*buf), - size_buf_in); - } - memcpy (GST_BUFFER_DATA (*buf), GST_BUFFER_DATA (*prepend), prepend_size); - gst_buffer_unref (*prepend); - *prepend = NULL; - } - - GST_BUFFER_SIZE (*buf) = size_buf_in + prepend_size; - - if (need_free_strip) { - g_free (boffset_strip); - g_free (bsize_strip); - g_free (seg_binter_strip); - } - - return injected_bytes || striped_bytes; - -} - -/* - * pos - position in stream striped - * orig_pos - position in original stream - * return TRUE - position in original buffer - * FALSE - position in inserted chunk - */ -static gboolean -gst_metadata_parse_translate_pos_to_orig (GstMetadataParse * filter, gint64 pos, - gint64 * orig_pos, GstBuffer ** buf) -{ - int i; - MetadataChunk *strip = filter->parse_data.strip_chunks.chunk; - MetadataChunk *inject = filter->parse_data.inject_chunks.chunk; - const gsize strip_len = filter->parse_data.strip_chunks.len; - const gsize inject_len = filter->parse_data.inject_chunks.len; - gboolean ret = TRUE; - guint64 new_buf_size = 0; - guint64 injected_before = 0; - - if (G_UNLIKELY (pos == -1)) { - *orig_pos = -1; - return TRUE; - } else if (G_UNLIKELY (pos >= filter->duration)) { - /* this should never happen */ - *orig_pos = filter->duration_orig; - return TRUE; - } - - /* calculate for injected */ - - /* just calculate size */ - *orig_pos = pos; /* save pos */ - for (i = 0; i < inject_len; ++i) { - /* check if pos in inside chunk */ - if (inject[i].offset <= pos) { - if (pos < inject[i].offset + inject[i].size) { - /* orig pos points after insert chunk */ - new_buf_size += inject[i].size; - /* put pos after current chunk */ - pos = inject[i].offset + inject[i].size; - ret = FALSE; - } else { - /* in case pos is not inside a injected chunk */ - injected_before += inject[i].size; - } - } else { - break; - } - } - - /* alloc buffer and calcute original pos */ - if (buf && ret == FALSE) { - guint8 *data; - - if (*buf) - gst_buffer_unref (*buf); - *buf = gst_buffer_new_and_alloc (new_buf_size); - data = GST_BUFFER_DATA (*buf); - pos = *orig_pos; /* recover saved pos */ - for (i = 0; i < inject_len; ++i) { - if (inject[i].offset > pos) { - break; - } - if (inject[i].offset <= pos && pos < inject[i].offset + inject[i].size) { - memcpy (data, inject[i].data, inject[i].size); - data += inject[i].size; - pos = inject[i].offset + inject[i].size; - /* out position after insert chunk orig */ - *orig_pos = inject[i].offset_orig + inject[i].size; - } - } - } - - if (ret == FALSE) { - /* if it inside a injected is already done */ - goto done; - } - - /* calculate for striped */ - - *orig_pos = pos - injected_before; - for (i = 0; i < strip_len; ++i) { - if (strip[i].offset_orig > pos) { - break; - } - *orig_pos += strip[i].size; - } - -done: - - if (G_UNLIKELY (*orig_pos >= filter->duration_orig)) { - *orig_pos = filter->duration_orig - 1; - } - - return ret; - -} - static gboolean -gst_metadata_parse_checkgetrange (GstPad * srcpad) +gst_metadata_demux_checkgetrange (GstPad * srcpad) { - GstMetadataParse *filter = NULL; + GstMetadataDemux *filter = NULL; - filter = GST_METADATA_PARSE (GST_PAD_PARENT (srcpad)); + filter = GST_METADATA_DEMUX (GST_PAD_PARENT (srcpad)); return gst_pad_check_pull_range (filter->sinkpad); } static GstFlowReturn -gst_metadata_parse_get_range (GstPad * pad, +gst_metadata_demux_get_range (GstPad * pad, guint64 offset, guint size, GstBuffer ** buf) { - GstMetadataParse *filter = NULL; + GstMetadataDemux *filter = NULL; GstFlowReturn ret = GST_FLOW_OK; gint64 offset_orig = 0; guint size_orig; GstBuffer *prepend = NULL; gboolean need_append = FALSE; - filter = GST_METADATA_PARSE (GST_PAD_PARENT (pad)); + filter = GST_METADATA_DEMUX (GST_PAD_PARENT (pad)); - if (filter->state != MT_STATE_PARSED) { + if (filter->common.state != MT_STATE_PARSED) { ret = GST_FLOW_ERROR; goto done; } - if (offset + size > filter->duration) { - size = filter->duration - offset; + if (offset + size > filter->common.duration) { + size = filter->common.duration - offset; } size_orig = size; if (filter->need_send_tag) { - gst_metadata_parse_send_tags (filter); + gst_metadata_demux_send_tags (filter); } - gst_metadata_parse_translate_pos_to_orig (filter, offset, &offset_orig, - &prepend); + gst_metadata_common_translate_pos_to_orig (&filter->common, offset, + &offset_orig, &prepend); if (size > 1) { gint64 pos; pos = offset + size - 1; - gst_metadata_parse_translate_pos_to_orig (filter, pos, &pos, NULL); + gst_metadata_common_translate_pos_to_orig (&filter->common, pos, &pos, + NULL); size_orig = pos + 1 - offset_orig; } @@ -1689,7 +1179,8 @@ gst_metadata_parse_get_range (GstPad * pad, ret = gst_pad_pull_range (filter->sinkpad, offset_orig, size_orig, buf); if (ret == GST_FLOW_OK && *buf) { - gst_metadata_parse_strip_push_buffer (filter, offset_orig, &prepend, buf); + gst_metadata_common_strip_push_buffer (&filter->common, offset_orig, + &prepend, buf); if (GST_BUFFER_SIZE (*buf) < size) { /* need append */ @@ -1705,7 +1196,7 @@ done: if (need_append) { /* FIXME: together with SEEK and - * gst_metadata_parse_translate_pos_to_orig + * gst_metadata_common_translate_pos_to_orig * this way if chunk is added in the end we are in trolble * ...still not implemented 'cause it will not be the * case for the time being @@ -1717,17 +1208,17 @@ done: } static gboolean -gst_metadata_parse_src_activate_pull (GstPad * pad, gboolean active) +gst_metadata_demux_src_activate_pull (GstPad * pad, gboolean active) { - GstMetadataParse *filter = NULL; + GstMetadataDemux *filter = NULL; gboolean ret; - filter = GST_METADATA_PARSE (gst_pad_get_parent (pad)); + filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad)); ret = gst_pad_activate_pull (filter->sinkpad, active); - if (ret && filter->state == MT_STATE_NULL) { - ret = gst_metadata_parse_pull_range_parse (filter); + if (ret && filter->common.state == MT_STATE_NULL) { + ret = gst_metadata_demux_pull_range_demux (filter); } gst_object_unref (filter); @@ -1737,17 +1228,17 @@ gst_metadata_parse_src_activate_pull (GstPad * pad, gboolean active) static GstStateChangeReturn -gst_metadata_parse_change_state (GstElement * element, +gst_metadata_demux_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstMetadataParse *filter = GST_METADATA_PARSE (element); + GstMetadataDemux *filter = GST_METADATA_DEMUX (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: - gst_metadata_parse_init_members (filter); + gst_metadata_demux_init_members (filter); filter->adapter_parsing = gst_adapter_new (); - metadata_init (&filter->parse_data, TRUE, filter->options); + gst_metadata_common_init (&filter->common, TRUE, filter->options); break; default: break; @@ -1767,15 +1258,14 @@ gst_metadata_parse_change_state (GstElement * element, if (filter->adapter_holding) { gst_adapter_clear (filter->adapter_holding); } - if (filter->state != MT_STATE_PARSED) { - /* cleanup parser */ - /* FIXME: could be improved a bit to avoid mem allocation */ - metadata_dispose (&filter->parse_data); - metadata_init (&filter->parse_data, TRUE, filter->options); + if (filter->common.state != MT_STATE_PARSED) { + /* cleanup demuxr */ + gst_metadata_common_dispose (&filter->common); + gst_metadata_common_init (&filter->common, TRUE, filter->options); } break; case GST_STATE_CHANGE_READY_TO_NULL: - gst_metadata_parse_dispose_members (filter); + gst_metadata_demux_dispose_members (filter); break; default: break; @@ -1791,11 +1281,11 @@ done: */ gboolean -gst_metadata_parse_plugin_init (GstPlugin * plugin) +gst_metadata_demux_plugin_init (GstPlugin * plugin) { - GST_DEBUG_CATEGORY_INIT (gst_metadata_parse_debug, "metadataparse", 0, + GST_DEBUG_CATEGORY_INIT (gst_metadata_demux_debug, "metadatademux", 0, "Metadata demuxer"); - return gst_element_register (plugin, "metadataparse", - GST_RANK_PRIMARY + 1, GST_TYPE_METADATA_PARSE); + return gst_element_register (plugin, "metadatademux", + GST_RANK_PRIMARY + 1, GST_TYPE_METADATA_DEMUX); } diff --git a/ext/metadata/gstmetadataparse.h b/ext/metadata/gstmetadatademux.h index fa1c9b71..2170a871 100644 --- a/ext/metadata/gstmetadataparse.h +++ b/ext/metadata/gstmetadatademux.h @@ -41,45 +41,40 @@ * Boston, MA 02111-1307, USA. */ -#ifndef __GST_METADATA_PARSE_H__ -#define __GST_METADATA_PARSE_H__ +#ifndef __GST_METADATA_DEMUX_H__ +#define __GST_METADATA_DEMUX_H__ #include <gst/gst.h> -#include "metadata.h" +#include "gstmetadatacommon.h" G_BEGIN_DECLS /* #defines don't like whitespacey bits */ -#define GST_TYPE_METADATA_PARSE \ - (gst_metadata_parse_get_type()) -#define GST_METADATA_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_METADATA_PARSE,GstMetadataParse)) -#define GST_METADATA_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_METADATA_PARSE,GstMetadataParseClass)) -#define GST_IS_METADATA_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_METADATA_PARSE)) -#define GST_IS_METADATA_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_METADATA_PARSE)) -typedef struct _GstMetadataParse GstMetadataParse; -typedef struct _GstMetadataParseClass GstMetadataParseClass; - -typedef enum _tag_MetadataState -{ - MT_STATE_NULL, /* still need to check media type */ - MT_STATE_PARSED -} MetadataState; - -struct _GstMetadataParse +#define GST_TYPE_METADATA_DEMUX \ + (gst_metadata_demux_get_type()) +#define GST_METADATA_DEMUX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_METADATA_DEMUX,GstMetadataDemux)) +#define GST_METADATA_DEMUX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_METADATA_DEMUX,GstMetadataDemuxClass)) +#define GST_IS_METADATA_DEMUX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_METADATA_DEMUX)) +#define GST_IS_METADATA_DEMUX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_METADATA_DEMUX)) +typedef struct _GstMetadataDemux GstMetadataDemux; +typedef struct _GstMetadataDemuxClass GstMetadataDemuxClass; + +struct _GstMetadataDemux { GstElement element; GstPad *sinkpad, *srcpad; + GstMetadataCommon common; + guint8 options; gboolean need_send_tag; - MetaData parse_data; GstAdapter *adapter_parsing; GstAdapter *adapter_holding; guint32 next_offset; @@ -87,14 +82,9 @@ struct _GstMetadataParse ImageType img_type; gint64 offset_orig; /* offset in original stream */ - gint64 duration_orig; /* durarion of stream */ gint64 offset; /* offset in current stream */ - gint64 duration; /* durarion of modified stream */ - - MetadataState state; GstBuffer * prepend_buffer; - GstBuffer * append_buffer; gboolean need_more_data; @@ -102,12 +92,12 @@ struct _GstMetadataParse }; -struct _GstMetadataParseClass +struct _GstMetadataDemuxClass { GstElementClass parent_class; }; -extern GType gst_metadata_parse_get_type (void); +extern GType gst_metadata_demux_get_type (void); G_END_DECLS -#endif /* __GST_METADATA_PARSE_H__ */ +#endif /* __GST_METADATA_DEMUX_H__ */ diff --git a/ext/metadata/gstmetadatamux.c b/ext/metadata/gstmetadatamux.c index 5c1a3bed..f2c2a895 100644 --- a/ext/metadata/gstmetadatamux.c +++ b/ext/metadata/gstmetadatamux.c @@ -154,6 +154,7 @@ static void gst_metadata_mux_init_members (GstMetadataMux * filter); static void gst_metadata_mux_dispose_members (GstMetadataMux * filter); static gboolean gst_metadata_mux_configure_srccaps (GstMetadataMux * filter); + static gboolean gst_metadata_mux_configure_caps (GstMetadataMux * filter); static int @@ -162,25 +163,10 @@ gst_metadata_mux_parse (GstMetadataMux * filter, const guint8 * buf, static void gst_metadata_mux_create_chunks_from_tags (GstMetadataMux * filter); -static int -gst_metadata_mux_get_strip_seg (const gint64 offset, guint32 size, - const gint64 seg_offset, const guint32 seg_size, - gint64 * boffset, guint32 * bsize, guint32 * seg_binter); - -static gboolean -gst_metadata_mux_strip_push_buffer (GstMetadataMux * filter, - gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf); - -static gboolean -gst_metadata_mux_translate_pos_to_orig (GstMetadataMux * filter, gint64 pos, - gint64 * orig_pos, GstBuffer ** buf); - static const GstQueryType *gst_metadata_mux_get_query_types (GstPad * pad); static gboolean gst_metadata_mux_src_query (GstPad * pad, GstQuery * query); -static gboolean gst_metadata_mux_calculate_offsets (GstMetadataMux * filter); - static void gst_metadata_mux_base_init (gpointer gclass) { @@ -283,11 +269,11 @@ gst_metadata_mux_init (GstMetadataMux * filter, GstMetadataMuxClass * gclass) gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); - metadataparse_xmp_init (); /* init members */ filter->options = META_OPT_EXIF | META_OPT_IPTC | META_OPT_XMP; + gst_metadata_mux_init_members (filter); } @@ -415,6 +401,48 @@ done: } +static void +gst_metadata_create_chunks_from_tags (GstMetadataMux * filter) +{ + + GstMessage *msg; + GstTagSetter *setter = GST_TAG_SETTER (filter); + const GstTagList *taglist = gst_tag_setter_get_tag_list (setter); + GstEvent *event; + guint8 *buf = NULL; + guint32 size = 0; + + if (taglist) { + + if (filter->options & META_OPT_EXIF) { + metadatamux_exif_create_chunk_from_tag_list (&buf, &size, taglist); + gst_metadata_common_update_segment_with_new_buffer (&filter->common, &buf, + &size, MD_CHUNK_EXIF); + } + + if (filter->options & META_OPT_IPTC) { + metadatamux_iptc_create_chunk_from_tag_list (&buf, &size, taglist); + gst_metadata_common_update_segment_with_new_buffer (&filter->common, &buf, + &size, MD_CHUNK_IPTC); + } + + if (filter->options & META_OPT_XMP) { + metadatamux_xmp_create_chunk_from_tag_list (&buf, &size, taglist); + gst_metadata_common_update_segment_with_new_buffer (&filter->common, &buf, + &size, MD_CHUNK_XMP); + } + + } + + if (buf) { + g_free (buf); + } + + metadata_chunk_array_remove_zero_size (&filter->common.metadata. + inject_chunks); + +} + static gboolean gst_metadata_mux_src_event (GstPad * pad, GstEvent * event) { @@ -436,7 +464,10 @@ gst_metadata_mux_src_event (GstPad * pad, GstEvent * event) /* we don't know where are the chunks to be stripped before mux */ if (filter->need_calculate_offset) { - if (!gst_metadata_mux_calculate_offsets (filter)) + gst_metadata_create_chunks_from_tags (filter); + if (gst_metadata_common_calculate_offsets (&filter->common)) + filter->need_calculate_offset = FALSE; + else goto done; } @@ -447,10 +478,10 @@ gst_metadata_mux_src_event (GstPad * pad, GstEvent * event) case GST_FORMAT_BYTES: break; case GST_FORMAT_PERCENT: - if (filter->duration < 0) + if (filter->common.duration < 0) goto done; - start = start * filter->duration / 100; - stop = stop * filter->duration / 100; + start = start * filter->common.duration / 100; + stop = stop * filter->common.duration / 100; break; default: goto done; @@ -460,9 +491,9 @@ gst_metadata_mux_src_event (GstPad * pad, GstEvent * event) if (start_type == GST_SEEK_TYPE_CUR) start = filter->offset + start; else if (start_type == GST_SEEK_TYPE_END) { - if (filter->duration < 0) + if (filter->common.duration < 0) goto done; - start = filter->duration + start; + start = filter->common.duration + start; } start_type == GST_SEEK_TYPE_SET; @@ -473,20 +504,21 @@ gst_metadata_mux_src_event (GstPad * pad, GstEvent * event) /* FIXME: related to append */ filter->offset = start; - gst_metadata_mux_translate_pos_to_orig (filter, start, &start, + gst_metadata_common_translate_pos_to_orig (&filter->common, start, &start, &filter->prepend_buffer); filter->offset_orig = start; if (stop_type == GST_SEEK_TYPE_CUR) stop = filter->offset + stop; else if (stop_type == GST_SEEK_TYPE_END) { - if (filter->duration < 0) + if (filter->common.duration < 0) goto done; - stop = filter->duration + stop; + stop = filter->common.duration + stop; } stop_type == GST_SEEK_TYPE_SET; - gst_metadata_mux_translate_pos_to_orig (filter, stop, &stop, NULL); + gst_metadata_common_translate_pos_to_orig (&filter->common, stop, &stop, + NULL); gst_event_unref (event); event = gst_event_new_seek (rate, format, flags, @@ -573,7 +605,7 @@ gst_metadata_mux_finalize (GObject * object) static void gst_metadata_mux_dispose_members (GstMetadataMux * filter) { - metadata_dispose (&filter->mux_data); + gst_metadata_common_dispose (&filter->common); if (filter->adapter_parsing) { gst_object_unref (filter->adapter_parsing); @@ -585,11 +617,6 @@ gst_metadata_mux_dispose_members (GstMetadataMux * filter) filter->adapter_holding = NULL; } - if (filter->append_buffer) { - gst_buffer_unref (filter->append_buffer); - filter->append_buffer = NULL; - } - if (filter->prepend_buffer) { gst_buffer_unref (filter->prepend_buffer); filter->prepend_buffer = NULL; @@ -607,16 +634,12 @@ gst_metadata_mux_init_members (GstMetadataMux * filter) filter->next_size = 0; filter->img_type = IMG_NONE; filter->offset_orig = 0; - filter->duration_orig = 0; filter->offset = 0; - filter->duration = 0; - filter->state = MT_STATE_NULL; filter->need_more_data = FALSE; - filter->append_buffer = NULL; filter->prepend_buffer = NULL; - memset (&filter->mux_data, 0x00, sizeof (MetaData)); + memset (&filter->common, 0x00, sizeof (filter->common)); } @@ -742,96 +765,6 @@ done: return ret; } -static const gchar * -gst_metadata_mux_get_type_name (int img_type) -{ - gchar *type_name = NULL; - - switch (img_type) { - case IMG_JPEG: - type_name = "jpeg"; - break; - case IMG_PNG: - type_name = "png"; - break; - default: - type_name = "invalid type"; - break; - } - return type_name; -} - -static void -gst_metadata_update_segment (GstMetadataMux * filter, guint8 ** buf, - guint32 * size, MetadataChunkType type) -{ - int i; - MetadataChunk *inject = filter->mux_data.inject_chunks.chunk; - const gsize inject_len = filter->mux_data.inject_chunks.len; - - if (!(buf && size)) - goto done; - if (*buf == 0) - goto done; - if (*size == 0) - goto done; - - for (i = 0; i < inject_len; ++i) { - if (inject[i].type == type) { - inject[i].size = *size; - if (inject[i].data) - g_free (inject[i].data); - inject[i].data = *buf; - *size = 0; - *buf = 0; - break; - } - } - -done: - - return; - -} - -static void -gst_metadata_create_chunks_from_tags (GstMetadataMux * filter) -{ - - GstMessage *msg; - GstTagSetter *setter = GST_TAG_SETTER (filter); - const GstTagList *taglist = gst_tag_setter_get_tag_list (setter); - GstEvent *event; - guint8 *buf = NULL; - guint32 size = 0; - - if (taglist) { - - if (filter->options & META_OPT_EXIF) { - metadatamux_exif_create_chunk_from_tag_list (&buf, &size, taglist); - gst_metadata_update_segment (filter, &buf, &size, MD_CHUNK_EXIF); - } - - if (filter->options & META_OPT_IPTC) { - metadatamux_iptc_create_chunk_from_tag_list (&buf, &size, taglist); - gst_metadata_update_segment (filter, &buf, &size, MD_CHUNK_IPTC); - } - - if (filter->options & META_OPT_XMP) { - metadatamux_xmp_create_chunk_from_tag_list (&buf, &size, taglist); - gst_metadata_update_segment (filter, &buf, &size, MD_CHUNK_XMP); - } - - } - - if (buf) { - g_free (buf); - } - - metadata_chunk_array_remove_zero_size (&filter->mux_data.inject_chunks); - -} - static const GstQueryType * gst_metadata_mux_get_query_types (GstPad * pad) { @@ -863,15 +796,19 @@ gst_metadata_mux_src_query (GstPad * pad, GstQuery * query) break; case GST_QUERY_DURATION: if (filter->need_calculate_offset) { - if (!gst_metadata_mux_calculate_offsets (filter)) + gst_metadata_create_chunks_from_tags (filter); + if (gst_metadata_common_calculate_offsets (&filter->common)) + filter->need_calculate_offset = FALSE; + else goto done; } gst_query_parse_duration (query, &format, NULL); if (format == GST_FORMAT_BYTES) { - if (filter->duration >= 0) { - gst_query_set_duration (query, GST_FORMAT_BYTES, filter->duration); + if (filter->common.duration >= 0) { + gst_query_set_duration (query, GST_FORMAT_BYTES, + filter->common.duration); ret = TRUE; } } @@ -893,91 +830,6 @@ done: } /* - * return: - * -1 -> error - * 0 -> succeded - * 1 -> need more data - */ - -static gboolean -gst_metadata_mux_calculate_offsets (GstMetadataMux * filter) -{ - int i, j; - guint32 append_size; - guint32 bytes_striped, bytes_inject; - MetadataChunk *strip = filter->mux_data.strip_chunks.chunk; - MetadataChunk *inject = filter->mux_data.inject_chunks.chunk; - gsize strip_len; - gsize inject_len; - - if (filter->state != MT_STATE_MUXED) - return FALSE; - - gst_metadata_create_chunks_from_tags (filter); - - metadata_lazy_update (&filter->mux_data); - - strip_len = filter->mux_data.strip_chunks.len; - inject_len = filter->mux_data.inject_chunks.len; - - bytes_striped = 0; - bytes_inject = 0; - - /* calculate the new position off injected chunks */ - j = 0; - for (i = 0; i < inject_len; ++i) { - for (; j < strip_len; ++j) { - if (strip[j].offset_orig >= inject[i].offset_orig) { - break; - } - bytes_striped += strip[j].size; - } - inject[i].offset = inject[i].offset_orig - bytes_striped + bytes_inject; - bytes_inject += inject[i].size; - } - - /* calculate append (doesnt make much sense, but, anyway..) */ - append_size = 0; - for (i = inject_len - 1; i >= 0; --i) { - if (inject[i].offset_orig == filter->duration_orig) - append_size += inject[i].size; - else - break; - } - if (append_size) { - guint8 *data; - - filter->append_buffer = gst_buffer_new_and_alloc (append_size); - GST_BUFFER_FLAG_SET (filter->append_buffer, GST_BUFFER_FLAG_READONLY); - data = GST_BUFFER_DATA (filter->append_buffer); - for (i = inject_len - 1; i >= 0; --i) { - if (inject[i].offset_orig == filter->duration_orig) { - memcpy (data, inject[i].data, inject[i].size); - data += inject[i].size; - } else { - break; - } - } - } - - if (filter->duration_orig) { - filter->duration = filter->duration_orig; - for (i = 0; i < inject_len; ++i) { - filter->duration += inject[i].size; - } - for (i = 0; i < strip_len; ++i) { - filter->duration -= strip[i].size; - } - } - - filter->need_calculate_offset = FALSE; - - return TRUE; - -} - - -/* * Do parsing step-by-step and reconfigure caps if need * return: * META_PARSING_ERROR @@ -995,11 +847,11 @@ gst_metadata_mux_parse (GstMetadataMux * filter, const guint8 * buf, filter->next_offset = 0; filter->next_size = 0; - ret = metadata_parse (&filter->mux_data, buf, size, + ret = metadata_parse (&filter->common.metadata, buf, size, &filter->next_offset, &filter->next_size); if (ret == META_PARSING_ERROR) { - if (META_DATA_IMG_TYPE (filter->mux_data) == IMG_NONE) { + if (META_DATA_IMG_TYPE (filter->common.metadata) == IMG_NONE) { /* image type not recognized */ GST_ELEMENT_ERROR (filter, STREAM, TYPE_NOT_FOUND, (NULL), ("Only jpeg and png are supported")); @@ -1008,17 +860,18 @@ gst_metadata_mux_parse (GstMetadataMux * filter, const guint8 * buf, } else if (ret == META_PARSING_NEED_MORE_DATA) { filter->need_more_data = TRUE; } else { - filter->state = MT_STATE_MUXED; + filter->common.state = MT_STATE_PARSED; filter->need_more_data = FALSE; filter->need_calculate_offset = TRUE; } - if (filter->img_type != META_DATA_IMG_TYPE (filter->mux_data)) { - filter->img_type = META_DATA_IMG_TYPE (filter->mux_data); + /* reconfigure caps if it is different from type detected by 'metadata_mux' function */ + if (filter->img_type != META_DATA_IMG_TYPE (filter->common.metadata)) { + filter->img_type = META_DATA_IMG_TYPE (filter->common.metadata); if (!gst_metadata_mux_configure_caps (filter)) { GST_ELEMENT_ERROR (filter, STREAM, FORMAT, (NULL), ("Couldn't reconfigure caps for %s", - gst_metadata_mux_get_type_name (filter->img_type))); + gst_metadata_common_get_type_name (filter->img_type))); ret = META_PARSING_ERROR; goto done; } @@ -1051,7 +904,7 @@ gst_metadata_mux_chain (GstPad * pad, GstBuffer * buf) filter = GST_METADATA_MUX (gst_pad_get_parent (pad)); - if (filter->state != MT_STATE_MUXED) { + if (filter->common.state != MT_STATE_PARSED) { guint32 adpt_size = gst_adapter_available (filter->adapter_parsing); if (filter->next_offset) { @@ -1100,7 +953,7 @@ gst_metadata_mux_chain (GstPad * pad, GstBuffer * buf) } } - if (filter->state == MT_STATE_MUXED) { + if (filter->common.state == MT_STATE_PARSED) { if (filter->adapter_holding) { gst_adapter_push (filter->adapter_holding, buf); @@ -1111,18 +964,22 @@ gst_metadata_mux_chain (GstPad * pad, GstBuffer * buf) } if (filter->need_calculate_offset) { - if (!gst_metadata_mux_calculate_offsets (filter)) { + gst_metadata_create_chunks_from_tags (filter); + if (gst_metadata_common_calculate_offsets (&filter->common)) { + filter->need_calculate_offset = FALSE; + } else { ret = GST_FLOW_ERROR; goto done; } } - if (filter->offset_orig + GST_BUFFER_SIZE (buf) == filter->duration_orig) + if (filter->offset_orig + GST_BUFFER_SIZE (buf) == + filter->common.duration_orig) append = TRUE; buf_size = GST_BUFFER_SIZE (buf); - gst_metadata_mux_strip_push_buffer (filter, filter->offset_orig, + gst_metadata_common_strip_push_buffer (&filter->common, filter->offset_orig, &filter->prepend_buffer, &buf); if (buf) { /* may be all buffer has been striped */ @@ -1137,11 +994,11 @@ gst_metadata_mux_chain (GstPad * pad, GstBuffer * buf) ret = GST_FLOW_OK; } - if (append && filter->append_buffer) { - gst_buffer_set_caps (filter->append_buffer, + if (append && filter->common.append_buffer) { + gst_buffer_set_caps (filter->common.append_buffer, GST_PAD_CAPS (filter->srcpad)); - gst_buffer_ref (filter->append_buffer); - ret = gst_pad_push (filter->srcpad, filter->append_buffer); + gst_buffer_ref (filter->common.append_buffer); + ret = gst_pad_push (filter->srcpad, filter->common.append_buffer); if (ret != GST_FLOW_OK) goto done; } @@ -1189,7 +1046,7 @@ gst_metadata_mux_pull_range_mux (GstMetadataMux * filter) ret = TRUE; goto done; } - filter->duration_orig = duration; + filter->common.duration_orig = duration; if (format != GST_FORMAT_BYTES) { /* this should never happen, but try chain anyway */ @@ -1235,7 +1092,6 @@ gst_metadata_mux_pull_range_mux (GstMetadataMux * filter) } while (res == META_PARSING_NEED_MORE_DATA); - done: return ret; @@ -1259,7 +1115,7 @@ gst_metadata_mux_sink_activate (GstPad * pad) } /* try to mux */ - if (filter->state == MT_STATE_NULL) { + if (filter->common.state == MT_STATE_NULL) { ret = gst_metadata_mux_pull_range_mux (filter); } @@ -1278,411 +1134,6 @@ done: } -/* - * offset - offset of buffer in original stream - * size - size of buffer - * seg_offset - offset of segment in original stream - * seg_size - size of segment - * boffset - offset inside buffer where segment starts (-1 for no intersection) - * bsize - size of intersection - * seg_binter - if segment start inside buffer is zero. if segment start before - * buffer and intersect, it is the offset inside segment. - * - * ret: - * -1 - segment before buffer - * 0 - segment intersects - * 1 - segment after buffer - */ - -static int -gst_metadata_mux_get_strip_seg (const gint64 offset, guint32 size, - const gint64 seg_offset, const guint32 seg_size, - gint64 * boffset, guint32 * bsize, guint32 * seg_binter) -{ - int ret = -1; - - *boffset = -1; - *bsize = 0; - *seg_binter = -1; - - /* all segment after buffer */ - if (seg_offset >= offset + size) { - ret = 1; - goto done; - } - - if (seg_offset < offset) { - /* segment start somewhere before buffer */ - - /* all segment before buffer */ - if (seg_offset + seg_size <= offset) { - ret = -1; - goto done; - } - - *seg_binter = offset - seg_offset; - *boffset = 0; - - /* FIXME : optimize to >= size -> = size */ - if (seg_offset + seg_size >= offset + size) { - /* segment cover all buffer */ - *bsize = size; - } else { - /* segment goes from start of buffer to somewhere before end */ - *bsize = seg_size - *seg_binter; - } - - ret = 0; - - } else { - /* segment start somewhere into buffer */ - - *boffset = seg_offset - offset; - *seg_binter = 0; - - if (seg_offset + seg_size <= offset + size) { - /* all segment into buffer */ - *bsize = seg_size; - } else { - *bsize = size - *boffset; - } - - ret = 0; - - } - -done: - - return ret; - -} - -/* - * TRUE -> buffer striped or injeted - * FALSE -> buffer unmodified - */ - -static gboolean -gst_metadata_mux_strip_push_buffer (GstMetadataMux * filter, - gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf) -{ - MetadataChunk *strip = filter->mux_data.strip_chunks.chunk; - MetadataChunk *inject = filter->mux_data.inject_chunks.chunk; - const gsize strip_len = filter->mux_data.strip_chunks.len; - const gsize inject_len = filter->mux_data.inject_chunks.len; - gboolean buffer_reallocated = FALSE; - - guint32 size_buf_in = GST_BUFFER_SIZE (*buf); - - gint64 *boffset_strip = NULL; - guint32 *bsize_strip = NULL; - guint32 *seg_binter_strip = NULL; - - int i, j; - gboolean need_free_strip = FALSE; - - guint32 striped_bytes = 0; - guint32 injected_bytes = 0; - - guint32 prepend_size = prepend && *prepend ? GST_BUFFER_SIZE (*prepend) : 0; - - if (inject_len) { - - for (i = 0; i < inject_len; ++i) { - int res; - - if (inject[i].offset_orig >= offset_orig) { - if (inject[i].offset_orig < offset_orig + size_buf_in) { - injected_bytes += inject[i].size; - } else { - /* segment is after size (segments are sorted) */ - break; - } - } - } - - } - - /* - * strip segments - */ - - if (strip_len == 0) - goto inject; - - if (G_UNLIKELY (strip_len > 16)) { - boffset_strip = g_new (gint64, strip_len); - bsize_strip = g_new (guint32, strip_len); - seg_binter_strip = g_new (guint32, strip_len); - need_free_strip = TRUE; - } else { - boffset_strip = g_alloca (sizeof (boffset_strip[0]) * strip_len); - bsize_strip = g_alloca (sizeof (bsize_strip[0]) * strip_len); - seg_binter_strip = g_alloca (sizeof (seg_binter_strip[0]) * strip_len); - } - - memset (bsize_strip, 0x00, sizeof (bsize_strip[0]) * strip_len); - - for (i = 0; i < strip_len; ++i) { - int res; - - res = gst_metadata_mux_get_strip_seg (offset_orig, size_buf_in, - strip[i].offset_orig, strip[i].size, &boffset_strip[i], &bsize_strip[i], - &seg_binter_strip[i]); - - /* segment is after size (segments are sorted) */ - striped_bytes += bsize_strip[i]; - if (res > 0) { - break; - } - - } - - if (striped_bytes) { - - guint8 *data; - - if (!buffer_reallocated) { - buffer_reallocated = TRUE; - if (injected_bytes + prepend_size > striped_bytes) { - GstBuffer *new_buf = - gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes + - prepend_size - striped_bytes); - - memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf), - GST_BUFFER_SIZE (*buf)); - - gst_buffer_unref (*buf); - *buf = new_buf; - - } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) { - GstBuffer *new_buf = gst_buffer_copy (*buf); - - gst_buffer_unref (*buf); - *buf = new_buf; - GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY); - GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes; - } - } - - data = GST_BUFFER_DATA (*buf); - - striped_bytes = 0; - for (i = 0; i < strip_len; ++i) { - /* intersect */ - if (bsize_strip[i]) { - memmove (data + boffset_strip[i] - striped_bytes, - data + boffset_strip[i] + bsize_strip[i] - striped_bytes, - size_buf_in - boffset_strip[i] - bsize_strip[i]); - striped_bytes += bsize_strip[i]; - } - } - size_buf_in -= striped_bytes; - - } - -inject: - - /* - * inject segments - */ - - if (inject_len) { - - guint8 *data; - guint32 striped_so_far; - - if (!buffer_reallocated) { - buffer_reallocated = TRUE; - if (injected_bytes + prepend_size > striped_bytes) { - GstBuffer *new_buf = - gst_buffer_new_and_alloc (GST_BUFFER_SIZE (*buf) + injected_bytes + - prepend_size - striped_bytes); - - memcpy (GST_BUFFER_DATA (new_buf), GST_BUFFER_DATA (*buf), - GST_BUFFER_SIZE (*buf)); - - gst_buffer_unref (*buf); - *buf = new_buf; - - } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_READONLY)) { - GstBuffer *new_buf = gst_buffer_copy (*buf); - - gst_buffer_unref (*buf); - *buf = new_buf; - GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY); - GST_BUFFER_SIZE (*buf) += injected_bytes + prepend_size - striped_bytes; - } - } - - data = GST_BUFFER_DATA (*buf); - - injected_bytes = 0; - striped_so_far = 0; - j = 0; - for (i = 0; i < inject_len; ++i) { - int res; - - while (j < strip_len) { - if (strip[j].offset_orig < inject[i].offset_orig) - striped_so_far += bsize_strip[j++]; - else - break; - } - - if (inject[i].offset_orig >= offset_orig) { - if (inject[i].offset_orig < - offset_orig + size_buf_in + striped_bytes - injected_bytes) { - /* insert */ - guint32 buf_off = - inject[i].offset_orig - offset_orig - striped_so_far + - injected_bytes; - memmove (data + buf_off + inject[i].size, data + buf_off, - size_buf_in - buf_off); - memcpy (data + buf_off, inject[i].data, inject[i].size); - injected_bytes += inject[i].size; - size_buf_in += inject[i].size; - } else { - /* segment is after size (segments are sorted) */ - break; - } - } - } - - } - - -done: - - if (prepend_size) { - if (injected_bytes == 0 && striped_bytes == 0) { - GstBuffer *new_buf = - gst_buffer_new_and_alloc (size_buf_in + prepend_size); - - memcpy (GST_BUFFER_DATA (new_buf) + prepend_size, GST_BUFFER_DATA (*buf), - size_buf_in); - - gst_buffer_unref (*buf); - *buf = new_buf; - } else { - memmove (GST_BUFFER_DATA (*buf) + prepend_size, GST_BUFFER_DATA (*buf), - size_buf_in); - } - memcpy (GST_BUFFER_DATA (*buf), GST_BUFFER_DATA (*prepend), prepend_size); - gst_buffer_unref (*prepend); - *prepend = NULL; - } - - GST_BUFFER_SIZE (*buf) = size_buf_in + prepend_size; - - if (need_free_strip) { - g_free (boffset_strip); - g_free (bsize_strip); - g_free (seg_binter_strip); - } - - return injected_bytes || striped_bytes; - -} - -/* - * pos - position in stream striped - * orig_pos - position in original stream - * return TRUE - position in original buffer - * FALSE - position in inserted chunk - */ -static gboolean -gst_metadata_mux_translate_pos_to_orig (GstMetadataMux * filter, gint64 pos, - gint64 * orig_pos, GstBuffer ** buf) -{ - int i; - MetadataChunk *strip = filter->mux_data.strip_chunks.chunk; - MetadataChunk *inject = filter->mux_data.inject_chunks.chunk; - const gsize strip_len = filter->mux_data.strip_chunks.len; - const gsize inject_len = filter->mux_data.inject_chunks.len; - gboolean ret = TRUE; - guint64 new_buf_size = 0; - guint64 injected_before = 0; - - if (G_UNLIKELY (pos == -1)) { - *orig_pos = -1; - return TRUE; - } else if (G_UNLIKELY (pos >= filter->duration)) { - /* this should never happen */ - *orig_pos = filter->duration_orig; - return TRUE; - } - - /* calculate for injected */ - - /* just calculate size */ - *orig_pos = pos; /* save pos */ - for (i = 0; i < inject_len; ++i) { - /* check if pos in inside chunk */ - if (inject[i].offset <= pos) { - if (pos < inject[i].offset + inject[i].size) { - /* orig pos points after insert chunk */ - new_buf_size += inject[i].size; - /* put pos after current chunk */ - pos = inject[i].offset + inject[i].size; - ret = FALSE; - } else { - /* in case pos is not inside a injected chunk */ - injected_before += inject[i].size; - } - } else { - break; - } - } - - /* alloc buffer and calcute original pos */ - if (buf && ret == FALSE) { - guint8 *data; - - if (*buf) - gst_buffer_unref (*buf); - *buf = gst_buffer_new_and_alloc (new_buf_size); - data = GST_BUFFER_DATA (*buf); - pos = *orig_pos; /* recover saved pos */ - for (i = 0; i < inject_len; ++i) { - if (inject[i].offset > pos) { - break; - } - if (inject[i].offset <= pos && pos < inject[i].offset + inject[i].size) { - memcpy (data, inject[i].data, inject[i].size); - data += inject[i].size; - pos = inject[i].offset + inject[i].size; - /* out position after insert chunk orig */ - *orig_pos = inject[i].offset_orig + inject[i].size; - } - } - } - - if (ret == FALSE) { - /* if it inside a injected is already done */ - goto done; - } - - /* calculate for striped */ - - *orig_pos = pos - injected_before; - for (i = 0; i < strip_len; ++i) { - if (strip[i].offset_orig > pos) { - break; - } - *orig_pos += strip[i].size; - } - -done: - - if (G_UNLIKELY (*orig_pos >= filter->duration_orig)) { - *orig_pos = filter->duration_orig - 1; - } - - return ret; - -} - static gboolean gst_metadata_mux_checkgetrange (GstPad * srcpad) { @@ -1707,26 +1158,30 @@ gst_metadata_mux_get_range (GstPad * pad, filter = GST_METADATA_MUX (GST_PAD_PARENT (pad)); if (filter->need_calculate_offset) { - if (!gst_metadata_mux_calculate_offsets (filter)) { + gst_metadata_create_chunks_from_tags (filter); + if (gst_metadata_common_calculate_offsets (&filter->common)) { + filter->need_calculate_offset = FALSE; + } else { ret = GST_FLOW_ERROR; goto done; } } - if (offset + size > filter->duration) { - size = filter->duration - offset; + if (offset + size > filter->common.duration) { + size = filter->common.duration - offset; } size_orig = size; - gst_metadata_mux_translate_pos_to_orig (filter, offset, &offset_orig, - &prepend); + gst_metadata_common_translate_pos_to_orig (&filter->common, offset, + &offset_orig, &prepend); if (size > 1) { gint64 pos; pos = offset + size - 1; - gst_metadata_mux_translate_pos_to_orig (filter, pos, &pos, NULL); + gst_metadata_common_translate_pos_to_orig (&filter->common, pos, &pos, + NULL); size_orig = pos + 1 - offset_orig; } @@ -1735,7 +1190,8 @@ gst_metadata_mux_get_range (GstPad * pad, ret = gst_pad_pull_range (filter->sinkpad, offset_orig, size_orig, buf); if (ret == GST_FLOW_OK && *buf) { - gst_metadata_mux_strip_push_buffer (filter, offset_orig, &prepend, buf); + gst_metadata_common_strip_push_buffer (&filter->common, offset_orig, + &prepend, buf); if (GST_BUFFER_SIZE (*buf) < size) { /* need append */ @@ -1751,7 +1207,7 @@ done: if (need_append) { /* FIXME: together with SEEK and - * gst_metadata_parse_translate_pos_to_orig + * gst_metadata_common_translate_pos_to_orig * this way if chunk is added in the end we are in trolble * ...still not implemented 'cause it will not be the * case for the time being @@ -1772,7 +1228,7 @@ gst_metadata_mux_src_activate_pull (GstPad * pad, gboolean active) ret = gst_pad_activate_pull (filter->sinkpad, active); - if (ret && filter->state == MT_STATE_NULL) { + if (ret && filter->common.state == MT_STATE_NULL) { ret = gst_metadata_mux_pull_range_mux (filter); } @@ -1792,7 +1248,7 @@ gst_metadata_mux_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_NULL_TO_READY: gst_metadata_mux_init_members (filter); filter->adapter_parsing = gst_adapter_new (); - metadata_init (&filter->mux_data, FALSE, filter->options); + gst_metadata_common_init (&filter->common, FALSE, filter->options); break; default: break; @@ -1812,11 +1268,10 @@ gst_metadata_mux_change_state (GstElement * element, GstStateChange transition) if (filter->adapter_holding) { gst_adapter_clear (filter->adapter_holding); } - if (filter->state != MT_STATE_MUXED) { + if (filter->common.state != MT_STATE_PARSED) { /* cleanup parser */ - /* FIXME: could be improved a bit to avoid mem allocation */ - metadata_dispose (&filter->mux_data); - metadata_init (&filter->mux_data, FALSE, filter->options); + gst_metadata_common_dispose (&filter->common); + gst_metadata_common_init (&filter->common, FALSE, filter->options); } break; case GST_STATE_CHANGE_READY_TO_NULL: diff --git a/ext/metadata/gstmetadatamux.h b/ext/metadata/gstmetadatamux.h index c7cb40ba..8b123f51 100644 --- a/ext/metadata/gstmetadatamux.h +++ b/ext/metadata/gstmetadatamux.h @@ -46,7 +46,7 @@ #include <gst/gst.h> -#include "metadata.h" +#include "gstmetadatacommon.h" G_BEGIN_DECLS /* #defines don't like whitespacey bits */ @@ -63,21 +63,16 @@ G_BEGIN_DECLS typedef struct _GstMetadataMux GstMetadataMux; typedef struct _GstMetadataMuxClass GstMetadataMuxClass; -typedef enum _tag_MetadataState -{ - MT_STATE_NULL, /* still need to check media type */ - MT_STATE_MUXED -} MetadataState; - struct _GstMetadataMux { GstElement element; GstPad *sinkpad, *srcpad; + GstMetadataCommon common; + guint8 options; - MetaData mux_data; GstAdapter *adapter_parsing; GstAdapter *adapter_holding; guint32 next_offset; @@ -85,14 +80,9 @@ struct _GstMetadataMux ImageType img_type; gint64 offset_orig; /* offset in original stream */ - gint64 duration_orig; /* durarion of stream */ gint64 offset; /* offset in current stream */ - gint64 duration; /* durarion of modified stream */ - - MetadataState state; GstBuffer * prepend_buffer; - GstBuffer * append_buffer; gboolean need_more_data; diff --git a/ext/metadata/metadataexif.c b/ext/metadata/metadataexif.c index 65ade6ea..5b745a7a 100644 --- a/ext/metadata/metadataexif.c +++ b/ext/metadata/metadataexif.c @@ -89,7 +89,6 @@ typedef struct _tag_MapIntStr { ExifTag exif; const gchar *str; - GType type; } MapIntStr; static void @@ -99,21 +98,21 @@ static void exif_content_foreach_entry_func (ExifEntry * entry, void *); /* *INDENT-OFF* */ static MapIntStr mappedTags[] = { - {EXIF_TAG_MAKE, /*EXIF_FORMAT_ASCII,*/ GST_TAG_DEVICE_MAKE, G_TYPE_STRING}, - {EXIF_TAG_MODEL, /*EXIF_FORMAT_ASCII,*/ GST_TAG_DEVICE_MODEL, G_TYPE_STRING}, - {EXIF_TAG_SOFTWARE, /*EXIF_FORMAT_ASCII,*/ GST_TAG_CREATOR_TOOL, G_TYPE_STRING}, - {EXIF_TAG_X_RESOLUTION, /*EXIF_FORMAT_RATIONAL,*/ GST_TAG_IMAGE_XRESOLUTION, G_TYPE_FLOAT}, /* inches */ - {EXIF_TAG_Y_RESOLUTION, /*EXIF_FORMAT_RATIONAL,*/ GST_TAG_IMAGE_YRESOLUTION, G_TYPE_FLOAT}, /* inches */ - {EXIF_TAG_EXPOSURE_TIME, /*EXIF_FORMAT_RATIONAL,*/ GST_TAG_CAPTURE_EXPOSURE_TIME, G_TYPE_FLOAT}, - {EXIF_TAG_FNUMBER, /*EXIF_FORMAT_RATIONAL,*/ GST_TAG_CAPTURE_FNUMBER, G_TYPE_FLOAT}, - {EXIF_TAG_EXPOSURE_PROGRAM, /*EXIF_FORMAT_SHORT,*/ GST_TAG_CAPTURE_EXPOSURE_PROGRAM, G_TYPE_UINT}, - {EXIF_TAG_BRIGHTNESS_VALUE, /*EXIF_FORMAT_SRATIONAL,*/ GST_TAG_CAPTURE_BRIGHTNESS, G_TYPE_FLOAT}, - {EXIF_TAG_WHITE_BALANCE, /*EXIF_FORMAT_SHORT,*/ GST_TAG_CAPTURE_WHITE_BALANCE, G_TYPE_UINT}, - {EXIF_TAG_DIGITAL_ZOOM_RATIO, /*EXIF_FORMAT_RATIONAL,*/ GST_TAG_CAPTURE_DIGITAL_ZOOM, G_TYPE_FLOAT}, - {EXIF_TAG_GAIN_CONTROL, /*EXIF_FORMAT_SHORT,*/ GST_TAG_CAPTURE_GAIN, G_TYPE_UINT}, - {EXIF_TAG_CONTRAST, /*EXIF_FORMAT_SHORT,*/ GST_TAG_CAPTURE_CONTRAST, G_TYPE_INT}, - {EXIF_TAG_SATURATION, /*EXIF_FORMAT_SHORT,*/ GST_TAG_CAPTURE_SATURATION, G_TYPE_INT}, - {0, NULL, G_TYPE_NONE} + {EXIF_TAG_MAKE, /*ASCII,*/ GST_TAG_DEVICE_MAKE, /*STRING*/}, + {EXIF_TAG_MODEL, /*ASCII,*/ GST_TAG_DEVICE_MODEL, /*STRING*/}, + {EXIF_TAG_SOFTWARE, /*ASCII,*/ GST_TAG_CREATOR_TOOL, /*STRING*/}, + {EXIF_TAG_X_RESOLUTION, /*RATIONAL,*/ GST_TAG_IMAGE_XRESOLUTION, /*FRACTION*/}, /* inches */ + {EXIF_TAG_Y_RESOLUTION, /*RATIONAL,*/ GST_TAG_IMAGE_YRESOLUTION, /*FRACTION*/}, /* inches */ + {EXIF_TAG_EXPOSURE_TIME, /*RATIONAL,*/ GST_TAG_CAPTURE_EXPOSURE_TIME, /*FRACTION*/}, + {EXIF_TAG_FNUMBER, /*RATIONAL,*/ GST_TAG_CAPTURE_FNUMBER, /*FRACTION*/}, + {EXIF_TAG_EXPOSURE_PROGRAM, /*SHORT,*/ GST_TAG_CAPTURE_EXPOSURE_PROGRAM, /*UINT*/}, + {EXIF_TAG_BRIGHTNESS_VALUE, /*SRATIONAL,*/ GST_TAG_CAPTURE_BRIGHTNESS, /*FRACTION*/}, + {EXIF_TAG_WHITE_BALANCE, /*SHORT,*/ GST_TAG_CAPTURE_WHITE_BALANCE, /*UINT*/}, + {EXIF_TAG_DIGITAL_ZOOM_RATIO, /*RATIONAL,*/ GST_TAG_CAPTURE_DIGITAL_ZOOM, /*FRACTION*/}, + {EXIF_TAG_GAIN_CONTROL, /*SHORT,*/ GST_TAG_CAPTURE_GAIN, /*UINT*/}, + {EXIF_TAG_CONTRAST, /*SHORT,*/ GST_TAG_CAPTURE_CONTRAST, /*INT*/}, + {EXIF_TAG_SATURATION, /*SHORT,*/ GST_TAG_CAPTURE_SATURATION, /*INT*/}, + {0, NULL} }; /* *INDENT-ON* */ @@ -123,12 +122,13 @@ metadataparse_exif_get_tag_from_exif (ExifTag exif, GType * type) int i = 0; while (mappedTags[i].exif) { - if (exif == mappedTags[i].exif) + if (exif == mappedTags[i].exif) { + *type = gst_tag_get_type (mappedTags[i].str); break; + } ++i; } - *type = mappedTags[i].type; return mappedTags[i].str; } @@ -139,12 +139,13 @@ metadataparse_exif_get_exif_from_tag (const gchar * tag, GType * type) int i = 0; while (mappedTags[i].exif) { - if (0 == strcmp (mappedTags[i].str, tag)) + if (0 == strcmp (mappedTags[i].str, tag)) { + *type = gst_tag_get_type (tag); break; + } ++i; } - *type = mappedTags[i].type; return mappedTags[i].exif; } @@ -257,61 +258,59 @@ exif_content_foreach_entry_func (ExifEntry * entry, void *user_data) goto done; } - if (tag) { - /* FIXME: create a generic function for this */ - /* could also be used with entry->format */ - switch (type) { - case G_TYPE_STRING: - gst_tag_list_add (meudata->taglist, meudata->mode, tag, - exif_entry_get_value (entry, buf, sizeof (buf)), NULL); + if (!tag) + goto done; + + if (type == GST_TYPE_FRACTION) { + gint numerator = 0; + gint denominator = 1; + + switch (entry->format) { + case EXIF_FORMAT_SRATIONAL: + { + ExifSRational v_srat; + + v_srat = exif_get_srational (entry->data, byte_order); + if (v_srat.denominator) { + numerator = (gint) v_srat.numerator; + denominator = (gint) v_srat.denominator; + } + } break; - case G_TYPE_FLOAT: + case EXIF_FORMAT_RATIONAL: { - gfloat f_value; + ExifRational v_rat; - switch (entry->format) { - case EXIF_FORMAT_SRATIONAL: - { - ExifSRational v_srat; - - v_srat = exif_get_srational (entry->data, byte_order); - if (v_srat.denominator == 0) - f_value = 0.0f; - else - f_value = (float) v_srat.numerator / (float) v_srat.denominator; - if (v_srat.numerator == 0xFFFFFFFF) { - if (entry->tag == EXIF_TAG_BRIGHTNESS_VALUE) { - f_value = 100.0f; - } - } - } - break; - case EXIF_FORMAT_RATIONAL: - { - ExifRational v_rat; - - v_rat = exif_get_rational (entry->data, byte_order); - if (v_rat.denominator == 0) - f_value = 0.0f; - else - f_value = (float) v_rat.numerator / (float) v_rat.denominator; - if (meudata->resolution_unit == 3) { - /* converts from cm to inches */ - if (entry->tag == EXIF_TAG_X_RESOLUTION - || entry->tag == EXIF_TAG_Y_RESOLUTION) { - f_value *= 0.4f; - } - } + v_rat = exif_get_rational (entry->data, byte_order); + if (v_rat.denominator) { + numerator = (gint) v_rat.numerator; + denominator = (gint) v_rat.denominator; + } + if (meudata->resolution_unit == 3) { + /* converts from cm to inches */ + if (entry->tag == EXIF_TAG_X_RESOLUTION + || entry->tag == EXIF_TAG_Y_RESOLUTION) { + numerator *= 2; + denominator *= 5; } - break; - default: - GST_ERROR ("Unexpected Tag Type"); - goto done; - break; } - gst_tag_list_add (meudata->taglist, meudata->mode, tag, f_value, NULL); } break; + default: + GST_ERROR ("Unexpected Tag Type"); + goto done; + break; + } + gst_tag_list_add (meudata->taglist, meudata->mode, tag, numerator, + denominator, NULL); + + } else { + + switch (type) { + case G_TYPE_STRING: + gst_tag_list_add (meudata->taglist, meudata->mode, tag, + exif_entry_get_value (entry, buf, sizeof (buf)), NULL); + break; case G_TYPE_INT: /* fall through */ case G_TYPE_UINT: @@ -350,8 +349,10 @@ exif_content_foreach_entry_func (ExifEntry * entry, void *user_data) default: break; } + } + done: GST_LOG ("\n Entry %p: %s (%s)\n" @@ -465,90 +466,82 @@ metadataexif_for_each_tag_in_list (const GstTagList * list, const gchar * tag, exif_entry_initialize (entry, exif_tag); } - switch (type) { - case G_TYPE_STRING: - { - gchar *value = NULL; + if (type == GST_TYPE_FRACTION) { + const GValue *gvalue = gst_tag_list_get_value_index (list, tag, 0); + gint numerator = gst_value_get_fraction_numerator (gvalue); + gint denominator = gst_value_get_fraction_denominator (gvalue); - if (gst_tag_list_get_string (list, tag, &value)) { - entry->components = strlen (value) + 1; - entry->size = exif_format_get_size (entry->format) * entry->components; - entry->data = value; + switch (entry->format) { + case EXIF_FORMAT_SRATIONAL: + { + ExifSRational sr = { numerator, denominator }; + + exif_set_srational (entry->data, byte_order, sr); } - } - break; - case G_TYPE_FLOAT: - { - gfloat value; + break; + case EXIF_FORMAT_RATIONAL: + { + ExifRational r = { numerator, denominator }; - gst_tag_list_get_float (list, tag, &value); + exif_set_rational (entry->data, byte_order, r); + if (entry->tag == EXIF_TAG_X_RESOLUTION || + entry->tag == EXIF_TAG_Y_RESOLUTION) { + ExifEntry *unit_entry = NULL; - switch (entry->format) { - case EXIF_FORMAT_SRATIONAL: - { - ExifSRational sr; + if ((unit_entry = exif_data_get_entry (ed, EXIF_TAG_RESOLUTION_UNIT))) { + ExifShort vsh = exif_get_short (unit_entry->data, byte_order); - sr = float_to_srational (value); - if (entry->tag == EXIF_TAG_BRIGHTNESS_VALUE) { - if (value == 100.0f) { - sr.numerator = 0xFFFFFFFF; - sr.denominator = 1; - } + if (vsh != 2) /* inches */ + exif_set_short (unit_entry->data, byte_order, 2); } - - exif_set_srational (entry->data, byte_order, sr); } - break; - case EXIF_FORMAT_RATIONAL: - { - ExifRational r; - - r = float_to_rational (value); - exif_set_rational (entry->data, byte_order, r); - if (entry->tag == EXIF_TAG_X_RESOLUTION || - entry->tag == EXIF_TAG_Y_RESOLUTION) { - ExifEntry *unit_entry = NULL; - - if ((unit_entry = - exif_data_get_entry (ed, EXIF_TAG_RESOLUTION_UNIT))) { - ExifShort vsh = exif_get_short (unit_entry->data, byte_order); - - if (vsh != 2) /* inches */ - exif_set_short (unit_entry->data, byte_order, 2); - } - } - } - break; - default: - break; } + break; + default: + break; } - break; - case G_TYPE_UINT: - case G_TYPE_INT: - { - gint value; - ExifShort v_short; - - if (G_TYPE_UINT == type) { - gst_tag_list_get_uint (list, tag, &value); - } else { - gst_tag_list_get_int (list, tag, &value); + } else { + + switch (type) { + case G_TYPE_STRING: + { + gchar *value = NULL; + + if (gst_tag_list_get_string (list, tag, &value)) { + entry->components = strlen (value) + 1; + entry->size = + exif_format_get_size (entry->format) * entry->components; + entry->data = value; + } } - if (entry->tag == EXIF_TAG_CONTRAST || entry->tag == EXIF_TAG_SATURATION) { - if (value < -33) - value = 1; /* low */ - else if (value < 34) - value = 0; /* normal */ - else - value = 2; /* high */ + break; + case G_TYPE_UINT: + case G_TYPE_INT: + { + gint value; + ExifShort v_short; + + if (G_TYPE_UINT == type) { + gst_tag_list_get_uint (list, tag, &value); + } else { + gst_tag_list_get_int (list, tag, &value); + } + if (entry->tag == EXIF_TAG_CONTRAST + || entry->tag == EXIF_TAG_SATURATION) { + if (value < -33) + value = 1; /* low */ + else if (value < 34) + value = 0; /* normal */ + else + value = 2; /* high */ + } + v_short = value; + exif_set_short (entry->data, byte_order, v_short); } - v_short = value; - exif_set_short (entry->data, byte_order, v_short); + break; + default: + break; } - break; - default: - break; } done: diff --git a/ext/metadata/metadatatags.c b/ext/metadata/metadatatags.c index 00f3956b..6250c256 100644 --- a/ext/metadata/metadatatags.c +++ b/ext/metadata/metadatatags.c @@ -50,39 +50,6 @@ static void metadata_tags_exif_register (void) { - gst_tag_register (GST_TAG_EXIF, GST_TAG_FLAG_META, - GST_TYPE_BUFFER, GST_TAG_EXIF, "exif metadata chunk", NULL); -} - -/* - * IPTC tags - */ - -static void -metadata_tags_iptc_register (void) -{ - gst_tag_register (GST_TAG_IPTC, GST_TAG_FLAG_META, - GST_TYPE_BUFFER, GST_TAG_IPTC, "iptc metadata chunk", NULL); -} - -/* - * XMP tags - */ - -static void -metadata_tags_xmp_register (void) -{ - gst_tag_register (GST_TAG_XMP, GST_TAG_FLAG_META, - GST_TYPE_BUFFER, GST_TAG_XMP, "xmp metadata chunk", NULL); -} - -/* - * - */ - -void -metadata_tags_register (void) -{ /* devices tags */ gst_tag_register (GST_TAG_DEVICE_MAKE, GST_TAG_FLAG_META, @@ -101,20 +68,21 @@ metadata_tags_register (void) /* image tags */ - gst_tag_register (GST_TAG_IMAGE_XRESOLUTION, GST_TAG_FLAG_META, G_TYPE_FLOAT, - GST_TAG_IMAGE_XRESOLUTION, "Horizontal resolution in pixels per inch", - NULL); - gst_tag_register (GST_TAG_IMAGE_YRESOLUTION, GST_TAG_FLAG_META, G_TYPE_FLOAT, - GST_TAG_IMAGE_YRESOLUTION, "Vertical resolution in pixels per inch", - NULL); + gst_tag_register (GST_TAG_IMAGE_XRESOLUTION, GST_TAG_FLAG_META, + GST_TYPE_FRACTION, GST_TAG_IMAGE_XRESOLUTION, + "Horizontal resolution in pixels per inch", NULL); + gst_tag_register (GST_TAG_IMAGE_YRESOLUTION, GST_TAG_FLAG_META, + GST_TYPE_FRACTION, GST_TAG_IMAGE_YRESOLUTION, + "Vertical resolution in pixels per inch", NULL); /* capture tags */ gst_tag_register (GST_TAG_CAPTURE_EXPOSURE_TIME, GST_TAG_FLAG_META, - G_TYPE_FLOAT, GST_TAG_CAPTURE_EXPOSURE_TIME, "Exposure time in seconds", + GST_TYPE_FRACTION, GST_TAG_CAPTURE_EXPOSURE_TIME, + "Exposure time in seconds", NULL); + gst_tag_register (GST_TAG_CAPTURE_FNUMBER, GST_TAG_FLAG_META, + GST_TYPE_FRACTION, GST_TAG_CAPTURE_FNUMBER, "F number (focal ratio)", NULL); - gst_tag_register (GST_TAG_CAPTURE_FNUMBER, GST_TAG_FLAG_META, G_TYPE_FLOAT, - GST_TAG_CAPTURE_FNUMBER, "F number (focal ratio)", NULL); /** 0 - not defined 1- Manual @@ -137,11 +105,11 @@ metadata_tags_register (void) "Class of program used for exposure", NULL); /** The unit is the APEX value. Ordinarily it is given in the range of -99.99 to 99.99. - 100.0 mean unknown + if numerator is 0xFFFFFFFF means unknown */ - gst_tag_register (GST_TAG_CAPTURE_BRIGHTNESS, GST_TAG_FLAG_META, G_TYPE_FLOAT, - GST_TAG_CAPTURE_BRIGHTNESS, "Brightness (APEX from -99.99 to 99.99)", - NULL); + gst_tag_register (GST_TAG_CAPTURE_BRIGHTNESS, GST_TAG_FLAG_META, + GST_TYPE_FRACTION, GST_TAG_CAPTURE_BRIGHTNESS, + "Brightness (APEX from -99.99 to 99.99)", NULL); /** 0- Auto 1- Off @@ -160,7 +128,8 @@ metadata_tags_register (void) /** if Zero ZOOM not used */ gst_tag_register (GST_TAG_CAPTURE_DIGITAL_ZOOM, GST_TAG_FLAG_META, - G_TYPE_FLOAT, GST_TAG_CAPTURE_DIGITAL_ZOOM, "Digital zoom ratio", NULL); + GST_TYPE_FRACTION, GST_TAG_CAPTURE_DIGITAL_ZOOM, "Digital zoom ratio", + NULL); /** 0- None 1- Low gain up @@ -189,6 +158,49 @@ metadata_tags_register (void) gst_tag_register (GST_TAG_CAPTURE_SATURATION, GST_TAG_FLAG_META, G_TYPE_INT, GST_TAG_CAPTURE_SATURATION, "", NULL); +} + +/* + * IPTC tags + */ + +static void +metadata_tags_iptc_register (void) +{ + +} + +/* + * XMP tags + */ + +static void +metadata_tags_xmp_register (void) +{ + +} + +/* + * + */ + +void +metadata_tags_register (void) +{ + + /* whole chunk tags */ + + gst_tag_register (GST_TAG_EXIF, GST_TAG_FLAG_META, + GST_TYPE_BUFFER, GST_TAG_EXIF, "exif metadata chunk", NULL); + + gst_tag_register (GST_TAG_IPTC, GST_TAG_FLAG_META, + GST_TYPE_BUFFER, GST_TAG_IPTC, "iptc metadata chunk", NULL); + + gst_tag_register (GST_TAG_XMP, GST_TAG_FLAG_META, + GST_TYPE_BUFFER, GST_TAG_XMP, "xmp metadata chunk", NULL); + + /* tags related to some metadata */ + metadata_tags_exif_register (); metadata_tags_iptc_register (); metadata_tags_xmp_register (); diff --git a/ext/metadata/test/metadata_editor.c b/ext/metadata/test/metadata_editor.c index 4228b227..e3b1cee5 100644 --- a/ext/metadata/test/metadata_editor.c +++ b/ext/metadata/test/metadata_editor.c @@ -160,33 +160,43 @@ change_tag_list (GstTagList ** list, const gchar * tag, const gchar * value) type = gst_tag_get_type (tag); - switch (type) { - case G_TYPE_STRING: - gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, value, NULL); - ret = TRUE; - break; - case G_TYPE_FLOAT: - { - gfloat fv = (gfloat) g_strtod (value, NULL); + if (type == GST_TYPE_FRACTION) { + /* FIXME: Ask GStreamer guys to add GST_FRACTION support to TAGS */ + /* Even better: ask GLib guys to add this type */ + gint n, d; - gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, fv, NULL); - ret = TRUE; - } - break; - case G_TYPE_INT: - /* fall through */ - case G_TYPE_UINT: - { - gint iv = atoi (value); - - gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, iv, NULL); - ret = TRUE; + sscanf (value, "%d/%d", &n, &d); + gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, n, d, NULL); + ret = TRUE; + } else { + switch (type) { + case G_TYPE_STRING: + gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, value, NULL); + ret = TRUE; + break; + case G_TYPE_FLOAT: + { + gfloat fv = (gfloat) g_strtod (value, NULL); + + gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, fv, NULL); + ret = TRUE; + } + break; + case G_TYPE_INT: + /* fall through */ + case G_TYPE_UINT: + { + gint iv = atoi (value); + + gst_tag_list_add (*list, GST_TAG_MERGE_REPLACE, tag, iv, NULL); + ret = TRUE; + } + break; + default: + fprintf (stderr, "This app still doesn't handle type (%s)(%ld)\n", + g_type_name (type), type); + break; } - break; - default: - fprintf (stderr, "This app still doesn't handle type (%s)(%ld)\n", - g_type_name (type), type); - break; } done: @@ -700,7 +710,7 @@ me_gst_setup_encode_pipeline (const gchar * src_file, const gchar * dest_file, /* create elements */ gst_source = gst_element_factory_make ("filesrc", NULL); - gst_metadata_demux = gst_element_factory_make ("metadataparse", NULL); + gst_metadata_demux = gst_element_factory_make ("metadatademux", NULL); gst_metadata_mux = gst_element_factory_make ("metadatamux", NULL); gst_file_sink = gst_element_factory_make ("filesink", NULL); @@ -767,7 +777,7 @@ me_gst_setup_view_pipeline (const gchar * filename, GdkWindow * window) /* create elements */ gst_source = gst_element_factory_make ("filesrc", NULL); - gst_metadata_demux = gst_element_factory_make ("metadataparse", NULL); + gst_metadata_demux = gst_element_factory_make ("metadatademux", NULL); /* let's do a dummy stuff to avoid decodebin */ if (is_png (filename)) gst_image_dec = gst_element_factory_make ("pngdec", NULL); |