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