Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst-libs / gst / riff / riff-read.c
1 /* GStreamer RIFF I/O
2  * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * riff-read.c: RIFF input file parsing
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <string.h>
27 #include <gst/gstutils.h>
28 #include <gst/tag/tag.h>
29
30 #include "riff-read.h"
31
32 GST_DEBUG_CATEGORY_EXTERN (riff_debug);
33 #define GST_CAT_DEFAULT riff_debug
34
35 /**
36  * gst_riff_read_chunk:
37  * @element: caller element (used for debugging).
38  * @pad: pad to pull data from.
39  * @offset: offset to pull from, incremented by this function.
40  * @tag: fourcc of the chunk (returned by this function).
41  * @chunk_data: buffer (returned by this function).
42  *
43  * Reads a single chunk of data. Since 0.10.8 'JUNK' chunks
44  * are skipped automatically.
45  *
46  * Returns: flow status.
47  */
48
49 GstFlowReturn
50 gst_riff_read_chunk (GstElement * element,
51     GstPad * pad, guint64 * _offset, guint32 * tag, GstBuffer ** _chunk_data)
52 {
53   GstBuffer *buf;
54   GstFlowReturn res;
55   GstMapInfo info;
56   guint size;
57   guint64 offset = *_offset;
58
59   g_return_val_if_fail (element != NULL, GST_FLOW_ERROR);
60   g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR);
61   g_return_val_if_fail (_offset != NULL, GST_FLOW_ERROR);
62   g_return_val_if_fail (tag != NULL, GST_FLOW_ERROR);
63   g_return_val_if_fail (_chunk_data != NULL, GST_FLOW_ERROR);
64
65 skip_junk:
66   size = 8;
67   if ((res = gst_pad_pull_range (pad, offset, size, &buf)) != GST_FLOW_OK)
68     return res;
69   else if (gst_buffer_get_size (buf) < size)
70     goto too_small;
71
72   gst_buffer_map (buf, &info, GST_MAP_READ);
73   *tag = GST_READ_UINT32_LE (info.data);
74   size = GST_READ_UINT32_LE (info.data + 4);
75   gst_buffer_unmap (buf, &info);
76   gst_buffer_unref (buf);
77
78   GST_DEBUG_OBJECT (element, "fourcc=%" GST_FOURCC_FORMAT ", size=%u",
79       GST_FOURCC_ARGS (*tag), size);
80
81   /* skip 'JUNK' chunks */
82   if (*tag == GST_RIFF_TAG_JUNK || *tag == GST_RIFF_TAG_JUNQ) {
83     size = GST_ROUND_UP_2 (size);
84     *_offset += 8 + size;
85     offset += 8 + size;
86     GST_DEBUG_OBJECT (element, "skipping JUNK chunk");
87     goto skip_junk;
88   }
89
90   if ((res = gst_pad_pull_range (pad, offset + 8, size, &buf)) != GST_FLOW_OK)
91     return res;
92   else if (gst_buffer_get_size (buf) < size)
93     goto too_small;
94
95   *_chunk_data = buf;
96   *_offset += 8 + GST_ROUND_UP_2 (size);
97
98   return GST_FLOW_OK;
99
100   /* ERRORS */
101 too_small:
102   {
103     /* short read, we return EOS to mark the EOS case */
104     GST_DEBUG_OBJECT (element, "not enough data (available=%" G_GSIZE_FORMAT
105         ", needed=%u)", gst_buffer_get_size (buf), size);
106     gst_buffer_unref (buf);
107     return GST_FLOW_EOS;
108   }
109 }
110
111 /**
112  * gst_riff_parse_chunk:
113  * @element: caller element (used for debugging).
114  * @buf: input buffer.
115  * @offset: offset in the buffer in the caller. Is incremented
116  *          by the read size by this function.
117  * @fourcc: fourcc (returned by this function0 of the chunk.
118  * @chunk_data: buffer (returned by the function) containing the
119  *              chunk data, which may be NULL if chunksize == 0
120  *
121  * Reads a single chunk.
122  *
123  * Returns: FALSE on error, TRUE otherwise
124  */
125 gboolean
126 gst_riff_parse_chunk (GstElement * element, GstBuffer * buf,
127     guint * _offset, guint32 * _fourcc, GstBuffer ** chunk_data)
128 {
129   guint size, bufsize;
130   guint32 fourcc;
131   guint8 *ptr;
132   GstMapInfo info;
133   guint offset = *_offset;
134
135   g_return_val_if_fail (element != NULL, FALSE);
136   g_return_val_if_fail (buf != NULL, FALSE);
137   g_return_val_if_fail (_offset != NULL, FALSE);
138   g_return_val_if_fail (_fourcc != NULL, FALSE);
139   g_return_val_if_fail (chunk_data != NULL, FALSE);
140
141   *chunk_data = NULL;
142   *_fourcc = 0;
143
144   bufsize = gst_buffer_get_size (buf);
145
146   if (bufsize == offset)
147     goto end_offset;
148
149   if (bufsize < offset + 8)
150     goto too_small;
151
152   /* read header */
153   gst_buffer_map (buf, &info, GST_MAP_READ);
154   ptr = info.data + offset;
155   fourcc = GST_READ_UINT32_LE (ptr);
156   size = GST_READ_UINT32_LE (ptr + 4);
157   gst_buffer_unmap (buf, &info);
158
159   GST_DEBUG_OBJECT (element, "fourcc=%" GST_FOURCC_FORMAT ", size=%u",
160       GST_FOURCC_ARGS (fourcc), size);
161
162   /* be paranoid: size may be nonsensical value here, such as (guint) -1 */
163   if (G_UNLIKELY (size > G_MAXINT))
164     goto bogus_size;
165
166   if (bufsize < size + 8 + offset) {
167     GST_DEBUG_OBJECT (element,
168         "Needed chunk data (%d) is more than available (%d), shortcutting",
169         size, bufsize - 8 - offset);
170     size = bufsize - 8 - offset;
171   }
172
173   if (size)
174     *chunk_data =
175         gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset + 8, size);
176   else
177     *chunk_data = NULL;
178
179   *_fourcc = fourcc;
180   *_offset += 8 + GST_ROUND_UP_2 (size);
181
182   return TRUE;
183
184   /* ERRORS */
185 end_offset:
186   {
187     GST_DEBUG_OBJECT (element, "End of chunk (offset %d)", offset);
188     return FALSE;
189   }
190 too_small:
191   {
192     GST_DEBUG_OBJECT (element,
193         "Failed to parse chunk header (offset %d, %d available, %d needed)",
194         offset, bufsize, 8);
195     return FALSE;
196   }
197 bogus_size:
198   {
199     GST_ERROR_OBJECT (element, "Broken file: bogus chunk size %u", size);
200     return FALSE;
201   }
202 }
203
204 /**
205  * gst_riff_parse_file_header:
206  * @element: caller element (used for debugging/error).
207  * @buf: input buffer from which the file header will be parsed,
208  *       should be at least 12 bytes long.
209  * @doctype: a fourcc (returned by this function) to indicate the
210  *           type of document (according to the header).
211  *
212  * Reads the first few bytes from the provided buffer, checks
213  * if this stream is a RIFF stream, and determines document type.
214  * This function takes ownership of @buf so it should not be used anymore
215  * after calling this function.
216  *
217  * Returns: FALSE if this is not a RIFF stream (in which case the
218  * caller should error out; we already throw an error), or TRUE
219  * if it is.
220  */
221 gboolean
222 gst_riff_parse_file_header (GstElement * element,
223     GstBuffer * buf, guint32 * doctype)
224 {
225   GstMapInfo info;
226   guint32 tag;
227
228   g_return_val_if_fail (buf != NULL, FALSE);
229   g_return_val_if_fail (doctype != NULL, FALSE);
230
231   gst_buffer_map (buf, &info, GST_MAP_READ);
232   if (info.size < 12)
233     goto too_small;
234
235   tag = GST_READ_UINT32_LE (info.data);
236   if (tag != GST_RIFF_TAG_RIFF && tag != GST_RIFF_TAG_AVF0)
237     goto not_riff;
238
239   *doctype = GST_READ_UINT32_LE (info.data + 8);
240   gst_buffer_unmap (buf, &info);
241
242   gst_buffer_unref (buf);
243
244   return TRUE;
245
246   /* ERRORS */
247 too_small:
248   {
249     GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
250         ("Not enough data to parse RIFF header (%" G_GSIZE_FORMAT " available,"
251             " %d needed)", info.size, 12));
252     gst_buffer_unmap (buf, &info);
253     gst_buffer_unref (buf);
254     return FALSE;
255   }
256 not_riff:
257   {
258     GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
259         ("Stream is no RIFF stream: %" GST_FOURCC_FORMAT,
260             GST_FOURCC_ARGS (tag)));
261     gst_buffer_unmap (buf, &info);
262     gst_buffer_unref (buf);
263     return FALSE;
264   }
265 }
266
267 /**
268  * gst_riff_parse_strh:
269  * @element: caller element (used for debugging/error).
270  * @buf: input data to be used for parsing, stripped from header.
271  * @strh: a pointer (returned by this function) to a filled-in
272  *        strh structure. Caller should free it.
273  *
274  * Parses a strh structure from input data. Takes ownership of @buf.
275  *
276  * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
277  *          should be skipped on error, but it is not fatal.
278  */
279
280 gboolean
281 gst_riff_parse_strh (GstElement * element,
282     GstBuffer * buf, gst_riff_strh ** _strh)
283 {
284   gst_riff_strh *strh;
285   GstMapInfo info;
286
287   g_return_val_if_fail (buf != NULL, FALSE);
288   g_return_val_if_fail (_strh != NULL, FALSE);
289
290   gst_buffer_map (buf, &info, GST_MAP_READ);
291   if (info.size < sizeof (gst_riff_strh))
292     goto too_small;
293
294   strh = g_memdup (info.data, info.size);
295   gst_buffer_unmap (buf, &info);
296
297   gst_buffer_unref (buf);
298
299 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
300   strh->type = GUINT32_FROM_LE (strh->type);
301   strh->fcc_handler = GUINT32_FROM_LE (strh->fcc_handler);
302   strh->flags = GUINT32_FROM_LE (strh->flags);
303   strh->priority = GUINT32_FROM_LE (strh->priority);
304   strh->init_frames = GUINT32_FROM_LE (strh->init_frames);
305   strh->scale = GUINT32_FROM_LE (strh->scale);
306   strh->rate = GUINT32_FROM_LE (strh->rate);
307   strh->start = GUINT32_FROM_LE (strh->start);
308   strh->length = GUINT32_FROM_LE (strh->length);
309   strh->bufsize = GUINT32_FROM_LE (strh->bufsize);
310   strh->quality = GUINT32_FROM_LE (strh->quality);
311   strh->samplesize = GUINT32_FROM_LE (strh->samplesize);
312 #endif
313
314   /* avoid divisions by zero */
315   if (!strh->scale)
316     strh->scale = 1;
317   if (!strh->rate)
318     strh->rate = 1;
319
320   /* debug */
321   GST_INFO_OBJECT (element, "strh tag found:");
322   GST_INFO_OBJECT (element, " type        %" GST_FOURCC_FORMAT,
323       GST_FOURCC_ARGS (strh->type));
324   GST_INFO_OBJECT (element, " fcc_handler %" GST_FOURCC_FORMAT,
325       GST_FOURCC_ARGS (strh->fcc_handler));
326   GST_INFO_OBJECT (element, " flags       0x%08x", strh->flags);
327   GST_INFO_OBJECT (element, " priority    %d", strh->priority);
328   GST_INFO_OBJECT (element, " init_frames %d", strh->init_frames);
329   GST_INFO_OBJECT (element, " scale       %d", strh->scale);
330   GST_INFO_OBJECT (element, " rate        %d", strh->rate);
331   GST_INFO_OBJECT (element, " start       %d", strh->start);
332   GST_INFO_OBJECT (element, " length      %d", strh->length);
333   GST_INFO_OBJECT (element, " bufsize     %d", strh->bufsize);
334   GST_INFO_OBJECT (element, " quality     %d", strh->quality);
335   GST_INFO_OBJECT (element, " samplesize  %d", strh->samplesize);
336
337   *_strh = strh;
338
339   return TRUE;
340
341   /* ERRORS */
342 too_small:
343   {
344     GST_ERROR_OBJECT (element,
345         "Too small strh (%" G_GSIZE_FORMAT " available, %d needed)",
346         info.size, (int) sizeof (gst_riff_strh));
347     gst_buffer_unmap (buf, &info);
348     gst_buffer_unref (buf);
349     return FALSE;
350   }
351 }
352
353 /**
354  * gst_riff_parse_strf_vids:
355  * @element: caller element (used for debugging/error).
356  * @buf: input data to be used for parsing, stripped from header.
357  * @strf: a pointer (returned by this function) to a filled-in
358  *        strf/vids structure. Caller should free it.
359  * @data: a pointer (returned by this function) to a buffer
360  *        containing extradata for this particular stream (e.g.
361  *        palette, codec initialization data).
362  *
363  * Parses a video streamĀ“s strf structure plus optionally some
364  * extradata from input data. This function takes ownership of @buf.
365  *
366  * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
367  *          should be skipped on error, but it is not fatal.
368  */
369
370 gboolean
371 gst_riff_parse_strf_vids (GstElement * element,
372     GstBuffer * buf, gst_riff_strf_vids ** _strf, GstBuffer ** data)
373 {
374   gst_riff_strf_vids *strf;
375   GstMapInfo info;
376
377   g_return_val_if_fail (buf != NULL, FALSE);
378   g_return_val_if_fail (_strf != NULL, FALSE);
379   g_return_val_if_fail (data != NULL, FALSE);
380
381   gst_buffer_map (buf, &info, GST_MAP_READ);
382   if (info.size < sizeof (gst_riff_strf_vids))
383     goto too_small;
384
385   strf = g_memdup (info.data, info.size);
386   gst_buffer_unmap (buf, &info);
387
388 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
389   strf->size = GUINT32_FROM_LE (strf->size);
390   strf->width = GUINT32_FROM_LE (strf->width);
391   strf->height = GUINT32_FROM_LE (strf->height);
392   strf->planes = GUINT16_FROM_LE (strf->planes);
393   strf->bit_cnt = GUINT16_FROM_LE (strf->bit_cnt);
394   strf->compression = GUINT32_FROM_LE (strf->compression);
395   strf->image_size = GUINT32_FROM_LE (strf->image_size);
396   strf->xpels_meter = GUINT32_FROM_LE (strf->xpels_meter);
397   strf->ypels_meter = GUINT32_FROM_LE (strf->ypels_meter);
398   strf->num_colors = GUINT32_FROM_LE (strf->num_colors);
399   strf->imp_colors = GUINT32_FROM_LE (strf->imp_colors);
400 #endif
401
402   /* size checking */
403   *data = NULL;
404   if (strf->size > info.size) {
405     GST_WARNING_OBJECT (element,
406         "strf_vids header gave %d bytes data, only %" G_GSIZE_FORMAT
407         " available", strf->size, info.size);
408     strf->size = info.size;
409   }
410   if (sizeof (gst_riff_strf_vids) < info.size) {
411     *data =
412         gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
413         sizeof (gst_riff_strf_vids), info.size - sizeof (gst_riff_strf_vids));
414   }
415   gst_buffer_unref (buf);
416
417   /* debug */
418   GST_INFO_OBJECT (element, "strf tag found in context vids:");
419   GST_INFO_OBJECT (element, " size        %d", strf->size);
420   GST_INFO_OBJECT (element, " width       %d", strf->width);
421   GST_INFO_OBJECT (element, " height      %d", strf->height);
422   GST_INFO_OBJECT (element, " planes      %d", strf->planes);
423   GST_INFO_OBJECT (element, " bit_cnt     %d", strf->bit_cnt);
424   GST_INFO_OBJECT (element, " compression %" GST_FOURCC_FORMAT,
425       GST_FOURCC_ARGS (strf->compression));
426   GST_INFO_OBJECT (element, " image_size  %d", strf->image_size);
427   GST_INFO_OBJECT (element, " xpels_meter %d", strf->xpels_meter);
428   GST_INFO_OBJECT (element, " ypels_meter %d", strf->ypels_meter);
429   GST_INFO_OBJECT (element, " num_colors  %d", strf->num_colors);
430   GST_INFO_OBJECT (element, " imp_colors  %d", strf->imp_colors);
431   if (*data)
432     GST_INFO_OBJECT (element, " %" G_GSIZE_FORMAT " bytes extradata",
433         gst_buffer_get_size (*data));
434
435   *_strf = strf;
436
437   return TRUE;
438
439   /* ERRORS */
440 too_small:
441   {
442     GST_ERROR_OBJECT (element,
443         "Too small strf_vids (%" G_GSIZE_FORMAT " available, %d needed)",
444         info.size, (int) sizeof (gst_riff_strf_vids));
445     gst_buffer_unmap (buf, &info);
446     gst_buffer_unref (buf);
447     return FALSE;
448   }
449 }
450
451 /**
452  * gst_riff_parse_strf_auds:
453  * @element: caller element (used for debugging/error).
454  * @buf: input data to be used for parsing, stripped from header.
455  * @strf: a pointer (returned by this function) to a filled-in
456  *        strf/auds structure. Caller should free it.
457  * @data: a pointer (returned by this function) to a buffer
458  *        containing extradata for this particular stream (e.g.
459  *        codec initialization data).
460  *
461  * Parses an audio streamĀ“s strf structure plus optionally some
462  * extradata from input data. This function takes ownership of @buf.
463  * use.
464  *
465  * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
466  *          should be skipped on error, but it is not fatal.
467  */
468 gboolean
469 gst_riff_parse_strf_auds (GstElement * element,
470     GstBuffer * buf, gst_riff_strf_auds ** _strf, GstBuffer ** data)
471 {
472   gst_riff_strf_auds *strf;
473   GstMapInfo info;
474
475   g_return_val_if_fail (buf != NULL, FALSE);
476   g_return_val_if_fail (_strf != NULL, FALSE);
477   g_return_val_if_fail (data != NULL, FALSE);
478
479   gst_buffer_map (buf, &info, GST_MAP_READ);
480   if (info.size < sizeof (gst_riff_strf_auds))
481     goto too_small;
482
483   strf = g_memdup (info.data, info.size);
484
485 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
486   strf->format = GUINT16_FROM_LE (strf->format);
487   strf->channels = GUINT16_FROM_LE (strf->channels);
488   strf->rate = GUINT32_FROM_LE (strf->rate);
489   strf->av_bps = GUINT32_FROM_LE (strf->av_bps);
490   strf->blockalign = GUINT16_FROM_LE (strf->blockalign);
491   strf->size = GUINT16_FROM_LE (strf->size);
492 #endif
493
494   /* size checking */
495   *data = NULL;
496   if (info.size > sizeof (gst_riff_strf_auds) + 2) {
497     gint len;
498
499     len = GST_READ_UINT16_LE (&data[16]);
500     if (len + 2 + sizeof (gst_riff_strf_auds) > info.size) {
501       GST_WARNING_OBJECT (element,
502           "Extradata indicated %d bytes, but only %" G_GSSIZE_FORMAT
503           " available", len, info.size - 2 - sizeof (gst_riff_strf_auds));
504       len = info.size - 2 - sizeof (gst_riff_strf_auds);
505     }
506     if (len)
507       *data = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
508           sizeof (gst_riff_strf_auds) + 2, len);
509   }
510
511   /* debug */
512   GST_INFO_OBJECT (element, "strf tag found in context auds:");
513   GST_INFO_OBJECT (element, " format      %d", strf->format);
514   GST_INFO_OBJECT (element, " channels    %d", strf->channels);
515   GST_INFO_OBJECT (element, " rate        %d", strf->rate);
516   GST_INFO_OBJECT (element, " av_bps      %d", strf->av_bps);
517   GST_INFO_OBJECT (element, " blockalign  %d", strf->blockalign);
518   GST_INFO_OBJECT (element, " size        %d", strf->size);
519   if (*data)
520     GST_INFO_OBJECT (element, " %" G_GSIZE_FORMAT " bytes extradata",
521         gst_buffer_get_size (*data));
522
523   gst_buffer_unmap (buf, &info);
524   gst_buffer_unref (buf);
525
526   *_strf = strf;
527
528   return TRUE;
529
530   /* ERROR */
531 too_small:
532   {
533     GST_ERROR_OBJECT (element,
534         "Too small strf_auds (%" G_GSIZE_FORMAT " available"
535         ", %" G_GSSIZE_FORMAT " needed)", info.size,
536         sizeof (gst_riff_strf_auds));
537     gst_buffer_unmap (buf, &info);
538     gst_buffer_unref (buf);
539     return FALSE;
540   }
541 }
542
543 /**
544  * gst_riff_parse_strf_iavs:
545  * @element: caller element (used for debugging/error).
546  * @buf: input data to be used for parsing, stripped from header.
547  * @strf: a pointer (returned by this function) to a filled-in
548  *        strf/iavs structure. Caller should free it.
549  * @data: a pointer (returned by this function) to a buffer
550  *        containing extradata for this particular stream (e.g.
551  *        codec initialization data).
552  *
553  * Parses a interleaved (also known as "complex")  streamĀ“s strf
554  * structure plus optionally some extradata from input data. This
555  * function takes ownership of @buf.
556  *
557  * Returns: TRUE if parsing succeeded, otherwise FALSE.
558  */
559
560 gboolean
561 gst_riff_parse_strf_iavs (GstElement * element,
562     GstBuffer * buf, gst_riff_strf_iavs ** _strf, GstBuffer ** data)
563 {
564   gst_riff_strf_iavs *strf;
565   GstMapInfo info;
566
567   g_return_val_if_fail (buf != NULL, FALSE);
568   g_return_val_if_fail (_strf != NULL, FALSE);
569   g_return_val_if_fail (data != NULL, FALSE);
570
571   gst_buffer_map (buf, &info, GST_MAP_READ);
572   if (info.size < sizeof (gst_riff_strf_iavs))
573     goto too_small;
574
575   strf = g_memdup (info.data, info.size);
576   gst_buffer_unmap (buf, &info);
577
578   gst_buffer_unref (buf);
579
580 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
581   strf->DVAAuxSrc = GUINT32_FROM_LE (strf->DVAAuxSrc);
582   strf->DVAAuxCtl = GUINT32_FROM_LE (strf->DVAAuxCtl);
583   strf->DVAAuxSrc1 = GUINT32_FROM_LE (strf->DVAAuxSrc1);
584   strf->DVAAuxCtl1 = GUINT32_FROM_LE (strf->DVAAuxCtl1);
585   strf->DVVAuxSrc = GUINT32_FROM_LE (strf->DVVAuxSrc);
586   strf->DVVAuxCtl = GUINT32_FROM_LE (strf->DVVAuxCtl);
587   strf->DVReserved1 = GUINT32_FROM_LE (strf->DVReserved1);
588   strf->DVReserved2 = GUINT32_FROM_LE (strf->DVReserved2);
589 #endif
590
591   /* debug */
592   GST_INFO_OBJECT (element, "strf tag found in context iavs:");
593   GST_INFO_OBJECT (element, " DVAAuxSrc   %08x", strf->DVAAuxSrc);
594   GST_INFO_OBJECT (element, " DVAAuxCtl   %08x", strf->DVAAuxCtl);
595   GST_INFO_OBJECT (element, " DVAAuxSrc1  %08x", strf->DVAAuxSrc1);
596   GST_INFO_OBJECT (element, " DVAAuxCtl1  %08x", strf->DVAAuxCtl1);
597   GST_INFO_OBJECT (element, " DVVAuxSrc   %08x", strf->DVVAuxSrc);
598   GST_INFO_OBJECT (element, " DVVAuxCtl   %08x", strf->DVVAuxCtl);
599   GST_INFO_OBJECT (element, " DVReserved1 %08x", strf->DVReserved1);
600   GST_INFO_OBJECT (element, " DVReserved2 %08x", strf->DVReserved2);
601
602   *_strf = strf;
603   *data = NULL;
604
605   return TRUE;
606
607   /* ERRORS */
608 too_small:
609   {
610     GST_ERROR_OBJECT (element,
611         "Too small strf_iavs (%" G_GSIZE_FORMAT "available"
612         ", %" G_GSSIZE_FORMAT " needed)", info.size,
613         sizeof (gst_riff_strf_iavs));
614     gst_buffer_unmap (buf, &info);
615     gst_buffer_unref (buf);
616     return FALSE;
617   }
618 }
619
620 /**
621  * gst_riff_parse_info:
622  * @element: caller element (used for debugging/error).
623  * @buf: input data to be used for parsing, stripped from header.
624  * @taglist: a pointer to a taglist (returned by this function)
625  *           containing information about this stream. May be
626  *           NULL if no supported tags were found.
627  *
628  * Parses stream metadata from input data.
629  */
630 void
631 gst_riff_parse_info (GstElement * element,
632     GstBuffer * buf, GstTagList ** _taglist)
633 {
634   GstMapInfo info;
635   guint8 *ptr;
636   gsize left;
637   guint tsize;
638   guint32 tag;
639   const gchar *type;
640   GstTagList *taglist;
641
642   g_return_if_fail (_taglist != NULL);
643
644   if (!buf) {
645     *_taglist = NULL;
646     return;
647   }
648   gst_buffer_map (buf, &info, GST_MAP_READ);
649
650   taglist = gst_tag_list_new_empty ();
651
652   ptr = info.data;
653   left = info.size;
654
655   while (left > 8) {
656     tag = GST_READ_UINT32_LE (ptr);
657     tsize = GST_READ_UINT32_LE (ptr + 4);
658     left -= 8;
659     ptr += 8;
660
661     GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u",
662         GST_FOURCC_ARGS (tag), tsize);
663
664     if (tsize > left) {
665       GST_WARNING_OBJECT (element,
666           "Tagsize %d is larger than available data %" G_GSIZE_FORMAT,
667           tsize, left);
668       tsize = left;
669     }
670
671     /* find out the type of metadata */
672     switch (tag) {
673       case GST_RIFF_INFO_IARL:
674         type = GST_TAG_LOCATION;
675         break;
676       case GST_RIFF_INFO_IART:
677         type = GST_TAG_ARTIST;
678         break;
679       case GST_RIFF_INFO_ICMS:
680         type = NULL;            /*"Commissioner"; */
681         break;
682       case GST_RIFF_INFO_ICMT:
683         type = GST_TAG_COMMENT;
684         break;
685       case GST_RIFF_INFO_ICOP:
686         type = GST_TAG_COPYRIGHT;
687         break;
688       case GST_RIFF_INFO_ICRD:
689         type = GST_TAG_DATE;
690         break;
691       case GST_RIFF_INFO_ICRP:
692         type = NULL;            /*"Cropped"; */
693         break;
694       case GST_RIFF_INFO_IDIM:
695         type = NULL;            /*"Dimensions"; */
696         break;
697       case GST_RIFF_INFO_IDPI:
698         type = NULL;            /*"Dots per Inch"; */
699         break;
700       case GST_RIFF_INFO_IENG:
701         type = NULL;            /*"Engineer"; */
702         break;
703       case GST_RIFF_INFO_IGNR:
704         type = GST_TAG_GENRE;
705         break;
706       case GST_RIFF_INFO_IKEY:
707         type = GST_TAG_KEYWORDS;
708         break;
709       case GST_RIFF_INFO_ILGT:
710         type = NULL;            /*"Lightness"; */
711         break;
712       case GST_RIFF_INFO_IMED:
713         type = NULL;            /*"Medium"; */
714         break;
715       case GST_RIFF_INFO_INAM:
716         type = GST_TAG_TITLE;
717         break;
718       case GST_RIFF_INFO_IPLT:
719         type = NULL;            /*"Palette"; */
720         break;
721       case GST_RIFF_INFO_IPRD:
722         type = NULL;            /*"Product"; */
723         break;
724       case GST_RIFF_INFO_ISBJ:
725         type = NULL;            /*"Subject"; */
726         break;
727       case GST_RIFF_INFO_ISFT:
728         type = GST_TAG_ENCODER;
729         break;
730       case GST_RIFF_INFO_ISHP:
731         type = NULL;            /*"Sharpness"; */
732         break;
733       case GST_RIFF_INFO_ISRC:
734         type = GST_TAG_ISRC;
735         break;
736       case GST_RIFF_INFO_ISRF:
737         type = NULL;            /*"Source Form"; */
738         break;
739       case GST_RIFF_INFO_ITCH:
740         type = NULL;            /*"Technician"; */
741         break;
742       default:
743         type = NULL;
744         GST_WARNING_OBJECT (element,
745             "Unknown INFO (metadata) tag entry %" GST_FOURCC_FORMAT,
746             GST_FOURCC_ARGS (tag));
747         break;
748     }
749
750     if (type != NULL && ptr[0] != '\0') {
751       static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING",
752         "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL
753       };
754       gchar *val;
755
756       val = gst_tag_freeform_string_to_utf8 ((gchar *) ptr, tsize, env_vars);
757
758       if (val) {
759         gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL);
760         g_free (val);
761       } else {
762         GST_WARNING_OBJECT (element, "could not extract %s tag", type);
763       }
764     }
765
766     if (tsize & 1) {
767       tsize++;
768       if (tsize > left)
769         tsize = left;
770     }
771
772     ptr += tsize;
773     left -= tsize;
774   }
775
776   if (!gst_tag_list_is_empty (taglist)) {
777     *_taglist = taglist;
778   } else {
779     *_taglist = NULL;
780     gst_tag_list_free (taglist);
781   }
782   gst_buffer_unmap (buf, &info);
783
784   return;
785 }