Add a parser for metadata

Original commit message from CVS:
Add a parser for metadata
(demux_metadata): Given the buffer containing the metadata, look through it and
get the info out of it.
(wav_new_chunk_callback): Change the if statement to a switch statement.
Handle GST_RIFF_TAG_LIST by changing what the type of list it is and parsing out
metadata if it is "INFO".
This commit is contained in:
Iain Holmes 2003-10-17 00:29:44 +00:00
parent ec91719c99
commit 919d3f2f7c
2 changed files with 219 additions and 64 deletions

View File

@ -51,6 +51,7 @@ static void gst_wavparse_chain (GstPad *pad, GstData *_data);
static const GstEventMask* static const GstEventMask*
gst_wavparse_get_event_masks (GstPad *pad); gst_wavparse_get_event_masks (GstPad *pad);
static gboolean gst_wavparse_srcpad_event (GstPad *pad, GstEvent *event); static gboolean gst_wavparse_srcpad_event (GstPad *pad, GstEvent *event);
static void gst_wavparse_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
/* elementfactory information */ /* elementfactory information */
static GstElementDetails gst_wavparse_details = { static GstElementDetails gst_wavparse_details = {
@ -136,8 +137,8 @@ enum {
}; };
enum { enum {
ARG_0, PROP_0,
/* FILL ME */ PROP_METADATA
}; };
static GstElementClass *parent_class = NULL; static GstElementClass *parent_class = NULL;
@ -168,12 +169,21 @@ static void
gst_wavparse_class_init (GstWavParseClass *klass) gst_wavparse_class_init (GstWavParseClass *klass)
{ {
GstElementClass *gstelement_class; GstElementClass *gstelement_class;
GObjectClass *object_class;
gstelement_class = (GstElementClass*) klass; gstelement_class = (GstElementClass*) klass;
object_class = (GObjectClass *) klass;
parent_class = g_type_class_ref (GST_TYPE_ELEMENT); parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
object_class->get_property = gst_wavparse_get_property;
gstelement_class->change_state = gst_wavparse_change_state; gstelement_class->change_state = gst_wavparse_change_state;
g_object_class_install_property (object_class, PROP_METADATA,
g_param_spec_boxed ("metadata",
"Metadata", "Metadata",
GST_TYPE_CAPS,
G_PARAM_READABLE));
} }
static void static void
@ -213,6 +223,26 @@ gst_wavparse_init (GstWavParse *wavparse)
wavparse->need_discont = FALSE; wavparse->need_discont = FALSE;
} }
static void
gst_wavparse_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GstWavParse *wavparse;
wavparse = GST_WAVPARSE (object);
switch (prop_id) {
case PROP_METADATA:
g_value_set_boxed (value, wavparse->metadata);
break;
default:
break;
}
}
static GstCaps* static GstCaps*
wav_type_find (GstByteStream *bs, gpointer private) wav_type_find (GstByteStream *bs, gpointer private)
{ {
@ -237,17 +267,129 @@ wav_type_find (GstByteStream *bs, gpointer private)
return new; return new;
} }
static void
demux_metadata (GstWavParse *wavparse,
const char *data,
int len)
{
gst_riff_chunk *temp_chunk, chunk;
char *name, *type;
GstPropsEntry *entry;
GstProps *props;
props = gst_props_empty_new ();
while (len > 0) {
temp_chunk = (gst_riff_chunk *) data;
chunk.id = GUINT32_FROM_LE (temp_chunk->id);
chunk.size = GUINT32_FROM_LE (temp_chunk->size);
/* move our pointer on past the header */
len -= sizeof (gst_riff_chunk);
data += sizeof (gst_riff_chunk);
if (chunk.size == 0) {
continue;
}
name = g_strndup (data, chunk.size);
/* move our pointer on past the data ... on an even boundary */
len -= ((chunk.size + 1) & ~1);
data += ((chunk.size + 1) & ~1);
/* We now have an info string in 'name' of type chunk.id
- find type */
switch (chunk.id) {
case GST_RIFF_INFO_IARL:
type = "Location";
break;
case GST_RIFF_INFO_IART:
type = "Artist";
break;
case GST_RIFF_INFO_ICMS:
type = "Commissioner";
break;
case GST_RIFF_INFO_ICMT:
type = "Comment";
break;
case GST_RIFF_INFO_ICOP:
type = "Copyright";
break;
case GST_RIFF_INFO_ICRD:
type = "Creation Date";
break;
case GST_RIFF_INFO_IENG:
type = "Engineer";
break;
case GST_RIFF_INFO_IGNR:
type = "Genre";
break;
case GST_RIFF_INFO_IKEY:
type = "Keywords";
break;
case GST_RIFF_INFO_INAM:
type = "Title"; /* name */
break;
case GST_RIFF_INFO_IPRD:
type = "Product";
break;
case GST_RIFF_INFO_ISBJ:
type = "Subject";
break;
case GST_RIFF_INFO_ISFT:
type = "Software";
break;
case GST_RIFF_INFO_ITCH:
type = "Technician";
break;
default:
type = NULL;
break;
}
if (type) {
entry = gst_props_entry_new (type, GST_PROPS_STRING (name));
gst_props_add_entry (props, entry);
}
g_free (name);
}
gst_caps_replace_sink (&wavparse->metadata,
gst_caps_new ("wav_metadata",
"application/x-gst-metadata",
props));
g_object_notify (G_OBJECT (wavparse), "metadata");
}
static void wav_new_chunk_callback(GstRiffChunk *chunk, gpointer data) static void wav_new_chunk_callback(GstRiffChunk *chunk, gpointer data)
{ {
GstWavParse *wavparse; GstWavParse *wavparse;
GstWavParseFormat *format;
GstCaps *caps = NULL;
wavparse = GST_WAVPARSE (data); wavparse = GST_WAVPARSE (data);
GST_DEBUG("new tag " GST_FOURCC_FORMAT "\n", GST_FOURCC_ARGS(chunk->id)); GST_DEBUG("new tag " GST_FOURCC_FORMAT "\n", GST_FOURCC_ARGS(chunk->id));
if(chunk->id == GST_RIFF_TAG_fmt){ switch (chunk->id) {
GstWavParseFormat *format; case GST_RIFF_TAG_fmt:
GstCaps *caps = NULL;
/* we can gather format information now */ /* we can gather format information now */
format = (GstWavParseFormat *)((guchar *) GST_BUFFER_DATA (wavparse->buf) + chunk->offset); format = (GstWavParseFormat *)((guchar *) GST_BUFFER_DATA (wavparse->buf) + chunk->offset);
@ -260,8 +402,7 @@ static void wav_new_chunk_callback(GstRiffChunk *chunk, gpointer data)
/* set the caps on the src pad */ /* set the caps on the src pad */
/* FIXME: handle all of the other formats as well */ /* FIXME: handle all of the other formats as well */
switch (wavparse->format) switch (wavparse->format) {
{
case GST_RIFF_WAVE_FORMAT_ALAW: case GST_RIFF_WAVE_FORMAT_ALAW:
case GST_RIFF_WAVE_FORMAT_MULAW: { case GST_RIFF_WAVE_FORMAT_MULAW: {
gchar *mime = (wavparse->format == GST_RIFF_WAVE_FORMAT_ALAW) ? gchar *mime = (wavparse->format == GST_RIFF_WAVE_FORMAT_ALAW) ?
@ -279,6 +420,7 @@ static void wav_new_chunk_callback(GstRiffChunk *chunk, gpointer data)
); );
} }
break; break;
case GST_RIFF_WAVE_FORMAT_PCM: case GST_RIFF_WAVE_FORMAT_PCM:
caps = GST_CAPS_NEW ( caps = GST_CAPS_NEW (
"parsewav_src", "parsewav_src",
@ -319,8 +461,18 @@ static void wav_new_chunk_callback(GstRiffChunk *chunk, gpointer data)
/* we're now looking for the data chunk */ /* we're now looking for the data chunk */
wavparse->state = GST_WAVPARSE_CHUNK_DATA; wavparse->state = GST_WAVPARSE_CHUNK_DATA;
} break;
case GST_RIFF_TAG_LIST:
if (strncmp (chunk->data, "INFO", 4) == 0) {
/* We got metadata */
demux_metadata (wavparse, chunk->data + 4, chunk->size - 4);
}
break;
default:
break;
}
} }
static void static void
@ -405,11 +557,11 @@ gst_wavparse_chain (GstPad *pad, GstData *_data)
if (wavparse->state == GST_WAVPARSE_OTHER) { if (wavparse->state == GST_WAVPARSE_OTHER) {
GST_DEBUG ("we're in unknown territory here, not passing on"); GST_DEBUG ("we're in unknown territory here, not passing on");
gst_buffer_unref(buf); gst_buffer_unref(buf);
return; return;
} }
/* here we deal with parsing out the primary state */ /* here we deal with parsing out the primary state */
/* these are sequenced such that in the normal case each (RIFF/WAVE, /* these are sequenced such that in the normal case each (RIFF/WAVE,
fmt, data) will fire in sequence, as they should */ fmt, data) will fire in sequence, as they should */

View File

@ -83,6 +83,8 @@ struct _GstWavParse {
gboolean need_discont; gboolean need_discont;
GstBuffer *buf; GstBuffer *buf;
GstCaps *metadata;
}; };
struct _GstWavParseClass { struct _GstWavParseClass {
@ -102,6 +104,7 @@ struct _GstWavParseFormat {
guint16 wBitsPerSample; guint16 wBitsPerSample;
}; };
/**** from public Microsoft RIFF docs ******/ /**** from public Microsoft RIFF docs ******/
#define GST_RIFF_WAVE_FORMAT_UNKNOWN (0x0000) #define GST_RIFF_WAVE_FORMAT_UNKNOWN (0x0000)
#define GST_RIFF_WAVE_FORMAT_PCM (0x0001) #define GST_RIFF_WAVE_FORMAT_PCM (0x0001)