mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-13 19:44:10 +00:00
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:
parent
5b6550dbd5
commit
bc1c9ac18e
44 changed files with 13 additions and 13187 deletions
40
configure.ac
40
configure.ac
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 <edgard.lima@indt.org.br></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 <edgard.lima@indt.org.br></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>
|
|
@ -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 \
|
||||
|
|
7
ext/metadata/.gitignore
vendored
7
ext/metadata/.gitignore
vendored
|
@ -1,7 +0,0 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.deps
|
||||
.libs
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
@ -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__ */
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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__ */
|
|
@ -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) */
|
|
@ -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__ */
|
|
@ -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 */
|
|
@ -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__ */
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
|
@ -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__ */
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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__ */
|
|
@ -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) */
|
|
@ -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__ */
|
|
@ -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
|
||||
|
|
1
tests/check/pipelines/.gitignore
vendored
1
tests/check/pipelines/.gitignore
vendored
|
@ -1,5 +1,4 @@
|
|||
.dirstamp
|
||||
metadata
|
||||
mxf
|
||||
mimic
|
||||
tagschecking
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue