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