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:
parent
ec91719c99
commit
919d3f2f7c
@ -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 */
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user