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