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