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