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