mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 01:45:33 +00:00
jpegformat: add xmp reading and writing support
Bump needed base version for new xmp helper library. Use xmp helpers in jpegparse and jifmux.
This commit is contained in:
parent
81e6d94bb5
commit
3b78cc5eca
4 changed files with 149 additions and 29 deletions
|
@ -51,7 +51,7 @@ AM_PROG_LIBTOOL
|
|||
|
||||
dnl *** required versions of GStreamer stuff ***
|
||||
GST_REQ=0.10.28.1
|
||||
GSTPB_REQ=0.10.27
|
||||
GSTPB_REQ=0.10.28.1
|
||||
|
||||
dnl *** autotools stuff ****
|
||||
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
plugin_LTLIBRARIES = libgstjpegformat.la
|
||||
|
||||
libgstjpegformat_la_SOURCES = gstjpegformat.c gstjpegparse.c gstjifmux.c
|
||||
libgstjpegformat_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
|
||||
libgstjpegformat_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
|
||||
libgstjpegformat_la_CFLAGS = \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
|
||||
libgstjpegformat_la_LIBADD = \
|
||||
$(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_MAJORMINOR@ \
|
||||
$(GST_LIBS) $(GST_BASE_LIBS)
|
||||
libgstjpegformat_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstjpegformat_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="comment=\"test
|
|||
#include <string.h>
|
||||
#include <gst/base/gstbytereader.h>
|
||||
#include <gst/base/gstbytewriter.h>
|
||||
#include <gst/tag/tag.h>
|
||||
|
||||
#include "gstjifmux.h"
|
||||
|
||||
|
@ -335,14 +336,16 @@ gst_jif_mux_mangle_markers (GstJifMux * self)
|
|||
const GstTagList *tags;
|
||||
GstJifMuxMarker *m;
|
||||
GList *node, *file_hdr = NULL, *frame_hdr = NULL, *scan_hdr = NULL;
|
||||
GList *app0_jfif = NULL, *app1_exif = NULL, *app1_xmp = NULL, *com = NULL;
|
||||
GstBuffer *xmp_data;
|
||||
gchar *str = NULL;
|
||||
|
||||
/* FIXME: implement me more
|
||||
* - update the APP markers
|
||||
* - put any JFIF APP0 first
|
||||
* - the Exif APP1 next,
|
||||
* - the XMP APP1 next,
|
||||
* - the PSIR APP13 next,
|
||||
* - followed by all other marker segments
|
||||
/* update the APP markers
|
||||
* - put any JFIF APP0 first
|
||||
* - the Exif APP1 next,
|
||||
* - the XMP APP1 next,
|
||||
* - the PSIR APP13 next,
|
||||
* - followed by all other marker segments
|
||||
*/
|
||||
|
||||
/* find some reference points where we insert before/after */
|
||||
|
@ -351,6 +354,30 @@ gst_jif_mux_mangle_markers (GstJifMux * self)
|
|||
m = (GstJifMuxMarker *) node->data;
|
||||
|
||||
switch (m->marker) {
|
||||
case APP0:
|
||||
if (m->size > 5 && !memcmp (m->data, "JFIF\0", 5)) {
|
||||
GST_DEBUG_OBJECT (self, "found APP0 JFIF");
|
||||
if (!app0_jfif)
|
||||
app0_jfif = node;
|
||||
}
|
||||
break;
|
||||
case APP1:
|
||||
if (m->size > 6 && !memcmp (m->data, "EXIF\0\0", 6)) {
|
||||
GST_DEBUG_OBJECT (self, "found APP1 EXIF");
|
||||
if (!app1_exif)
|
||||
app1_exif = node;
|
||||
} else if (m->size > 29
|
||||
&& !memcmp (m->data, "http://ns.adobe.com/xap/1.0/\0", 29)) {
|
||||
GST_INFO_OBJECT (self, "found APP1 XMP, will be replaced");
|
||||
if (!app1_xmp)
|
||||
app1_xmp = node;
|
||||
}
|
||||
break;
|
||||
case COM:
|
||||
GST_INFO_OBJECT (self, "found COM, will be replaced");
|
||||
if (!com)
|
||||
com = node;
|
||||
break;
|
||||
case DQT:
|
||||
case SOF0:
|
||||
case SOF1:
|
||||
|
@ -380,36 +407,88 @@ gst_jif_mux_mangle_markers (GstJifMux * self)
|
|||
|
||||
/* if we want combined or JFIF */
|
||||
/* check if we don't have JFIF APP0 */
|
||||
/* insert into self->markers list */
|
||||
/* ensure its first */
|
||||
if (!app0_jfif) {
|
||||
/* build jfif header */
|
||||
static const struct
|
||||
{
|
||||
gchar id[5];
|
||||
guint8 ver[2];
|
||||
guint8 du;
|
||||
guint8 xd[2], yd[2];
|
||||
guint8 tw, th;
|
||||
} jfif_data = {
|
||||
"JFIF", {
|
||||
1, 2}, 0, {
|
||||
0, 1}, /* FIXME: check pixel-aspect from caps */
|
||||
{
|
||||
0, 1}, 0, 0};
|
||||
m = gst_jif_mux_new_marker (APP0, sizeof (jfif_data),
|
||||
(const guint8 *) &jfif_data, FALSE);
|
||||
/* insert into self->markers list */
|
||||
self->priv->markers = g_list_insert (self->priv->markers, m, 1);
|
||||
}
|
||||
/* else */
|
||||
/* remove JFIF if exists */
|
||||
|
||||
/* if we want combined or EXIF */
|
||||
/* check if we don't have EXIF APP1 */
|
||||
/* insert into self->markers list */
|
||||
if (!app1_exif) {
|
||||
/* exif_data = gst_tag_list_to_exif_buffer (tags); */
|
||||
/* insert into self->markers list */
|
||||
}
|
||||
/* else */
|
||||
/* remove EXIF if exists */
|
||||
|
||||
/* add jpeg comment */
|
||||
tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (self));
|
||||
if (tags) {
|
||||
gchar *str = NULL;
|
||||
if (!tags) {
|
||||
tags = gst_tag_list_new ();
|
||||
}
|
||||
/* FIXME: not happy with those
|
||||
* - else where we would use VIDEO_CODEC = "Jpeg"
|
||||
gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
|
||||
GST_TAG_VIDEO_CODEC, "image/jpeg", NULL);
|
||||
*/
|
||||
|
||||
(void) (gst_tag_list_get_string (tags, GST_TAG_COMMENT, &str) ||
|
||||
gst_tag_list_get_string (tags, GST_TAG_DESCRIPTION, &str) ||
|
||||
gst_tag_list_get_string (tags, GST_TAG_TITLE, &str));
|
||||
/* add xmp */
|
||||
xmp_data = gst_tag_list_to_xmp_buffer (tags, FALSE);
|
||||
if (xmp_data) {
|
||||
guint8 *data, *xmp = GST_BUFFER_DATA (xmp_data);
|
||||
guint size = GST_BUFFER_SIZE (xmp_data);
|
||||
GList *pos;
|
||||
|
||||
if (str) {
|
||||
/* insert new marker into self->markers list */
|
||||
m = gst_jif_mux_new_marker (COM, strlen (str) + 1, (const guint8 *) str,
|
||||
TRUE);
|
||||
/* this should go before SOS, maybe at the end of file-header */
|
||||
self->priv->markers = g_list_insert_before (self->priv->markers,
|
||||
frame_hdr, m);
|
||||
data = g_malloc (size + 29);
|
||||
memcpy (data, "http://ns.adobe.com/xap/1.0/\0", 29);
|
||||
memcpy (&data[29], xmp, size);
|
||||
m = gst_jif_mux_new_marker (APP1, size + 29, data, TRUE);
|
||||
|
||||
modified = TRUE;
|
||||
}
|
||||
pos = file_hdr;
|
||||
if (app1_exif)
|
||||
pos = app1_exif;
|
||||
else if (app0_jfif)
|
||||
pos = app0_jfif;
|
||||
pos = g_list_next (pos);
|
||||
|
||||
self->priv->markers = g_list_insert_before (self->priv->markers, pos, m);
|
||||
|
||||
gst_buffer_unref (xmp_data);
|
||||
modified = TRUE;
|
||||
}
|
||||
|
||||
/* add jpeg comment */
|
||||
(void) (gst_tag_list_get_string (tags, GST_TAG_COMMENT, &str) ||
|
||||
gst_tag_list_get_string (tags, GST_TAG_DESCRIPTION, &str) ||
|
||||
gst_tag_list_get_string (tags, GST_TAG_TITLE, &str));
|
||||
|
||||
if (str) {
|
||||
/* insert new marker into self->markers list */
|
||||
m = gst_jif_mux_new_marker (COM, strlen (str) + 1, (const guint8 *) str,
|
||||
TRUE);
|
||||
/* FIXME: if we have one already, replace */
|
||||
/* this should go before SOS, maybe at the end of file-header */
|
||||
self->priv->markers = g_list_insert_before (self->priv->markers,
|
||||
frame_hdr, m);
|
||||
|
||||
modified = TRUE;
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include <string.h>
|
||||
#include <gst/base/gstbytereader.h>
|
||||
#include <gst/tag/tag.h>
|
||||
|
||||
#include "gstjpegparse.h"
|
||||
|
||||
|
@ -557,8 +558,44 @@ gst_jpeg_parse_read_header (GstJpegParse * parse, GstBuffer * buffer)
|
|||
break;
|
||||
}
|
||||
|
||||
case APP1:{
|
||||
const gchar *id_str;
|
||||
if (!gst_byte_reader_get_uint16_be (&reader, &size))
|
||||
goto error;
|
||||
if (!gst_byte_reader_get_string_utf8 (&reader, &id_str))
|
||||
goto error;
|
||||
|
||||
if (!strcmp (id_str, "http://ns.adobe.com/xap/1.0/")) {
|
||||
const guint8 *xmp_data;
|
||||
guint xmp_size = size - 2 - 29;
|
||||
GstTagList *tags;
|
||||
GstBuffer *buf;
|
||||
|
||||
/* handle xmp metadata */
|
||||
if (!gst_byte_reader_get_data (&reader, xmp_size, &xmp_data))
|
||||
goto error;
|
||||
|
||||
buf = gst_buffer_new ();
|
||||
GST_BUFFER_DATA (buf) = (guint8 *) xmp_data;
|
||||
GST_BUFFER_SIZE (buf) = xmp_size;
|
||||
tags = gst_tag_list_from_xmp_buffer (buf);
|
||||
gst_buffer_unref (buf);
|
||||
if (tags) {
|
||||
GST_INFO_OBJECT (parse, "post xmp metadata");
|
||||
gst_element_found_tags_for_pad (GST_ELEMENT_CAST (parse),
|
||||
parse->priv->srcpad, tags);
|
||||
}
|
||||
GST_LOG_OBJECT (parse, "parsed marker %x: '%s' %u bytes",
|
||||
marker, id_str, size - 2);
|
||||
} else {
|
||||
if (!gst_byte_reader_skip (&reader, size - 3 - strlen (id_str)))
|
||||
goto error;
|
||||
GST_LOG_OBJECT (parse, "unhandled marker %x: '%s' skiping %u bytes",
|
||||
marker, id_str, size - 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APP0:
|
||||
case APP1:
|
||||
case APP2:
|
||||
case APP13:
|
||||
case APP14:
|
||||
|
|
Loading…
Reference in a new issue