matroskamux: add streamheaders
[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., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <string.h>
28 #include <gst/floatcast/floatcast.h>
29
30 #include "ebml-write.h"
31 #include "ebml-ids.h"
32
33
34 GST_DEBUG_CATEGORY_STATIC (gst_ebml_write_debug);
35 #define GST_CAT_DEFAULT gst_ebml_write_debug
36
37 #define _do_init(thing) \
38       GST_DEBUG_CATEGORY_INIT (gst_ebml_write_debug, "ebmlwrite", 0, "Write EBML structured data")
39 GST_BOILERPLATE_FULL (GstEbmlWrite, gst_ebml_write, GstObject, GST_TYPE_OBJECT,
40     _do_init);
41
42 static void gst_ebml_write_finalize (GObject * object);
43
44
45 static void
46 gst_ebml_write_base_init (gpointer g_class)
47 {
48 }
49
50 static void
51 gst_ebml_write_class_init (GstEbmlWriteClass * klass)
52 {
53   GObjectClass *object = G_OBJECT_CLASS (klass);
54
55   object->finalize = gst_ebml_write_finalize;
56 }
57
58 static void
59 gst_ebml_write_init (GstEbmlWrite * ebml, GstEbmlWriteClass * klass)
60 {
61   ebml->srcpad = NULL;
62   ebml->pos = 0;
63
64   ebml->cache = NULL;
65   ebml->streamheader = NULL;
66   ebml->streamheader_pos = 0;
67   ebml->writing_streamheader = FALSE;
68 }
69
70 static void
71 gst_ebml_write_finalize (GObject * object)
72 {
73   GstEbmlWrite *ebml = GST_EBML_WRITE (object);
74
75   gst_object_unref (ebml->srcpad);
76
77   if (ebml->cache) {
78     gst_byte_writer_free (ebml->cache);
79     ebml->cache = NULL;
80   }
81
82   if (ebml->streamheader) {
83     gst_byte_writer_free (ebml->streamheader);
84     ebml->streamheader = NULL;
85   }
86
87   GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
88 }
89
90
91 /**
92  * gst_ebml_write_new:
93  * @srcpad: Source pad to which the output will be pushed.
94  *
95  * Creates a new #GstEbmlWrite.
96  *
97  * Returns: a new #GstEbmlWrite
98  */
99 GstEbmlWrite *
100 gst_ebml_write_new (GstPad * srcpad)
101 {
102   GstEbmlWrite *ebml =
103       GST_EBML_WRITE (g_object_new (GST_TYPE_EBML_WRITE, NULL));
104
105   ebml->srcpad = gst_object_ref (srcpad);
106   ebml->timestamp = GST_CLOCK_TIME_NONE;
107
108   gst_ebml_write_reset (ebml);
109
110   return ebml;
111 }
112
113
114 /**
115  * gst_ebml_write_reset:
116  * @ebml: a #GstEbmlWrite.
117  *
118  * Reset internal state of #GstEbmlWrite.
119  */
120 void
121 gst_ebml_write_reset (GstEbmlWrite * ebml)
122 {
123   ebml->pos = 0;
124
125   if (ebml->cache) {
126     gst_byte_writer_free (ebml->cache);
127     ebml->cache = NULL;
128   }
129   ebml->last_write_result = GST_FLOW_OK;
130   ebml->timestamp = GST_CLOCK_TIME_NONE;
131   ebml->need_newsegment = TRUE;
132 }
133
134
135 /**
136  * gst_ebml_last_write_result:
137  * @ebml: a #GstEbmlWrite.
138  *
139  * Returns: GST_FLOW_OK if there was not write error since the last call of
140  *          gst_ebml_last_write_result or code of the error.
141  */
142 GstFlowReturn
143 gst_ebml_last_write_result (GstEbmlWrite * ebml)
144 {
145   GstFlowReturn res = ebml->last_write_result;
146
147   ebml->last_write_result = GST_FLOW_OK;
148
149   return res;
150 }
151
152
153 void
154 gst_ebml_start_streamheader (GstEbmlWrite * ebml)
155 {
156   g_return_if_fail (ebml->streamheader == NULL);
157
158   GST_DEBUG ("Starting streamheader at %" G_GUINT64_FORMAT, ebml->pos);
159   ebml->streamheader = gst_byte_writer_new_with_size (1000, FALSE);
160   ebml->streamheader_pos = ebml->pos;
161   ebml->writing_streamheader = TRUE;
162 }
163
164 GstBuffer *
165 gst_ebml_stop_streamheader (GstEbmlWrite * ebml)
166 {
167   GstBuffer *buffer;
168
169   if (!ebml->streamheader)
170     return NULL;
171
172   buffer = gst_byte_writer_free_and_get_buffer (ebml->streamheader);
173   ebml->streamheader = NULL;
174   GST_DEBUG ("Streamheader was size %d", GST_BUFFER_SIZE (buffer));
175
176   ebml->writing_streamheader = FALSE;
177   return buffer;
178 }
179
180 /**
181  * gst_ebml_write_set_cache:
182  * @ebml: a #GstEbmlWrite.
183  * @size: size of the cache.
184  * Create a cache.
185  *
186  * The idea is that you use this for writing a lot
187  * of small elements. This will just "queue" all of
188  * them and they'll be pushed to the next element all
189  * at once. This saves memory and time for buffer
190  * allocation and init, and it looks better.
191  */
192 void
193 gst_ebml_write_set_cache (GstEbmlWrite * ebml, guint size)
194 {
195   g_return_if_fail (ebml->cache == NULL);
196
197   GST_DEBUG ("Starting cache at %" G_GUINT64_FORMAT, ebml->pos);
198   ebml->cache = gst_byte_writer_new_with_size (size, FALSE);
199   ebml->cache_pos = ebml->pos;
200 }
201
202 /**
203  * gst_ebml_write_flush_cache:
204  * @ebml: a #GstEbmlWrite.
205  *
206  * Flush the cache.
207  */
208 void
209 gst_ebml_write_flush_cache (GstEbmlWrite * ebml)
210 {
211   GstBuffer *buffer;
212
213   if (!ebml->cache)
214     return;
215
216   buffer = gst_byte_writer_free_and_get_buffer (ebml->cache);
217   ebml->cache = NULL;
218   GST_DEBUG ("Flushing cache of size %d", GST_BUFFER_SIZE (buffer));
219
220   if (ebml->last_write_result == GST_FLOW_OK) {
221     if (ebml->need_newsegment) {
222       GstEvent *ev;
223
224       ev = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0);
225       if (gst_pad_push_event (ebml->srcpad, ev))
226         ebml->need_newsegment = FALSE;
227     }
228     ebml->last_write_result = gst_pad_push (ebml->srcpad, buffer);
229   } else {
230     gst_buffer_unref (buffer);
231   }
232 }
233
234
235 /**
236  * gst_ebml_write_element_new:
237  * @ebml: a #GstEbmlWrite.
238  * @size: size of the requested buffer.
239  *
240  * Create a buffer for one element. If there is
241  * a cache, use that instead.
242  *
243  * Returns: A new #GstBuffer.
244  */
245 static GstBuffer *
246 gst_ebml_write_element_new (GstEbmlWrite * ebml, guint size)
247 {
248   /* Create new buffer of size + ID + length */
249   GstBuffer *buf;
250
251   /* length, ID */
252   size += 12;
253
254   buf = gst_buffer_new_and_alloc (size);
255   GST_BUFFER_SIZE (buf) = 0;
256   GST_BUFFER_TIMESTAMP (buf) = ebml->timestamp;
257
258   return buf;
259 }
260
261
262 /**
263  * gst_ebml_write_element_id:
264  * @buf: Buffer to which id should be written.
265  * @id: Element ID that should be written.
266  * 
267  * Write element ID into a buffer.
268  */
269 static void
270 gst_ebml_write_element_id (GstBuffer * buf, guint32 id)
271 {
272   guint8 *data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
273   guint bytes = 4, mask = 0x10;
274
275   /* get ID length */
276   while (!(id & (mask << ((bytes - 1) * 8))) && bytes > 0) {
277     mask <<= 1;
278     bytes--;
279   }
280
281   /* if invalid ID, use dummy */
282   if (bytes == 0) {
283     GST_WARNING ("Invalid ID, voiding");
284     bytes = 1;
285     id = GST_EBML_ID_VOID;
286   }
287
288   /* write out, BE */
289   GST_BUFFER_SIZE (buf) += bytes;
290   while (bytes--) {
291     data[bytes] = id & 0xff;
292     id >>= 8;
293   }
294 }
295
296
297 /**
298  * gst_ebml_write_element_size:
299  * @buf: #GstBuffer to which size should be written.
300  * @size: Element length.
301  * 
302  * Write element length into a buffer.
303  */
304 static void
305 gst_ebml_write_element_size (GstBuffer * buf, guint64 size)
306 {
307   guint8 *data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
308   guint bytes = 1, mask = 0x80;
309
310   if (size != GST_EBML_SIZE_UNKNOWN) {
311     /* how many bytes? - use mask-1 because an all-1 bitset is not allowed */
312     while ((size >> ((bytes - 1) * 8)) >= (mask - 1) && bytes <= 8) {
313       mask >>= 1;
314       bytes++;
315     }
316
317     /* if invalid size, use max. */
318     if (bytes > 8) {
319       GST_WARNING ("Invalid size, writing size unknown");
320       mask = 0x01;
321       bytes = 8;
322       /* Now here's a real FIXME: we cannot read those yet! */
323       size = GST_EBML_SIZE_UNKNOWN;
324     }
325   } else {
326     mask = 0x01;
327     bytes = 8;
328   }
329
330   /* write out, BE, with length size marker */
331   GST_BUFFER_SIZE (buf) += bytes;
332   while (bytes-- > 0) {
333     data[bytes] = size & 0xff;
334     size >>= 8;
335     if (!bytes)
336       *data |= mask;
337   }
338 }
339
340
341 /**
342  * gst_ebml_write_element_data:
343  * @buf: #GstBuffer to which data should be written.
344  * @write: Data that should be written.
345  * @length: Length of the data.
346  *
347  * Write element data into a buffer.
348  */
349 static void
350 gst_ebml_write_element_data (GstBuffer * buf, guint8 * write, guint64 length)
351 {
352   guint8 *data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
353
354   memcpy (data, write, length);
355   GST_BUFFER_SIZE (buf) += length;
356 }
357
358
359 /**
360  * gst_ebml_write_element_push:
361  * @ebml: #GstEbmlWrite
362  * @buf: #GstBuffer to be written.
363  * 
364  * Write out buffer by moving it to the next element.
365  */
366 static void
367 gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf)
368 {
369   guint data_size = GST_BUFFER_SIZE (buf);
370
371   ebml->pos += data_size;
372
373   /* if there's no cache, then don't push it! */
374   if (ebml->writing_streamheader) {
375     gst_byte_writer_put_data (ebml->streamheader, GST_BUFFER_DATA (buf),
376         data_size);
377   }
378   if (ebml->cache) {
379     gst_byte_writer_put_data (ebml->cache, GST_BUFFER_DATA (buf), data_size);
380     gst_buffer_unref (buf);
381     return;
382   }
383
384   if (ebml->last_write_result == GST_FLOW_OK) {
385     if (ebml->need_newsegment) {
386       GstEvent *ev;
387
388       ev = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0);
389       if (gst_pad_push_event (ebml->srcpad, ev))
390         ebml->need_newsegment = FALSE;
391     }
392     buf = gst_buffer_make_metadata_writable (buf);
393     gst_buffer_set_caps (buf, GST_PAD_CAPS (ebml->srcpad));
394     ebml->last_write_result = gst_pad_push (ebml->srcpad, buf);
395   } else {
396     gst_buffer_unref (buf);
397   }
398 }
399
400
401 /**
402  * gst_ebml_write_seek:
403  * @ebml: #GstEbmlWrite
404  * @pos: Seek position.
405  * 
406  * Seek.
407  */
408 void
409 gst_ebml_write_seek (GstEbmlWrite * ebml, guint64 pos)
410 {
411   GstEvent *event;
412
413   if (ebml->writing_streamheader) {
414     GST_DEBUG ("wanting to seek to pos %" G_GUINT64_FORMAT, pos);
415     if (pos >= ebml->streamheader_pos &&
416         pos <= ebml->streamheader_pos + ebml->streamheader->parent.size) {
417       gst_byte_writer_set_pos (ebml->streamheader,
418           pos - ebml->streamheader_pos);
419       GST_DEBUG ("seeked in streamheader to position %" G_GUINT64_FORMAT,
420           pos - ebml->streamheader_pos);
421     } else {
422       GST_WARNING
423           ("we are writing streamheader still and seek is out of bounds");
424     }
425   }
426   /* Cache seeking. A bit dangerous, we assume the client writer
427    * knows what he's doing... */
428   if (ebml->cache) {
429     /* within bounds? */
430     if (pos >= ebml->cache_pos &&
431         pos <= ebml->cache_pos + ebml->cache->parent.size) {
432       ebml->pos = pos;
433       gst_byte_writer_set_pos (ebml->cache, ebml->pos - ebml->cache_pos);
434       return;
435     } else {
436       GST_LOG ("Seek outside cache range. Clearing...");
437       gst_ebml_write_flush_cache (ebml);
438     }
439   }
440
441   event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, pos, -1, 0);
442   if (gst_pad_push_event (ebml->srcpad, event)) {
443     GST_DEBUG ("Seek'd to offset %" G_GUINT64_FORMAT, pos);
444   } else {
445     GST_WARNING ("Seek to offset %" G_GUINT64_FORMAT " failed", pos);
446   }
447   ebml->pos = pos;
448 }
449
450
451 /**
452  * gst_ebml_write_get_uint_size:
453  * @num: Number to be encoded.
454  * 
455  * Get number of bytes needed to write a uint.
456  *
457  * Returns: Encoded uint length.
458  */
459 static guint
460 gst_ebml_write_get_uint_size (guint64 num)
461 {
462   guint size = 1;
463
464   /* get size */
465   while (num >= (G_GINT64_CONSTANT (1) << (size * 8)) && size < 8) {
466     size++;
467   }
468
469   return size;
470 }
471
472
473 /**
474  * gst_ebml_write_set_uint:
475  * @buf: #GstBuffer to which ithe number should be written.
476  * @num: Number to be written.
477  * @size: Encoded number length.
478  *
479  * Write an uint into a buffer.
480  */
481 static void
482 gst_ebml_write_set_uint (GstBuffer * buf, guint64 num, guint size)
483 {
484   guint8 *data;
485
486   data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
487   GST_BUFFER_SIZE (buf) += size;
488   while (size-- > 0) {
489     data[size] = num & 0xff;
490     num >>= 8;
491   }
492 }
493
494
495 /**
496  * gst_ebml_write_uint:
497  * @ebml: #GstEbmlWrite
498  * @id: Element ID.
499  * @num: Number to be written.
500  *
501  * Write uint element.
502  */
503 void
504 gst_ebml_write_uint (GstEbmlWrite * ebml, guint32 id, guint64 num)
505 {
506   GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num));
507   guint size = gst_ebml_write_get_uint_size (num);
508
509   /* write */
510   gst_ebml_write_element_id (buf, id);
511   gst_ebml_write_element_size (buf, size);
512   gst_ebml_write_set_uint (buf, num, size);
513   gst_ebml_write_element_push (ebml, buf);
514 }
515
516
517 /**
518  * gst_ebml_write_sint:
519  * @ebml: #GstEbmlWrite
520  * @id: Element ID.
521  * @num: Number to be written.
522  *
523  * Write sint element.
524  */
525 void
526 gst_ebml_write_sint (GstEbmlWrite * ebml, guint32 id, gint64 num)
527 {
528   GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num));
529
530   /* if the signed number is on the edge of a extra-byte,
531    * then we'll fall over when detecting it. Example: if I
532    * have a number (-)0x8000 (G_MINSHORT), then my abs()<<1
533    * will be 0x10000; this is G_MAXUSHORT+1! So: if (<0) -1. */
534   guint64 unum = (num < 0 ? (-num - 1) << 1 : num << 1);
535   guint size = gst_ebml_write_get_uint_size (unum);
536
537   /* make unsigned */
538   if (num >= 0) {
539     unum = num;
540   } else {
541     unum = 0x80 << (size - 1);
542     unum += num;
543     unum |= 0x80 << (size - 1);
544   }
545
546   /* write */
547   gst_ebml_write_element_id (buf, id);
548   gst_ebml_write_element_size (buf, size);
549   gst_ebml_write_set_uint (buf, unum, size);
550   gst_ebml_write_element_push (ebml, buf);
551 }
552
553
554 /**
555  * gst_ebml_write_float:
556  * @ebml: #GstEbmlWrite
557  * @id: Element ID.
558  * @num: Number to be written.
559  *
560  * Write float element.
561  */
562 void
563 gst_ebml_write_float (GstEbmlWrite * ebml, guint32 id, gdouble num)
564 {
565   GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num));
566
567   gst_ebml_write_element_id (buf, id);
568   gst_ebml_write_element_size (buf, 8);
569   num = GDOUBLE_TO_BE (num);
570   gst_ebml_write_element_data (buf, (guint8 *) & num, 8);
571   gst_ebml_write_element_push (ebml, buf);
572 }
573
574
575 /**
576  * gst_ebml_write_ascii:
577  * @ebml: #GstEbmlWrite
578  * @id: Element ID.
579  * @str: String to be written.
580  *
581  * Write string element.
582  */
583 void
584 gst_ebml_write_ascii (GstEbmlWrite * ebml, guint32 id, const gchar * str)
585 {
586   gint len = strlen (str) + 1;  /* add trailing '\0' */
587   GstBuffer *buf = gst_ebml_write_element_new (ebml, len);
588
589   gst_ebml_write_element_id (buf, id);
590   gst_ebml_write_element_size (buf, len);
591   gst_ebml_write_element_data (buf, (guint8 *) str, len);
592   gst_ebml_write_element_push (ebml, buf);
593 }
594
595
596 /**
597  * gst_ebml_write_utf8:
598  * @ebml: #GstEbmlWrite
599  * @id: Element ID.
600  * @str: String to be written.
601  *
602  * Write utf8 encoded string element.
603  */
604 void
605 gst_ebml_write_utf8 (GstEbmlWrite * ebml, guint32 id, const gchar * str)
606 {
607   gst_ebml_write_ascii (ebml, id, str);
608 }
609
610
611 /**
612  * gst_ebml_write_date:
613  * @ebml: #GstEbmlWrite
614  * @id: Element ID.
615  * @date: Date in seconds since the unix epoch.
616  *
617  * Write date element.
618  */
619 void
620 gst_ebml_write_date (GstEbmlWrite * ebml, guint32 id, gint64 date)
621 {
622   gst_ebml_write_sint (ebml, id, (date - GST_EBML_DATE_OFFSET) * GST_SECOND);
623 }
624
625 /**
626  * gst_ebml_write_master_start:
627  * @ebml: #GstEbmlWrite
628  * @id: Element ID.
629  *
630  * Start wiriting mater element.
631  *
632  * Master writing is annoying. We use a size marker of
633  * the max. allowed length, so that we can later fill it
634  * in validly. 
635  *
636  * Returns: Master starting position.
637  */
638 guint64
639 gst_ebml_write_master_start (GstEbmlWrite * ebml, guint32 id)
640 {
641   guint64 pos = ebml->pos, t;
642   GstBuffer *buf = gst_ebml_write_element_new (ebml, 0);
643
644   t = GST_BUFFER_SIZE (buf);
645   gst_ebml_write_element_id (buf, id);
646   pos += GST_BUFFER_SIZE (buf) - t;
647   gst_ebml_write_element_size (buf, GST_EBML_SIZE_UNKNOWN);
648   gst_ebml_write_element_push (ebml, buf);
649
650   return pos;
651 }
652
653
654 /**
655  * gst_ebml_write_master_finish_full:
656  * @ebml: #GstEbmlWrite
657  * @startpos: Master starting position.
658  *
659  * Finish writing master element.  Size of master element is difference between
660  * current position and the element start, and @extra_size added to this.
661  */
662 void
663 gst_ebml_write_master_finish_full (GstEbmlWrite * ebml, guint64 startpos,
664     guint64 extra_size)
665 {
666   guint64 pos = ebml->pos;
667   GstBuffer *buf;
668
669   gst_ebml_write_seek (ebml, startpos);
670   buf = gst_buffer_new_and_alloc (8);
671   GST_WRITE_UINT64_BE (GST_BUFFER_DATA (buf),
672       (G_GINT64_CONSTANT (1) << 56) | (pos - startpos - 8 + extra_size));
673   gst_ebml_write_element_push (ebml, buf);
674   gst_ebml_write_seek (ebml, pos);
675 }
676
677 void
678 gst_ebml_write_master_finish (GstEbmlWrite * ebml, guint64 startpos)
679 {
680   gst_ebml_write_master_finish_full (ebml, startpos, 0);
681 }
682
683 /**
684  * gst_ebml_write_binary:
685  * @ebml: #GstEbmlWrite
686  * @id: Element ID.
687  * @binary: Data to be written.
688  * @length: Length of the data
689  *
690  * Write an element with binary data.
691  */
692 void
693 gst_ebml_write_binary (GstEbmlWrite * ebml,
694     guint32 id, guint8 * binary, guint64 length)
695 {
696   GstBuffer *buf = gst_ebml_write_element_new (ebml, length);
697
698   gst_ebml_write_element_id (buf, id);
699   gst_ebml_write_element_size (buf, length);
700   gst_ebml_write_element_data (buf, binary, length);
701   gst_ebml_write_element_push (ebml, buf);
702 }
703
704
705 /**
706  * gst_ebml_write_buffer_header:
707  * @ebml: #GstEbmlWrite
708  * @id: Element ID.
709  * @length: Length of the data
710  * 
711  * Write header of the binary element (use with gst_ebml_write_buffer function).
712  * 
713  * For things like video frames and audio samples,
714  * you want to use this function, as it doesn't have
715  * the overhead of memcpy() that other functions
716  * such as write_binary() do have.
717  */
718 void
719 gst_ebml_write_buffer_header (GstEbmlWrite * ebml, guint32 id, guint64 length)
720 {
721   GstBuffer *buf = gst_ebml_write_element_new (ebml, 0);
722
723   gst_ebml_write_element_id (buf, id);
724   gst_ebml_write_element_size (buf, length);
725   gst_ebml_write_element_push (ebml, buf);
726 }
727
728
729 /**
730  * gst_ebml_write_buffer:
731  * @ebml: #GstEbmlWrite
732  * @data: #GstBuffer cointaining the data.
733  *
734  * Write  binary element (see gst_ebml_write_buffer_header).
735  */
736 void
737 gst_ebml_write_buffer (GstEbmlWrite * ebml, GstBuffer * data)
738 {
739   gst_ebml_write_element_push (ebml, data);
740 }
741
742
743 /**
744  * gst_ebml_replace_uint:
745  * @ebml: #GstEbmlWrite
746  * @pos: Position of the uint that should be replaced.
747  * @num: New value.
748  *
749  * Replace uint with a new value.
750  * 
751  * When replacing a uint, we assume that it is *always*
752  * 8-byte, since that's the safest guess we can do. This
753  * is just for simplicity.
754  *
755  * FIXME: this function needs to be replaced with something
756  * proper. This is a crude hack.
757  */
758 void
759 gst_ebml_replace_uint (GstEbmlWrite * ebml, guint64 pos, guint64 num)
760 {
761   guint64 oldpos = ebml->pos;
762   GstBuffer *buf = gst_buffer_new_and_alloc (8);
763
764   gst_ebml_write_seek (ebml, pos);
765   GST_BUFFER_SIZE (buf) = 0;
766   gst_ebml_write_set_uint (buf, num, 8);
767   gst_ebml_write_element_push (ebml, buf);
768   gst_ebml_write_seek (ebml, oldpos);
769 }
770
771 /**
772  * gst_ebml_write_header:
773  * @ebml: #GstEbmlWrite
774  * @doctype: Document type.
775  * @version: Document type version.
776  * 
777  * Write EBML header.
778  */
779 void
780 gst_ebml_write_header (GstEbmlWrite * ebml, const gchar * doctype,
781     guint version)
782 {
783   guint64 pos;
784
785   /* write the basic EBML header */
786   gst_ebml_write_set_cache (ebml, 0x40);
787   pos = gst_ebml_write_master_start (ebml, GST_EBML_ID_HEADER);
788 #if (GST_EBML_VERSION != 1)
789   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLVERSION, GST_EBML_VERSION);
790   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLREADVERSION, GST_EBML_VERSION);
791 #endif
792 #if 0
793   /* we don't write these until they're "non-default" (never!) */
794   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXIDLENGTH, sizeof (guint32));
795   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXSIZELENGTH, sizeof (guint64));
796 #endif
797   gst_ebml_write_ascii (ebml, GST_EBML_ID_DOCTYPE, doctype);
798   gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEVERSION, version);
799   gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEREADVERSION, version);
800   gst_ebml_write_master_finish (ebml, pos);
801   gst_ebml_write_flush_cache (ebml);
802 }