metadata: remove metadata plugin

This plugins functionality is replaced by utility libraries in base for exif
and xmp. Jpeg images can use this via jpegformat plugin.
Fixes #486659
This commit is contained in:
Stefan Kost 2010-09-15 18:10:33 +03:00
parent 5b6550dbd5
commit bc1c9ac18e
44 changed files with 13 additions and 13187 deletions

View file

@ -743,7 +743,7 @@ AG_GST_CHECK_FEATURE(RESINDVD, [resindvd plugin], resindvd, [
])
])
dnl **** exif (used on metadata and jifmux tests) ****
dnl **** exif (used on jifmux tests) ****
translit(dnm, m, l) AM_CONDITIONAL(USE_EXIF, true)
AG_GST_CHECK_FEATURE(EXIF, [exif], exif, [
PKG_CHECK_MODULES(EXIF, libexif >= 0.6.16, HAVE_EXIF="yes", [
@ -752,42 +752,6 @@ AG_GST_CHECK_FEATURE(EXIF, [exif], exif, [
])
])
dnl *** METADATA ***
translit(dnm, m, l) AM_CONDITIONAL(USE_METADATA, true)
AG_GST_CHECK_FEATURE(METADATA, [METADATA muxer and demuxer], metadata, [
HAVE_METADATA="no"
PKG_CHECK_MODULES(IPTC, libiptcdata >= 1.0.2, HAVE_IPTC="yes", [
HAVE_IPTC="no"
])
PKG_CHECK_MODULES(XMP, exempi-2.0, HAVE_XMP="yes", [
HAVE_XMP="no"
])
PKG_CHECK_MODULES(XMP_1_99_5, exempi-2.0 >= 1.99.5, XMP_CFLAGS="-DXMP_1_99_5 $XMP_CFLAGS", AC_MSG_RESULT(no))
if test x$HAVE_EXIF = xyes; then
METADATA_CFLAGS="$EXIF_CFLAGS $METADATA_CFLAGS"
METADATA_LIBS="$EXIF_LIBS $METADATA_LIBS -lm"
HAVE_METADATA="yes"
fi
if test x$HAVE_IPTC = xyes; then
METADATA_CFLAGS="-DHAVE_IPTC $IPTC_CFLAGS $METADATA_CFLAGS"
METADATA_LIBS="$IPTC_LIBS $METADATA_LIBS"
HAVE_METADATA="yes"
fi
if test x$HAVE_XMP = xyes; then
METADATA_CFLAGS="-DHAVE_XMP $XMP_CFLAGS $METADATA_CFLAGS"
METADATA_LIBS="$XMP_LIBS $METADATA_LIBS"
HAVE_METADATA="yes"
fi
if test x$HAVE_METADATA = xno; then
AC_MSG_WARN(no of metadata libraries (exif, iptc or xmp) found)
else
HAVE_METADATA="yes"
fi
AC_SUBST(METADATA_CFLAGS)
AC_SUBST(METADATA_LIBS)
])
dnl **** Free AAC Encoder (FAAC) ****
translit(dnm, m, l) AM_CONDITIONAL(USE_FAAC, true)
AG_GST_CHECK_FEATURE(FAAC, [AAC encoder plug-in], faac, [
@ -1602,7 +1566,6 @@ AM_CONDITIONAL(USE_DTS, false)
AM_CONDITIONAL(USE_DIVX, false)
AM_CONDITIONAL(USE_EXIF, false)
AM_CONDITIONAL(USE_RESINDVD, false)
AM_CONDITIONAL(USE_METADATA, false)
AM_CONDITIONAL(USE_FAAC, false)
AM_CONDITIONAL(USE_FAAD, false)
AM_CONDITIONAL(USE_FBDEV, false)
@ -1835,7 +1798,6 @@ ext/ladspa/Makefile
ext/lv2/Makefile
ext/libmms/Makefile
ext/Makefile
ext/metadata/Makefile
ext/modplug/Makefile
ext/mpeg2enc/Makefile
ext/mimic/Makefile

View file

@ -108,9 +108,6 @@ EXTRA_HFILES = \
$(top_srcdir)/ext/kate/gstkatetiger.h \
$(top_srcdir)/ext/ladspa/gstladspa.h \
$(top_srcdir)/ext/musicbrainz/gsttrm.h \
$(top_srcdir)/ext/metadata/gstbasemetadata.h \
$(top_srcdir)/ext/metadata/gstmetadatademux.h \
$(top_srcdir)/ext/metadata/gstmetadatamux.h \
$(top_srcdir)/ext/mimic/gstmimenc.h \
$(top_srcdir)/ext/mimic/gstmimdec.h \
$(top_srcdir)/ext/modplug/gstmodplug.h \

View file

@ -81,8 +81,6 @@
<xi:include href="xml/element-legacyresample.xml" />
<xi:include href="xml/element-liveadder.xml" />
<xi:include href="xml/element-marble.xml" />
<xi:include href="xml/element-metadatademux.xml" />
<xi:include href="xml/element-metadatamux.xml" />
<xi:include href="xml/element-mimenc.xml" />
<xi:include href="xml/element-mimdec.xml" />
<xi:include href="xml/element-mirror.xml" />
@ -178,7 +176,6 @@
<xi:include href="xml/plugin-ladspa.xml" />
<xi:include href="xml/plugin-liveadder.xml" />
<xi:include href="xml/plugin-lv2.xml" />
<xi:include href="xml/plugin-metadata.xml" />
<xi:include href="xml/plugin-mimic.xml" />
<xi:include href="xml/plugin-mms.xml" />
<xi:include href="xml/plugin-modplug.xml" />
@ -226,11 +223,6 @@
<xi:include href="xml/plugin-zbar.xml" />
</chapter>
<chapter>
<title>gst-plugins-bad Classes</title>
<xi:include href="xml/gstbasemetadata.xml" />
</chapter>
<chapter>
<title>gst-plugins-bad Interfaces</title>
<xi:include href="xml/gstphotography.xml" />

View file

@ -982,33 +982,6 @@ GstLADSPA
GstLADSPAClass
</SECTION>
<SECTION>
<FILE>gstbasemetadata</FILE>
<TITLE>GstBaseMetadata</TITLE>
GstBaseMetadata
GST_BASE_METADATA_SINK_PAD
GST_BASE_METADATA_SRC_PAD
gst_base_metadata_get_option_flag
gst_base_metadata_set_option_flag
gst_base_metadata_unset_option_flag
gst_base_metadata_update_inject_segment_with_new_data
<SUBSECTION Standard>
GstBaseMetadataClass
MetadataState
GST_BASE_METADATA
GST_BASE_METADATA_CLASS
GST_IS_BASE_METADATA
GST_IS_BASE_METADATA_CLASS
GST_BASE_METADATA_GET_CLASS
GST_BASE_METADATA_CAST
GST_TYPE_BASE_METADATA
gst_base_metadata_get_type
GST_BASE_METADATA_EXIF_ADAPTER
GST_BASE_METADATA_IPTC_ADAPTER
GST_BASE_METADATA_XMP_ADAPTER
GST_BASE_METADATA_IMG_TYPE
</SECTION>
<SECTION>
<FILE>element-marble</FILE>
<TITLE>marble</TITLE>
@ -1025,34 +998,6 @@ gst_marble_get_type
gst_marble_plugin_init
</SECTION>
<SECTION>
<FILE>element-metadatademux</FILE>
<TITLE>metadatademux</TITLE>
GstMetadataDemux
<SUBSECTION Standard>
GstMetadataDemuxClass
GST_METADATA_DEMUX
GST_METADATA_DEMUX_CLASS
GST_IS_METADATA_DEMUX
GST_IS_METADATA_DEMUX_CLASS
GST_TYPE_METADATA_DEMUX
gst_metadata_demux_get_type
</SECTION>
<SECTION>
<FILE>element-metadatamux</FILE>
<TITLE>metadatamux</TITLE>
GstMetadataMux
<SUBSECTION Standard>
GstMetadataMuxClass
GST_METADATA_MUX
GST_METADATA_MUX_CLASS
GST_IS_METADATA_MUX
GST_IS_METADATA_MUX_CLASS
GST_TYPE_METADATA_MUX
gst_metadata_mux_get_type
</SECTION>
<SECTION>
<FILE>element-mimdec</FILE>
<TITLE>mimdec</TITLE>

View file

@ -1,55 +0,0 @@
<plugin>
<name>metadata</name>
<description>Metadata (EXIF, IPTC and XMP) image (JPEG, TIFF) demuxer and muxer</description>
<filename>../../ext/metadata/.libs/libgstmetadata.so</filename>
<basename>libgstmetadata.so</basename>
<version>0.10.20.1</version>
<license>LGPL</license>
<source>gst-plugins-bad</source>
<package>GStreamer Bad Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>
<name>metadatademux</name>
<longname>Metadata demuxer</longname>
<class>Demuxer/Extracter/Metadata</class>
<description>Send metadata tags (EXIF, IPTC and XMP) and remove metadata chunks from stream</description>
<author>Edgard Lima &lt;edgard.lima@indt.org.br&gt;</author>
<pads>
<caps>
<name>sink</name>
<direction>sink</direction>
<presence>always</presence>
<details>image/jpeg, tags-extracted=(boolean)false; image/png, tags-extracted=(boolean)false</details>
</caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>image/jpeg, tags-extracted=(boolean)true; image/png, tags-extracted=(boolean)true</details>
</caps>
</pads>
</element>
<element>
<name>metadatamux</name>
<longname>Metadata muxer</longname>
<class>Muxer/Formatter/Metadata</class>
<description>Write metadata (EXIF, IPTC and XMP) into a image stream</description>
<author>Edgard Lima &lt;edgard.lima@indt.org.br&gt;</author>
<pads>
<caps>
<name>sink</name>
<direction>sink</direction>
<presence>always</presence>
<details>image/jpeg, tags-extracted=(boolean)true; image/png, tags-extracted=(boolean)true</details>
</caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>image/jpeg; image/png</details>
</caps>
</pads>
</element>
</elements>
</plugin>

View file

@ -202,12 +202,6 @@ else
MPEG2ENC_DIR=
endif
if USE_METADATA
METADATA_DIR=metadata
else
METADATA_DIR=
endif
if USE_MIMIC
MIMIC_DIR=mimic
else
@ -421,7 +415,6 @@ SUBDIRS=\
$(LIBMMS_DIR) \
$(MODPLUG_DIR) \
$(MPEG2ENC_DIR) \
$(METADATA_DIR) \
$(MIMIC_DIR) \
$(MPLEX_DIR) \
$(MUSEPACK_DIR) \
@ -476,7 +469,6 @@ DIST_SUBDIRS = \
dts \
divx \
modplug \
metadata \
mimic \
mpeg2enc \
mplex \

View file

@ -1,7 +0,0 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

View file

@ -1,39 +0,0 @@
plugin_LTLIBRARIES = libgstmetadata.la
libgstmetadata_la_SOURCES = gstmetadata.c \
gstmetadatademux.c \
metadata.c \
metadataparsejpeg.c \
metadatamuxjpeg.c \
metadataparsepng.c \
metadatamuxpng.c \
metadataexif.c \
metadataiptc.c \
metadataxmp.c \
metadataparseutil.c \
metadatatypes.c \
gstmetadatamux.c \
metadatatags.c \
gstbasemetadata.c
libgstmetadata_la_CFLAGS = $(METADATA_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
libgstmetadata_la_LIBADD = $(METADATA_LIBS) -lgsttag-@GST_MAJORMINOR@ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS)
libgstmetadata_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstmetadata_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstmetadatademux.h \
metadata.h \
metadataparsejpeg.h \
metadatamuxjpeg.h \
metadataparsepng.h \
metadatamuxpng.h \
metadataexif.h \
metadataiptc.h \
metadataxmp.h \
metadataparseutil.h \
metadatatags.h \
metadatatypes.h \
gstmetadatamux.h \
gstbasemetadata.h
EXTRA_DIST = metadata_mapping.htm

View file

@ -1,106 +0,0 @@
### design proposal for metadata mux and parser ###
## use cases ##
1- Create metadata
[ App send tag events to the pipeline ]
|| /\
|| ||
|| jpegenc send tag messages like (width, height and compression info)
|| ||
\/ ||
+---------+ +---------+ +-------------+ +----------+
| v4l2src | -> | jpegenc | -> | metadatamux | -> | filesink |
+---------+ +---------+ +-------------+ +----------+
* elements like videoscale should also send (width and height tags)
* should metadatamux get info from caps (width and height) and use if not receive a event with such tags?
2- View metadata
+---------+ +---------------+ +---------+ +-------------+
| filesrc | -> | metadataparse | -> | jpegdec | -> | xvimagesink |
+---------+ +---------------+ +---------+ +-------------+
or
+--> whole chunk send as event to next element
|
+---------+ +---------------+ +----------+
| filesrc | -> | metadataparse | -> | fakesink |
+---------+ +---------------+ +----------+
||
\/
1- individual tags send as messages (what about not mapped tags??)
2- whole chunk send as message (probably the application will ignore this)
* in any case metadataparse strips out metadata chunks (different from current implementation)
3- Modify (add, change, delete tags)
+--> whole chunk send as event to next element -- ... --+
| |
| V
+---------+ +---------------+ +-------------+ +----------+
| filesrc | -> | metadataparse | --------------- ... --------------> | metadatamux | -> | filesink |
+---------+ +---------------+ +-------------+ +----------+
/\ ||
|| \/
|| 1- individual tags send as messages (what about not mapped tags??) ==============\\
|| 2- whole chunk send as message (probably the application will ignore this) ||
|| ||
[ App send tag events to the pipeline ] <=======================================================//
* metadataparse strips out metadata chunks (different from current implementation)
* application receives individual tag messages (what about not mapped ones?)
* the application only send events back to the pipeline for the tags the application wants to modify or keep.
The tags not sent will not be included in metadata chunks
* the metadatamux modify the whole chunk event received before to just keep the individual tags sent by application
* the metadatamux could have a property to say if it should remove or keep tags not sent by application.
Obs: By looking at the proposed design (1- view and 2- modify) seems that the metadataparse and metadatamux should not know about mapped tags.
Only the application map the tags to/from metadata specific format. This is because, if you notice, only tags sent by application will be keep
on new file.
4- Convert (for example from jpeg to png)
+--> whole chunk send as event to next element -- ... --+
| |
| V
+---------+ +---------------+ +-------------+ +----------+
| filesrc | -> | metadataparse | -> | jpegdec | -> ... -> | pngenc | -> | metadatamux | -> | filesink |
+---------+ +---------------+ +-------------+ +----------+
/\ ||
|| \/
|| 1- individual tags send as messages (what about not mapped tags??) ==============\\
|| 2- whole chunk send as message (probably the application will ignore this) ||
|| ||
[ App send tag events to the pipeline ] <=======================================================//
* in this case the application set the metadatamux property to always keep the tags by default (application don't not need to send tag events)
* metadatamux needs additional smartness to check what tags still does make sense (some from original jpeg may not make sense anymore)
* if the image is resized, the videoscale should send messages to the application with new width (in the same way pngenc should also) and the
application could send width and height tag events to the pipeline
* should metadatamux get info from caps (width and height) and use if not receive a event with such tags?
Testing
GST_DEBUG="*:2,metadata*:4"
gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=66.1,geo-location-longitude=22.5,geo-location-elevation=10.3" ! metadatamux ! filesink location="meta_test_ppp.jpeg"
gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=66.1,geo-location-longitude=22.5,geo-location-elevation=-10.3" ! metadatamux ! filesink location="meta_test_ppn.jpeg"
gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=66.1,geo-location-longitude=-22.5,geo-location-elevation=10.3" ! metadatamux ! filesink location="meta_test_pnp.jpeg"
gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=66.1,geo-location-longitude=-22.5,geo-location-elevation=-10.3" ! metadatamux ! filesink location="meta_test_pnn.jpeg"
gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=-66.1,geo-location-longitude=22.5,geo-location-elevation=10.3" ! metadatamux ! filesink location="meta_test_npp.jpeg"
gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=-66.1,geo-location-longitude=22.5,geo-location-elevation=-10.3" ! metadatamux ! filesink location="meta_test_npn.jpeg"
gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=-66.1,geo-location-longitude=-22.5,geo-location-elevation=10.3" ! metadatamux ! filesink location="meta_test_nnp.jpeg"
gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=-66.1,geo-location-longitude=-22.5,geo-location-elevation=-10.3" ! metadatamux ! filesink location="meta_test_nnn.jpeg"
exiv2 -pt pr meta_test_ppp.jpeg | grep "Exif.GPSInfo"
exif meta_test_ppp.jpeg
gst-launch -t filesrc location="meta_test_ppp.jpeg" ! metadatademux ! fakesink

View file

@ -1,56 +0,0 @@
This file contains a list of things to be done as well some open issues (questions) related to design/implementation.
INFO:
1- To see the list of tags current mapped:
http://webcvs.freedesktop.org/gstreamer/gst-plugins-bad/ext/metadata/metadata_mapping.htm?view=co
TODO:
1- Add more individual tags to XMP, EXIF and IPTC
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)
5- Improve the test application (to save also in png and to make it possible to set the metadata elements properties)
6- Implement GDateTime support in GLib to be used by GStreamer (http://bugzilla.gnome.org/show_bug.cgi?id=50076)
7- Use a standard GStreamer Data-Time type to map our Data-time tags
8- Make the correct merge mode for multiple value tags (bag and seq) like dc:creator, ...
OPEN ISSUES:
1- What is (How) the best way to delete some tag?
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- In EXIF, how to make sure we are compliant with the specification when adding some tag? For example, we are not considerinb what are mandatory (or optional) IFDs for tags.
4- Add GST_TYPE_FRACTION support for GStreamer TAGS
5- currently, in JPEG files, if there is a Photoshop segment, everything inside it but IPTC will be lost. From the point of view of implementation it is easy, but I still don't now how to solve from the point of view of "designing". Anyway I think it is not so important.
6- language is not considered in XMP (How to do it with GStreamer?)
7- Add a helper function that convert from value to string. For example,
aperture-size is 2.7 and the app wants to show "f/2.7", 'contrast' is a range
and the app wants to show as "Normal", "Soft", "Hard". For the time being it is
up to the APP to make this conversion.
LINKS IN BUGZILA
1- to move to good
http://bugzilla.gnome.org/show_bug.cgi?id=513182
2- Proposal of new tags
http://bugzilla.gnome.org/show_bug.cgi?id=482947
http://bugzilla.gnome.org/show_bug.cgi?id=481169
3- Discussion about the architecture
http://bugzilla.gnome.org/show_bug.cgi?id=486659
KNOWN BUGS
bugs in libexif:
1- https://sourceforge.net/tracker/?func=detail&atid=112272&aid=1884609&group_id=12272
a- EXIF_TAG_ISO_SPEED_RATINGS should be in EXIF_IFD_EXIF
b- EXIF_TAG_ISO_SPEED_RATINGS is not inserted anyway
2- EXIF_TAG_FLASH can't be written from the scratch
3- GST_TAG_CAPTURE_COLOR_SPACE can't be written from the scratch

File diff suppressed because it is too large Load diff

View file

@ -1,209 +0,0 @@
/*
* 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_BASE_METADATA_H__
#define __GST_BASE_METADATA_H__
#include <gst/gst.h>
#include "metadata.h"
G_BEGIN_DECLS
/* *INDENT-OFF* */
#define GST_TYPE_BASE_METADATA (gst_base_metadata_get_type())
#define GST_BASE_METADATA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
GST_TYPE_BASE_METADATA,GstBaseMetadata))
#define GST_BASE_METADATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\
GST_TYPE_BASE_METADATA,GstBaseMetadataClass))
#define GST_BASE_METADATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
GST_TYPE_BASE_METADATA, GstBaseMetadataClass))
#define GST_IS_BASE_METADATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
GST_TYPE_BASE_METADATA))
#define GST_IS_BASE_METADATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
GST_TYPE_BASE_METADATA))
#define GST_BASE_METADATA_CAST(obj) ((GstBaseMetadata *)(obj))
/* *INDENT-ON* */
typedef struct _GstBaseMetadata GstBaseMetadata;
typedef struct _GstBaseMetadataClass GstBaseMetadataClass;
enum {
BASE_METADATA_DEMUXING,
BASE_METADATA_MUXING
};
/*
* GST_BASE_METADATA_SRC_PAD:
* @obj: base metadata instance
*
* Gives the pointer to the #GstPad object of the element.
*/
#define GST_BASE_METADATA_SRC_PAD(obj) (GST_BASE_METADATA_CAST (obj)->srcpad)
/*
* GST_BASE_METADATA_SINK_PAD:
* @obj: base metadata instance
*
* Gives the pointer to the #GstPad object of the element.
*/
#define GST_BASE_METADATA_SINK_PAD(obj) (GST_BASE_METADATA_CAST (obj)->sinkpad)
/*
* GST_BASE_METADATA_EXIF_ADAPTER
* @obj: base metadata instance
*
* Gives the pointer to the EXIF #GstAdapter of the element.
*/
#define GST_BASE_METADATA_EXIF_ADAPTER(obj) \
(GST_BASE_METADATA_CAST (obj)->metadata->exif_adapter)
/*
* GST_BASE_METADATA_IPTC_ADAPTER
* @obj: base metadata instance
*
* Gives the pointer to the IPTC #GstAdapter of the element.
*/
#define GST_BASE_METADATA_IPTC_ADAPTER(obj) \
(GST_BASE_METADATA_CAST (obj)->metadata->iptc_adapter)
/*
* GST_BASE_METADATA_XMP_ADAPTER
* @obj: base metadata instance
*
* Gives the pointer to the XMP #GstAdapter of the element.
*/
#define GST_BASE_METADATA_XMP_ADAPTER(obj) \
(GST_BASE_METADATA_CAST (obj)->metadata->xmp_adapter)
/*
* GST_BASE_METADATA_IMG_TYPE
* @obj: base metadata instance
*
* Gives the type indentified by the parser of the element.
*/
#define GST_BASE_METADATA_IMG_TYPE(obj) \
(GST_BASE_METADATA_CAST (obj)->img_type)
typedef enum _MetadataState
{
MT_STATE_NULL, /* still need to check media type */
MT_STATE_PARSED
} MetadataState;
/**
* GstBaseMetadata:
*
* The opaque #GstBaseMetadata data structure.
*/
struct _GstBaseMetadata
{
GstElement element;
/*< protected >*/
GstPad *sinkpad, *srcpad;
MetaData *metadata; /* handle for parsing module */
ImageType img_type;
/*< private >*/
gint64 duration_orig; /* durarion of stream */
gint64 duration; /* durarion of modified stream */
MetadataState state;
MetaOptions options;
gboolean need_processing; /* still need a action before send first buffer */
GstAdapter *adapter_parsing;
GstAdapter *adapter_holding;
guint32 next_offset;
guint32 next_size;
gboolean need_more_data;
gint64 offset_orig; /* offset in original stream */
gint64 offset; /* offset in current stream */
GstBuffer * append_buffer;
GstBuffer * prepend_buffer;
};
struct _GstBaseMetadataClass
{
GstElementClass parent_class;
void (*processing) (GstBaseMetadata *basemetadata);
gboolean (*set_caps) (GstPad * pad, GstCaps * caps);
GstCaps* (*get_src_caps) (GstPad * pad);
GstCaps* (*get_sink_caps) (GstPad * pad);
gboolean (*sink_event) (GstPad * pad, GstEvent * event);
};
extern GType
gst_base_metadata_get_type (void);
extern void
gst_base_metadata_set_option_flag(GstBaseMetadata *base,
const MetaOptions options);
extern void
gst_base_metadata_unset_option_flag(GstBaseMetadata *base,
const MetaOptions options);
extern MetaOptions
gst_base_metadata_get_option_flag(const GstBaseMetadata *base);
extern void
gst_base_metadata_update_inject_segment_with_new_data (GstBaseMetadata *base,
guint8 ** data, guint32 * size, MetadataChunkType type);
G_END_DECLS
#endif /* __GST_BASE_METADATA_H__ */

View file

@ -1,85 +0,0 @@
/*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include "gstmetadatademux.h"
#include "gstmetadatamux.h"
#include "metadatatags.h"
GST_DEBUG_CATEGORY_EXTERN (gst_metadata_exif_debug);
GST_DEBUG_CATEGORY_EXTERN (gst_metadata_iptc_debug);
GST_DEBUG_CATEGORY_EXTERN (gst_metadata_xmp_debug);
static gboolean
plugin_init (GstPlugin * plugin)
{
gboolean ret = TRUE;
GST_DEBUG_CATEGORY_INIT (gst_metadata_exif_debug, "metadata_exif",
0, "Metadata exif");
GST_DEBUG_CATEGORY_INIT (gst_metadata_iptc_debug, "metadata_iptc",
0, "Metadata iptc");
GST_DEBUG_CATEGORY_INIT (gst_metadata_xmp_debug, "metadata_xmp", 0,
"Metadata xmp");
metadata_tags_register ();
ret = gst_metadata_demux_plugin_init (plugin);
ret = ret && gst_metadata_mux_plugin_init (plugin);
return ret;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"metadata",
"Metadata (EXIF, IPTC and XMP) image (JPEG, TIFF) demuxer and muxer",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,538 +0,0 @@
/*
* 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: element-metadatademux
* @see_also: #metadatamux
*
* <refsect2>
* <para>
* This element parses image files JPEG and PNG, to find metadata chunks (EXIF,
* IPTC, XMP) in it, and then send individual tags as a 'tag message' do the
* application and as 'tag event' to the next element in pipeline. It also
* strips out the metadata chunks from original stream (unless the 'parse-only'
* property is set to 'true'). In addition the whole metadata chunk (striped
* or not) it also sent as a message to the application bus, so the application
* can have more controls about the metadata.
* </para>
* <title>Example launch line</title>
* <para>
* <programlisting>
* gst-launch -v -m filesrc location=./test.jpeg ! metadatademux ! fakesink
* silent=TRUE
* </programlisting>
* <programlisting>
* GST_DEBUG:*metadata:5 gst-launch filesrc location=./test.jpeg !
* metadatademux ! fakesink
* </programlisting>
* </para>
* <title>Application sample code using 'libexif' to have more control</title>
* <para>
* <programlisting>
* val = gst_tag_list_get_value_index (taglist, GST_TAG_EXIF, 0);
* if (val) {
* exif_chunk = gst_value_get_buffer (val);
* if (exif_chunk) {
* ed = exif_data_new_from_data (GST_BUFFER_DATA (exif_chunk),
* GST_BUFFER_SIZE (exif_chunk));
* }
* }
* </programlisting>
* This same idea can be used to handle IPTC and XMP directly by using
* libdata and exempi (or any other libraries). Notice: the whole metadata
* chunk sent as a message to the application contains only metadata data, i.e.
* the wrapper specific to the file format (JPEG, PNG, ...) is already
* striped out.
* </para>
* </refsect2>
*/
/*
* includes
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gst/gst.h>
#include "gstmetadatademux.h"
#include "metadataexif.h"
#include "metadataiptc.h"
#include "metadataxmp.h"
#include <string.h>
/*
* enum and types
*/
enum
{
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_PARSE_ONLY
};
/*
* defines and static global vars
*/
GST_DEBUG_CATEGORY (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)
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("image/jpeg, "
"tags-extracted = (bool) false;"
"image/png, " "tags-extracted = (bool) false")
);
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("image/jpeg, "
"tags-extracted = (bool) true;"
"image/png, " "tags-extracted = (bool) true")
);
static GstMetadataDemuxClass *metadata_parent_class = NULL;
/*
* static helper functions declaration
*/
static gboolean
gst_metadata_demux_configure_srccaps (GstMetadataDemux * filter);
/*
* GObject callback functions declaration
*/
static void gst_metadata_demux_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_metadata_demux_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
/*
* GstBaseMetadata virtual functions declaration
*/
static void gst_metadata_demux_send_tags (GstBaseMetadata * base);
static gboolean gst_metadata_demux_set_caps (GstPad * pad, GstCaps * caps);
static GstCaps *gst_metadata_demux_get_caps (GstPad * pad);
static gboolean gst_metadata_demux_sink_event (GstPad * pad, GstEvent * event);
/*
* GST BOILERPLATE
*/
GST_BOILERPLATE (GstMetadataDemux, gst_metadata_demux, GstBaseMetadata,
GST_TYPE_BASE_METADATA);
/*
* static helper functions implementation
*/
static gboolean
gst_metadata_demux_configure_srccaps (GstMetadataDemux * filter)
{
GstCaps *caps = NULL;
gboolean ret = FALSE;
const gchar *mime = NULL;
switch (GST_BASE_METADATA_IMG_TYPE (filter)) {
case IMG_JPEG:
mime = "image/jpeg";
break;
case IMG_PNG:
mime = "image/png";
break;
default:
ret = FALSE;
goto done;
break;
}
caps =
gst_caps_new_simple (mime, "tags-extracted", G_TYPE_BOOLEAN, TRUE, NULL);
ret = gst_pad_set_caps (GST_BASE_METADATA_SRC_PAD (filter), caps);
done:
if (caps) {
gst_caps_unref (caps);
caps = NULL;
}
return ret;
}
/*
* GObject callback functions implementation
*/
static void
gst_metadata_demux_base_init (gpointer gclass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details_simple (element_class, "Metadata demuxer",
"Demuxer/Extracter/Metadata",
"Send metadata tags (EXIF, IPTC and XMP) and "
"remove metadata chunks from stream",
"Edgard Lima <edgard.lima@indt.org.br>");
}
static void
gst_metadata_demux_class_init (GstMetadataDemuxClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseMetadataClass *gstbasemetadata_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasemetadata_class = (GstBaseMetadataClass *) klass;
metadata_parent_class = g_type_class_peek_parent (klass);
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_PARSE_ONLY,
g_param_spec_boolean ("parse-only", "parse-only",
"If TRUE, don't strip out any chunk", FALSE, G_PARAM_READWRITE));
gstbasemetadata_class->processing =
GST_DEBUG_FUNCPTR (gst_metadata_demux_send_tags);
gstbasemetadata_class->set_caps =
GST_DEBUG_FUNCPTR (gst_metadata_demux_set_caps);
gstbasemetadata_class->get_sink_caps =
GST_DEBUG_FUNCPTR (gst_metadata_demux_get_caps);
gstbasemetadata_class->get_src_caps =
GST_DEBUG_FUNCPTR (gst_metadata_demux_get_caps);
gstbasemetadata_class->sink_event =
GST_DEBUG_FUNCPTR (gst_metadata_demux_sink_event);
}
static void
gst_metadata_demux_init (GstMetadataDemux * filter,
GstMetadataDemuxClass * gclass)
{
gst_base_metadata_set_option_flag (GST_BASE_METADATA (filter),
META_OPT_EXIF | META_OPT_IPTC | META_OPT_XMP | META_OPT_DEMUX);
}
static void
gst_metadata_demux_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
case ARG_PARSE_ONLY:
if (g_value_get_boolean (value))
gst_base_metadata_set_option_flag (GST_BASE_METADATA (object),
META_OPT_PARSE_ONLY);
else
gst_base_metadata_unset_option_flag (GST_BASE_METADATA (object),
META_OPT_PARSE_ONLY);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_metadata_demux_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
guint8 option =
gst_base_metadata_get_option_flag (GST_BASE_METADATA (object));
switch (prop_id) {
case ARG_PARSE_ONLY:
g_value_set_boolean (value, option & META_OPT_PARSE_ONLY);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/*
* GstBaseMetadata virtual functions implementation
*/
/*
* gst_metadata_demux_send_tags:
* @base: the base metadata instance
*
* Send individual tags as message to the bus and as event to the next
* element, and send the whole metadata chunk (with file specific wrapper
* striped) to the next element as a event.
*
* Returns: nothing
*
*/
static void
gst_metadata_demux_send_tags (GstBaseMetadata * base)
{
GstMetadataDemux *filter = GST_METADATA_DEMUX (base);
GstMessage *msg;
GstTagList *taglist = gst_tag_list_new ();
GstEvent *event;
GstPad *srcpad = GST_BASE_METADATA_SRC_PAD (filter);
/* get whole chunk */
if (gst_base_metadata_get_option_flag (base) & META_OPT_EXIF)
metadataparse_exif_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
GST_BASE_METADATA_EXIF_ADAPTER (base), METADATA_TAG_MAP_WHOLECHUNK);
if (gst_base_metadata_get_option_flag (base) & META_OPT_IPTC)
metadataparse_iptc_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
GST_BASE_METADATA_IPTC_ADAPTER (base), METADATA_TAG_MAP_WHOLECHUNK);
if (gst_base_metadata_get_option_flag (base) & META_OPT_XMP)
metadataparse_xmp_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
GST_BASE_METADATA_XMP_ADAPTER (base), METADATA_TAG_MAP_WHOLECHUNK);
if (taglist && !gst_tag_list_is_empty (taglist)) {
msg =
gst_message_new_tag (GST_OBJECT (filter), gst_tag_list_copy (taglist));
gst_element_post_message (GST_ELEMENT (filter), msg);
event = gst_event_new_tag (taglist);
gst_pad_push_event (srcpad, event);
taglist = NULL;
}
if (!taglist)
taglist = gst_tag_list_new ();
/*get individual tags */
if (gst_base_metadata_get_option_flag (base) & META_OPT_EXIF)
metadataparse_exif_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
GST_BASE_METADATA_EXIF_ADAPTER (base), METADATA_TAG_MAP_INDIVIDUALS);
if (gst_base_metadata_get_option_flag (base) & META_OPT_IPTC)
metadataparse_iptc_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
GST_BASE_METADATA_IPTC_ADAPTER (base), METADATA_TAG_MAP_INDIVIDUALS);
if (gst_base_metadata_get_option_flag (base) & META_OPT_XMP)
metadataparse_xmp_tag_list_add (taglist, GST_TAG_MERGE_KEEP,
GST_BASE_METADATA_XMP_ADAPTER (base), METADATA_TAG_MAP_INDIVIDUALS);
if (taglist && !gst_tag_list_is_empty (taglist)) {
msg = gst_message_new_tag (GST_OBJECT (filter), taglist);
gst_element_post_message (GST_ELEMENT (filter), msg);
taglist = NULL;
}
if (taglist)
gst_tag_list_free (taglist);
}
static gboolean
gst_metadata_demux_set_caps (GstPad * pad, GstCaps * caps)
{
GstMetadataDemux *filter = NULL;
GstStructure *structure = NULL;
const gchar *mime = NULL;
gboolean ret = FALSE;
gboolean based = TRUE;
filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad));
structure = gst_caps_get_structure (caps, 0);
mime = gst_structure_get_name (structure);
if (strcmp (mime, "image/jpeg") == 0) {
GST_BASE_METADATA_IMG_TYPE (filter) = IMG_JPEG;
} else if (strcmp (mime, "image/png") == 0) {
GST_BASE_METADATA_IMG_TYPE (filter) = IMG_PNG;
} else {
ret = FALSE;
goto done;
}
if (gst_structure_get_boolean (structure, "tags-extracted", &based)) {
if (based == TRUE) {
ret = FALSE;
goto done;
}
}
ret = gst_metadata_demux_configure_srccaps (filter);
done:
gst_object_unref (filter);
return ret;
}
static GstCaps *
gst_metadata_demux_get_caps (GstPad * pad)
{
GstMetadataDemux *filter = NULL;
GstPad *otherpad;
GstCaps *caps_new = NULL;
GstCaps *caps_otherpad_peer = NULL;
filter = GST_METADATA_DEMUX (gst_pad_get_parent (pad));
(GST_BASE_METADATA_SRC_PAD (filter) == pad) ?
(otherpad = GST_BASE_METADATA_SINK_PAD (filter)) :
(otherpad = GST_BASE_METADATA_SRC_PAD (filter));
caps_new = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
caps_otherpad_peer = gst_pad_get_allowed_caps (otherpad);
GOTO_DONE_IF_NULL (caps_otherpad_peer);
if (gst_caps_is_empty (caps_otherpad_peer)
|| gst_caps_is_any (caps_otherpad_peer)) {
goto done;
} else {
guint i;
guint caps_size = 0;
caps_size = gst_caps_get_size (caps_otherpad_peer);
gst_caps_unref (caps_new);
caps_new = gst_caps_new_empty ();
for (i = 0; i < caps_size; ++i) {
GstStructure *structure = NULL;
GstStructure *structure_new = NULL;
const gchar *mime = NULL;
structure = gst_caps_get_structure (caps_otherpad_peer, i);
mime = gst_structure_get_name (structure);
if (pad == GST_BASE_METADATA_SINK_PAD (filter)) {
structure_new =
gst_structure_new (mime, "tags-extracted", G_TYPE_BOOLEAN, FALSE,
NULL);
} else {
structure_new =
gst_structure_new (mime, "tags-extracted", G_TYPE_BOOLEAN, TRUE,
NULL);
}
gst_caps_append_structure (caps_new, structure_new);
}
}
done:
if (caps_otherpad_peer) {
gst_caps_unref (caps_otherpad_peer);
caps_otherpad_peer = NULL;
}
gst_object_unref (filter);
return caps_new;
}
static gboolean
gst_metadata_demux_sink_event (GstPad * pad, GstEvent * event)
{
return gst_pad_event_default (pad, event);
}
/*
* element plugin init function
*/
gboolean
gst_metadata_demux_plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_metadata_demux_debug, "metadatademux", 0,
"Metadata demuxer");
return gst_element_register (plugin, "metadatademux",
GST_RANK_NONE, GST_TYPE_METADATA_DEMUX);
}

View file

@ -1,92 +0,0 @@
/*
* 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_DEMUX_H__
#define __GST_METADATA_DEMUX_H__
#include <gst/gst.h>
#include "gstbasemetadata.h"
G_BEGIN_DECLS
/* *INDENT-OFF* */
#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))
/* *INDENT-ON* */
typedef struct _GstMetadataDemux GstMetadataDemux;
typedef struct _GstMetadataDemuxClass GstMetadataDemuxClass;
/**
* GstMetadataDemux:
*
* The opaque #GstMetadataDemux data structure.
*/
struct _GstMetadataDemux
{
GstBaseMetadata metadata;
};
struct _GstMetadataDemuxClass
{
GstBaseMetadataClass parent_class;
};
GType gst_metadata_demux_get_type (void);
gboolean gst_metadata_demux_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* __GST_METADATA_DEMUX_H__ */

View file

@ -1,581 +0,0 @@
/*
* 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: element-metadatamux
*
* <refsect2>
* <para>
* This element writes tags into metadata (EXIF, IPTC and XMP) chunks, and
* writes the chunks into image files (JPEG, PNG). Tags the are received as
* GST_EVENT_TAG event or set by the application using #GstTagSetter interface.
* </para>
* <title>Example launch line</title>
* <para>
* <programlisting>
* gst-launch -v -m filesrc location=orig.jpeg ! metadatamux ! filesink
* location=dest.jpeg
* </programlisting>
* <programlisting>
* gst-launch -v -m filesrc location=orig.png ! metadatademux ! pngdec !
* ffmpegcolorspace ! jpegenc ! metadatamux ! filesink location=dest.jpeg
* </programlisting>
* </para>
* <title>How it works</title>
* <para>
* If this element receives a GST_TAG_EXIF, GST_TAG_IPTC or GST_TAG_XMP which
* are whole chunk metadata tags, then this whole chunk will be modified by
* individual tags received and written to the file. Otherwise, a new chunk
* will be created from the scratch and then modified in same way.
* </para>
* </refsect2>
*/
/*
* includes
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gst/gst.h>
#include "gstmetadatamux.h"
#include "metadataiptc.h"
#include "metadataxmp.h"
#include <string.h>
/*
* enum and types
*/
enum
{
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_EXIF_BYTE_ORDER,
};
/*
* defines and static global vars
*/
GST_DEBUG_CATEGORY (gst_metadata_mux_debug);
#define GST_CAT_DEFAULT gst_metadata_mux_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)
#define DEFAULT_EXIF_BYTE_ORDER GST_META_EXIF_BYTE_ORDER_MOTOROLA
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("image/jpeg, tags-extracted = (bool) true;"
"image/png, tags-extracted = (bool) true")
);
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("image/jpeg; " "image/png")
);
static GstMetadataMuxClass *metadata_parent_class = NULL;
/*
* static helper functions declaration
*/
static gboolean gst_metadata_mux_configure_srccaps (GstMetadataMux * filter);
/*
* GObject callback functions declaration
*/
static void gst_metadata_mux_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_metadata_mux_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstStateChangeReturn gst_metadata_mux_change_state (GstElement * element,
GstStateChange transition);
/*
* GstBaseMetadata virtual functions declaration
*/
static void gst_metadata_mux_create_chunks_from_tags (GstBaseMetadata * base);
static gboolean gst_metadata_mux_set_caps (GstPad * pad, GstCaps * caps);
static GstCaps *gst_metadata_mux_get_caps (GstPad * pad);
static gboolean gst_metadata_mux_sink_event (GstPad * pad, GstEvent * event);
/*
* GST BOILERPLATE
*/
static void
gst_metadata_mux_add_interfaces (GType type)
{
static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
}
GST_BOILERPLATE_FULL (GstMetadataMux, gst_metadata_mux, GstBaseMetadata,
GST_TYPE_BASE_METADATA, gst_metadata_mux_add_interfaces);
/*
* static helper functions implementation
*/
static gboolean
gst_metadata_mux_configure_srccaps (GstMetadataMux * filter)
{
GstCaps *caps = NULL;
gboolean ret = FALSE;
const gchar *mime = NULL;
switch (GST_BASE_METADATA_IMG_TYPE (filter)) {
case IMG_JPEG:
mime = "image/jpeg";
break;
case IMG_PNG:
mime = "image/png";
break;
default:
ret = FALSE;
goto done;
break;
}
caps = gst_caps_new_simple (mime, NULL);
ret = gst_pad_set_caps (GST_BASE_METADATA_SRC_PAD (filter), caps);
done:
if (caps) {
gst_caps_unref (caps);
caps = NULL;
}
return ret;
}
/*
* GObject callback functions declaration
*/
static void
gst_metadata_mux_base_init (gpointer gclass)
{
/* *INDENT-ON* */
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details_simple (element_class, "Metadata muxer",
"Muxer/Formatter/Metadata",
"Write metadata (EXIF, IPTC and XMP) into a image stream",
"Edgard Lima <edgard.lima@indt.org.br>");
}
static void
gst_metadata_mux_class_init (GstMetadataMuxClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseMetadataClass *gstbasemetadata_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasemetadata_class = (GstBaseMetadataClass *) klass;
metadata_parent_class = g_type_class_peek_parent (klass);
gobject_class->set_property = gst_metadata_mux_set_property;
gobject_class->get_property = gst_metadata_mux_get_property;
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_metadata_mux_change_state);
gstbasemetadata_class->processing =
GST_DEBUG_FUNCPTR (gst_metadata_mux_create_chunks_from_tags);
gstbasemetadata_class->set_caps =
GST_DEBUG_FUNCPTR (gst_metadata_mux_set_caps);
gstbasemetadata_class->get_sink_caps =
GST_DEBUG_FUNCPTR (gst_metadata_mux_get_caps);
gstbasemetadata_class->get_src_caps =
GST_DEBUG_FUNCPTR (gst_metadata_mux_get_caps);
gstbasemetadata_class->sink_event =
GST_DEBUG_FUNCPTR (gst_metadata_mux_sink_event);
/**
* GstMetadataMux:exif-byte-order:
*
* Set byte-order for exif metadata writing.
*
* Since: 0.10.11
*/
g_object_class_install_property (gobject_class, ARG_EXIF_BYTE_ORDER,
g_param_spec_enum ("exif-byte-order", "Exif byte-order",
"Byte-order for exif metadata writing", GST_TYPE_META_EXIF_BYTE_ORDER,
DEFAULT_EXIF_BYTE_ORDER, G_PARAM_READWRITE));
}
static void
gst_metadata_mux_init (GstMetadataMux * filter, GstMetadataMuxClass * gclass)
{
gst_base_metadata_set_option_flag (GST_BASE_METADATA (filter),
META_OPT_EXIF | META_OPT_IPTC | META_OPT_XMP | META_OPT_MUX);
filter->exif_options.byteorder = DEFAULT_EXIF_BYTE_ORDER;
}
static void
gst_metadata_mux_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstMetadataMux *filter = GST_METADATA_MUX (object);
switch (prop_id) {
case ARG_EXIF_BYTE_ORDER:
filter->exif_options.byteorder = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_metadata_mux_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstMetadataMux *filter = GST_METADATA_MUX (object);
switch (prop_id) {
case ARG_EXIF_BYTE_ORDER:
g_value_set_enum (value, filter->exif_options.byteorder);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstStateChangeReturn
gst_metadata_mux_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
GstMetadataMux *filter = GST_METADATA_MUX (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_tag_setter_reset_tags (GST_TAG_SETTER (filter));
break;
case GST_STATE_CHANGE_READY_TO_NULL:
break;
default:
break;
}
return ret;
}
/*
* GstBaseMetadata virtual functions implementation
*/
/*
* gst_metadata_mux_create_chunks_from_tags:
* @base: the base metadata instance
*
* This function creates new metadata (EXIF, IPTC, XMP) chunks with the tags
* received and add it to the list of segments that will be injected to the
* resulting file by #GstBaseMetadata.
*
* Returns: nothing
*
*/
static void
gst_metadata_mux_create_chunks_from_tags (GstBaseMetadata * base)
{
GstMetadataMux *filter = GST_METADATA_MUX (base);
GstTagSetter *setter = GST_TAG_SETTER (filter);
const GstTagList *taglist = gst_tag_setter_get_tag_list (setter);
GST_DEBUG_OBJECT (base, "Creating chunks from tags..");
if (taglist) {
guint8 *buf = NULL;
guint32 size = 0;
if (gst_base_metadata_get_option_flag (base) & META_OPT_EXIF) {
GST_DEBUG_OBJECT (base, "Using EXIF");
metadatamux_exif_create_chunk_from_tag_list (&buf, &size, taglist,
&filter->exif_options);
gst_base_metadata_update_inject_segment_with_new_data (base, &buf, &size,
MD_CHUNK_EXIF);
g_free (buf);
buf = NULL;
size = 0;
}
if (gst_base_metadata_get_option_flag (base) & META_OPT_IPTC) {
GST_DEBUG_OBJECT (base, "Using IPTC");
metadatamux_iptc_create_chunk_from_tag_list (&buf, &size, taglist);
gst_base_metadata_update_inject_segment_with_new_data (base, &buf, &size,
MD_CHUNK_IPTC);
g_free (buf);
buf = NULL;
size = 0;
}
if (gst_base_metadata_get_option_flag (base) & META_OPT_XMP) {
GST_DEBUG_OBJECT (base, "Using XMP");
metadatamux_xmp_create_chunk_from_tag_list (&buf, &size, taglist);
gst_base_metadata_update_inject_segment_with_new_data (base, &buf, &size,
MD_CHUNK_XMP);
g_free (buf);
}
} else {
GST_DEBUG_OBJECT (base, "Empty taglist");
}
}
static gboolean
gst_metadata_mux_set_caps (GstPad * pad, GstCaps * caps)
{
GstMetadataMux *filter = NULL;
GstStructure *structure = NULL;
const gchar *mime = NULL;
gboolean ret = FALSE;
gboolean based = TRUE;
filter = GST_METADATA_MUX (gst_pad_get_parent (pad));
structure = gst_caps_get_structure (caps, 0);
mime = gst_structure_get_name (structure);
if (strcmp (mime, "image/jpeg") == 0) {
GST_BASE_METADATA_IMG_TYPE (filter) = IMG_JPEG;
} else if (strcmp (mime, "image/png") == 0) {
GST_BASE_METADATA_IMG_TYPE (filter) = IMG_PNG;
} else {
ret = FALSE;
goto done;
}
if (gst_structure_get_boolean (structure, "tags-extracted", &based)) {
if (based == FALSE) {
ret = FALSE;
goto done;
}
}
ret = gst_metadata_mux_configure_srccaps (filter);
done:
gst_object_unref (filter);
return ret;
}
static GstCaps *
gst_metadata_mux_get_caps (GstPad * pad)
{
GstMetadataMux *filter = NULL;
GstPad *otherpad;
GstCaps *caps_new = NULL;
GstCaps *caps_otherpad_peer = NULL;
filter = GST_METADATA_MUX (gst_pad_get_parent (pad));
(GST_BASE_METADATA_SRC_PAD (filter) == pad) ?
(otherpad = GST_BASE_METADATA_SINK_PAD (filter)) :
(otherpad = GST_BASE_METADATA_SRC_PAD (filter));
caps_new = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
caps_otherpad_peer = gst_pad_get_allowed_caps (otherpad);
GOTO_DONE_IF_NULL (caps_otherpad_peer);
if (gst_caps_is_empty (caps_otherpad_peer)
|| gst_caps_is_any (caps_otherpad_peer)) {
goto done;
} else {
guint i;
guint caps_size = 0;
caps_size = gst_caps_get_size (caps_otherpad_peer);
gst_caps_unref (caps_new);
caps_new = gst_caps_new_empty ();
for (i = 0; i < caps_size; ++i) {
GstStructure *structure = NULL;
GstStructure *structure_new = NULL;
const gchar *mime = NULL;
structure = gst_caps_get_structure (caps_otherpad_peer, i);
mime = gst_structure_get_name (structure);
if (pad == GST_BASE_METADATA_SINK_PAD (filter)) {
structure_new =
gst_structure_new (mime, "tags-extracted", G_TYPE_BOOLEAN, TRUE,
NULL);
} else {
structure_new = gst_structure_new (mime, NULL);
}
gst_caps_append_structure (caps_new, structure_new);
}
}
done:
if (caps_otherpad_peer) {
gst_caps_unref (caps_otherpad_peer);
caps_otherpad_peer = NULL;
}
gst_object_unref (filter);
return caps_new;
}
static gboolean
gst_metadata_mux_sink_event (GstPad * pad, GstEvent * event)
{
GstMetadataMux *filter = NULL;
gboolean ret = FALSE;
filter = GST_METADATA_MUX (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_TAG:
{
GstTagList *taglist;
GstTagSetter *setter = GST_TAG_SETTER (filter);
const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
gst_event_parse_tag (event, &taglist);
gst_tag_setter_merge_tags (setter, taglist, mode);
break;
}
default:
break;
}
ret = gst_pad_event_default (pad, event);
gst_object_unref (filter);
return ret;
}
/*
* element plugin init function
*/
gboolean
gst_metadata_mux_plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_metadata_mux_debug, "metadatamux", 0,
"Metadata muxer");
return gst_element_register (plugin, "metadatamux",
GST_RANK_NONE, GST_TYPE_METADATA_MUX);
}

View file

@ -1,93 +0,0 @@
/*
* 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_MUX_H__
#define __GST_METADATA_MUX_H__
#include <gst/gst.h>
#include "gstbasemetadata.h"
#include "metadataexif.h"
G_BEGIN_DECLS
/* *INDENT-OFF* */
#define GST_TYPE_METADATA_MUX \
(gst_metadata_mux_get_type())
#define GST_METADATA_MUX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_METADATA_MUX,GstMetadataMux))
#define GST_METADATA_MUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_METADATA_MUX,GstMetadataMuxClass))
#define GST_IS_METADATA_MUX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_METADATA_MUX))
#define GST_IS_METADATA_MUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_METADATA_MUX))
/* *INDENT-ON* */
typedef struct _GstMetadataMux GstMetadataMux;
typedef struct _GstMetadataMuxClass GstMetadataMuxClass;
/**
* GstMetadataMux:
*
* The opaque #GstMetadataMux data structure.
*/
struct _GstMetadataMux
{
GstBaseMetadata metadata;
MetaExifWriteOptions exif_options;
};
struct _GstMetadataMuxClass
{
GstBaseMetadataClass parent_class;
};
GType gst_metadata_mux_get_type (void);
gboolean gst_metadata_mux_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* __GST_METADATA_MUX_H__ */

View file

@ -1,444 +0,0 @@
/*
* 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: metadata
* @short_description: This module provides high-level functions to parse files
*
* This module find out the stream type (JPEG or PNG), and provide functions to
* the caller to know where are the metadata chunks and where should it be
* written, as well, it gives the caller the metedata chunk to be written and
* also gets a metadata chunk and wraps it according the strem type
* specification.
*
* <refsect2>
* <para>
* #metadata_init must be called before any other function in this module and
* must be paired with a call to #metadata_dispose. #metadata_parse is used to
* parse the stream (find the metadata chunks and the place it should be
* written to. And #metadata_lazy_update is used by muxers to wrap the metadata
* chunk according the stream type specification. Actually after indentify the
* stream type, the real jog of parsing is delivered to speciallized module.
* See, #metadata[mux/parse][jpeg/png].[c/h] files.
* </para>
* </refsect2>
*
* Last reviewed on 2008-01-24 (0.10.15)
*/
/*
* includes
*/
#include <string.h>
#include "metadata.h"
/*
* static helper functions declaration
*/
static MetadataParsingReturn
metadata_parse_none (MetaData * meta_data, const guint8 * data,
guint32 * data_size, guint8 ** next_start, guint32 * next_size);
/*
* extern functions implementations
*/
/*
* metadata_init:
* @meta_data: [in] metadata handler to be inited
* @options: [in] which types of metadata will be processed (EXIF, IPTC and/or
* XMP) and how it will be handled (DEMUXING or MUXING). Look at #MetaOptions
* to see the available options.
*
* Init metadata handle.
* This function must be called before any other function from this module.
* This function must not be called twice without call to #metadata_dispose
* beteween them.
* @see_also: #metadata_dispose #metadata_parse
*
* Returns: nothing
*/
void
metadata_init (MetaData ** meta_data, const MetaOptions options)
{
if (meta_data == NULL)
return;
if ((*meta_data))
metadata_dispose (meta_data);
(*meta_data) = g_new (MetaData, 1);
(*meta_data)->state = STATE_NULL;
(*meta_data)->img_type = IMG_NONE;
(*meta_data)->options = options;
(*meta_data)->offset_orig = 0;
(*meta_data)->exif_adapter = NULL;
(*meta_data)->iptc_adapter = NULL;
(*meta_data)->xmp_adapter = NULL;
if ((*meta_data)->options & META_OPT_DEMUX) {
/* when parsing we will probably strip only 3 chunk (exif, iptc and xmp)
so we use 4 just in case there is more than one chunk of them.
But this is just for convinience, 'cause the chunk_array increases
dynamically */
metadata_chunk_array_init (&(*meta_data)->strip_chunks, 4);
/* at most 1 chunk will be injected (JPEG JFIF) */
metadata_chunk_array_init (&(*meta_data)->inject_chunks, 1);
} else {
/* at most 1 chunk will be striped (JPEG JFIF) */
metadata_chunk_array_init (&(*meta_data)->strip_chunks, 1);
/* at most 3 chunk will be injected (EXIF, IPTC, XMP) */
metadata_chunk_array_init (&(*meta_data)->inject_chunks, 3);
}
}
/*
* metadata_dispose:
* @meta_data: [in] metadata handler to be freed
*
* Call this function to free any resource allocated by #metadata_init
* @see_also: #metadata_init
*
* Returns: nothing
*/
void
metadata_dispose (MetaData ** meta_data)
{
if (meta_data == NULL || (*meta_data) == NULL)
return;
switch ((*meta_data)->img_type) {
case IMG_JPEG:
if (G_LIKELY ((*meta_data)->options & META_OPT_DEMUX))
metadataparse_jpeg_dispose (&(*meta_data)->format_data.jpeg_parse);
else
metadatamux_jpeg_dispose (&(*meta_data)->format_data.jpeg_mux);
break;
case IMG_PNG:
if (G_LIKELY ((*meta_data)->options & META_OPT_DEMUX))
metadataparse_png_dispose (&(*meta_data)->format_data.png_parse);
else
metadatamux_png_dispose (&(*meta_data)->format_data.png_mux);
break;
case IMG_NONE:
default:
break;
}
metadata_chunk_array_free (&(*meta_data)->strip_chunks);
metadata_chunk_array_free (&(*meta_data)->inject_chunks);
if ((*meta_data)->xmp_adapter) {
g_object_unref ((*meta_data)->xmp_adapter);
(*meta_data)->xmp_adapter = NULL;
}
if ((*meta_data)->iptc_adapter) {
g_object_unref ((*meta_data)->iptc_adapter);
(*meta_data)->iptc_adapter = NULL;
}
if ((*meta_data)->exif_adapter) {
g_object_unref ((*meta_data)->exif_adapter);
(*meta_data)->exif_adapter = NULL;
}
g_free (*meta_data);
*meta_data = NULL;
}
/*
* metadata_parse:
* @meta_data: [in] metadata handle
* @buf: [in] data to be parsed
* @buf_size: [in] size of @buf in bytes
* @next_offset: [out] number of bytes to jump from the begining of @buf in
* the next call. i.e, 0 (zero) mean that in the next call this function @buf
* must have the same data (probably resized, see @next_size)
* @next_size: [out] number of minimal bytes in @buf for the next call to this
* function
*
* This function is used to parse the stream step-by-step incrementaly, which
* means, discover the stream type and find the metadata chunks
* (#META_OPT_DEMUX), or point out where metadata chunks should be written
* (#META_OPT_MUX). It is important to notice that there could be both strip
* and inject chunks in both demuxing and muxing modes.
* @see_also: #metadata_init #META_DATA_STRIP_CHUNKS #META_DATA_INJECT_CHUNKS
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
* inject chunks has been found
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_offset and @next_size)
* </para></listitem>
* </itemizedlist>
*/
MetadataParsingReturn
metadata_parse (MetaData * meta_data, const guint8 * buf,
guint32 buf_size, guint32 * next_offset, guint32 * next_size)
{
int ret = META_PARSING_DONE;
guint8 *next_start = (guint8 *) buf;
if (meta_data->state == STATE_NULL) {
ret =
metadata_parse_none (meta_data, buf, &buf_size, &next_start, next_size);
if (ret == META_PARSING_DONE)
meta_data->state = STATE_READING;
else
goto done;
}
switch (meta_data->img_type) {
case IMG_JPEG:
if (G_LIKELY (meta_data->options & META_OPT_DEMUX)) {
GST_DEBUG ("parsing jpeg");
ret =
metadataparse_jpeg_parse (&meta_data->format_data.jpeg_parse,
(guint8 *) buf, &buf_size, meta_data->offset_orig, &next_start,
next_size);
} else {
GST_DEBUG ("formatting jpeg");
ret =
metadatamux_jpeg_parse (&meta_data->format_data.jpeg_mux,
(guint8 *) buf, &buf_size, meta_data->offset_orig, &next_start,
next_size);
}
break;
case IMG_PNG:
if (G_LIKELY (meta_data->options & META_OPT_DEMUX)) {
GST_DEBUG ("parsing png");
ret =
metadataparse_png_parse (&meta_data->format_data.png_parse,
(guint8 *) buf, &buf_size, meta_data->offset_orig, &next_start,
next_size);
} else {
GST_DEBUG ("formatting png");
ret =
metadatamux_png_parse (&meta_data->format_data.png_mux,
(guint8 *) buf, &buf_size, meta_data->offset_orig, &next_start,
next_size);
}
break;
default:
/* unexpected */
ret = META_PARSING_ERROR;
goto done;
break;
}
*next_offset = next_start - buf;
meta_data->offset_orig += *next_offset;
done:
if (ret == META_PARSING_DONE) {
meta_data->state = STATE_DONE;
}
GST_DEBUG ("parsing/formatting done : %d", ret);
return ret;
}
/*
* metadata_lazy_update:
* @meta_data: [in] metata handle
*
* This function must be called after #metadata_parse and after the element
* has modified the segments (chunks)
* Data written to #META_DATA_INJECT_CHUNKS will be properly wrapped
* This function is really important in case of muxing because it gives the
* oportunity to muxers:
* 1: to frame new segments
* ex: in case of JPEG it can wrap the EXIF chunk (created using tags) with
* chunk id and chunk size
* 2: to decide if some chunks should still be striped/injected
* ex: if there is no EXIF chunk to be inserted, the muxer decides to not
* strip JFIF anymore
* @see_also: #metadata_parse #META_DATA_INJECT_CHUNKS
*
* Returns: nothing
*/
void
metadata_lazy_update (MetaData * meta_data)
{
switch (meta_data->img_type) {
case IMG_JPEG:
if (G_LIKELY (meta_data->options & META_OPT_DEMUX))
metadataparse_jpeg_lazy_update (&meta_data->format_data.jpeg_parse);
else
metadatamux_jpeg_lazy_update (&meta_data->format_data.jpeg_mux);
break;
case IMG_PNG:
if (G_LIKELY (meta_data->options & META_OPT_DEMUX))
metadataparse_png_lazy_update (&meta_data->format_data.png_parse);
else
metadatamux_png_lazy_update (&meta_data->format_data.png_mux);
break;
default:
/* unexpected */
break;
}
}
/*
* static helper functions implementation
*/
/*
* metadata_parse_none:
* @meta_data: [in] metata handle
* @buf: [in] data to be parsed
* @buf_size: [in] size of @buf in bytes
* @next_offset: [out] number of bytes to jump from the begining of @buf in
* the next call. i.e, 0 (zero) mean that in the next call this function @buf
* must have the same data (probably resized, see @next_size)
* @next_size: [out] number of minimal bytes in @buf for the next call to this
* function
*
* Parse the fisrt bytes of the stream to identify the stream type
* @see_also: metadata_parse
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR none of the alloed strem types (JPEG,
* PNG) has been identified
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if the stream type has been identified
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_offset and @next_size)
* </para></listitem>
* </itemizedlist>
*/
static MetadataParsingReturn
metadata_parse_none (MetaData * meta_data, const guint8 * buf,
guint32 * buf_size, guint8 ** next_start, guint32 * next_size)
{
int ret = META_PARSING_ERROR;
GstAdapter **exif = NULL;
GstAdapter **iptc = NULL;
GstAdapter **xmp = NULL;
*next_start = (guint8 *) buf;
meta_data->img_type = IMG_NONE;
/*
* Be sure of add checking for more types in order from the
* less to more bytes need to detect the stream type.
*/
/* we need at least 3 bytes to see if it is JPEG */
if (*buf_size < 3) {
*next_size = 3;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
if (meta_data->options & META_OPT_EXIF)
exif = &meta_data->exif_adapter;
if (meta_data->options & META_OPT_IPTC)
iptc = &meta_data->iptc_adapter;
if (meta_data->options & META_OPT_XMP)
xmp = &meta_data->xmp_adapter;
if (buf[0] == 0xFF && buf[1] == 0xD8 && buf[2] == 0xFF) {
if (G_LIKELY (meta_data->options & META_OPT_DEMUX))
metadataparse_jpeg_init (&meta_data->format_data.jpeg_parse, exif, iptc,
xmp, &meta_data->strip_chunks, &meta_data->inject_chunks,
meta_data->options & META_OPT_PARSE_ONLY);
else
metadatamux_jpeg_init (&meta_data->format_data.jpeg_mux,
&meta_data->strip_chunks, &meta_data->inject_chunks);
ret = META_PARSING_DONE;
meta_data->img_type = IMG_JPEG;
goto done;
}
/* we need at least 8 bytes to see if it is PNG */
if (*buf_size < 8) {
*next_size = 8;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
if (buf[0] == 0x89 && buf[1] == 0x50 && buf[2] == 0x4E && buf[3] == 0x47 &&
buf[4] == 0x0D && buf[5] == 0x0A && buf[6] == 0x1A && buf[7] == 0x0A) {
if (G_LIKELY (meta_data->options & META_OPT_DEMUX))
metadataparse_png_init (&meta_data->format_data.png_parse, exif, iptc,
xmp, &meta_data->strip_chunks, &meta_data->inject_chunks,
meta_data->options & META_OPT_PARSE_ONLY);
else
metadatamux_png_init (&meta_data->format_data.png_mux,
&meta_data->strip_chunks, &meta_data->inject_chunks);
ret = META_PARSING_DONE;
meta_data->img_type = IMG_PNG;
goto done;
}
done:
return ret;
}

View file

@ -1,139 +0,0 @@
/*
* 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 __METADATA_H__
#define __METADATA_H__
/*
* includes
*/
#include <gst/base/gstadapter.h>
#include "metadatatypes.h"
#include "metadataparsejpeg.h"
#include "metadatamuxjpeg.h"
#include "metadataparsepng.h"
#include "metadatamuxpng.h"
G_BEGIN_DECLS
/*
* enum and types
*/
/* *INDENT-OFF* */
typedef enum _tag_MetaOptions
{
META_OPT_EXIF = (1 << 0),
META_OPT_IPTC = (1 << 1),
META_OPT_XMP = (1 << 2),
META_OPT_PARSE_ONLY = (1 << 3), /* only makes sense with META_OPT_DEMUX */
META_OPT_DEMUX = (1 << 4), /* to operates in demuxing mode */
META_OPT_MUX = (1 << 5), /* to operates in muxing mode */
META_OPT_ALL = (1 << 6) - 1
} MetaOptions;
/* *INDENT-ON* */
typedef enum _tag_MetaState
{
STATE_NULL,
STATE_READING,
STATE_DONE
} MetaState;
typedef enum _tag_ImageType
{
IMG_NONE,
IMG_JPEG,
IMG_PNG
} ImageType;
typedef struct _tag_MetaData
{
MetaState state;
ImageType img_type;
guint8 options;
guint32 offset_orig; /* offset since begining of stream */
union
{
JpegParseData jpeg_parse;
JpegMuxData jpeg_mux;
PngParseData png_parse;
PngMuxData png_mux;
} format_data;
GstAdapter * exif_adapter;
GstAdapter * iptc_adapter;
GstAdapter * xmp_adapter;
MetadataChunkArray strip_chunks;
MetadataChunkArray inject_chunks;
} MetaData;
/*
* defines and macros
*/
#define META_DATA_IMG_TYPE(p) (p)->img_type
#define META_DATA_STRIP_CHUNKS(p) (p)->strip_chunks
#define META_DATA_INJECT_CHUNKS(p) (p)->inject_chunks
/*
* external function prototypes
*/
extern void metadata_init (MetaData ** meta_data, const MetaOptions options);
extern void metadata_dispose (MetaData ** meta_data);
extern MetadataParsingReturn
metadata_parse (MetaData * meta_data, const guint8 * buf,
guint32 buf_size, guint32 * next_offset, guint32 * next_size);
extern void metadata_lazy_update (MetaData * meta_data);
G_END_DECLS
#endif /* __METADATA_H__ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,93 +0,0 @@
/*
* 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_EXIF_H__
#define __GST_METADATA_EXIF_H__
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include "metadatatags.h"
G_BEGIN_DECLS
/*
* defines
*/
#define EXIF_HEADER "Exif\0"
typedef enum {
GST_META_EXIF_BYTE_ORDER_MOTOROLA,
GST_META_EXIF_BYTE_ORDER_INTEL
} MetaExifByteOrder;
typedef struct _MetaExifWriteOptions MetaExifWriteOptions;
/**
* MetaExifWriteOptions:
* @byteorder: byte-ordering for exif chunk
*
* Options for Exif metadata writing
*/
struct _MetaExifWriteOptions
{
MetaExifByteOrder byteorder;
};
#define GST_TYPE_META_EXIF_BYTE_ORDER (gst_meta_exif_byte_order_get_type())
GType gst_meta_exif_byte_order_get_type (void);
/*
* external function prototypes
*/
extern void
metadataparse_exif_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
GstAdapter * adapter, MetadataTagMapping mapping);
extern void
metadatamux_exif_create_chunk_from_tag_list (guint8 ** buf, guint32 *size,
const GstTagList * taglist, const MetaExifWriteOptions *opts);
G_END_DECLS
#endif /* __GST_METADATA_EXIF_H__ */

View file

@ -1,467 +0,0 @@
/*
* 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: metadataiptc
* @short_description: This module provides functions to extract tags from
* IPTC metadata chunks and create IPTC chunks from metadata tags.
* @see_also: #metadatatags.[c/h]
*
* If libiptcdata isn't available at compilation time, only the whole chunk
* (#METADATA_TAG_MAP_WHOLECHUNK) tags is created. It means that individual
* tags aren't mapped.
*
* Last reviewed on 2008-01-24 (0.10.15)
*/
/*
* includes
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "metadataiptc.h"
#include "metadataparseutil.h"
#include "metadatatags.h"
/*
* defines
*/
GST_DEBUG_CATEGORY (gst_metadata_iptc_debug);
#define GST_CAT_DEFAULT gst_metadata_iptc_debug
/*
* Implementation when libiptcdata isn't available at compilation time
*/
#ifndef HAVE_IPTC
/*
* extern functions implementations
*/
void
metadataparse_iptc_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
GstAdapter * adapter, MetadataTagMapping mapping)
{
if (mapping & METADATA_TAG_MAP_WHOLECHUNK) {
GST_LOG ("IPTC not defined, sending just one tag as whole chunk");
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_IPTC,
adapter);
}
}
void
metadatamux_iptc_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
const GstTagList * taglist)
{
/* do nothing */
}
#else /* ifndef HAVE_IPTC */
/*
* Implementation when libiptcdata is available at compilation time
*/
/*
* includes
*/
#include <iptc-data.h>
#include <iptc-tag.h>
#include <string.h>
#include <gst/gsttaglist.h>
/*
* enum and types
*/
typedef struct _tag_MEUserData
{
GstTagList *taglist;
GstTagMergeMode mode;
} MEUserData;
typedef struct _tag_MapIntStr
{
IptcRecord record;
IptcTag iptc;
const gchar *str;
} MapIntStr;
/*
* defines and static global vars
*/
/* *INDENT-OFF* */
/* When changing this table, update 'metadata_mapping.htm' file too. */
static MapIntStr mappedTags[] = {
{IPTC_RECORD_APP_2, IPTC_TAG_OBJECT_NAME, /*ASCII*/
GST_TAG_TITLE /*STRING*/},
{IPTC_RECORD_APP_2, IPTC_TAG_BYLINE, /*ASCII*/
GST_TAG_COMPOSER /*STRING*/},
{IPTC_RECORD_APP_2, IPTC_TAG_CAPTION, /*ASCII*/
GST_TAG_DESCRIPTION /*STRING*/},
{IPTC_RECORD_APP_2, IPTC_TAG_COPYRIGHT_NOTICE, /*ASCII*/
GST_TAG_COPYRIGHT /*STRING*/},
{0, 0, NULL}
};
/* *INDENT-ON* */
/*
* static helper functions declaration
*/
static const gchar *metadataparse_iptc_get_tag_from_iptc (IptcTag iptc,
GType * type, IptcRecord * record);
static IptcTag
metadatamux_iptc_get_iptc_from_tag (const gchar * tag, GType * type,
IptcRecord * record);
static void
metadataparse_iptc_data_foreach_dataset_func (IptcDataSet * dataset,
void *user_data);
static void
metadatamux_iptc_for_each_tag_in_list (const GstTagList * list,
const gchar * tag, gpointer user_data);
/*
* extern functions implementations
*/
/*
* metadataparse_iptc_tag_list_add:
* @taglist: tag list in which extracted tags will be added
* @mode: tag list merge mode
* @adapter: contains the IPTC metadata chunk
* @mapping: if is to extract individual tags and/or the whole chunk.
*
* This function gets a IPTC chunk (@adapter) and extract tags form it
* and then add to @taglist.
* Note: The IPTC chunk (@adapetr) must NOT be wrapped by any bytes specific
* to any file format
*
* Returns: nothing
*/
void
metadataparse_iptc_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
GstAdapter * adapter, MetadataTagMapping mapping)
{
const guint8 *buf;
guint32 size;
IptcData *iptc = NULL;
MEUserData user_data = { taglist, mode };
if (adapter == NULL || (size = gst_adapter_available (adapter)) == 0) {
goto done;
}
/* add chunk tag */
if (mapping & METADATA_TAG_MAP_WHOLECHUNK)
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_IPTC,
adapter);
if (!(mapping & METADATA_TAG_MAP_INDIVIDUALS))
goto done;
buf = gst_adapter_peek (adapter, size);
iptc = iptc_data_new_from_data (buf, size);
if (iptc == NULL) {
goto done;
}
iptc_data_foreach_dataset (iptc,
metadataparse_iptc_data_foreach_dataset_func, (void *) &user_data);
done:
if (iptc)
iptc_data_unref (iptc);
return;
}
/*
* metadatamux_iptc_create_chunk_from_tag_list:
* @buf: buffer that will have the created IPTC chunk
* @size: size of the buffer that will be created
* @taglist: list of tags to be added to IPTC chunk
*
* Get tags from @taglist, create a IPTC chunk based on it and save to @buf.
* Note: The IPTC chunk is NOT wrapped by any bytes specific to any file format
*
* Returns: nothing
*/
void
metadatamux_iptc_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
const GstTagList * taglist)
{
IptcData *iptc = NULL;
GstBuffer *iptc_chunk = NULL;
const GValue *val = NULL;
if (!(buf && size))
goto done;
g_free (*buf);
*buf = NULL;
*size = 0;
val = gst_tag_list_get_value_index (taglist, GST_TAG_IPTC, 0);
if (val) {
iptc_chunk = gst_value_get_buffer (val);
if (iptc_chunk) {
iptc = iptc_data_new_from_data (GST_BUFFER_DATA (iptc_chunk),
GST_BUFFER_SIZE (iptc_chunk));
}
}
if (!iptc) {
iptc = iptc_data_new ();
}
gst_tag_list_foreach (taglist, metadatamux_iptc_for_each_tag_in_list, iptc);
iptc_data_save (iptc, buf, size);
done:
if (iptc)
iptc_data_unref (iptc);
return;
}
/*
* static helper functions implementation
*/
/*
* metadataparse_iptc_get_tag_from_iptc:
* @iptc: IPTC tag to look for
* @type: the type of the GStreamer tag mapped to @iptc
* @record: the place into IPTC chunk @iptc belongs to.
*
* This returns the GStreamer tag mapped to an IPTC tag.
*
* Returns:
* <itemizedlist>
* <listitem><para>The GStreamer tag mapped to the @iptc
* </para></listitem>
* <listitem><para>%NULL if there is no mapped GST tag for @iptc
* </para></listitem>
* </itemizedlist>
*/
static const gchar *
metadataparse_iptc_get_tag_from_iptc (IptcTag iptc, GType * type,
IptcRecord * record)
{
int i = 0;
while (mappedTags[i].iptc) {
if (iptc == mappedTags[i].iptc) {
*type = gst_tag_get_type (mappedTags[i].str);
*record = mappedTags[i].record;
break;
}
++i;
}
return mappedTags[i].str;
}
/*
* metadatamux_iptc_get_iptc_from_tag:
* @tag: GST tag to look for
* @type: the type of the GStreamer @tag
* @record: the place into IPTC chunk @iptc belongs to.
*
* This returns thet IPTC tag mapped to an GStreamer @tag.
*
* Returns:
* <itemizedlist>
* <listitem><para>The IPTC tag mapped to the GST @tag
* </para></listitem>
* <listitem><para>0 if there is no mapped IPTC tag for GST @tag
* </para></listitem>
* </itemizedlist>
*/
static IptcTag
metadatamux_iptc_get_iptc_from_tag (const gchar * tag, GType * type,
IptcRecord * record)
{
int i = 0;
while (mappedTags[i].iptc) {
if (0 == strcmp (mappedTags[i].str, tag)) {
*type = gst_tag_get_type (tag);
*record = mappedTags[i].record;
break;
}
++i;
}
return mappedTags[i].iptc;
}
/*
* metadataparse_iptc_data_foreach_dataset_func:
* @dataset: IPTC structure from libiptcdata having IPTC tag
* @user_data: pointer to #MEUserData
*
* This function designed to be called for each IPTC tag in a IPTC chunk. This
* function gets the IPTC tag from @dataset and then add to the tag list
* in @user_data by using a merge mode also specified in @user_data
* @see_also: #metadataparse_iptc_tag_list_add
*
* Returns: nothing
*/
static void
metadataparse_iptc_data_foreach_dataset_func (IptcDataSet * dataset,
void *user_data)
{
char buf[1024];
MEUserData *meudata = (MEUserData *) user_data;
GType type;
IptcRecord record;
const gchar *tag =
metadataparse_iptc_get_tag_from_iptc (dataset->tag, &type, &record);
const gchar *value = iptc_dataset_get_as_str (dataset, buf, 1024);
if (!tag)
goto done;
gst_tag_list_add (meudata->taglist, meudata->mode, tag, value, NULL);
done:
GST_LOG ("name -> %s", iptc_tag_get_name (dataset->record, dataset->tag));
GST_LOG ("title -> %s", iptc_tag_get_title (dataset->record, dataset->tag));
GST_LOG ("description -> %s", iptc_tag_get_description (dataset->record,
dataset->tag));
GST_LOG ("value = %s", value);
GST_LOG ("record = %d", dataset->record);
return;
}
/*
* metadatamux_iptc_for_each_tag_in_list:
* @list: GStreamer tag list from which @tag belongs to
* @tag: GStreamer tag to be added to the IPTC chunk
* @user_data: pointer to #IptcData in which the tag will be added
*
* This function designed to be called for each tag in GST tag list. This
* function adds get the tag value from tag @list and then add it to the IPTC
* chunk by using #IptcData and related functions from libiptcdata
* @see_also: #metadatamux_iptc_create_chunk_from_tag_list
*
* Returns: nothing
*/
static void
metadatamux_iptc_for_each_tag_in_list (const GstTagList * list,
const gchar * tag, gpointer user_data)
{
IptcData *iptc = (IptcData *) user_data;
IptcTag iptc_tag;
IptcRecord record;
GType type;
IptcDataSet *dataset = NULL;
gboolean new_dataset = FALSE;
gchar *tag_value = NULL;
iptc_tag = metadatamux_iptc_get_iptc_from_tag (tag, &type, &record);
if (!iptc_tag)
goto done;
dataset = iptc_data_get_dataset (iptc, record, iptc_tag);
if (!dataset) {
dataset = iptc_dataset_new ();
new_dataset = TRUE;
}
iptc_dataset_set_tag (dataset, record, iptc_tag);
if (gst_tag_list_get_string (list, tag, &tag_value)) {
iptc_dataset_set_data (dataset, (guint8 *) tag_value, strlen (tag_value),
IPTC_DONT_VALIDATE);
g_free (tag_value);
tag_value = NULL;
}
if (new_dataset)
iptc_data_add_dataset (iptc, dataset);
done:
if (dataset)
iptc_dataset_unref (dataset);
}
#endif /* else (ifndef HAVE_IPTC) */

View file

@ -1,72 +0,0 @@
/*
* 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_IPTC_H__
#define __GST_METADATA_IPTC_H__
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include "metadatatags.h"
G_BEGIN_DECLS
/*
* defines
*/
#define PHOTOSHOP_HEADER "Photoshop 3.0"
/*
* external function prototypes
*/
extern void
metadataparse_iptc_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
GstAdapter * adapter, MetadataTagMapping mapping);
extern void
metadatamux_iptc_create_chunk_from_tag_list (guint8 ** buf, guint32 *size,
const GstTagList * taglist);
G_END_DECLS
#endif /* __GST_METADATA_IPTC_H__ */

View file

@ -1,545 +0,0 @@
/*
* 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: metadatamuxjpeg
* @short_description: This module provides functions to parse JPEG files in
* order to write metadata to it.
*
* This module parses a JPEG stream to find the places in which metadata (EXIF,
* IPTC, XMP) chunks would be written. It also wraps metadata chunks with JPEG
* marks according to the specification.
*
* <refsect2>
* <para>
* #metadatamux_jpeg_init must be called before any other function in this
* module and must be paired with a call to #metadatamux_jpeg_dispose.
* #metadatamux_jpeg_parse is used to parse the stream (find the place
* metadata chunks should be written to).
* #metadatamux_jpeg_lazy_update do nothing.
* </para>
* <para>
* EXIF chunks will always be the first chunk (replaces JFIF). IPTC and XMP
* chunks will be placed or second chunk (after JFIF or EXIF) or third chunk
* if both (IPTC and XMP) are written to the file.
* </para>
* <para>
* When a EXIF chunk is written to the JPEG stream, if there is a JFIF chunk
* as the first chunk, it will be stripped out.
* </para>
* </refsect2>
*
* Last reviewed on 2008-01-24 (0.10.15)
*/
/*
* includes
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "metadatamuxjpeg.h"
#include "metadataxmp.h"
#include <string.h>
#ifdef HAVE_IPTC
#include <libiptcdata/iptc-jpeg.h>
#endif
GST_DEBUG_CATEGORY_EXTERN (gst_metadata_mux_debug);
#define GST_CAT_DEFAULT gst_metadata_mux_debug
/*
* defines and macros
*/
#define READ(buf, size) ( (size)--, *((buf)++) )
/*
* static helper functions declaration
*/
static MetadataParsingReturn
metadatamux_jpeg_reading (JpegMuxData * jpeg_data, guint8 ** buf,
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
guint8 ** next_start, guint32 * next_size);
static void
metadatamux_wrap_chunk (MetadataChunk * chunk, const guint8 * buf,
guint32 buf_size, guint8 a, guint8 b);
#ifdef HAVE_IPTC
static gboolean
metadatamux_wrap_iptc_with_ps3 (unsigned char **buf, unsigned int *buf_size);
#endif /* #ifdef HAVE_IPTC */
/*
* extern functions implementations
*/
/*
* metadatamux_jpeg_init:
* @jpeg_data: [in] jpeg data handler to be inited
* @strip_chunks: Array of chunks (offset and size) marked for removal
* @inject_chunks: Array of chunks (offset, data, size) marked for injection
* adapter (@exif_adpt, @iptc_adpt, @xmp_adpt). Or FALSE if should also put
* them on @strip_chunks.
*
* Init jpeg data handle.
* This function must be called before any other function from this module.
* This function must not be called twice without call to
* #metadatamux_jpeg_dispose beteween them.
* @see_also: #metadatamux_jpeg_dispose #metadatamux_jpeg_parse
*
* Returns: nothing
*/
void
metadatamux_jpeg_init (JpegMuxData * jpeg_data,
MetadataChunkArray * strip_chunks, MetadataChunkArray * inject_chunks)
{
jpeg_data->state = JPEG_MUX_NULL;
jpeg_data->strip_chunks = strip_chunks;
jpeg_data->inject_chunks = inject_chunks;
}
/*
* metadatamux_jpeg_dispose:
* @jpeg_data: [in] jpeg data handler to be freed
*
* Call this function to free any resource allocated by #metadatamux_jpeg_init
* @see_also: #metadatamux_jpeg_init
*
* Returns: nothing
*/
void
metadatamux_jpeg_dispose (JpegMuxData * jpeg_data)
{
jpeg_data->inject_chunks = NULL;
jpeg_data->strip_chunks = NULL;
jpeg_data->state = JPEG_MUX_NULL;
}
/*
* metadatamux_jpeg_parse:
* @jpeg_data: [in] jpeg data handle
* @buf: [in] data to be parsed
* @bufsize: [in] size of @buf in bytes
* @offset: is the offset where @buf starts from the beginnig of the whole
* stream
* @next_start: is a pointer after @buf which indicates where @buf should start
* on the next call to this function. It means, that after returning, this
* function has consumed *@next_start - @buf bytes. Which also means
* that @offset should also be incremanted by (*@next_start - @buf) for the
* next time.
* @next_size: [out] number of minimal bytes in @buf for the next call to this
* function
*
* This function is used to parse a JPEG stream step-by-step incrementally.
* Basically this function works like a state machine, that will run in a loop
* while there is still bytes in @buf to be read or it has finished parsing.
* If the it hasn't parsed yet and there is no more data in @buf, then the
* current state is saved and a indication will be make about the buffer to
* be passed by the caller function.
* @see_also: #metadatamux_jpeg_init
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
* inject chunks has been found
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_start and @next_size)
* </para></listitem>
* </itemizedlist>
*/
MetadataParsingReturn
metadatamux_jpeg_parse (JpegMuxData * jpeg_data, guint8 * buf,
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
guint32 * next_size)
{
int ret = META_PARSING_DONE;
const guint8 *step_buf = buf;
*next_start = buf;
if (jpeg_data->state == JPEG_MUX_NULL) {
guint8 mark[2];
if (*bufsize < 2) {
GST_INFO ("need more data");
*next_size = (buf - *next_start) + 2;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
mark[0] = READ (buf, *bufsize);
mark[1] = READ (buf, *bufsize);
if (mark[0] != 0xFF || mark[1] != 0xD8) {
GST_INFO ("missing marker");
ret = META_PARSING_ERROR;
goto done;
}
jpeg_data->state = JPEG_MUX_READING;
}
while (ret == META_PARSING_DONE) {
switch (jpeg_data->state) {
case JPEG_MUX_READING:
GST_DEBUG ("start reading");
ret =
metadatamux_jpeg_reading (jpeg_data, &buf, bufsize,
offset, step_buf, next_start, next_size);
break;
case JPEG_MUX_DONE:
goto done;
break;
default:
GST_INFO ("invalid parser state");
ret = META_PARSING_ERROR;
break;
}
}
done:
GST_INFO ("finishing: %d", ret);
return ret;
}
/*
* metadatamux_jpeg_lazy_update:
* @jpeg_data: [in] jpeg data handle
*
* This function wrap metadata chunk with proper JPEG marks. In case of IPTC
* it will be wrapped by PhotoShop and then by JPEG mark.
* @see_also: #metadata_lazy_update
*
* Returns: nothing
*/
void
metadatamux_jpeg_lazy_update (JpegMuxData * jpeg_data)
{
gsize i;
gboolean has_exif = FALSE;
MetadataChunkArray *chunks = jpeg_data->inject_chunks;
GST_INFO ("checking %" G_GSIZE_FORMAT " chunks", chunks->len);
for (i = 0; i < chunks->len; ++i) {
GST_INFO ("checking chunk[%" G_GSIZE_FORMAT "], type=%d, len=%u",
i, chunks->chunk[i].type, chunks->chunk[i].size);
if (chunks->chunk[i].size > 0 && chunks->chunk[i].data) {
switch (chunks->chunk[i].type) {
case MD_CHUNK_EXIF:
metadatamux_wrap_chunk (&chunks->chunk[i], NULL, 0, 0xFF, 0xE1);
has_exif = TRUE;
break;
case MD_CHUNK_IPTC:
#ifdef HAVE_IPTC
if (metadatamux_wrap_iptc_with_ps3 (&chunks->chunk[i].data,
&chunks->chunk[i].size)) {
metadatamux_wrap_chunk (&chunks->chunk[i], NULL, 0, 0xFF, 0xED);
} else {
GST_ERROR ("Invalid IPTC chunk\n");
metadata_chunk_array_remove_by_index (chunks, i);
continue;
}
#endif /* #ifdef HAVE_IPTC */
break;
case MD_CHUNK_XMP:
metadatamux_wrap_chunk (&chunks->chunk[i],
(guint8 *) XMP_HEADER, sizeof (XMP_HEADER), 0xFF, 0xE1);
break;
default:
break;
}
}
}
if (!has_exif) {
/* EXIF not injected so not strip JFIF anymore */
metadata_chunk_array_clear (jpeg_data->strip_chunks);
}
}
/*
* static helper functions implementation
*/
/*
* metadatamux_jpeg_reading:
* @jpeg_data: [in] jpeg data handle
* @buf: [in] data to be parsed. @buf will increment during the parsing step.
* So it will hold the next byte to be read inside a parsing function or on
* the next nested parsing function. And so, @bufsize will decrement.
* @bufsize: [in] size of @buf in bytes. This value will decrement during the
* parsing for the same reason that @buf will advance.
* @offset: is the offset where @step_buf starts from the beginnig of the
* stream
* @step_buf: holds the pointer to the buffer passed to
* #metadatamux_jpeg_parse. It means that any point inside this function
* the offset (related to the beginning of the whole stream) after the last
* byte read so far is "(*buf - step_buf) + offset"
* @next_start: is a pointer after @step_buf which indicates where the next
* call to #metadatamux_jpeg_parse should start on the next call to this
* function. It means, that after return, this function has
* consumed *@next_start - @buf bytes. Which also means that @offset should
* also be incremanted by (*@next_start - @buf) for the next time.
* @next_size: [out] number of minimal bytes in @buf for the next call to this
* function
*
* This function is used to parse a JPEG stream step-by-step incrementally.
* If this function quickly finds the place (offset) in which EXIF, IPTC and
* XMP chunk should be written to.
* The found places are written to @jpeg_data->inject_chunks
* @see_also: #metadatamux_jpeg_init
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
* inject chunks has been found. Or some chunk has been found and should be
* held or jumped.
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_start and @next_size)
* </para></listitem>
* </itemizedlist>
*/
static MetadataParsingReturn
metadatamux_jpeg_reading (JpegMuxData * jpeg_data, guint8 ** buf,
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
guint8 ** next_start, guint32 * next_size)
{
int ret = META_PARSING_ERROR;
guint8 mark[2] = { 0x00, 0x00 };
guint16 chunk_size = 0;
gint64 new_chunk_offset = 0;
MetadataChunk chunk;
gboolean jfif_found = FALSE;
static const char JfifHeader[] = "JFIF";
*next_start = *buf;
if (*bufsize < 2) {
GST_INFO ("need more data");
*next_size = (*buf - *next_start) + 2;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
mark[0] = READ (*buf, *bufsize);
mark[1] = READ (*buf, *bufsize);
GST_DEBUG ("parsing JPEG marker : 0x%02x%02x", mark[0], mark[1]);
if (mark[0] == 0xFF) {
chunk_size = READ (*buf, *bufsize) << 8;
chunk_size += READ (*buf, *bufsize);
if (mark[1] == 0xE0) { /* APP0 - may be JFIF */
/* FIXME: whats the 14 ? according to
* http://en.wikipedia.org/wiki/JFIF#JFIF_segment_format
* its the jfif segment without thumbnails
*/
if (chunk_size >= 14 + 2) {
if (*bufsize < sizeof (JfifHeader)) {
GST_INFO ("need more data");
*next_size = (*buf - *next_start) + sizeof (JfifHeader);
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
if (0 == memcmp (JfifHeader, *buf, sizeof (JfifHeader))) {
jfif_found = TRUE;
}
} else {
/* FIXME: should we check if the first chunk is EXIF? */
GST_INFO ("chunk size too small %u", chunk_size);
}
}
if (!jfif_found) {
GST_INFO ("no jfif found, will insert it as needed");
}
new_chunk_offset = 2;
/* EXIF will always be in the begining */
memset (&chunk, 0x00, sizeof (MetadataChunk));
chunk.offset_orig = 2;
chunk.type = MD_CHUNK_EXIF;
metadata_chunk_array_append_sorted (jpeg_data->inject_chunks, &chunk);
if (jfif_found) {
/* remove JFIF chunk */
/* this acation can be canceled with lazy update if no Exif is add */
memset (&chunk, 0x00, sizeof (MetadataChunk));
chunk.offset_orig = 2;
chunk.size = chunk_size + 2; /* chunk size plus app marker */
chunk.type = MD_CHUNK_UNKNOWN;
metadata_chunk_array_append_sorted (jpeg_data->strip_chunks, &chunk);
new_chunk_offset = chunk.offset_orig + chunk.size;
}
/* IPTC */
memset (&chunk, 0x00, sizeof (MetadataChunk));
chunk.offset_orig = new_chunk_offset;
chunk.type = MD_CHUNK_IPTC;
metadata_chunk_array_append_sorted (jpeg_data->inject_chunks, &chunk);
/* XMP */
memset (&chunk, 0x00, sizeof (MetadataChunk));
chunk.offset_orig = new_chunk_offset;
chunk.type = MD_CHUNK_XMP;
metadata_chunk_array_append_sorted (jpeg_data->inject_chunks, &chunk);
jpeg_data->state = JPEG_MUX_DONE;
ret = META_PARSING_DONE;
} else {
GST_INFO ("invalid JPEG chunk");
ret = META_PARSING_ERROR;
}
done:
return ret;
}
/*
* metadatamux_wrap_chunk:
* @chunk: chunk to be wrapped
* @buf: data to inject in the beginning of @chunk->data and after @a and @b
* @buf_size: size in bytes of @buf
* @a: together with @b forms the JPEG mark to be injected in the beginning
* @b: look at @a
*
* Wraps a chunk if a JPEG mark (@a@b) and, if @buf_size > 0, with some data
* (@buf)
*
* Returns: nothing
*/
static void
metadatamux_wrap_chunk (MetadataChunk * chunk, const guint8 * buf,
guint32 buf_size, guint8 a, guint8 b)
{
guint8 *data = g_new (guint8, 4 + buf_size + chunk->size);
memcpy (data + 4 + buf_size, chunk->data, chunk->size);
g_free (chunk->data);
chunk->data = data;
chunk->size += 4 + buf_size;
data[0] = a;
data[1] = b;
data[2] = ((chunk->size - 2) >> 8) & 0xFF;
data[3] = (chunk->size - 2) & 0xFF;
if (buf && buf_size) {
memcpy (data + 4, buf, buf_size);
}
}
#ifdef HAVE_IPTC
static gboolean
metadatamux_wrap_iptc_with_ps3 (unsigned char **buf, unsigned int *buf_size)
{
unsigned int out_size = *buf_size + 4096;
unsigned char *outbuf = g_new (unsigned char, out_size);
int size_written;
gboolean ret = TRUE;
size_written =
iptc_jpeg_ps3_save_iptc (NULL, 0, *buf, *buf_size, outbuf, out_size);
g_free (*buf);
*buf = NULL;
*buf_size = 0;
if (size_written < 0) {
g_free (outbuf);
ret = FALSE;
} else {
*buf_size = size_written;
*buf = outbuf;
}
return ret;
}
#endif /* #ifdef HAVE_IPTC */

View file

@ -1,96 +0,0 @@
/*
* 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 __METADATAMUX_JPEG_H__
#define __METADATAMUX_JPEG_H__
/*
* includes
*/
#include <gst/base/gstadapter.h>
#include "metadatatypes.h"
/*
* enum and types
*/
G_BEGIN_DECLS
typedef enum _tag_JpegMuxState
{
JPEG_MUX_NULL,
JPEG_MUX_READING,
JPEG_MUX_DONE
} JpegMuxState;
typedef struct _tag_JpegMuxData
{
JpegMuxState state;
MetadataChunkArray * strip_chunks;
MetadataChunkArray * inject_chunks;
} JpegMuxData;
/*
* external function prototypes
*/
extern void
metadatamux_jpeg_init (JpegMuxData * jpeg_data,
MetadataChunkArray * strip_chunks, MetadataChunkArray * inject_chunks);
extern void metadatamux_jpeg_dispose (JpegMuxData * jpeg_data);
extern MetadataParsingReturn
metadatamux_jpeg_parse (JpegMuxData * jpeg_data, guint8 * buf,
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
guint32 * next_size);
extern void metadatamux_jpeg_lazy_update (JpegMuxData * jpeg_data);
G_END_DECLS
#endif /* __METADATAMUX_JPEG_H__ */

View file

@ -1,558 +0,0 @@
/*
* 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: metadatamuxpng
* @short_description: This module provides functions to parse PNG files in
* order to write metadata to it.
*
* This module parses a PNG stream to find the places in which XMP metadata
* chunks would be written. It also wraps metadata chunks with PNG marks
* according to the specification.
*
* <refsect2>
* <para>
* #metadatamux_png_init must be called before any other function in this
* module and must be paired with a call to #metadatamux_png_dispose.
* #metadatamux_png_parse is used to parse the stream (find the place
* metadata chunks should be written to).
* #metadatamux_png_lazy_update do nothing.
* </para>
* <para>
* EXIF chunks will always be the first chunk (replaces JFIF). IPTC and XMP
* chunks will be placed or second chunk (after JFIF or EXIF) or third chunk
* if both (IPTC and XMP) are written to the file.
* </para>
* <para>
* When a EXIF chunk is written to the PNG stream, if there is a JFIF chunk
* as the first chunk, it will be stripped out.
* </para>
* </refsect2>
*
* Last reviewed on 2008-01-24 (0.10.15)
*/
/*
* includes
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "metadatamuxpng.h"
#include <string.h>
GST_DEBUG_CATEGORY_EXTERN (gst_metadata_mux_debug);
#define GST_CAT_DEFAULT gst_metadata_mux_debug
/*
* defines and macros
*/
#define READ(buf, size) ( (size)--, *((buf)++) )
/*
* static global vars
*/
static const guint32 metadatamux_crc_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535,
0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b,
0x7eb17cbd,
0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d,
0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a,
0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e,
0xd56041e4,
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa,
0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac,
0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11,
0xc1611dab,
0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589,
0x06b6b51f,
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb,
0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8,
0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea,
0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158,
0x3ab551ce,
0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a,
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f,
0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3,
0xb966d409,
0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739,
0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e,
0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2,
0x1e01f268,
0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76,
0x89d32be0,
0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8,
0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd,
0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef,
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795,
0xbb0b4703,
0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7,
0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14,
0x7bb12bae,
0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4,
0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6,
0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3,
0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
0x4969474d,
0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53,
0xdebb9ec5,
0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605,
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02,
0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
/*
* static helper functions declaration
*/
static MetadataParsingReturn
metadatamux_png_reading (PngMuxData * png_data, guint8 ** buf,
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
guint8 ** next_start, guint32 * next_size);
static guint32 metadatamux_update_crc (guint32 crc, guint8 * buf, guint32 len);
static guint32 metadatamux_calc_crc (guint8 * buf, guint32 len);
static void metadatamux_wrap_xmp_chunk (MetadataChunk * chunk);
/*
* extern functions implementations
*/
/*
* metadatamux_png_init:
* @png_data: [in] png data handler to be inited
* @strip_chunks: Array of chunks (offset and size) marked for removal
* @inject_chunks: Array of chunks (offset, data, size) marked for injection
* adapter (@exif_adpt, @iptc_adpt, @xmp_adpt). Or FALSE if should also put
* them on @strip_chunks.
*
* Init png data handle.
* This function must be called before any other function from this module.
* This function must not be called twice without call to
* #metadatamux_png_dispose beteween them.
* @see_also: #metadatamux_png_dispose #metadatamux_png_parse
*
* Returns: nothing
*/
void
metadatamux_png_init (PngMuxData * png_data,
MetadataChunkArray * strip_chunks, MetadataChunkArray * inject_chunks)
{
png_data->state = PNG_MUX_NULL;
png_data->strip_chunks = strip_chunks;
png_data->inject_chunks = inject_chunks;
}
/*
* metadatamux_png_dispose:
* png_data: [in] png data handler to be freed
*
* Call this function to free any resource allocated by #metadatamux_png_init
* @see_also: #metadatamux_png_init
*
* Returns: nothing
*/
void
metadatamux_png_dispose (PngMuxData * png_data)
{
png_data->strip_chunks = NULL;
png_data->inject_chunks = NULL;
png_data->state = PNG_MUX_NULL;
}
/*
* metadatamux_png_parse:
* @png_data: [in] png data handle
* @buf: [in] data to be parsed
* @bufsize: [in] size of @buf in bytes
* @offset: is the offset where @buf starts from the beginnig of the whole
* stream
* @next_start: is a pointer after @buf which indicates where @buf should start
* on the next call to this function. It means, that after returning, this
* function has consumed *@next_start - @buf bytes. Which also means
* that @offset should also be incremanted by (*@next_start - @buf) for the
* next time.
* @next_size: [out] number of minimal bytes in @buf for the next call to this
* function
*
* This function is used to parse a PNG stream step-by-step incrementally.
* Basically this function works like a state machine, that will run in a loop
* while there is still bytes in @buf to be read or it has finished parsing.
* If the it hasn't parsed yet and there is no more data in @buf, then the
* current state is saved and a indication will be make about the buffer to
* be passed by the caller function.
* @see_also: #metadatamux_png_init
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
* inject chunks has been found
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_start and @next_size)
* </para></listitem>
* </itemizedlist>
*/
MetadataParsingReturn
metadatamux_png_parse (PngMuxData * png_data, guint8 * buf,
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
guint32 * next_size)
{
int ret = META_PARSING_DONE;
guint8 mark[8];
const guint8 *step_buf = buf;
*next_start = buf;
if (png_data->state == PNG_MUX_NULL) {
if (*bufsize < 8) {
*next_size = (buf - *next_start) + 8;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
mark[0] = READ (buf, *bufsize);
mark[1] = READ (buf, *bufsize);
mark[2] = READ (buf, *bufsize);
mark[3] = READ (buf, *bufsize);
mark[4] = READ (buf, *bufsize);
mark[5] = READ (buf, *bufsize);
mark[6] = READ (buf, *bufsize);
mark[7] = READ (buf, *bufsize);
if (mark[0] != 0x89 || mark[1] != 0x50 || mark[2] != 0x4E || mark[3] != 0x47
|| mark[4] != 0x0D || mark[5] != 0x0A || mark[6] != 0x1A
|| mark[7] != 0x0A) {
ret = META_PARSING_ERROR;
goto done;
}
png_data->state = PNG_MUX_READING;
}
while (ret == META_PARSING_DONE) {
switch (png_data->state) {
case PNG_MUX_READING:
ret =
metadatamux_png_reading (png_data, &buf, bufsize,
offset, step_buf, next_start, next_size);
break;
case PNG_MUX_DONE:
goto done;
break;
default:
ret = META_PARSING_ERROR;
break;
}
}
done:
return ret;
}
/*
* metadatamux_png_lazy_update:
* @png_data: [in] png data handle
*
* This function wrap metadata chunk with proper PNG bytes.
* @see_also: #metadata_lazy_update
*
* Returns: nothing
*/
void
metadatamux_png_lazy_update (PngMuxData * png_data)
{
gsize i;
MetadataChunkArray *chunks = png_data->inject_chunks;
GST_INFO ("checking %" G_GSIZE_FORMAT " chunks", chunks->len);
for (i = 0; i < chunks->len; ++i) {
GST_INFO ("checking chunk[%" G_GSIZE_FORMAT "], type=%d, len=%u",
i, chunks->chunk[i].type, chunks->chunk[i].size);
if (chunks->chunk[i].size > 0 && chunks->chunk[i].data) {
switch (chunks->chunk[i].type) {
case MD_CHUNK_XMP:
metadatamux_wrap_xmp_chunk (&chunks->chunk[i]);
break;
default:
GST_ERROR ("Unexpected chunk for PNG muxer.");
break;
}
}
}
}
/*
* static helper functions implementation
*/
/*
* metadatamux_png_reading:
* @png_data: [in] png data handle
* @buf: [in] data to be parsed. @buf will increment during the parsing step.
* So it will hold the next byte to be read inside a parsing function or on
* the next nested parsing function. And so, @bufsize will decrement.
* @bufsize: [in] size of @buf in bytes. This value will decrement during the
* parsing for the same reason that @buf will advance.
* @offset: is the offset where @step_buf starts from the beginnig of the
* stream
* @step_buf: holds the pointer to the buffer passed to
* #metadatamux_png_parse. It means that any point inside this function
* the offset (related to the beginning of the whole stream) after the last
* byte read so far is "(*buf - step_buf) + offset"
* @next_start: is a pointer after @step_buf which indicates where the next
* call to #metadatamux_png_parse should start on the next call to this
* function. It means, that after return, this function has
* consumed *@next_start - @buf bytes. Which also means that @offset should
* also be incremanted by (*@next_start - @buf) for the next time.
* @next_size: [out] number of minimal bytes in @buf for the next call to this
* function
*
* This function is used to parse a PNG stream step-by-step incrementally.
* If this function quickly finds the place (offset) in which EXIF, IPTC and
* XMP chunk should be written to.
* The found places are written to @png_data->inject_chunks
* @see_also: #metadatamux_png_init
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
* inject chunks has been found. Or some chunk has been found and should be
* held or jumped.
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_start and @next_size)
* </para></listitem>
* </itemizedlist>
*/
static MetadataParsingReturn
metadatamux_png_reading (PngMuxData * png_data, guint8 ** buf,
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
guint8 ** next_start, guint32 * next_size)
{
int ret = META_PARSING_ERROR;
guint8 mark[4];
guint32 chunk_size = 0;
MetadataChunk chunk;
*next_start = *buf;
if (*bufsize < 8) {
*next_size = (*buf - *next_start) + 8;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
chunk_size = READ (*buf, *bufsize) << 24;
chunk_size += READ (*buf, *bufsize) << 16;
chunk_size += READ (*buf, *bufsize) << 8;
chunk_size += READ (*buf, *bufsize);
mark[0] = READ (*buf, *bufsize);
mark[1] = READ (*buf, *bufsize);
mark[2] = READ (*buf, *bufsize);
mark[3] = READ (*buf, *bufsize);
if (!(mark[0] == 'I' && mark[1] == 'H' && mark[2] == 'D' && mark[3] == 'R')) {
ret = META_PARSING_ERROR;
png_data->state = PNG_MUX_NULL;
goto done;
}
/* always inject after first chunk (IHDR) */
memset (&chunk, 0x00, sizeof (MetadataChunk));
/* 8(header) + 4(size) +4(id) + chunksize + 4(crc) */
chunk.offset_orig = chunk_size + 20;
chunk.type = MD_CHUNK_XMP;
metadata_chunk_array_append_sorted (png_data->inject_chunks, &chunk);
png_data->state = PNG_MUX_DONE;
ret = META_PARSING_DONE;
done:
return ret;
}
/*
* metadatamux_update_crc:
* @crc: seed to calculate the CRC
* @buf: data to calculate the CRC for
* @len: size in bytes of @buf
*
* Calculates the CRC of a data buffer for a seed @crc.
* @see_also: #metadatamux_calc_crc
*
* Returns: the CRC of the bytes buf[0..len-1].
*/
static guint32
metadatamux_update_crc (guint32 crc, guint8 * buf, guint32 len)
{
guint32 c = crc;
guint32 n;
for (n = 0; n < len; n++) {
c = metadatamux_crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
}
return c;
}
/*
* metadatamux_calc_crc:
* @buf: data to calculate the CRC for
* @len: size in bytes of @buf
*
* Calculates the CRC of a data buffer.
*
* Returns: the CRC of the bytes buf[0..len-1].
*/
static guint32
metadatamux_calc_crc (guint8 * buf, guint32 len)
{
return metadatamux_update_crc (0xffffffffL, buf, len) ^ 0xffffffffL;
}
/*
* metadatamux_wrap_xmp_chunk:
* @chunk: chunk to be wrapped
*
* Wraps a XMP chunk with proper PNG bytes (mark, size and crc in the end)
*
* Returns: nothing
*/
static void
metadatamux_wrap_xmp_chunk (MetadataChunk * chunk)
{
static const char XmpHeader[] = "XML:com.adobe.xmp";
guint8 *data = NULL;
guint32 crc;
data = g_new (guint8, 12 + 18 + 4 + chunk->size);
memcpy (data + 8, XmpHeader, 18);
memset (data + 8 + 18, 0x00, 4);
memcpy (data + 8 + 18 + 4, chunk->data, chunk->size);
g_free (chunk->data);
chunk->data = data;
chunk->size += 18 + 4;
data[0] = (chunk->size >> 24) & 0xFF;
data[1] = (chunk->size >> 16) & 0xFF;
data[2] = (chunk->size >> 8) & 0xFF;
data[3] = chunk->size & 0xFF;
data[4] = 'i';
data[5] = 'T';
data[6] = 'X';
data[7] = 't';
crc = metadatamux_calc_crc (data + 4, chunk->size + 4);
data[chunk->size + 8] = (crc >> 24) & 0xFF;
data[chunk->size + 9] = (crc >> 16) & 0xFF;
data[chunk->size + 10] = (crc >> 8) & 0xFF;
data[chunk->size + 11] = crc & 0xFF;
chunk->size += 12;
}

View file

@ -1,98 +0,0 @@
/*
* 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 __METADATAMUX_PNG_H__
#define __METADATAMUX_PNG_H__
/*
* includes
*/
#include <gst/base/gstadapter.h>
#include "metadatatypes.h"
G_BEGIN_DECLS
/*
* enum and types
*/
typedef enum _tag_PngMuxState
{
PNG_MUX_NULL,
PNG_MUX_READING,
PNG_MUX_JUMPING,
PNG_MUX_XMP,
PNG_MUX_DONE
} PngMuxState;
typedef struct _tag_PngMuxData
{
PngMuxState state;
MetadataChunkArray * strip_chunks;
MetadataChunkArray * inject_chunks;
} PngMuxData;
/*
* external function prototypes
*/
extern void
metadatamux_png_init (PngMuxData * png_data,
MetadataChunkArray * strip_chunks, MetadataChunkArray * inject_chunks);
extern void metadatamux_png_dispose (PngMuxData * png_data);
extern void metadatamux_png_lazy_update (PngMuxData * png_data);
extern MetadataParsingReturn
metadatamux_png_parse (PngMuxData * png_data, guint8 * buf,
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
guint32 * next_size);
G_END_DECLS
#endif /* __METADATAMUX_PNG_H__ */

View file

@ -1,782 +0,0 @@
/*
* 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: metadataparsejpeg
* @short_description: This module provides functions to parse JPEG files
*
* This module parses a JPEG stream finding metadata chunks, and marking them
* to be removed from the stream and saving them in a adapter.
*
* <refsect2>
* <para>
* #metadataparse_jpeg_init must be called before any other function in this
* module and must be paired with a call to #metadataparse_jpeg_dispose.
* #metadataparse_jpeg_parse is used to parse the stream (find the metadata
* chunks and the place it should be written to.
* #metadataparse_jpeg_lazy_update do nothing.
* </para>
* <para>
* This module tries to find metadata chunk until it reaches the "start of scan
* image". So if the metadata chunk, which could be EXIF, XMP or IPTC (inside
* Photoshop), is after the "start of scan image" it will not be found. This is
* 'cause of performance reason and 'cause we believe that files with metadata
* chunk after the "scan of image" chunk are very bad practice, so we don't
* worry about them.
* </para>
* <para>
* If it is working in non-parse_only mode, and the first chunk is a EXIF
* instead of a JFIF chunk, the EXIF chunk will be marked for removal and a new
* JFIF chunk will be create and marked to be injected as the first chunk.
* </para>
* </refsect2>
*
* Last reviewed on 2008-01-24 (0.10.15)
*/
/*
* includes
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <string.h>
#include "metadataparsejpeg.h"
#include "metadataparseutil.h"
#include "metadataexif.h"
#include "metadataxmp.h"
#ifdef HAVE_IPTC
#include <libiptcdata/iptc-jpeg.h>
#include "metadataiptc.h"
#endif
GST_DEBUG_CATEGORY_EXTERN (gst_metadata_demux_debug);
#define GST_CAT_DEFAULT gst_metadata_demux_debug
/*
* defines and macros
*/
/* returns the current byte, advance to the next one and decrease the size */
#define READ(buf, size) ( (size)--, *((buf)++) )
/*
* static helper functions declaration
*/
static MetadataParsingReturn
metadataparse_jpeg_reading (JpegParseData * jpeg_data, guint8 ** buf,
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
guint8 ** next_start, guint32 * next_size);
static MetadataParsingReturn
metadataparse_jpeg_exif (JpegParseData * jpeg_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
#ifdef HAVE_IPTC
static MetadataParsingReturn
metadataparse_jpeg_iptc (JpegParseData * jpeg_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
#endif
static MetadataParsingReturn
metadataparse_jpeg_xmp (JpegParseData * jpeg_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
static MetadataParsingReturn
metadataparse_jpeg_jump (JpegParseData * jpeg_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
/*
* extern functions implementations
*/
/*
* metadataparse_jpeg_init:
* @jpeg_data: [in] jpeg data handler to be inited
* @exif_adpt: where to create/write an adapter to hold the EXIF chunk found
* @iptc_adpt: where to create/write an adapter to hold the IPTC chunk found
* @xmp_adpt: where to create/write an adapter to hold the XMP chunk found
* @strip_chunks: Array of chunks (offset and size) marked for removal
* @inject_chunks: Array of chunks (offset, data, size) marked for injection
* @parse_only: TRUE if it should only find the chunks and write then to the
* adapter (@exif_adpt, @iptc_adpt, @xmp_adpt). Or FALSE if should also put
* them on @strip_chunks.
*
* Init jpeg data handle.
* This function must be called before any other function from this module.
* This function must not be called twice without call to
* #metadataparse_jpeg_dispose beteween them.
* @see_also: #metadataparse_jpeg_dispose #metadataparse_jpeg_parse
*
* Returns: nothing
*/
void
metadataparse_jpeg_init (JpegParseData * jpeg_data, GstAdapter ** exif_adpt,
GstAdapter ** iptc_adpt, GstAdapter ** xmp_adpt,
MetadataChunkArray * strip_chunks, MetadataChunkArray * inject_chunks,
gboolean parse_only)
{
jpeg_data->state = JPEG_PARSE_NULL;
jpeg_data->exif_adapter = exif_adpt;
jpeg_data->iptc_adapter = iptc_adpt;
jpeg_data->xmp_adapter = xmp_adpt;
jpeg_data->read = 0;
jpeg_data->jfif_found = FALSE;
jpeg_data->strip_chunks = strip_chunks;
jpeg_data->inject_chunks = inject_chunks;
jpeg_data->parse_only = parse_only;
}
/*
* metadataparse_jpeg_dispose:
* @jpeg_data: [in] jpeg data handler to be freed
*
* Call this function to free any resource allocated by
* #metadataparse_jpeg_init
* @see_also: #metadataparse_jpeg_init
*
* Returns: nothing
*/
void
metadataparse_jpeg_dispose (JpegParseData * jpeg_data)
{
jpeg_data->exif_adapter = NULL;
jpeg_data->iptc_adapter = NULL;
jpeg_data->xmp_adapter = NULL;
}
/*
* metadataparse_jpeg_parse:
* @jpeg_data: [in] jpeg data handle
* @buf: [in] data to be parsed
* @bufsize: [in] size of @buf in bytes
* @offset: is the offset where @buf starts from the beginnig of the whole
* stream
* @next_start: is a pointer after @buf which indicates where @buf should start
* on the next call to this function. It means, that after returning, this
* function has consumed *@next_start - @buf bytes. Which also means
* that @offset should also be incremanted by (*@next_start - @buf) for the
* next time.
* @next_size: [out] number of minimal bytes in @buf for the next call to this
* function
*
* This function is used to parse a JPEG stream step-by-step incrementally.
* Basically this function works like a state machine, that will run in a loop
* while there is still bytes in @buf to be read or it has finished parsing.
* If the it hasn't parsed yet and there is no more data in @buf, then the
* current state is saved and a indication will be make about the buffer to
* be passed by the caller function.
* @see_also: #metadataparse_jpeg_init
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
* inject chunks has been found
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_start and @next_size)
* </para></listitem>
* </itemizedlist>
*/
MetadataParsingReturn
metadataparse_jpeg_parse (JpegParseData * jpeg_data, guint8 * buf,
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
guint32 * next_size)
{
int ret = META_PARSING_DONE;
const guint8 *step_buf = buf;
/* step_buf holds where buf starts. this const value will be passed to
the nested parsing function, so those function knows how far they from
the initial buffer. This is not related to the beginning of the whole
stream, it is just related to the buf passed in this step to this
function */
*next_start = buf;
if (jpeg_data->state == JPEG_PARSE_NULL) {
guint8 mark[2];
/* only the first time this function is called it will verify the stream
type to be sure it is a JPEG */
if (*bufsize < 2) {
GST_INFO ("need more data");
*next_size = (buf - *next_start) + 2;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
mark[0] = READ (buf, *bufsize);
mark[1] = READ (buf, *bufsize);
if (mark[0] != 0xFF || mark[1] != 0xD8) {
GST_INFO ("missing marker");
ret = META_PARSING_ERROR;
goto done;
}
jpeg_data->state = JPEG_PARSE_READING;
}
while (ret == META_PARSING_DONE) {
switch (jpeg_data->state) {
case JPEG_PARSE_READING:
GST_DEBUG ("start reading");
ret =
metadataparse_jpeg_reading (jpeg_data, &buf, bufsize,
offset, step_buf, next_start, next_size);
break;
case JPEG_PARSE_JUMPING:
GST_DEBUG ("jump");
ret =
metadataparse_jpeg_jump (jpeg_data, &buf, bufsize, next_start,
next_size);
break;
case JPEG_PARSE_EXIF:
GST_DEBUG ("parse exif");
ret =
metadataparse_jpeg_exif (jpeg_data, &buf, bufsize, next_start,
next_size);
break;
case JPEG_PARSE_IPTC:
GST_DEBUG ("parse iptc");
#ifdef HAVE_IPTC
ret =
metadataparse_jpeg_iptc (jpeg_data, &buf, bufsize, next_start,
next_size);
#endif
break;
case JPEG_PARSE_XMP:
GST_DEBUG ("parse xmp");
ret =
metadataparse_jpeg_xmp (jpeg_data, &buf, bufsize, next_start,
next_size);
break;
case JPEG_PARSE_DONE:
goto done;
break;
default:
GST_INFO ("invalid parser state");
ret = META_PARSING_ERROR;
break;
}
}
done:
GST_INFO ("finishing: %d", ret);
return ret;
}
/*
* metadataparse_jpeg_lazy_update:
* @jpeg_data: [in] jpeg data handle
*
* This function do nothing
* @see_also: #metadata_lazy_update
*
* Returns: nothing
*/
void
metadataparse_jpeg_lazy_update (JpegParseData * jpeg_data)
{
/* nothing to do */
}
/*
* static helper functions implementation
*/
/*
* metadataparse_jpeg_reading:
* @jpeg_data: [in] jpeg data handle
* @buf: [in] data to be parsed. @buf will increment during the parsing step.
* So it will hold the next byte to be read inside a parsing function or on
* the next nested parsing function. And so, @bufsize will decrement.
* @bufsize: [in] size of @buf in bytes. This value will decrement during the
* parsing for the same reason that @buf will advance.
* @offset: is the offset where @step_buf starts from the beginnig of the
* stream
* @step_buf: holds the pointer to the buffer passed to
* #metadataparse_jpeg_parse. It means that any point inside this function
* the offset (related to the beginning of the whole stream) after the last
* byte read so far is "(*buf - step_buf) + offset"
* @next_start: is a pointer after @step_buf which indicates where the next
* call to #metadataparse_jpeg_parse should start on the next call to this
* function. It means, that after return, this function has
* consumed *@next_start - @buf bytes. Which also means that @offset should
* also be incremanted by (*@next_start - @buf) for the next time.
* @next_size: [out] number of minimal bytes in @buf for the next call to this
* function
*
* This function is used to parse a JPEG stream step-by-step incrementally.
* If this function finds a EXIF, IPTC or XMP chunk (or a chunk that should be
* jumped), then it changes the state of the parsing process so that the
* remaing parsing can be done by another more specialized function.
* @see_also: #metadataparse_jpeg_init #metadataparse_jpeg_exif
* #metadataparse_jpeg_iptc #metadataparse_jpeg_xmp #metadataparse_jpeg_jump
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
* inject chunks has been found. Or some chunk has been found and should be
* held or jumped.
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_start and @next_size)
* </para></listitem>
* </itemizedlist>
*/
/* look for markers */
static MetadataParsingReturn
metadataparse_jpeg_reading (JpegParseData * jpeg_data, guint8 ** buf,
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
guint8 ** next_start, guint32 * next_size)
{
int ret = META_PARSING_ERROR;
guint8 mark[2] = { 0x00, 0x00 };
guint16 chunk_size = 0;
static const char JfifHeader[] = "JFIF";
*next_start = *buf;
if (*bufsize < 2) {
*next_size = (*buf - *next_start) + 2;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
mark[0] = READ (*buf, *bufsize);
mark[1] = READ (*buf, *bufsize);
GST_DEBUG ("parsing JPEG marker : 0x%02x%02x", mark[0], mark[1]);
if (mark[0] == 0xFF) {
if (mark[1] == 0xD9) { /* EOI - end of image */
ret = META_PARSING_DONE;
jpeg_data->state = JPEG_PARSE_DONE;
goto done;
} else if (mark[1] == 0xDA) { /* SOS - start of scan */
/* start of scan image, lets not look behind of this */
ret = META_PARSING_DONE;
jpeg_data->state = JPEG_PARSE_DONE;
goto done;
}
if (*bufsize < 2) {
*next_size = (*buf - *next_start) + 2;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
chunk_size = READ (*buf, *bufsize) << 8;
chunk_size += READ (*buf, *bufsize);
if (mark[1] == 0xE0) { /* APP0 - may be JFIF */
/* FIXME: whats the 14 ? according to
* http://en.wikipedia.org/wiki/JFIF#JFIF_segment_format
* its the jfif segment without thumbnails
*/
if (chunk_size >= 14 + 2) {
if (*bufsize < 14) {
*next_size = (*buf - *next_start) + 14;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
if (0 == memcmp (JfifHeader, *buf, sizeof (JfifHeader))) {
jpeg_data->jfif_found = TRUE;
}
}
} else if (mark[1] == 0xE1) { /* APP1 - may be it is Exif or XMP */
if (chunk_size >= sizeof (EXIF_HEADER) + 2) {
if (*bufsize < sizeof (EXIF_HEADER)) {
*next_size = (*buf - *next_start) + sizeof (EXIF_HEADER);
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
if (0 == memcmp (EXIF_HEADER, *buf, sizeof (EXIF_HEADER))) {
MetadataChunk chunk;
if (!jpeg_data->parse_only) {
memset (&chunk, 0x00, sizeof (MetadataChunk));
chunk.offset_orig = (*buf - step_buf) + offset - 4; /* 4 == maker + size */
chunk.size = chunk_size + 2; /* chunk size plus app marker */
chunk.type = MD_CHUNK_EXIF;
metadata_chunk_array_append_sorted (jpeg_data->strip_chunks,
&chunk);
}
if (!jpeg_data->jfif_found) {
/* only inject if no JFIF has been found */
if (!jpeg_data->parse_only) {
static const guint8 segment[] = { 0xff, 0xe0, 0x00, 0x10,
0x4a, 0x46, 0x49, 0x46, 0x00,
0x01, 0x02,
0x00, 0x00, 0x01, 0x00, 0x01,
0x00, 0x00
};
memset (&chunk, 0x00, sizeof (MetadataChunk));
chunk.offset_orig = 2;
chunk.size = 18;
chunk.type = MD_CHUNK_UNKNOWN;
chunk.data = g_new (guint8, 18);
memcpy (chunk.data, segment, 18);
metadata_chunk_array_append_sorted (jpeg_data->inject_chunks,
&chunk);
}
}
if (jpeg_data->exif_adapter) {
jpeg_data->read = chunk_size - 2;
jpeg_data->state = JPEG_PARSE_EXIF;
ret = META_PARSING_DONE;
goto done;
}
}
if (chunk_size >= sizeof (XMP_HEADER) + 2) {
if (*bufsize < sizeof (XMP_HEADER)) {
*next_size = (*buf - *next_start) + sizeof (XMP_HEADER);
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
if (0 == memcmp (XMP_HEADER, *buf, sizeof (XMP_HEADER))) {
if (!jpeg_data->parse_only) {
MetadataChunk chunk;
memset (&chunk, 0x00, sizeof (MetadataChunk));
chunk.offset_orig = (*buf - step_buf) + offset - 4; /* 4 == maker + size */
chunk.size = chunk_size + 2; /* chunk size plus app marker */
chunk.type = MD_CHUNK_XMP;
metadata_chunk_array_append_sorted (jpeg_data->strip_chunks,
&chunk);
}
/* if adapter has been provided, prepare to hold chunk */
if (jpeg_data->xmp_adapter) {
*buf += sizeof (XMP_HEADER);
*bufsize -= sizeof (XMP_HEADER);
jpeg_data->read = chunk_size - 2 - sizeof (XMP_HEADER);
jpeg_data->state = JPEG_PARSE_XMP;
ret = META_PARSING_DONE;
goto done;
}
}
}
}
}
#ifdef HAVE_IPTC
else if (mark[1] == 0xED) {
/* may be it is photoshop and may be there is iptc */
if (chunk_size >= 16) { /* size2 "Photoshop 3.0" */
if (*bufsize < 14) {
*next_size = (*buf - *next_start) + 14;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
if (0 == memcmp (PHOTOSHOP_HEADER, *buf, sizeof (PHOTOSHOP_HEADER))) {
if (!jpeg_data->parse_only) {
MetadataChunk chunk;
memset (&chunk, 0x00, sizeof (MetadataChunk));
chunk.offset_orig = (*buf - step_buf) + offset - 4; /* 4 == maker + size */
chunk.size = chunk_size + 2; /* chunk size plus app marker */
chunk.type = MD_CHUNK_IPTC;
metadata_chunk_array_append_sorted (jpeg_data->strip_chunks,
&chunk);
}
/* if adapter has been provided, prepare to hold chunk */
if (jpeg_data->iptc_adapter) {
jpeg_data->read = chunk_size - 2;
jpeg_data->state = JPEG_PARSE_IPTC;
ret = META_PARSING_DONE;
goto done;
}
}
}
}
#endif /* #ifdef HAVE_IPTC */
/* just set jump sise */
jpeg_data->read = chunk_size - 2;
jpeg_data->state = JPEG_PARSE_JUMPING;
ret = META_PARSING_DONE;
} else {
/* invalid JPEG chunk */
ret = META_PARSING_ERROR;
}
done:
return ret;
}
/*
* metadataparse_jpeg_exif:
* @jpeg_data: [in] jpeg data handle
* @buf: [in] data to be parsed
* @bufsize: [in] size of @buf in bytes
* @next_start: look at #metadataparse_jpeg_reading
* @next_size: look at #metadataparse_jpeg_reading
* NOTE: To have a explanation of each parameters of this function look at
* the documentation of #metadataparse_jpeg_reading
*
* This function saves the EXIF chunk to @jpeg_data->exif_adapter and makes the
* parsing process point to the next buffer after the EXIF chunk.
* This function will be called by the parsing process 'cause at some point
* #metadataparse_jpeg_reading found out the EXIF chunk, skipped the JPEG
* wrapper bytes and changed the state of parsing process to JPEG_PARSE_EXIF.
* Which just happens if @jpeg_data->parse_only is FALSE and there is a EXIF
* chunk into the stream and @jpeg_data->exif_adapter is not NULL.
* This function will just be called once even if there is more than one EXIF
* chunk in the stream. This function do it by setting @jpeg_data->exif_adapter
* to NULL.
* After this function has completely parsed (hold) the chunk, it changes the
* parsing state back to JPEG_PARSE_READING which makes
* #metadataparse_jpeg_reading to be called again
* @see_also: #metadataparse_util_hold_chunk #metadataparse_jpeg_reading
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if the chunk bas been completely hold
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_start and @next_size)
* </para></listitem>
* </itemizedlist>
*/
static MetadataParsingReturn
metadataparse_jpeg_exif (JpegParseData * jpeg_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
{
int ret;
ret = metadataparse_util_hold_chunk (&jpeg_data->read, buf,
bufsize, next_start, next_size, jpeg_data->exif_adapter);
if (ret == META_PARSING_DONE) {
jpeg_data->state = JPEG_PARSE_READING;
/* if there is a second Exif chunk in the file it will be jumped */
jpeg_data->exif_adapter = NULL;
}
return ret;
}
/*
* metadataparse_jpeg_iptc:
*
* Look at #metadataparse_jpeg_exif. This function has the same behavior as
* that. The only difference is that this function also cut out others
* PhotoShop data and only holds IPTC data in it.
*
*/
#ifdef HAVE_IPTC
static MetadataParsingReturn
metadataparse_jpeg_iptc (JpegParseData * jpeg_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
{
int ret;
ret = metadataparse_util_hold_chunk (&jpeg_data->read, buf,
bufsize, next_start, next_size, jpeg_data->iptc_adapter);
if (ret == META_PARSING_DONE) {
const guint8 *buf;
guint32 size;
unsigned int iptc_len;
int res;
jpeg_data->state = JPEG_PARSE_READING;
size = gst_adapter_available (*jpeg_data->iptc_adapter);
buf = gst_adapter_peek (*jpeg_data->iptc_adapter, size);
/* FIXME: currently we are throwing away others PhotoShop data */
res = iptc_jpeg_ps3_find_iptc (buf, size, &iptc_len);
if (res < 0) {
/* error */
ret = META_PARSING_ERROR;
} else if (res == 0) {
/* no iptc data found */
gst_adapter_clear (*jpeg_data->iptc_adapter);
} else {
gst_adapter_flush (*jpeg_data->iptc_adapter, res);
size = gst_adapter_available (*jpeg_data->iptc_adapter);
if (size > iptc_len) {
GstBuffer *buf;
buf = gst_adapter_take_buffer (*jpeg_data->iptc_adapter, iptc_len);
gst_adapter_clear (*jpeg_data->iptc_adapter);
gst_adapter_push (*jpeg_data->iptc_adapter, buf);
}
}
/* if there is a second Iptc chunk in the file it will be jumped */
jpeg_data->iptc_adapter = NULL;
}
return ret;
}
#endif
/*
* metadataparse_jpeg_xmp:
*
* Look at #metadataparse_jpeg_exif. This function has the same behavior as
* that.
*
*/
static MetadataParsingReturn
metadataparse_jpeg_xmp (JpegParseData * jpeg_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
{
int ret;
ret = metadataparse_util_hold_chunk (&jpeg_data->read, buf,
bufsize, next_start, next_size, jpeg_data->xmp_adapter);
if (ret == META_PARSING_DONE) {
jpeg_data->state = JPEG_PARSE_READING;
/* if there is a second XMP chunk in the file it will be jumped */
jpeg_data->xmp_adapter = NULL;
}
return ret;
}
/*
* metadataparse_jpeg_jump:
* @jpeg_data: [in] jpeg data handle
* @buf: [in] data to be parsed
* @bufsize: [in] size of @buf in bytes
* @next_start: look at #metadataparse_jpeg_reading
* @next_size: look at #metadataparse_jpeg_reading
* NOTE: To have a explanation of each parameters of this function look at
* the documentation of #metadataparse_jpeg_reading
*
* This function just makes a chunk we are not interested in to be jumped.
* This is done basically by incrementing @next_start and @buf,
* and decreasing @bufsize and setting the next parsing state properly.
* @see_also: #metadataparse_jpeg_reading #metadataparse_util_jump_chunk
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_DONE if bytes has been skiped and there is
* still data in @buf
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if the skiped bytes end at
* some point after @buf + @bufsize
* </para></listitem>
* </itemizedlist>
*/
static MetadataParsingReturn
metadataparse_jpeg_jump (JpegParseData * jpeg_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
{
jpeg_data->state = JPEG_PARSE_READING;
return metadataparse_util_jump_chunk (&jpeg_data->read, buf,
bufsize, next_start, next_size);
}

View file

@ -1,110 +0,0 @@
/*
* 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 __METADATAPARSE_JPEG_H__
#define __METADATAPARSE_JPEG_H__
/*
* includes
*/
#include <gst/base/gstadapter.h>
#include "metadatatypes.h"
G_BEGIN_DECLS
/*
* enum and types
*/
typedef enum _tag_JpegParseState
{
JPEG_PARSE_NULL,
JPEG_PARSE_READING,
JPEG_PARSE_JUMPING,
JPEG_PARSE_EXIF,
JPEG_PARSE_IPTC,
JPEG_PARSE_XMP,
JPEG_PARSE_DONE
} JpegParseState;
typedef struct _tag_JpegParseData
{
JpegParseState state;
GstAdapter ** exif_adapter;
GstAdapter ** iptc_adapter;
GstAdapter ** xmp_adapter;
MetadataChunkArray * strip_chunks;
MetadataChunkArray * inject_chunks;
gboolean parse_only;
guint32 read;
gboolean jfif_found;
} JpegParseData;
/*
* external function prototypes
*/
extern void
metadataparse_jpeg_init (JpegParseData * jpeg_data, GstAdapter ** exif_adpt,
GstAdapter ** iptc_adpt, GstAdapter ** xmp_adpt,
MetadataChunkArray * strip_chunks, MetadataChunkArray * inject_chunks,
gboolean parse_only);
extern void metadataparse_jpeg_dispose (JpegParseData * jpeg_data);
extern MetadataParsingReturn
metadataparse_jpeg_parse (JpegParseData * jpeg_data, guint8 * buf,
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
guint32 * next_size);
extern void metadataparse_jpeg_lazy_update (JpegParseData * jpeg_data);
G_END_DECLS
#endif /* __METADATAPARSE_JPEG_H__ */

View file

@ -1,521 +0,0 @@
/*
* 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: metadataparsepng
* @short_description: This module provides functions to parse PNG files
*
* This module parses a PNG stream finding XMP metadata chunks, and marking
* them to be removed from the stream and saving the XMP chunk in a adapter.
*
* <refsect2>
* <para>
* #metadataparse_png_init must be called before any other function in this
* module and must be paired with a call to #metadataparse_png_dispose.
* #metadataparse_png_parse is used to parse the stream (find the metadata
* chunks and the place it should be written to.
* #metadataparse_png_lazy_update do nothing.
* </para>
* </refsect2>
*
* Last reviewed on 2008-01-24 (0.10.15)
*/
/*
* includes
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "metadataparsepng.h"
#include "metadataparseutil.h"
#include <string.h>
GST_DEBUG_CATEGORY_EXTERN (gst_metadata_demux_debug);
#define GST_CAT_DEFAULT gst_metadata_demux_debug
/*
* defines and macros
*/
/* returns the current byte, advance to the next one and decrease the size */
#define READ(buf, size) ( (size)--, *((buf)++) )
/*
* static helper functions declaration
*/
static MetadataParsingReturn
metadataparse_png_reading (PngParseData * png_data, guint8 ** buf,
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
guint8 ** next_start, guint32 * next_size);
static MetadataParsingReturn
metadataparse_png_xmp (PngParseData * png_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
static MetadataParsingReturn
metadataparse_png_jump (PngParseData * png_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
/*
* extern functions implementations
*/
/*
* metadataparse_png_init:
* @png_data: [in] png data handler to be inited
* @exif_adpt: ignored
* @iptc_adpt: ignored
* @xmp_adpt: where to create/write an adapter to hold the XMP chunk found
* @strip_chunks: Array of chunks (offset and size) marked for removal
* @inject_chunks: Array of chunks (offset, data, size) marked for injection
* @parse_only: TRUE if it should only find the chunks and write then to the
* adapter (@xmp_adpt). Or FALSE if should also put
* them on @strip_chunks.
*
* Init png data handle.
* This function must be called before any other function from this module.
* This function must not be called twice without call to
* #metadataparse_png_dispose beteween them.
* @see_also: #metadataparse_png_dispose #metadataparse_png_parse
*
* Returns: nothing
*/
void
metadataparse_png_init (PngParseData * png_data, GstAdapter ** exif_adpt,
GstAdapter ** iptc_adpt, GstAdapter ** xmp_adpt,
MetadataChunkArray * strip_chunks, MetadataChunkArray * inject_chunks,
gboolean parse_only)
{
png_data->state = PNG_PARSE_NULL;
png_data->xmp_adapter = xmp_adpt;
png_data->read = 0;
png_data->strip_chunks = strip_chunks;
png_data->parse_only = parse_only;
}
/*
* metadataparse_png_dispose:
* @png_data: [in] png data handler to be freed
*
* Call this function to free any resource allocated by
* #metadataparse_png_init
* @see_also: #metadataparse_png_init
*
* Returns: nothing
*/
void
metadataparse_png_dispose (PngParseData * png_data)
{
png_data->xmp_adapter = NULL;
}
/*
* metadataparse_png_parse:
* @png_data: [in] png data handle
* @buf: [in] data to be parsed
* @bufsize: [in] size of @buf in bytes
* @offset: is the offset where @buf starts from the beginnig of the whole
* stream.
* @next_start: is a pointer after @buf which indicates where @buf should start
* on the next call to this function. It means, that after returning, this
* function has consumed *@next_start - @buf bytes. Which also means
* that @offset should also be incremanted by (*@next_start - @buf) for the
* next time.
* @next_size: [out] number of minimal bytes in @buf for the next call to this
* function
*
* This function is used to parse a PNG stream step-by-step incrementally.
* Basically this function works like a state machine, that will run in a loop
* while there is still bytes in @buf to be read or it has finished parsing.
* If the it hasn't parsed yet and there is no more data in @buf, then the
* current state is saved and a indication will be make about the buffer to
* be passed by the caller function.
* @see_also: #metadataparse_png_init
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
* inject chunks has been found
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_start and @next_size)
* </para></listitem>
* </itemizedlist>
*/
MetadataParsingReturn
metadataparse_png_parse (PngParseData * png_data, guint8 * buf,
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
guint32 * next_size)
{
int ret = META_PARSING_DONE;
guint8 mark[8];
const guint8 *step_buf = buf;
/* step_buf holds where buf starts. this const value will be passed to
the nested parsing function, so those function knows how far they from
the initial buffer. This is not related to the beginning of the whole
stream, it is just related to the buf passed in this step to this
function */
*next_start = buf;
if (png_data->state == PNG_PARSE_NULL) {
/* only the first time this function is called it will verify the stream
type to be sure it is a PNG */
if (*bufsize < 8) {
*next_size = (buf - *next_start) + 8;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
mark[0] = READ (buf, *bufsize);
mark[1] = READ (buf, *bufsize);
mark[2] = READ (buf, *bufsize);
mark[3] = READ (buf, *bufsize);
mark[4] = READ (buf, *bufsize);
mark[5] = READ (buf, *bufsize);
mark[6] = READ (buf, *bufsize);
mark[7] = READ (buf, *bufsize);
if (mark[0] != 0x89 || mark[1] != 0x50 || mark[2] != 0x4E ||
mark[3] != 0x47 || mark[4] != 0x0D || mark[5] != 0x0A ||
mark[6] != 0x1A || mark[7] != 0x0A) {
ret = META_PARSING_ERROR;
goto done;
}
png_data->state = PNG_PARSE_READING;
}
while (ret == META_PARSING_DONE) {
switch (png_data->state) {
case PNG_PARSE_READING:
ret =
metadataparse_png_reading (png_data, &buf, bufsize,
offset, step_buf, next_start, next_size);
break;
case PNG_PARSE_JUMPING:
ret =
metadataparse_png_jump (png_data, &buf, bufsize, next_start,
next_size);
break;
case PNG_PARSE_XMP:
ret =
metadataparse_png_xmp (png_data, &buf, bufsize, next_start,
next_size);
break;
case PNG_PARSE_DONE:
goto done;
break;
default:
ret = META_PARSING_ERROR;
break;
}
}
done:
return ret;
}
/*
* metadataparse_png_lazy_update:
* @png_data: [in] png data handle
*
* This function do nothing
* @see_also: #metadata_lazy_update
*
* Returns: nothing
*/
void
metadataparse_png_lazy_update (PngParseData * png_data)
{
/* nothing to do */
}
/*
* static helper functions implementation
*/
/*
* metadataparse_png_reading:
* @png_data: [in] png data handle
* @buf: [in] data to be parsed. @buf will increment during the parsing step.
* So it will hold the next byte to be read inside a parsing function or on
* the next nested parsing function. And so, @bufsize will decrement.
* @bufsize: [in] size of @buf in bytes. This value will decrement during the
* parsing for the same reason that @buf will advance.
* @offset: is the offset where @step_buf starts from the beginnig of the
* stream
* @step_buf: holds the pointer to the buffer passed to
* #metadataparse_png_parse. It means that any point inside this function
* the offset (related to the beginning of the whole stream) after the last
* byte read so far is "(*buf - step_buf) + offset"
* @next_start: is a pointer after @step_buf which indicates where the next
* call to #metadataparse_png_parse should start on the next call to this
* function. It means, that after return, this function has
* consumed *@next_start - @buf bytes. Which also means that @offset should
* also be incremanted by (*@next_start - @buf) for the next time.
* @next_size: [out] number of minimal bytes in @buf for the next call to this
* function
*
* This function is used to parse a PNG stream step-by-step incrementally.
* If this function finds a XMP chunk (or a chunk that should be
* jumped), then it changes the state of the parsing process so that the
* remaing parsing can be done by another more specialized function.
* @see_also: #metadataparse_png_init #metadataparse_png_xmp
* #metadataparse_png_jump
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
* inject chunks has been found. Or some chunk has been found and should be
* held or jumped.
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_start and @next_size)
* </para></listitem>
* </itemizedlist>
*/
/* look for markers */
static MetadataParsingReturn
metadataparse_png_reading (PngParseData * png_data, guint8 ** buf,
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
guint8 ** next_start, guint32 * next_size)
{
int ret = META_PARSING_ERROR;
guint8 mark[4];
guint32 chunk_size = 0;
static const char XmpHeader[] = "XML:com.adobe.xmp";
*next_start = *buf;
if (*bufsize < 8) {
*next_size = (*buf - *next_start) + 8;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
chunk_size = READ (*buf, *bufsize) << 24;
chunk_size += READ (*buf, *bufsize) << 16;
chunk_size += READ (*buf, *bufsize) << 8;
chunk_size += READ (*buf, *bufsize);
mark[0] = READ (*buf, *bufsize);
mark[1] = READ (*buf, *bufsize);
mark[2] = READ (*buf, *bufsize);
mark[3] = READ (*buf, *bufsize);
/* FIXME: use FOURCECC macros */
GST_DEBUG ("parsing png : 0x%02x%02x%02x%02x",
mark[0], mark[1], mark[2], mark[3]);
if (mark[0] == 'I' && mark[1] == 'E' && mark[2] == 'N' && mark[3] == 'D') {
ret = META_PARSING_DONE;
png_data->state = PNG_PARSE_DONE;
goto done;
}
if (mark[0] == 'i' && mark[1] == 'T' && mark[2] == 'X' && mark[3] == 't') {
if (chunk_size >= 22) { /* "XML:com.adobe.xmp" plus some flags */
if (*bufsize < 22) {
*next_size = (*buf - *next_start) + 22;
ret = META_PARSING_NEED_MORE_DATA;
goto done;
}
if (0 == memcmp (XmpHeader, *buf, 18)) {
if (!png_data->parse_only) {
MetadataChunk chunk;
memset (&chunk, 0x00, sizeof (MetadataChunk));
chunk.offset_orig = (*buf - step_buf) + offset - 8; /* maker + size */
chunk.size = chunk_size + 12; /* chunk size + app marker + crc */
chunk.type = MD_CHUNK_XMP;
metadata_chunk_array_append_sorted (png_data->strip_chunks, &chunk);
}
/* if adapter has been provided, prepare to hold chunk */
if (png_data->xmp_adapter) {
*buf += 22; /* jump "XML:com.adobe.xmp" + some flags */
*bufsize -= 22;
/* four CRC bytes at the end will be jumped after */
png_data->read = chunk_size - 22;
png_data->state = PNG_PARSE_XMP;
ret = META_PARSING_DONE;
goto done;
}
}
}
}
/* just set jump sise */
png_data->read = chunk_size + 4; /* four CRC bytes at the end */
png_data->state = PNG_PARSE_JUMPING;
ret = META_PARSING_DONE;
done:
return ret;
}
/*
* metadataparse_png_xmp:
* @png_data: [in] png data handle
* @buf: [in] data to be parsed
* @bufsize: [in] size of @buf in bytes
* @next_start: look at #metadataparse_png_reading
* @next_size: look at #metadataparse_png_reading
* NOTE: To have a explanation of each parameters of this function look at
* the documentation of #metadataparse_png_reading
*
* This function saves the XMP chunk to @png_data->xmp_adapter and makes the
* parsing process point to the next buffer after the XMP chunk.
* This function will be called by the parsing process 'cause at some point
* #metadataparse_png_reading found out the XMP chunk, skipped the PNG
* wrapper bytes and changed the state of parsing process to PNG_PARSE_XMP.
* Which just happens if @png_data->parse_only is FALSE and there is a XMP
* chunk into the stream and @png_data->xmp_adapter is not NULL.
* This function will just be called once even if there is more than one XMP
* chunk in the stream. This function do it by setting @png_data->xmp_adapter
* to NULL.
* After this function has completely parsed (hold) the chunk, it changes the
* parsing state to PNG_PARSE_JUMP which makes
* #metadataparse_png_jump to be called in order to jumo the remaing 4 CRC
* bytes
* @see_also: #metadataparse_util_hold_chunk #metadataparse_png_reading
* #metadataparse_png_jump
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if the chunk bas been completely hold
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_start and @next_size)
* </para></listitem>
* </itemizedlist>
*/
static MetadataParsingReturn
metadataparse_png_xmp (PngParseData * png_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
{
int ret;
ret = metadataparse_util_hold_chunk (&png_data->read, buf,
bufsize, next_start, next_size, png_data->xmp_adapter);
if (ret == META_PARSING_DONE) {
/* jump four CRC bytes at the end of chunk */
png_data->read = 4;
png_data->state = PNG_PARSE_JUMPING;
/* if there is a second XMP chunk in the file it will be jumped */
png_data->xmp_adapter = NULL;
}
return ret;
}
/*
* metadataparse_png_jump:
* @png_data: [in] png data handle
* @buf: [in] data to be parsed
* @bufsize: [in] size of @buf in bytes
* @next_start: look at #metadataparse_png_reading
* @next_size: look at #metadataparse_png_reading
* NOTE: To have a explanation of each parameters of this function look at
* the documentation of #metadataparse_png_reading
*
* This function just makes a chunk we are not interested in to be jumped.
* This is done basically by incrementing @next_start and @buf,
* and decreasing @bufsize and setting the next parsing state properly.
* @see_also: #metadataparse_png_reading #metadataparse_util_jump_chunk
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_DONE if bytes has been skiped and there is
* still data in @buf
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if the skiped bytes end at
* some point after @buf + @bufsize
* </para></listitem>
* </itemizedlist>
*/
static MetadataParsingReturn
metadataparse_png_jump (PngParseData * png_data, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
{
png_data->state = PNG_PARSE_READING;
return metadataparse_util_jump_chunk (&png_data->read, buf,
bufsize, next_start, next_size);
}

View file

@ -1,104 +0,0 @@
/*
* 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 __METADATAPARSE_PNG_H__
#define __METADATAPARSE_PNG_H__
/*
* includes
*/
#include <gst/base/gstadapter.h>
#include "metadatatypes.h"
G_BEGIN_DECLS
/*
* enum and types
*/
typedef enum _tag_PngParseState
{
PNG_PARSE_NULL,
PNG_PARSE_READING,
PNG_PARSE_JUMPING,
PNG_PARSE_XMP,
PNG_PARSE_DONE
} PngParseState;
typedef struct _tag_PngParseData
{
PngParseState state;
GstAdapter ** xmp_adapter;
MetadataChunkArray * strip_chunks;
gboolean parse_only;
guint32 read;
} PngParseData;
/*
* external function prototypes
*/
extern void
metadataparse_png_init (PngParseData * png_data, GstAdapter ** exif_adpt,
GstAdapter ** iptc_adpt, GstAdapter ** xmp_adpt,
MetadataChunkArray * strip_chunks, MetadataChunkArray * inject_chunks,
gboolean parse_only);
extern void metadataparse_png_dispose (PngParseData * png_data);
extern void metadataparse_png_lazy_update (PngParseData * png_data);
extern MetadataParsingReturn
metadataparse_png_parse (PngParseData * png_data, guint8 * buf,
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
guint32 * next_size);
G_END_DECLS
#endif /* __METADATAPARSE_PNG_H__ */

View file

@ -1,197 +0,0 @@
/*
* 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: metadataparseutil
* @short_description: This module has some util function for parsing.
*
* Last reviewed on 2008-01-24 (0.10.15)
*/
/*
* includes
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "metadataparseutil.h"
#include <string.h>
GST_DEBUG_CATEGORY_EXTERN (gst_metadata_demux_debug);
#define GST_CAT_DEFAULT gst_metadata_demux_debug
/*
* extern functions implementations
*/
/*
* metadataparse_util_tag_list_add_chunk:
* @taglist: tag list in which the whole chunk tag will be added
* @mode: GStreamer merge mode
* @name: name of the tag (ex: GST_TAG_EXIF, GST_TAG_IPTC, GST_TAG_XMP)
* @adapter: contains the whole chunk to be added as tag to @taglist
*
* This function get all the bytes from @adapter, create a GST_BUFFER, copy
* the bytes to it and then add it to @taglist as a tage @name using a
* merge @mode.
*
* Returns: nothing.
*/
void
metadataparse_util_tag_list_add_chunk (GstTagList * taglist,
GstTagMergeMode mode, const gchar * name, GstAdapter * adapter)
{
GstBuffer *buf;
guint size;
if (adapter && (size = gst_adapter_available (adapter))) {
buf = gst_buffer_new_and_alloc (size);
gst_adapter_copy (adapter, GST_BUFFER_DATA (buf), 0, size);
gst_tag_list_add (taglist, mode, name, buf, NULL);
gst_buffer_unref (buf);
}
}
/*
* metadataparse_util_hold_chunk:
* @read: number of bytes that still need to be hold
* @buf: [in] data to be parsed
* @bufsize: [in] size of @buf in bytes
* @next_start: indicates a pointer after the @buf where the next parsing step
* should start from
* @next_size: indicates the minimal size of the the buffer to be given on
* the next call to the parser
* @adapter: adapter to hold the chunk
* NOTE: To have a explanation of each parameters of this function look at the
* documentation of #metadataparse_jpeg_reading or #metadataparse_png_reading
*
* This function holds a chunk into the adapter. If there is enough bytes
* (*@read > *@bufsize), then it just hold and make the parser continue after
* the chunk by setting @next_start properly. Otherwise, if there is not
* enough bytes in @buf, it just set @next_start and @next_size, to make the
* parse return META_PARSING_NEED_MORE_DATA and request the caller the proper
* offset and size, so in the sencond time this function is called it should
* (or must) have enough data hold the whole chunk.
*
* Returns:
* <itemizedlist>
* <listitem><para>%META_PARSING_ERROR
* </para></listitem>
* <listitem><para>%META_PARSING_DONE if the chunk bas been completely hold
* </para></listitem>
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
* called again (look @next_start and @next_size)
* </para></listitem>
* </itemizedlist>
*/
MetadataParsingReturn
metadataparse_util_hold_chunk (guint32 * read, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start,
guint32 * next_size, GstAdapter ** adapter)
{
int ret;
if (*read > *bufsize) {
*next_start = *buf;
*next_size = *read;
ret = META_PARSING_NEED_MORE_DATA;
} else {
GstBuffer *gst_buf;
if (NULL == *adapter) {
*adapter = gst_adapter_new ();
}
gst_buf = gst_buffer_new_and_alloc (*read);
memcpy (GST_BUFFER_DATA (gst_buf), *buf, *read);
gst_adapter_push (*adapter, gst_buf);
*next_start = *buf + *read;
*buf += *read;
*bufsize -= *read;
*read = 0;
ret = META_PARSING_DONE;
}
return ret;
}
/*
* metadataparse_util_jump_chunk:
* NOTE: To have a explanation of each parameters of this function look at
* the documentation of #metadataparse_util_hold_chunk
*
* This function works in the same way as #metadataparse_util_hold_chunk, but
* just skip the bytes instead of also hold it
*
*/
MetadataParsingReturn
metadataparse_util_jump_chunk (guint32 * read, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
{
int ret;
if (*read > *bufsize) {
*read -= *bufsize;
*next_size = 2;
*next_start = *buf + *bufsize + *read;
*read = 0;
*bufsize = 0;
ret = META_PARSING_NEED_MORE_DATA;
} else {
*next_start = *buf + *read;
*buf += *read;
*bufsize -= *read;
*read = 0;
ret = META_PARSING_DONE;
}
return ret;
}

View file

@ -1,76 +0,0 @@
/*
* 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_METADATAPARSE_UTIL_H__
#define __GST_METADATAPARSE_UTIL_H__
/*
* includes
*/
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include "metadatatypes.h"
G_BEGIN_DECLS
/*
* external function prototypes
*/
extern void
metadataparse_util_tag_list_add_chunk (GstTagList * taglist,
GstTagMergeMode mode, const gchar * name, GstAdapter * adapter);
extern MetadataParsingReturn
metadataparse_util_hold_chunk (guint32 * read, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size,
GstAdapter ** adapter);
extern MetadataParsingReturn
metadataparse_util_jump_chunk (guint32 * read, guint8 ** buf,
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
G_END_DECLS
#endif /* __GST_METADATAPARSE_UTIL_H__ */

View file

@ -1,453 +0,0 @@
/*
* 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: metadatatags
* @short_description: This module contains has tag definitions to be mapped
* to EXIF, IPTC and XMP tags.
*
* This module register tags need for image metadata but aren't already define
* in GStreamer base. So, the EXIF, IPTC and XMP tags can be mapped to tags
* not registered in this file (tags already in GST base)
*
* When changing this file, update 'metadata_mapping.htm' file too.
*
* Last reviewed on 2008-01-24 (0.10.15)
*/
/*
* includes
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "metadatatags.h"
/*
* static helper functions declaration
*/
static void metadata_tags_exif_register (void);
static void metadata_tags_iptc_register (void);
static void metadata_tags_xmp_register (void);
/*
* extern functions implementations
*/
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 ();
}
/*
* static helper functions implementation
*/
/*
* EXIF tags
*/
static void
metadata_tags_exif_register (void)
{
/* capture tags */
gst_tag_register (GST_TAG_CAPTURE_APERTURE, GST_TAG_FLAG_META,
GST_TYPE_FRACTION, GST_TAG_CAPTURE_APERTURE,
"Aperture (in APEX units)", NULL);
/* The unit is the APEX value.
Ordinarily it is given in the range of -99.99 to 99.99.
if numerator is 0xFFFFFFFF means unknown
*/
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);
/*
* 1- sRGB
* 0xFFFF - Uncalibrated
*/
gst_tag_register (GST_TAG_CAPTURE_COLOR_SPACE, GST_TAG_FLAG_META,
G_TYPE_UINT, GST_TAG_CAPTURE_COLOR_SPACE, "Color Space", NULL);
/*
from -100 to 100
[-100, -34] - soft
[-33, 33] - normal
[34, 100] - hard
*** exif is just 0, 1, 2 (normal, soft and hard)
*/
gst_tag_register (GST_TAG_CAPTURE_CONTRAST, GST_TAG_FLAG_META, G_TYPE_INT,
GST_TAG_CAPTURE_CONTRAST, "Contrast", NULL);
/*
* 0- Normal process
* 1- Custom process
*/
gst_tag_register (GST_TAG_CAPTURE_CUSTOM_RENDERED, GST_TAG_FLAG_META,
G_TYPE_UINT, GST_TAG_CAPTURE_CUSTOM_RENDERED,
"Indicates the use of special processing on image data", NULL);
/* if Zero ZOOM not used
*/
gst_tag_register (GST_TAG_CAPTURE_DIGITAL_ZOOM, GST_TAG_FLAG_META,
GST_TYPE_FRACTION, GST_TAG_CAPTURE_DIGITAL_ZOOM, "Digital zoom ratio",
NULL);
/*
* 0 - Auto exposure
* 1 - Manual exposure
* 2 - Auto bracket (the camera shoots a series of frames of the same scene
* at different exposure settings)
*/
gst_tag_register (GST_TAG_CAPTURE_EXPOSURE_MODE, GST_TAG_FLAG_META,
G_TYPE_UINT, GST_TAG_CAPTURE_EXPOSURE_MODE, "Exposure Mode", NULL);
/*
0 - not defined
1- Manual
2- Normal program
3- Aperture priority
4- Shutter priority
5- Creative program (biased toward death of field)
6- Action program (biased toward fast shutter speed)
7- Portrait mode (for closeup photos with the background out of focus)
8- Landscape mode (for landscape photos with the background in focus)
*** exif is until here ***
9- Night
10- Back-light
11- Spotlight
12- Snow
13- Beach
*/
gst_tag_register (GST_TAG_CAPTURE_EXPOSURE_PROGRAM, GST_TAG_FLAG_META,
G_TYPE_UINT, GST_TAG_CAPTURE_EXPOSURE_PROGRAM,
"Class of program used for exposure", NULL);
gst_tag_register (GST_TAG_CAPTURE_EXPOSURE_TIME, GST_TAG_FLAG_META,
GST_TYPE_FRACTION, GST_TAG_CAPTURE_EXPOSURE_TIME,
"Exposure time in seconds", NULL);
/*
* bits (76543210) indicating the flash status:
* 0- Flash firing
* 0- Flash did not fire
* 1- Flash fired
* 1,2- Flash return
* 00- No strobe return detection function
* 01- reserved
* 10- Strobe return light not detected
* 11- Strobe return light detected.
* 3,4- Flash mode
* 00- unknown
* 01- Compulsory flash firing
* 10- Compulsory flash suppression
* 11- Auto mode
* 5- if flash function is present
* 0- Flash function present
* 1- No flash function
* 6- Red-eye mode
* 0- No red-eye reduction mode or unknown
* 1- Red-eye reduction supported
* So, we have the following possible values:
*
* 0000.H = Flash did not fire.
* 0001.H = Flash fired.
* 0005.H = Strobe return light not detected.
* 0007.H = Strobe return light detected.
* 0009.H = Flash fired, compulsory flash mode
* 000D.H = Flash fired, compulsory flash mode, return light not detected
* 000F.H = Flash fired, compulsory flash mode, return light detected
* 0010.H = Flash did not fire, compulsory flash mode
* 0018.H = Flash did not fire, auto mode
* 0019.H = Flash fired, auto mode
* 001D.H = Flash fired, auto mode, return light not detected
* 001F.H = Flash fired, auto mode, return light detected
* 0020.H = No flash function
* 0041.H = Flash fired, red-eye reduction mode
* 0045.H = Flash fired, red-eye reduction mode, return light not detected
* 0047.H = Flash fired, red-eye reduction mode, return light detected
* 0049.H = Flash fired, compulsory flash mode, red-eye reduction mode
* 004D.H = Flash fired, compulsory flash mode, red-eye reduction mode,
* return light not detected
* 004F.H = Flash fired, compulsory flash mode, red-eye reduction mode,
* return light detected
* 0059.H = Flash fired, auto mode, red-eye reduction mode
* 005D.H = Flash fired, auto mode, return light not detected,
* red-eye reduction mode
* 005F.H = Flash fired, auto mode, return light detected,
* red-eye reduction mode
* Other = reserved
*/
gst_tag_register (GST_TAG_CAPTURE_FLASH, GST_TAG_FLAG_META,
G_TYPE_UINT, GST_TAG_CAPTURE_FLASH, "Flash status", 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_FOCAL_LEN, GST_TAG_FLAG_META,
GST_TYPE_FRACTION, GST_TAG_CAPTURE_FOCAL_LEN,
"Focal length of lens used to take image. Unit is millimeter", NULL);
/*
0- None
1- Low gain up
2- High gain up
3- Low gain down
4- High gain down
*/
gst_tag_register (GST_TAG_CAPTURE_GAIN, GST_TAG_FLAG_META, G_TYPE_UINT,
GST_TAG_CAPTURE_GAIN, "", NULL);
gst_tag_register (GST_TAG_CAPTURE_ISO_SPEED_RATINGS, GST_TAG_FLAG_META,
G_TYPE_INT, GST_TAG_CAPTURE_ISO_SPEED_RATINGS,
"ISO Speed and ISO Latitude as specified in ISO 12232", NULL);
/*
0- unknown (default)
1- Daylight
2- Fluorescent
3- Tungsten (incandescent light)
4- Flash
9- Fine weather
10- Cloudy weather
11- Shade
12- Daylight fluorescent (D 5700 %G%@ 7100K)
13- Day white fluorescent (N 4600 %G%@ 5400K)
14- Cool white fluorescent (W 3900 %G%@ 4500K)
15- White fluorescent (WW 3200 %G%@ 3700K)
17- Standard light A
18- Standard light B
19- Standard light C
20- D55
21- D65
22- D75
23- D50
24- ISO studio tungsten
255- other light source
Other = reserved
*/
gst_tag_register (GST_TAG_CAPTURE_LIGHT_SOURCE, GST_TAG_FLAG_META,
G_TYPE_UINT, GST_TAG_CAPTURE_LIGHT_SOURCE,
"The kind of light source.", NULL);
/*
* The relation of the '0th row' and '0th column' to visual position:
* 1- top-left
* 2- top-right
* 3- bottom-right
* 4- bottom-left
* 5- left-top
* 6- right-top
* 7- right-bottom
* 8- left-bottom
*/
gst_tag_register (GST_TAG_CAPTURE_ORIENTATION, GST_TAG_FLAG_META,
G_TYPE_UINT, GST_TAG_CAPTURE_ORIENTATION,
"The orientation of the camera.", NULL);
/*
from -100 to 100
[-100, -34] - low
[-33, 33] - normal
[34, 100] - high
*** exif is just 0, 1, 2 (normal, low and high)
*/
gst_tag_register (GST_TAG_CAPTURE_SATURATION, GST_TAG_FLAG_META, G_TYPE_INT,
GST_TAG_CAPTURE_SATURATION, "The saturation", NULL);
/*
* 0 - Standard
* 1 - Landscape
* 2 - Portrait
* 3 - Night scene
*/
gst_tag_register (GST_TAG_CAPTURE_SCENE_CAPTURE_TYPE, GST_TAG_FLAG_META,
G_TYPE_UINT, GST_TAG_CAPTURE_SCENE_CAPTURE_TYPE, "Scene Type", NULL);
gst_tag_register (GST_TAG_CAPTURE_SHUTTER_SPEED, GST_TAG_FLAG_META,
GST_TYPE_FRACTION, GST_TAG_CAPTURE_SHUTTER_SPEED, "Shutter speed (APEX)",
NULL);
/*
0- Auto
1- Off
*** exif is until here ***
2- Sunlight
3- Cloudy
4- Shade
5- Tungsten
6- Fluorescent
7- Incandescent
8- Flash
9- Horizon (sun on the horizon)
*/
gst_tag_register (GST_TAG_CAPTURE_WHITE_BALANCE, GST_TAG_FLAG_META,
G_TYPE_UINT, GST_TAG_CAPTURE_WHITE_BALANCE, "White balance mode", NULL);
/* generic tags */
gst_tag_register (GST_TAG_CREATOR_TOOL, GST_TAG_FLAG_META, G_TYPE_STRING,
GST_TAG_CREATOR_TOOL,
"The name of the first known tool used to create the resource."
" Or firmware or driver version of device", NULL);
/* date and time tags */
/* formated as subset of ISO RFC 8601 as described in
* http://www.w3.org/TR/1998/NOTE-datetime-19980827
* which is:
* YYYY
* YYYY-MM
* YYYY-MM-DD
* YYYY-MM-DDThh:mmTZD
* YYYY-MM-DDThh:mm:ssTZD
* YYYY-MM-DDThh:mm:ss.sTZD
* where:
* YYYY = four-digit year
* MM = two-digit month (01=January)
* DD = two-digit day of month (01 through 31)
* hh = two digits of hour (00 through 23)
* mm = two digits of minute (00 through 59)
* ss = two digits of second (00 through 59)
* s = one or more digits representing a decimal fraction of a second
* TZD = time zone designator (Z or +hh:mm or -hh:mm)
*/
gst_tag_register (GST_TAG_DATE_TIME_DIGITIZED, GST_TAG_FLAG_META,
G_TYPE_STRING, GST_TAG_DATE_TIME_DIGITIZED,
"Date/Time of image digitized", NULL);
gst_tag_register (GST_TAG_DATE_TIME_MODIFIED, GST_TAG_FLAG_META,
G_TYPE_STRING, GST_TAG_DATE_TIME_MODIFIED,
"Date/Time of image was last modified", NULL);
gst_tag_register (GST_TAG_DATE_TIME_ORIGINAL, GST_TAG_FLAG_META,
G_TYPE_STRING, GST_TAG_DATE_TIME_ORIGINAL,
"Date/Time of original image taken", NULL);
/* devices tags */
gst_tag_register (GST_TAG_DEVICE_MAKE, GST_TAG_FLAG_META,
G_TYPE_STRING, GST_TAG_DEVICE_MAKE,
"The manufacturer of the recording equipment", NULL);
gst_tag_register (GST_TAG_DEVICE_MODEL, GST_TAG_FLAG_META, G_TYPE_STRING,
GST_TAG_DEVICE_MODEL, "The model name or model number of the equipment",
NULL);
/* exif specific tags */
gst_tag_register (GST_TAG_EXIF_MAKER_NOTE, GST_TAG_FLAG_META,
GST_TYPE_BUFFER, GST_TAG_EXIF_MAKER_NOTE, "Camera private data", NULL);
/* image tags */
gst_tag_register (GST_TAG_IMAGE_HEIGHT, GST_TAG_FLAG_META,
G_TYPE_UINT, GST_TAG_IMAGE_HEIGHT, "Image height in pixels", NULL);
gst_tag_register (GST_TAG_IMAGE_WIDTH, GST_TAG_FLAG_META,
G_TYPE_UINT, GST_TAG_IMAGE_WIDTH, "Image width in pixels", 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);
}
/*
* IPTC tags
*/
static void
metadata_tags_iptc_register (void)
{
}
/*
* XMP tags
*/
static void
metadata_tags_xmp_register (void)
{
}

View file

@ -1,139 +0,0 @@
/*
* 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_TAGS_H__
#define __GST_METADATA_TAGS_H__
/*
* includes
*/
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
G_BEGIN_DECLS
/*
* enum and types
*/
/* set bit to desired mapping */
typedef enum {
METADATA_TAG_MAP_INDIVIDUALS = 1 << 0,
METADATA_TAG_MAP_WHOLECHUNK = 1 << 1
} MetadataTagMapping;
/*
* defines
*/
/* *INDENT-OFF* */
/* whole chunk tags */
#define GST_TAG_EXIF "exif"
#define GST_TAG_IPTC "iptc"
#define GST_TAG_XMP "xmp"
/* individual tags */
#define GST_TAG_CAPTURE_APERTURE "capture-aperture"
#define GST_TAG_CAPTURE_BRIGHTNESS "capture-brightness"
#define GST_TAG_CAPTURE_COLOR_SPACE "capture-color-space"
#define GST_TAG_CAPTURE_CONTRAST "capture-contrast"
#define GST_TAG_CAPTURE_CUSTOM_RENDERED "capture-custom-rendered"
#define GST_TAG_CAPTURE_DIGITAL_ZOOM "capture-digital-zoom"
#define GST_TAG_CAPTURE_EXPOSURE_MODE "capture-exposure-mode"
#define GST_TAG_CAPTURE_EXPOSURE_PROGRAM "capture-exposure-program"
#define GST_TAG_CAPTURE_EXPOSURE_TIME "capture-exposure-time"
#define GST_TAG_CAPTURE_FLASH "capture-flash"
#define GST_TAG_CAPTURE_FNUMBER "capture-fnumber"
#define GST_TAG_CAPTURE_FOCAL_LEN "capture-focal-len"
#define GST_TAG_CAPTURE_GAIN "capture-gain"
#define GST_TAG_CAPTURE_ISO_SPEED_RATINGS "capture-iso-speed-ratings"
#define GST_TAG_CAPTURE_LIGHT_SOURCE "capture-light-source"
#define GST_TAG_CAPTURE_ORIENTATION "capture-orientation"
#define GST_TAG_CAPTURE_SATURATION "capture-saturation"
#define GST_TAG_CAPTURE_SCENE_CAPTURE_TYPE "capture-scene-capture-type"
#define GST_TAG_CAPTURE_SHUTTER_SPEED "capture-shutter-speed"
#define GST_TAG_CAPTURE_WHITE_BALANCE "capture-white-balance"
#define GST_TAG_CREATOR_TOOL "creator-tool"
#define GST_TAG_DATE_TIME_DIGITIZED "date-time-digitized"
#define GST_TAG_DATE_TIME_MODIFIED "date-time-modified"
#define GST_TAG_DATE_TIME_ORIGINAL "date-time-original"
#define GST_TAG_DEVICE_MAKE "device-make"
#define GST_TAG_DEVICE_MODEL "device-model"
#define GST_TAG_EXIF_MAKER_NOTE "exif-maker-note"
#define GST_TAG_IMAGE_HEIGHT "image-height"
#define GST_TAG_IMAGE_WIDTH "image-width"
#define GST_TAG_IMAGE_XRESOLUTION "image-xresolution"
#define GST_TAG_IMAGE_YRESOLUTION "image-yresolution"
#define GST_TAG_GPS_AREA_INFORMATION ""
#define GST_TAG_GPS_DIFFERENTIAL ""
#define GST_TAG_GPS_DOP ""
#define GST_TAG_GPS_IMAGE_DIRECTION ""
#define GST_TAG_GPS_MEASURE_MODE ""
#define GST_TAG_GPS_PROCESSING_METHOD ""
#define GST_TAG_GPS_SATELLITES ""
#define GST_TAG_GPS_SPEED ""
#define GST_TAG_GPS_TRACK ""
/* *INDENT-ON* */
/*
* external function prototypes
*/
extern void
metadata_tags_register (void);
G_END_DECLS
#endif /* __GST_METADATA_TAGS_H__ */

View file

@ -1,247 +0,0 @@
/*
* 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: metadatatypes
* @short_description: This module contains function to operates a list of
* chunks
*
* Last reviewed on 2008-01-24 (0.10.15)
*/
/*
* includes
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "metadatatypes.h"
#include <string.h>
/*
* extern functions implementations
*/
/*
* metadata_chunk_array_init:
* @array: an array of chunks
* @alloc_size: number of chunks that can be added to the array without futher
* allocation
*
* Call this function before any other function in this module.
* Nerver call this function a second time without call
* #metadata_chunk_array_free beteween them
* An example of use is:
* int test() { MetadataChunkArray a; metadata_chunk_array_init(&a, 1); ... }
*
* Returns: nothing
*/
void
metadata_chunk_array_init (MetadataChunkArray * array, gsize alloc_size)
{
array->len = 0;
array->chunk = g_new0 (MetadataChunk, alloc_size);
array->allocated_len = alloc_size;
}
/*
* metadata_chunk_array_free:
* @array: an array of chunks
*
* Call this function after have finished using the @array to free any internal
* memory alocated by it.
*
* Returns: nothing
*/
void
metadata_chunk_array_free (MetadataChunkArray * array)
{
metadata_chunk_array_clear (array);
array->allocated_len = 0;
g_free (array->chunk);
array->chunk = NULL;
}
/*
* metadata_chunk_array_clear:
* @array: an array of chunks
*
* Free memory allocated internally by each chunk and set the @array->len to 0
* (zero). So, the number of chunks into the array will be zero,
* but the number of slots into the array to strore chunks will be kept
*
* Returns: nothing
*/
void
metadata_chunk_array_clear (MetadataChunkArray * array)
{
while (array->len) {
array->len--;
g_free (array->chunk[array->len].data);
}
}
/*
* metadata_chunk_array_append:
* @array: an array of chunks
* @chunk: chunk to be append
*
* Just append a @chunk to the end of the @array. The @array now will be the
* owner of @chunk->data. Just call this function if you a sure the @array
* chunks will be sorted by @chunk->offset_orig anyway.
* @see_also: #metadata_chunk_array_append_sorted
*
* Returns: nothing
*/
void
metadata_chunk_array_append (MetadataChunkArray * array, MetadataChunk * chunk)
{
if (array->len == array->allocated_len) {
array->allocated_len += 2;
array->chunk =
g_realloc (array->chunk, sizeof (MetadataChunk) * array->allocated_len);
}
memcpy (&array->chunk[array->len], chunk, sizeof (MetadataChunk));
++array->len;
}
/*
* metadata_chunk_array_append_sorted:
* @array: an array of chunks
* @chunk: chunk to be append
*
* Append a @chunk sorted by @chunk->offset_orig the @array. The @array now
* will be the owner of @chunk->data. This function supposes that @array
* is already sorted by @chunk->offset_orig.
* @see_also: #metadata_chunk_array_append
*
* Returns: nothing
*/
void
metadata_chunk_array_append_sorted (MetadataChunkArray * array,
MetadataChunk * chunk)
{
gint32 i, pos;
if (array->len == array->allocated_len) {
array->allocated_len += 2;
array->chunk =
g_realloc (array->chunk, sizeof (MetadataChunk) * array->allocated_len);
}
pos = array->len;
for (i = array->len - 1; i >= 0; --i) {
if (chunk->offset_orig >= array->chunk[i].offset_orig) {
break;
}
}
pos = i + 1;
if (pos < array->len) {
memmove (&array->chunk[pos + 1], &array->chunk[pos],
sizeof (MetadataChunk) * (array->len - pos));
}
memcpy (&array->chunk[pos], chunk, sizeof (MetadataChunk));
++array->len;
return;
}
/*
* metadata_chunk_array_remove_zero_size:
* @array: an array of chunks
*
* This function removes all the chunks in @array that has 'chunk.size == 0'.
* It is possible to have the 'chunk.data==NULL' and 'chunk.size != 0', those
* chunks are used by muxer for lazy 'filling' and are not removed by this
* function.
*
* Returns: nothing
*/
void
metadata_chunk_array_remove_zero_size (MetadataChunkArray * array)
{
int i;
for (i = 0; i < array->len;) {
if (array->chunk[i].size == 0) {
if (i < --array->len) {
memmove (&array->chunk[i], &array->chunk[i + 1],
sizeof (MetadataChunk) * (array->len - i));
}
} else {
++i;
}
}
}
/*
* metadata_chunk_array_remove_by_index:
* @array: an array of chunks
* @i: index of chunk to be removed
*
* This function removes the chunk at index @i from @array
*
* Returns: nothing
*/
void
metadata_chunk_array_remove_by_index (MetadataChunkArray * array, guint32 i)
{
if (i < array->len) {
g_free (array->chunk[i].data);
if (i < --array->len) {
memmove (&array->chunk[i], &array->chunk[i + 1],
sizeof (MetadataChunk) * (array->len - i));
}
}
}

View file

@ -1,115 +0,0 @@
/*
* 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 __METADATATYPES_H__
#define __METADATATYPES_H__
/*
* includes
*/
#include <glib.h>
G_BEGIN_DECLS
/*
* enum and types
*/
/* *INDENT-OFF* */
typedef enum _tag_MetadataParsingReturn {
META_PARSING_ERROR = -1,
META_PARSING_DONE = 0,
META_PARSING_NEED_MORE_DATA = 1
} MetadataParsingReturn;
/* *INDENT-ON* */
typedef enum _tag_MetadataChunkType
{
MD_CHUNK_UNKNOWN,
MD_CHUNK_EXIF,
MD_CHUNK_IPTC,
MD_CHUNK_XMP
} MetadataChunkType;
typedef struct _tag_MetadataChunk
{
gint64 offset_orig; /* from the beginning of original file */
/*here just for convinience (filled by element) offset in new stream */
gint64 offset;
guint32 size; /* chunk or buffer size */
guint8 *data;
MetadataChunkType type; /* used by mux to see what tags to insert here */
} MetadataChunk;
typedef struct _tag_MetadataChunkArray
{
MetadataChunk *chunk;
gsize len; /* number of chunks into aray */
gsize allocated_len; /* number of slots into the array to store chunks */
} MetadataChunkArray;
/*
* external function prototypes
*/
extern void
metadata_chunk_array_init (MetadataChunkArray * array, gsize alloc_size);
extern void metadata_chunk_array_free (MetadataChunkArray * array);
extern void metadata_chunk_array_clear (MetadataChunkArray * array);
extern void
metadata_chunk_array_append (MetadataChunkArray * array, MetadataChunk * chunk);
extern void
metadata_chunk_array_append_sorted (MetadataChunkArray * array,
MetadataChunk * chunk);
extern void metadata_chunk_array_remove_zero_size (MetadataChunkArray * array);
extern void
metadata_chunk_array_remove_by_index (MetadataChunkArray * array, guint32 i);
G_END_DECLS
#endif /* __METADATATYPES_H__ */

View file

@ -1,904 +0,0 @@
/*
* 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: metadataxmp
* @short_description: This module provides functions to extract tags from
* XMP metadata chunks and create XMP chunks from metadata tags.
* @see_also: #metadatatags.[c/h]
*
* If lib exempi isn't available at compilation time, only the whole chunk
* (#METADATA_TAG_MAP_WHOLECHUNK) tags is created. It means that individual
* tags aren't mapped.
*
* <refsect2>
* <para>
* #metadata_xmp_init must be called before any other function in this
* module and must be paired with a call to #metadata_xmp_dispose
* </para>
* </refsect2>
*
* Last reviewed on 2008-01-24 (0.10.15)
*/
/*
* includes
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "metadataxmp.h"
#include "metadataparseutil.h"
#include "metadatatags.h"
/*
* defines
*/
GST_DEBUG_CATEGORY (gst_metadata_xmp_debug);
#define GST_CAT_DEFAULT gst_metadata_xmp_debug
/*
* Implementation when lib exempi isn't available at compilation time
*/
#ifndef HAVE_XMP
/*
* extern functions implementations
*/
gboolean
metadata_xmp_init (void)
{
return TRUE;
}
void
metadata_xmp_dispose (void)
{
return;
}
void
metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
GstAdapter * adapter, MetadataTagMapping mapping)
{
if (mapping & METADATA_TAG_MAP_WHOLECHUNK) {
GST_LOG ("XMP not defined, sending just one tag as whole chunk");
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_XMP, adapter);
}
}
void
metadatamux_xmp_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
const GstTagList * taglist)
{
/* do nothing */
}
#else /* ifndef HAVE_XMP */
/*
* Implementation when lib exempi isn't available at compilation time
*/
/*
* includes
*/
#include <exempi/xmp.h>
#include <string.h>
/*
* enum and types
*/
typedef struct _tag_SchemaTagMap
{
const gchar *xmp_tag;
const gchar *gst_tag;
} SchemaTagMap;
typedef struct _tag_SchemaMap
{
const gchar *schema;
const gchar *prefix;
const guint8 prefix_len;
const SchemaTagMap *tags_map;
} SchemaMap;
/*
* defines and static global vars
*/
#define XMP_SCHEMA_NODE 0x80000000UL
/* *INDENT-OFF* */
/* When changing these tables, update 'metadata_mapping.htm' file too. */
static const SchemaTagMap schema_map_dublin_tags_map[] = {
{"creator", GST_TAG_ARTIST },
{"description", GST_TAG_DESCRIPTION },
{"format", GST_TAG_VIDEO_CODEC },
{"rights", GST_TAG_COPYRIGHT },
{"subject", GST_TAG_KEYWORDS },
{"title", GST_TAG_TITLE },
{"type", GST_TAG_CODEC },
{NULL, NULL}
};
static const SchemaTagMap schema_map_photoshop_tags_map[] = {
{"Country", GST_TAG_GEO_LOCATION_COUNTRY },
{"City", GST_TAG_GEO_LOCATION_CITY },
{NULL, NULL}
};
static const SchemaTagMap schema_map_iptc4xmpcore_tags_map[] = {
{"location", GST_TAG_GEO_LOCATION_SUBLOCATION },
{NULL, NULL}
};
/* *INDENT-ON* */
static const SchemaMap schema_map_dublin = {
"http://purl.org/dc/elements/1.1/",
"dc:",
3,
schema_map_dublin_tags_map
};
/* http://www.adobe.com/devnet/xmp/pdfs/xmp_specification.pdf */
static const SchemaMap schema_map_photoshop = {
"http://ns.adobe.com/photoshop/1.0/",
"photoshop:",
10,
schema_map_photoshop_tags_map
};
/* http://www.iptc.org/std/Iptc4xmpCore/1.0/specification/Iptc4xmpCore_1.0-spec-XMPSchema_8.pdf */
static const SchemaMap schema_map_iptc4xmpcore = {
"http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/",
"Iptc4xmpCore:",
13,
schema_map_iptc4xmpcore_tags_map
};
static const SchemaMap *schemas_map[] = {
&schema_map_dublin,
&schema_map_photoshop,
&schema_map_iptc4xmpcore,
NULL
};
/*
* static helper functions declaration
*/
static const SchemaTagMap *metadataparse_xmp_get_tagsmap_from_path (const
SchemaMap * schema_map, const gchar * path, uint32_t opt);
static const SchemaTagMap *metadatamux_xmp_get_tagsmap_from_gsttag (const
SchemaMap * schema_map, const gchar * tag);
static void
metadataparse_xmp_iter (GstTagList * taglist, GstTagMergeMode mode, XmpPtr xmp);
static void
metadataparse_xmp_iter_node_schema (GstTagList * taglist, GstTagMergeMode mode,
XmpPtr xmp, const char *schema, const char *path);
static void
metadataparse_xmp_iter_array (GstTagList * taglist, GstTagMergeMode mode,
XmpPtr xmp, const char *schema, const char *path,
const SchemaMap * schema_map);
static void
metadataparse_xmp_iter_simple_qual (GstTagList * taglist, GstTagMergeMode mode,
const char *path, const char *value, const SchemaMap * schema_map);
static void
metadataparse_xmp_iter_simple (GstTagList * taglist, GstTagMergeMode mode,
const char *path, const char *value, const SchemaMap * schema_map);
static void
metadataparse_xmp_iter_add_to_tag_list (GstTagList * taglist,
GstTagMergeMode mode, const char *path, const char *value,
const SchemaMap * schema_map, const uint32_t opt);
static void
metadatamux_xmp_for_each_tag_in_list (const GstTagList * list,
const gchar * tag, gpointer user_data);
/*
* extern functions implementations
*/
/*
* metadata_xmp_init:
*
* Init lib exempi (if present in compilation time)
* This function must be called before any other function from this module.
* This function must not be called twice without call
* to #metadata_xmp_dispose beteween them.
* @see_also: #metadata_xmp_dispose
*
* Returns: nothing
*/
gboolean
metadata_xmp_init (void)
{
return xmp_init ();
}
/*
* metadata_xmp_dispose:
*
* Call this function to free any resource allocated by #metadata_xmp_init
* @see_also: #metadata_xmp_init
*
* Returns: nothing
*/
void
metadata_xmp_dispose (void)
{
xmp_terminate ();
}
/*
* metadataparse_xmp_tag_list_add:
* @taglist: tag list in which extracted tags will be added
* @mode: tag list merge mode
* @adapter: contains the XMP metadata chunk
* @mapping: if is to extract individual tags and/or the whole chunk.
*
* This function gets a XMP chunk (@adapter) and extract tags from it
* and then to add to @taglist.
* Note: The XMP chunk (@adapetr) must NOT be wrapped by any bytes specific
* to any file format
* @see_also: #metadataparse_xmp_iter
*
* Returns: nothing
*/
void
metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
GstAdapter * adapter, MetadataTagMapping mapping)
{
const guint8 *buf;
guint32 size;
XmpPtr xmp = NULL;
if (adapter == NULL || (size = gst_adapter_available (adapter)) == 0) {
goto done;
}
/* add chunk tag */
if (mapping & METADATA_TAG_MAP_WHOLECHUNK) {
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_XMP, adapter);
}
if (!(mapping & METADATA_TAG_MAP_INDIVIDUALS))
goto done;
buf = gst_adapter_peek (adapter, size);
xmp = xmp_new ((gchar *) buf, size);
if (!xmp)
goto done;
metadataparse_xmp_iter (taglist, mode, xmp);
done:
if (xmp) {
xmp_free (xmp);
}
return;
}
/*
* metadatamux_xmp_create_chunk_from_tag_list:
* @buf: buffer that will have the created XMP chunk
* @size: size of the buffer that will be created
* @taglist: list of tags to be added to XMP chunk
*
* Get tags from @taglist, create a XMP chunk based on it and save to @buf.
* Note: The XMP chunk is NOT wrapped by any bytes specific to any file format
*
* Returns: nothing
*/
void
metadatamux_xmp_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
const GstTagList * taglist)
{
GstBuffer *xmp_chunk = NULL;
const GValue *val = NULL;
XmpPtr xmp = NULL;
XmpStringPtr xmp_str_buf = xmp_string_new ();
if (!(buf && size))
goto done;
g_free (*buf);
*buf = NULL;
*size = 0;
val = gst_tag_list_get_value_index (taglist, GST_TAG_XMP, 0);
if (val) {
xmp_chunk = gst_value_get_buffer (val);
if (xmp_chunk)
xmp =
xmp_new ((gchar *) GST_BUFFER_DATA (xmp_chunk),
GST_BUFFER_SIZE (xmp_chunk));
}
if (NULL == xmp)
xmp = xmp_new_empty ();
gst_tag_list_foreach (taglist, metadatamux_xmp_for_each_tag_in_list, xmp);
if (!xmp_serialize (xmp, xmp_str_buf, 0, 2)) {
GST_ERROR ("failed to serialize xmp into chunk\n");
} else if (xmp_str_buf) {
const gchar *text = xmp_string_cstr (xmp_str_buf);
*buf = (guint8 *) g_strdup (text);
*size = strlen (text);
} else {
GST_ERROR ("failed to serialize xmp into chunk\n");
}
done:
if (xmp_str_buf)
xmp_string_free (xmp_str_buf);
if (xmp)
xmp_free (xmp);
return;
}
/*
* static helper functions implementation
*/
/*
* metadataparse_xmp_get_tagsmap_from_path:
* @schema_map: Structure containg a map beteween GST tags and tags into a XMP
* schema
* @path: string describing a XMP tag
* @opt: indicates if the string (@path) has extras caracters like '[' and ']'
*
* This returns a structure that contains the GStreamer tag mapped to an XMP
* tag.
*
* Returns:
* <itemizedlist>
* <listitem><para>Structure containing the GST tag mapped
* to the XMP tag (@path)
* </para></listitem>
* <listitem><para>%NULL if there is no mapped GST tag for XMP tag (@path)
* </para></listitem>
* </itemizedlist>
*/
static const SchemaTagMap *
metadataparse_xmp_get_tagsmap_from_path (const SchemaMap * schema_map,
const gchar * path, uint32_t opt)
{
GString *string = NULL;
gchar *ch;
SchemaTagMap *tags_map = NULL;
if (NULL == schema_map)
goto done;
tags_map = (SchemaTagMap *) schema_map->tags_map;
if (XMP_HAS_PROP_QUALIFIERS (opt) || XMP_IS_ARRAY_ALTTEXT (opt)) {
string = g_string_new (path);
/* remove the language qualifier "[xxx]" */
ch = string->str + string->len - 3;
while (ch != string->str + schema_map->prefix_len) {
if (*ch == '[') {
*ch = '\0';
}
--ch;
}
} else {
ch = (gchar *) path + schema_map->prefix_len;
}
while (tags_map->xmp_tag) {
if (0 == strcmp (tags_map->xmp_tag, ch))
break;
tags_map++;
}
done:
if (string)
g_string_free (string, TRUE);
return tags_map;
}
/*
* metadatamux_xmp_get_tagsmap_from_gsttag:
* @schema_map: Structure containg a map beteween GST tags and tags into a XMP
* schema
* @tag: GStreaner tag to look for
*
* This returns a structure that contains the XMP tag mapped to a GStreamer
* tag.
*
* Returns:
* <itemizedlist>
* <listitem><para>Structure containing the XMP tag mapped
* to the GST tag (@path)
* </para></listitem>
* <listitem><para>%NULL if there is no mapped XMP tag for GST @tag
* </para></listitem>
* </itemizedlist>
*/
static const SchemaTagMap *
metadatamux_xmp_get_tagsmap_from_gsttag (const SchemaMap * schema_map,
const gchar * tag)
{
SchemaTagMap *tags_map = NULL;
int i;
if (NULL == schema_map)
goto done;
for (i = 0; schema_map->tags_map[i].gst_tag; i++) {
if (0 == strcmp (schema_map->tags_map[i].gst_tag, tag)) {
tags_map = (SchemaTagMap *) & schema_map->tags_map[i];
break;
}
}
done:
return tags_map;
}
/*
* metadataparse_xmp_iter:
* @taglist: tag list in which extracted tags will be added
* @mode: tag list merge mode
* @xmp: handle to XMP data from lib exempi
*
* This function looks all the shemas in a XMP data (@xmp) and then calls
* #metadataparse_xmp_iter_node_schema for each schema. In the end, the idea is
* to add all XMP mapped tags to @taglist by unsing a specified merge @mode
* @see_also: #metadataparse_xmp_tag_list_add
* #metadataparse_xmp_iter_node_schema
*
* Returns: nothing
*/
void
metadataparse_xmp_iter (GstTagList * taglist, GstTagMergeMode mode, XmpPtr xmp)
{
XmpStringPtr xstr_schema = xmp_string_new ();
XmpStringPtr xstr_path = xmp_string_new ();
XmpStringPtr xstr_prop = xmp_string_new ();
uint32_t opt = 0;
XmpIteratorPtr xmp_iter = NULL;
xmp_iter = xmp_iterator_new (xmp, NULL, NULL, XMP_ITER_JUSTCHILDREN);
if (NULL == xmp_iter)
goto done;
while (xmp_iterator_next (xmp_iter, xstr_schema, xstr_path, xstr_prop, &opt)) {
const char *schema = xmp_string_cstr (xstr_schema);
const char *path = xmp_string_cstr (xstr_path);
if (XMP_IS_NODE_SCHEMA (opt)) {
GST_LOG ("%s", schema);
metadataparse_xmp_iter_node_schema (taglist, mode, xmp, schema, path);
} else {
GST_LOG ("Unexpected iteraction");
}
}
done:
if (xmp_iter)
xmp_iterator_free (xmp_iter);
if (xstr_prop)
xmp_string_free (xstr_prop);
if (xstr_path)
xmp_string_free (xstr_path);
if (xstr_schema)
xmp_string_free (xstr_schema);
}
/*
* metadataparse_xmp_iter_node_schema:
* @taglist: tag list in which extracted tags will be added
* @mode: tag list merge mode
* @xmp: handle to XMP data from lib exempi
* @schema: schema name string
* @path: schema path
*
* This function gets a @schema, finds the #SchemaMap (structure
* containing @schema description and map with GST tags) to it. And then call
* #metadataparse_xmp_iter_array. In the end, the idea is
* to add all XMP Schema mapped tags to @taglist by unsing a specified
* merge @mode
* @see_also: #metadataparse_xmp_iter
* #metadataparse_xmp_iter_array
*
* Returns: nothing
*/
void
metadataparse_xmp_iter_node_schema (GstTagList * taglist, GstTagMergeMode mode,
XmpPtr xmp, const char *schema, const char *path)
{
const SchemaMap *schema_map = NULL;
gint i;
for (i = 0; schemas_map[i]; i++) {
if (0 == strcmp (schema, schemas_map[i]->schema)) {
schema_map = schemas_map[i];
break;
}
}
metadataparse_xmp_iter_array (taglist, mode, xmp, schema, path, schema_map);
}
/*
* metadataparse_xmp_iter_array:
* @taglist: tag list in which extracted tags will be added
* @mode: tag list merge mode
* @xmp: handle to XMP data from lib exempi
* @schema: schema name string
* @path: schema path
* @schema_map: structure containing @schema description and map with GST tags
*
* This function looks all the tags into a @schema and call other functions in
* order to add the mapped ones to @taglist by using a specified merge @mode
* @see_also: #metadataparse_xmp_iter_node_schema
* #metadataparse_xmp_iter_simple_qual metadataparse_xmp_iter_simple
*
* Returns: nothing
*/
void
metadataparse_xmp_iter_array (GstTagList * taglist, GstTagMergeMode mode,
XmpPtr xmp, const char *schema, const char *path,
const SchemaMap * schema_map)
{
XmpStringPtr xstr_schema = xmp_string_new ();
XmpStringPtr xstr_path = xmp_string_new ();
XmpStringPtr xstr_prop = xmp_string_new ();
uint32_t opt = 0;
XmpIteratorPtr xmp_iter = NULL;
xmp_iter = xmp_iterator_new (xmp, schema, path, XMP_ITER_JUSTCHILDREN);
if (NULL == xmp_iter)
goto done;
while (xmp_iterator_next (xmp_iter, xstr_schema, xstr_path, xstr_prop, &opt)) {
const char *schema = xmp_string_cstr (xstr_schema);
const char *path = xmp_string_cstr (xstr_path);
const char *value = xmp_string_cstr (xstr_prop);
if (XMP_IS_NODE_SCHEMA (opt)) {
GST_LOG ("Unexpected iteraction");
} else if (XMP_IS_PROP_SIMPLE (opt)) {
if (strcmp (path, "") != 0) {
if (XMP_HAS_PROP_QUALIFIERS (opt)) {
/* ignore language qualifier, just get the first */
metadataparse_xmp_iter_simple_qual (taglist, mode, path, value,
schema_map);
} else {
metadataparse_xmp_iter_simple (taglist, mode, path, value,
schema_map);
}
}
} else if (XMP_IS_PROP_ARRAY (opt)) {
/* FIXME: array with merge mode */
GstTagMergeMode new_mode = mode;
#if 0
//const gchar *tag = ;
if (mode == GST_TAG_MERGE_REPLACE) {
//gst_tag_list_remove_tag(taglist, );
}
#endif
if (XMP_IS_ARRAY_ALTTEXT (opt)) {
metadataparse_xmp_iter_array (taglist, new_mode, xmp, schema, path,
schema_map);
xmp_iterator_skip (xmp_iter, XMP_ITER_SKIPSUBTREE);
} else {
metadataparse_xmp_iter_array (taglist, new_mode, xmp, schema, path,
schema_map);
xmp_iterator_skip (xmp_iter, XMP_ITER_SKIPSUBTREE);
}
}
}
done:
if (xmp_iter)
xmp_iterator_free (xmp_iter);
if (xstr_prop)
xmp_string_free (xstr_prop);
if (xstr_path)
xmp_string_free (xstr_path);
if (xstr_schema)
xmp_string_free (xstr_schema);
}
/*
* metadataparse_xmp_iter_simple_qual:
* @taglist: tag list in which extracted tags will be added
* @mode: tag list merge mode
* @path: schema path
* @value: value of the (@path) tag
* @schema_map: structure containing @schema description and map with GST tags
*
* This function gets a XMP tag (@path) with quilifiers and try to add it
* to @taglist by calling #metadataparse_xmp_iter_add_to_tag_list
* @see_also: #metadataparse_xmp_iter_array
* #metadataparse_xmp_iter_simple #metadataparse_xmp_iter_add_to_tag_list
*
* Returns: nothing
*/
void
metadataparse_xmp_iter_simple_qual (GstTagList * taglist, GstTagMergeMode mode,
const char *path, const char *value, const SchemaMap * schema_map)
{
GString *string = g_string_new (path);
#ifndef GST_DISABLE_GST_DEBUG
gchar *ch;
/* remove the language qualifier */
ch = string->str + string->len - 3;
while (ch != string->str + schema_map->prefix_len) {
if (*ch == '[') {
*ch = '\0';
}
--ch;
}
GST_LOG (" %s = %s", string->str, value);
#endif /* #ifndef GST_DISABLE_GST_DEBUG */
metadataparse_xmp_iter_add_to_tag_list (taglist, mode, path, value,
schema_map, XMP_PROP_HAS_QUALIFIERS);
g_string_free (string, TRUE);
}
/*
* metadataparse_xmp_iter_simple:
* @taglist: tag list in which extracted tags will be added
* @mode: tag list merge mode
* @path: schema path
* @value: value of the (@path) tag
* @schema_map: structure containing @schema description and map with GST tags
*
* This function gets a simple XMP tag (@path) and try to add it to @taglist by
* calling # metadataparse_xmp_iter_add_to_tag_list
* @see_also: #metadataparse_xmp_iter_array
* #metadataparse_xmp_iter_simple_qual #metadataparse_xmp_iter_add_to_tag_list
*
* Returns: nothing
*/
void
metadataparse_xmp_iter_simple (GstTagList * taglist, GstTagMergeMode mode,
const char *path, const char *value, const SchemaMap * schema_map)
{
GST_LOG (" %s = %s", path, value);
metadataparse_xmp_iter_add_to_tag_list (taglist, mode, path, value,
schema_map, 0);
}
/*
* metadataparse_xmp_iter_add_to_tag_list:
* @taglist: tag list in which extracted tags will be added
* @mode: tag list merge mode
* @path: schema path
* @value: value of the (@path) tag
* @schema_map: structure containing @schema description and map with GST tags
* @opt: indicates if the string (@path) has extras caracters like '[' and ']'
*
* This function gets a XMP tag (@path) and see if it is mapped to a GST tag by
* calling #metadataparse_xmp_get_tagsmap_from_path, if so, add it to @taglist
* by using a specified merge @mode
* @see_also: #metadataparse_xmp_iter_simple_qual
* #metadataparse_xmp_iter_simple #metadataparse_xmp_get_tagsmap_from_path
*
* Returns: nothing
*/
static void
metadataparse_xmp_iter_add_to_tag_list (GstTagList * taglist,
GstTagMergeMode mode, const char *path, const char *value,
const SchemaMap * schema_map, const uint32_t opt)
{
GType type;
const SchemaTagMap *smaptag =
metadataparse_xmp_get_tagsmap_from_path (schema_map, path, opt);
if (NULL == smaptag)
goto done;
if (NULL == smaptag->gst_tag)
goto done;
type = gst_tag_get_type (smaptag->gst_tag);
switch (type) {
case G_TYPE_STRING:
gst_tag_list_add (taglist, mode, smaptag->gst_tag, value, NULL);
break;
default:
break;
}
done:
return;
}
/*
* metadatamux_xmp_for_each_tag_in_list:
* @list: GStreamer tag list from which @tag belongs to
* @tag: GStreamer tag to be added to the XMP chunk
* @user_data: pointer to #XmpPtr in which the tag will be added
*
* This function designed to be called for each tag in GST tag list. This
* function adds get the tag value from tag @list and then add it to the XMP
* chunk by using #XmpPtr and related functions from lib exempi
* @see_also: #metadatamux_xmp_create_chunk_from_tag_list
*
* Returns: nothing
*/
static void
metadatamux_xmp_for_each_tag_in_list (const GstTagList * list,
const gchar * tag, gpointer user_data)
{
XmpPtr xmp = (XmpPtr) user_data;
int i;
GST_DEBUG ("trying to map tag '%s' to xmp", tag);
for (i = 0; schemas_map[i]; i++) {
/* FIXME: should try to get all of values (index) for the tag */
const SchemaMap *smap = schemas_map[i];
const SchemaTagMap *stagmap =
metadatamux_xmp_get_tagsmap_from_gsttag (smap, tag);
if (stagmap) {
gchar *value = NULL;
GType type = gst_tag_get_type (tag);
switch (type) {
case G_TYPE_STRING:
gst_tag_list_get_string (list, tag, &value);
break;
default:
break;
}
GST_DEBUG ("found mapping for tag '%s' in schema %s", tag,
schemas_map[i]->prefix);
if (value) {
uint32_t options = 0;
#ifdef XMP_1_99_5
if (xmp_get_property (xmp, smap->schema, stagmap->xmp_tag,
NULL, &options)) {
#else
if (xmp_get_property_and_bits (xmp, smap->schema, stagmap->xmp_tag,
NULL, &options)) {
#endif
if (XMP_IS_PROP_SIMPLE (options)) {
#ifdef XMP_1_99_5
xmp_set_property (xmp, smap->schema, stagmap->xmp_tag, value, 0);
#else
xmp_set_property (xmp, smap->schema, stagmap->xmp_tag, value);
#endif
} else {
xmp_set_array_item (xmp, smap->schema, stagmap->xmp_tag, 1,
value, 0);
}
} else {
#ifdef XMP_1_99_5
xmp_set_property (xmp, smap->schema, stagmap->xmp_tag, value, 0);
#else
xmp_set_property (xmp, smap->schema, stagmap->xmp_tag, value);
#endif
}
g_free (value);
}
} else {
GST_DEBUG ("no xmp mapping for tag '%s' in schema %s found", tag,
schemas_map[i]->prefix);
}
}
}
#endif /* else (ifndef HAVE_XMP) */

View file

@ -1,75 +0,0 @@
/*
* 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_XMP_H__
#define __GST_METADATA_XMP_H__
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include "metadatatags.h"
G_BEGIN_DECLS
/*
* defines
*/
#define XMP_HEADER "http://ns.adobe.com/xap/1.0/"
/*
* external function prototypes
*/
extern gboolean metadata_xmp_init (void);
extern void metadata_xmp_dispose (void);
extern void
metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
GstAdapter * adapter, MetadataTagMapping mapping);
extern void
metadatamux_xmp_create_chunk_from_tag_list (guint8 ** buf, guint32 *size,
const GstTagList * taglist);
G_END_DECLS
#endif /* __GST_METADATA_XMP_H__ */

View file

@ -51,12 +51,6 @@ else
check_jifmux =
endif
if USE_METADATA
check_metadata = pipelines/metadata
else
check_metadata =
endif
if USE_MPEG2ENC
check_mpeg2enc = elements/mpeg2enc
else

View file

@ -1,5 +1,4 @@
.dirstamp
metadata
mxf
mimic
tagschecking

View file

@ -1,260 +0,0 @@
/* GStreamer
* Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
*
* 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.
*/
#include <gst/check/gstcheck.h>
static GstTagList *received_tags = NULL;
static gboolean
bus_handler (GstBus * bus, GstMessage * message, gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;
switch (message->type) {
case GST_MESSAGE_EOS:
g_main_loop_quit (loop);
break;
case GST_MESSAGE_WARNING:
case GST_MESSAGE_ERROR:{
GError *gerror;
gchar *debug;
gst_message_parse_error (message, &gerror, &debug);
gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
g_error_free (gerror);
g_free (debug);
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_TAG:{
if (received_tags == NULL) {
gst_message_parse_tag (message, &received_tags);
} else {
GstTagList *tl = NULL, *ntl = NULL;
gst_message_parse_tag (message, &tl);
if (tl) {
ntl = gst_tag_list_merge (received_tags, tl, GST_TAG_MERGE_PREPEND);
if (ntl) {
GST_LOG ("taglists merged: %" GST_PTR_FORMAT, ntl);
gst_tag_list_free (received_tags);
received_tags = ntl;
}
gst_tag_list_free (tl);
}
}
break;
}
default:
break;
}
return TRUE;
}
static void
test_tags (const gchar * tag_str)
{
GstElement *pipeline;
GstBus *bus;
GMainLoop *loop;
GstTagList *sent_tags;
gint i, j, n_recv, n_sent;
const gchar *name_sent, *name_recv;
const GValue *value_sent, *value_recv;
gboolean found, ok;
gint comparison;
GstElement *videotestsrc, *jpegenc, *metadatamux, *metadatademux, *fakesink;
GstTagSetter *setter;
GST_DEBUG ("testing tags : %s", tag_str);
if (received_tags) {
gst_tag_list_free (received_tags);
received_tags = NULL;
}
pipeline = gst_pipeline_new ("pipeline");
fail_unless (pipeline != NULL);
videotestsrc = gst_element_factory_make ("videotestsrc", "src");
fail_unless (videotestsrc != NULL);
g_object_set (G_OBJECT (videotestsrc), "num-buffers", 1, NULL);
jpegenc = gst_element_factory_make ("jpegenc", "enc");
if (jpegenc == NULL) {
g_print ("Cannot test - jpegenc not available\n");
return;
}
metadatamux = gst_element_factory_make ("metadatamux", "mux");
g_object_set (G_OBJECT (metadatamux), "exif", TRUE, NULL);
fail_unless (metadatamux != NULL);
metadatademux = gst_element_factory_make ("metadatademux", "demux");
fail_unless (metadatademux != NULL);
fakesink = gst_element_factory_make ("fakesink", "sink");
fail_unless (fakesink != NULL);
gst_bin_add_many (GST_BIN (pipeline), videotestsrc, jpegenc, metadatamux,
metadatademux, fakesink, NULL);
ok = gst_element_link_many (videotestsrc, jpegenc, metadatamux, metadatademux,
fakesink, NULL);
fail_unless (ok == TRUE);
loop = g_main_loop_new (NULL, TRUE);
fail_unless (loop != NULL);
bus = gst_element_get_bus (pipeline);
fail_unless (bus != NULL);
gst_bus_add_watch (bus, bus_handler, loop);
gst_object_unref (bus);
gst_element_set_state (pipeline, GST_STATE_READY);
setter = GST_TAG_SETTER (metadatamux);
fail_unless (setter != NULL);
sent_tags = gst_structure_from_string (tag_str, NULL);
fail_unless (sent_tags != NULL);
gst_tag_setter_merge_tags (setter, sent_tags, GST_TAG_MERGE_REPLACE);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_main_loop_run (loop);
GST_DEBUG ("mainloop done : %p", received_tags);
/* verify tags */
fail_unless (received_tags != NULL);
n_recv = gst_structure_n_fields (received_tags);
n_sent = gst_structure_n_fields (sent_tags);
/* we also get e.g. an exif binary block */
fail_unless (n_recv >= n_sent);
/* FIXME: compare taglits values */
for (i = 0; i < n_sent; i++) {
name_sent = gst_structure_nth_field_name (sent_tags, i);
value_sent = gst_structure_get_value (sent_tags, name_sent);
found = FALSE;
for (j = 0; j < n_recv; j++) {
name_recv = gst_structure_nth_field_name (received_tags, j);
if (!strcmp (name_sent, name_recv)) {
value_recv = gst_structure_get_value (received_tags, name_recv);
comparison = gst_value_compare (value_sent, value_recv);
if (comparison != GST_VALUE_EQUAL) {
gchar *vs = g_strdup_value_contents (value_sent);
gchar *vr = g_strdup_value_contents (value_recv);
GST_DEBUG ("sent = %s:'%s', recv = %s:'%s'",
G_VALUE_TYPE_NAME (value_sent), vs,
G_VALUE_TYPE_NAME (value_recv), vr);
g_free (vs);
g_free (vr);
}
fail_unless (comparison == GST_VALUE_EQUAL,
"tag item %s has been received with different type or value",
name_sent);
found = TRUE;
break;
}
}
fail_unless (found, "tag item %s is lost", name_sent);
}
gst_tag_list_free (received_tags);
received_tags = NULL;
gst_tag_list_free (sent_tags);
gst_element_set_state (pipeline, GST_STATE_NULL);
g_main_loop_unref (loop);
g_object_unref (pipeline);
}
GST_START_TEST (test_common_tags)
{
/* The title tag will only work if the XMP backend is enabled.
* And since we don't have any programmatic feedback on whether
* a tag is properly handled or not... we need to do this kind
* of hack. */
#ifdef HAVE_XMP
test_tags ("taglist,title=\"test image\"");
#endif
}
GST_END_TEST;
GST_START_TEST (test_gps_tags)
{
test_tags
("taglist,geo-location-latitude=66.1,geo-location-longitude=22.5,geo-location-elevation=10.3");
test_tags
("taglist,geo-location-latitude=66.1,geo-location-longitude=22.5,geo-location-elevation=-10.3");
test_tags
("taglist,geo-location-latitude=66.1,geo-location-longitude=-22.5,geo-location-elevation=10.3");
test_tags
("taglist,geo-location-latitude=66.1,geo-location-longitude=-22.5,geo-location-elevation=-10.3");
test_tags
("taglist,geo-location-latitude=-66.1,geo-location-longitude=22.5,geo-location-elevation=10.3");
test_tags
("taglist,geo-location-latitude=-66.1,geo-location-longitude=22.5,geo-location-elevation=-10.3");
test_tags
("taglist,geo-location-latitude=-66.1,geo-location-longitude=-22.5,geo-location-elevation=10.3");
test_tags
("taglist,geo-location-latitude=-66.1,geo-location-longitude=-22.5,geo-location-elevation=-10.3");
}
GST_END_TEST;
static Suite *
metadata_suite (void)
{
Suite *s = suite_create ("MetaData");
TCase *tc_chain = tcase_create ("general");
/* time out after 60s, not the default 3 */
tcase_set_timeout (tc_chain, 60);
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_common_tags);
tcase_add_test (tc_chain, test_gps_tags);
return s;
}
int
main (int argc, char **argv)
{
int nf;
Suite *s = metadata_suite ();
SRunner *sr = srunner_create (s);
gst_check_init (&argc, &argv);
srunner_run_all (sr, CK_NORMAL);
nf = srunner_ntests_failed (sr);
srunner_free (sr);
return nf;
}

View file

@ -11,23 +11,19 @@ else
GST_SOUNDTOUCH_TESTS =
endif
if USE_METADATA
if HAVE_GTK
GST_METADATA_TESTS = metadata_editor
metadata_editor_SOURCES = metadata_editor.h metadata_editor.c
metadata_editor_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GTK_CFLAGS) $(GMODULE_EXPORT_CFLAGS)
metadata_editor_LDADD = \
$(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-0.10 $(GST_LIBS) $(GTK_LIBS) $(GMODULE_EXPORT_LIBS)
else
# needs porting
#if HAVE_GTK
#
#GST_METADATA_TESTS = metadata_editor
#
#metadata_editor_SOURCES = metadata_editor.h metadata_editor.c
#metadata_editor_CFLAGS = \
# $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GTK_CFLAGS) $(GMODULE_EXPORT_CFLAGS)
#metadata_editor_LDADD = \
# $(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-0.10 $(GST_LIBS) $(GTK_LIBS) $(GMODULE_EXPORT_LIBS)
#else
GST_METADATA_TESTS =
endif
else
GST_METADATA_TESTS =
endif
#endif
equalizer_test_SOURCES = equalizer-test.c
equalizer_test_CFLAGS = $(GST_CFLAGS)