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
gst_asf_generate_file_id(Guid * guid)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
gst_byte_reader_get_asf_var_size_field(GstByteReader * reader,guint8 field_type,guint32 * var)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
gst_asf_read_var_size_field(guint8 * data,guint8 field_type)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
gst_asf_get_var_size_field_len(guint8 field_type)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 *
gst_asf_file_info_new(void)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
gst_asf_file_info_reset(GstAsfFileInfo * info)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
gst_asf_file_info_free(GstAsfFileInfo * info)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
gst_asf_payload_get_size(AsfPayload * payload)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
gst_asf_payload_free(AsfPayload * payload)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
gst_asf_get_current_time(void)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
gst_asf_match_guid(const guint8 * data,const Guid * guid)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
gst_asf_put_i32(guint8 * buf,gint32 data)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
gst_asf_put_time(guint8 * buf,guint64 time)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
gst_asf_put_guid(guint8 * buf,Guid guid)312 gst_asf_put_guid (guint8 * buf, Guid guid)
313 {
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);
322 }
323
324 /**
325 * gst_asf_put_payload:
326 * @buf: memory to write the payload to
327 * @payload: #AsfPayload to be written
328 *
329 * Writes the asf payload to the buffer. The #AsfPayload
330 * packet count is incremented.
331 */
332 void
gst_asf_put_payload(guint8 * buf,AsfPayload * payload)333 gst_asf_put_payload (guint8 * buf, AsfPayload * payload)
334 {
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_get_size (payload->data));
342 gst_buffer_extract (payload->data, 0, buf + 17,
343 gst_buffer_get_size (payload->data));
344
345 payload->packet_count++;
346 }
347
348 /**
349 * gst_asf_put_subpayload:
350 * @buf: buffer to write the payload to
351 * @payload: the payload to be written
352 * @size: maximum size in bytes to write
353 *
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 written
357 * to the buffer and the written size is returned.
358 *
359 * It also updates the values of the payload to match the remaining
360 * data.
361 * In case there is not enough space to write the headers, nothing is done.
362 *
363 * Returns: The written size in bytes.
364 */
365 guint16
gst_asf_put_subpayload(guint8 * buf,AsfPayload * payload,guint16 size)366 gst_asf_put_subpayload (guint8 * buf, AsfPayload * payload, guint16 size)
367 {
368 guint16 payload_size;
369 GstBuffer *newbuf;
370 if (size <= ASF_MULTIPLE_PAYLOAD_HEADER_SIZE) {
371 return 0; /* do nothing if there is not enough space */
372 }
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_get_size (payload->data) ?
381 size : gst_buffer_get_size (payload->data);
382 GST_WRITE_UINT16_LE (buf + 15, payload_size);
383 gst_buffer_extract (payload->data, 0, buf + 17, payload_size);
384
385 /* updates the payload to the remaining data */
386 payload->offset_in_media_obj += payload_size;
387 newbuf = gst_buffer_copy_region (payload->data, GST_BUFFER_COPY_ALL,
388 payload_size, gst_buffer_get_size (payload->data) - payload_size);
389 GST_BUFFER_TIMESTAMP (newbuf) = GST_BUFFER_TIMESTAMP (payload->data);
390 gst_buffer_unref (payload->data);
391 payload->data = newbuf;
392
393 payload->packet_count++;
394
395 return payload_size;
396 }
397
398 /**
399 * gst_asf_match_and_peek_obj_size:
400 * @data: data to be peeked at
401 * @guid: pointer to a guid
402 *
403 * Compares the first bytes of data against the guid parameter and
404 * if they match gets the object size (that are right after the guid in
405 * asf objects).
406 *
407 * In case the guids don't match, 0 is returned.
408 * If the guid is NULL the match is assumed to be true.
409 *
410 * Returns: The size of the object in case the guid matches, 0 otherwise
411 */
412 guint64
gst_asf_match_and_peek_obj_size(const guint8 * data,const Guid * guid)413 gst_asf_match_and_peek_obj_size (const guint8 * data, const Guid * guid)
414 {
415 g_assert (data);
416 if (guid && !gst_asf_match_guid (data, guid)) {
417 /* this is not the expected object */
418 return 0;
419 }
420 /* return the object size */
421 return GST_READ_UINT64_LE (data + ASF_GUID_SIZE);
422 }
423
424 /**
425 * gst_asf_match_and_peek_obj_size_buf:
426 * @buf: buffer to be peeked at
427 * @guid: pointer to a guid
428 *
429 * Compares the first bytes of buf against the guid parameter and
430 * if they match gets the object size (that are right after the guid in
431 * asf objects).
432 *
433 * In case the guids don't match, 0 is returned.
434 * If the guid is NULL the match is assumed to be true.
435 *
436 * Returns: The size of the object in case the guid matches, 0 otherwise
437 */
438 guint64
gst_asf_match_and_peek_obj_size_buf(GstBuffer * buf,const Guid * guid)439 gst_asf_match_and_peek_obj_size_buf (GstBuffer * buf, const Guid * guid)
440 {
441 GstMapInfo map;
442 guint64 res;
443
444 gst_buffer_map (buf, &map, GST_MAP_READ);
445 res = gst_asf_match_and_peek_obj_size (map.data, guid);
446 gst_buffer_unmap (buf, &map);
447
448 return res;
449 }
450
451 /**
452 * gst_asf_parse_mult_payload:
453 * @reader: a #GstByteReader ready to read the multiple payload data
454 * @has_keyframe: pointer to return the result
455 *
456 * Parses a multiple payload section of an asf data packet
457 * to see if any of the paylaods has a a keyframe
458 *
459 * Notice that the #GstByteReader might not be positioned after
460 * this section on this function return. Because this section
461 * is the last one in an asf packet and the remaining data
462 * is probably uninteresting to the application.
463 *
464 * Returns: true on success, false if some error occurs
465 */
466 static gboolean
gst_asf_parse_mult_payload(GstByteReader * reader,gboolean * has_keyframe)467 gst_asf_parse_mult_payload (GstByteReader * reader, gboolean * has_keyframe)
468 {
469 guint payloads;
470 guint8 payload_len_type;
471 guint8 rep_data_len = 0;
472 guint32 payload_len;
473 guint8 stream_num = 0;
474 guint8 aux = 0;
475 guint i;
476
477 if (!gst_byte_reader_get_uint8 (reader, &aux))
478 return FALSE;
479
480 payloads = (aux & 0x3F);
481 payload_len_type = (aux & 0xC0) >> 6;
482
483 *has_keyframe = FALSE;
484 for (i = 0; i < payloads; i++) {
485 GST_LOG ("Parsing payload %u/%u", i + 1, payloads);
486 if (!gst_byte_reader_get_uint8 (reader, &stream_num))
487 goto error;
488 if ((stream_num & 0x80) != 0) {
489 GST_LOG ("Keyframe found, stopping parse of payloads");
490 *has_keyframe = TRUE;
491 return TRUE;
492 }
493 /* skip to replicated data length */
494 if (!gst_byte_reader_skip (reader, 5))
495 goto error;
496 if (!gst_byte_reader_get_uint8 (reader, &rep_data_len))
497 goto error;
498 if (!gst_byte_reader_skip (reader, rep_data_len))
499 goto error;
500 if (!gst_byte_reader_get_asf_var_size_field (reader, payload_len_type,
501 &payload_len))
502 goto error;
503 if (!gst_byte_reader_skip (reader, payload_len))
504 goto error;
505 }
506
507 /* we do not skip the rest of the payload bytes as
508 this is the last data to be parsed on the buffer */
509 return TRUE;
510 error:
511 GST_WARNING ("Error while parsing payloads");
512 return FALSE;
513 }
514
515 /**
516 * gst_asf_parse_single_payload:
517 * @reader: a #GstByteReader ready to read the multiple payload data
518 * @has_keyframe: pointer to return the result
519 *
520 * Parses a single payload section of an asf data packet
521 * to see if any of the paylaods has a a keyframe
522 *
523 * Notice that the #GstByteReader might not be positioned after
524 * this section on this function return. Because this section
525 * is the last one in an asf packet and the remaining data
526 * is probably uninteresting to the application.
527 *
528 * Returns: true on success, false if some error occurs
529 */
530 static gboolean
gst_asf_parse_single_payload(GstByteReader * reader,gboolean * has_keyframe)531 gst_asf_parse_single_payload (GstByteReader * reader, gboolean * has_keyframe)
532 {
533 guint8 stream_num = 0;
534 if (!gst_byte_reader_get_uint8 (reader, &stream_num))
535 return GST_FLOW_ERROR;
536 *has_keyframe = (stream_num & 0x80) != 0;
537
538 /* we do not skip the rest of the payload bytes as
539 this is the last data to be parsed on the buffer */
540 return TRUE;
541 }
542
543 gboolean
gst_asf_parse_packet(GstBuffer * buffer,GstAsfPacketInfo * packet,gboolean trust_delta_flag,guint packet_size)544 gst_asf_parse_packet (GstBuffer * buffer, GstAsfPacketInfo * packet,
545 gboolean trust_delta_flag, guint packet_size)
546 {
547 gboolean ret;
548 GstMapInfo map;
549
550 gst_buffer_map (buffer, &map, GST_MAP_READ);
551 ret = gst_asf_parse_packet_from_data (map.data, map.size, buffer, packet,
552 trust_delta_flag, packet_size);
553 gst_buffer_unmap (buffer, &map);
554
555 return ret;
556 }
557
558 gboolean
gst_asf_parse_packet_from_data(guint8 * data,gsize size,GstBuffer * buffer,GstAsfPacketInfo * packet,gboolean trust_delta_flag,guint packet_size)559 gst_asf_parse_packet_from_data (guint8 * data, gsize size, GstBuffer * buffer,
560 GstAsfPacketInfo * packet, gboolean trust_delta_flag, guint packet_size)
561 {
562 /* Might be useful in future:
563 guint8 rep_data_len_type;
564 guint8 mo_number_len_type;
565 guint8 mo_offset_type;
566 */
567 GstByteReader reader;
568 gboolean ret = TRUE;
569 guint8 first = 0;
570 guint8 err_length = 0; /* length of the error fields */
571 guint8 aux = 0;
572 guint8 packet_len_type;
573 guint8 padding_len_type;
574 guint8 seq_len_type;
575 gboolean mult_payloads;
576 guint32 packet_len;
577 guint32 padd_len;
578 guint32 send_time = 0;
579 guint16 duration = 0;
580 gboolean has_keyframe;
581
582 if (packet_size != 0 && size != packet_size) {
583 GST_WARNING ("ASF packets should be aligned with buffers");
584 return FALSE;
585 }
586
587 gst_byte_reader_init (&reader, data, size);
588
589 GST_LOG ("Starting packet parsing, size: %" G_GSIZE_FORMAT, size);
590 if (!gst_byte_reader_get_uint8 (&reader, &first))
591 goto error;
592
593 if (first & 0x80) { /* error correction present */
594 guint8 err_cor_len;
595 err_length += 1;
596 GST_DEBUG ("Packet contains error correction");
597 if (first & 0x60) {
598 GST_ERROR ("Error correction data length should be "
599 "set to 0 and is reserved for future use.");
600 goto error;
601 }
602 err_cor_len = (first & 0x0F);
603 err_length += err_cor_len;
604 GST_DEBUG ("Error correction data length: %d", (gint) err_cor_len);
605 if (!gst_byte_reader_skip (&reader, err_cor_len))
606 goto error;
607
608 /* put payload parsing info first byte in aux var */
609 if (!gst_byte_reader_get_uint8 (&reader, &aux))
610 goto error;
611 } else {
612 aux = first;
613 }
614 mult_payloads = (aux & 0x1) != 0;
615
616 packet_len_type = (aux >> 5) & 0x3;
617 padding_len_type = (aux >> 3) & 0x3;
618 seq_len_type = (aux >> 1) & 0x3;
619 GST_LOG ("Field sizes: packet length type: %u "
620 ", padding length type: %u, sequence length type: %u",
621 gst_asf_get_var_size_field_len (packet_len_type),
622 gst_asf_get_var_size_field_len (padding_len_type),
623 gst_asf_get_var_size_field_len (seq_len_type));
624
625 if (mult_payloads) {
626 GST_DEBUG ("Packet contains multiple payloads");
627 }
628
629 if (!gst_byte_reader_get_uint8 (&reader, &aux))
630 goto error;
631
632 /*
633 rep_data_len_type = aux & 0x3;
634 mo_offset_type = (aux >> 2) & 0x3;
635 mo_number_len_type = (aux >> 4) & 0x3;
636 */
637
638 /* gets the fields lengths */
639 GST_LOG ("Getting packet and padding length");
640 if (!gst_byte_reader_get_asf_var_size_field (&reader,
641 packet_len_type, &packet_len))
642 goto error;
643 if (!gst_byte_reader_skip (&reader,
644 gst_asf_get_var_size_field_len (seq_len_type)))
645 goto error;
646 if (!gst_byte_reader_get_asf_var_size_field (&reader,
647 padding_len_type, &padd_len))
648 goto error;
649
650 /* some packet size validation */
651 if (packet_size != 0 && packet_len_type != ASF_FIELD_TYPE_NONE) {
652 if (padding_len_type != ASF_FIELD_TYPE_NONE &&
653 packet_len + padd_len != packet_size) {
654 GST_WARNING ("Packet size (payload=%u + padding=%u) doesn't "
655 "match expected size %u", packet_len, padd_len, packet_size);
656 ret = FALSE;
657 }
658
659 /* Be forgiving if packet_len has the full packet size
660 * as the spec isn't really clear on its meaning.
661 *
662 * I had been taking it as the full packet size (fixed)
663 * until bug #607555, that convinced me that it is more likely
664 * the actual payloaded data size.
665 */
666 if (packet_len == packet_size) {
667 GST_DEBUG ("This packet's length field represents the full "
668 "packet and not the payloaded data length");
669 ret = TRUE;
670 }
671
672 if (!ret)
673 goto end;
674 }
675
676 GST_LOG ("Getting send time and duration");
677 if (!gst_byte_reader_get_uint32_le (&reader, &send_time))
678 goto error;
679 if (!gst_byte_reader_get_uint16_le (&reader, &duration))
680 goto error;
681
682 has_keyframe = FALSE;
683 GST_LOG ("Checking for keyframes");
684 if (trust_delta_flag) {
685 has_keyframe = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
686 } else {
687 if (mult_payloads) {
688 ret = gst_asf_parse_mult_payload (&reader, &has_keyframe);
689 } else {
690 ret = gst_asf_parse_single_payload (&reader, &has_keyframe);
691 }
692 }
693
694 if (!ret) {
695 GST_WARNING ("Failed to parse payloads");
696 goto end;
697 }
698 GST_DEBUG ("Received packet of length %" G_GUINT32_FORMAT
699 ", padding %" G_GUINT32_FORMAT ", send time %" G_GUINT32_FORMAT
700 ", duration %" G_GUINT16_FORMAT " and %s keyframe(s)",
701 packet_len, padd_len, send_time, duration,
702 (has_keyframe) ? "with" : "without");
703
704 packet->packet_size = packet_len;
705 packet->padding = padd_len;
706 packet->send_time = send_time;
707 packet->duration = duration;
708 packet->has_keyframe = has_keyframe;
709 packet->multiple_payloads = mult_payloads ? TRUE : FALSE;
710 packet->padd_field_type = padding_len_type;
711 packet->packet_field_type = packet_len_type;
712 packet->seq_field_type = seq_len_type;
713 packet->err_cor_len = err_length;
714
715 return ret;
716
717 error:
718 ret = FALSE;
719 GST_WARNING ("Error while parsing data packet");
720 end:
721 return ret;
722 }
723
724 static gboolean
gst_asf_parse_file_properties_obj(GstByteReader * reader,GstAsfFileInfo * asfinfo)725 gst_asf_parse_file_properties_obj (GstByteReader * reader,
726 GstAsfFileInfo * asfinfo)
727 {
728 guint32 min_ps = 0;
729 guint32 max_ps = 0;
730 guint64 packets = 0;
731 guint32 flags = 0;
732 GST_DEBUG ("ASF: Parsing file properties object");
733
734 /* skip until data packets count */
735 if (!gst_byte_reader_skip (reader, 32))
736 return FALSE;
737 if (!gst_byte_reader_get_uint64_le (reader, &packets))
738 return FALSE;
739 asfinfo->packets_count = packets;
740 GST_DEBUG ("ASF: packets count %" G_GUINT64_FORMAT, packets);
741
742 /* skip until flags */
743 if (!gst_byte_reader_skip (reader, 24))
744 return FALSE;
745
746 if (!gst_byte_reader_get_uint32_le (reader, &flags))
747 return GST_FLOW_ERROR;
748 asfinfo->broadcast = (flags & 0x1) == 1;
749 GST_DEBUG ("ASF: broadcast flag: %s", asfinfo->broadcast ? "true" : "false");
750 if (!gst_byte_reader_get_uint32_le (reader, &min_ps))
751 return GST_FLOW_ERROR;
752 if (!gst_byte_reader_get_uint32_le (reader, &max_ps))
753 return GST_FLOW_ERROR;
754
755 if (min_ps != max_ps) {
756 GST_WARNING ("Minimum and maximum packet size differ "
757 "%" G_GUINT32_FORMAT " and %" G_GUINT32_FORMAT ", "
758 "ASF spec states they should be the same", min_ps, max_ps);
759 return FALSE;
760 }
761
762 GST_DEBUG ("ASF: Packet size: %" G_GUINT32_FORMAT, min_ps);
763 asfinfo->packet_size = min_ps;
764 if (!gst_byte_reader_skip (reader, 4))
765 return FALSE;
766
767 return TRUE;
768 }
769
770 gboolean
gst_asf_parse_headers(GstBuffer * buffer,GstAsfFileInfo * file_info)771 gst_asf_parse_headers (GstBuffer * buffer, GstAsfFileInfo * file_info)
772 {
773 GstMapInfo map;
774 gboolean ret;
775
776 gst_buffer_map (buffer, &map, GST_MAP_READ);
777 ret = gst_asf_parse_headers_from_data (map.data, map.size, file_info);
778 gst_buffer_unmap (buffer, &map);
779
780 return ret;
781 }
782
783 gboolean
gst_asf_parse_headers_from_data(guint8 * data,guint size,GstAsfFileInfo * file_info)784 gst_asf_parse_headers_from_data (guint8 * data, guint size,
785 GstAsfFileInfo * file_info)
786 {
787 gboolean ret = TRUE;
788 guint32 header_objects = 0;
789 guint32 i;
790 GstByteReader reader;
791 guint64 object_size;
792
793 object_size = gst_asf_match_and_peek_obj_size (data,
794 &(guids[ASF_HEADER_OBJECT_INDEX]));
795 if (object_size == 0) {
796 GST_WARNING ("ASF: Cannot parse, header guid not found at the beginning "
797 " of data");
798 return FALSE;
799 }
800
801 gst_byte_reader_init (&reader, data, size);
802
803 if (!gst_byte_reader_skip (&reader, ASF_GUID_OBJSIZE_SIZE))
804 goto error;
805 if (!gst_byte_reader_get_uint32_le (&reader, &header_objects))
806 goto error;
807 GST_DEBUG ("ASF: Header has %" G_GUINT32_FORMAT " child"
808 " objects", header_objects);
809 /* skip reserved bytes */
810 if (!gst_byte_reader_skip (&reader, 2))
811 goto error;
812
813 /* iterate through childs of header object */
814 for (i = 0; i < header_objects; i++) {
815 const guint8 *guid = NULL;
816 guint64 obj_size = 0;
817
818 if (!gst_byte_reader_get_data (&reader, ASF_GUID_SIZE, &guid))
819 goto error;
820 if (!gst_byte_reader_get_uint64_le (&reader, &obj_size))
821 goto error;
822
823 if (gst_asf_match_guid (guid, &guids[ASF_FILE_PROPERTIES_OBJECT_INDEX])) {
824 ret = gst_asf_parse_file_properties_obj (&reader, file_info);
825 } else {
826 /* we don't know/care about this object */
827 if (!gst_byte_reader_skip (&reader, obj_size - ASF_GUID_OBJSIZE_SIZE))
828 goto error;
829 }
830
831 if (!ret)
832 goto end;
833 }
834 goto end;
835
836 error:
837 ret = FALSE;
838 GST_WARNING ("ASF: Error while parsing headers");
839 end:
840 return ret;
841 }
842
843 #define MAP_GST_TO_ASF_TAG(tag, gst, asf) \
844 if (strcmp (tag, gst) == 0) \
845 return asf
846
847 /**
848 * gst_asf_get_asf_tag:
849 * @gsttag: a gstreamer tag
850 *
851 * Maps gstreamer tags to asf tags
852 *
853 * Returns: The tag corresponding name in asf files or NULL if it is not mapped
854 */
855 const gchar *
gst_asf_get_asf_tag(const gchar * gsttag)856 gst_asf_get_asf_tag (const gchar * gsttag)
857 {
858 g_return_val_if_fail (gsttag != NULL, NULL);
859
860 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_TITLE, ASF_TAG_TITLE);
861 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_TITLE_SORTNAME, ASF_TAG_TITLE_SORTNAME);
862 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ARTIST, ASF_TAG_ARTIST);
863 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ARTIST_SORTNAME, ASF_TAG_ARTIST_SORTNAME);
864 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ALBUM, ASF_TAG_ALBUM_TITLE);
865 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_ALBUM_SORTNAME,
866 ASF_TAG_ALBUM_TITLE_SORTNAME);
867 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_GENRE, ASF_TAG_GENRE);
868 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_COPYRIGHT, ASF_TAG_COPYRIGHT);
869 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_COMPOSER, ASF_TAG_COMPOSER);
870 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_COMMENT, ASF_TAG_COMMENT);
871 MAP_GST_TO_ASF_TAG (gsttag, GST_TAG_TRACK_NUMBER, ASF_TAG_TRACK_NUMBER);
872
873 return NULL;
874 }
875
876 guint
gst_asf_get_tag_field_type(GValue * value)877 gst_asf_get_tag_field_type (GValue * value)
878 {
879 if (G_VALUE_HOLDS_STRING (value))
880 return ASF_TAG_TYPE_UNICODE_STR;
881 if (G_VALUE_HOLDS_UINT (value))
882 return ASF_TAG_TYPE_DWORD;
883
884 return -1;
885 }
886
887 gboolean
gst_asf_tag_present_in_content_description(const gchar * tag)888 gst_asf_tag_present_in_content_description (const gchar * tag)
889 {
890 return strcmp (tag, GST_TAG_TITLE) == 0 ||
891 strcmp (tag, GST_TAG_ARTIST) == 0 ||
892 strcmp (tag, GST_TAG_COPYRIGHT) == 0 ||
893 strcmp (tag, GST_TAG_DESCRIPTION) == 0;
894 /* FIXME we have no tag for rating */
895 }
896