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