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