*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
* @tag: fourcc of the chunk (returned by this function).
* @chunk_data: buffer (returned by this function).
*
- * Reads a single chunk of data. Since 0.10.8 'JUNK' chunks
- * are skipped automatically.
+ * Reads a single chunk of data. 'JUNK' chunks are skipped
+ * automatically.
*
* Returns: flow status.
*/
{
GstBuffer *buf;
GstFlowReturn res;
- guint8 *data;
+ GstMapInfo info;
guint size;
guint64 offset = *_offset;
- gsize bsize;
g_return_val_if_fail (element != NULL, GST_FLOW_ERROR);
g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR);
skip_junk:
size = 8;
+ buf = NULL;
if ((res = gst_pad_pull_range (pad, offset, size, &buf)) != GST_FLOW_OK)
return res;
else if (gst_buffer_get_size (buf) < size)
goto too_small;
- data = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
- *tag = GST_READ_UINT32_LE (data);
- size = GST_READ_UINT32_LE (data + 4);
- gst_buffer_unmap (buf, data, bsize);
+ gst_buffer_map (buf, &info, GST_MAP_READ);
+ *tag = GST_READ_UINT32_LE (info.data);
+ size = GST_READ_UINT32_LE (info.data + 4);
+ gst_buffer_unmap (buf, &info);
gst_buffer_unref (buf);
GST_DEBUG_OBJECT (element, "fourcc=%" GST_FOURCC_FORMAT ", size=%u",
goto skip_junk;
}
+ buf = NULL;
if ((res = gst_pad_pull_range (pad, offset + 8, size, &buf)) != GST_FLOW_OK)
return res;
else if (gst_buffer_get_size (buf) < size)
{
guint size, bufsize;
guint32 fourcc;
- guint8 *data, *ptr;
- gsize bsize;
+ guint8 *ptr;
+ GstMapInfo info;
guint offset = *_offset;
g_return_val_if_fail (element != NULL, FALSE);
goto too_small;
/* read header */
- data = ptr = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
- ptr += offset;
+ gst_buffer_map (buf, &info, GST_MAP_READ);
+ ptr = info.data + offset;
fourcc = GST_READ_UINT32_LE (ptr);
size = GST_READ_UINT32_LE (ptr + 4);
- gst_buffer_unmap (buf, data, bsize);
+ gst_buffer_unmap (buf, &info);
GST_DEBUG_OBJECT (element, "fourcc=%" GST_FOURCC_FORMAT ", size=%u",
GST_FOURCC_ARGS (fourcc), size);
gst_riff_parse_file_header (GstElement * element,
GstBuffer * buf, guint32 * doctype)
{
- guint8 *data;
+ GstMapInfo info;
guint32 tag;
- gsize size;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (doctype != NULL, FALSE);
- data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
- if (size < 12)
+ gst_buffer_map (buf, &info, GST_MAP_READ);
+ if (info.size < 12)
goto too_small;
- tag = GST_READ_UINT32_LE (data);
- if (tag != GST_RIFF_TAG_RIFF && tag != GST_RIFF_TAG_AVF0)
+ tag = GST_READ_UINT32_LE (info.data);
+ if (tag != GST_RIFF_TAG_RIFF && tag != GST_RIFF_TAG_AVF0
+ && tag != GST_RIFF_TAG_RF64)
goto not_riff;
- *doctype = GST_READ_UINT32_LE (data + 8);
- gst_buffer_unmap (buf, data, size);
+ *doctype = GST_READ_UINT32_LE (info.data + 8);
+ gst_buffer_unmap (buf, &info);
gst_buffer_unref (buf);
{
GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
("Not enough data to parse RIFF header (%" G_GSIZE_FORMAT " available,"
- " %d needed)", size, 12));
- gst_buffer_unmap (buf, data, size);
+ " %d needed)", info.size, 12));
+ gst_buffer_unmap (buf, &info);
gst_buffer_unref (buf);
return FALSE;
}
not_riff:
{
GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
- ("Stream is no RIFF stream: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (tag)));
- gst_buffer_unmap (buf, data, size);
+ ("Stream is no RIFF stream: 0x%" G_GINT32_MODIFIER "x", tag));
+ gst_buffer_unmap (buf, &info);
gst_buffer_unref (buf);
return FALSE;
}
GstBuffer * buf, gst_riff_strh ** _strh)
{
gst_riff_strh *strh;
- guint8 *data;
- gsize size;
+ GstMapInfo info;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (_strh != NULL, FALSE);
- data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
- if (size < sizeof (gst_riff_strh))
+ gst_buffer_map (buf, &info, GST_MAP_READ);
+ if (info.size < sizeof (gst_riff_strh))
goto too_small;
- strh = g_memdup (data, size);
- gst_buffer_unmap (buf, data, size);
+ strh = g_memdup2 (info.data, info.size);
+ gst_buffer_unmap (buf, &info);
gst_buffer_unref (buf);
{
GST_ERROR_OBJECT (element,
"Too small strh (%" G_GSIZE_FORMAT " available, %d needed)",
- size, (int) sizeof (gst_riff_strh));
- gst_buffer_unmap (buf, data, size);
+ info.size, (int) sizeof (gst_riff_strh));
+ gst_buffer_unmap (buf, &info);
gst_buffer_unref (buf);
return FALSE;
}
* containing extradata for this particular stream (e.g.
* palette, codec initialization data).
*
- * Parses a video stream´s strf structure plus optionally some
+ * Parses a video stream's strf structure plus optionally some
* extradata from input data. This function takes ownership of @buf.
*
* Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
GstBuffer * buf, gst_riff_strf_vids ** _strf, GstBuffer ** data)
{
gst_riff_strf_vids *strf;
- guint8 *bdata;
- gsize size;
+ GstMapInfo info;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (_strf != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
- bdata = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
- if (size < sizeof (gst_riff_strf_vids))
+ gst_buffer_map (buf, &info, GST_MAP_READ);
+ if (info.size < sizeof (gst_riff_strf_vids))
goto too_small;
- strf = g_memdup (bdata, size);
- gst_buffer_unmap (buf, bdata, size);
+ strf = g_memdup2 (info.data, info.size);
+ gst_buffer_unmap (buf, &info);
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
strf->size = GUINT32_FROM_LE (strf->size);
/* size checking */
*data = NULL;
- if (strf->size > size) {
+ if (strf->size > info.size) {
GST_WARNING_OBJECT (element,
"strf_vids header gave %d bytes data, only %" G_GSIZE_FORMAT
- " available", strf->size, size);
- strf->size = size;
+ " available", strf->size, info.size);
+ strf->size = info.size;
}
- if (sizeof (gst_riff_strf_vids) < size) {
+ if (sizeof (gst_riff_strf_vids) < info.size) {
*data =
gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
- sizeof (gst_riff_strf_vids), size - sizeof (gst_riff_strf_vids));
+ sizeof (gst_riff_strf_vids), info.size - sizeof (gst_riff_strf_vids));
}
gst_buffer_unref (buf);
{
GST_ERROR_OBJECT (element,
"Too small strf_vids (%" G_GSIZE_FORMAT " available, %d needed)",
- size, (int) sizeof (gst_riff_strf_vids));
- gst_buffer_unmap (buf, data, size);
+ info.size, (int) sizeof (gst_riff_strf_vids));
+ gst_buffer_unmap (buf, &info);
gst_buffer_unref (buf);
return FALSE;
}
* containing extradata for this particular stream (e.g.
* codec initialization data).
*
- * Parses an audio stream´s strf structure plus optionally some
+ * Parses an audio stream's strf structure plus optionally some
* extradata from input data. This function takes ownership of @buf.
* use.
*
GstBuffer * buf, gst_riff_strf_auds ** _strf, GstBuffer ** data)
{
gst_riff_strf_auds *strf;
- gsize bsize;
- guint8 *bdata;
+ GstMapInfo info;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (_strf != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
- bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
- if (bsize < sizeof (gst_riff_strf_auds))
+ gst_buffer_map (buf, &info, GST_MAP_READ);
+ if (info.size < sizeof (gst_riff_strf_auds))
goto too_small;
- strf = g_memdup (bdata, bsize);
+ strf = g_memdup2 (info.data, info.size);
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
strf->format = GUINT16_FROM_LE (strf->format);
strf->rate = GUINT32_FROM_LE (strf->rate);
strf->av_bps = GUINT32_FROM_LE (strf->av_bps);
strf->blockalign = GUINT16_FROM_LE (strf->blockalign);
- strf->size = GUINT16_FROM_LE (strf->size);
+ strf->bits_per_sample = GUINT16_FROM_LE (strf->bits_per_sample);
#endif
/* size checking */
*data = NULL;
- if (bsize > sizeof (gst_riff_strf_auds) + 2) {
+ if (info.size > sizeof (gst_riff_strf_auds) + 2) {
gint len;
- len = GST_READ_UINT16_LE (&data[16]);
- if (len + 2 + sizeof (gst_riff_strf_auds) > bsize) {
+ len = GST_READ_UINT16_LE (&info.data[16]);
+ if (len + 2 + sizeof (gst_riff_strf_auds) > info.size) {
GST_WARNING_OBJECT (element,
- "Extradata indicated %d bytes, but only %" G_GSSIZE_FORMAT
- " available", len, bsize - 2 - sizeof (gst_riff_strf_auds));
- len = bsize - 2 - sizeof (gst_riff_strf_auds);
+ "Extradata indicated %d bytes, but only %" G_GSIZE_FORMAT
+ " available", len, info.size - 2 - sizeof (gst_riff_strf_auds));
+ len = info.size - 2 - sizeof (gst_riff_strf_auds);
}
if (len)
*data = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
GST_INFO_OBJECT (element, " rate %d", strf->rate);
GST_INFO_OBJECT (element, " av_bps %d", strf->av_bps);
GST_INFO_OBJECT (element, " blockalign %d", strf->blockalign);
- GST_INFO_OBJECT (element, " size %d", strf->size);
+ GST_INFO_OBJECT (element, " bits/sample %d", strf->bits_per_sample);
if (*data)
GST_INFO_OBJECT (element, " %" G_GSIZE_FORMAT " bytes extradata",
gst_buffer_get_size (*data));
- gst_buffer_unmap (buf, bdata, bsize);
+ gst_buffer_unmap (buf, &info);
gst_buffer_unref (buf);
*_strf = strf;
{
GST_ERROR_OBJECT (element,
"Too small strf_auds (%" G_GSIZE_FORMAT " available"
- ", %" G_GSSIZE_FORMAT " needed)", bsize, sizeof (gst_riff_strf_auds));
- gst_buffer_unmap (buf, bdata, bsize);
+ ", %" G_GSIZE_FORMAT " needed)", info.size,
+ sizeof (gst_riff_strf_auds));
+ gst_buffer_unmap (buf, &info);
gst_buffer_unref (buf);
return FALSE;
}
GstBuffer * buf, gst_riff_strf_iavs ** _strf, GstBuffer ** data)
{
gst_riff_strf_iavs *strf;
- gsize bsize;
- guint8 *bdata;
+ GstMapInfo info;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (_strf != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
- bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
- if (bsize < sizeof (gst_riff_strf_iavs))
+ gst_buffer_map (buf, &info, GST_MAP_READ);
+ if (info.size < sizeof (gst_riff_strf_iavs))
goto too_small;
- strf = g_memdup (bdata, bsize);
- gst_buffer_unmap (buf, bdata, bsize);
+ strf = g_memdup2 (info.data, info.size);
+ gst_buffer_unmap (buf, &info);
gst_buffer_unref (buf);
{
GST_ERROR_OBJECT (element,
"Too small strf_iavs (%" G_GSIZE_FORMAT "available"
- ", %" G_GSSIZE_FORMAT " needed)", bsize, sizeof (gst_riff_strf_iavs));
- gst_buffer_unmap (buf, bdata, bsize);
+ ", %" G_GSIZE_FORMAT " needed)", info.size,
+ sizeof (gst_riff_strf_iavs));
+ gst_buffer_unmap (buf, &info);
gst_buffer_unref (buf);
return FALSE;
}
}
+static void
+parse_tag_value (GstElement * element, GstTagList * taglist, const gchar * type,
+ guint8 * ptr, guint tsize)
+{
+ static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING",
+ "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL
+ };
+ GType tag_type;
+ gchar *val;
+
+ tag_type = gst_tag_get_type (type);
+ val = gst_tag_freeform_string_to_utf8 ((gchar *) ptr, tsize, env_vars);
+
+ if (val != NULL) {
+ if (tag_type == G_TYPE_STRING) {
+ gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL);
+ } else {
+ GValue tag_val = { 0, };
+
+ g_value_init (&tag_val, tag_type);
+ if (gst_value_deserialize (&tag_val, val)) {
+ gst_tag_list_add_value (taglist, GST_TAG_MERGE_APPEND, type, &tag_val);
+ } else {
+ GST_WARNING_OBJECT (element, "could not deserialize '%s' into a "
+ "tag %s of type %s", val, type, g_type_name (tag_type));
+ }
+ g_value_unset (&tag_val);
+ }
+ g_free (val);
+ } else {
+ GST_WARNING_OBJECT (element, "could not extract %s tag", type);
+ }
+}
+
/**
* gst_riff_parse_info:
* @element: caller element (used for debugging/error).
gst_riff_parse_info (GstElement * element,
GstBuffer * buf, GstTagList ** _taglist)
{
- guint8 *data, *ptr;
- gsize size, left;
+ GstMapInfo info;
+ guint8 *ptr;
+ gsize left;
guint tsize;
guint32 tag;
const gchar *type;
*_taglist = NULL;
return;
}
- data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ gst_buffer_map (buf, &info, GST_MAP_READ);
taglist = gst_tag_list_new_empty ();
- ptr = data;
- left = size;
+ ptr = info.data;
+ left = info.size;
while (left > 8) {
tag = GST_READ_UINT32_LE (ptr);
tsize = GST_READ_UINT32_LE (ptr + 4);
+
+ GST_MEMDUMP_OBJECT (element, "tag chunk", ptr, MIN (tsize + 8, left));
+
left -= 8;
ptr += 8;
tsize = left;
}
+ /* make uppercase */
+ tag = tag & 0xDFDFDFDF;
+
/* find out the type of metadata */
switch (tag) {
case GST_RIFF_INFO_IARL:
type = GST_TAG_LOCATION;
break;
+ case GST_RIFF_INFO_IAAR:
+ type = GST_TAG_ALBUM_ARTIST;
+ break;
case GST_RIFF_INFO_IART:
type = GST_TAG_ARTIST;
break;
type = GST_TAG_COPYRIGHT;
break;
case GST_RIFF_INFO_ICRD:
- type = GST_TAG_DATE;
+ type = GST_TAG_DATE_TIME;
break;
case GST_RIFF_INFO_ICRP:
type = NULL; /*"Cropped"; */
type = NULL; /*"Palette"; */
break;
case GST_RIFF_INFO_IPRD:
- type = NULL; /*"Product"; */
+ type = GST_TAG_ALBUM;
break;
case GST_RIFF_INFO_ISBJ:
- type = NULL; /*"Subject"; */
+ type = GST_TAG_ALBUM_ARTIST;
break;
case GST_RIFF_INFO_ISFT:
type = GST_TAG_ENCODER;
case GST_RIFF_INFO_ITCH:
type = NULL; /*"Technician"; */
break;
+ case GST_RIFF_INFO_ITRK:
+ type = GST_TAG_TRACK_NUMBER;
+ break;
default:
type = NULL;
GST_WARNING_OBJECT (element,
}
if (type != NULL && ptr[0] != '\0') {
- static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING",
- "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL
- };
- gchar *val;
-
- val = gst_tag_freeform_string_to_utf8 ((gchar *) ptr, tsize, env_vars);
+ GST_DEBUG_OBJECT (element, "mapped tag %" GST_FOURCC_FORMAT " to tag %s",
+ GST_FOURCC_ARGS (tag), type);
- if (val) {
- gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL);
- g_free (val);
- } else {
- GST_WARNING_OBJECT (element, "could not extract %s tag", type);
- }
+ parse_tag_value (element, taglist, type, ptr, tsize);
}
if (tsize & 1) {
}
if (!gst_tag_list_is_empty (taglist)) {
+ GST_INFO_OBJECT (element, "extracted tags: %" GST_PTR_FORMAT, taglist);
*_taglist = taglist;
} else {
*_taglist = NULL;
- gst_tag_list_free (taglist);
+ gst_tag_list_unref (taglist);
}
- gst_buffer_unmap (buf, data, size);
+ gst_buffer_unmap (buf, &info);
return;
}