matroska: catch failure to map buffer
[platform/upstream/gstreamer.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., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, 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 %" G_GSIZE_FORMAT,
182       gst_buffer_get_size (buffer));
183
184   ebml->writing_streamheader = FALSE;
185   return buffer;
186 }
187
188 /**
189  * gst_ebml_write_set_cache:
190  * @ebml: a #GstEbmlWrite.
191  * @size: size of the cache.
192  * Create a cache.
193  *
194  * The idea is that you use this for writing a lot
195  * of small elements. This will just "queue" all of
196  * them and they'll be pushed to the next element all
197  * at once. This saves memory and time for buffer
198  * allocation and init, and it looks better.
199  */
200 void
201 gst_ebml_write_set_cache (GstEbmlWrite * ebml, guint size)
202 {
203   g_return_if_fail (ebml->cache == NULL);
204
205   GST_DEBUG ("Starting cache at %" G_GUINT64_FORMAT, ebml->pos);
206   ebml->cache = gst_byte_writer_new_with_size (size, FALSE);
207   ebml->cache_pos = ebml->pos;
208 }
209
210 static gboolean
211 gst_ebml_writer_send_segment_event (GstEbmlWrite * ebml, guint64 new_pos)
212 {
213   GstSegment segment;
214   gboolean res;
215
216   GST_INFO ("seeking to %" G_GUINT64_FORMAT, new_pos);
217
218   gst_segment_init (&segment, GST_FORMAT_BYTES);
219   segment.start = new_pos;
220   segment.stop = -1;
221   segment.position = 0;
222
223   res = gst_pad_push_event (ebml->srcpad, gst_event_new_segment (&segment));
224
225   if (!res)
226     GST_WARNING ("seek to %" G_GUINT64_FORMAT "failed", new_pos);
227
228   return res;
229 }
230
231 /**
232  * gst_ebml_write_flush_cache:
233  * @ebml:      a #GstEbmlWrite.
234  * @timestamp: timestamp of the buffer.
235  *
236  * Flush the cache.
237  */
238 void
239 gst_ebml_write_flush_cache (GstEbmlWrite * ebml, gboolean is_keyframe,
240     GstClockTime timestamp)
241 {
242   GstBuffer *buffer;
243
244   if (!ebml->cache)
245     return;
246
247   buffer = gst_byte_writer_free_and_get_buffer (ebml->cache);
248   ebml->cache = NULL;
249   GST_DEBUG ("Flushing cache of size %" G_GSIZE_FORMAT,
250       gst_buffer_get_size (buffer));
251   GST_BUFFER_TIMESTAMP (buffer) = timestamp;
252   GST_BUFFER_OFFSET (buffer) = ebml->pos - gst_buffer_get_size (buffer);
253   GST_BUFFER_OFFSET_END (buffer) = ebml->pos;
254   if (ebml->last_write_result == GST_FLOW_OK) {
255     if (GST_BUFFER_OFFSET (buffer) != ebml->last_pos) {
256       gst_ebml_writer_send_segment_event (ebml, GST_BUFFER_OFFSET (buffer));
257       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
258     }
259     if (ebml->writing_streamheader) {
260       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
261     }
262     if (!is_keyframe) {
263       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
264     }
265     ebml->last_pos = ebml->pos;
266     ebml->last_write_result = gst_pad_push (ebml->srcpad, buffer);
267   } else {
268     gst_buffer_unref (buffer);
269   }
270 }
271
272
273 /**
274  * gst_ebml_write_element_new:
275  * @ebml: a #GstEbmlWrite.
276  * @size: size of the requested buffer.
277  *
278  * Create a buffer for one element. If there is
279  * a cache, use that instead.
280  *
281  * Returns: A new #GstBuffer.
282  */
283 static GstBuffer *
284 gst_ebml_write_element_new (GstEbmlWrite * ebml, GstMapInfo * map, guint size)
285 {
286   /* Create new buffer of size + ID + length */
287   GstBuffer *buf;
288
289   /* length, ID */
290   size += 12;
291
292   buf = gst_buffer_new_and_alloc (size);
293   GST_BUFFER_TIMESTAMP (buf) = ebml->timestamp;
294
295   /* FIXME unmap not possible */
296   gst_buffer_map (buf, map, GST_MAP_WRITE);
297
298   return buf;
299 }
300
301
302 /**
303  * gst_ebml_write_element_id:
304  * @data_inout: Pointer to data pointer
305  * @id: Element ID that should be written.
306  * 
307  * Write element ID into a buffer.
308  */
309 static void
310 gst_ebml_write_element_id (guint8 ** data_inout, guint32 id)
311 {
312   guint8 *data = *data_inout;
313   guint bytes = 4, mask = 0x10;
314
315   /* get ID length */
316   while (!(id & (mask << ((bytes - 1) * 8))) && bytes > 0) {
317     mask <<= 1;
318     bytes--;
319   }
320
321   /* if invalid ID, use dummy */
322   if (bytes == 0) {
323     GST_WARNING ("Invalid ID, voiding");
324     bytes = 1;
325     id = GST_EBML_ID_VOID;
326   }
327
328   /* write out, BE */
329   *data_inout += bytes;
330   while (bytes--) {
331     data[bytes] = id & 0xff;
332     id >>= 8;
333   }
334 }
335
336
337 /**
338  * gst_ebml_write_element_size:
339  * @data_inout: Pointer to data pointer
340  * @size: Element length.
341  *
342  * Write element length into a buffer.
343  */
344 static void
345 gst_ebml_write_element_size (guint8 ** data_inout, guint64 size)
346 {
347   guint8 *data = *data_inout;
348   guint bytes = 1, mask = 0x80;
349
350   if (size != GST_EBML_SIZE_UNKNOWN) {
351     /* how many bytes? - use mask-1 because an all-1 bitset is not allowed */
352     while ((size >> ((bytes - 1) * 8)) >= (mask - 1) && bytes <= 8) {
353       mask >>= 1;
354       bytes++;
355     }
356
357     /* if invalid size, use max. */
358     if (bytes > 8) {
359       GST_WARNING ("Invalid size, writing size unknown");
360       mask = 0x01;
361       bytes = 8;
362       /* Now here's a real FIXME: we cannot read those yet! */
363       size = GST_EBML_SIZE_UNKNOWN;
364     }
365   } else {
366     mask = 0x01;
367     bytes = 8;
368   }
369
370   /* write out, BE, with length size marker */
371   *data_inout += bytes;
372   while (bytes-- > 0) {
373     data[bytes] = size & 0xff;
374     size >>= 8;
375     if (!bytes)
376       *data |= mask;
377   }
378 }
379
380
381 /**
382  * gst_ebml_write_element_data:
383  * @data_inout: Pointer to data pointer
384  * @write: Data that should be written.
385  * @length: Length of the data.
386  *
387  * Write element data into a buffer.
388  */
389 static void
390 gst_ebml_write_element_data (guint8 ** data_inout, guint8 * write,
391     guint64 length)
392 {
393   memcpy (*data_inout, write, length);
394   *data_inout += length;
395 }
396
397
398 /**
399  * gst_ebml_write_element_push:
400  * @ebml: #GstEbmlWrite
401  * @buf: #GstBuffer to be written.
402  * @buf_data: Start of data to push from @buf (or NULL for whole buffer).
403  * @buf_data_end: Data pointer positioned after the last byte in @buf_data (or
404  * NULL for whole buffer).
405  * 
406  * Write out buffer by moving it to the next element.
407  */
408 static void
409 gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf,
410     guint8 * buf_data, guint8 * buf_data_end)
411 {
412   GstMapInfo map;
413   guint data_size;
414
415   map.data = NULL;
416
417   if (buf_data_end)
418     data_size = buf_data_end - buf_data;
419   else
420     data_size = gst_buffer_get_size (buf);
421
422   ebml->pos += data_size;
423
424   /* if there's no cache, then don't push it! */
425   if (ebml->writing_streamheader) {
426     if (!buf_data) {
427       gst_buffer_map (buf, &map, GST_MAP_READ);
428       buf_data = map.data;
429     }
430     if (!buf_data)
431       GST_WARNING ("Failed to map buffer");
432     else if (!gst_byte_writer_put_data (ebml->streamheader, buf_data,
433             data_size))
434       GST_WARNING ("Error writing data to streamheader");
435   }
436   if (ebml->cache) {
437     if (!buf_data) {
438       gst_buffer_map (buf, &map, GST_MAP_READ);
439       buf_data = map.data;
440     }
441     if (!buf_data)
442       GST_WARNING ("Failed to map buffer");
443     else if (!gst_byte_writer_put_data (ebml->cache, buf_data, data_size))
444       GST_WARNING ("Error writing data to cache");
445     if (map.data)
446       gst_buffer_unmap (buf, &map);
447     gst_buffer_unref (buf);
448     return;
449   }
450
451   if (buf_data && map.data)
452     gst_buffer_unmap (buf, &map);
453
454   if (ebml->last_write_result == GST_FLOW_OK) {
455     buf = gst_buffer_make_writable (buf);
456     GST_BUFFER_OFFSET (buf) = ebml->pos - data_size;
457     GST_BUFFER_OFFSET_END (buf) = ebml->pos;
458     if (ebml->writing_streamheader) {
459       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
460     }
461     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
462
463     if (GST_BUFFER_OFFSET (buf) != ebml->last_pos) {
464       gst_ebml_writer_send_segment_event (ebml, GST_BUFFER_OFFSET (buf));
465       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
466     }
467     ebml->last_pos = ebml->pos;
468     ebml->last_write_result = gst_pad_push (ebml->srcpad, buf);
469   } else {
470     gst_buffer_unref (buf);
471   }
472 }
473
474
475 /**
476  * gst_ebml_write_seek:
477  * @ebml: #GstEbmlWrite
478  * @pos: Seek position.
479  * 
480  * Seek.
481  */
482 void
483 gst_ebml_write_seek (GstEbmlWrite * ebml, guint64 pos)
484 {
485   if (ebml->writing_streamheader) {
486     GST_DEBUG ("wanting to seek to pos %" G_GUINT64_FORMAT, pos);
487     if (pos >= ebml->streamheader_pos &&
488         pos <= ebml->streamheader_pos + ebml->streamheader->parent.size) {
489       gst_byte_writer_set_pos (ebml->streamheader,
490           pos - ebml->streamheader_pos);
491       GST_DEBUG ("seeked in streamheader to position %" G_GUINT64_FORMAT,
492           pos - ebml->streamheader_pos);
493     } else {
494       GST_WARNING
495           ("we are writing streamheader still and seek is out of bounds");
496     }
497   }
498   /* Cache seeking. A bit dangerous, we assume the client writer
499    * knows what he's doing... */
500   if (ebml->cache) {
501     /* within bounds? */
502     if (pos >= ebml->cache_pos &&
503         pos <= ebml->cache_pos + ebml->cache->parent.size) {
504       GST_DEBUG ("seeking in cache to %" G_GUINT64_FORMAT, pos);
505       ebml->pos = pos;
506       gst_byte_writer_set_pos (ebml->cache, ebml->pos - ebml->cache_pos);
507       return;
508     } else {
509       GST_LOG ("Seek outside cache range. Clearing...");
510       gst_ebml_write_flush_cache (ebml, FALSE, GST_CLOCK_TIME_NONE);
511     }
512   }
513
514   GST_INFO ("scheduling seek to %" G_GUINT64_FORMAT, pos);
515   ebml->pos = pos;
516 }
517
518
519 /**
520  * gst_ebml_write_get_uint_size:
521  * @num: Number to be encoded.
522  * 
523  * Get number of bytes needed to write a uint.
524  *
525  * Returns: Encoded uint length.
526  */
527 static guint
528 gst_ebml_write_get_uint_size (guint64 num)
529 {
530   guint size = 1;
531
532   /* get size */
533   while (num >= (G_GINT64_CONSTANT (1) << (size * 8)) && size < 8) {
534     size++;
535   }
536
537   return size;
538 }
539
540
541 /**
542  * gst_ebml_write_set_uint:
543  * @data_inout: Pointer to data pointer
544  * @num: Number to be written.
545  * @size: Encoded number length.
546  *
547  * Write an uint into a buffer.
548  */
549 static void
550 gst_ebml_write_set_uint (guint8 ** data_inout, guint64 num, guint size)
551 {
552   guint8 *data = *data_inout;
553
554   *data_inout += size;
555
556   while (size-- > 0) {
557     data[size] = num & 0xff;
558     num >>= 8;
559   }
560 }
561
562
563 /**
564  * gst_ebml_write_uint:
565  * @ebml: #GstEbmlWrite
566  * @id: Element ID.
567  * @num: Number to be written.
568  *
569  * Write uint element.
570  */
571 void
572 gst_ebml_write_uint (GstEbmlWrite * ebml, guint32 id, guint64 num)
573 {
574   GstBuffer *buf;
575   guint8 *data_start, *data_end;
576   guint size = gst_ebml_write_get_uint_size (num);
577   GstMapInfo map;
578
579   buf = gst_ebml_write_element_new (ebml, &map, sizeof (num));
580   data_end = data_start = map.data;
581
582   /* write */
583   gst_ebml_write_element_id (&data_end, id);
584   gst_ebml_write_element_size (&data_end, size);
585   gst_ebml_write_set_uint (&data_end, num, size);
586   gst_buffer_unmap (buf, &map);
587   gst_buffer_set_size (buf, (data_end - data_start));
588
589   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
590 }
591
592
593 /**
594  * gst_ebml_write_sint:
595  * @ebml: #GstEbmlWrite
596  * @id: Element ID.
597  * @num: Number to be written.
598  *
599  * Write sint element.
600  */
601 void
602 gst_ebml_write_sint (GstEbmlWrite * ebml, guint32 id, gint64 num)
603 {
604   GstBuffer *buf;
605   guint8 *data_start, *data_end;
606   GstMapInfo map;
607
608   /* if the signed number is on the edge of a extra-byte,
609    * then we'll fall over when detecting it. Example: if I
610    * have a number (-)0x8000 (G_MINSHORT), then my abs()<<1
611    * will be 0x10000; this is G_MAXUSHORT+1! So: if (<0) -1. */
612   guint64 unum = (num < 0 ? (-num - 1) << 1 : num << 1);
613   guint size = gst_ebml_write_get_uint_size (unum);
614
615   buf = gst_ebml_write_element_new (ebml, &map, sizeof (num));
616   data_end = data_start = map.data;
617
618   /* make unsigned */
619   if (num >= 0) {
620     unum = num;
621   } else {
622     unum = 0x80 << (size - 1);
623     unum += num;
624     unum |= 0x80 << (size - 1);
625   }
626
627   /* write */
628   gst_ebml_write_element_id (&data_end, id);
629   gst_ebml_write_element_size (&data_end, size);
630   gst_ebml_write_set_uint (&data_end, unum, size);
631   gst_buffer_unmap (buf, &map);
632   gst_buffer_set_size (buf, (data_end - data_start));
633
634   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
635 }
636
637
638 /**
639  * gst_ebml_write_float:
640  * @ebml: #GstEbmlWrite
641  * @id: Element ID.
642  * @num: Number to be written.
643  *
644  * Write float element.
645  */
646 void
647 gst_ebml_write_float (GstEbmlWrite * ebml, guint32 id, gdouble num)
648 {
649   GstBuffer *buf;
650   GstMapInfo map;
651   guint8 *data_start, *data_end;
652
653   buf = gst_ebml_write_element_new (ebml, &map, sizeof (num));
654   data_end = data_start = map.data;
655
656   gst_ebml_write_element_id (&data_end, id);
657   gst_ebml_write_element_size (&data_end, 8);
658   num = GDOUBLE_TO_BE (num);
659   gst_ebml_write_element_data (&data_end, (guint8 *) & num, 8);
660   gst_buffer_unmap (buf, &map);
661   gst_buffer_set_size (buf, (data_end - data_start));
662
663   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
664 }
665
666
667 /**
668  * gst_ebml_write_ascii:
669  * @ebml: #GstEbmlWrite
670  * @id: Element ID.
671  * @str: String to be written.
672  *
673  * Write string element.
674  */
675 void
676 gst_ebml_write_ascii (GstEbmlWrite * ebml, guint32 id, const gchar * str)
677 {
678   gint len = strlen (str) + 1;  /* add trailing '\0' */
679   GstBuffer *buf;
680   GstMapInfo map;
681   guint8 *data_start, *data_end;
682
683   buf = gst_ebml_write_element_new (ebml, &map, len);
684   data_end = data_start = map.data;
685
686   gst_ebml_write_element_id (&data_end, id);
687   gst_ebml_write_element_size (&data_end, len);
688   gst_ebml_write_element_data (&data_end, (guint8 *) str, len);
689   gst_buffer_unmap (buf, &map);
690   gst_buffer_set_size (buf, (data_end - data_start));
691
692   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
693 }
694
695
696 /**
697  * gst_ebml_write_utf8:
698  * @ebml: #GstEbmlWrite
699  * @id: Element ID.
700  * @str: String to be written.
701  *
702  * Write utf8 encoded string element.
703  */
704 void
705 gst_ebml_write_utf8 (GstEbmlWrite * ebml, guint32 id, const gchar * str)
706 {
707   gst_ebml_write_ascii (ebml, id, str);
708 }
709
710
711 /**
712  * gst_ebml_write_date:
713  * @ebml: #GstEbmlWrite
714  * @id: Element ID.
715  * @date: Date in seconds since the unix epoch.
716  *
717  * Write date element.
718  */
719 void
720 gst_ebml_write_date (GstEbmlWrite * ebml, guint32 id, gint64 date)
721 {
722   gst_ebml_write_sint (ebml, id, (date - GST_EBML_DATE_OFFSET) * GST_SECOND);
723 }
724
725 /**
726  * gst_ebml_write_master_start:
727  * @ebml: #GstEbmlWrite
728  * @id: Element ID.
729  *
730  * Start wiriting mater element.
731  *
732  * Master writing is annoying. We use a size marker of
733  * the max. allowed length, so that we can later fill it
734  * in validly. 
735  *
736  * Returns: Master starting position.
737  */
738 guint64
739 gst_ebml_write_master_start (GstEbmlWrite * ebml, guint32 id)
740 {
741   guint64 pos = ebml->pos;
742   GstBuffer *buf;
743   GstMapInfo map;
744   guint8 *data_start, *data_end;
745
746   buf = gst_ebml_write_element_new (ebml, &map, 0);
747   data_end = data_start = map.data;
748
749   gst_ebml_write_element_id (&data_end, id);
750   pos += data_end - data_start;
751   gst_ebml_write_element_size (&data_end, GST_EBML_SIZE_UNKNOWN);
752   gst_buffer_unmap (buf, &map);
753   gst_buffer_set_size (buf, (data_end - data_start));
754
755   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
756
757   return pos;
758 }
759
760
761 /**
762  * gst_ebml_write_master_finish_full:
763  * @ebml: #GstEbmlWrite
764  * @startpos: Master starting position.
765  *
766  * Finish writing master element.  Size of master element is difference between
767  * current position and the element start, and @extra_size added to this.
768  */
769 void
770 gst_ebml_write_master_finish_full (GstEbmlWrite * ebml, guint64 startpos,
771     guint64 extra_size)
772 {
773   guint64 pos = ebml->pos;
774   guint8 *data = g_malloc (8);
775   GstBuffer *buf = gst_buffer_new_wrapped (data, 8);
776
777   gst_ebml_write_seek (ebml, startpos);
778
779   GST_WRITE_UINT64_BE (data,
780       (G_GINT64_CONSTANT (1) << 56) | (pos - startpos - 8 + extra_size));
781
782   gst_ebml_write_element_push (ebml, buf, NULL, NULL);
783   gst_ebml_write_seek (ebml, pos);
784 }
785
786 void
787 gst_ebml_write_master_finish (GstEbmlWrite * ebml, guint64 startpos)
788 {
789   gst_ebml_write_master_finish_full (ebml, startpos, 0);
790 }
791
792 /**
793  * gst_ebml_write_binary:
794  * @ebml: #GstEbmlWrite
795  * @id: Element ID.
796  * @binary: Data to be written.
797  * @length: Length of the data
798  *
799  * Write an element with binary data.
800  */
801 void
802 gst_ebml_write_binary (GstEbmlWrite * ebml,
803     guint32 id, guint8 * binary, guint64 length)
804 {
805   GstBuffer *buf;
806   GstMapInfo map;
807   guint8 *data_start, *data_end;
808
809   buf = gst_ebml_write_element_new (ebml, &map, length);
810   data_end = data_start = map.data;
811
812   gst_ebml_write_element_id (&data_end, id);
813   gst_ebml_write_element_size (&data_end, length);
814   gst_ebml_write_element_data (&data_end, binary, length);
815   gst_buffer_unmap (buf, &map);
816   gst_buffer_set_size (buf, (data_end - data_start));
817
818   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
819 }
820
821
822 /**
823  * gst_ebml_write_buffer_header:
824  * @ebml: #GstEbmlWrite
825  * @id: Element ID.
826  * @length: Length of the data
827  * 
828  * Write header of the binary element (use with gst_ebml_write_buffer function).
829  * 
830  * For things like video frames and audio samples,
831  * you want to use this function, as it doesn't have
832  * the overhead of memcpy() that other functions
833  * such as write_binary() do have.
834  */
835 void
836 gst_ebml_write_buffer_header (GstEbmlWrite * ebml, guint32 id, guint64 length)
837 {
838   GstBuffer *buf;
839   GstMapInfo map;
840   guint8 *data_start, *data_end;
841
842   buf = gst_ebml_write_element_new (ebml, &map, 0);
843   data_end = data_start = map.data;
844
845   gst_ebml_write_element_id (&data_end, id);
846   gst_ebml_write_element_size (&data_end, length);
847   gst_buffer_unmap (buf, &map);
848   gst_buffer_set_size (buf, (data_end - data_start));
849
850   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
851 }
852
853
854 /**
855  * gst_ebml_write_buffer:
856  * @ebml: #GstEbmlWrite
857  * @buf: #GstBuffer cointaining the data.
858  *
859  * Write  binary element (see gst_ebml_write_buffer_header).
860  */
861 void
862 gst_ebml_write_buffer (GstEbmlWrite * ebml, GstBuffer * buf)
863 {
864   gst_ebml_write_element_push (ebml, buf, NULL, NULL);
865 }
866
867
868 /**
869  * gst_ebml_replace_uint:
870  * @ebml: #GstEbmlWrite
871  * @pos: Position of the uint that should be replaced.
872  * @num: New value.
873  *
874  * Replace uint with a new value.
875  * 
876  * When replacing a uint, we assume that it is *always*
877  * 8-byte, since that's the safest guess we can do. This
878  * is just for simplicity.
879  *
880  * FIXME: this function needs to be replaced with something
881  * proper. This is a crude hack.
882  */
883 void
884 gst_ebml_replace_uint (GstEbmlWrite * ebml, guint64 pos, guint64 num)
885 {
886   guint64 oldpos = ebml->pos;
887   guint8 *data_start, *data_end;
888   GstBuffer *buf;
889
890   data_start = g_malloc (8);
891   data_end = data_start;
892   buf = gst_buffer_new_wrapped (data_start, 8);
893
894   gst_ebml_write_seek (ebml, pos);
895   gst_ebml_write_set_uint (&data_end, num, 8);
896
897   gst_ebml_write_element_push (ebml, buf, data_start, data_end);
898   gst_ebml_write_seek (ebml, oldpos);
899 }
900
901 /**
902  * gst_ebml_write_header:
903  * @ebml: #GstEbmlWrite
904  * @doctype: Document type.
905  * @version: Document type version.
906  * 
907  * Write EBML header.
908  */
909 void
910 gst_ebml_write_header (GstEbmlWrite * ebml, const gchar * doctype,
911     guint version)
912 {
913   guint64 pos;
914
915   /* write the basic EBML header */
916   gst_ebml_write_set_cache (ebml, 0x40);
917   pos = gst_ebml_write_master_start (ebml, GST_EBML_ID_HEADER);
918 #if (GST_EBML_VERSION != 1)
919   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLVERSION, GST_EBML_VERSION);
920   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLREADVERSION, GST_EBML_VERSION);
921 #endif
922 #if 0
923   /* we don't write these until they're "non-default" (never!) */
924   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXIDLENGTH, sizeof (guint32));
925   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXSIZELENGTH, sizeof (guint64));
926 #endif
927   gst_ebml_write_ascii (ebml, GST_EBML_ID_DOCTYPE, doctype);
928   gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEVERSION, version);
929   gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEREADVERSION, version);
930   gst_ebml_write_master_finish (ebml, pos);
931   gst_ebml_write_flush_cache (ebml, FALSE, 0);
932 }