mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +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>
|
2008-01-29 Wim Taymans <wim.taymans@collabora.co.uk>
|
||||||
|
|
||||||
Patch by: Thijs Vermeir <thijsvermeir at gmail dot com>
|
Patch by: Thijs Vermeir <thijsvermeir at gmail dot com>
|
||||||
|
|
|
@ -76,12 +76,6 @@ else
|
||||||
DTS_DIR=
|
DTS_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USE_METADATA
|
|
||||||
METADATA_DIR=metadata
|
|
||||||
else
|
|
||||||
METADATA_DIR=
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_FAAC
|
if USE_FAAC
|
||||||
FAAC_DIR=faac
|
FAAC_DIR=faac
|
||||||
else
|
else
|
||||||
|
@ -160,6 +154,12 @@ else
|
||||||
MPEG2ENC_DIR=
|
MPEG2ENC_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if USE_METADATA
|
||||||
|
METADATA_DIR=metadata
|
||||||
|
else
|
||||||
|
METADATA_DIR=
|
||||||
|
endif
|
||||||
|
|
||||||
# if USE_MPLEX
|
# if USE_MPLEX
|
||||||
# MPLEX_DIR=mplex
|
# MPLEX_DIR=mplex
|
||||||
# else
|
# else
|
||||||
|
@ -313,6 +313,7 @@ SUBDIRS=\
|
||||||
$(LIBFAME_DIR) \
|
$(LIBFAME_DIR) \
|
||||||
$(LIBMMS_DIR) \
|
$(LIBMMS_DIR) \
|
||||||
$(MPEG2ENC_DIR) \
|
$(MPEG2ENC_DIR) \
|
||||||
|
$(METADATA_DIR) \
|
||||||
$(MPLEX_DIR) \
|
$(MPLEX_DIR) \
|
||||||
$(MUSEPACK_DIR) \
|
$(MUSEPACK_DIR) \
|
||||||
$(MUSICBRAINZ_DIR) \
|
$(MUSICBRAINZ_DIR) \
|
||||||
|
@ -342,7 +343,6 @@ DIST_SUBDIRS = \
|
||||||
cdaudio \
|
cdaudio \
|
||||||
dc1394 \
|
dc1394 \
|
||||||
directfb \
|
directfb \
|
||||||
metadata \
|
|
||||||
faac \
|
faac \
|
||||||
faad \
|
faad \
|
||||||
gio \
|
gio \
|
||||||
|
@ -353,6 +353,7 @@ DIST_SUBDIRS = \
|
||||||
libmms \
|
libmms \
|
||||||
dts \
|
dts \
|
||||||
divx \
|
divx \
|
||||||
|
metadata \
|
||||||
mpeg2enc \
|
mpeg2enc \
|
||||||
musepack \
|
musepack \
|
||||||
musicbrainz \
|
musicbrainz \
|
||||||
|
|
|
@ -26,12 +26,4 @@ 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
|
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,8 @@ gst_base_metadata_parse (GstBaseMetadata * filter, const guint8 * buf,
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_metadata_strip_push_buffer (GstBaseMetadata * base,
|
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
|
static int
|
||||||
gst_base_metadata_buf_get_intersection_seg (const gint64 offset, guint32 size,
|
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
|
static gboolean
|
||||||
gst_base_metadata_translate_pos_to_orig (GstBaseMetadata * base,
|
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);
|
static gboolean gst_base_metadata_calculate_offsets (GstBaseMetadata * base);
|
||||||
|
|
||||||
|
@ -639,6 +640,7 @@ done:
|
||||||
* beginning og @buf
|
* beginning og @buf
|
||||||
* @buf: a pointer to a buffer that will be modified (data striped/injected or
|
* @buf: a pointer to a buffer that will be modified (data striped/injected or
|
||||||
* prepended)
|
* 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
|
* 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
|
* a whole injected chunk if some inject chunk starts into the buffer. Prepend
|
||||||
|
@ -658,7 +660,8 @@ done:
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_metadata_strip_push_buffer (GstBaseMetadata * base,
|
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 *strip = META_DATA_STRIP_CHUNKS (base->metadata).chunk;
|
||||||
MetadataChunk *inject = META_DATA_INJECT_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;
|
int res;
|
||||||
|
|
||||||
if (inject[i].offset_orig >= offset_orig) {
|
if (inject[i].offset_orig >= offset_orig) {
|
||||||
if (inject[i].offset_orig < offset_orig + size_buf_in) {
|
if (G_LIKELY (inject_begin || inject[i].offset_orig > offset_orig)) {
|
||||||
injected_bytes += inject[i].size;
|
if (inject[i].offset_orig < offset_orig + size_buf_in) {
|
||||||
} else {
|
injected_bytes += inject[i].size;
|
||||||
/* segment is after size (segments are sorted) */
|
} else {
|
||||||
break;
|
/* segment is after size (segments are sorted) */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -846,20 +851,22 @@ inject:
|
||||||
original buffer */
|
original buffer */
|
||||||
|
|
||||||
if (inject[i].offset_orig >= offset_orig) {
|
if (inject[i].offset_orig >= offset_orig) {
|
||||||
if (inject[i].offset_orig <
|
if (G_LIKELY (inject_begin || inject[i].offset_orig > offset_orig)) {
|
||||||
offset_orig + size_buf_in + striped_bytes - injected_bytes) {
|
if (inject[i].offset_orig <
|
||||||
/* insert */
|
offset_orig + size_buf_in + striped_bytes - injected_bytes) {
|
||||||
guint32 buf_off =
|
/* insert */
|
||||||
inject[i].offset_orig - offset_orig - striped_so_far +
|
guint32 buf_off =
|
||||||
injected_bytes;
|
inject[i].offset_orig - offset_orig - striped_so_far +
|
||||||
memmove (data + buf_off + inject[i].size, data + buf_off,
|
injected_bytes;
|
||||||
size_buf_in - buf_off);
|
memmove (data + buf_off + inject[i].size, data + buf_off,
|
||||||
memcpy (data + buf_off, inject[i].data, inject[i].size);
|
size_buf_in - buf_off);
|
||||||
injected_bytes += inject[i].size;
|
memcpy (data + buf_off, inject[i].data, inject[i].size);
|
||||||
size_buf_in += inject[i].size;
|
injected_bytes += inject[i].size;
|
||||||
} else {
|
size_buf_in += inject[i].size;
|
||||||
/* segment is after size (segments are sorted) */
|
} else {
|
||||||
break;
|
/* segment is after size (segments are sorted) */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -988,6 +995,7 @@ done:
|
||||||
* @orig_pos: position in original stream
|
* @orig_pos: position in original stream
|
||||||
* @buf: if not NULL, will have data that starts at some point into a injected
|
* @buf: if not NULL, will have data that starts at some point into a injected
|
||||||
* chunk
|
* 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
|
* 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
|
* stream (@orig_pos) that contains the same data. If @pos is into a injected
|
||||||
|
@ -1006,7 +1014,7 @@ done:
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_metadata_translate_pos_to_orig (GstBaseMetadata * base,
|
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 *strip = META_DATA_STRIP_CHUNKS (base->metadata).chunk;
|
||||||
MetadataChunk *inject = META_DATA_INJECT_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 gsize inject_len = META_DATA_INJECT_CHUNKS (base->metadata).len;
|
||||||
const gint64 duration_orig = base->duration_orig;
|
const gint64 duration_orig = base->duration_orig;
|
||||||
const gint64 duration = base->duration;
|
const gint64 duration = base->duration;
|
||||||
|
gboolean ret = TRUE;
|
||||||
|
const gint64 saved_pos = pos;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
gboolean ret = TRUE;
|
|
||||||
guint64 new_buf_size = 0;
|
guint64 new_buf_size = 0;
|
||||||
guint64 injected_before = 0;
|
guint64 injected_before = 0;
|
||||||
|
|
||||||
|
@ -1032,56 +1042,67 @@ gst_base_metadata_translate_pos_to_orig (GstBaseMetadata * base,
|
||||||
/* calculate for injected */
|
/* calculate for injected */
|
||||||
|
|
||||||
/* just calculate size */
|
/* just calculate size */
|
||||||
*orig_pos = pos; /* save pos */
|
|
||||||
for (i = 0; i < inject_len; ++i) {
|
for (i = 0; i < inject_len; ++i) {
|
||||||
/* check if pos in inside chunk */
|
if (pos >= inject[i].offset) {
|
||||||
if (inject[i].offset <= pos) {
|
|
||||||
if (pos < inject[i].offset + inject[i].size) {
|
if (pos < inject[i].offset + inject[i].size) {
|
||||||
/* orig pos points after insert chunk */
|
/* pos is inside the chunk */
|
||||||
new_buf_size += inject[i].size;
|
const guint32 offset_in_chunk = pos - inject[i].offset;
|
||||||
/* put pos after current chunk */
|
|
||||||
pos = inject[i].offset + inject[i].size;
|
|
||||||
ret = FALSE;
|
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 {
|
} else {
|
||||||
/* in case pos is not inside a injected chunk */
|
/* in case pos is not inside a injected chunk */
|
||||||
injected_before += inject[i].size;
|
injected_before += inject[i].size;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* pos is before the chunk */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* alloc buffer and calcute original pos */
|
/* alloc buffer and calcute original pos */
|
||||||
if (buf && ret == FALSE) {
|
if (ret == FALSE) {
|
||||||
guint8 *data;
|
|
||||||
|
|
||||||
if (*buf)
|
*orig_pos = pos;
|
||||||
gst_buffer_unref (*buf);
|
|
||||||
*buf = gst_buffer_new_and_alloc (new_buf_size);
|
if (buf) {
|
||||||
data = GST_BUFFER_DATA (*buf);
|
guint8 *data;
|
||||||
pos = *orig_pos; /* recover saved pos */
|
|
||||||
for (i = 0; i < inject_len; ++i) {
|
if (max_size > 0)
|
||||||
if (inject[i].offset > pos) {
|
if (new_buf_size > max_size)
|
||||||
break;
|
new_buf_size = max_size;
|
||||||
}
|
|
||||||
if (inject[i].offset <= pos && pos < inject[i].offset + inject[i].size) {
|
if (*buf)
|
||||||
memcpy (data, inject[i].data, inject[i].size);
|
gst_buffer_unref (*buf);
|
||||||
data += inject[i].size;
|
*buf = gst_buffer_new_and_alloc (new_buf_size);
|
||||||
pos = inject[i].offset + inject[i].size;
|
data = GST_BUFFER_DATA (*buf);
|
||||||
/* out position after insert chunk orig */
|
pos = saved_pos;
|
||||||
*orig_pos = inject[i].offset_orig + inject[i].size;
|
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;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calculate for striped */
|
/* calculate for striped */
|
||||||
|
|
||||||
*orig_pos = pos - injected_before;
|
*orig_pos = saved_pos - injected_before;
|
||||||
for (i = 0; i < strip_len; ++i) {
|
for (i = 0; i < strip_len; ++i) {
|
||||||
if (strip[i].offset_orig > pos) {
|
if (strip[i].offset_orig > pos) {
|
||||||
break;
|
break;
|
||||||
|
@ -1479,7 +1500,7 @@ gst_base_metadata_src_event (GstPad * pad, GstEvent * event)
|
||||||
striped/injected buffer in next 'chain' calling */
|
striped/injected buffer in next 'chain' calling */
|
||||||
filter->offset = start;
|
filter->offset = start;
|
||||||
gst_base_metadata_translate_pos_to_orig (filter, start, &start,
|
gst_base_metadata_translate_pos_to_orig (filter, start, &start,
|
||||||
&filter->prepend_buffer);
|
&filter->prepend_buffer, 0);
|
||||||
filter->offset_orig = start;
|
filter->offset_orig = start;
|
||||||
|
|
||||||
if (stop_type == GST_SEEK_TYPE_CUR)
|
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;
|
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);
|
gst_event_unref (event);
|
||||||
event = gst_event_new_seek (rate, format, flags,
|
event = gst_event_new_seek (rate, format, flags,
|
||||||
|
@ -1569,6 +1590,7 @@ gst_base_metadata_get_range (GstPad * pad,
|
||||||
guint size_orig;
|
guint size_orig;
|
||||||
GstBuffer *prepend = NULL;
|
GstBuffer *prepend = NULL;
|
||||||
gboolean need_append = FALSE;
|
gboolean need_append = FALSE;
|
||||||
|
gboolean into_inject;
|
||||||
|
|
||||||
filter = GST_BASE_METADATA (GST_PAD_PARENT (pad));
|
filter = GST_BASE_METADATA (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
@ -1583,34 +1605,45 @@ gst_base_metadata_get_range (GstPad * pad,
|
||||||
|
|
||||||
size_orig = size;
|
size_orig = size;
|
||||||
|
|
||||||
gst_base_metadata_translate_pos_to_orig (filter, offset,
|
into_inject = !gst_base_metadata_translate_pos_to_orig (filter, offset,
|
||||||
&offset_orig, &prepend);
|
&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;
|
gint64 pos;
|
||||||
|
|
||||||
pos = offset + size - 1;
|
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;
|
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 (ret == GST_FLOW_OK && *buf) {
|
FALSE);
|
||||||
gst_base_metadata_strip_push_buffer (filter, offset_orig, &prepend, buf);
|
|
||||||
|
|
||||||
if (GST_BUFFER_SIZE (*buf) < size) {
|
|
||||||
/* need append */
|
|
||||||
need_append = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (GST_BUFFER_SIZE (*buf) < size) {
|
||||||
|
/* need append */
|
||||||
|
need_append = TRUE;
|
||||||
|
} else {
|
||||||
|
/* hide extra bytes */
|
||||||
|
GST_BUFFER_SIZE (*buf) = size;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
*buf = prepend;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
if (need_append) {
|
if (need_append) {
|
||||||
|
@ -1715,7 +1748,7 @@ gst_base_metadata_chain (GstPad * pad, GstBuffer * buf)
|
||||||
buf_size = GST_BUFFER_SIZE (buf);
|
buf_size = GST_BUFFER_SIZE (buf);
|
||||||
|
|
||||||
gst_base_metadata_strip_push_buffer (filter, filter->offset_orig,
|
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 */
|
if (buf) { /* may be all buffer has been striped */
|
||||||
gst_buffer_set_caps (buf, GST_PAD_CAPS (filter->srcpad));
|
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);
|
gst_query_set_position (query, GST_FORMAT_BYTES, filter->offset);
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case GST_QUERY_DURATION:
|
case GST_QUERY_DURATION:
|
||||||
|
|
||||||
|
@ -1864,6 +1898,7 @@ gst_base_metadata_src_query (GstPad * pad, GstQuery * query)
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case GST_QUERY_FORMATS:
|
case GST_QUERY_FORMATS:
|
||||||
gst_query_set_formats (query, 1, GST_FORMAT_BYTES);
|
gst_query_set_formats (query, 1, GST_FORMAT_BYTES);
|
||||||
|
|
|
@ -73,27 +73,57 @@ typedef enum _tag_BaseMetadataType {
|
||||||
} BaseMetadataType;
|
} BaseMetadataType;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* GST_BASE_METADATA_SRC_PAD:
|
* GST_BASE_METADATA_SRC_PAD:
|
||||||
* @obj: base metadata instance
|
* @obj: base metadata instance
|
||||||
*
|
*
|
||||||
* Gives the pointer to the #GstPad object of the element.
|
* 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:
|
* GST_BASE_METADATA_SINK_PAD:
|
||||||
* @obj: base metadata instance
|
* @obj: base metadata instance
|
||||||
*
|
*
|
||||||
* Gives the pointer to the #GstPad object of the element.
|
* 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)
|
* GST_BASE_METADATA_EXIF_ADAPTER
|
||||||
#define GST_BASE_METADATA_XMP_ADAPTER(obj) (GST_BASE_METADATA_CAST (obj)->metadata->xmp_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
|
typedef enum _tag_MetadataState
|
||||||
|
@ -127,7 +157,7 @@ struct _GstBaseMetadata
|
||||||
|
|
||||||
MetaOptions options;
|
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_parsing;
|
||||||
GstAdapter *adapter_holding;
|
GstAdapter *adapter_holding;
|
||||||
|
@ -161,10 +191,12 @@ extern GType
|
||||||
gst_base_metadata_get_type (void);
|
gst_base_metadata_get_type (void);
|
||||||
|
|
||||||
extern 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
|
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
|
extern MetaOptions
|
||||||
gst_base_metadata_get_option_flag(const GstBaseMetadata *base);
|
gst_base_metadata_get_option_flag(const GstBaseMetadata *base);
|
||||||
|
|
|
@ -41,6 +41,41 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* 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 "metadatamuxjpeg.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -49,109 +84,51 @@
|
||||||
#include <libiptcdata/iptc-jpeg.h>
|
#include <libiptcdata/iptc-jpeg.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* defines and macros
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define READ(buf, size) ( (size)--, *((buf)++) )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* static helper functions declaration
|
||||||
|
*/
|
||||||
|
|
||||||
static MetadataParsingReturn
|
static MetadataParsingReturn
|
||||||
metadatamux_jpeg_reading (JpegMuxData * jpeg_data, guint8 ** buf,
|
metadatamux_jpeg_reading (JpegMuxData * jpeg_data, guint8 ** buf,
|
||||||
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
||||||
guint8 ** next_start, guint32 * next_size);
|
guint8 ** next_start, guint32 * next_size);
|
||||||
|
|
||||||
#define READ(buf, size) ( (size)--, *((buf)++) )
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
metadatamux_wrap_chunk (MetadataChunk * chunk, const guint8 * buf,
|
metadatamux_wrap_chunk (MetadataChunk * chunk, const guint8 * buf,
|
||||||
guint32 buf_size, guint8 a, guint8 b)
|
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
|
#ifdef HAVE_IPTC
|
||||||
static gboolean
|
static gboolean
|
||||||
metadatamux_wrap_iptc_with_ps3 (unsigned char **buf, unsigned int *buf_size)
|
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 */
|
#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 &&
|
* extern functions implementations
|
||||||
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);
|
* metadatamux_jpeg_init:
|
||||||
}
|
* @jpeg_data: [in] jpeg data handler to be inited
|
||||||
break;
|
* @strip_chunks: Array of chunks (offset and size) marked for removal
|
||||||
default:
|
* @inject_chunks: Array of chunks (offset, data, size) marked for injection
|
||||||
break;
|
* adapter (@exif_adpt, @iptc_adpt, @xmp_adpt). Or FALSE if should also put
|
||||||
}
|
* them on @strip_chunks.
|
||||||
}
|
*
|
||||||
}
|
* Init jpeg data handle.
|
||||||
if (!has_exif) {
|
* This function must be called before any other function from this module.
|
||||||
/* EXIF not injected so not strip JFIF anymore */
|
* This function must not be called twice without call to
|
||||||
metadata_chunk_array_clear (jpeg_data->strip_chunks);
|
* #metadatamux_jpeg_dispose beteween them.
|
||||||
}
|
* @see_also: #metadatamux_jpeg_dispose #metadatamux_jpeg_parse
|
||||||
|
*
|
||||||
}
|
* Returns: nothing
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
metadatamux_jpeg_init (JpegMuxData * jpeg_data,
|
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
|
void
|
||||||
metadatamux_jpeg_dispose (JpegMuxData * jpeg_data)
|
metadatamux_jpeg_dispose (JpegMuxData * jpeg_data)
|
||||||
{
|
{
|
||||||
|
@ -173,6 +160,42 @@ metadatamux_jpeg_dispose (JpegMuxData * jpeg_data)
|
||||||
jpeg_data->state = JPEG_MUX_NULL;
|
jpeg_data->state = JPEG_MUX_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metadatamux_jpeg_parse:
|
||||||
|
* @jpeg_data: [in] jpeg data handle
|
||||||
|
* @buf: [in] data to be parsed
|
||||||
|
* @bufsize: [in] size of @buf in bytes
|
||||||
|
* @offset: is the offset where @buf starts from the beginnig of the whole
|
||||||
|
* stream
|
||||||
|
* @next_start: is a pointer after @buf which indicates where @buf should start
|
||||||
|
* on the next call to this function. It means, that after returning, this
|
||||||
|
* function has consumed *@next_start - @buf bytes. Which also means
|
||||||
|
* that @offset should also be incremanted by (*@next_start - @buf) for the
|
||||||
|
* next time.
|
||||||
|
* @next_size: [out] number of minimal bytes in @buf for the next call to this
|
||||||
|
* function
|
||||||
|
*
|
||||||
|
* This function is used to parse a JPEG stream step-by-step incrementally.
|
||||||
|
* Basically this function works like a state machine, that will run in a loop
|
||||||
|
* while there is still bytes in @buf to be read or it has finished parsing.
|
||||||
|
* If the it hasn't parsed yet and there is no more data in @buf, then the
|
||||||
|
* current state is saved and a indication will be make about the buffer to
|
||||||
|
* be passed by the caller function.
|
||||||
|
* @see_also: #metadatamux_jpeg_init
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* <itemizedlist>
|
||||||
|
* <listitem><para>%META_PARSING_ERROR
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
|
||||||
|
* inject chunks has been found
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
|
||||||
|
* called again (look @next_start and @next_size)
|
||||||
|
* </para></listitem>
|
||||||
|
* </itemizedlist>
|
||||||
|
*/
|
||||||
|
|
||||||
MetadataParsingReturn
|
MetadataParsingReturn
|
||||||
metadatamux_jpeg_parse (JpegMuxData * jpeg_data, guint8 * buf,
|
metadatamux_jpeg_parse (JpegMuxData * jpeg_data, guint8 * buf,
|
||||||
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
|
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
|
static MetadataParsingReturn
|
||||||
metadatamux_jpeg_reading (JpegMuxData * jpeg_data, guint8 ** buf,
|
metadatamux_jpeg_reading (JpegMuxData * jpeg_data, guint8 ** buf,
|
||||||
guint32 * bufsize, const guint32 offset, const guint8 * step_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__
|
#ifndef __METADATAMUX_JPEG_H__
|
||||||
#define __METADATAMUX_JPEG_H__
|
#define __METADATAMUX_JPEG_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* includes
|
||||||
|
*/
|
||||||
|
|
||||||
#include <gst/base/gstadapter.h>
|
#include <gst/base/gstadapter.h>
|
||||||
|
|
||||||
#include "metadatatypes.h"
|
#include "metadatatypes.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enum and types
|
||||||
|
*/
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
typedef enum _tag_JpegMuxState
|
typedef enum _tag_JpegMuxState
|
||||||
|
@ -67,6 +75,9 @@ typedef struct _tag_JpegMuxData
|
||||||
|
|
||||||
} JpegMuxData;
|
} JpegMuxData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* external function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadatamux_jpeg_init (JpegMuxData * jpeg_data,
|
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_dispose (JpegMuxData * jpeg_data);
|
||||||
|
|
||||||
extern void metadatamux_jpeg_lazy_update (JpegMuxData * jpeg_data);
|
|
||||||
|
|
||||||
extern MetadataParsingReturn
|
extern MetadataParsingReturn
|
||||||
metadatamux_jpeg_parse (JpegMuxData * jpeg_data, guint8 * buf,
|
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
|
G_END_DECLS
|
||||||
#endif /* __METADATAMUX_JPEG_H__ */
|
#endif /* __METADATAMUX_JPEG_H__ */
|
||||||
|
|
|
@ -41,113 +41,88 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* 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 "metadatamuxpng.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* defines and macros
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define READ(buf, size) ( (size)--, *((buf)++) )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* static helper functions declaration
|
||||||
|
*/
|
||||||
|
|
||||||
static MetadataParsingReturn
|
static MetadataParsingReturn
|
||||||
metadatamux_png_reading (PngMuxData * png_data, guint8 ** buf,
|
metadatamux_png_reading (PngMuxData * png_data, guint8 ** buf,
|
||||||
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
guint32 * bufsize, const guint32 offset, const guint8 * step_buf,
|
||||||
guint8 ** next_start, guint32 * next_size);
|
guint8 ** next_start, guint32 * next_size);
|
||||||
|
|
||||||
#define READ(buf, size) ( (size)--, *((buf)++) )
|
static void metadatamux_make_crc_table (guint32 crc_table[]);
|
||||||
|
|
||||||
static void
|
static guint32 metadatamux_update_crc (guint32 crc, guint8 * buf, guint32 len);
|
||||||
make_crc_table (guint32 crc_table[])
|
|
||||||
{
|
|
||||||
guint32 c;
|
|
||||||
guint16 n, k;
|
|
||||||
|
|
||||||
for (n = 0; n < 256; n++) {
|
static guint32 metadatamux_calc_crc (guint8 * buf, guint32 len);
|
||||||
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
|
static void metadatamux_wrap_xmp_chunk (MetadataChunk * chunk);
|
||||||
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 */
|
* extern functions implementations
|
||||||
make_crc_table (crc_table);
|
*/
|
||||||
|
|
||||||
for (n = 0; n < len; n++) {
|
/*
|
||||||
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
|
* metadatamux_png_init:
|
||||||
}
|
* @png_data: [in] png data handler to be inited
|
||||||
return c;
|
* @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
|
||||||
/* Return the CRC of the bytes buf[0..len-1]. */
|
* them on @strip_chunks.
|
||||||
static guint32
|
*
|
||||||
calc_crc (guint8 * buf, guint32 len)
|
* Init png data handle.
|
||||||
{
|
* This function must be called before any other function from this module.
|
||||||
return update_crc (0xffffffffL, buf, len) ^ 0xffffffffL;
|
* This function must not be called twice without call to
|
||||||
}
|
* #metadatamux_png_dispose beteween them.
|
||||||
|
* @see_also: #metadatamux_png_dispose #metadatamux_png_parse
|
||||||
|
*
|
||||||
static void
|
* Returns: nothing
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
metadatamux_png_init (PngMuxData * png_data,
|
metadatamux_png_init (PngMuxData * png_data,
|
||||||
|
@ -159,6 +134,16 @@ metadatamux_png_init (PngMuxData * png_data,
|
||||||
png_data->inject_chunks = inject_chunks;
|
png_data->inject_chunks = inject_chunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metadatamux_png_dispose:
|
||||||
|
* png_data: [in] png data handler to be freed
|
||||||
|
*
|
||||||
|
* Call this function to free any resource allocated by #metadatamux_png_init
|
||||||
|
* @see_also: #metadatamux_png_init
|
||||||
|
*
|
||||||
|
* Returns: nothing
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
metadatamux_png_dispose (PngMuxData * png_data)
|
metadatamux_png_dispose (PngMuxData * png_data)
|
||||||
{
|
{
|
||||||
|
@ -168,6 +153,42 @@ metadatamux_png_dispose (PngMuxData * png_data)
|
||||||
png_data->state = PNG_MUX_NULL;
|
png_data->state = PNG_MUX_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metadatamux_png_parse:
|
||||||
|
* @png_data: [in] png data handle
|
||||||
|
* @buf: [in] data to be parsed
|
||||||
|
* @bufsize: [in] size of @buf in bytes
|
||||||
|
* @offset: is the offset where @buf starts from the beginnig of the whole
|
||||||
|
* stream
|
||||||
|
* @next_start: is a pointer after @buf which indicates where @buf should start
|
||||||
|
* on the next call to this function. It means, that after returning, this
|
||||||
|
* function has consumed *@next_start - @buf bytes. Which also means
|
||||||
|
* that @offset should also be incremanted by (*@next_start - @buf) for the
|
||||||
|
* next time.
|
||||||
|
* @next_size: [out] number of minimal bytes in @buf for the next call to this
|
||||||
|
* function
|
||||||
|
*
|
||||||
|
* This function is used to parse a PNG stream step-by-step incrementally.
|
||||||
|
* Basically this function works like a state machine, that will run in a loop
|
||||||
|
* while there is still bytes in @buf to be read or it has finished parsing.
|
||||||
|
* If the it hasn't parsed yet and there is no more data in @buf, then the
|
||||||
|
* current state is saved and a indication will be make about the buffer to
|
||||||
|
* be passed by the caller function.
|
||||||
|
* @see_also: #metadatamux_png_init
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* <itemizedlist>
|
||||||
|
* <listitem><para>%META_PARSING_ERROR
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>%META_PARSING_DONE if parse has finished. Now strip and
|
||||||
|
* inject chunks has been found
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>%META_PARSING_NEED_MORE_DATA if this function should be
|
||||||
|
* called again (look @next_start and @next_size)
|
||||||
|
* </para></listitem>
|
||||||
|
* </itemizedlist>
|
||||||
|
*/
|
||||||
|
|
||||||
MetadataParsingReturn
|
MetadataParsingReturn
|
||||||
metadatamux_png_parse (PngMuxData * png_data, guint8 * buf,
|
metadatamux_png_parse (PngMuxData * png_data, guint8 * buf,
|
||||||
guint32 * bufsize, const guint32 offset, guint8 ** next_start,
|
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
|
static MetadataParsingReturn
|
||||||
metadatamux_png_reading (PngMuxData * png_data, guint8 ** buf,
|
metadatamux_png_reading (PngMuxData * png_data, guint8 ** buf,
|
||||||
guint32 * bufsize, const guint32 offset, const guint8 * step_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__
|
#ifndef __METADATAMUX_PNG_H__
|
||||||
#define __METADATAMUX_PNG_H__
|
#define __METADATAMUX_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_PngMuxState
|
typedef enum _tag_PngMuxState
|
||||||
{
|
{
|
||||||
PNG_MUX_NULL,
|
PNG_MUX_NULL,
|
||||||
|
@ -69,6 +77,9 @@ typedef struct _tag_PngMuxData
|
||||||
|
|
||||||
} PngMuxData;
|
} PngMuxData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* external function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
metadatamux_png_init (PngMuxData * png_data,
|
metadatamux_png_init (PngMuxData * png_data,
|
||||||
|
@ -80,7 +91,8 @@ extern void metadatamux_png_lazy_update (PngMuxData * png_data);
|
||||||
|
|
||||||
extern MetadataParsingReturn
|
extern MetadataParsingReturn
|
||||||
metadatamux_png_parse (PngMuxData * png_data, guint8 * buf,
|
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
|
G_END_DECLS
|
||||||
#endif /* __METADATAMUX_PNG_H__ */
|
#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
|
* @jpeg_data: [in] jpeg data handle
|
||||||
* @buf: [in] data to be parsed
|
* @buf: [in] data to be parsed
|
||||||
* @bufsize: [in] size of @buf in bytes
|
* @bufsize: [in] size of @buf in bytes
|
||||||
|
@ -310,7 +310,7 @@ done:
|
||||||
* @jpeg_data: [in] jpeg data handle
|
* @jpeg_data: [in] jpeg data handle
|
||||||
*
|
*
|
||||||
* This function do nothing
|
* This function do nothing
|
||||||
* @see_also: metadata_lazy_update
|
* @see_also: #metadata_lazy_update
|
||||||
*
|
*
|
||||||
* Returns: nothing
|
* Returns: nothing
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -152,7 +152,7 @@ metadataparse_png_dispose (PngParseData * png_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* metadata_parse:
|
* metadataparse_png_parse:
|
||||||
* @png_data: [in] png data handle
|
* @png_data: [in] png data handle
|
||||||
* @buf: [in] data to be parsed
|
* @buf: [in] data to be parsed
|
||||||
* @bufsize: [in] size of @buf in bytes
|
* @bufsize: [in] size of @buf in bytes
|
||||||
|
@ -273,7 +273,7 @@ done:
|
||||||
* @png_data: [in] png data handle
|
* @png_data: [in] png data handle
|
||||||
*
|
*
|
||||||
* This function do nothing
|
* This function do nothing
|
||||||
* @see_also: metadata_lazy_update
|
* @see_also: #metadata_lazy_update
|
||||||
*
|
*
|
||||||
* Returns: nothing
|
* Returns: nothing
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -22,7 +22,8 @@ metadata_editor_SOURCES = metadata_editor.c
|
||||||
metadata_editor_CFLAGS = \
|
metadata_editor_CFLAGS = \
|
||||||
$(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GLADE_CFLAGS)
|
$(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GLADE_CFLAGS)
|
||||||
metadata_editor_LDADD = \
|
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)
|
metadata_editor_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
else
|
else
|
||||||
GST_METADATA_TESTS =
|
GST_METADATA_TESTS =
|
||||||
|
|
Loading…
Reference in a new issue