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