mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 17:20:36 +00:00
Add lot of documentation.
Original commit message from CVS: Add lot of documentation.
This commit is contained in:
parent
ef421fee72
commit
9e31b57dc3
25 changed files with 2116 additions and 679 deletions
30
ChangeLog
30
ChangeLog
|
@ -1,3 +1,33 @@
|
||||||
|
2008-01-25 Edgard Lima <edgard.lima@indt.org.br>
|
||||||
|
|
||||||
|
* ext/metadata/TODO:
|
||||||
|
* ext/metadata/gstbasemetadata.c:
|
||||||
|
* ext/metadata/metadata.c:
|
||||||
|
* ext/metadata/metadata.h:
|
||||||
|
* ext/metadata/metadataexif.c:
|
||||||
|
* ext/metadata/metadataexif.h:
|
||||||
|
* ext/metadata/metadataiptc.c:
|
||||||
|
* ext/metadata/metadataiptc.h:
|
||||||
|
* ext/metadata/metadataparsejpeg.c:
|
||||||
|
* ext/metadata/metadataparsejpeg.h:
|
||||||
|
* ext/metadata/metadataparsepng.c:
|
||||||
|
* ext/metadata/metadataparsepng.h:
|
||||||
|
* ext/metadata/metadataparseutil.c:
|
||||||
|
* ext/metadata/metadataparseutil.h:
|
||||||
|
* ext/metadata/metadatatags.c:
|
||||||
|
* ext/metadata/metadatatags.h:
|
||||||
|
* ext/metadata/metadatatypes.c:
|
||||||
|
* ext/metadata/metadatatypes.h:
|
||||||
|
* ext/metadata/metadataxmp.c:
|
||||||
|
* ext/metadata/metadataxmp.h:
|
||||||
|
* ext/metadata/test/Makefile:
|
||||||
|
* ext/metadata/test/MetadataEditorMain.glade:
|
||||||
|
* ext/metadata/test/metadata_editor.c:
|
||||||
|
* tests/icles/Makefile.am:
|
||||||
|
* tests/icles/metadata_editor.c:
|
||||||
|
* tests/icles/metadata_editor.glade:
|
||||||
|
Add lot of documentation.
|
||||||
|
|
||||||
2008-01-25 Zaheer Abbas Merali <zaheerabbas at merali dot org>
|
2008-01-25 Zaheer Abbas Merali <zaheerabbas at merali dot org>
|
||||||
|
|
||||||
* sys/dvb/gstdvbsrc.c:
|
* sys/dvb/gstdvbsrc.c:
|
||||||
|
|
|
@ -26,3 +26,12 @@ OPEN ISSUES:
|
||||||
|
|
||||||
KNOWN BUGS
|
KNOWN BUGS
|
||||||
|
|
||||||
|
1- gst-launch-0.10 filesrc location=BlueSquare.png ! metadatademux ! metadatamux ! pngdec ! ffmpegcolorspace ! freeze ! xvimagesink
|
||||||
|
|
||||||
|
the following pipelines work fine:
|
||||||
|
|
||||||
|
gst-launch-0.10 filesrc location=BlueSquare.png ! metadatamux ! metadatademux ! pngdec ! ffmpegcolorspace ! freeze ! xvimagesink
|
||||||
|
gst-launch-0.10 filesrc location=BlueSquare.png ! metadatademux ! metadatamux ! queue ! pngdec ! ffmpegcolorspace ! freeze ! xvimagesink
|
||||||
|
gst-launch-0.10 filesrc location=BlueSquare.png ! ! metadatamux ! pngdec ! ffmpegcolorspace ! freeze ! xvimagesink
|
||||||
|
gst-launch-0.10 filesrc location=BlueSquare.png ! metadatademux ! ! pngdec ! ffmpegcolorspace ! freeze ! xvimagesink
|
||||||
|
|
||||||
|
|
|
@ -1291,7 +1291,7 @@ gst_base_metadata_init (GstBaseMetadata * filter, GstBaseMetadataClass * gclass)
|
||||||
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
|
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
|
||||||
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
|
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
|
||||||
|
|
||||||
metadataparse_xmp_init ();
|
metadata_xmp_init ();
|
||||||
/* init members */
|
/* init members */
|
||||||
|
|
||||||
gst_base_metadata_init_members (filter);
|
gst_base_metadata_init_members (filter);
|
||||||
|
@ -1307,7 +1307,7 @@ gst_base_metadata_dispose (GObject * object)
|
||||||
|
|
||||||
gst_base_metadata_dispose_members (filter);
|
gst_base_metadata_dispose_members (filter);
|
||||||
|
|
||||||
metadataparse_xmp_dispose ();
|
metadata_xmp_dispose ();
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,32 +41,67 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* 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 <string.h>
|
||||||
|
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*static declarations
|
* static helper functions declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static MetadataParsingReturn
|
static MetadataParsingReturn
|
||||||
metadata_parse_none (MetaData * meta_data, const guint8 * buf,
|
metadata_parse_none (MetaData * meta_data, const guint8 * data,
|
||||||
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
|
guint32 * data_size, guint8 ** next_start, guint32 * next_size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* extern functions implementations
|
* extern functions implementations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Init metadata handle vars.
|
* metadata_init:
|
||||||
* This function must becalled before any other function from this module.
|
* @meta_data: [in] metadata handler to be inited
|
||||||
* This functoin must not be called twice without call 'metadata_dispose'
|
* @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.
|
* beteween them.
|
||||||
* meta_data [in]: metadata handler to be inited
|
* @see_also: #metadata_dispose #metadata_parse
|
||||||
* parse [in]: pass TRUE for demuxing and FALSE for muxing
|
*
|
||||||
* options [in]: which types of metadata will be processed (EXIF, IPTC and/or XMP).
|
* Returns: nothing
|
||||||
* Look at 'MetaOptions' to see the available options.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
metadata_init (MetaData ** meta_data, const MetaOptions options)
|
metadata_init (MetaData ** meta_data, const MetaOptions options)
|
||||||
{
|
{
|
||||||
|
@ -89,7 +124,8 @@ metadata_init (MetaData ** meta_data, const MetaOptions options)
|
||||||
if ((*meta_data)->options & META_OPT_DEMUX) {
|
if ((*meta_data)->options & META_OPT_DEMUX) {
|
||||||
/* when parsing we will probably strip only 3 chunk (exif, iptc and xmp)
|
/* 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.
|
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 incriases dinamically */
|
But this is just for convinience, 'cause the chunk_array increases
|
||||||
|
dinamically */
|
||||||
metadata_chunk_array_init (&(*meta_data)->strip_chunks, 4);
|
metadata_chunk_array_init (&(*meta_data)->strip_chunks, 4);
|
||||||
/* at most 1 chunk will be injected (JPEG JFIF) */
|
/* at most 1 chunk will be injected (JPEG JFIF) */
|
||||||
metadata_chunk_array_init (&(*meta_data)->inject_chunks, 1);
|
metadata_chunk_array_init (&(*meta_data)->inject_chunks, 1);
|
||||||
|
@ -103,9 +139,15 @@ metadata_init (MetaData ** meta_data, const MetaOptions options)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dispose medadata handler data.
|
* metadata_dispose:
|
||||||
* Call this function to free any resource allocated by 'metadata_init'
|
* @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
|
void
|
||||||
metadata_dispose (MetaData ** meta_data)
|
metadata_dispose (MetaData ** meta_data)
|
||||||
{
|
{
|
||||||
|
@ -151,27 +193,41 @@ metadata_dispose (MetaData ** meta_data)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* meta_data [in]: metata handle
|
* metadata_parse:
|
||||||
* buf [in]: data to be parsed
|
* @meta_data: [in] metadata handle
|
||||||
* bufsize [in]: size of data in bytes
|
* @buf: [in] data to be parsed
|
||||||
* next_offset [out]: number of bytes to jump from the begining of 'buf' in the next call.
|
* @buf_size: [in] size of @buf in bytes
|
||||||
* i.e, 0 (zero) mean that in the next call to function "buf" must have the same
|
* @next_offset: [out] number of bytes to jump from the begining of @buf in
|
||||||
* data (probably resized, see 'size')
|
* the next call. i.e, 0 (zero) mean that in the next call this function @buf
|
||||||
* size [out]: number of minimal bytes in buf for the next call to this function
|
* must have the same data (probably resized, see @next_size)
|
||||||
* return:
|
* @next_size: [out] number of minimal bytes in @buf for the next call to this
|
||||||
* META_PARSING_ERROR
|
* function
|
||||||
* META_PARSING_DONE
|
*
|
||||||
* META_PARSING_NEED_MORE_DATA (look 'next_offset' and 'size')
|
* This function is used to parse the stream step-by-step incrementaly, which
|
||||||
* when this function returns 0 you have strip and inject chunks ready to use
|
* means, discover the stream type and find the metadata chunks
|
||||||
* If you change the contents of strip and inject chunks, you have to call
|
* (#META_OPT_DEMUX), or point out where metadata chunks should be written
|
||||||
* 'metadata_lazy_update' (this is the case when muxing)
|
* (#META_OPT_MUX). It is important to notice that there could be both strip
|
||||||
* see MetaData->strip_chunks and MetaData->inject_chunks
|
* 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
|
MetadataParsingReturn
|
||||||
metadata_parse (MetaData * meta_data, const guint8 * buf,
|
metadata_parse (MetaData * meta_data, const guint8 * buf,
|
||||||
guint32 bufsize, guint32 * next_offset, guint32 * next_size)
|
guint32 buf_size, guint32 * next_offset, guint32 * next_size)
|
||||||
{
|
{
|
||||||
|
|
||||||
int ret = META_PARSING_DONE;
|
int ret = META_PARSING_DONE;
|
||||||
|
@ -180,7 +236,7 @@ metadata_parse (MetaData * meta_data, const guint8 * buf,
|
||||||
|
|
||||||
if (meta_data->state == STATE_NULL) {
|
if (meta_data->state == STATE_NULL) {
|
||||||
ret =
|
ret =
|
||||||
metadata_parse_none (meta_data, buf, &bufsize, &next_start, next_size);
|
metadata_parse_none (meta_data, buf, &buf_size, &next_start, next_size);
|
||||||
if (ret == META_PARSING_DONE)
|
if (ret == META_PARSING_DONE)
|
||||||
meta_data->state = STATE_READING;
|
meta_data->state = STATE_READING;
|
||||||
else
|
else
|
||||||
|
@ -192,24 +248,24 @@ metadata_parse (MetaData * meta_data, const guint8 * buf,
|
||||||
if (G_LIKELY (meta_data->options & META_OPT_DEMUX))
|
if (G_LIKELY (meta_data->options & META_OPT_DEMUX))
|
||||||
ret =
|
ret =
|
||||||
metadataparse_jpeg_parse (&meta_data->format_data.jpeg_parse,
|
metadataparse_jpeg_parse (&meta_data->format_data.jpeg_parse,
|
||||||
(guint8 *) buf, &bufsize, meta_data->offset_orig, &next_start,
|
(guint8 *) buf, &buf_size, meta_data->offset_orig, &next_start,
|
||||||
next_size);
|
next_size);
|
||||||
else
|
else
|
||||||
ret =
|
ret =
|
||||||
metadatamux_jpeg_parse (&meta_data->format_data.jpeg_mux,
|
metadatamux_jpeg_parse (&meta_data->format_data.jpeg_mux,
|
||||||
(guint8 *) buf, &bufsize, meta_data->offset_orig, &next_start,
|
(guint8 *) buf, &buf_size, meta_data->offset_orig, &next_start,
|
||||||
next_size);
|
next_size);
|
||||||
break;
|
break;
|
||||||
case IMG_PNG:
|
case IMG_PNG:
|
||||||
if (G_LIKELY (meta_data->options & META_OPT_DEMUX))
|
if (G_LIKELY (meta_data->options & META_OPT_DEMUX))
|
||||||
ret =
|
ret =
|
||||||
metadataparse_png_parse (&meta_data->format_data.png_parse,
|
metadataparse_png_parse (&meta_data->format_data.png_parse,
|
||||||
(guint8 *) buf, &bufsize, meta_data->offset_orig, &next_start,
|
(guint8 *) buf, &buf_size, meta_data->offset_orig, &next_start,
|
||||||
next_size);
|
next_size);
|
||||||
else
|
else
|
||||||
ret =
|
ret =
|
||||||
metadatamux_png_parse (&meta_data->format_data.png_mux,
|
metadatamux_png_parse (&meta_data->format_data.png_mux,
|
||||||
(guint8 *) buf, &bufsize, meta_data->offset_orig, &next_start,
|
(guint8 *) buf, &buf_size, meta_data->offset_orig, &next_start,
|
||||||
next_size);
|
next_size);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -232,13 +288,24 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function must be called after 'metadata_parse' and after the element has modified the 'segments'.
|
* 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 importante in case o muxing 'cause:
|
* This function is really importante in case o muxing 'cause:
|
||||||
* 1- 'cause gives the oportunity to muxers to wrapper new segments with apropriate bytes
|
* 1- 'cause gives the oportunity to muxers to wrapper new segments with
|
||||||
* ex: in case of JPEG it can wrap the EXIF chunk (created using tags) with chunk id and chunk size
|
* apropriate bytes
|
||||||
* 2- 'cause gives the oportunity to muxer to decide if some chunks should still be striped/injected
|
* ex: in case of JPEG it can wrap the EXIF chunk (created using tags) with
|
||||||
* ex: if there is no EXIF chunk to be inserted, the muxer decides to not strip JFIF anymore
|
* chunk id and chunk size
|
||||||
* see MetaData->strip_chunks and MetaData->inject_chunks
|
* 2- 'cause gives the oportunity to muxer 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
|
void
|
||||||
|
@ -266,15 +333,38 @@ metadata_lazy_update (MetaData * meta_data)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* static functions implementation
|
* static helper functions implementation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find out the type of the stream
|
* 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
|
static MetadataParsingReturn
|
||||||
metadata_parse_none (MetaData * meta_data, const guint8 * buf,
|
metadata_parse_none (MetaData * meta_data, const guint8 * buf,
|
||||||
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
|
guint32 * buf_size, guint8 ** next_start, guint32 * next_size)
|
||||||
{
|
{
|
||||||
|
|
||||||
int ret = META_PARSING_ERROR;
|
int ret = META_PARSING_ERROR;
|
||||||
|
@ -292,7 +382,7 @@ metadata_parse_none (MetaData * meta_data, const guint8 * buf,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* we need at least 3 bytes to see if it is JPEG */
|
/* we need at least 3 bytes to see if it is JPEG */
|
||||||
if (*bufsize < 3) {
|
if (*buf_size < 3) {
|
||||||
*next_size = 3;
|
*next_size = 3;
|
||||||
ret = META_PARSING_NEED_MORE_DATA;
|
ret = META_PARSING_NEED_MORE_DATA;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -319,7 +409,7 @@ metadata_parse_none (MetaData * meta_data, const guint8 * buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we need at least 8 bytes to see if it is PNG */
|
/* we need at least 8 bytes to see if it is PNG */
|
||||||
if (*bufsize < 8) {
|
if (*buf_size < 8) {
|
||||||
*next_size = 8;
|
*next_size = 8;
|
||||||
ret = META_PARSING_NEED_MORE_DATA;
|
ret = META_PARSING_NEED_MORE_DATA;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
@ -44,6 +44,10 @@
|
||||||
#ifndef __METADATA_H__
|
#ifndef __METADATA_H__
|
||||||
#define __METADATA_H__
|
#define __METADATA_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* includes
|
||||||
|
*/
|
||||||
|
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
#include "metadatatypes.h"
|
#include "metadatatypes.h"
|
||||||
|
|
||||||
|
@ -54,16 +58,19 @@
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/*
|
||||||
|
* enum and types
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
typedef enum _tag_MetaOptions
|
typedef enum _tag_MetaOptions
|
||||||
{
|
{
|
||||||
META_OPT_EXIF = (1 << 0),
|
META_OPT_EXIF = (1 << 0),
|
||||||
META_OPT_IPTC = (1 << 1),
|
META_OPT_IPTC = (1 << 1),
|
||||||
META_OPT_XMP = (1 << 2),
|
META_OPT_XMP = (1 << 2),
|
||||||
META_OPT_PARSE_ONLY = (1 << 3), /* only makes sense with META_OPT_DEMUX */
|
META_OPT_PARSE_ONLY = (1 << 3), /* only makes sense with META_OPT_DEMUX */
|
||||||
META_OPT_DEMUX = (1 << 4),
|
META_OPT_DEMUX = (1 << 4), /* to operates in demuxing mode */
|
||||||
META_OPT_MUX = (1 << 5),
|
META_OPT_MUX = (1 << 5), /* to operates in muxing mode */
|
||||||
META_OPT_ALL = (1 << 6) - 1
|
META_OPT_ALL = (1 << 6) - 1
|
||||||
} MetaOptions;
|
} MetaOptions;
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
@ -104,18 +111,26 @@ typedef struct _tag_MetaData
|
||||||
|
|
||||||
} MetaData;
|
} MetaData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* defines and macros
|
||||||
|
*/
|
||||||
|
|
||||||
#define META_DATA_IMG_TYPE(p) (p)->img_type
|
#define META_DATA_IMG_TYPE(p) (p)->img_type
|
||||||
|
|
||||||
#define META_DATA_STRIP_CHUNKS(p) (p)->strip_chunks
|
#define META_DATA_STRIP_CHUNKS(p) (p)->strip_chunks
|
||||||
#define META_DATA_INJECT_CHUNKS(p) (p)->inject_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_init (MetaData ** meta_data, const MetaOptions options);
|
||||||
|
|
||||||
extern void metadata_dispose (MetaData ** meta_data);
|
extern void metadata_dispose (MetaData ** meta_data);
|
||||||
|
|
||||||
extern MetadataParsingReturn
|
extern MetadataParsingReturn
|
||||||
metadata_parse (MetaData * meta_data, const guint8 * buf,
|
metadata_parse (MetaData * meta_data, const guint8 * buf,
|
||||||
guint32 bufsize, guint32 * next_offset, guint32 * next_size);
|
guint32 buf_size, guint32 * next_offset, guint32 * next_size);
|
||||||
|
|
||||||
|
|
||||||
extern void metadata_lazy_update (MetaData * meta_data);
|
extern void metadata_lazy_update (MetaData * meta_data);
|
||||||
|
|
|
@ -41,23 +41,52 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SECTION: metadataexif
|
||||||
|
* @short_description: This module provides functions to extract tags from
|
||||||
|
* EXIF metadata chunks and create EXIF chunks from metadata tags.
|
||||||
|
* @see_also: #metadatatags.[c/h]
|
||||||
|
*
|
||||||
|
* If libexif 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
|
||||||
|
*/
|
||||||
|
|
||||||
#include "metadataexif.h"
|
#include "metadataexif.h"
|
||||||
#include "metadataparseutil.h"
|
#include "metadataparseutil.h"
|
||||||
#include "metadatatags.h"
|
#include "metadatatags.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* defines
|
||||||
|
*/
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (gst_metadata_exif_debug);
|
GST_DEBUG_CATEGORY (gst_metadata_exif_debug);
|
||||||
#define GST_CAT_DEFAULT gst_metadata_exif_debug
|
#define GST_CAT_DEFAULT gst_metadata_exif_debug
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation when libexif isn't available at compilation time
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef HAVE_EXIF
|
#ifndef HAVE_EXIF
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extern functions implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
metadataparse_exif_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_exif_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
GstAdapter * adapter, MetadataTagMapping mapping)
|
GstAdapter * adapter, MetadataTagMapping mapping)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (mapping & METADATA_TAG_MAP_WHOLECHUNK) {
|
if (mapping & METADATA_TAG_MAP_WHOLECHUNK) {
|
||||||
GST_LOG
|
GST_LOG ("EXIF not defined, sending just one tag as whole chunk");
|
||||||
("EXIF not defined, here I should send just one tag as whole chunk");
|
|
||||||
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_EXIF,
|
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_EXIF,
|
||||||
adapter);
|
adapter);
|
||||||
}
|
}
|
||||||
|
@ -73,11 +102,23 @@ metadatamux_exif_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
|
||||||
|
|
||||||
#else /* ifndef HAVE_EXIF */
|
#else /* ifndef HAVE_EXIF */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation when libexif is available at compilation time
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* includes
|
||||||
|
*/
|
||||||
|
|
||||||
#include <libexif/exif-data.h>
|
#include <libexif/exif-data.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enum and types
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct _tag_MEUserData
|
typedef struct _tag_MEUserData
|
||||||
{
|
{
|
||||||
GstTagList *taglist;
|
GstTagList *taglist;
|
||||||
|
@ -92,10 +133,9 @@ typedef struct _tag_MapIntStr
|
||||||
const gchar *str;
|
const gchar *str;
|
||||||
} MapIntStr;
|
} MapIntStr;
|
||||||
|
|
||||||
static void
|
/*
|
||||||
exif_data_foreach_content_func (ExifContent * content, void *callback_data);
|
* defines and static global vars
|
||||||
|
*/
|
||||||
static void exif_content_foreach_entry_func (ExifEntry * entry, void *);
|
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
static MapIntStr mappedTags[] = {
|
static MapIntStr mappedTags[] = {
|
||||||
|
@ -131,41 +171,47 @@ static MapIntStr mappedTags[] = {
|
||||||
};
|
};
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
static const gchar *
|
/*
|
||||||
metadataparse_exif_get_tag_from_exif (ExifTag exif, GType * type)
|
* static helper functions declaration
|
||||||
{
|
*/
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while (mappedTags[i].exif) {
|
static const gchar *metadataparse_exif_get_tag_from_exif (ExifTag exif,
|
||||||
if (exif == mappedTags[i].exif) {
|
GType * type);
|
||||||
*type = gst_tag_get_type (mappedTags[i].str);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mappedTags[i].str;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static ExifTag
|
static ExifTag
|
||||||
metadataparse_exif_get_exif_from_tag (const gchar * tag, GType * type,
|
metadatamux_exif_get_exif_from_tag (const gchar * tag, GType * type,
|
||||||
ExifIfd * ifd)
|
ExifIfd * ifd);
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while (mappedTags[i].exif) {
|
static void
|
||||||
if (0 == strcmp (mappedTags[i].str, tag)) {
|
metadataparse_exif_data_foreach_content_func (ExifContent * content,
|
||||||
*type = gst_tag_get_type (tag);
|
void *callback_data);
|
||||||
*ifd = mappedTags[i].ifd;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mappedTags[i].exif;
|
static void
|
||||||
|
metadataparse_exif_content_foreach_entry_func (ExifEntry * entry,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
}
|
static void
|
||||||
|
metadatamux_exif_for_each_tag_in_list (const GstTagList * list,
|
||||||
|
const gchar * tag, gpointer user_data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extern functions implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metadataparse_exif_tag_list_add:
|
||||||
|
* @taglist: tag list in which extracted tags will be added
|
||||||
|
* @mode: tag list merge mode
|
||||||
|
* @adapter: contains the EXIF metadata chunk
|
||||||
|
* @mapping: if is to extract individual tags and/or the whole chunk.
|
||||||
|
*
|
||||||
|
* This function gets a EXIF chunk (@adapter) and extract tags from it
|
||||||
|
* and the add to @taglist.
|
||||||
|
* Note: The EXIF chunk (@adapetr) must NOT be wrapped by any bytes specific
|
||||||
|
* to any file format
|
||||||
|
*
|
||||||
|
* Returns: nothing
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
metadataparse_exif_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_exif_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
|
@ -195,8 +241,8 @@ metadataparse_exif_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
exif_data_foreach_content (exif, exif_data_foreach_content_func,
|
exif_data_foreach_content (exif,
|
||||||
(void *) &user_data);
|
metadataparse_exif_data_foreach_content_func, (void *) &user_data);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
|
@ -207,44 +253,178 @@ done:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metadatamux_exif_create_chunk_from_tag_list:
|
||||||
|
* @buf: buffer that will have the created EXIF chunk
|
||||||
|
* @size: size of the buffer that will be created
|
||||||
|
* @taglist: list of tags to be added to EXIF chunk
|
||||||
|
*
|
||||||
|
* Get tags from @taglist, create a EXIF chunk based on it and save to @buf.
|
||||||
|
* Note: The EXIF chunk is NOT wrapped by any bytes specific to any file format
|
||||||
|
*
|
||||||
|
* Returns: nothing
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
metadatamux_exif_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
|
||||||
|
const GstTagList * taglist)
|
||||||
|
{
|
||||||
|
ExifData *ed = NULL;
|
||||||
|
GstBuffer *exif_chunk = NULL;
|
||||||
|
const GValue *val = NULL;
|
||||||
|
|
||||||
|
if (!(buf && size))
|
||||||
|
goto done;
|
||||||
|
if (*buf) {
|
||||||
|
g_free (*buf);
|
||||||
|
*buf = NULL;
|
||||||
|
}
|
||||||
|
*size = 0;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ed) {
|
||||||
|
ed = exif_data_new ();
|
||||||
|
exif_data_set_data_type (ed, EXIF_DATA_TYPE_COMPRESSED);
|
||||||
|
exif_data_fix (ed);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_tag_list_foreach (taglist, metadatamux_exif_for_each_tag_in_list, ed);
|
||||||
|
|
||||||
|
exif_data_save_data (ed, buf, size);
|
||||||
|
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
if (ed)
|
||||||
|
exif_data_unref (ed);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* static helper functions implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metadataparse_exif_get_tag_from_exif:
|
||||||
|
* @exif: EXIF tag to look for
|
||||||
|
* @type: the type of the GStreamer tag mapped to @exif
|
||||||
|
*
|
||||||
|
* This returns the GStreamer tag mapped to an EXIF tag.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* <itemizedlist>
|
||||||
|
* <listitem><para>The GStreamer tag mapped to the @exif
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>%NULL if there is no mapped GST tag for @exif
|
||||||
|
* </para></listitem>
|
||||||
|
* </itemizedlist>
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const gchar *
|
||||||
|
metadataparse_exif_get_tag_from_exif (ExifTag exif, GType * type)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (mappedTags[i].exif) {
|
||||||
|
if (exif == mappedTags[i].exif) {
|
||||||
|
*type = gst_tag_get_type (mappedTags[i].str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mappedTags[i].str;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metadatamux_exif_get_exif_from_tag:
|
||||||
|
* @tag: GST tag to look for
|
||||||
|
* @type: the type of the GStreamer @tag
|
||||||
|
* @ifd: the place into EXIF chunk @exif belongs to.
|
||||||
|
*
|
||||||
|
* This returns thet EXIF tag mapped to an GStreamer @tag.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* <itemizedlist>
|
||||||
|
* <listitem><para>The EXIF tag mapped to the GST @tag
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>0 if there is no mapped EXIF tag for GST @tag
|
||||||
|
* </para></listitem>
|
||||||
|
* </itemizedlist>
|
||||||
|
*/
|
||||||
|
|
||||||
|
static ExifTag
|
||||||
|
metadatamux_exif_get_exif_from_tag (const gchar * tag, GType * type,
|
||||||
|
ExifIfd * ifd)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (mappedTags[i].exif) {
|
||||||
|
if (0 == strcmp (mappedTags[i].str, tag)) {
|
||||||
|
*type = gst_tag_get_type (tag);
|
||||||
|
*ifd = mappedTags[i].ifd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mappedTags[i].exif;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metadataparse_exif_data_foreach_content_func:
|
||||||
|
* @content: EXIF structure from libexif containg a IFD
|
||||||
|
* @user_data: pointer to #MEUserData
|
||||||
|
*
|
||||||
|
* This function designed to be called for each EXIF IFD in a EXIF chunk. This
|
||||||
|
* function gets calls another function for each tag into @content. Then all
|
||||||
|
* tags into a EXIF chunk can be extracted to a tag list in @user_data.
|
||||||
|
* @see_also: #metadataparse_exif_tag_list_add
|
||||||
|
* #metadataparse_exif_content_foreach_entry_func
|
||||||
|
*
|
||||||
|
* Returns: nothing
|
||||||
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
exif_data_foreach_content_func (ExifContent * content, void *user_data)
|
metadataparse_exif_data_foreach_content_func (ExifContent * content,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
ExifIfd ifd = exif_content_get_ifd (content);
|
ExifIfd ifd = exif_content_get_ifd (content);
|
||||||
|
|
||||||
GST_LOG ("\n Content %p: %s (ifd=%d)", content, exif_ifd_get_name (ifd),
|
GST_LOG ("\n Content %p: %s (ifd=%d)", content, exif_ifd_get_name (ifd),
|
||||||
ifd);
|
ifd);
|
||||||
exif_content_foreach_entry (content, exif_content_foreach_entry_func,
|
exif_content_foreach_entry (content,
|
||||||
user_data);
|
metadataparse_exif_content_foreach_entry_func, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
/*
|
||||||
static gboolean
|
* metadataparse_exif_content_foreach_entry_func:
|
||||||
exif_fast_mdc (glong n, glong d, gulong * m)
|
* @entry: EXIF structure from libexif having a EXIF tag
|
||||||
{
|
* @user_data: pointer to #MEUserData
|
||||||
gboolean ret = FALSE;
|
*
|
||||||
|
* This function designed to be called for each EXIF tag in a EXIF IFD. This
|
||||||
static const int a[] =
|
* function gets the EXIF tag from @entry and then add to the tag list
|
||||||
{ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 39, 41, 43, 47, 49, 53, 0 };
|
* in @user_data by using a merge mode also specified in @user_data
|
||||||
int i = 0;
|
* @see_also: #metadataparse_exif_data_foreach_content_func
|
||||||
|
*
|
||||||
*m = 1;
|
* Returns: nothing
|
||||||
|
*/
|
||||||
while (a[i] <= n && a[i] <= d) {
|
|
||||||
while ((n % a[i] == 0) && (d % a[i]) == 0) {
|
|
||||||
*m *= a[i];
|
|
||||||
ret = TRUE;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
exif_content_foreach_entry_func (ExifEntry * entry, void *user_data)
|
metadataparse_exif_content_foreach_entry_func (ExifEntry * entry,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
char buf[2048];
|
char buf[2048];
|
||||||
MEUserData *meudata = (MEUserData *) user_data;
|
MEUserData *meudata = (MEUserData *) user_data;
|
||||||
|
@ -390,76 +570,22 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* metadatamux_exif_for_each_tag_in_list:
|
||||||
|
* @list: GStreamer tag list from which @tag belongs to
|
||||||
|
* @tag: GStreamer tag to be added to the EXIF chunk
|
||||||
|
* @user_data: pointer to #ExifData 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 EXIF
|
||||||
|
* chunk by using #ExifData and related functions from libexif
|
||||||
|
* @see_also: #metadatamux_exif_create_chunk_from_tag_list
|
||||||
|
*
|
||||||
|
* Returns: nothing
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static ExifRational
|
|
||||||
float_to_rational (gfloat f)
|
|
||||||
{
|
|
||||||
ExifRational r;
|
|
||||||
int i = 6; /* precision */
|
|
||||||
|
|
||||||
r.denominator = 1;
|
|
||||||
|
|
||||||
while (i--) {
|
|
||||||
if (f == floorf (f)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
f *= 10.0f;
|
|
||||||
r.denominator *= 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
r.numerator = f;
|
|
||||||
|
|
||||||
if (!(r.numerator & 0x1 || r.denominator & 0x1)) {
|
|
||||||
/* divide both by 2 */
|
|
||||||
r.numerator >>= 1;
|
|
||||||
r.denominator >>= 1;
|
|
||||||
}
|
|
||||||
if (r.numerator % 5 == 0 && r.denominator % 5 == 0) {
|
|
||||||
r.numerator /= 5;
|
|
||||||
r.denominator /= 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static ExifSRational
|
|
||||||
float_to_srational (gfloat f)
|
|
||||||
{
|
|
||||||
ExifSRational sr;
|
|
||||||
int i = 6; /* precision */
|
|
||||||
|
|
||||||
sr.denominator = 1;
|
|
||||||
|
|
||||||
while (i--) {
|
|
||||||
if (f == floorf (f)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
f *= 10.0f;
|
|
||||||
sr.denominator *= 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
sr.numerator = f;
|
|
||||||
|
|
||||||
if (!(sr.numerator & 0x1 || sr.denominator & 0x1)) {
|
|
||||||
/* divide both by 2 */
|
|
||||||
sr.numerator >>= 1;
|
|
||||||
sr.denominator >>= 1;
|
|
||||||
}
|
|
||||||
if (sr.numerator % 5 == 0 && sr.denominator % 5 == 0) {
|
|
||||||
sr.numerator /= 5;
|
|
||||||
sr.denominator /= 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sr;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
metadataexif_for_each_tag_in_list (const GstTagList * list, const gchar * tag,
|
metadatamux_exif_for_each_tag_in_list (const GstTagList * list,
|
||||||
gpointer user_data)
|
const gchar * tag, gpointer user_data)
|
||||||
{
|
{
|
||||||
ExifData *ed = (ExifData *) user_data;
|
ExifData *ed = (ExifData *) user_data;
|
||||||
ExifTag exif_tag;
|
ExifTag exif_tag;
|
||||||
|
@ -468,7 +594,7 @@ metadataexif_for_each_tag_in_list (const GstTagList * list, const gchar * tag,
|
||||||
ExifIfd ifd;
|
ExifIfd ifd;
|
||||||
const ExifByteOrder byte_order = exif_data_get_byte_order (ed);
|
const ExifByteOrder byte_order = exif_data_get_byte_order (ed);
|
||||||
|
|
||||||
exif_tag = metadataparse_exif_get_exif_from_tag (tag, &type, &ifd);
|
exif_tag = metadatamux_exif_get_exif_from_tag (tag, &type, &ifd);
|
||||||
|
|
||||||
if (!exif_tag)
|
if (!exif_tag)
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -505,7 +631,9 @@ metadataexif_for_each_tag_in_list (const GstTagList * list, const gchar * tag,
|
||||||
entry->tag == EXIF_TAG_Y_RESOLUTION) {
|
entry->tag == EXIF_TAG_Y_RESOLUTION) {
|
||||||
ExifEntry *unit_entry = NULL;
|
ExifEntry *unit_entry = NULL;
|
||||||
|
|
||||||
if ((unit_entry = exif_data_get_entry (ed, EXIF_TAG_RESOLUTION_UNIT))) {
|
unit_entry = exif_data_get_entry (ed, EXIF_TAG_RESOLUTION_UNIT);
|
||||||
|
|
||||||
|
if (unit_entry) {
|
||||||
ExifShort vsh = exif_get_short (unit_entry->data, byte_order);
|
ExifShort vsh = exif_get_short (unit_entry->data, byte_order);
|
||||||
|
|
||||||
if (vsh != 2) /* inches */
|
if (vsh != 2) /* inches */
|
||||||
|
@ -568,48 +696,5 @@ done:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
metadatamux_exif_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
|
|
||||||
const GstTagList * taglist)
|
|
||||||
{
|
|
||||||
ExifData *ed = NULL;
|
|
||||||
GstBuffer *exif_chunk = NULL;
|
|
||||||
const GValue *val = NULL;
|
|
||||||
|
|
||||||
if (!(buf && size))
|
|
||||||
goto done;
|
|
||||||
if (*buf) {
|
|
||||||
g_free (*buf);
|
|
||||||
*buf = NULL;
|
|
||||||
}
|
|
||||||
*size = 0;
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ed) {
|
|
||||||
ed = exif_data_new ();
|
|
||||||
exif_data_set_data_type (ed, EXIF_DATA_TYPE_COMPRESSED);
|
|
||||||
exif_data_fix (ed);
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_tag_list_foreach (taglist, metadataexif_for_each_tag_in_list, ed);
|
|
||||||
|
|
||||||
exif_data_save_data (ed, buf, size);
|
|
||||||
|
|
||||||
|
|
||||||
done:
|
|
||||||
|
|
||||||
if (ed)
|
|
||||||
exif_data_unref (ed);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* else (ifndef HAVE_EXIF) */
|
#endif /* else (ifndef HAVE_EXIF) */
|
||||||
|
|
|
@ -50,6 +50,10 @@
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* external function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadataparse_exif_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_exif_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
GstAdapter * adapter, MetadataTagMapping mapping);
|
GstAdapter * adapter, MetadataTagMapping mapping);
|
||||||
|
|
|
@ -41,23 +41,51 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
#include "metadataiptc.h"
|
#include "metadataiptc.h"
|
||||||
#include "metadataparseutil.h"
|
#include "metadataparseutil.h"
|
||||||
#include "metadatatags.h"
|
#include "metadatatags.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* defines
|
||||||
|
*/
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (gst_metadata_iptc_debug);
|
GST_DEBUG_CATEGORY (gst_metadata_iptc_debug);
|
||||||
#define GST_CAT_DEFAULT gst_metadata_iptc_debug
|
#define GST_CAT_DEFAULT gst_metadata_iptc_debug
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation when libiptcdata isn't available at compilation time
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef HAVE_IPTC
|
#ifndef HAVE_IPTC
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extern functions implementations
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
metadataparse_iptc_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_iptc_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
GstAdapter * adapter, MetadataTagMapping mapping)
|
GstAdapter * adapter, MetadataTagMapping mapping)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (mapping & METADATA_TAG_MAP_WHOLECHUNK) {
|
if (mapping & METADATA_TAG_MAP_WHOLECHUNK) {
|
||||||
GST_LOG
|
GST_LOG ("IPTC not defined, sending just one tag as whole chunk");
|
||||||
("IPTC not defined, here I should send just one tag as whole chunk");
|
|
||||||
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_IPTC,
|
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_IPTC,
|
||||||
adapter);
|
adapter);
|
||||||
}
|
}
|
||||||
|
@ -74,11 +102,23 @@ metadatamux_iptc_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
|
||||||
|
|
||||||
#else /* ifndef HAVE_IPTC */
|
#else /* ifndef HAVE_IPTC */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation when libiptcdata is available at compilation time
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* includes
|
||||||
|
*/
|
||||||
|
|
||||||
#include <iptc-data.h>
|
#include <iptc-data.h>
|
||||||
#include <iptc-tag.h>
|
#include <iptc-tag.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <gst/gsttaglist.h>
|
#include <gst/gsttaglist.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enum and types
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct _tag_MEUserData
|
typedef struct _tag_MEUserData
|
||||||
{
|
{
|
||||||
GstTagList *taglist;
|
GstTagList *taglist;
|
||||||
|
@ -92,56 +132,62 @@ typedef struct _tag_MapIntStr
|
||||||
const gchar *str;
|
const gchar *str;
|
||||||
} MapIntStr;
|
} MapIntStr;
|
||||||
|
|
||||||
static void
|
/*
|
||||||
iptc_data_foreach_dataset_func (IptcDataSet * dataset, void *user_data);
|
* defines and static global vars
|
||||||
|
*/
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
static MapIntStr mappedTags[] = {
|
static MapIntStr mappedTags[] = {
|
||||||
{IPTC_RECORD_APP_2, IPTC_TAG_OBJECT_NAME, /*ASCII*/ GST_TAG_TITLE /*STRING*/},
|
{IPTC_RECORD_APP_2, IPTC_TAG_OBJECT_NAME, /*ASCII*/
|
||||||
{IPTC_RECORD_APP_2, IPTC_TAG_BYLINE, /*ASCII*/ GST_TAG_COMPOSER /*STRING*/},
|
GST_TAG_TITLE /*STRING*/},
|
||||||
{IPTC_RECORD_APP_2, IPTC_TAG_CAPTION, /*ASCII*/ GST_TAG_DESCRIPTION /*STRING*/},
|
{IPTC_RECORD_APP_2, IPTC_TAG_BYLINE, /*ASCII*/
|
||||||
{IPTC_RECORD_APP_2, IPTC_TAG_COPYRIGHT_NOTICE, /*ASCII*/ GST_TAG_COPYRIGHT /*STRING*/},
|
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}
|
{0, 0, NULL}
|
||||||
};
|
};
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
static const gchar *
|
/*
|
||||||
metadataparse_iptc_get_tag_from_iptc (IptcTag iptc, GType * type,
|
* static helper functions declaration
|
||||||
IptcRecord * record)
|
*/
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while (mappedTags[i].iptc) {
|
static const gchar *metadataparse_iptc_get_tag_from_iptc (IptcTag iptc,
|
||||||
if (iptc == mappedTags[i].iptc) {
|
GType * type, IptcRecord * record);
|
||||||
*type = gst_tag_get_type (mappedTags[i].str);
|
|
||||||
*record = mappedTags[i].record;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mappedTags[i].str;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static IptcTag
|
static IptcTag
|
||||||
metadataparse_iptc_get_iptc_from_tag (const gchar * tag, GType * type,
|
metadatamux_iptc_get_iptc_from_tag (const gchar * tag, GType * type,
|
||||||
IptcRecord * record)
|
IptcRecord * record);
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while (mappedTags[i].iptc) {
|
static void
|
||||||
if (0 == strcmp (mappedTags[i].str, tag)) {
|
metadataparse_iptc_data_foreach_dataset_func (IptcDataSet * dataset,
|
||||||
*type = gst_tag_get_type (tag);
|
void *user_data);
|
||||||
*record = mappedTags[i].record;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mappedTags[i].iptc;
|
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
|
void
|
||||||
metadataparse_iptc_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_iptc_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
|
@ -171,8 +217,8 @@ metadataparse_iptc_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
iptc_data_foreach_dataset (iptc, iptc_data_foreach_dataset_func,
|
iptc_data_foreach_dataset (iptc,
|
||||||
(void *) &user_data);
|
metadataparse_iptc_data_foreach_dataset_func, (void *) &user_data);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
|
@ -183,79 +229,17 @@ done:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/*
|
||||||
iptc_data_foreach_dataset_func (IptcDataSet * dataset, void *user_data)
|
* 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
|
||||||
char buf[1024];
|
* @taglist: list of tags to be added to IPTC chunk
|
||||||
MEUserData *meudata = (MEUserData *) user_data;
|
*
|
||||||
GType type;
|
* Get tags from @taglist, create a IPTC chunk based on it and save to @buf.
|
||||||
IptcRecord record;
|
* Note: The IPTC chunk is NOT wrapped by any bytes specific to any file format
|
||||||
const gchar *tag =
|
*
|
||||||
metadataparse_iptc_get_tag_from_iptc (dataset->tag, &type, &record);
|
* Returns: nothing
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
metadataiptc_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 = metadataparse_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, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
metadatamux_iptc_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
|
metadatamux_iptc_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
|
||||||
|
@ -286,7 +270,7 @@ metadatamux_iptc_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
|
||||||
iptc = iptc_data_new ();
|
iptc = iptc_data_new ();
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_tag_list_foreach (taglist, metadataiptc_for_each_tag_in_list, iptc);
|
gst_tag_list_foreach (taglist, metadatamux_iptc_for_each_tag_in_list, iptc);
|
||||||
|
|
||||||
iptc_data_save (iptc, buf, size);
|
iptc_data_save (iptc, buf, size);
|
||||||
|
|
||||||
|
@ -299,4 +283,182 @@ done:
|
||||||
return;
|
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, 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) */
|
#endif /* else (ifndef HAVE_IPTC) */
|
||||||
|
|
|
@ -50,6 +50,10 @@
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* external function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadataparse_iptc_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_iptc_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
GstAdapter * adapter, MetadataTagMapping mapping);
|
GstAdapter * adapter, MetadataTagMapping mapping);
|
||||||
|
|
|
@ -41,14 +41,62 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "metadataparsejpeg.h"
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "metadataparsejpeg.h"
|
||||||
|
|
||||||
#ifdef HAVE_IPTC
|
#ifdef HAVE_IPTC
|
||||||
#include <libiptcdata/iptc-jpeg.h>
|
#include <libiptcdata/iptc-jpeg.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
static MetadataParsingReturn
|
||||||
metadataparse_jpeg_reading (JpegParseData * jpeg_data, guint8 ** buf,
|
metadataparse_jpeg_reading (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
||||||
|
@ -72,13 +120,30 @@ static MetadataParsingReturn
|
||||||
metadataparse_jpeg_jump (JpegParseData * jpeg_data, guint8 ** buf,
|
metadataparse_jpeg_jump (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
|
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
|
||||||
|
|
||||||
#define READ(buf, size) ( (size)--, *((buf)++) )
|
/*
|
||||||
|
* extern functions implementations
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
/*
|
||||||
metadataparse_jpeg_lazy_update (JpegParseData * jpeg_data)
|
* metadataparse_jpeg_init:
|
||||||
{
|
* @jpeg_data: [in] jpeg data handler to be inited
|
||||||
/* nothing to do */
|
* @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
|
void
|
||||||
metadataparse_jpeg_init (JpegParseData * jpeg_data, GstAdapter ** exif_adpt,
|
metadataparse_jpeg_init (JpegParseData * jpeg_data, GstAdapter ** exif_adpt,
|
||||||
|
@ -100,6 +165,17 @@ metadataparse_jpeg_init (JpegParseData * jpeg_data, GstAdapter ** exif_adpt,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
void
|
||||||
metadataparse_jpeg_dispose (JpegParseData * jpeg_data)
|
metadataparse_jpeg_dispose (JpegParseData * jpeg_data)
|
||||||
{
|
{
|
||||||
|
@ -108,6 +184,42 @@ metadataparse_jpeg_dispose (JpegParseData * jpeg_data)
|
||||||
jpeg_data->xmp_adapter = NULL;
|
jpeg_data->xmp_adapter = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metadata_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
|
MetadataParsingReturn
|
||||||
metadataparse_jpeg_parse (JpegParseData * jpeg_data, guint8 * buf,
|
metadataparse_jpeg_parse (JpegParseData * jpeg_data, guint8 * buf,
|
||||||
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
|
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
|
||||||
|
@ -118,10 +230,19 @@ metadataparse_jpeg_parse (JpegParseData * jpeg_data, guint8 * buf,
|
||||||
guint8 mark[2] = { 0x00, 0x00 };
|
guint8 mark[2] = { 0x00, 0x00 };
|
||||||
const guint8 *step_buf = buf;
|
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;
|
*next_start = buf;
|
||||||
|
|
||||||
if (jpeg_data->state == JPEG_PARSE_NULL) {
|
if (jpeg_data->state == JPEG_PARSE_NULL) {
|
||||||
|
|
||||||
|
/* only the first time this function is called it will verify the stream
|
||||||
|
type to be sure it is a JPEG */
|
||||||
|
|
||||||
if (*bufsize < 2) {
|
if (*bufsize < 2) {
|
||||||
*next_size = (buf - *next_start) + 2;
|
*next_size = (buf - *next_start) + 2;
|
||||||
ret = META_PARSING_NEED_MORE_DATA;
|
ret = META_PARSING_NEED_MORE_DATA;
|
||||||
|
@ -184,6 +305,68 @@ done:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 */
|
/* look for markers */
|
||||||
static MetadataParsingReturn
|
static MetadataParsingReturn
|
||||||
|
@ -218,7 +401,8 @@ metadataparse_jpeg_reading (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
ret = META_PARSING_DONE;
|
ret = META_PARSING_DONE;
|
||||||
jpeg_data->state = JPEG_PARSE_DONE;
|
jpeg_data->state = JPEG_PARSE_DONE;
|
||||||
goto done;
|
goto done;
|
||||||
} else if (mark[1] == 0xDA) { /* start of scan, lets not look behinf of this */
|
} else if (mark[1] == 0xDA) {
|
||||||
|
/* start of scan image, lets not look behind of this */
|
||||||
ret = META_PARSING_DONE;
|
ret = META_PARSING_DONE;
|
||||||
jpeg_data->state = JPEG_PARSE_DONE;
|
jpeg_data->state = JPEG_PARSE_DONE;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -264,7 +448,9 @@ metadataparse_jpeg_reading (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
if (!jpeg_data->parse_only) {
|
if (!jpeg_data->parse_only) {
|
||||||
|
|
||||||
memset (&chunk, 0x00, sizeof (MetadataChunk));
|
memset (&chunk, 0x00, sizeof (MetadataChunk));
|
||||||
chunk.offset_orig = (*buf - step_buf) + offset - 4; /* maker + size */
|
|
||||||
|
chunk.offset_orig = (*buf - step_buf) + offset - 4; /* 4 == maker + size */
|
||||||
|
|
||||||
chunk.size = chunk_size + 2; /* chunk size plus app marker */
|
chunk.size = chunk_size + 2; /* chunk size plus app marker */
|
||||||
chunk.type = MD_CHUNK_EXIF;
|
chunk.type = MD_CHUNK_EXIF;
|
||||||
|
|
||||||
|
@ -276,15 +462,15 @@ metadataparse_jpeg_reading (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
if (!jpeg_data->jfif_found) {
|
if (!jpeg_data->jfif_found) {
|
||||||
/* only inject if no JFIF has been found */
|
/* only inject if no JFIF has been found */
|
||||||
|
|
||||||
static const guint8 segment[] = { 0xff, 0xe0, 0x00, 0x10,
|
|
||||||
0x4a, 0x46, 0x49, 0x46, 0x00,
|
|
||||||
0x01, 0x02,
|
|
||||||
0x00, 0x00, 0x01, 0x00, 0x01,
|
|
||||||
0x00, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!jpeg_data->parse_only) {
|
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));
|
memset (&chunk, 0x00, sizeof (MetadataChunk));
|
||||||
chunk.offset_orig = 2;
|
chunk.offset_orig = 2;
|
||||||
chunk.size = 18;
|
chunk.size = 18;
|
||||||
|
@ -321,7 +507,7 @@ metadataparse_jpeg_reading (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
MetadataChunk chunk;
|
MetadataChunk chunk;
|
||||||
|
|
||||||
memset (&chunk, 0x00, sizeof (MetadataChunk));
|
memset (&chunk, 0x00, sizeof (MetadataChunk));
|
||||||
chunk.offset_orig = (*buf - step_buf) + offset - 4; /* maker + size */
|
chunk.offset_orig = (*buf - step_buf) + offset - 4; /* 4 == maker + size */
|
||||||
chunk.size = chunk_size + 2; /* chunk size plus app marker */
|
chunk.size = chunk_size + 2; /* chunk size plus app marker */
|
||||||
chunk.type = MD_CHUNK_XMP;
|
chunk.type = MD_CHUNK_XMP;
|
||||||
|
|
||||||
|
@ -344,7 +530,9 @@ metadataparse_jpeg_reading (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef HAVE_IPTC
|
#ifdef HAVE_IPTC
|
||||||
else if (mark[1] == 0xED) { /* may be it is photoshop and may be there is 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 (chunk_size >= 16) { /* size2 "Photoshop 3.0" */
|
||||||
|
|
||||||
if (*bufsize < 14) {
|
if (*bufsize < 14) {
|
||||||
|
@ -361,7 +549,7 @@ metadataparse_jpeg_reading (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
MetadataChunk chunk;
|
MetadataChunk chunk;
|
||||||
|
|
||||||
memset (&chunk, 0x00, sizeof (MetadataChunk));
|
memset (&chunk, 0x00, sizeof (MetadataChunk));
|
||||||
chunk.offset_orig = (*buf - step_buf) + offset - 4; /* maker + size */
|
chunk.offset_orig = (*buf - step_buf) + offset - 4; /* 4 == maker + size */
|
||||||
chunk.size = chunk_size + 2; /* chunk size plus app marker */
|
chunk.size = chunk_size + 2; /* chunk size plus app marker */
|
||||||
chunk.type = MD_CHUNK_IPTC;
|
chunk.type = MD_CHUNK_IPTC;
|
||||||
|
|
||||||
|
@ -400,6 +588,43 @@ done:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
static MetadataParsingReturn
|
||||||
metadataparse_jpeg_exif (JpegParseData * jpeg_data, guint8 ** buf,
|
metadataparse_jpeg_exif (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
|
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
|
||||||
|
@ -419,6 +644,15 @@ metadataparse_jpeg_exif (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
#ifdef HAVE_IPTC
|
||||||
static MetadataParsingReturn
|
static MetadataParsingReturn
|
||||||
metadataparse_jpeg_iptc (JpegParseData * jpeg_data, guint8 ** buf,
|
metadataparse_jpeg_iptc (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
|
@ -443,6 +677,7 @@ metadataparse_jpeg_iptc (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
size = gst_adapter_available (*jpeg_data->iptc_adapter);
|
size = gst_adapter_available (*jpeg_data->iptc_adapter);
|
||||||
buf = gst_adapter_peek (*jpeg_data->iptc_adapter, size);
|
buf = gst_adapter_peek (*jpeg_data->iptc_adapter, size);
|
||||||
|
|
||||||
|
/* FIXME: currently we are trhowing away others PhotoShop data */
|
||||||
res = iptc_jpeg_ps3_find_iptc (buf, size, &iptc_len);
|
res = iptc_jpeg_ps3_find_iptc (buf, size, &iptc_len);
|
||||||
|
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
|
@ -473,6 +708,14 @@ metadataparse_jpeg_iptc (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metadataparse_jpeg_xmp:
|
||||||
|
*
|
||||||
|
* Look at #metadataparse_jpeg_exif. This function has the same behavior as
|
||||||
|
* that.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
static MetadataParsingReturn
|
static MetadataParsingReturn
|
||||||
metadataparse_jpeg_xmp (JpegParseData * jpeg_data, guint8 ** buf,
|
metadataparse_jpeg_xmp (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
|
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
|
||||||
|
@ -490,6 +733,32 @@ metadataparse_jpeg_xmp (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
return ret;
|
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
|
static MetadataParsingReturn
|
||||||
metadataparse_jpeg_jump (JpegParseData * jpeg_data, guint8 ** buf,
|
metadataparse_jpeg_jump (JpegParseData * jpeg_data, guint8 ** buf,
|
||||||
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
|
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
|
||||||
|
|
|
@ -44,12 +44,20 @@
|
||||||
#ifndef __METADATAPARSE_JPEG_H__
|
#ifndef __METADATAPARSE_JPEG_H__
|
||||||
#define __METADATAPARSE_JPEG_H__
|
#define __METADATAPARSE_JPEG_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* includes
|
||||||
|
*/
|
||||||
|
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
#include "metadatatypes.h"
|
#include "metadatatypes.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enum and types
|
||||||
|
*/
|
||||||
|
|
||||||
typedef enum _tag_JpegParseState
|
typedef enum _tag_JpegParseState
|
||||||
{
|
{
|
||||||
JPEG_PARSE_NULL,
|
JPEG_PARSE_NULL,
|
||||||
|
@ -79,6 +87,9 @@ typedef struct _tag_JpegParseData
|
||||||
gboolean jfif_found;
|
gboolean jfif_found;
|
||||||
} JpegParseData;
|
} JpegParseData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* external function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadataparse_jpeg_init (JpegParseData * jpeg_data, GstAdapter ** exif_adpt,
|
metadataparse_jpeg_init (JpegParseData * jpeg_data, GstAdapter ** exif_adpt,
|
||||||
|
@ -88,11 +99,12 @@ metadataparse_jpeg_init (JpegParseData * jpeg_data, GstAdapter ** exif_adpt,
|
||||||
|
|
||||||
extern void metadataparse_jpeg_dispose (JpegParseData * jpeg_data);
|
extern void metadataparse_jpeg_dispose (JpegParseData * jpeg_data);
|
||||||
|
|
||||||
extern void metadataparse_jpeg_lazy_update (JpegParseData * jpeg_data);
|
|
||||||
|
|
||||||
extern MetadataParsingReturn
|
extern MetadataParsingReturn
|
||||||
metadataparse_jpeg_parse (JpegParseData * jpeg_data, guint8 * buf,
|
metadataparse_jpeg_parse (JpegParseData * jpeg_data, guint8 * buf,
|
||||||
guint32 * bufsize, const guint32 offset, guint8 ** next_start, guint32 * next_size);
|
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
|
||||||
|
guint32 * next_size);
|
||||||
|
|
||||||
|
extern void metadataparse_jpeg_lazy_update (JpegParseData * jpeg_data);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
#endif /* __METADATAPARSE_JPEG_H__ */
|
#endif /* __METADATAPARSE_JPEG_H__ */
|
||||||
|
|
|
@ -41,10 +41,45 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
#include "metadataparsepng.h"
|
#include "metadataparsepng.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
static MetadataParsingReturn
|
||||||
metadataparse_png_reading (PngParseData * png_data, guint8 ** buf,
|
metadataparse_png_reading (PngParseData * png_data, guint8 ** buf,
|
||||||
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
||||||
|
@ -58,13 +93,30 @@ static MetadataParsingReturn
|
||||||
metadataparse_png_jump (PngParseData * png_data, guint8 ** buf,
|
metadataparse_png_jump (PngParseData * png_data, guint8 ** buf,
|
||||||
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
|
guint32 * bufsize, guint8 ** next_start, guint32 * next_size);
|
||||||
|
|
||||||
#define READ(buf, size) ( (size)--, *((buf)++) )
|
/*
|
||||||
|
* extern functions implementations
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
/*
|
||||||
metadataparse_png_lazy_update (PngParseData * jpeg_data)
|
* metadataparse_png_init:
|
||||||
{
|
* @png_data: [in] png data handler to be inited
|
||||||
/* nothing to do */
|
* @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
|
void
|
||||||
metadataparse_png_init (PngParseData * png_data, GstAdapter ** exif_adpt,
|
metadataparse_png_init (PngParseData * png_data, GstAdapter ** exif_adpt,
|
||||||
|
@ -82,12 +134,59 @@ metadataparse_png_init (PngParseData * png_data, GstAdapter ** exif_adpt,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
void
|
||||||
metadataparse_png_dispose (PngParseData * png_data)
|
metadataparse_png_dispose (PngParseData * png_data)
|
||||||
{
|
{
|
||||||
png_data->xmp_adapter = NULL;
|
png_data->xmp_adapter = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metadata_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
|
MetadataParsingReturn
|
||||||
metadataparse_png_parse (PngParseData * png_data, guint8 * buf,
|
metadataparse_png_parse (PngParseData * png_data, guint8 * buf,
|
||||||
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
|
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
|
||||||
|
@ -98,10 +197,19 @@ metadataparse_png_parse (PngParseData * png_data, guint8 * buf,
|
||||||
guint8 mark[8];
|
guint8 mark[8];
|
||||||
const guint8 *step_buf = buf;
|
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;
|
*next_start = buf;
|
||||||
|
|
||||||
if (png_data->state == PNG_PARSE_NULL) {
|
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) {
|
if (*bufsize < 8) {
|
||||||
*next_size = (buf - *next_start) + 8;
|
*next_size = (buf - *next_start) + 8;
|
||||||
ret = META_PARSING_NEED_MORE_DATA;
|
ret = META_PARSING_NEED_MORE_DATA;
|
||||||
|
@ -117,9 +225,9 @@ metadataparse_png_parse (PngParseData * png_data, guint8 * buf,
|
||||||
mark[6] = READ (buf, *bufsize);
|
mark[6] = READ (buf, *bufsize);
|
||||||
mark[7] = READ (buf, *bufsize);
|
mark[7] = READ (buf, *bufsize);
|
||||||
|
|
||||||
if (mark[0] != 0x89 || mark[1] != 0x50 || mark[2] != 0x4E || mark[3] != 0x47
|
if (mark[0] != 0x89 || mark[1] != 0x50 || mark[2] != 0x4E ||
|
||||||
|| mark[4] != 0x0D || mark[5] != 0x0A || mark[6] != 0x1A
|
mark[3] != 0x47 || mark[4] != 0x0D || mark[5] != 0x0A ||
|
||||||
|| mark[7] != 0x0A) {
|
mark[6] != 0x1A || mark[7] != 0x0A) {
|
||||||
ret = META_PARSING_ERROR;
|
ret = META_PARSING_ERROR;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -160,6 +268,68 @@ done:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 */
|
/* look for markers */
|
||||||
static MetadataParsingReturn
|
static MetadataParsingReturn
|
||||||
|
@ -213,7 +383,7 @@ metadataparse_png_reading (PngParseData * png_data, guint8 ** buf,
|
||||||
|
|
||||||
memset (&chunk, 0x00, sizeof (MetadataChunk));
|
memset (&chunk, 0x00, sizeof (MetadataChunk));
|
||||||
chunk.offset_orig = (*buf - step_buf) + offset - 8; /* maker + size */
|
chunk.offset_orig = (*buf - step_buf) + offset - 8; /* maker + size */
|
||||||
chunk.size = chunk_size + 12; /* chunk size plus app marker plus crc */
|
chunk.size = chunk_size + 12; /* chunk size + app marker + crc */
|
||||||
chunk.type = MD_CHUNK_XMP;
|
chunk.type = MD_CHUNK_XMP;
|
||||||
|
|
||||||
metadata_chunk_array_append_sorted (png_data->strip_chunks, &chunk);
|
metadata_chunk_array_append_sorted (png_data->strip_chunks, &chunk);
|
||||||
|
@ -221,9 +391,10 @@ metadataparse_png_reading (PngParseData * png_data, guint8 ** buf,
|
||||||
|
|
||||||
/* if adapter has been provided, prepare to hold chunk */
|
/* if adapter has been provided, prepare to hold chunk */
|
||||||
if (png_data->xmp_adapter) {
|
if (png_data->xmp_adapter) {
|
||||||
*buf += 22; /* jump "XML:com.adobe.xmp" plus some flags */
|
*buf += 22; /* jump "XML:com.adobe.xmp" + some flags */
|
||||||
*bufsize -= 22;
|
*bufsize -= 22;
|
||||||
png_data->read = chunk_size - 22; /* four CRC bytes at the end will be jumped after */
|
/* four CRC bytes at the end will be jumped after */
|
||||||
|
png_data->read = chunk_size - 22;
|
||||||
png_data->state = PNG_PARSE_XMP;
|
png_data->state = PNG_PARSE_XMP;
|
||||||
ret = META_PARSING_DONE;
|
ret = META_PARSING_DONE;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -244,14 +415,44 @@ done:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static MetadataParsingReturn
|
/*
|
||||||
metadataparse_png_jump (PngParseData * png_data, guint8 ** buf,
|
* metadataparse_png_xmp:
|
||||||
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
|
* @png_data: [in] png data handle
|
||||||
{
|
* @buf: [in] data to be parsed
|
||||||
png_data->state = PNG_PARSE_READING;
|
* @bufsize: [in] size of @buf in bytes
|
||||||
return metadataparse_util_jump_chunk (&png_data->read, buf,
|
* @next_start: look at #metadataparse_png_reading
|
||||||
bufsize, next_start, next_size);
|
* @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
|
static MetadataParsingReturn
|
||||||
metadataparse_png_xmp (PngParseData * png_data, guint8 ** buf,
|
metadataparse_png_xmp (PngParseData * png_data, guint8 ** buf,
|
||||||
|
@ -271,3 +472,38 @@ metadataparse_png_xmp (PngParseData * png_data, guint8 ** buf,
|
||||||
return ret;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -44,12 +44,20 @@
|
||||||
#ifndef __METADATAPARSE_PNG_H__
|
#ifndef __METADATAPARSE_PNG_H__
|
||||||
#define __METADATAPARSE_PNG_H__
|
#define __METADATAPARSE_PNG_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* includes
|
||||||
|
*/
|
||||||
|
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
#include "metadatatypes.h"
|
#include "metadatatypes.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enum and types
|
||||||
|
*/
|
||||||
|
|
||||||
typedef enum _tag_PngParseState
|
typedef enum _tag_PngParseState
|
||||||
{
|
{
|
||||||
PNG_PARSE_NULL,
|
PNG_PARSE_NULL,
|
||||||
|
@ -73,6 +81,9 @@ typedef struct _tag_PngParseData
|
||||||
guint32 read;
|
guint32 read;
|
||||||
} PngParseData;
|
} PngParseData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* external function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadataparse_png_init (PngParseData * png_data, GstAdapter ** exif_adpt,
|
metadataparse_png_init (PngParseData * png_data, GstAdapter ** exif_adpt,
|
||||||
|
@ -82,11 +93,12 @@ metadataparse_png_init (PngParseData * png_data, GstAdapter ** exif_adpt,
|
||||||
|
|
||||||
extern void metadataparse_png_dispose (PngParseData * png_data);
|
extern void metadataparse_png_dispose (PngParseData * png_data);
|
||||||
|
|
||||||
extern void metadataparse_png_lazy_update (PngParseData * jpeg_data);
|
extern void metadataparse_png_lazy_update (PngParseData * png_data);
|
||||||
|
|
||||||
extern MetadataParsingReturn
|
extern MetadataParsingReturn
|
||||||
metadataparse_png_parse (PngParseData * png_data, guint8 * buf,
|
metadataparse_png_parse (PngParseData * png_data, guint8 * buf,
|
||||||
guint32 * bufsize, const guint32 offset, guint8 ** next_start, guint32 * next_size);
|
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
|
||||||
|
guint32 * next_size);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
#endif /* __METADATAPARSE_PNG_H__ */
|
#endif /* __METADATAPARSE_PNG_H__ */
|
||||||
|
|
|
@ -41,9 +41,38 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
#include "metadataparseutil.h"
|
#include "metadataparseutil.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
void
|
||||||
metadataparse_util_tag_list_add_chunk (GstTagList * taglist,
|
metadataparse_util_tag_list_add_chunk (GstTagList * taglist,
|
||||||
GstTagMergeMode mode, const gchar * name, GstAdapter * adapter)
|
GstTagMergeMode mode, const gchar * name, GstAdapter * adapter)
|
||||||
|
@ -64,6 +93,39 @@ metadataparse_util_tag_list_add_chunk (GstTagList * taglist,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
MetadataParsingReturn
|
||||||
metadataparse_util_hold_chunk (guint32 * read, guint8 ** buf,
|
metadataparse_util_hold_chunk (guint32 * read, guint8 ** buf,
|
||||||
guint32 * bufsize, guint8 ** next_start,
|
guint32 * bufsize, guint8 ** next_start,
|
||||||
|
@ -95,6 +157,16 @@ metadataparse_util_hold_chunk (guint32 * read, guint8 ** buf,
|
||||||
return ret;
|
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
|
MetadataParsingReturn
|
||||||
metadataparse_util_jump_chunk (guint32 * read, guint8 ** buf,
|
metadataparse_util_jump_chunk (guint32 * read, guint8 ** buf,
|
||||||
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
|
guint32 * bufsize, guint8 ** next_start, guint32 * next_size)
|
||||||
|
|
|
@ -44,6 +44,10 @@
|
||||||
#ifndef __GST_METADATAPARSE_UTIL_H__
|
#ifndef __GST_METADATAPARSE_UTIL_H__
|
||||||
#define __GST_METADATAPARSE_UTIL_H__
|
#define __GST_METADATAPARSE_UTIL_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* includes
|
||||||
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
|
@ -51,6 +55,10 @@
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* external function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadataparse_util_tag_list_add_chunk (GstTagList * taglist,
|
metadataparse_util_tag_list_add_chunk (GstTagList * taglist,
|
||||||
GstTagMergeMode mode, const gchar * name, GstAdapter * adapter);
|
GstTagMergeMode mode, const gchar * name, GstAdapter * adapter);
|
||||||
|
|
|
@ -41,8 +41,67 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* 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)
|
||||||
|
*
|
||||||
|
* Last reviewed on 2008-01-24 (0.10.15)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* includes
|
||||||
|
*/
|
||||||
|
|
||||||
#include "metadatatags.h"
|
#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
|
* EXIF tags
|
||||||
*/
|
*/
|
||||||
|
@ -179,30 +238,3 @@ metadata_tags_xmp_register (void)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
|
||||||
metadata_tags_register (void)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* whole chunk tags */
|
|
||||||
|
|
||||||
gst_tag_register (GST_TAG_EXIF, GST_TAG_FLAG_META,
|
|
||||||
GST_TYPE_BUFFER, GST_TAG_EXIF, "exif metadata chunk", NULL);
|
|
||||||
|
|
||||||
gst_tag_register (GST_TAG_IPTC, GST_TAG_FLAG_META,
|
|
||||||
GST_TYPE_BUFFER, GST_TAG_IPTC, "iptc metadata chunk", NULL);
|
|
||||||
|
|
||||||
gst_tag_register (GST_TAG_XMP, GST_TAG_FLAG_META,
|
|
||||||
GST_TYPE_BUFFER, GST_TAG_XMP, "xmp metadata chunk", NULL);
|
|
||||||
|
|
||||||
/* tags related to some metadata */
|
|
||||||
|
|
||||||
metadata_tags_exif_register ();
|
|
||||||
metadata_tags_iptc_register ();
|
|
||||||
metadata_tags_xmp_register ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -44,17 +44,29 @@
|
||||||
#ifndef __GST_METADATA_TAGS_H__
|
#ifndef __GST_METADATA_TAGS_H__
|
||||||
#define __GST_METADATA_TAGS_H__
|
#define __GST_METADATA_TAGS_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* includes
|
||||||
|
*/
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enum and types
|
||||||
|
*/
|
||||||
|
|
||||||
/* set bit to desired mapping */
|
/* set bit to desired mapping */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
METADATA_TAG_MAP_INDIVIDUALS = 1 << 0,
|
METADATA_TAG_MAP_INDIVIDUALS = 1 << 0,
|
||||||
METADATA_TAG_MAP_WHOLECHUNK = 1 << 1
|
METADATA_TAG_MAP_WHOLECHUNK = 1 << 1
|
||||||
} MetadataTagMapping;
|
} MetadataTagMapping;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* defines
|
||||||
|
*/
|
||||||
|
|
||||||
#define GST_TAG_EXIF "exif"
|
#define GST_TAG_EXIF "exif"
|
||||||
|
|
||||||
#define GST_TAG_IPTC "iptc"
|
#define GST_TAG_IPTC "iptc"
|
||||||
|
@ -79,6 +91,10 @@ typedef enum {
|
||||||
#define GST_TAG_CAPTURE_CONTRAST "capture-contrast"
|
#define GST_TAG_CAPTURE_CONTRAST "capture-contrast"
|
||||||
#define GST_TAG_CAPTURE_SATURATION "capture-saturation"
|
#define GST_TAG_CAPTURE_SATURATION "capture-saturation"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* external function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadata_tags_register (void);
|
metadata_tags_register (void);
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,41 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
#include "metadatatypes.h"
|
#include "metadatatypes.h"
|
||||||
|
|
||||||
#include <string.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
|
void
|
||||||
metadata_chunk_array_init (MetadataChunkArray * array, gsize alloc_size)
|
metadata_chunk_array_init (MetadataChunkArray * array, gsize alloc_size)
|
||||||
{
|
{
|
||||||
|
@ -53,6 +84,16 @@ metadata_chunk_array_init (MetadataChunkArray * array, gsize alloc_size)
|
||||||
array->allocated_len = 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
|
void
|
||||||
metadata_chunk_array_free (MetadataChunkArray * array)
|
metadata_chunk_array_free (MetadataChunkArray * array)
|
||||||
{
|
{
|
||||||
|
@ -64,6 +105,17 @@ metadata_chunk_array_free (MetadataChunkArray * array)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
void
|
||||||
metadata_chunk_array_clear (MetadataChunkArray * array)
|
metadata_chunk_array_clear (MetadataChunkArray * array)
|
||||||
{
|
{
|
||||||
|
@ -75,6 +127,19 @@ metadata_chunk_array_clear (MetadataChunkArray * array)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
void
|
||||||
metadata_chunk_array_append (MetadataChunkArray * array, MetadataChunk * chunk)
|
metadata_chunk_array_append (MetadataChunkArray * array, MetadataChunk * chunk)
|
||||||
{
|
{
|
||||||
|
@ -87,6 +152,19 @@ metadata_chunk_array_append (MetadataChunkArray * array, MetadataChunk * chunk)
|
||||||
++array->len;
|
++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
|
void
|
||||||
metadata_chunk_array_append_sorted (MetadataChunkArray * array,
|
metadata_chunk_array_append_sorted (MetadataChunkArray * array,
|
||||||
MetadataChunk * chunk)
|
MetadataChunk * chunk)
|
||||||
|
@ -116,6 +194,18 @@ metadata_chunk_array_append_sorted (MetadataChunkArray * array,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
void
|
||||||
metadata_chunk_array_remove_zero_size (MetadataChunkArray * array)
|
metadata_chunk_array_remove_zero_size (MetadataChunkArray * array)
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,10 +44,18 @@
|
||||||
#ifndef __METADATATYPES_H__
|
#ifndef __METADATATYPES_H__
|
||||||
#define __METADATATYPES_H__
|
#define __METADATATYPES_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* includes
|
||||||
|
*/
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enum and types
|
||||||
|
*/
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
|
|
||||||
typedef enum _tag_MetadataParsingReturn {
|
typedef enum _tag_MetadataParsingReturn {
|
||||||
|
@ -78,10 +86,14 @@ typedef struct _tag_MetadataChunk
|
||||||
typedef struct _tag_MetadataChunkArray
|
typedef struct _tag_MetadataChunkArray
|
||||||
{
|
{
|
||||||
MetadataChunk * chunk;
|
MetadataChunk * chunk;
|
||||||
gsize len;
|
gsize len; /* number of chunks into aray */
|
||||||
gsize allocated_len;
|
gsize allocated_len; /* number of slots into the array to store chunks */
|
||||||
} MetadataChunkArray;
|
} MetadataChunkArray;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* external function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadata_chunk_array_init(MetadataChunkArray * array, gsize alloc_size);
|
metadata_chunk_array_init(MetadataChunkArray * array, gsize alloc_size);
|
||||||
|
|
||||||
|
@ -94,11 +106,9 @@ metadata_chunk_array_clear(MetadataChunkArray * array);
|
||||||
extern void
|
extern void
|
||||||
metadata_chunk_array_append(MetadataChunkArray * array, MetadataChunk * chunk);
|
metadata_chunk_array_append(MetadataChunkArray * array, MetadataChunk * chunk);
|
||||||
|
|
||||||
/* sorted by offset (chunk supposed to be already sorted
|
|
||||||
* returns false if chunks are inserted in same offset
|
|
||||||
*/
|
|
||||||
extern void
|
extern void
|
||||||
metadata_chunk_array_append_sorted(MetadataChunkArray * array, MetadataChunk * chunk);
|
metadata_chunk_array_append_sorted(MetadataChunkArray * array,
|
||||||
|
MetadataChunk * chunk);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadata_chunk_array_remove_zero_size (MetadataChunkArray * array);
|
metadata_chunk_array_remove_zero_size (MetadataChunkArray * array);
|
||||||
|
|
|
@ -41,39 +41,75 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
#include "metadataxmp.h"
|
#include "metadataxmp.h"
|
||||||
#include "metadataparseutil.h"
|
#include "metadataparseutil.h"
|
||||||
#include "metadatatags.h"
|
#include "metadatatags.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* defines
|
||||||
|
*/
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (gst_metadata_xmp_debug);
|
GST_DEBUG_CATEGORY (gst_metadata_xmp_debug);
|
||||||
#define GST_CAT_DEFAULT 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
|
#ifndef HAVE_XMP
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extern functions implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
metadata_xmp_init (void)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
metadata_xmp_dispose (void)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
GstAdapter * adapter, MetadataTagMapping mapping)
|
GstAdapter * adapter, MetadataTagMapping mapping)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (mapping & METADATA_TAG_MAP_WHOLECHUNK) {
|
if (mapping & METADATA_TAG_MAP_WHOLECHUNK) {
|
||||||
GST_LOG ("XMP not defined, here I should send just one tag as whole chunk");
|
GST_LOG ("XMP not defined, sending just one tag as whole chunk");
|
||||||
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_XMP, adapter);
|
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_XMP, adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
|
||||||
metadataparse_xmp_init (void)
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
metadataparse_xmp_dispose (void)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
metadatamux_xmp_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
|
metadatamux_xmp_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
|
||||||
const GstTagList * taglist)
|
const GstTagList * taglist)
|
||||||
|
@ -83,10 +119,20 @@ metadatamux_xmp_create_chunk_from_tag_list (guint8 ** buf, guint32 * size,
|
||||||
|
|
||||||
#else /* ifndef HAVE_XMP */
|
#else /* ifndef HAVE_XMP */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation when lib exempi isn't available at compilation time
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* includes
|
||||||
|
*/
|
||||||
|
|
||||||
#include <xmp.h>
|
#include <xmp.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define XMP_SCHEMA_NODE 0x80000000UL
|
/*
|
||||||
|
* enum and types
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct _tag_SchemaTagMap
|
typedef struct _tag_SchemaTagMap
|
||||||
{
|
{
|
||||||
|
@ -102,6 +148,12 @@ typedef struct _tag_SchemaMap
|
||||||
const SchemaTagMap *tags_map;
|
const SchemaTagMap *tags_map;
|
||||||
} SchemaMap;
|
} SchemaMap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* defines and static global vars
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define XMP_SCHEMA_NODE 0x80000000UL
|
||||||
|
|
||||||
static const SchemaTagMap schema_map_dublin_tags_map[] = {
|
static const SchemaTagMap schema_map_dublin_tags_map[] = {
|
||||||
{"description", GST_TAG_DESCRIPTION},
|
{"description", GST_TAG_DESCRIPTION},
|
||||||
{"title", GST_TAG_TITLE},
|
{"title", GST_TAG_TITLE},
|
||||||
|
@ -109,7 +161,8 @@ static const SchemaTagMap schema_map_dublin_tags_map[] = {
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const SchemaMap schema_map_dublin = { "http://purl.org/dc/elements/1.1/",
|
static const SchemaMap schema_map_dublin = {
|
||||||
|
"http://purl.org/dc/elements/1.1/",
|
||||||
"dc:",
|
"dc:",
|
||||||
3,
|
3,
|
||||||
schema_map_dublin_tags_map
|
schema_map_dublin_tags_map
|
||||||
|
@ -120,10 +173,22 @@ static const SchemaMap *schemas_map[] = {
|
||||||
NULL
|
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
|
static void
|
||||||
metadataparse_xmp_iter_add_to_tag_list (GstTagList * taglist,
|
metadataparse_xmp_iter (GstTagList * taglist, GstTagMergeMode mode, XmpPtr xmp);
|
||||||
GstTagMergeMode mode, const char *path, const char *value,
|
|
||||||
const SchemaMap * schema_map, const uint32_t opt);
|
static void
|
||||||
|
metadataparse_xmp_iter_node_schema (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
|
XmpPtr xmp, const char *schema, const char *path);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
metadataparse_xmp_iter_array (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_xmp_iter_array (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
|
@ -131,34 +196,75 @@ metadataparse_xmp_iter_array (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
const SchemaMap * schema_map);
|
const SchemaMap * schema_map);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
metadataparse_xmp_iter_node_schema (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_xmp_iter_simple_qual (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
XmpPtr xmp, const char *schema, const char *path);
|
const char *path, const char *value, const SchemaMap * schema_map);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
metadataparse_xmp_iter_simple (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_xmp_iter_simple (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
const char *schema, const char *path, const char *value,
|
const char *path, const char *value, const SchemaMap * schema_map);
|
||||||
const SchemaMap * schema_map);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
metadataparse_xmp_iter_simple_qual (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_xmp_iter_add_to_tag_list (GstTagList * taglist,
|
||||||
const char *schema, const char *path, const char *value,
|
GstTagMergeMode mode, const char *path, const char *value,
|
||||||
const SchemaMap * schema_map);
|
const SchemaMap * schema_map, const uint32_t opt);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
metadataparse_xmp_iter (GstTagList * taglist, GstTagMergeMode mode, XmpPtr xmp);
|
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
|
gboolean
|
||||||
metadataparse_xmp_init (void)
|
metadata_xmp_init (void)
|
||||||
{
|
{
|
||||||
return xmp_init ();
|
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
|
void
|
||||||
metadataparse_xmp_dispose (void)
|
metadata_xmp_dispose (void)
|
||||||
{
|
{
|
||||||
xmp_terminate ();
|
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
|
void
|
||||||
metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
GstAdapter * adapter, MetadataTagMapping mapping)
|
GstAdapter * adapter, MetadataTagMapping mapping)
|
||||||
|
@ -172,8 +278,9 @@ metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add chunk tag */
|
/* add chunk tag */
|
||||||
if (mapping & METADATA_TAG_MAP_WHOLECHUNK)
|
if (mapping & METADATA_TAG_MAP_WHOLECHUNK) {
|
||||||
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_XMP, adapter);
|
metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_XMP, adapter);
|
||||||
|
}
|
||||||
|
|
||||||
if (!(mapping & METADATA_TAG_MAP_INDIVIDUALS))
|
if (!(mapping & METADATA_TAG_MAP_INDIVIDUALS))
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -196,32 +303,96 @@ done:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const SchemaTagMap *
|
/*
|
||||||
metadataparse_get_tagsmap_from_gsttag (const SchemaMap * schema_map,
|
* metadatamux_xmp_create_chunk_from_tag_list:
|
||||||
const gchar * tag)
|
* @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)
|
||||||
{
|
{
|
||||||
SchemaTagMap *tags_map = NULL;
|
GstBuffer *xmp_chunk = NULL;
|
||||||
int i;
|
const GValue *val = NULL;
|
||||||
|
XmpPtr xmp = NULL;
|
||||||
|
XmpStringPtr xmp_str_buf = xmp_string_new ();
|
||||||
|
|
||||||
if (NULL == schema_map)
|
if (!(buf && size))
|
||||||
goto done;
|
goto done;
|
||||||
|
if (*buf) {
|
||||||
|
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 (GST_BUFFER_DATA (xmp_chunk), GST_BUFFER_SIZE (xmp_chunk));
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; schema_map->tags_map[i].gst_tag; i++) {
|
if (NULL == xmp)
|
||||||
if (0 == strcmp (schema_map->tags_map[i].gst_tag, tag)) {
|
xmp = xmp_new_empty ();
|
||||||
tags_map = (SchemaTagMap *) & schema_map->tags_map[i];
|
|
||||||
break;
|
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) {
|
||||||
|
unsigned int len = strlen (xmp_string_cstr (xmp_str_buf));
|
||||||
|
|
||||||
|
*size = len + 1;
|
||||||
|
*buf = malloc (*size);
|
||||||
|
memcpy (*buf, xmp_string_cstr (xmp_str_buf), *size);
|
||||||
|
} else {
|
||||||
|
GST_ERROR ("failed to serialize xmp into chunk\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
return tags_map;
|
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 *
|
static const SchemaTagMap *
|
||||||
metadataparse_get_tagsmap_from_path (const SchemaMap * schema_map,
|
metadataparse_xmp_get_tagsmap_from_path (const SchemaMap * schema_map,
|
||||||
const gchar * path, uint32_t opt)
|
const gchar * path, uint32_t opt)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -238,7 +409,7 @@ metadataparse_get_tagsmap_from_path (const SchemaMap * schema_map,
|
||||||
|
|
||||||
string = g_string_new (path);
|
string = g_string_new (path);
|
||||||
|
|
||||||
/* remove the language qualifier */
|
/* remove the language qualifier "[xxx]" */
|
||||||
ch = string->str + string->len - 3;
|
ch = string->str + string->len - 3;
|
||||||
while (ch != string->str + schema_map->prefix_len) {
|
while (ch != string->str + schema_map->prefix_len) {
|
||||||
if (*ch == '[') {
|
if (*ch == '[') {
|
||||||
|
@ -266,160 +437,63 @@ done:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/*
|
||||||
metadataparse_xmp_iter_add_to_tag_list (GstTagList * taglist,
|
* metadatamux_xmp_get_tagsmap_from_gsttag:
|
||||||
GstTagMergeMode mode, const char *path, const char *value,
|
* @schema_map: Structure containg a map beteween GST tags and tags into a XMP
|
||||||
const SchemaMap * schema_map, const uint32_t opt)
|
* 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;
|
||||||
|
|
||||||
const SchemaTagMap *smaptag =
|
if (NULL == schema_map)
|
||||||
metadataparse_get_tagsmap_from_path (schema_map, path, opt);
|
|
||||||
|
|
||||||
if (NULL == smaptag)
|
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (NULL == smaptag->gst_tag)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
GType type = gst_tag_get_type (smaptag->gst_tag);
|
for (i = 0; schema_map->tags_map[i].gst_tag; i++) {
|
||||||
|
if (0 == strcmp (schema_map->tags_map[i].gst_tag, tag)) {
|
||||||
switch (type) {
|
tags_map = (SchemaTagMap *) & schema_map->tags_map[i];
|
||||||
case G_TYPE_STRING:
|
|
||||||
gst_tag_list_add (taglist, mode, smaptag->gst_tag, value, NULL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
return;
|
return tags_map;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/*
|
||||||
metadataparse_xmp_iter_simple_qual (GstTagList * taglist, GstTagMergeMode mode,
|
* metadataparse_xmp_iter:
|
||||||
const char *schema, const char *path, const char *value,
|
* @taglist: tag list in which extracted tags will be added
|
||||||
const SchemaMap * schema_map)
|
* @mode: tag list merge mode
|
||||||
{
|
* @xmp: handle to XMP data from lib exempi
|
||||||
GString *string = g_string_new (path);
|
*
|
||||||
gchar *ch;
|
* 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
|
||||||
/* remove the language qualifier */
|
* to add all XMP mapped tags to @taglist by unsing a specified merge @mode
|
||||||
ch = string->str + string->len - 3;
|
* @see_also: #metadataparse_xmp_tag_list_add
|
||||||
while (ch != string->str + schema_map->prefix_len) {
|
* #metadataparse_xmp_iter_node_schema
|
||||||
if (*ch == '[') {
|
*
|
||||||
*ch = '\0';
|
* Returns: nothing
|
||||||
}
|
*/
|
||||||
--ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_LOG (" %s = %s", string->str, value);
|
|
||||||
|
|
||||||
metadataparse_xmp_iter_add_to_tag_list (taglist, mode, path, value,
|
|
||||||
schema_map, XMP_PROP_HAS_QUALIFIERS);
|
|
||||||
|
|
||||||
g_string_free (string, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
metadataparse_xmp_iter_simple (GstTagList * taglist, GstTagMergeMode mode,
|
|
||||||
const char *schema, 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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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, schema, path,
|
|
||||||
value, schema_map);
|
|
||||||
} else {
|
|
||||||
metadataparse_xmp_iter_simple (taglist, mode, schema, 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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
metadataparse_xmp_iter_node_schema (GstTagList * taglist, GstTagMergeMode mode,
|
|
||||||
XmpPtr xmp, const char *schema, const char *path)
|
|
||||||
{
|
|
||||||
SchemaMap *schema_map = NULL;
|
|
||||||
|
|
||||||
if (0 == strcmp (schema, "http://purl.org/dc/elements/1.1/")) {
|
|
||||||
schema_map = (SchemaMap *) & schema_map_dublin;
|
|
||||||
}
|
|
||||||
|
|
||||||
metadataparse_xmp_iter_array (taglist, mode, xmp, schema, path, schema_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
metadataparse_xmp_iter (GstTagList * taglist, GstTagMergeMode mode, XmpPtr xmp)
|
metadataparse_xmp_iter (GstTagList * taglist, GstTagMergeMode mode, XmpPtr xmp)
|
||||||
|
@ -462,10 +536,263 @@ done:
|
||||||
xmp_string_free (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)
|
||||||
|
{
|
||||||
|
SchemaMap *schema_map = NULL;
|
||||||
|
|
||||||
|
if (0 == strcmp (schema, "http://purl.org/dc/elements/1.1/")) {
|
||||||
|
schema_map = (SchemaMap *) & schema_map_dublin;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
metadataxmp_for_each_tag_in_list (const GstTagList * list, const gchar * tag,
|
metadataparse_xmp_iter_add_to_tag_list (GstTagList * taglist,
|
||||||
gpointer user_data)
|
GstTagMergeMode mode, const char *path, const char *value,
|
||||||
|
const SchemaMap * schema_map, const uint32_t opt)
|
||||||
|
{
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
GType 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;
|
XmpPtr xmp = (XmpPtr) user_data;
|
||||||
int i;
|
int i;
|
||||||
|
@ -474,7 +801,7 @@ metadataxmp_for_each_tag_in_list (const GstTagList * list, const gchar * tag,
|
||||||
|
|
||||||
const SchemaMap *smap = schemas_map[i];
|
const SchemaMap *smap = schemas_map[i];
|
||||||
const SchemaTagMap *stagmap =
|
const SchemaTagMap *stagmap =
|
||||||
metadataparse_get_tagsmap_from_gsttag (smap, tag);
|
metadatamux_xmp_get_tagsmap_from_gsttag (smap, tag);
|
||||||
|
|
||||||
if (stagmap) {
|
if (stagmap) {
|
||||||
|
|
||||||
|
@ -501,56 +828,4 @@ metadataxmp_for_each_tag_in_list (const GstTagList * list, const gchar * tag,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
if (*buf) {
|
|
||||||
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 (GST_BUFFER_DATA (xmp_chunk), GST_BUFFER_SIZE (xmp_chunk));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NULL == xmp)
|
|
||||||
xmp = xmp_new_empty ();
|
|
||||||
|
|
||||||
gst_tag_list_foreach (taglist, metadataxmp_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) {
|
|
||||||
unsigned int len = strlen (xmp_string_cstr (xmp_str_buf));
|
|
||||||
|
|
||||||
*size = len + 1;
|
|
||||||
*buf = malloc (*size);
|
|
||||||
memcpy (*buf, xmp_string_cstr (xmp_str_buf), *size);
|
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* else (ifndef HAVE_XMP) */
|
#endif /* else (ifndef HAVE_XMP) */
|
||||||
|
|
|
@ -50,14 +50,18 @@
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* external function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern gboolean metadata_xmp_init (void);
|
||||||
|
|
||||||
|
extern void metadata_xmp_dispose (void);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode,
|
||||||
GstAdapter * adapter, MetadataTagMapping mapping);
|
GstAdapter * adapter, MetadataTagMapping mapping);
|
||||||
|
|
||||||
extern gboolean metadataparse_xmp_init (void);
|
|
||||||
|
|
||||||
extern void metadataparse_xmp_dispose (void);
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadatamux_xmp_create_chunk_from_tag_list (guint8 ** buf, guint32 *size,
|
metadatamux_xmp_create_chunk_from_tag_list (guint8 ** buf, guint32 *size,
|
||||||
const GstTagList * taglist);
|
const GstTagList * taglist);
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
|
|
||||||
CC=gcc
|
|
||||||
CFLAGS=-c -Wall -g3 -O0 `pkg-config --cflags gstreamer-0.10 libglade-2.0 gtk+-2.0`
|
|
||||||
CLIBS=-lgstinterfaces-0.10 -Wl -export-dynamic `pkg-config --libs gstreamer-0.10 libglade-2.0 gtk+-2.0`
|
|
||||||
|
|
||||||
all: metadata_editor
|
|
||||||
|
|
||||||
metadata_editor: metadata_editor.o
|
|
||||||
$(CC) $(CLIBS) metadata_editor.o -o metadata_editor
|
|
||||||
|
|
||||||
metadata_editor.o: metadata_editor.c
|
|
||||||
$(CC) $(CFLAGS) metadata_editor.c
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf *.o metadata_editor
|
|
||||||
|
|
|
@ -11,9 +11,27 @@ else
|
||||||
GST_SOUNDTOUCH_TESTS =
|
GST_SOUNDTOUCH_TESTS =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if USE_METADATA
|
||||||
|
|
||||||
|
GST_METADATA_TESTS = metadata_editor
|
||||||
|
|
||||||
|
metadata_editor_SOURCES = metadata_editor.c
|
||||||
|
metadata_editor_CFLAGS = $(GST_CFLAGS) \
|
||||||
|
`pkg-config --cflags gstreamer-0.10 libglade-2.0 gtk+-2.0`
|
||||||
|
metadata_editor_LDADD = $(GST_LIBS)
|
||||||
|
metadata_editor_LDFLAGS = $(GST_PLUGIN_LDFLAGS) \
|
||||||
|
-Wl -export-dynamic \
|
||||||
|
-lgstinterfaces-0.10 \
|
||||||
|
`pkg-config --libs gstreamer-0.10 libglade-2.0 gtk+-2.0`
|
||||||
|
|
||||||
|
else
|
||||||
|
GST_METADATA_TESTS =
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
equalizer_test_SOURCES = equalizer-test.c
|
equalizer_test_SOURCES = equalizer-test.c
|
||||||
equalizer_test_CFLAGS = $(GST_CFLAGS)
|
equalizer_test_CFLAGS = $(GST_CFLAGS)
|
||||||
equalizer_test_LDADD = $(GST_LIBS)
|
equalizer_test_LDADD = $(GST_LIBS)
|
||||||
equalizer_test_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
equalizer_test_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
|
|
||||||
noinst_PROGRAMS = $(GST_SOUNDTOUCH_TESTS) equalizer-test
|
noinst_PROGRAMS = $(GST_SOUNDTOUCH_TESTS) $(GST_METADATA_TESTS) equalizer-test
|
||||||
|
|
|
@ -523,7 +523,7 @@ ui_create ()
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ui_glade_xml = glade_xml_new ("MetadataEditorMain.glade", NULL, NULL);
|
ui_glade_xml = glade_xml_new ("metadata_editor.glade", NULL, NULL);
|
||||||
|
|
||||||
if (!ui_glade_xml) {
|
if (!ui_glade_xml) {
|
||||||
fprintf (stderr, "glade_xml_new failed\n");
|
fprintf (stderr, "glade_xml_new failed\n");
|
Loading…
Reference in a new issue