mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
Add documentation. Fix test app compilation. Fix pull mode.
Original commit message from CVS: Add documentation. Fix test app compilation. Fix pull mode.
This commit is contained in:
parent
7460bb6d91
commit
1159638102
12 changed files with 796 additions and 290 deletions
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
|||
2008-01-30 Edgard Lima <edgard.lima@indt.org.br>
|
||||
|
||||
* ext/Makefile.am:
|
||||
* ext/metadata/TODO:
|
||||
* ext/metadata/gstbasemetadata.c:
|
||||
* ext/metadata/gstbasemetadata.h:
|
||||
* ext/metadata/metadatamuxjpeg.c:
|
||||
* ext/metadata/metadatamuxjpeg.h:
|
||||
* ext/metadata/metadatamuxpng.c:
|
||||
* ext/metadata/metadatamuxpng.h:
|
||||
* ext/metadata/metadataparsejpeg.c:
|
||||
* ext/metadata/metadataparsepng.c:
|
||||
* tests/icles/Makefile.am:
|
||||
Add documentation. Fix test app compilation. Fix pull mode.
|
||||
|
||||
2008-01-29 Wim Taymans <wim.taymans@collabora.co.uk>
|
||||
|
||||
Patch by: Thijs Vermeir <thijsvermeir at gmail dot com>
|
||||
|
|
|
@ -76,12 +76,6 @@ else
|
|||
DTS_DIR=
|
||||
endif
|
||||
|
||||
if USE_METADATA
|
||||
METADATA_DIR=metadata
|
||||
else
|
||||
METADATA_DIR=
|
||||
endif
|
||||
|
||||
if USE_FAAC
|
||||
FAAC_DIR=faac
|
||||
else
|
||||
|
@ -160,6 +154,12 @@ else
|
|||
MPEG2ENC_DIR=
|
||||
endif
|
||||
|
||||
if USE_METADATA
|
||||
METADATA_DIR=metadata
|
||||
else
|
||||
METADATA_DIR=
|
||||
endif
|
||||
|
||||
# if USE_MPLEX
|
||||
# MPLEX_DIR=mplex
|
||||
# else
|
||||
|
@ -313,6 +313,7 @@ SUBDIRS=\
|
|||
$(LIBFAME_DIR) \
|
||||
$(LIBMMS_DIR) \
|
||||
$(MPEG2ENC_DIR) \
|
||||
$(METADATA_DIR) \
|
||||
$(MPLEX_DIR) \
|
||||
$(MUSEPACK_DIR) \
|
||||
$(MUSICBRAINZ_DIR) \
|
||||
|
@ -342,7 +343,6 @@ DIST_SUBDIRS = \
|
|||
cdaudio \
|
||||
dc1394 \
|
||||
directfb \
|
||||
metadata \
|
||||
faac \
|
||||
faad \
|
||||
gio \
|
||||
|
@ -353,6 +353,7 @@ DIST_SUBDIRS = \
|
|||
libmms \
|
||||
dts \
|
||||
divx \
|
||||
metadata \
|
||||
mpeg2enc \
|
||||
musepack \
|
||||
musicbrainz \
|
||||
|
|
|
@ -26,12 +26,4 @@ OPEN ISSUES:
|
|||
|
||||
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
|
||||
|
||||
|
|
|
@ -159,7 +159,8 @@ gst_base_metadata_parse (GstBaseMetadata * filter, const guint8 * buf,
|
|||
|
||||
static gboolean
|
||||
gst_base_metadata_strip_push_buffer (GstBaseMetadata * base,
|
||||
gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf);
|
||||
const gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf,
|
||||
gboolean inject_begin);
|
||||
|
||||
static int
|
||||
gst_base_metadata_buf_get_intersection_seg (const gint64 offset, guint32 size,
|
||||
|
@ -168,7 +169,7 @@ gst_base_metadata_buf_get_intersection_seg (const gint64 offset, guint32 size,
|
|||
|
||||
static gboolean
|
||||
gst_base_metadata_translate_pos_to_orig (GstBaseMetadata * base,
|
||||
gint64 pos, gint64 * orig_pos, GstBuffer ** buf);
|
||||
gint64 pos, gint64 * orig_pos, GstBuffer ** buf, guint32 max_size);
|
||||
|
||||
static gboolean gst_base_metadata_calculate_offsets (GstBaseMetadata * base);
|
||||
|
||||
|
@ -639,6 +640,7 @@ done:
|
|||
* beginning og @buf
|
||||
* @buf: a pointer to a buffer that will be modified (data striped/injected or
|
||||
* prepended)
|
||||
* @inject_begin: is TRUE can inject a chunk start exactly in @offset_orig
|
||||
*
|
||||
* Strip bytes from @buf that are part of some chunk that will be striped. Add
|
||||
* a whole injected chunk if some inject chunk starts into the buffer. Prepend
|
||||
|
@ -658,7 +660,8 @@ done:
|
|||
|
||||
static gboolean
|
||||
gst_base_metadata_strip_push_buffer (GstBaseMetadata * base,
|
||||
gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf)
|
||||
const gint64 offset_orig, GstBuffer ** prepend, GstBuffer ** buf,
|
||||
gboolean inject_begin)
|
||||
{
|
||||
MetadataChunk *strip = META_DATA_STRIP_CHUNKS (base->metadata).chunk;
|
||||
MetadataChunk *inject = META_DATA_INJECT_CHUNKS (base->metadata).chunk;
|
||||
|
@ -692,11 +695,13 @@ gst_base_metadata_strip_push_buffer (GstBaseMetadata * base,
|
|||
int res;
|
||||
|
||||
if (inject[i].offset_orig >= offset_orig) {
|
||||
if (inject[i].offset_orig < offset_orig + size_buf_in) {
|
||||
injected_bytes += inject[i].size;
|
||||
} else {
|
||||
/* segment is after size (segments are sorted) */
|
||||
break;
|
||||
if (G_LIKELY (inject_begin || inject[i].offset_orig > offset_orig)) {
|
||||
if (inject[i].offset_orig < offset_orig + size_buf_in) {
|
||||
injected_bytes += inject[i].size;
|
||||
} else {
|
||||
/* segment is after size (segments are sorted) */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -846,20 +851,22 @@ inject:
|
|||
original buffer */
|
||||
|
||||
if (inject[i].offset_orig >= offset_orig) {
|
||||
if (inject[i].offset_orig <
|
||||
offset_orig + size_buf_in + striped_bytes - injected_bytes) {
|
||||
/* insert */
|
||||
guint32 buf_off =
|
||||
inject[i].offset_orig - offset_orig - striped_so_far +
|
||||
injected_bytes;
|
||||
memmove (data + buf_off + inject[i].size, data + buf_off,
|
||||
size_buf_in - buf_off);
|
||||
memcpy (data + buf_off, inject[i].data, inject[i].size);
|
||||
injected_bytes += inject[i].size;
|
||||
size_buf_in += inject[i].size;
|
||||
} else {
|
||||
/* segment is after size (segments are sorted) */
|
||||
break;
|
||||
if (G_LIKELY (inject_begin || inject[i].offset_orig > offset_orig)) {
|
||||
if (inject[i].offset_orig <
|
||||
offset_orig + size_buf_in + striped_bytes - injected_bytes) {
|
||||
/* insert */
|
||||
guint32 buf_off =
|
||||
inject[i].offset_orig - offset_orig - striped_so_far +
|
||||
injected_bytes;
|
||||
memmove (data + buf_off + inject[i].size, data + buf_off,
|
||||
size_buf_in - buf_off);
|
||||
memcpy (data + buf_off, inject[i].data, inject[i].size);
|
||||
injected_bytes += inject[i].size;
|
||||
size_buf_in += inject[i].size;
|
||||
} else {
|
||||
/* segment is after size (segments are sorted) */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -988,6 +995,7 @@ done:
|
|||
* @orig_pos: position in original stream
|
||||
* @buf: if not NULL, will have data that starts at some point into a injected
|
||||
* chunk
|
||||
* @max_size: the maximum size to allocate to @buf. pass 0 if don't care
|
||||
*
|
||||
* Given a position in output stream (@pos), returns the position in original
|
||||
* stream (@orig_pos) that contains the same data. If @pos is into a injected
|
||||
|
@ -1006,7 +1014,7 @@ done:
|
|||
|
||||
static gboolean
|
||||
gst_base_metadata_translate_pos_to_orig (GstBaseMetadata * base,
|
||||
gint64 pos, gint64 * orig_pos, GstBuffer ** buf)
|
||||
gint64 pos, gint64 * orig_pos, GstBuffer ** buf, guint32 max_size)
|
||||
{
|
||||
MetadataChunk *strip = META_DATA_STRIP_CHUNKS (base->metadata).chunk;
|
||||
MetadataChunk *inject = META_DATA_INJECT_CHUNKS (base->metadata).chunk;
|
||||
|
@ -1014,9 +1022,11 @@ gst_base_metadata_translate_pos_to_orig (GstBaseMetadata * base,
|
|||
const gsize inject_len = META_DATA_INJECT_CHUNKS (base->metadata).len;
|
||||
const gint64 duration_orig = base->duration_orig;
|
||||
const gint64 duration = base->duration;
|
||||
gboolean ret = TRUE;
|
||||
const gint64 saved_pos = pos;
|
||||
|
||||
int i;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
guint64 new_buf_size = 0;
|
||||
guint64 injected_before = 0;
|
||||
|
||||
|
@ -1032,56 +1042,67 @@ gst_base_metadata_translate_pos_to_orig (GstBaseMetadata * base,
|
|||
/* calculate for injected */
|
||||
|
||||
/* just calculate size */
|
||||
*orig_pos = pos; /* save pos */
|
||||
for (i = 0; i < inject_len; ++i) {
|
||||
/* check if pos in inside chunk */
|
||||
if (inject[i].offset <= pos) {
|
||||
if (pos >= inject[i].offset) {
|
||||
if (pos < inject[i].offset + inject[i].size) {
|
||||
/* orig pos points after insert chunk */
|
||||
new_buf_size += inject[i].size;
|
||||
/* put pos after current chunk */
|
||||
pos = inject[i].offset + inject[i].size;
|
||||
/* pos is inside the chunk */
|
||||
const guint32 offset_in_chunk = pos - inject[i].offset;
|
||||
|
||||
ret = FALSE;
|
||||
pos = inject[i].offset + inject[i].size; /* put pos just after chunk */
|
||||
new_buf_size += inject[i].size - offset_in_chunk;
|
||||
/* we still continue, 'cause the next chunk could be just after this */
|
||||
} else {
|
||||
/* in case pos is not inside a injected chunk */
|
||||
injected_before += inject[i].size;
|
||||
}
|
||||
} else {
|
||||
/* pos is before the chunk */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* alloc buffer and calcute original pos */
|
||||
if (buf && ret == FALSE) {
|
||||
guint8 *data;
|
||||
if (ret == FALSE) {
|
||||
|
||||
if (*buf)
|
||||
gst_buffer_unref (*buf);
|
||||
*buf = gst_buffer_new_and_alloc (new_buf_size);
|
||||
data = GST_BUFFER_DATA (*buf);
|
||||
pos = *orig_pos; /* recover saved pos */
|
||||
for (i = 0; i < inject_len; ++i) {
|
||||
if (inject[i].offset > pos) {
|
||||
break;
|
||||
}
|
||||
if (inject[i].offset <= pos && pos < inject[i].offset + inject[i].size) {
|
||||
memcpy (data, inject[i].data, inject[i].size);
|
||||
data += inject[i].size;
|
||||
pos = inject[i].offset + inject[i].size;
|
||||
/* out position after insert chunk orig */
|
||||
*orig_pos = inject[i].offset_orig + inject[i].size;
|
||||
*orig_pos = pos;
|
||||
|
||||
if (buf) {
|
||||
guint8 *data;
|
||||
|
||||
if (max_size > 0)
|
||||
if (new_buf_size > max_size)
|
||||
new_buf_size = max_size;
|
||||
|
||||
if (*buf)
|
||||
gst_buffer_unref (*buf);
|
||||
*buf = gst_buffer_new_and_alloc (new_buf_size);
|
||||
data = GST_BUFFER_DATA (*buf);
|
||||
pos = saved_pos;
|
||||
for (i = 0; i < inject_len && new_buf_size > 0; ++i) {
|
||||
if (inject[i].offset > pos) {
|
||||
break;
|
||||
}
|
||||
if (pos < inject[i].offset + inject[i].size) {
|
||||
const guint32 offset = pos - inject[i].offset;
|
||||
guint32 size = inject[i].size - offset;
|
||||
|
||||
if (size > new_buf_size)
|
||||
size = new_buf_size;
|
||||
memcpy (data, inject[i].data + offset, size);
|
||||
data += size;
|
||||
pos = inject[i].offset + inject[i].size;
|
||||
new_buf_size -= size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == FALSE) {
|
||||
/* if it inside a injected is already done */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* calculate for striped */
|
||||
|
||||
*orig_pos = pos - injected_before;
|
||||
*orig_pos = saved_pos - injected_before;
|
||||
for (i = 0; i < strip_len; ++i) {
|
||||
if (strip[i].offset_orig > pos) {
|
||||
break;
|
||||
|
@ -1479,7 +1500,7 @@ gst_base_metadata_src_event (GstPad * pad, GstEvent * event)
|
|||
striped/injected buffer in next 'chain' calling */
|
||||
filter->offset = start;
|
||||
gst_base_metadata_translate_pos_to_orig (filter, start, &start,
|
||||
&filter->prepend_buffer);
|
||||
&filter->prepend_buffer, 0);
|
||||
filter->offset_orig = start;
|
||||
|
||||
if (stop_type == GST_SEEK_TYPE_CUR)
|
||||
|
@ -1491,7 +1512,7 @@ gst_base_metadata_src_event (GstPad * pad, GstEvent * event)
|
|||
}
|
||||
stop_type == GST_SEEK_TYPE_SET;
|
||||
|
||||
gst_base_metadata_translate_pos_to_orig (filter, stop, &stop, NULL);
|
||||
gst_base_metadata_translate_pos_to_orig (filter, stop, &stop, NULL, 0);
|
||||
|
||||
gst_event_unref (event);
|
||||
event = gst_event_new_seek (rate, format, flags,
|
||||
|
@ -1569,6 +1590,7 @@ gst_base_metadata_get_range (GstPad * pad,
|
|||
guint size_orig;
|
||||
GstBuffer *prepend = NULL;
|
||||
gboolean need_append = FALSE;
|
||||
gboolean into_inject;
|
||||
|
||||
filter = GST_BASE_METADATA (GST_PAD_PARENT (pad));
|
||||
|
||||
|
@ -1583,34 +1605,45 @@ gst_base_metadata_get_range (GstPad * pad,
|
|||
|
||||
size_orig = size;
|
||||
|
||||
gst_base_metadata_translate_pos_to_orig (filter, offset,
|
||||
&offset_orig, &prepend);
|
||||
into_inject = !gst_base_metadata_translate_pos_to_orig (filter, offset,
|
||||
&offset_orig, &prepend, size);
|
||||
|
||||
if (size > 1) {
|
||||
if (into_inject) {
|
||||
size_orig = GST_BUFFER_SIZE (prepend) < size_orig ?
|
||||
size_orig - GST_BUFFER_SIZE (prepend) : 0;
|
||||
}
|
||||
|
||||
if (size_orig == 0) {
|
||||
/* enough data in prepend */
|
||||
*buf = prepend;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (size_orig > 1) {
|
||||
gint64 pos;
|
||||
|
||||
pos = offset + size - 1;
|
||||
gst_base_metadata_translate_pos_to_orig (filter, pos, &pos, NULL);
|
||||
into_inject = gst_base_metadata_translate_pos_to_orig (filter, pos, &pos,
|
||||
NULL, 0);
|
||||
size_orig = pos + 1 - offset_orig;
|
||||
}
|
||||
|
||||
if (size_orig) {
|
||||
ret = gst_pad_pull_range (filter->sinkpad, offset_orig, size_orig, buf);
|
||||
|
||||
ret = gst_pad_pull_range (filter->sinkpad, offset_orig, size_orig, buf);
|
||||
|
||||
if (ret == GST_FLOW_OK && *buf) {
|
||||
gst_base_metadata_strip_push_buffer (filter, offset_orig, &prepend, buf);
|
||||
|
||||
if (GST_BUFFER_SIZE (*buf) < size) {
|
||||
/* need append */
|
||||
need_append = TRUE;
|
||||
}
|
||||
if (ret == GST_FLOW_OK && *buf) {
|
||||
gst_base_metadata_strip_push_buffer (filter, offset_orig, &prepend, buf,
|
||||
FALSE);
|
||||
|
||||
if (GST_BUFFER_SIZE (*buf) < size) {
|
||||
/* need append */
|
||||
need_append = TRUE;
|
||||
} else {
|
||||
/* hide extra bytes */
|
||||
GST_BUFFER_SIZE (*buf) = size;
|
||||
}
|
||||
} else {
|
||||
*buf = prepend;
|
||||
}
|
||||
|
||||
|
||||
done:
|
||||
|
||||
if (need_append) {
|
||||
|
@ -1715,7 +1748,7 @@ gst_base_metadata_chain (GstPad * pad, GstBuffer * buf)
|
|||
buf_size = GST_BUFFER_SIZE (buf);
|
||||
|
||||
gst_base_metadata_strip_push_buffer (filter, filter->offset_orig,
|
||||
&filter->prepend_buffer, &buf);
|
||||
&filter->prepend_buffer, &buf, TRUE);
|
||||
|
||||
if (buf) { /* may be all buffer has been striped */
|
||||
gst_buffer_set_caps (buf, GST_PAD_CAPS (filter->srcpad));
|
||||
|
@ -1848,6 +1881,7 @@ gst_base_metadata_src_query (GstPad * pad, GstQuery * query)
|
|||
gst_query_set_position (query, GST_FORMAT_BYTES, filter->offset);
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
break;
|
||||
case GST_QUERY_DURATION:
|
||||
|
||||
|
@ -1864,6 +1898,7 @@ gst_base_metadata_src_query (GstPad * pad, GstQuery * query)
|
|||
ret = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case GST_QUERY_FORMATS:
|
||||
gst_query_set_formats (query, 1, GST_FORMAT_BYTES);
|
||||
|
|
|
@ -73,27 +73,57 @@ typedef enum _tag_BaseMetadataType {
|
|||
} BaseMetadataType;
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* GST_BASE_METADATA_SRC_PAD:
|
||||
* @obj: base metadata instance
|
||||
*
|
||||
* Gives the pointer to the #GstPad object of the element.
|
||||
*/
|
||||
#define GST_BASE_METADATA_SRC_PAD(obj) (GST_BASE_METADATA_CAST (obj)->srcpad)
|
||||
#define GST_BASE_METADATA_SRC_PAD(obj) (GST_BASE_METADATA_CAST (obj)->srcpad)
|
||||
|
||||
/**
|
||||
/*
|
||||
* GST_BASE_METADATA_SINK_PAD:
|
||||
* @obj: base metadata instance
|
||||
*
|
||||
* Gives the pointer to the #GstPad object of the element.
|
||||
*/
|
||||
#define GST_BASE_METADATA_SINK_PAD(obj) (GST_BASE_METADATA_CAST (obj)->sinkpad)
|
||||
#define GST_BASE_METADATA_SINK_PAD(obj) (GST_BASE_METADATA_CAST (obj)->sinkpad)
|
||||
|
||||
#define GST_BASE_METADATA_EXIF_ADAPTER(obj) (GST_BASE_METADATA_CAST (obj)->metadata->exif_adapter)
|
||||
#define GST_BASE_METADATA_IPTC_ADAPTER(obj) (GST_BASE_METADATA_CAST (obj)->metadata->iptc_adapter)
|
||||
#define GST_BASE_METADATA_XMP_ADAPTER(obj) (GST_BASE_METADATA_CAST (obj)->metadata->xmp_adapter)
|
||||
/*
|
||||
* GST_BASE_METADATA_EXIF_ADAPTER
|
||||
* @obj: base metadata instance
|
||||
*
|
||||
* Gives the pointer to the EXIF #GstAdapter of the element.
|
||||
*/
|
||||
#define GST_BASE_METADATA_EXIF_ADAPTER(obj) \
|
||||
(GST_BASE_METADATA_CAST (obj)->metadata->exif_adapter)
|
||||
|
||||
#define GST_BASE_METADATA_IMG_TYPE(obj) (GST_BASE_METADATA_CAST (obj)->img_type)
|
||||
/*
|
||||
* GST_BASE_METADATA_IPTC_ADAPTER
|
||||
* @obj: base metadata instance
|
||||
*
|
||||
* Gives the pointer to the IPTC #GstAdapter of the element.
|
||||
*/
|
||||
#define GST_BASE_METADATA_IPTC_ADAPTER(obj) \
|
||||
(GST_BASE_METADATA_CAST (obj)->metadata->iptc_adapter)
|
||||
|
||||
/*
|
||||
* GST_BASE_METADATA_XMP_ADAPTER
|
||||
* @obj: base metadata instance
|
||||
*
|
||||
* Gives the pointer to the XMP #GstAdapter of the element.
|
||||
*/
|
||||
#define GST_BASE_METADATA_XMP_ADAPTER(obj) \
|
||||
(GST_BASE_METADATA_CAST (obj)->metadata->xmp_adapter)
|
||||
|
||||
/*
|
||||
* GST_BASE_METADATA_IMG_TYPE
|
||||
* @obj: base metadata instance
|
||||
*
|
||||
* Gives the type indentified by the parser of the element.
|
||||
*/
|
||||
#define GST_BASE_METADATA_IMG_TYPE(obj) \
|
||||
(GST_BASE_METADATA_CAST (obj)->img_type)
|
||||
|
||||
|
||||
typedef enum _tag_MetadataState
|
||||
|
@ -127,7 +157,7 @@ struct _GstBaseMetadata
|
|||
|
||||
MetaOptions options;
|
||||
|
||||
gboolean need_processing; /* still need some action before send first buffer */
|
||||
gboolean need_processing; /* still need a action before send first buffer */
|
||||
|
||||
GstAdapter *adapter_parsing;
|
||||
GstAdapter *adapter_holding;
|
||||
|
@ -161,10 +191,12 @@ extern GType
|
|||
gst_base_metadata_get_type (void);
|
||||
|
||||
extern void
|
||||
gst_base_metadata_set_option_flag(GstBaseMetadata *base, const MetaOptions options);
|
||||
gst_base_metadata_set_option_flag(GstBaseMetadata *base,
|
||||
const MetaOptions options);
|
||||
|
||||
extern void
|
||||
gst_base_metadata_unset_option_flag(GstBaseMetadata *base, const MetaOptions options);
|
||||
gst_base_metadata_unset_option_flag(GstBaseMetadata *base,
|
||||
const MetaOptions options);
|
||||
|
||||
extern MetaOptions
|
||||
gst_base_metadata_get_option_flag(const GstBaseMetadata *base);
|
||||
|
|
|
@ -41,6 +41,41 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SECTION: metadatamuxjpeg
|
||||
* @short_description: This module provides functions to parse JPEG files in
|
||||
* order to write metadata to it.
|
||||
*
|
||||
* This module parses a JPEG stream to find the places in which metadata (EXIF,
|
||||
* IPTC, XMP) chunks would be written. It also wraps metadata chunks with JPEG
|
||||
* marks according to the specification.
|
||||
*
|
||||
* <refsect2>
|
||||
* <para>
|
||||
* #metadatamux_jpeg_init must be called before any other function in this
|
||||
* module and must be paired with a call to #metadatamux_jpeg_dispose.
|
||||
* #metadatamux_jpeg_parse is used to parse the stream (find the place
|
||||
* metadata chunks should be written to).
|
||||
* #metadatamux_jpeg_lazy_update do nothing.
|
||||
* </para>
|
||||
* <para>
|
||||
* EXIF chunks will always be the first chunk (replaces JFIF). IPTC and XMP
|
||||
* chunks will be placed or second chunk (after JFIF or EXIF) or third chunk
|
||||
* if both (IPTC and XMP) are written to the file.
|
||||
* </para>
|
||||
* <para>
|
||||
* When a EXIF chunk is written to the JPEG stream, if there is a JFIF chunk
|
||||
* as the first chunk, it will be stripped out.
|
||||
* </para>
|
||||
* </refsect2>
|
||||
*
|
||||
* Last reviewed on 2008-01-24 (0.10.15)
|
||||
*/
|
||||
|
||||
/*
|
||||
* includes
|
||||
*/
|
||||
|
||||
#include "metadatamuxjpeg.h"
|
||||
|
||||
#include <string.h>
|
||||
|
@ -49,109 +84,51 @@
|
|||
#include <libiptcdata/iptc-jpeg.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* defines and macros
|
||||
*/
|
||||
|
||||
#define READ(buf, size) ( (size)--, *((buf)++) )
|
||||
|
||||
/*
|
||||
* static helper functions declaration
|
||||
*/
|
||||
|
||||
static MetadataParsingReturn
|
||||
metadatamux_jpeg_reading (JpegMuxData * jpeg_data, guint8 ** buf,
|
||||
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
||||
guint8 ** next_start, guint32 * next_size);
|
||||
|
||||
#define READ(buf, size) ( (size)--, *((buf)++) )
|
||||
|
||||
static void
|
||||
metadatamux_wrap_chunk (MetadataChunk * chunk, const guint8 * buf,
|
||||
guint32 buf_size, guint8 a, guint8 b)
|
||||
{
|
||||
guint8 *data = g_new (guint8, 4 + buf_size + chunk->size);
|
||||
|
||||
memcpy (data + 4 + buf_size, chunk->data, chunk->size);
|
||||
g_free (chunk->data);
|
||||
chunk->data = data;
|
||||
chunk->size += 4 + buf_size;
|
||||
data[0] = a;
|
||||
data[1] = b;
|
||||
data[2] = ((chunk->size - 2) >> 8) & 0xFF;
|
||||
data[3] = (chunk->size - 2) & 0xFF;
|
||||
if (buf && buf_size) {
|
||||
memcpy (data + 4, buf, buf_size);
|
||||
}
|
||||
}
|
||||
guint32 buf_size, guint8 a, guint8 b);
|
||||
|
||||
#ifdef HAVE_IPTC
|
||||
static gboolean
|
||||
metadatamux_wrap_iptc_with_ps3 (unsigned char **buf, unsigned int *buf_size)
|
||||
{
|
||||
unsigned int out_size = *buf_size + 4096;
|
||||
unsigned char *outbuf = g_new (unsigned char, out_size);
|
||||
int size_written;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
size_written =
|
||||
iptc_jpeg_ps3_save_iptc (NULL, 0, *buf, *buf_size, outbuf, out_size);
|
||||
|
||||
g_free (*buf);
|
||||
*buf = NULL;
|
||||
*buf_size = 0;
|
||||
|
||||
if (size_written < 0) {
|
||||
g_free (outbuf);
|
||||
ret = FALSE;
|
||||
} else {
|
||||
*buf_size = size_written;
|
||||
*buf = outbuf;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
metadatamux_wrap_iptc_with_ps3 (unsigned char **buf, unsigned int *buf_size);
|
||||
#endif /* #ifdef HAVE_IPTC */
|
||||
|
||||
void
|
||||
metadatamux_jpeg_lazy_update (JpegMuxData * jpeg_data)
|
||||
{
|
||||
gsize i;
|
||||
gboolean has_exif = FALSE;
|
||||
|
||||
for (i = 0; i < jpeg_data->inject_chunks->len; ++i) {
|
||||
if (jpeg_data->inject_chunks->chunk[i].size > 0 &&
|
||||
jpeg_data->inject_chunks->chunk[i].data) {
|
||||
switch (jpeg_data->inject_chunks->chunk[i].type) {
|
||||
case MD_CHUNK_EXIF:
|
||||
metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i], NULL, 0,
|
||||
0xFF, 0xE1);
|
||||
has_exif = TRUE;
|
||||
break;
|
||||
case MD_CHUNK_IPTC:
|
||||
#ifdef HAVE_IPTC
|
||||
{
|
||||
if (metadatamux_wrap_iptc_with_ps3 (&jpeg_data->inject_chunks->
|
||||
chunk[i].data, &jpeg_data->inject_chunks->chunk[i].size)) {
|
||||
metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i], NULL,
|
||||
0, 0xFF, 0xED);
|
||||
} else {
|
||||
GST_ERROR ("Invalid IPTC chunk\n");
|
||||
/* FIXME: remove entry from list */
|
||||
}
|
||||
}
|
||||
#endif /* #ifdef HAVE_IPTC */
|
||||
break;
|
||||
case MD_CHUNK_XMP:
|
||||
{
|
||||
static const char XmpHeader[] = "http://ns.adobe.com/xap/1.0/";
|
||||
/*
|
||||
* extern functions implementations
|
||||
*/
|
||||
|
||||
metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i],
|
||||
XmpHeader, sizeof (XmpHeader), 0xFF, 0xE1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!has_exif) {
|
||||
/* EXIF not injected so not strip JFIF anymore */
|
||||
metadata_chunk_array_clear (jpeg_data->strip_chunks);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* metadatamux_jpeg_init:
|
||||
* @jpeg_data: [in] jpeg data handler to be inited
|
||||
* @strip_chunks: Array of chunks (offset and size) marked for removal
|
||||
* @inject_chunks: Array of chunks (offset, data, size) marked for injection
|
||||
* adapter (@exif_adpt, @iptc_adpt, @xmp_adpt). Or FALSE if should also put
|
||||
* them on @strip_chunks.
|
||||
*
|
||||
* Init jpeg data handle.
|
||||
* This function must be called before any other function from this module.
|
||||
* This function must not be called twice without call to
|
||||
* #metadatamux_jpeg_dispose beteween them.
|
||||
* @see_also: #metadatamux_jpeg_dispose #metadatamux_jpeg_parse
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
|
||||
void
|
||||
metadatamux_jpeg_init (JpegMuxData * jpeg_data,
|
||||
|
@ -164,6 +141,16 @@ metadatamux_jpeg_init (JpegMuxData * jpeg_data,
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* metadatamux_jpeg_dispose:
|
||||
* @jpeg_data: [in] jpeg data handler to be freed
|
||||
*
|
||||
* Call this function to free any resource allocated by #metadatamux_jpeg_init
|
||||
* @see_also: #metadatamux_jpeg_init
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
|
||||
void
|
||||
metadatamux_jpeg_dispose (JpegMuxData * jpeg_data)
|
||||
{
|
||||
|
@ -173,6 +160,42 @@ metadatamux_jpeg_dispose (JpegMuxData * jpeg_data)
|
|||
jpeg_data->state = JPEG_MUX_NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* metadatamux_jpeg_parse:
|
||||
* @jpeg_data: [in] jpeg data handle
|
||||
* @buf: [in] data to be parsed
|
||||
* @bufsize: [in] size of @buf in bytes
|
||||
* @offset: is the offset where @buf starts from the beginnig of the whole
|
||||
* stream
|
||||
* @next_start: is a pointer after @buf which indicates where @buf should start
|
||||
* on the next call to this function. It means, that after returning, this
|
||||
* function has consumed *@next_start - @buf bytes. Which also means
|
||||
* that @offset should also be incremanted by (*@next_start - @buf) for the
|
||||
* next time.
|
||||
* @next_size: [out] number of minimal bytes in @buf for the next call to this
|
||||
* function
|
||||
*
|
||||
* This function is used to parse a JPEG stream step-by-step incrementally.
|
||||
* Basically this function works like a state machine, that will run in a loop
|
||||
* while there is still bytes in @buf to be read or it has finished parsing.
|
||||
* If the it hasn't parsed yet and there is no more data in @buf, then the
|
||||
* current state is saved and a indication will be make about the buffer to
|
||||
* be passed by the caller function.
|
||||
* @see_also: #metadatamux_jpeg_init
|
||||
*
|
||||
* Returns:
|
||||
* <itemizedlist>
|
||||
* <listitem><para>%META_PARSING_ERROR
|
||||
* </para></listitem>
|
||||
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
|
||||
* inject chunks has been found
|
||||
* </para></listitem>
|
||||
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
|
||||
* called again (look @next_start and @next_size)
|
||||
* </para></listitem>
|
||||
* </itemizedlist>
|
||||
*/
|
||||
|
||||
MetadataParsingReturn
|
||||
metadatamux_jpeg_parse (JpegMuxData * jpeg_data, guint8 * buf,
|
||||
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
|
||||
|
@ -227,8 +250,114 @@ done:
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* metadatamux_jpeg_lazy_update:
|
||||
* @jpeg_data: [in] jpeg data handle
|
||||
*
|
||||
* This function wrap metadata chunk with proper JPEG marks. In case of IPTC
|
||||
* it will be wrapped by PhotoShop and then by JPEG mark.
|
||||
* @see_also: #metadata_lazy_update
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
|
||||
void
|
||||
metadatamux_jpeg_lazy_update (JpegMuxData * jpeg_data)
|
||||
{
|
||||
gsize i;
|
||||
gboolean has_exif = FALSE;
|
||||
|
||||
for (i = 0; i < jpeg_data->inject_chunks->len; ++i) {
|
||||
if (jpeg_data->inject_chunks->chunk[i].size > 0 &&
|
||||
jpeg_data->inject_chunks->chunk[i].data) {
|
||||
switch (jpeg_data->inject_chunks->chunk[i].type) {
|
||||
case MD_CHUNK_EXIF:
|
||||
metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i], NULL, 0,
|
||||
0xFF, 0xE1);
|
||||
has_exif = TRUE;
|
||||
break;
|
||||
case MD_CHUNK_IPTC:
|
||||
#ifdef HAVE_IPTC
|
||||
{
|
||||
if (metadatamux_wrap_iptc_with_ps3 (&jpeg_data->inject_chunks->
|
||||
chunk[i].data, &jpeg_data->inject_chunks->chunk[i].size)) {
|
||||
metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i], NULL,
|
||||
0, 0xFF, 0xED);
|
||||
} else {
|
||||
GST_ERROR ("Invalid IPTC chunk\n");
|
||||
/* FIXME: remove entry from list */
|
||||
}
|
||||
}
|
||||
#endif /* #ifdef HAVE_IPTC */
|
||||
break;
|
||||
case MD_CHUNK_XMP:
|
||||
{
|
||||
static const char XmpHeader[] = "http://ns.adobe.com/xap/1.0/";
|
||||
|
||||
metadatamux_wrap_chunk (&jpeg_data->inject_chunks->chunk[i],
|
||||
XmpHeader, sizeof (XmpHeader), 0xFF, 0xE1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!has_exif) {
|
||||
/* EXIF not injected so not strip JFIF anymore */
|
||||
metadata_chunk_array_clear (jpeg_data->strip_chunks);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* static helper functions implementation
|
||||
*/
|
||||
|
||||
/*
|
||||
* metadatamux_jpeg_reading:
|
||||
* @jpeg_data: [in] jpeg data handle
|
||||
* @buf: [in] data to be parsed. @buf will increment during the parsing step.
|
||||
* So it will hold the next byte to be read inside a parsing function or on
|
||||
* the next nested parsing function. And so, @bufsize will decrement.
|
||||
* @bufsize: [in] size of @buf in bytes. This value will decrement during the
|
||||
* parsing for the same reason that @buf will advance.
|
||||
* @offset: is the offset where @step_buf starts from the beginnig of the
|
||||
* stream
|
||||
* @step_buf: holds the pointer to the buffer passed to
|
||||
* #metadatamux_jpeg_parse. It means that any point inside this function
|
||||
* the offset (related to the beginning of the whole stream) after the last
|
||||
* byte read so far is "(*buf - step_buf) + offset"
|
||||
* @next_start: is a pointer after @step_buf which indicates where the next
|
||||
* call to #metadatamux_jpeg_parse should start on the next call to this
|
||||
* function. It means, that after return, this function has
|
||||
* consumed *@next_start - @buf bytes. Which also means that @offset should
|
||||
* also be incremanted by (*@next_start - @buf) for the next time.
|
||||
* @next_size: [out] number of minimal bytes in @buf for the next call to this
|
||||
* function
|
||||
*
|
||||
* This function is used to parse a JPEG stream step-by-step incrementally.
|
||||
* If this function quickly finds the place (offset) in which EXIF, IPTC and
|
||||
* XMP chunk should be written to.
|
||||
* The found places are written to @jpeg_data->inject_chunks
|
||||
* @see_also: #metadatamux_jpeg_init
|
||||
*
|
||||
* Returns:
|
||||
* <itemizedlist>
|
||||
* <listitem><para>%META_PARSING_ERROR
|
||||
* </para></listitem>
|
||||
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
|
||||
* inject chunks has been found. Or some chunk has been found and should be
|
||||
* held or jumped.
|
||||
* </para></listitem>
|
||||
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
|
||||
* called again (look @next_start and @next_size)
|
||||
* </para></listitem>
|
||||
* </itemizedlist>
|
||||
*/
|
||||
|
||||
/* look for markers */
|
||||
static MetadataParsingReturn
|
||||
metadatamux_jpeg_reading (JpegMuxData * jpeg_data, guint8 ** buf,
|
||||
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
||||
|
@ -338,3 +467,65 @@ done:
|
|||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* metadatamux_wrap_chunk:
|
||||
* @chunk: chunk to be wrapped
|
||||
* @buf: data to inject in the beginning of @chunk->data and after @a and @b
|
||||
* @buf_size: size in bytes of @buf
|
||||
* @a: together with @b forms the JPEG mark to be injected in the beginning
|
||||
* @b: look at @a
|
||||
*
|
||||
* Wraps a chunk if a JPEG mark (@a@b) and, if @buf_size > 0, with some data
|
||||
* (@buf)
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
|
||||
static void
|
||||
metadatamux_wrap_chunk (MetadataChunk * chunk, const guint8 * buf,
|
||||
guint32 buf_size, guint8 a, guint8 b)
|
||||
{
|
||||
guint8 *data = g_new (guint8, 4 + buf_size + chunk->size);
|
||||
|
||||
memcpy (data + 4 + buf_size, chunk->data, chunk->size);
|
||||
g_free (chunk->data);
|
||||
chunk->data = data;
|
||||
chunk->size += 4 + buf_size;
|
||||
data[0] = a;
|
||||
data[1] = b;
|
||||
data[2] = ((chunk->size - 2) >> 8) & 0xFF;
|
||||
data[3] = (chunk->size - 2) & 0xFF;
|
||||
if (buf && buf_size) {
|
||||
memcpy (data + 4, buf, buf_size);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPTC
|
||||
static gboolean
|
||||
metadatamux_wrap_iptc_with_ps3 (unsigned char **buf, unsigned int *buf_size)
|
||||
{
|
||||
unsigned int out_size = *buf_size + 4096;
|
||||
unsigned char *outbuf = g_new (unsigned char, out_size);
|
||||
int size_written;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
size_written =
|
||||
iptc_jpeg_ps3_save_iptc (NULL, 0, *buf, *buf_size, outbuf, out_size);
|
||||
|
||||
g_free (*buf);
|
||||
*buf = NULL;
|
||||
*buf_size = 0;
|
||||
|
||||
if (size_written < 0) {
|
||||
g_free (outbuf);
|
||||
ret = FALSE;
|
||||
} else {
|
||||
*buf_size = size_written;
|
||||
*buf = outbuf;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
#endif /* #ifdef HAVE_IPTC */
|
||||
|
|
|
@ -44,10 +44,18 @@
|
|||
#ifndef __METADATAMUX_JPEG_H__
|
||||
#define __METADATAMUX_JPEG_H__
|
||||
|
||||
/*
|
||||
* includes
|
||||
*/
|
||||
|
||||
#include <gst/base/gstadapter.h>
|
||||
|
||||
#include "metadatatypes.h"
|
||||
|
||||
/*
|
||||
* enum and types
|
||||
*/
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum _tag_JpegMuxState
|
||||
|
@ -67,6 +75,9 @@ typedef struct _tag_JpegMuxData
|
|||
|
||||
} JpegMuxData;
|
||||
|
||||
/*
|
||||
* external function prototypes
|
||||
*/
|
||||
|
||||
extern void
|
||||
metadatamux_jpeg_init (JpegMuxData * jpeg_data,
|
||||
|
@ -74,11 +85,12 @@ metadatamux_jpeg_init (JpegMuxData * jpeg_data,
|
|||
|
||||
extern void metadatamux_jpeg_dispose (JpegMuxData * jpeg_data);
|
||||
|
||||
extern void metadatamux_jpeg_lazy_update (JpegMuxData * jpeg_data);
|
||||
|
||||
extern MetadataParsingReturn
|
||||
metadatamux_jpeg_parse (JpegMuxData * 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 metadatamux_jpeg_lazy_update (JpegMuxData * jpeg_data);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __METADATAMUX_JPEG_H__ */
|
||||
|
|
|
@ -41,113 +41,88 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SECTION: metadatamuxpng
|
||||
* @short_description: This module provides functions to parse PNG files in
|
||||
* order to write metadata to it.
|
||||
*
|
||||
* This module parses a PNG stream to find the places in which XMP metadata
|
||||
* chunks would be written. It also wraps metadata chunks with PNG marks
|
||||
* according to the specification.
|
||||
*
|
||||
* <refsect2>
|
||||
* <para>
|
||||
* #metadatamux_png_init must be called before any other function in this
|
||||
* module and must be paired with a call to #metadatamux_png_dispose.
|
||||
* #metadatamux_png_parse is used to parse the stream (find the place
|
||||
* metadata chunks should be written to).
|
||||
* #metadatamux_png_lazy_update do nothing.
|
||||
* </para>
|
||||
* <para>
|
||||
* EXIF chunks will always be the first chunk (replaces JFIF). IPTC and XMP
|
||||
* chunks will be placed or second chunk (after JFIF or EXIF) or third chunk
|
||||
* if both (IPTC and XMP) are written to the file.
|
||||
* </para>
|
||||
* <para>
|
||||
* When a EXIF chunk is written to the PNG stream, if there is a JFIF chunk
|
||||
* as the first chunk, it will be stripped out.
|
||||
* </para>
|
||||
* </refsect2>
|
||||
*
|
||||
* Last reviewed on 2008-01-24 (0.10.15)
|
||||
*/
|
||||
|
||||
/*
|
||||
* includes
|
||||
*/
|
||||
|
||||
#include "metadatamuxpng.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* defines and macros
|
||||
*/
|
||||
|
||||
#define READ(buf, size) ( (size)--, *((buf)++) )
|
||||
|
||||
/*
|
||||
* static helper functions declaration
|
||||
*/
|
||||
|
||||
static MetadataParsingReturn
|
||||
metadatamux_png_reading (PngMuxData * png_data, guint8 ** buf,
|
||||
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
||||
guint8 ** next_start, guint32 * next_size);
|
||||
|
||||
#define READ(buf, size) ( (size)--, *((buf)++) )
|
||||
static void metadatamux_make_crc_table (guint32 crc_table[]);
|
||||
|
||||
static void
|
||||
make_crc_table (guint32 crc_table[])
|
||||
{
|
||||
guint32 c;
|
||||
guint16 n, k;
|
||||
static guint32 metadatamux_update_crc (guint32 crc, guint8 * buf, guint32 len);
|
||||
|
||||
for (n = 0; n < 256; n++) {
|
||||
c = (guint32) n;
|
||||
for (k = 0; k < 8; k++) {
|
||||
if (c & 1)
|
||||
c = 0xedb88320L ^ (c >> 1);
|
||||
else
|
||||
c = c >> 1;
|
||||
}
|
||||
crc_table[n] = c;
|
||||
}
|
||||
}
|
||||
static guint32 metadatamux_calc_crc (guint8 * buf, guint32 len);
|
||||
|
||||
static guint32
|
||||
update_crc (guint32 crc, guint8 * buf, guint32 len)
|
||||
{
|
||||
guint32 c = crc;
|
||||
guint32 n;
|
||||
guint32 crc_table[256];
|
||||
static void metadatamux_wrap_xmp_chunk (MetadataChunk * chunk);
|
||||
|
||||
/* FIXME: make_crc_table should be done once in life
|
||||
for speed up */
|
||||
make_crc_table (crc_table);
|
||||
/*
|
||||
* extern functions implementations
|
||||
*/
|
||||
|
||||
for (n = 0; n < len; n++) {
|
||||
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Return the CRC of the bytes buf[0..len-1]. */
|
||||
static guint32
|
||||
calc_crc (guint8 * buf, guint32 len)
|
||||
{
|
||||
return update_crc (0xffffffffL, buf, len) ^ 0xffffffffL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
metadatamux_wrap_xmp_chunk (MetadataChunk * chunk)
|
||||
{
|
||||
static const char XmpHeader[] = "XML:com.adobe.xmp";
|
||||
guint8 *data = NULL;
|
||||
guint32 crc;
|
||||
|
||||
data = g_new (guint8, 12 + 18 + 4 + chunk->size);
|
||||
|
||||
memcpy (data + 8, XmpHeader, 18);
|
||||
memset (data + 8 + 18, 0x00, 4);
|
||||
memcpy (data + 8 + 18 + 4, chunk->data, chunk->size);
|
||||
g_free (chunk->data);
|
||||
chunk->data = data;
|
||||
chunk->size += 18 + 4;
|
||||
data[0] = (chunk->size >> 24) & 0xFF;
|
||||
data[1] = (chunk->size >> 16) & 0xFF;
|
||||
data[2] = (chunk->size >> 8) & 0xFF;
|
||||
data[3] = chunk->size & 0xFF;
|
||||
data[4] = 'i';
|
||||
data[5] = 'T';
|
||||
data[6] = 'X';
|
||||
data[7] = 't';
|
||||
crc = calc_crc (data + 4, chunk->size + 4 + 18);
|
||||
data[chunk->size + 8] = (crc >> 24) & 0xFF;
|
||||
data[chunk->size + 9] = (crc >> 16) & 0xFF;
|
||||
data[chunk->size + 10] = (crc >> 8) & 0xFF;
|
||||
data[chunk->size + 11] = crc & 0xFF;
|
||||
chunk->size += 12;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
metadatamux_png_lazy_update (PngMuxData * png_data)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
for (i = 0; i < png_data->inject_chunks->len; ++i) {
|
||||
if (png_data->inject_chunks->chunk[i].size > 0 &&
|
||||
png_data->inject_chunks->chunk[i].data) {
|
||||
switch (png_data->inject_chunks->chunk[i].type) {
|
||||
case MD_CHUNK_XMP:
|
||||
{
|
||||
metadatamux_wrap_xmp_chunk (&png_data->inject_chunks->chunk[i]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GST_ERROR ("Unexpected chunk for PNG muxer.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* metadatamux_png_init:
|
||||
* @png_data: [in] png data handler to be inited
|
||||
* @strip_chunks: Array of chunks (offset and size) marked for removal
|
||||
* @inject_chunks: Array of chunks (offset, data, size) marked for injection
|
||||
* adapter (@exif_adpt, @iptc_adpt, @xmp_adpt). Or FALSE if should also put
|
||||
* them on @strip_chunks.
|
||||
*
|
||||
* Init png data handle.
|
||||
* This function must be called before any other function from this module.
|
||||
* This function must not be called twice without call to
|
||||
* #metadatamux_png_dispose beteween them.
|
||||
* @see_also: #metadatamux_png_dispose #metadatamux_png_parse
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
|
||||
void
|
||||
metadatamux_png_init (PngMuxData * png_data,
|
||||
|
@ -159,6 +134,16 @@ metadatamux_png_init (PngMuxData * png_data,
|
|||
png_data->inject_chunks = inject_chunks;
|
||||
}
|
||||
|
||||
/*
|
||||
* metadatamux_png_dispose:
|
||||
* png_data: [in] png data handler to be freed
|
||||
*
|
||||
* Call this function to free any resource allocated by #metadatamux_png_init
|
||||
* @see_also: #metadatamux_png_init
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
|
||||
void
|
||||
metadatamux_png_dispose (PngMuxData * png_data)
|
||||
{
|
||||
|
@ -168,6 +153,42 @@ metadatamux_png_dispose (PngMuxData * png_data)
|
|||
png_data->state = PNG_MUX_NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* metadatamux_png_parse:
|
||||
* @png_data: [in] png data handle
|
||||
* @buf: [in] data to be parsed
|
||||
* @bufsize: [in] size of @buf in bytes
|
||||
* @offset: is the offset where @buf starts from the beginnig of the whole
|
||||
* stream
|
||||
* @next_start: is a pointer after @buf which indicates where @buf should start
|
||||
* on the next call to this function. It means, that after returning, this
|
||||
* function has consumed *@next_start - @buf bytes. Which also means
|
||||
* that @offset should also be incremanted by (*@next_start - @buf) for the
|
||||
* next time.
|
||||
* @next_size: [out] number of minimal bytes in @buf for the next call to this
|
||||
* function
|
||||
*
|
||||
* This function is used to parse a PNG stream step-by-step incrementally.
|
||||
* Basically this function works like a state machine, that will run in a loop
|
||||
* while there is still bytes in @buf to be read or it has finished parsing.
|
||||
* If the it hasn't parsed yet and there is no more data in @buf, then the
|
||||
* current state is saved and a indication will be make about the buffer to
|
||||
* be passed by the caller function.
|
||||
* @see_also: #metadatamux_png_init
|
||||
*
|
||||
* Returns:
|
||||
* <itemizedlist>
|
||||
* <listitem><para>%META_PARSING_ERROR
|
||||
* </para></listitem>
|
||||
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
|
||||
* inject chunks has been found
|
||||
* </para></listitem>
|
||||
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
|
||||
* called again (look @next_start and @next_size)
|
||||
* </para></listitem>
|
||||
* </itemizedlist>
|
||||
*/
|
||||
|
||||
MetadataParsingReturn
|
||||
metadatamux_png_parse (PngMuxData * png_data, guint8 * buf,
|
||||
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
|
||||
|
@ -230,8 +251,86 @@ done:
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* metadatamux_png_lazy_update:
|
||||
* @png_data: [in] png data handle
|
||||
*
|
||||
* This function wrap metadata chunk with proper PNG bytes.
|
||||
* @see_also: #metadata_lazy_update
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
|
||||
void
|
||||
metadatamux_png_lazy_update (PngMuxData * png_data)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
for (i = 0; i < png_data->inject_chunks->len; ++i) {
|
||||
if (png_data->inject_chunks->chunk[i].size > 0 &&
|
||||
png_data->inject_chunks->chunk[i].data) {
|
||||
switch (png_data->inject_chunks->chunk[i].type) {
|
||||
case MD_CHUNK_XMP:
|
||||
{
|
||||
metadatamux_wrap_xmp_chunk (&png_data->inject_chunks->chunk[i]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GST_ERROR ("Unexpected chunk for PNG muxer.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* static helper functions implementation
|
||||
*/
|
||||
|
||||
/*
|
||||
* metadatamux_png_reading:
|
||||
* @png_data: [in] png data handle
|
||||
* @buf: [in] data to be parsed. @buf will increment during the parsing step.
|
||||
* So it will hold the next byte to be read inside a parsing function or on
|
||||
* the next nested parsing function. And so, @bufsize will decrement.
|
||||
* @bufsize: [in] size of @buf in bytes. This value will decrement during the
|
||||
* parsing for the same reason that @buf will advance.
|
||||
* @offset: is the offset where @step_buf starts from the beginnig of the
|
||||
* stream
|
||||
* @step_buf: holds the pointer to the buffer passed to
|
||||
* #metadatamux_png_parse. It means that any point inside this function
|
||||
* the offset (related to the beginning of the whole stream) after the last
|
||||
* byte read so far is "(*buf - step_buf) + offset"
|
||||
* @next_start: is a pointer after @step_buf which indicates where the next
|
||||
* call to #metadatamux_png_parse should start on the next call to this
|
||||
* function. It means, that after return, this function has
|
||||
* consumed *@next_start - @buf bytes. Which also means that @offset should
|
||||
* also be incremanted by (*@next_start - @buf) for the next time.
|
||||
* @next_size: [out] number of minimal bytes in @buf for the next call to this
|
||||
* function
|
||||
*
|
||||
* This function is used to parse a PNG stream step-by-step incrementally.
|
||||
* If this function quickly finds the place (offset) in which EXIF, IPTC and
|
||||
* XMP chunk should be written to.
|
||||
* The found places are written to @png_data->inject_chunks
|
||||
* @see_also: #metadatamux_png_init
|
||||
*
|
||||
* Returns:
|
||||
* <itemizedlist>
|
||||
* <listitem><para>%META_PARSING_ERROR
|
||||
* </para></listitem>
|
||||
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
|
||||
* inject chunks has been found. Or some chunk has been found and should be
|
||||
* held or jumped.
|
||||
* </para></listitem>
|
||||
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
|
||||
* called again (look @next_start and @next_size)
|
||||
* </para></listitem>
|
||||
* </itemizedlist>
|
||||
*/
|
||||
|
||||
|
||||
/* look for markers */
|
||||
static MetadataParsingReturn
|
||||
metadatamux_png_reading (PngMuxData * png_data, guint8 ** buf,
|
||||
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
||||
|
@ -287,3 +386,119 @@ done:
|
|||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* metadatamux_make_crc_table:
|
||||
* @crc_table: table to be written to.
|
||||
*
|
||||
* Creates a startup CRC table. For optimization it should be done only once.
|
||||
* @see_also: #metadatamux_update_crc
|
||||
*
|
||||
* Returns: nothing.
|
||||
*/
|
||||
|
||||
static void
|
||||
metadatamux_make_crc_table (guint32 crc_table[])
|
||||
{
|
||||
guint32 c;
|
||||
guint16 n, k;
|
||||
|
||||
for (n = 0; n < 256; n++) {
|
||||
c = (guint32) n;
|
||||
for (k = 0; k < 8; k++) {
|
||||
if (c & 1)
|
||||
c = 0xedb88320L ^ (c >> 1);
|
||||
else
|
||||
c = c >> 1;
|
||||
}
|
||||
crc_table[n] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* metadatamux_update_crc:
|
||||
* @crc: seed to calculate the CRC
|
||||
* @buf: data to calculate the CRC for
|
||||
* @len: size in bytes of @buf
|
||||
*
|
||||
* Calculates the CRC of a data buffer for a seed @crc.
|
||||
* @see_also: #metadatamux_make_crc_table #metadatamux_calc_crc
|
||||
*
|
||||
* Returns: the CRC of the bytes buf[0..len-1].
|
||||
*/
|
||||
|
||||
static guint32
|
||||
metadatamux_update_crc (guint32 crc, guint8 * buf, guint32 len)
|
||||
{
|
||||
guint32 c = crc;
|
||||
guint32 n;
|
||||
guint32 crc_table[256];
|
||||
|
||||
/* FIXME: make_crc_table should be done once in life
|
||||
for speed up. It could be written hard coded to a file */
|
||||
metadatamux_make_crc_table (crc_table);
|
||||
|
||||
for (n = 0; n < len; n++) {
|
||||
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* metadatamux_calc_crc:
|
||||
* @buf: data to calculate the CRC for
|
||||
* @len: size in bytes of @buf
|
||||
*
|
||||
* Calculates the CRC of a data buffer.
|
||||
*
|
||||
* Returns: the CRC of the bytes buf[0..len-1].
|
||||
*/
|
||||
|
||||
static guint32
|
||||
metadatamux_calc_crc (guint8 * buf, guint32 len)
|
||||
{
|
||||
return metadatamux_update_crc (0xffffffffL, buf, len) ^ 0xffffffffL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* metadatamux_wrap_xmp_chunk:
|
||||
* @chunk: chunk to be wrapped
|
||||
*
|
||||
* Wraps a XMP chunk with proper PNG bytes (mark, size and crc in the end)
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
|
||||
static void
|
||||
metadatamux_wrap_xmp_chunk (MetadataChunk * chunk)
|
||||
{
|
||||
static const char XmpHeader[] = "XML:com.adobe.xmp";
|
||||
guint8 *data = NULL;
|
||||
guint32 crc;
|
||||
|
||||
data = g_new (guint8, 12 + 18 + 4 + chunk->size);
|
||||
|
||||
memcpy (data + 8, XmpHeader, 18);
|
||||
memset (data + 8 + 18, 0x00, 4);
|
||||
memcpy (data + 8 + 18 + 4, chunk->data, chunk->size);
|
||||
g_free (chunk->data);
|
||||
chunk->data = data;
|
||||
chunk->size += 18 + 4;
|
||||
data[0] = (chunk->size >> 24) & 0xFF;
|
||||
data[1] = (chunk->size >> 16) & 0xFF;
|
||||
data[2] = (chunk->size >> 8) & 0xFF;
|
||||
data[3] = chunk->size & 0xFF;
|
||||
data[4] = 'i';
|
||||
data[5] = 'T';
|
||||
data[6] = 'X';
|
||||
data[7] = 't';
|
||||
crc = metadatamux_calc_crc (data + 4, chunk->size + 4);
|
||||
data[chunk->size + 8] = (crc >> 24) & 0xFF;
|
||||
data[chunk->size + 9] = (crc >> 16) & 0xFF;
|
||||
data[chunk->size + 10] = (crc >> 8) & 0xFF;
|
||||
data[chunk->size + 11] = crc & 0xFF;
|
||||
|
||||
chunk->size += 12;
|
||||
|
||||
}
|
||||
|
|
|
@ -44,12 +44,20 @@
|
|||
#ifndef __METADATAMUX_PNG_H__
|
||||
#define __METADATAMUX_PNG_H__
|
||||
|
||||
/*
|
||||
* includes
|
||||
*/
|
||||
|
||||
#include <gst/base/gstadapter.h>
|
||||
|
||||
#include "metadatatypes.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* enum and types
|
||||
*/
|
||||
|
||||
typedef enum _tag_PngMuxState
|
||||
{
|
||||
PNG_MUX_NULL,
|
||||
|
@ -69,6 +77,9 @@ typedef struct _tag_PngMuxData
|
|||
|
||||
} PngMuxData;
|
||||
|
||||
/*
|
||||
* external function prototypes
|
||||
*/
|
||||
|
||||
extern void
|
||||
metadatamux_png_init (PngMuxData * png_data,
|
||||
|
@ -80,7 +91,8 @@ extern void metadatamux_png_lazy_update (PngMuxData * png_data);
|
|||
|
||||
extern MetadataParsingReturn
|
||||
metadatamux_png_parse (PngMuxData * png_data, guint8 * buf,
|
||||
guint32 * bufsize, const guint32 offset, guint8 ** next_start, guint32 * next_size);
|
||||
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
|
||||
guint32 * next_size);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __METADATAMUX_PNG_H__ */
|
||||
|
|
|
@ -185,7 +185,7 @@ metadataparse_jpeg_dispose (JpegParseData * jpeg_data)
|
|||
}
|
||||
|
||||
/*
|
||||
* metadata_parse:
|
||||
* metadataparse_jpeg_parse:
|
||||
* @jpeg_data: [in] jpeg data handle
|
||||
* @buf: [in] data to be parsed
|
||||
* @bufsize: [in] size of @buf in bytes
|
||||
|
@ -310,7 +310,7 @@ done:
|
|||
* @jpeg_data: [in] jpeg data handle
|
||||
*
|
||||
* This function do nothing
|
||||
* @see_also: metadata_lazy_update
|
||||
* @see_also: #metadata_lazy_update
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
|
|
|
@ -152,7 +152,7 @@ metadataparse_png_dispose (PngParseData * png_data)
|
|||
}
|
||||
|
||||
/*
|
||||
* metadata_parse:
|
||||
* metadataparse_png_parse:
|
||||
* @png_data: [in] png data handle
|
||||
* @buf: [in] data to be parsed
|
||||
* @bufsize: [in] size of @buf in bytes
|
||||
|
@ -273,7 +273,7 @@ done:
|
|||
* @png_data: [in] png data handle
|
||||
*
|
||||
* This function do nothing
|
||||
* @see_also: metadata_lazy_update
|
||||
* @see_also: #metadata_lazy_update
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
|
|
|
@ -22,7 +22,8 @@ metadata_editor_SOURCES = metadata_editor.c
|
|||
metadata_editor_CFLAGS = \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GLADE_CFLAGS)
|
||||
metadata_editor_LDADD = \
|
||||
$(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-0.10 $(GST_LIBS) $(GLADE_LIBS)
|
||||
$(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-0.10 $(GST_LIBS) \
|
||||
$(GLADE_LIBS) -Wl -export-dynamic
|
||||
metadata_editor_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
else
|
||||
GST_METADATA_TESTS =
|
||||
|
|
Loading…
Reference in a new issue