rtsp-server:wfd: Fix build error for gcc upgrade
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst / asfmux / gstasfobjects.c
1 /* ASF muxer plugin for GStreamer
2  * Copyright (C) 2009 Thiago Santos <thiagoss@embedded.ufcg.edu.br>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "gstasfobjects.h"
21 #include <string.h>
22
23 /* Guids */
24 const Guid guids[] = {
25   /* asf header object */
26   {0x75B22630, 0x668E, 0x11CF, G_GUINT64_CONSTANT (0xA6D900AA0062CE6C)},
27   /* asf file properties object */
28   {0x8CABDCA1, 0xA947, 0x11CF, G_GUINT64_CONSTANT (0x8EE400C00C205365)},
29   /* asf stream properties object */
30   {0xB7DC0791, 0xA9B7, 0x11CF, G_GUINT64_CONSTANT (0x8EE600C00C205365)},
31   /* asf audio media */
32   {0xF8699E40, 0x5B4D, 0x11CF, G_GUINT64_CONSTANT (0xA8FD00805F5C442B)},
33   /* asf no error correction */
34   {0x20FB5700, 0x5B55, 0x11CF, G_GUINT64_CONSTANT (0xA8FD00805F5C442B)},
35   /* asf audio spread */
36   {0xBFC3CD50, 0x618F, 0x11CF, G_GUINT64_CONSTANT (0x8BB200AA00B4E220)},
37   /* asf header extension object */
38   {0x5FBF03B5, 0xA92E, 0x11CF, G_GUINT64_CONSTANT (0x8EE300C00C205365)},
39   /* asf reserved 1 */
40   {0xABD3D211, 0xA9BA, 0x11CF, G_GUINT64_CONSTANT (0x8EE600C00C205365)},
41   /* asf data object */
42   {0x75B22636, 0x668E, 0x11CF, G_GUINT64_CONSTANT (0xA6D900AA0062CE6C)},
43   /* asf extended stream properties object */
44   {0x14E6A5CB, 0xC672, 0x4332, G_GUINT64_CONSTANT (0x8399A96952065B5A)},
45   /* asf video media */
46   {0xBC19EFC0, 0x5B4D, 0x11CF, G_GUINT64_CONSTANT (0xA8FD00805F5C442B)},
47   /* asf simple index object */
48   {0x33000890, 0xE5B1, 0x11CF, G_GUINT64_CONSTANT (0x89F400A0C90349CB)},
49   /* asf content description */
50   {0x75B22633, 0x668E, 0x11CF, G_GUINT64_CONSTANT (0xA6D900AA0062CE6C)},
51   /* asf extended content description */
52   {0xD2D0A440, 0xE307, 0x11D2, G_GUINT64_CONSTANT (0x97F000A0C95EA850)},
53   /* asf metadata object */
54   {0xC5F8CBEA, 0x5BAF, 0x4877, G_GUINT64_CONSTANT (0x8467AA8C44FA4CCA)},
55   /* asf padding object */
56   {0x1806D474, 0xCADF, 0x4509, G_GUINT64_CONSTANT (0xA4BA9AABCB96AAE8)}
57 };
58
59 /**
60  * gst_asf_generate_file_id:
61  *
62  * Generates a random GUID
63  *
64  * Returns: The generated GUID
65  */
66 void
67 gst_asf_generate_file_id (Guid * guid)
68 {
69   guint32 aux;
70
71   guid->v1 = g_random_int ();
72   aux = g_random_int ();
73   guid->v2 = (guint16) (aux & 0x0000FFFF);
74   guid->v3 = (guint16) (aux >> 16);
75   guid->v4 = (((guint64) g_random_int ()) << 32) | (guint64) g_random_int ();
76 }
77
78 /**
79  * gst_byte_reader_get_asf_var_size_field:
80  * @reader: A #GstByteReader
81  * @field_type: an asf field type
82  * @var: pointer to store the result
83  *
84  * Reads the proper data from the #GstByteReader according to the
85  * asf field type and stores it in var
86  *
87  * Returns: True on success, false otherwise
88  */
89 gboolean
90 gst_byte_reader_get_asf_var_size_field (GstByteReader * reader,
91     guint8 field_type, guint32 * var)
92 {
93   guint8 aux8 = 0;
94   guint16 aux16 = 0;
95   guint32 aux32 = 0;
96   gboolean ret;
97
98   switch (field_type) {
99     case ASF_FIELD_TYPE_DWORD:
100       ret = gst_byte_reader_get_uint32_le (reader, &aux32);
101       *var = aux32;
102       break;
103     case ASF_FIELD_TYPE_WORD:
104       ret = gst_byte_reader_get_uint16_le (reader, &aux16);
105       *var = aux16;
106       break;
107     case ASF_FIELD_TYPE_BYTE:
108       ret = gst_byte_reader_get_uint8 (reader, &aux8);
109       *var = aux8;
110       break;
111     case ASF_FIELD_TYPE_NONE:
112       ret = TRUE;
113       *var = 0;
114       break;
115     default:
116       return FALSE;
117   }
118   return ret;
119 }
120
121 /**
122  * gst_asf_read_var_size_field:
123  * @data: pointer to the data to be read
124  * @field_type: the asf field type pointed by data
125  *
126  * Reads and returns the value read from the data, according to the
127  * field type given
128  *
129  * Returns: The value read
130  */
131 guint32
132 gst_asf_read_var_size_field (guint8 * data, guint8 field_type)
133 {
134   switch (field_type) {
135     case ASF_FIELD_TYPE_DWORD:
136       return GST_READ_UINT32_LE (data);
137     case ASF_FIELD_TYPE_WORD:
138       return GST_READ_UINT16_LE (data);
139     case ASF_FIELD_TYPE_BYTE:
140       return data[0];
141     default:
142       return 0;
143   }
144 }
145
146 /**
147  * gst_asf_get_var_size_field_len:
148  * @field_type: the asf field type
149  *
150  * Returns: the size in bytes of a variable of field_type type
151  */
152 guint
153 gst_asf_get_var_size_field_len (guint8 field_type)
154 {
155   switch (field_type) {
156     case ASF_FIELD_TYPE_DWORD:
157       return 4;
158     case ASF_FIELD_TYPE_WORD:
159       return 2;
160     case ASF_FIELD_TYPE_BYTE:
161       return 1;
162     default:
163       return 0;
164   }
165 }
166
167 /**
168  * gst_asf_file_info_new:
169  *
170  * Creates a new #GstAsfFileInfo
171  *
172  * Returns: the created struct
173  */
174 GstAsfFileInfo *
175 gst_asf_file_info_new (void)
176 {
177   return g_new0 (GstAsfFileInfo, 1);
178 }
179
180 /**
181  * gst_asf_file_info_reset:
182  * @info: the #GstAsfFileInfo to be reset
183  *
184  * resets the data of a #GstFileInfo
185  */
186 void
187 gst_asf_file_info_reset (GstAsfFileInfo * info)
188 {
189   info->packet_size = 0;
190   info->packets_count = 0;
191   info->broadcast = FALSE;
192 }
193
194 /**
195  * gst_asf_file_info_free:
196  * @info: the #GstAsfFileInfo to be freed
197  *
198  * Releases memory associated with this #GstAsfFileInfo
199  */
200 void
201 gst_asf_file_info_free (GstAsfFileInfo * info)
202 {
203   g_free (info);
204 }
205
206 /**
207  * gst_asf_payload_get_size:
208  * @payload: the payload to get the size from
209  *
210  * Returns: the size of an asf payload of the data represented by this
211  * #AsfPayload
212  */
213 guint32
214 gst_asf_payload_get_size (AsfPayload * payload)
215 {
216   return ASF_MULTIPLE_PAYLOAD_HEADER_SIZE + gst_buffer_get_size (payload->data);
217 }
218
219 /**
220  * gst_asf_payload_free:
221  * @payload: the #AsfPayload to be freed
222  *
223  * Releases the memory associated with this payload
224  */
225 void
226 gst_asf_payload_free (AsfPayload * payload)
227 {
228   gst_buffer_unref (payload->data);
229   g_free (payload);
230 }
231
232 /**
233  * gst_asf_get_current_time:
234  *
235  * Gets system current time in ASF time unit
236  * (100-nanoseconds since Jan, 1st 1601)
237  *
238  * Returns:
239  */
240 guint64
241 gst_asf_get_current_time (void)
242 {
243   gint64 now;
244   guint64 secs;
245   guint64 usecs;
246
247   now = g_get_real_time ();
248
249   secs = (guint64) now / G_USEC_PER_SEC;
250   usecs = (guint64) now % G_USEC_PER_SEC;
251   return secs * G_GUINT64_CONSTANT (10000000) + usecs * 10
252       + G_GUINT64_CONSTANT (116444628000000000);
253 }
254
255 /**
256  * gst_asf_match_guid:
257  * @data: pointer to the guid to be tested
258  * @guid: guid to match against data
259  *
260  * Checks if the guid pointed by data is the same
261  * as the guid parameter
262  *
263  * Returns: True if they are the same, false otherwise
264  */
265 gboolean
266 gst_asf_match_guid (const guint8 * data, const Guid * guid)
267 {
268   Guid g;
269   g.v1 = GST_READ_UINT32_LE (data);
270   g.v2 = GST_READ_UINT16_LE (data + 4);
271   g.v3 = GST_READ_UINT16_LE (data + 6);
272   g.v4 = GST_READ_UINT64_BE (data + 8);
273
274   return g.v1 == guid->v1 &&
275       g.v2 == guid->v2 && g.v3 == guid->v3 && g.v4 == guid->v4;
276 }
277
278 /**
279  * gst_asf_put_i32:
280  * @buf: the memory to write data to
281  * @data: the value to be written
282  *
283  * Writes a 32 bit signed integer to memory
284  */
285 void
286 gst_asf_put_i32 (guint8 * buf, gint32 data)
287 {
288   GST_WRITE_UINT32_LE (buf, (guint32) data);
289 }
290
291 /**
292  * gst_asf_put_time:
293  * @buf: pointer to the buffer to write the value to
294  * @time: value to be written
295  *
296  * Writes an asf time value to the buffer
297  */
298 void
299 gst_asf_put_time (guint8 * buf, guint64 time)
300 {
301   GST_WRITE_UINT64_LE (buf, time);
302 }
303
304 /**
305  * gst_asf_put_guid:
306  * @buf: the buffer to write the guid to
307  * @guid: the guid to be written
308  *
309  * Writes a GUID to the buffer
310  */
311 void
312 gst_asf_put_guid (guint8 * buf, Guid guid)
313 {
314   GST_WRITE_UINT32_LE (buf + 0, guid.v1);
315   GST_WRITE_UINT16_LE (buf + 4, guid.v2);
316   GST_WRITE_UINT16_LE (buf + 6, guid.v3);
317   GST_WRITE_UINT64_BE (buf + 8, guid.v4);
318 }
319
320 /**
321  * gst_asf_put_payload:
322  * @buf: memory to write the payload to
323  * @payload: #AsfPayload to be written
324  *
325  * Writes the asf payload to the buffer. The #AsfPayload
326  * packet count is incremented.
327  */
328 void
329 gst_asf_put_payload (guint8 * buf, AsfPayload * payload)
330 {
331   GST_WRITE_UINT8 (buf, payload->stream_number);
332   GST_WRITE_UINT8 (buf + 1, payload->media_obj_num);
333   GST_WRITE_UINT32_LE (buf + 2, payload->offset_in_media_obj);
334   GST_WRITE_UINT8 (buf + 6, payload->replicated_data_length);
335   GST_WRITE_UINT32_LE (buf + 7, payload->media_object_size);
336   GST_WRITE_UINT32_LE (buf + 11, payload->presentation_time);
337   GST_WRITE_UINT16_LE (buf + 15, (guint16) gst_buffer_get_size (payload->data));
338   gst_buffer_extract (payload->data, 0, buf + 17,
339       gst_buffer_get_size (payload->data));
340
341   payload->packet_count++;
342 }
343
344 /**
345  * gst_asf_put_subpayload:
346  * @buf: buffer to write the payload to
347  * @payload: the payload to be written
348  * @size: maximum size in bytes to write
349  *
350  * Serializes part of a payload to a buffer.
351  * The maximum size is checked against the payload length,
352  * the minimum of this size and the payload length is written
353  * to the buffer and the written size is returned.
354  *
355  * It also updates the values of the payload to match the remaining
356  * data.
357  * In case there is not enough space to write the headers, nothing is done.
358  *
359  * Returns: The written size in bytes.
360  */
361 guint16
362 gst_asf_put_subpayload (guint8 * buf, AsfPayload * payload, guint16 size)
363 {
364   guint16 payload_size;
365   GstBuffer *newbuf;
366   if (size <= ASF_MULTIPLE_PAYLOAD_HEADER_SIZE) {
367     return 0;                   /* do nothing if there is not enough space */
368   }
369   GST_WRITE_UINT8 (buf, payload->stream_number);
370   GST_WRITE_UINT8 (buf + 1, payload->media_obj_num);
371   GST_WRITE_UINT32_LE (buf + 2, payload->offset_in_media_obj);
372   GST_WRITE_UINT8 (buf + 6, payload->replicated_data_length);
373   GST_WRITE_UINT32_LE (buf + 7, payload->media_object_size);
374   GST_WRITE_UINT32_LE (buf + 11, payload->presentation_time);
375   size -= ASF_MULTIPLE_PAYLOAD_HEADER_SIZE;
376   payload_size = size < gst_buffer_get_size (payload->data) ?
377       size : gst_buffer_get_size (payload->data);
378   GST_WRITE_UINT16_LE (buf + 15, payload_size);
379   gst_buffer_extract (payload->data, 0, buf + 17, payload_size);
380
381   /* updates the payload to the remaining data */
382   payload->offset_in_media_obj += payload_size;
383   newbuf = gst_buffer_copy_region (payload->data, GST_BUFFER_COPY_ALL,
384       payload_size, gst_buffer_get_size (payload->data) - payload_size);
385   GST_BUFFER_TIMESTAMP (newbuf) = GST_BUFFER_TIMESTAMP (payload->data);
386   gst_buffer_unref (payload->data);
387   payload->data = newbuf;
388
389   payload->packet_count++;
390
391   return payload_size;
392 }
393
394 /**
395  * gst_asf_match_and_peek_obj_size:
396  * @data: data to be peeked at
397  * @guid: pointer to a guid
398  *
399  * Compares the first bytes of data against the guid parameter and
400  * if they match gets the object size (that are right after the guid in
401  * asf objects).
402  *
403  * In case the guids don't match, 0 is returned.
404  * If the guid is NULL the match is assumed to be true.
405  *
406  * Returns: The size of the object in case the guid matches, 0 otherwise
407  */
408 guint64
409 gst_asf_match_and_peek_obj_size (const guint8 * data, const Guid * guid)
410 {
411   g_assert (data);
412   if (guid && !gst_asf_match_guid (data, guid)) {
413     /* this is not the expected object */
414     return 0;
415   }
416   /* return the object size */
417   return GST_READ_UINT64_LE (data + ASF_GUID_SIZE);
418 }
419
420 /**
421  * gst_asf_match_and_peek_obj_size_buf:
422  * @buf: buffer to be peeked at
423  * @guid: pointer to a guid
424  *
425  * Compares the first bytes of buf against the guid parameter and
426  * if they match gets the object size (that are right after the guid in
427  * asf objects).
428  *
429  * In case the guids don't match, 0 is returned.
430  * If the guid is NULL the match is assumed to be true.
431  *
432  * Returns: The size of the object in case the guid matches, 0 otherwise
433  */
434 guint64
435 gst_asf_match_and_peek_obj_size_buf (GstBuffer * buf, const Guid * guid)
436 {
437   GstMapInfo map;
438   guint64 res;
439
440   gst_buffer_map (buf, &map, GST_MAP_READ);
441   res = gst_asf_match_and_peek_obj_size (map.data, guid);
442   gst_buffer_unmap (buf, &map);
443
444   return res;
445 }
446
447 /**
448  * gst_asf_parse_mult_payload:
449  * @reader: a #GstByteReader ready to read the multiple payload data
450  * @has_keyframe: pointer to return the result
451  *
452  * Parses a multiple payload section of an asf data packet
453  * to see if any of the paylaods has a a keyframe
454  *
455  * Notice that the #GstByteReader might not be positioned after
456  * this section on this function return. Because this section
457  * is the last one in an asf packet and the remaining data
458  * is probably uninteresting to the application.
459  *
460  * Returns: true on success, false if some error occurs
461  */
462 static gboolean
463 gst_asf_parse_mult_payload (GstByteReader * reader, gboolean * has_keyframe)
464 {
465   guint payloads;
466   guint8 payload_len_type;
467   guint8 rep_data_len = 0;
468   guint32 payload_len;
469   guint8 stream_num = 0;
470   guint8 aux = 0;
471   guint i;
472
473   if (!gst_byte_reader_get_uint8 (reader, &aux))
474     return FALSE;
475
476   payloads = (aux & 0x3F);
477   payload_len_type = (aux & 0xC0) >> 6;
478
479   *has_keyframe = FALSE;
480   for (i = 0; i < payloads; i++) {
481     GST_LOG ("Parsing payload %u/%u", i + 1, payloads);
482     if (!gst_byte_reader_get_uint8 (reader, &stream_num))
483       goto error;
484     if ((stream_num & 0x80) != 0) {
485       GST_LOG ("Keyframe found, stopping parse of payloads");
486       *has_keyframe = TRUE;
487       return TRUE;
488     }
489     /* skip to replicated data length */
490     if (!gst_byte_reader_skip (reader, 5))
491       goto error;
492     if (!gst_byte_reader_get_uint8 (reader, &rep_data_len))
493       goto error;
494     if (!gst_byte_reader_skip (reader, rep_data_len))
495       goto error;
496     if (!gst_byte_reader_get_asf_var_size_field (reader, payload_len_type,
497             &payload_len))
498       goto error;
499     if (!gst_byte_reader_skip (reader, payload_len))
500       goto error;
501   }
502
503   /* we do not skip the rest of the payload bytes as
504      this is the last data to be parsed on the buffer */
505   return TRUE;
506 error:
507   GST_WARNING ("Error while parsing payloads");
508   return FALSE;
509 }
510
511 /**
512  * gst_asf_parse_single_payload:
513  * @reader: a #GstByteReader ready to read the multiple payload data
514  * @has_keyframe: pointer to return the result
515  *
516  * Parses a single payload section of an asf data packet
517  * to see if any of the paylaods has a a keyframe
518  *
519  * Notice that the #GstByteReader might not be positioned after
520  * this section on this function return. Because this section
521  * is the last one in an asf packet and the remaining data
522  * is probably uninteresting to the application.
523  *
524  * Returns: true on success, false if some error occurs
525  */
526 static gboolean
527 gst_asf_parse_single_payload (GstByteReader * reader, gboolean * has_keyframe)
528 {
529   guint8 stream_num = 0;
530   if (!gst_byte_reader_get_uint8 (reader, &stream_num))
531     return GST_FLOW_ERROR;
532   *has_keyframe = (stream_num & 0x80) != 0;
533
534   /* we do not skip the rest of the payload bytes as
535      this is the last data to be parsed on the buffer */
536   return TRUE;
537 }
538
539 gboolean
540 gst_asf_parse_packet (GstBuffer * buffer, GstAsfPacketInfo * packet,
541     gboolean trust_delta_flag, guint packet_size)
542 {
543   gboolean ret;
544   GstMapInfo map;
545
546   gst_buffer_map (buffer, &map, GST_MAP_READ);
547   ret = gst_asf_parse_packet_from_data (map.data, map.size, buffer, packet,
548       trust_delta_flag, packet_size);
549   gst_buffer_unmap (buffer, &map);
550
551   return ret;
552 }
553
554 gboolean
555 gst_asf_parse_packet_from_data (guint8 * data, gsize size, GstBuffer * buffer,
556     GstAsfPacketInfo * packet, gboolean trust_delta_flag, guint packet_size)
557 {
558 /* Might be useful in future:
559   guint8 rep_data_len_type;
560   guint8 mo_number_len_type;
561   guint8 mo_offset_type;
562 */
563   GstByteReader reader;
564   gboolean ret = TRUE;
565   guint8 first = 0;
566   guint8 err_length = 0;        /* length of the error fields */
567   guint8 aux = 0;
568   guint8 packet_len_type;
569   guint8 padding_len_type;
570   guint8 seq_len_type;
571   gboolean mult_payloads;
572   guint32 packet_len;
573   guint32 padd_len;
574   guint32 send_time = 0;
575   guint16 duration = 0;
576   gboolean has_keyframe;
577
578   if (packet_size != 0 && size != packet_size) {
579     GST_WARNING ("ASF packets should be aligned with buffers");
580     return FALSE;
581   }
582
583   gst_byte_reader_init (&reader, data, size);
584
585   GST_LOG ("Starting packet parsing, size: %" G_GSIZE_FORMAT, size);
586   if (!gst_byte_reader_get_uint8 (&reader, &first))
587     goto error;
588
589   if (first & 0x80) {           /* error correction present */
590     guint8 err_cor_len;
591     err_length += 1;
592     GST_DEBUG ("Packet contains error correction");
593     if (first & 0x60) {
594       GST_ERROR ("Error correction data length should be "
595           "set to 0 and is reserved for future use.");
596       goto error;
597     }
598     err_cor_len = (first & 0x0F);
599     err_length += err_cor_len;
600     GST_DEBUG ("Error correction data length: %d", (gint) err_cor_len);
601     if (!gst_byte_reader_skip (&reader, err_cor_len))
602       goto error;
603
604     /* put payload parsing info first byte in aux var */
605     if (!gst_byte_reader_get_uint8 (&reader, &aux))
606       goto error;
607   } else {
608     aux = first;
609   }
610   mult_payloads = (aux & 0x1) != 0;
611
612   packet_len_type = (aux >> 5) & 0x3;
613   padding_len_type = (aux >> 3) & 0x3;
614   seq_len_type = (aux >> 1) & 0x3;
615   GST_LOG ("Field sizes: packet length type: %u "
616       ", padding length type: %u, sequence length type: %u",
617       gst_asf_get_var_size_field_len (packet_len_type),
618       gst_asf_get_var_size_field_len (padding_len_type),
619       gst_asf_get_var_size_field_len (seq_len_type));
620
621   if (mult_payloads) {
622     GST_DEBUG ("Packet contains multiple payloads");
623   }
624
625   if (!gst_byte_reader_get_uint8 (&reader, &aux))
626     goto error;
627
628 /*
629   rep_data_len_type = aux & 0x3;
630   mo_offset_type = (aux >> 2) & 0x3;
631   mo_number_len_type = (aux >> 4) & 0x3;
632 */
633
634   /* gets the fields lengths */
635   GST_LOG ("Getting packet and padding length");
636   if (!gst_byte_reader_get_asf_var_size_field (&reader,
637           packet_len_type, &packet_len))
638     goto error;
639   if (!gst_byte_reader_skip (&reader,
640           gst_asf_get_var_size_field_len (seq_len_type)))
641     goto error;
642   if (!gst_byte_reader_get_asf_var_size_field (&reader,
643           padding_len_type, &padd_len))
644     goto error;
645
646   /* some packet size validation */
647   if (packet_size != 0 && packet_len_type != ASF_FIELD_TYPE_NONE) {
648     if (padding_len_type != ASF_FIELD_TYPE_NONE &&
649         packet_len + padd_len != packet_size) {
650       GST_WARNING ("Packet size (payload=%u + padding=%u) doesn't "
651           "match expected size %u", packet_len, padd_len, packet_size);
652       ret = FALSE;
653     }
654
655     /* Be forgiving if packet_len has the full packet size
656      * as the spec isn't really clear on its meaning.
657      *
658      * I had been taking it as the full packet size (fixed)
659      * until bug #607555, that convinced me that it is more likely
660      * the actual payloaded data size.
661      */
662     if (packet_len == packet_size) {
663       GST_DEBUG ("This packet's length field represents the full "
664           "packet and not the payloaded data length");
665       ret = TRUE;
666     }
667
668     if (!ret)
669       goto end;
670   }
671
672   GST_LOG ("Getting send time and duration");
673   if (!gst_byte_reader_get_uint32_le (&reader, &send_time))
674     goto error;
675   if (!gst_byte_reader_get_uint16_le (&reader, &duration))
676     goto error;
677
678   has_keyframe = FALSE;
679   GST_LOG ("Checking for keyframes");
680   if (trust_delta_flag) {
681     has_keyframe = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
682   } else {
683     if (mult_payloads) {
684       ret = gst_asf_parse_mult_payload (&reader, &has_keyframe);
685     } else {
686       ret = gst_asf_parse_single_payload (&reader, &has_keyframe);
687     }
688   }
689
690   if (!ret) {
691     GST_WARNING ("Failed to parse payloads");
692     goto end;
693   }
694   GST_DEBUG ("Received packet of length %" G_GUINT32_FORMAT
695       ", padding %" G_GUINT32_FORMAT ", send time %" G_GUINT32_FORMAT
696       ", duration %" G_GUINT16_FORMAT " and %s keyframe(s)",
697       packet_len, padd_len, send_time, duration,
698       (has_keyframe) ? "with" : "without");
699
700   packet->packet_size = packet_len;
701   packet->padding = padd_len;
702   packet->send_time = send_time;
703   packet->duration = duration;
704   packet->has_keyframe = has_keyframe;
705   packet->multiple_payloads = mult_payloads ? TRUE : FALSE;
706   packet->padd_field_type = padding_len_type;
707   packet->packet_field_type = packet_len_type;
708   packet->seq_field_type = seq_len_type;
709   packet->err_cor_len = err_length;
710
711   return ret;
712
713 error:
714   ret = FALSE;
715   GST_WARNING ("Error while parsing data packet");
716 end:
717   return ret;
718 }
719
720 static gboolean
721 gst_asf_parse_file_properties_obj (GstByteReader * reader,
722     GstAsfFileInfo * asfinfo)
723 {
724   guint32 min_ps = 0;
725   guint32 max_ps = 0;
726   guint64 packets = 0;
727   guint32 flags = 0;
728   GST_DEBUG ("ASF: Parsing file properties object");
729
730   /* skip until data packets count */
731   if (!gst_byte_reader_skip (reader, 32))
732     return FALSE;
733   if (!gst_byte_reader_get_uint64_le (reader, &packets))
734     return FALSE;
735   asfinfo->packets_count = packets;
736   GST_DEBUG ("ASF: packets count %" G_GUINT64_FORMAT, packets);
737
738   /* skip until flags */
739   if (!gst_byte_reader_skip (reader, 24))
740     return FALSE;
741
742   if (!gst_byte_reader_get_uint32_le (reader, &flags))
743     return GST_FLOW_ERROR;
744   asfinfo->broadcast = (flags & 0x1) == 1;
745   GST_DEBUG ("ASF: broadcast flag: %s", asfinfo->broadcast ? "true" : "false");
746   if (!gst_byte_reader_get_uint32_le (reader, &min_ps))
747     return GST_FLOW_ERROR;
748   if (!gst_byte_reader_get_uint32_le (reader, &max_ps))
749     return GST_FLOW_ERROR;
750
751   if (min_ps != max_ps) {
752     GST_WARNING ("Minimum and maximum packet size differ "
753         "%" G_GUINT32_FORMAT " and %" G_GUINT32_FORMAT ", "
754         "ASF spec states they should be the same", min_ps, max_ps);
755     return FALSE;
756   }
757
758   GST_DEBUG ("ASF: Packet size: %" G_GUINT32_FORMAT, min_ps);
759   asfinfo->packet_size = min_ps;
760   if (!gst_byte_reader_skip (reader, 4))
761     return FALSE;
762
763   return TRUE;
764 }
765
766 gboolean
767 gst_asf_parse_headers (GstBuffer * buffer, GstAsfFileInfo * file_info)
768 {
769   GstMapInfo map;
770   gboolean ret;
771
772   gst_buffer_map (buffer, &map, GST_MAP_READ);
773   ret = gst_asf_parse_headers_from_data (map.data, map.size, file_info);
774   gst_buffer_unmap (buffer, &map);
775
776   return ret;
777 }
778
779 gboolean
780 gst_asf_parse_headers_from_data (guint8 * data, guint size,
781     GstAsfFileInfo * file_info)
782 {
783   gboolean ret = TRUE;
784   guint32 header_objects = 0;
785   guint32 i;
786   GstByteReader reader;
787   guint64 object_size;
788
789   object_size = gst_asf_match_and_peek_obj_size (data,
790       &(guids[ASF_HEADER_OBJECT_INDEX]));
791   if (object_size == 0) {
792     GST_WARNING ("ASF: Cannot parse, header guid not found at the beginning "
793         " of data");
794     return FALSE;
795   }
796
797   gst_byte_reader_init (&reader, data, size);
798
799   if (!gst_byte_reader_skip (&reader, ASF_GUID_OBJSIZE_SIZE))
800     goto error;
801   if (!gst_byte_reader_get_uint32_le (&reader, &header_objects))
802     goto error;
803   GST_DEBUG ("ASF: Header has %" G_GUINT32_FORMAT " child"
804       " objects", header_objects);
805   /* skip reserved bytes */
806   if (!gst_byte_reader_skip (&reader, 2))
807     goto error;
808
809   /* iterate through childs of header object */
810   for (i = 0; i < header_objects; i++) {
811     const guint8 *guid = NULL;
812     guint64 obj_size = 0;
813
814     if (!gst_byte_reader_get_data (&reader, ASF_GUID_SIZE, &guid))
815       goto error;
816     if (!gst_byte_reader_get_uint64_le (&reader, &obj_size))
817       goto error;
818
819     if (gst_asf_match_guid (guid, &guids[ASF_FILE_PROPERTIES_OBJECT_INDEX])) {
820       ret = gst_asf_parse_file_properties_obj (&reader, file_info);
821     } else {
822       /* we don't know/care about this object */
823       if (!gst_byte_reader_skip (&reader, obj_size - ASF_GUID_OBJSIZE_SIZE))
824         goto error;
825     }
826
827     if (!ret)
828       goto end;
829   }
830   goto end;
831
832 error:
833   ret = FALSE;
834   GST_WARNING ("ASF: Error while parsing headers");
835 end:
836   return ret;
837 }
838
839 #define MAP_GST_TO_ASF_TAG(tag, gst, asf) \
840   if (strcmp (tag, gst) == 0) \
841     return asf
842
843 /**
844  * gst_asf_get_asf_tag:
845  * @gsttag: a gstreamer tag
846  *
847  * Maps gstreamer tags to asf tags
848  *
849  * Returns: The tag corresponding name in asf files or NULL if it is not mapped
850  */
851 const gchar *
852 gst_asf_get_asf_tag (const gchar * gsttag)
853 {
854   g_return_val_if_fail (gsttag != NULL, NULL);
855
856   MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_TITLE, ASF_TAG_TITLE);
857   MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_TITLE_SORTNAME, ASF_TAG_TITLE_SORTNAME);
858   MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ARTIST, ASF_TAG_ARTIST);
859   MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ARTIST_SORTNAME, ASF_TAG_ARTIST_SORTNAME);
860   MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ALBUM, ASF_TAG_ALBUM_TITLE);
861   MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ALBUM_SORTNAME,
862       ASF_TAG_ALBUM_TITLE_SORTNAME);
863   MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_GENRE, ASF_TAG_GENRE);
864   MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_COPYRIGHT, ASF_TAG_COPYRIGHT);
865   MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_COMPOSER, ASF_TAG_COMPOSER);
866   MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_COMMENT, ASF_TAG_COMMENT);
867   MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_TRACK_NUMBER, ASF_TAG_TRACK_NUMBER);
868
869   return NULL;
870 }
871
872 guint
873 gst_asf_get_tag_field_type (GValue * value)
874 {
875   if (G_VALUE_HOLDS_STRING (value))
876     return ASF_TAG_TYPE_UNICODE_STR;
877   if (G_VALUE_HOLDS_UINT (value))
878     return ASF_TAG_TYPE_DWORD;
879
880   return -1;
881 }
882
883 gboolean
884 gst_asf_tag_present_in_content_description (const gchar * tag)
885 {
886   return strcmp (tag, GST_TAG_TITLE) == 0 ||
887       strcmp (tag, GST_TAG_ARTIST) == 0 ||
888       strcmp (tag, GST_TAG_COPYRIGHT) == 0 ||
889       strcmp (tag, GST_TAG_DESCRIPTION) == 0;
890   /* FIXME we have no tag for rating */
891 }