matroskamux: drop HEADER flag from output buffers
[platform/upstream/gst-plugins-good.git] / gst / matroska / ebml-write.c
1 /* GStreamer EBML I/O
2  * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  * (c) 2005 Michal Benes <michal.benes@xeris.cz>
4  *
5  * ebml-write.c: write EBML data to file/stream
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <string.h>
28
29 #include "ebml-write.h"
30 #include "ebml-ids.h"
31
32
33 GST_DEBUG_CATEGORY_STATIC (gst_ebml_write_debug);
34 #define GST_CAT_DEFAULT gst_ebml_write_debug
35
36 #define _do_init \
37       GST_DEBUG_CATEGORY_INIT (gst_ebml_write_debug, "ebmlwrite", 0, "Write EBML structured data")
38 #define parent_class gst_ebml_write_parent_class
39 G_DEFINE_TYPE_WITH_CODE (GstEbmlWrite, gst_ebml_write, GST_TYPE_OBJECT,
40     _do_init);
41
42 static void gst_ebml_write_finalize (GObject * object);
43
44 static void
45 gst_ebml_write_class_init (GstEbmlWriteClass * klass)
46 {
47   GObjectClass *object = G_OBJECT_CLASS (klass);
48
49   object->finalize = gst_ebml_write_finalize;
50 }
51
52 static void
53 gst_ebml_write_init (GstEbmlWrite * ebml)
54 {
55   ebml->srcpad = NULL;
56   ebml->pos = 0;
57   ebml->last_pos = G_MAXUINT64; /* force segment event */
58
59   ebml->cache = NULL;
60   ebml->streamheader = NULL;
61   ebml->streamheader_pos = 0;
62   ebml->writing_streamheader = FALSE;
63   ebml->caps = NULL;
64 }
65
66 static void
67 gst_ebml_write_finalize (GObject * object)
68 {
69   GstEbmlWrite *ebml = GST_EBML_WRITE (object);
70
71   gst_object_unref (ebml->srcpad);
72
73   if (ebml->cache) {
74     gst_byte_writer_free (ebml->cache);
75     ebml->cache = NULL;
76   }
77
78   if (ebml->streamheader) {
79     gst_byte_writer_free (ebml->streamheader);
80     ebml->streamheader = NULL;
81   }
82
83   if (ebml->caps) {
84     gst_caps_unref (ebml->caps);
85     ebml->caps = NULL;
86   }
87
88   G_OBJECT_CLASS (parent_class)->finalize (object);
89 }
90
91
92 /**
93  * gst_ebml_write_new:
94  * @srcpad: Source pad to which the output will be pushed.
95  *
96  * Creates a new #GstEbmlWrite.
97  *
98  * Returns: a new #GstEbmlWrite
99  */
100 GstEbmlWrite *
101 gst_ebml_write_new (GstPad * srcpad)
102 {
103   GstEbmlWrite *ebml =
104       GST_EBML_WRITE (g_object_new (GST_TYPE_EBML_WRITE, NULL));
105
106   ebml->srcpad = gst_object_ref (srcpad);
107   ebml->timestamp = GST_CLOCK_TIME_NONE;
108
109   gst_ebml_write_reset (ebml);
110
111   return ebml;
112 }
113
114
115 /**
116  * gst_ebml_write_reset:
117  * @ebml: a #GstEbmlWrite.
118  *
119  * Reset internal state of #GstEbmlWrite.
120  */
121 void
122 gst_ebml_write_reset (GstEbmlWrite * ebml)
123 {
124   ebml->pos = 0;
125   ebml->last_pos = G_MAXUINT64; /* force segment event */
126
127   if (ebml->cache) {
128     gst_byte_writer_free (ebml->cache);
129     ebml->cache = NULL;
130   }
131
132   if (ebml->caps) {
133     gst_caps_unref (ebml->caps);
134     ebml->caps = NULL;
135   }
136
137   ebml->last_write_result = GST_FLOW_OK;
138   ebml->timestamp = GST_CLOCK_TIME_NONE;
139 }
140
141
142 /**
143  * gst_ebml_last_write_result:
144  * @ebml: a #GstEbmlWrite.
145  *
146  * Returns: GST_FLOW_OK if there was not write error since the last call of
147  *          gst_ebml_last_write_result or code of the error.
148  */
149 GstFlowReturn
150 gst_ebml_last_write_result (GstEbmlWrite * ebml)
151 {
152   GstFlowReturn res = ebml->last_write_result;
153
154   ebml->last_write_result = GST_FLOW_OK;
155
156   return res;
157 }
158
159
160 void
161 gst_ebml_start_streamheader (GstEbmlWrite * ebml)
162 {
163   g_return_if_fail (ebml->streamheader == NULL);
164
165   GST_DEBUG ("Starting streamheader at %" G_GUINT64_FORMAT, ebml->pos);
166   ebml->streamheader = gst_byte_writer_new_with_size (1000, FALSE);
167   ebml->streamheader_pos = ebml->pos;
168   ebml->writing_streamheader = TRUE;
169 }
170
171 GstBuffer *
172 gst_ebml_stop_streamheader (GstEbmlWrite * ebml)
173 {
174   GstBuffer *buffer;
175
176   if (!ebml->streamheader)
177     return NULL;
178
179   buffer = gst_byte_writer_free_and_get_buffer (ebml->streamheader);
180   ebml->streamheader = NULL;
181   GST_DEBUG ("Streamheader was size %" G_GSIZE_FORMAT,
182       gst_buffer_get_size (buffer));
183
184   ebml->writing_streamheader = FALSE;
185   return buffer;
186 }
187
188 /**
189  * gst_ebml_write_set_cache:
190  * @ebml: a #GstEbmlWrite.
191  * @size: size of the cache.
192  * Create a cache.
193  *
194  * The idea is that you use this for writing a lot
195  * of small elements. This will just "queue" all of
196  * them and they'll be pushed to the next element all
197  * at once. This saves memory and time for buffer
198  * allocation and init, and it looks better.
199  */
200 void
201 gst_ebml_write_set_cache (GstEbmlWrite * ebml, guint size)
202 {
203   g_return_if_fail (ebml->cache == NULL);
204
205   GST_DEBUG ("Starting cache at %" G_GUINT64_FORMAT, ebml->pos);
206   ebml->cache = gst_byte_writer_new_with_size (size, FALSE);
207   ebml->cache_pos = ebml->pos;
208 }
209
210 static gboolean
211 gst_ebml_writer_send_segment_event (GstEbmlWrite * ebml, guint64 new_pos)
212 {
213   GstSegment segment;
214   gboolean res;
215
216   GST_INFO ("seeking to %" G_GUINT64_FORMAT, new_pos);
217
218   gst_segment_init (&segment, GST_FORMAT_BYTES);
219   segment.start = new_pos;
220   segment.stop = -1;
221   segment.position = 0;
222
223   res = gst_pad_push_event (ebml->srcpad, gst_event_new_segment (&segment));
224
225   if (!res)
226     GST_WARNING ("seek to %" G_GUINT64_FORMAT "failed", new_pos);
227
228   return res;
229 }
230
231 /**
232  * gst_ebml_write_flush_cache:
233  * @ebml:      a #GstEbmlWrite.
234  * @timestamp: timestamp of the buffer.
235  *
236  * Flush the cache.
237  */
238 void
239 gst_ebml_write_flush_cache (GstEbmlWrite * ebml, gboolean is_keyframe,
240     GstClockTime timestamp)
241 {
242   GstBuffer *buffer;
243
244   if (!ebml->cache)
245     return;
246
247   buffer = gst_byte_writer_free_and_get_buffer (ebml->cache);
248   ebml->cache = NULL;
249   GST_DEBUG ("Flushing cache of size %" G_GSIZE_FORMAT,
250       gst_buffer_get_size (buffer));
251   GST_BUFFER_TIMESTAMP (buffer) = timestamp;
252   GST_BUFFER_OFFSET (buffer) = ebml->pos - gst_buffer_get_size (buffer);
253   GST_BUFFER_OFFSET_END (buffer) = ebml->pos;
254   if (ebml->last_write_result == GST_FLOW_OK) {
255     if (GST_BUFFER_OFFSET (buffer) != ebml->last_pos) {
256       gst_ebml_writer_send_segment_event (ebml, GST_BUFFER_OFFSET (buffer));
257       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
258     } else {
259       GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
260     }
261     if (ebml->writing_streamheader) {
262       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
263     } else {
264       GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_HEADER);
265     }
266     if (!is_keyframe) {
267       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
268     }
269     ebml->last_pos = ebml->pos;
270     ebml->last_write_result = gst_pad_push (ebml->srcpad, buffer);
271   } else {
272     gst_buffer_unref (buffer);
273   }
274 }
275
276
277 /**
278  * gst_ebml_write_element_new:
279  * @ebml: a #GstEbmlWrite.
280  * @size: size of the requested buffer.
281  *
282  * Create a buffer for one element. If there is
283  * a cache, use that instead.
284  *
285  * Returns: A new #GstBuffer.
286  */
287 static GstBuffer *
288 gst_ebml_write_element_new (GstEbmlWrite * ebml, GstMapInfo * map, guint size)
289 {
290   /* Create new buffer of size + ID + length */
291   GstBuffer *buf;
292
293   /* length, ID */
294   size += 12;
295
296   buf = gst_buffer_new_and_alloc (size);
297   GST_BUFFER_TIMESTAMP (buf) = ebml->timestamp;
298
299   /* FIXME unmap not possible */
300   gst_buffer_map (buf, map, GST_MAP_WRITE);
301
302   return buf;
303 }
304
305
306 /**
307  * gst_ebml_write_element_id:
308  * @data_inout: Pointer to data pointer
309  * @id: Element ID that should be written.
310  * 
311  * Write element ID into a buffer.
312  */
313 static void
314 gst_ebml_write_element_id (guint8 ** data_inout, guint32 id)
315 {
316   guint8 *data = *data_inout;
317   guint bytes = 4, mask = 0x10;
318
319   /* get ID length */
320   while (!(id & (mask << ((bytes - 1) * 8))) && bytes > 0) {
321     mask <<= 1;
322     bytes--;
323   }
324
325   /* if invalid ID, use dummy */
326   if (bytes == 0) {
327     GST_WARNING ("Invalid ID, voiding");
328     bytes = 1;
329     id = GST_EBML_ID_VOID;
330   }
331
332   /* write out, BE */
333   *data_inout += bytes;
334   while (bytes--) {
335     data[bytes] = id & 0xff;
336     id >>= 8;
337   }
338 }
339
340
341 /**
342  * gst_ebml_write_element_size:
343  * @data_inout: Pointer to data pointer
344  * @size: Element length.
345  *
346  * Write element length into a buffer.
347  */
348 static void
349 gst_ebml_write_element_size (guint8 ** data_inout, guint64 size)
350 {
351   guint8 *data = *data_inout;
352   guint bytes = 1, mask = 0x80;
353
354   if (size != GST_EBML_SIZE_UNKNOWN) {
355     /* how many bytes? - use mask-1 because an all-1 bitset is not allowed */
356     while (bytes <= 8 && (size >> ((bytes - 1) * 8)) >= (mask - 1)) {
357       mask >>= 1;
358       bytes++;
359     }
360
361     /* if invalid size, use max. */
362     if (bytes > 8) {
363       GST_WARNING ("Invalid size, writing size unknown");
364       mask = 0x01;
365       bytes = 8;
366       /* Now here's a real FIXME: we cannot read those yet! */
367       size = GST_EBML_SIZE_UNKNOWN;
368     }
369   } else {
370     mask = 0x01;
371     bytes = 8;
372   }
373
374   /* write out, BE, with length size marker */
375   *data_inout += bytes;
376   while (bytes-- > 0) {
377     data[bytes] = size & 0xff;
378     size >>= 8;
379     if (!bytes)
380       *data |= mask;
381   }
382 }
383
384
385 /**
386  * gst_ebml_write_element_data:
387  * @data_inout: Pointer to data pointer
388  * @write: Data that should be written.
389  * @length: Length of the data.
390  *
391  * Write element data into a buffer.
392  */
393 static void
394 gst_ebml_write_element_data (guint8 ** data_inout, guint8 * write,
395     guint64 length)
396 {
397   memcpy (*data_inout, write, length);
398   *data_inout += length;
399 }
400
401
402 /**
403  * gst_ebml_write_element_push:
404  * @ebml: #GstEbmlWrite
405  * @buf: #GstBuffer to be written.
406  * @buf_data: Start of data to push from @buf (or NULL for whole buffer).
407  * @buf_data_end: Data pointer positioned after the last byte in @buf_data (or
408  * NULL for whole buffer).
409  * 
410  * Write out buffer by moving it to the next element.
411  */
412 static void
413 gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf,
414     guint8 * buf_data, guint8 * buf_data_end)
415 {
416   GstMapInfo map;
417   guint data_size;
418
419   map.data = NULL;
420
421   if (buf_data_end)
422     data_size = buf_data_end - buf_data;
423   else
424     data_size = gst_buffer_get_size (buf);
425
426   ebml->pos += data_size;
427
428   /* if there's no cache, then don't push it! */
429   if (ebml->writing_streamheader) {
430     if (!buf_data) {
431       gst_buffer_map (buf, &map, GST_MAP_READ);
432       buf_data = map.data;
433     }
434     if (!buf_data)
435       GST_WARNING ("Failed to map buffer");
436     else if (!gst_byte_writer_put_data (ebml->streamheader, buf_data,
437             data_size))
438       GST_WARNING ("Error writing data to streamheader");
439   }
440   if (ebml->cache) {
441     if (!buf_data) {
442       gst_buffer_map (buf, &map, GST_MAP_READ);
443       buf_data = map.data;
444     }
445     if (!buf_data)
446       GST_WARNING ("Failed to map buffer");
447     else if (!gst_byte_writer_put_data (ebml->cache, buf_data, data_size))
448       GST_WARNING ("Error writing data to cache");
449     if (map.data)
450       gst_buffer_unmap (buf, &map);
451     gst_buffer_unref (buf);
452     return;
453   }
454
455   if (buf_data && map.data)
456     gst_buffer_unmap (buf, &map);
457
458   if (ebml->last_write_result == GST_FLOW_OK) {
459     buf = gst_buffer_make_writable (buf);
460     GST_BUFFER_OFFSET (buf) = ebml->pos - data_size;
461     GST_BUFFER_OFFSET_END (buf) = ebml->pos;
462     if (ebml->writing_streamheader) {
463       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
464     } else {
465       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_HEADER);
466     }
467     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
468
469     if (GST_BUFFER_OFFSET (buf) != ebml->last_pos) {
470       gst_ebml_writer_send_segment_event (ebml, GST_BUFFER_OFFSET (buf));
471       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
472     } else {
473       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
474     }
475     ebml->last_pos = ebml->pos;
476     ebml->last_write_result = gst_pad_push (ebml->srcpad, buf);
477   } else {
478     gst_buffer_unref (buf);
479   }
480 }
481
482
483 /**
484  * gst_ebml_write_seek:
485  * @ebml: #GstEbmlWrite
486  * @pos: Seek position.
487  * 
488  * Seek.
489  */
490 void
491 gst_ebml_write_seek (GstEbmlWrite * ebml, guint64 pos)
492 {
493   if (ebml->writing_streamheader) {
494     GST_DEBUG ("wanting to seek to pos %" G_GUINT64_FORMAT, pos);
495     if (pos >= ebml->streamheader_pos &&
496         pos <= ebml->streamheader_pos + ebml->streamheader->parent.size) {
497       gst_byte_writer_set_pos (ebml->streamheader,
498           pos - ebml->streamheader_pos);
499       GST_DEBUG ("seeked in streamheader to position %" G_GUINT64_FORMAT,
500           pos - ebml->streamheader_pos);
501     } else {
502       GST_WARNING
503           ("we are writing streamheader still and seek is out of bounds");
504     }
505   }
506   /* Cache seeking. A bit dangerous, we assume the client writer
507    * knows what he's doing... */
508   if (ebml->cache) {
509     /* within bounds? */
510     if (pos >= ebml->cache_pos &&
511         pos <= ebml->cache_pos + ebml->cache->parent.size) {
512       GST_DEBUG ("seeking in cache to %" G_GUINT64_FORMAT, pos);
513       ebml->pos = pos;
514       gst_byte_writer_set_pos (ebml->cache, ebml->pos - ebml->cache_pos);
515       return;
516     } else {
517       GST_LOG ("Seek outside cache range. Clearing...");
518       gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
519     }
520   }
521
522   GST_INFO ("scheduling seek to %" G_GUINT64_FORMAT, pos);
523   ebml->pos = pos;
524 }
525
526
527 /**
528  * gst_ebml_write_get_uint_size:
529  * @num: Number to be encoded.
530  * 
531  * Get number of bytes needed to write a uint.
532  *
533  * Returns: Encoded uint length.
534  */
535 static guint
536 gst_ebml_write_get_uint_size (guint64 num)
537 {
538   guint size = 1;
539
540   /* get size */
541   while (size < 8 && num >= (G_GINT64_CONSTANT (1) << (size * 8))) {
542     size++;
543   }
544
545   return size;
546 }
547
548
549 /**
550  * gst_ebml_write_set_uint:
551  * @data_inout: Pointer to data pointer
552  * @num: Number to be written.
553  * @size: Encoded number length.
554  *
555  * Write an uint into a buffer.
556  */
557 static void
558 gst_ebml_write_set_uint (guint8 ** data_inout, guint64 num, guint size)
559 {
560   guint8 *data = *data_inout;
561
562   *data_inout += size;
563
564   while (size-- > 0) {
565     data[size] = num & 0xff;
566     num >>= 8;
567   }
568 }
569
570
571 /**
572  * gst_ebml_write_uint:
573  * @ebml: #GstEbmlWrite
574  * @id: Element ID.
575  * @num: Number to be written.
576  *
577  * Write uint element.
578  */
579 void
580 gst_ebml_write_uint (GstEbmlWrite * ebml, guint32 id, guint64 num)
581 {
582   GstBuffer *buf;
583   guint8 *data_start, *data_end;
584   guint size = gst_ebml_write_get_uint_size (num);
585   GstMapInfo map;
586
587   buf = gst_ebml_write_element_new (ebml, &map, sizeof (num));
588   data_end = data_start = map.data;
589
590   /* write */
591   gst_ebml_write_element_id (&data_end, id);
592   gst_ebml_write_element_size (&data_end, size);
593   gst_ebml_write_set_uint (&data_end, num, size);
594   gst_buffer_unmap (buf, &map);
595   gst_buffer_set_size (buf, (data_end - data_start));
596
597   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
598 }
599
600
601 /**
602  * gst_ebml_write_sint:
603  * @ebml: #GstEbmlWrite
604  * @id: Element ID.
605  * @num: Number to be written.
606  *
607  * Write sint element.
608  */
609 void
610 gst_ebml_write_sint (GstEbmlWrite * ebml, guint32 id, gint64 num)
611 {
612   GstBuffer *buf;
613   guint8 *data_start, *data_end;
614   GstMapInfo map;
615
616   /* if the signed number is on the edge of a extra-byte,
617    * then we'll fall over when detecting it. Example: if I
618    * have a number (-)0x8000 (G_MINSHORT), then my abs()<<1
619    * will be 0x10000; this is G_MAXUSHORT+1! So: if (<0) -1. */
620   guint64 unum = (num < 0 ? (-num - 1) << 1 : num << 1);
621   guint size = gst_ebml_write_get_uint_size (unum);
622
623   buf = gst_ebml_write_element_new (ebml, &map, sizeof (num));
624   data_end = data_start = map.data;
625
626   /* make unsigned */
627   if (num >= 0) {
628     unum = num;
629   } else {
630     unum = ((guint64) 0x80) << ((size - 1) * 8);
631     unum += num;
632     unum |= ((guint64) 0x80) << ((size - 1) * 8);
633   }
634
635   /* write */
636   gst_ebml_write_element_id (&data_end, id);
637   gst_ebml_write_element_size (&data_end, size);
638   gst_ebml_write_set_uint (&data_end, unum, size);
639   gst_buffer_unmap (buf, &map);
640   gst_buffer_set_size (buf, (data_end - data_start));
641
642   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
643 }
644
645
646 /**
647  * gst_ebml_write_float:
648  * @ebml: #GstEbmlWrite
649  * @id: Element ID.
650  * @num: Number to be written.
651  *
652  * Write float element.
653  */
654 void
655 gst_ebml_write_float (GstEbmlWrite * ebml, guint32 id, gdouble num)
656 {
657   GstBuffer *buf;
658   GstMapInfo map;
659   guint8 *data_start, *data_end;
660
661   buf = gst_ebml_write_element_new (ebml, &map, sizeof (num));
662   data_end = data_start = map.data;
663
664   gst_ebml_write_element_id (&data_end, id);
665   gst_ebml_write_element_size (&data_end, 8);
666   num = GDOUBLE_TO_BE (num);
667   gst_ebml_write_element_data (&data_end, (guint8 *) & num, 8);
668   gst_buffer_unmap (buf, &map);
669   gst_buffer_set_size (buf, (data_end - data_start));
670
671   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
672 }
673
674
675 /**
676  * gst_ebml_write_ascii:
677  * @ebml: #GstEbmlWrite
678  * @id: Element ID.
679  * @str: String to be written.
680  *
681  * Write string element.
682  */
683 void
684 gst_ebml_write_ascii (GstEbmlWrite * ebml, guint32 id, const gchar * str)
685 {
686   gint len = strlen (str) + 1;  /* add trailing '\0' */
687   GstBuffer *buf;
688   GstMapInfo map;
689   guint8 *data_start, *data_end;
690
691   buf = gst_ebml_write_element_new (ebml, &map, len);
692   data_end = data_start = map.data;
693
694   gst_ebml_write_element_id (&data_end, id);
695   gst_ebml_write_element_size (&data_end, len);
696   gst_ebml_write_element_data (&data_end, (guint8 *) str, len);
697   gst_buffer_unmap (buf, &map);
698   gst_buffer_set_size (buf, (data_end - data_start));
699
700   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
701 }
702
703
704 /**
705  * gst_ebml_write_utf8:
706  * @ebml: #GstEbmlWrite
707  * @id: Element ID.
708  * @str: String to be written.
709  *
710  * Write utf8 encoded string element.
711  */
712 void
713 gst_ebml_write_utf8 (GstEbmlWrite * ebml, guint32 id, const gchar * str)
714 {
715   gst_ebml_write_ascii (ebml, id, str);
716 }
717
718
719 /**
720  * gst_ebml_write_date:
721  * @ebml: #GstEbmlWrite
722  * @id: Element ID.
723  * @date: Date in seconds since the unix epoch.
724  *
725  * Write date element.
726  */
727 void
728 gst_ebml_write_date (GstEbmlWrite * ebml, guint32 id, gint64 date)
729 {
730   gst_ebml_write_sint (ebml, id, (date - GST_EBML_DATE_OFFSET) * GST_SECOND);
731 }
732
733 /**
734  * gst_ebml_write_master_start:
735  * @ebml: #GstEbmlWrite
736  * @id: Element ID.
737  *
738  * Start wiriting mater element.
739  *
740  * Master writing is annoying. We use a size marker of
741  * the max. allowed length, so that we can later fill it
742  * in validly. 
743  *
744  * Returns: Master starting position.
745  */
746 guint64
747 gst_ebml_write_master_start (GstEbmlWrite * ebml, guint32 id)
748 {
749   guint64 pos = ebml->pos;
750   GstBuffer *buf;
751   GstMapInfo map;
752   guint8 *data_start, *data_end;
753
754   buf = gst_ebml_write_element_new (ebml, &map, 0);
755   data_end = data_start = map.data;
756
757   gst_ebml_write_element_id (&data_end, id);
758   pos += data_end - data_start;
759   gst_ebml_write_element_size (&data_end, GST_EBML_SIZE_UNKNOWN);
760   gst_buffer_unmap (buf, &map);
761   gst_buffer_set_size (buf, (data_end - data_start));
762
763   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
764
765   return pos;
766 }
767
768
769 /**
770  * gst_ebml_write_master_finish_full:
771  * @ebml: #GstEbmlWrite
772  * @startpos: Master starting position.
773  *
774  * Finish writing master element.  Size of master element is difference between
775  * current position and the element start, and @extra_size added to this.
776  */
777 void
778 gst_ebml_write_master_finish_full (GstEbmlWrite * ebml, guint64 startpos,
779     guint64 extra_size)
780 {
781   guint64 pos = ebml->pos;
782   guint8 *data = g_malloc (8);
783   GstBuffer *buf = gst_buffer_new_wrapped (data, 8);
784
785   gst_ebml_write_seek (ebml, startpos);
786
787   GST_WRITE_UINT64_BE (data,
788       (G_GINT64_CONSTANT (1) << 56) | (pos - startpos - 8 + extra_size));
789
790   gst_ebml_write_element_push (ebml, buf, NULL, NULL);
791   gst_ebml_write_seek (ebml, pos);
792 }
793
794 void
795 gst_ebml_write_master_finish (GstEbmlWrite * ebml, guint64 startpos)
796 {
797   gst_ebml_write_master_finish_full (ebml, startpos, 0);
798 }
799
800 /**
801  * gst_ebml_write_binary:
802  * @ebml: #GstEbmlWrite
803  * @id: Element ID.
804  * @binary: Data to be written.
805  * @length: Length of the data
806  *
807  * Write an element with binary data.
808  */
809 void
810 gst_ebml_write_binary (GstEbmlWrite * ebml,
811     guint32 id, guint8 * binary, guint64 length)
812 {
813   GstBuffer *buf;
814   GstMapInfo map;
815   guint8 *data_start, *data_end;
816
817   buf = gst_ebml_write_element_new (ebml, &map, length);
818   data_end = data_start = map.data;
819
820   gst_ebml_write_element_id (&data_end, id);
821   gst_ebml_write_element_size (&data_end, length);
822   gst_ebml_write_element_data (&data_end, binary, length);
823   gst_buffer_unmap (buf, &map);
824   gst_buffer_set_size (buf, (data_end - data_start));
825
826   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
827 }
828
829
830 /**
831  * gst_ebml_write_buffer_header:
832  * @ebml: #GstEbmlWrite
833  * @id: Element ID.
834  * @length: Length of the data
835  * 
836  * Write header of the binary element (use with gst_ebml_write_buffer function).
837  * 
838  * For things like video frames and audio samples,
839  * you want to use this function, as it doesn't have
840  * the overhead of memcpy() that other functions
841  * such as write_binary() do have.
842  */
843 void
844 gst_ebml_write_buffer_header (GstEbmlWrite * ebml, guint32 id, guint64 length)
845 {
846   GstBuffer *buf;
847   GstMapInfo map;
848   guint8 *data_start, *data_end;
849
850   buf = gst_ebml_write_element_new (ebml, &map, 0);
851   data_end = data_start = map.data;
852
853   gst_ebml_write_element_id (&data_end, id);
854   gst_ebml_write_element_size (&data_end, length);
855   gst_buffer_unmap (buf, &map);
856   gst_buffer_set_size (buf, (data_end - data_start));
857
858   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
859 }
860
861
862 /**
863  * gst_ebml_write_buffer:
864  * @ebml: #GstEbmlWrite
865  * @buf: #GstBuffer cointaining the data.
866  *
867  * Write  binary element (see gst_ebml_write_buffer_header).
868  */
869 void
870 gst_ebml_write_buffer (GstEbmlWrite * ebml, GstBuffer * buf)
871 {
872   gst_ebml_write_element_push (ebml, buf, NULL, NULL);
873 }
874
875
876 /**
877  * gst_ebml_replace_uint:
878  * @ebml: #GstEbmlWrite
879  * @pos: Position of the uint that should be replaced.
880  * @num: New value.
881  *
882  * Replace uint with a new value.
883  * 
884  * When replacing a uint, we assume that it is *always*
885  * 8-byte, since that's the safest guess we can do. This
886  * is just for simplicity.
887  *
888  * FIXME: this function needs to be replaced with something
889  * proper. This is a crude hack.
890  */
891 void
892 gst_ebml_replace_uint (GstEbmlWrite * ebml, guint64 pos, guint64 num)
893 {
894   guint64 oldpos = ebml->pos;
895   guint8 *data_start, *data_end;
896   GstBuffer *buf;
897
898   data_start = g_malloc (8);
899   data_end = data_start;
900   buf = gst_buffer_new_wrapped (data_start, 8);
901
902   gst_ebml_write_seek (ebml, pos);
903   gst_ebml_write_set_uint (&data_end, num, 8);
904
905   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
906   gst_ebml_write_seek (ebml, oldpos);
907 }
908
909 /**
910  * gst_ebml_write_header:
911  * @ebml: #GstEbmlWrite
912  * @doctype: Document type.
913  * @version: Document type version.
914  * 
915  * Write EBML header.
916  */
917 void
918 gst_ebml_write_header (GstEbmlWrite * ebml, const gchar * doctype,
919     guint version)
920 {
921   guint64 pos;
922
923   /* write the basic EBML header */
924   gst_ebml_write_set_cache (ebml, 0x40);
925   pos = gst_ebml_write_master_start (ebml, GST_EBML_ID_HEADER);
926 #if (GST_EBML_VERSION != 1)
927   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLVERSION, GST_EBML_VERSION);
928   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLREADVERSION, GST_EBML_VERSION);
929 #endif
930 #if 0
931   /* we don't write these until they're "non-default" (never!) */
932   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXIDLENGTH, sizeof (guint32));
933   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXSIZELENGTH, sizeof (guint64));
934 #endif
935   gst_ebml_write_ascii (ebml, GST_EBML_ID_DOCTYPE, doctype);
936   gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEVERSION, version);
937   gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEREADVERSION, version);
938   gst_ebml_write_master_finish (ebml, pos);
939   gst_ebml_write_flush_cache (ebml, FALSE, 0);
940 }