1 /* ASF muxer plugin for GStreamer
2 * Copyright (C) 2009 Thiago Santos <thiagoss@embedded.ufcg.edu.br>
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.
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.
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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #include "gstasfobjects.h"
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)},
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)},
40 {0xABD3D211, 0xA9BA, 0x11CF, G_GUINT64_CONSTANT (0x8EE600C00C205365)},
42 {0x75B22636, 0x668E, 0x11CF, G_GUINT64_CONSTANT (0xA6D900AA0062CE6C)},
43 /* asf extended stream properties object */
44 {0x14E6A5CB, 0xC672, 0x4332, G_GUINT64_CONSTANT (0x8399A96952065B5A)},
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)}
60 * gst_asf_generate_file_id:
62 * Generates a random GUID
64 * Returns: The generated GUID
67 gst_asf_generate_file_id (Guid * guid)
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 ();
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
84 * Reads the proper data from the #GstByteReader according to the
85 * asf field type and stores it in var
87 * Returns: True on success, false otherwise
90 gst_byte_reader_get_asf_var_size_field (GstByteReader * reader,
91 guint8 field_type, guint32 * var)
99 case ASF_FIELD_TYPE_DWORD:
100 ret = gst_byte_reader_get_uint32_le (reader, &aux32);
103 case ASF_FIELD_TYPE_WORD:
104 ret = gst_byte_reader_get_uint16_le (reader, &aux16);
107 case ASF_FIELD_TYPE_BYTE:
108 ret = gst_byte_reader_get_uint8 (reader, &aux8);
111 case ASF_FIELD_TYPE_NONE:
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
126 * Reads and returns the value read from the data, according to the
129 * Returns: The value read
132 gst_asf_read_var_size_field (guint8 * data, guint8 field_type)
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:
147 * gst_asf_get_var_size_field_len:
148 * @field_type: the asf field type
150 * Returns: the size in bytes of a variable of field_type type
153 gst_asf_get_var_size_field_len (guint8 field_type)
155 switch (field_type) {
156 case ASF_FIELD_TYPE_DWORD:
158 case ASF_FIELD_TYPE_WORD:
160 case ASF_FIELD_TYPE_BYTE:
168 * gst_asf_file_info_new:
170 * Creates a new #GstAsfFileInfo
172 * Returns: the created struct
175 gst_asf_file_info_new (void)
177 return g_new0 (GstAsfFileInfo, 1);
181 * gst_asf_file_info_reset:
182 * @info: the #GstAsfFileInfo to be reset
184 * resets the data of a #GstFileInfo
187 gst_asf_file_info_reset (GstAsfFileInfo * info)
189 info->packet_size = 0;
190 info->packets_count = 0;
191 info->broadcast = FALSE;
195 * gst_asf_file_info_free:
196 * @info: the #GstAsfFileInfo to be freed
198 * Releases memory associated with this #GstAsfFileInfo
201 gst_asf_file_info_free (GstAsfFileInfo * info)
207 * gst_asf_payload_get_size:
208 * @payload: the payload to get the size from
210 * Returns: the size of an asf payload of the data represented by this
214 gst_asf_payload_get_size (AsfPayload * payload)
216 return ASF_MULTIPLE_PAYLOAD_HEADER_SIZE + GST_BUFFER_SIZE (payload->data);
220 * gst_asf_payload_free:
221 * @payload: the #AsfPayload to be freed
223 * Releases teh memory associated with this payload
226 gst_asf_payload_free (AsfPayload * payload)
228 gst_buffer_unref (payload->data);
233 * gst_asf_get_current_time:
235 * Gets system current time in ASF time unit
236 * (100-nanoseconds since Jan, 1st 1601)
241 gst_asf_get_current_time (void)
247 g_get_current_time (&timeval);
249 secs = (guint64) timeval.tv_sec;
250 usecs = (guint64) timeval.tv_usec;
251 return secs * G_GUINT64_CONSTANT (10000000) + usecs * 10
252 + G_GUINT64_CONSTANT (116444628000000000);
256 * gst_asf_match_guid:
257 * @data: pointer to the guid to be tested
258 * @guid: guid to match against data
260 * Checks if the guid pointed by data is the same
261 * as the guid parameter
263 * Returns: True if they are the same, false otherwise
266 gst_asf_match_guid (const guint8 * data, const Guid * guid)
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);
274 return g.v1 == guid->v1 &&
275 g.v2 == guid->v2 && g.v3 == guid->v3 && g.v4 == guid->v4;
280 * @buf: the memory to write data to
281 * @data: the value to be writen
283 * Writes a 32 bit signed integer to memory
286 gst_asf_put_i32 (guint8 * buf, gint32 data)
288 GST_WRITE_UINT32_LE (buf, (guint32) data);
293 * @buf: pointer to the buffer to write the value to
294 * @time: value to be writen
296 * Writes an asf time value to the buffer
299 gst_asf_put_time (guint8 * buf, guint64 time)
301 GST_WRITE_UINT64_LE (buf, time);
306 * @buf: the buffer to write the guid to
307 * @guid: the guid to be writen
309 * Writes a GUID to the buffer
312 gst_asf_put_guid (guint8 * buf, Guid guid)
314 guint32 *aux32 = (guint32 *) buf;
315 guint16 *aux16 = (guint16 *) & (buf[4]);
316 guint64 *aux64 = (guint64 *) & (buf[8]);
317 *aux32 = GUINT32_TO_LE (guid.v1);
318 *aux16 = GUINT16_TO_LE (guid.v2);
319 aux16 = (guint16 *) & (buf[6]);
320 *aux16 = GUINT16_TO_LE (guid.v3);
321 *aux64 = GUINT64_TO_BE (guid.v4);
325 * gst_asf_put_payload:
326 * @buf: memory to write the payload to
327 * @payload: #AsfPayload to be writen
329 * Writes the asf payload to the buffer. The #AsfPayload
330 * packet count is incremented.
333 gst_asf_put_payload (guint8 * buf, AsfPayload * payload)
335 GST_WRITE_UINT8 (buf, payload->stream_number);
336 GST_WRITE_UINT8 (buf + 1, payload->media_obj_num);
337 GST_WRITE_UINT32_LE (buf + 2, payload->offset_in_media_obj);
338 GST_WRITE_UINT8 (buf + 6, payload->replicated_data_length);
339 GST_WRITE_UINT32_LE (buf + 7, payload->media_object_size);
340 GST_WRITE_UINT32_LE (buf + 11, payload->presentation_time);
341 GST_WRITE_UINT16_LE (buf + 15, (guint16) GST_BUFFER_SIZE (payload->data));
342 memcpy (buf + 17, GST_BUFFER_DATA (payload->data),
343 GST_BUFFER_SIZE (payload->data));
345 payload->packet_count++;
349 * gst_asf_put_subpayload:
350 * @buf: buffer to write the payload to
351 * @payload: the payload to be writen
352 * @size: maximum size in bytes to write
354 * Serializes part of a payload to a buffer.
355 * The maximum size is checked against the payload length,
356 * the minimum of this size and the payload length is writen
357 * to the buffer and the writen size is returned.
359 * It also updates the values of the payload to match the remaining
361 * In case there is not enough space to write the headers, nothing is done.
363 * Returns: The writen size in bytes.
366 gst_asf_put_subpayload (guint8 * buf, AsfPayload * payload, guint16 size)
368 guint16 payload_size;
370 if (size <= ASF_MULTIPLE_PAYLOAD_HEADER_SIZE) {
371 return 0; /* do nothing if there is not enough space */
373 GST_WRITE_UINT8 (buf, payload->stream_number);
374 GST_WRITE_UINT8 (buf + 1, payload->media_obj_num);
375 GST_WRITE_UINT32_LE (buf + 2, payload->offset_in_media_obj);
376 GST_WRITE_UINT8 (buf + 6, payload->replicated_data_length);
377 GST_WRITE_UINT32_LE (buf + 7, payload->media_object_size);
378 GST_WRITE_UINT32_LE (buf + 11, payload->presentation_time);
379 size -= ASF_MULTIPLE_PAYLOAD_HEADER_SIZE;
380 payload_size = size < GST_BUFFER_SIZE (payload->data) ?
381 size : GST_BUFFER_SIZE (payload->data);
382 GST_WRITE_UINT16_LE (buf + 15, payload_size);
383 memcpy (buf + 17, GST_BUFFER_DATA (payload->data), payload_size);
385 /* updates the payload to the remaining data */
386 payload->offset_in_media_obj += payload_size;
387 newbuf = gst_buffer_create_sub (payload->data, payload_size,
388 GST_BUFFER_SIZE (payload->data) - payload_size);
389 payload->data = gst_buffer_make_metadata_writable (payload->data);
390 gst_buffer_copy_metadata (payload->data, newbuf, GST_BUFFER_COPY_FLAGS |
391 GST_BUFFER_COPY_CAPS);
392 GST_BUFFER_TIMESTAMP (newbuf) = GST_BUFFER_TIMESTAMP (payload->data);
393 gst_buffer_unref (payload->data);
394 payload->data = newbuf;
396 payload->packet_count++;
402 * gst_asf_match_and_peek_obj_size:
403 * @data: data to be peeked at
404 * @guid: pointer to a guid
406 * Compares the first bytes of data against the guid parameter and
407 * if they match gets the object size (that are right after the guid in
410 * In case the guids don't match, 0 is returned.
411 * If the guid is NULL the match is assumed to be true.
413 * Returns: The size of the object in case the guid matches, 0 otherwise
416 gst_asf_match_and_peek_obj_size (const guint8 * data, const Guid * guid)
419 if (guid && !gst_asf_match_guid (data, guid)) {
420 /* this is not the expected object */
423 /* return the object size */
424 return GST_READ_UINT64_LE (data + ASF_GUID_SIZE);
428 * gst_asf_parse_mult_payload:
429 * @reader: a #GstByteReader ready to read the multiple payload data
430 * @has_keyframe: pointer to return the result
432 * Parses a multiple payload section of an asf data packet
433 * to see if any of the paylaods has a a keyframe
435 * Notice that the #GstByteReader might not be positioned after
436 * this section on this function return. Because this section
437 * is the last one in an asf packet and the remaining data
438 * is probably uninteresting to the application.
440 * Returns: true on success, false if some error occurrs
443 gst_asf_parse_mult_payload (GstByteReader * reader, gboolean * has_keyframe)
446 guint8 payload_len_type;
447 guint8 rep_data_len = 0;
449 guint8 stream_num = 0;
453 if (!gst_byte_reader_get_uint8 (reader, &aux))
456 payloads = (aux & 0x3F);
457 payload_len_type = (aux & 0xC0) >> 6;
459 *has_keyframe = FALSE;
460 for (i = 0; i < payloads; i++) {
461 GST_LOG ("Parsing payload %u/%u", i + 1, payloads);
462 if (!gst_byte_reader_get_uint8 (reader, &stream_num))
464 if ((stream_num & 0x80) != 0) {
465 GST_LOG ("Keyframe found, stoping parse of payloads");
466 *has_keyframe = TRUE;
469 /* skip to replicated data length */
470 if (!gst_byte_reader_skip (reader, 5))
472 if (!gst_byte_reader_get_uint8 (reader, &rep_data_len))
474 if (!gst_byte_reader_skip (reader, rep_data_len))
476 if (!gst_byte_reader_get_asf_var_size_field (reader, payload_len_type,
479 if (!gst_byte_reader_skip (reader, payload_len))
483 /* we do not skip the rest of the payload bytes as
484 this is the last data to be parsed on the buffer */
487 GST_WARNING ("Error while parsing payloads");
492 * gst_asf_parse_single_payload:
493 * @reader: a #GstByteReader ready to read the multiple payload data
494 * @has_keyframe: pointer to return the result
496 * Parses a single payload section of an asf data packet
497 * to see if any of the paylaods has a a keyframe
499 * Notice that the #GstByteReader might not be positioned after
500 * this section on this function return. Because this section
501 * is the last one in an asf packet and the remaining data
502 * is probably uninteresting to the application.
504 * Returns: true on success, false if some error occurrs
507 gst_asf_parse_single_payload (GstByteReader * reader, gboolean * has_keyframe)
509 guint8 stream_num = 0;
510 if (!gst_byte_reader_get_uint8 (reader, &stream_num))
511 return GST_FLOW_ERROR;
512 *has_keyframe = (stream_num & 0x80) != 0;
514 /* we do not skip the rest of the payload bytes as
515 this is the last data to be parsed on the buffer */
520 gst_asf_parse_packet (GstBuffer * buffer, GstAsfPacketInfo * packet,
521 gboolean trust_delta_flag, guint packet_size)
523 /* Might be useful in future:
524 guint8 rep_data_len_type;
525 guint8 mo_number_len_type;
526 guint8 mo_offset_type;
528 GstByteReader *reader;
531 guint8 err_length = 0; /* length of the error fields */
533 guint8 packet_len_type;
534 guint8 padding_len_type;
536 gboolean mult_payloads;
539 guint32 send_time = 0;
540 guint16 duration = 0;
541 gboolean has_keyframe;
543 if (packet_size != 0 && GST_BUFFER_SIZE (buffer) != packet_size) {
544 GST_WARNING ("ASF packets should be aligned with buffers");
548 reader = gst_byte_reader_new_from_buffer (buffer);
550 GST_LOG ("Starting packet parsing, size: %u", GST_BUFFER_SIZE (buffer));
551 if (!gst_byte_reader_get_uint8 (reader, &first))
554 if (first & 0x80) { /* error correction present */
557 GST_DEBUG ("Packet contains error correction");
559 GST_ERROR ("Error correction data length should be "
560 "set to 0 and is reserved for future use.");
563 err_cor_len = (first & 0x0F);
564 err_length += err_cor_len;
565 GST_DEBUG ("Error correction data length: %d", (gint) err_cor_len);
566 if (!gst_byte_reader_skip (reader, err_cor_len))
569 /* put payload parsing info first byte in aux var */
570 if (!gst_byte_reader_get_uint8 (reader, &aux))
575 mult_payloads = (aux & 0x1) != 0;
577 packet_len_type = (aux >> 5) & 0x3;
578 padding_len_type = (aux >> 3) & 0x3;
579 seq_len_type = (aux >> 1) & 0x3;
580 GST_LOG ("Field sizes: packet length type: %u "
581 ", padding length type: %u, sequence length type: %u",
582 gst_asf_get_var_size_field_len (packet_len_type),
583 gst_asf_get_var_size_field_len (padding_len_type),
584 gst_asf_get_var_size_field_len (seq_len_type));
587 GST_DEBUG ("Packet contains multiple payloads");
590 if (!gst_byte_reader_get_uint8 (reader, &aux))
594 rep_data_len_type = aux & 0x3;
595 mo_offset_type = (aux >> 2) & 0x3;
596 mo_number_len_type = (aux >> 4) & 0x3;
599 /* gets the fields lengths */
600 GST_LOG ("Getting packet and padding length");
601 if (!gst_byte_reader_get_asf_var_size_field (reader,
602 packet_len_type, &packet_len))
604 if (!gst_byte_reader_skip (reader,
605 gst_asf_get_var_size_field_len (seq_len_type)))
607 if (!gst_byte_reader_get_asf_var_size_field (reader,
608 padding_len_type, &padd_len))
611 /* some packet size validation */
612 if (packet_size != 0 && packet_len_type != ASF_FIELD_TYPE_NONE) {
613 if (padding_len_type != ASF_FIELD_TYPE_NONE &&
614 packet_len + padd_len != packet_size) {
615 GST_WARNING ("Packet size (payload=%u + padding=%u) doesn't "
616 "match expected size %u", packet_len, padd_len, packet_size);
620 /* Be forgiving if packet_len has the full packet size
621 * as the spec isn't really clear on its meaning.
623 * I had been taking it as the full packet size (fixed)
624 * until bug #607555, that convinced me that it is more likely
625 * the actual payloaded data size.
627 if (packet_len == packet_size) {
628 GST_DEBUG ("This packet's length field represents the full "
629 "packet and not the payloaded data length");
637 GST_LOG ("Getting send time and duration");
638 if (!gst_byte_reader_get_uint32_le (reader, &send_time))
640 if (!gst_byte_reader_get_uint16_le (reader, &duration))
643 has_keyframe = FALSE;
644 GST_LOG ("Checking for keyframes");
645 if (trust_delta_flag) {
646 has_keyframe = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
649 ret = gst_asf_parse_mult_payload (reader, &has_keyframe);
651 ret = gst_asf_parse_single_payload (reader, &has_keyframe);
656 GST_WARNING ("Failed to parse payloads");
659 GST_DEBUG ("Received packet of length %" G_GUINT32_FORMAT
660 ", padding %" G_GUINT32_FORMAT ", send time %" G_GUINT32_FORMAT
661 ", duration %" G_GUINT16_FORMAT " and %s keyframe(s)",
662 packet_len, padd_len, send_time, duration,
663 (has_keyframe) ? "with" : "without");
665 packet->packet_size = packet_len;
666 packet->padding = padd_len;
667 packet->send_time = send_time;
668 packet->duration = duration;
669 packet->has_keyframe = has_keyframe;
670 packet->multiple_payloads = mult_payloads ? TRUE : FALSE;
671 packet->padd_field_type = padding_len_type;
672 packet->packet_field_type = packet_len_type;
673 packet->seq_field_type = seq_len_type;
674 packet->err_cor_len = err_length;
676 gst_byte_reader_free (reader);
681 GST_WARNING ("Error while parsing data packet");
683 gst_byte_reader_free (reader);
688 gst_asf_parse_file_properties_obj (GstByteReader * reader,
689 GstAsfFileInfo * asfinfo)
695 GST_DEBUG ("ASF: Parsing file properties object");
697 /* skip until data packets count */
698 if (!gst_byte_reader_skip (reader, 32))
700 if (!gst_byte_reader_get_uint64_le (reader, &packets))
702 asfinfo->packets_count = packets;
703 GST_DEBUG ("ASF: packets count %" G_GUINT64_FORMAT, packets);
705 /* skip until flags */
706 if (!gst_byte_reader_skip (reader, 24))
709 if (!gst_byte_reader_get_uint32_le (reader, &flags))
710 return GST_FLOW_ERROR;
711 asfinfo->broadcast = (flags & 0x1) == 1;
712 GST_DEBUG ("ASF: broadcast flag: %s", asfinfo->broadcast ? "true" : "false");
713 if (!gst_byte_reader_get_uint32_le (reader, &min_ps))
714 return GST_FLOW_ERROR;
715 if (!gst_byte_reader_get_uint32_le (reader, &max_ps))
716 return GST_FLOW_ERROR;
718 if (min_ps != max_ps) {
719 GST_WARNING ("Mininum and maximum packet size differ "
720 "%" G_GUINT32_FORMAT " and %" G_GUINT32_FORMAT ", "
721 "ASF spec states they should be the same", min_ps, max_ps);
725 GST_DEBUG ("ASF: Packet size: %" G_GUINT32_FORMAT, min_ps);
726 asfinfo->packet_size = min_ps;
727 if (!gst_byte_reader_skip (reader, 4))
734 gst_asf_parse_headers (GstBuffer * buffer, GstAsfFileInfo * file_info)
737 guint32 header_objects = 0;
739 GstByteReader *reader;
742 object_size = gst_asf_match_and_peek_obj_size (GST_BUFFER_DATA (buffer),
743 &(guids[ASF_HEADER_OBJECT_INDEX]));
744 if (object_size == 0) {
745 GST_WARNING ("ASF: Cannot parse, header guid not found at the beginning "
750 reader = gst_byte_reader_new_from_buffer (buffer);
752 if (!gst_byte_reader_skip (reader, ASF_GUID_OBJSIZE_SIZE))
754 if (!gst_byte_reader_get_uint32_le (reader, &header_objects))
756 GST_DEBUG ("ASF: Header has %" G_GUINT32_FORMAT " child"
757 " objects", header_objects);
758 /* skip reserved bytes */
759 if (!gst_byte_reader_skip (reader, 2))
762 /* iterate through childs of header object */
763 for (i = 0; i < header_objects; i++) {
764 const guint8 *guid = NULL;
765 guint64 obj_size = 0;
766 if (!gst_byte_reader_get_data (reader, ASF_GUID_SIZE, &guid))
768 if (!gst_byte_reader_get_uint64_le (reader, &obj_size))
771 if (gst_asf_match_guid (guid, &guids[ASF_FILE_PROPERTIES_OBJECT_INDEX])) {
772 ret = gst_asf_parse_file_properties_obj (reader, file_info);
774 /* we don't know/care about this object */
775 if (!gst_byte_reader_skip (reader, obj_size - ASF_GUID_OBJSIZE_SIZE))
786 GST_WARNING ("ASF: Error while parsing headers");
788 gst_byte_reader_free (reader);
792 #define MAP_GST_TO_ASF_TAG(tag, gst, asf) \
793 if (strcmp (tag, gst) == 0) \
797 * gst_asf_get_asf_tag:
798 * @gsttag: a gstreamer tag
800 * Maps gstreamer tags to asf tags
802 * Returns: The tag corresponding name in asf files or NULL if it is not mapped
805 gst_asf_get_asf_tag (const gchar * gsttag)
807 g_return_val_if_fail (gsttag != NULL, NULL);
809 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_TITLE, ASF_TAG_TITLE);
810 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_TITLE_SORTNAME, ASF_TAG_TITLE_SORTNAME);
811 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ARTIST, ASF_TAG_ARTIST);
812 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ARTIST_SORTNAME, ASF_TAG_ARTIST_SORTNAME);
813 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ALBUM, ASF_TAG_ALBUM_TITLE);
814 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ALBUM_SORTNAME,
815 ASF_TAG_ALBUM_TITLE_SORTNAME);
816 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_GENRE, ASF_TAG_GENRE);
817 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_COPYRIGHT, ASF_TAG_COPYRIGHT);
818 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_COMPOSER, ASF_TAG_COMPOSER);
819 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_COMMENT, ASF_TAG_COMMENT);
820 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_TRACK_NUMBER, ASF_TAG_TRACK_NUMBER);
826 gst_asf_get_tag_field_type (GValue * value)
828 if (G_VALUE_HOLDS_STRING (value))
829 return ASF_TAG_TYPE_UNICODE_STR;
830 if (G_VALUE_HOLDS_UINT (value))
831 return ASF_TAG_TYPE_DWORD;
837 gst_asf_tag_present_in_content_description (const gchar * tag)
839 return strcmp (tag, GST_TAG_TITLE) == 0 ||
840 strcmp (tag, GST_TAG_ARTIST) == 0 ||
841 strcmp (tag, GST_TAG_COPYRIGHT) == 0 ||
842 strcmp (tag, GST_TAG_DESCRIPTION) == 0;
843 /* FIXME we have no tag for rating */