gst-indent
[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  *
4  * ebml-write.c: write EBML data to file/stream
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <string.h>
27
28 #include "ebml-write.h"
29 #include "ebml-ids.h"
30
31 enum
32 {
33   /* FILL ME */
34   LAST_SIGNAL
35 };
36
37 static void gst_ebml_write_class_init (GstEbmlWriteClass * klass);
38 static void gst_ebml_write_init (GstEbmlWrite * ebml);
39 static GstElementStateReturn gst_ebml_write_change_state (GstElement * element);
40
41 static GstElementClass *parent_class = NULL;
42
43 GType
44 gst_ebml_write_get_type (void)
45 {
46   static GType gst_ebml_write_type = 0;
47
48   if (!gst_ebml_write_type) {
49     static const GTypeInfo gst_ebml_write_info = {
50       sizeof (GstEbmlWriteClass),
51       NULL,
52       NULL,
53       (GClassInitFunc) gst_ebml_write_class_init,
54       NULL,
55       NULL,
56       sizeof (GstEbmlWrite),
57       0,
58       (GInstanceInitFunc) gst_ebml_write_init,
59     };
60
61     gst_ebml_write_type =
62         g_type_register_static (GST_TYPE_ELEMENT, "GstEbmlWrite",
63         &gst_ebml_write_info, 0);
64   }
65
66   return gst_ebml_write_type;
67 }
68
69 static void
70 gst_ebml_write_class_init (GstEbmlWriteClass * klass)
71 {
72   GstElementClass *gstelement_class = (GstElementClass *) klass;
73
74   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
75
76   gstelement_class->change_state = gst_ebml_write_change_state;
77 }
78
79 static void
80 gst_ebml_write_init (GstEbmlWrite * ebml)
81 {
82   ebml->srcpad = NULL;
83   ebml->pos = 0;
84
85   ebml->cache = NULL;
86 }
87
88 static GstElementStateReturn
89 gst_ebml_write_change_state (GstElement * element)
90 {
91   GstEbmlWrite *ebml = GST_EBML_WRITE (element);
92
93   switch (GST_STATE_TRANSITION (element)) {
94     case GST_STATE_PAUSED_TO_READY:
95       ebml->pos = 0;
96       break;
97     default:
98       break;
99   }
100
101   if (GST_ELEMENT_CLASS (parent_class)->change_state)
102     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
103
104   return GST_STATE_SUCCESS;
105 }
106
107 /*
108  * Caching.
109  *
110  * The idea is that you use this for writing a lot
111  * of small elements. This will just "queue" all of
112  * them and they'll be pushed to the next element all
113  * at once. This saves memory and time for buffer
114  * allocation and init, and it looks better.
115  */
116
117 void
118 gst_ebml_write_set_cache (GstEbmlWrite * ebml, guint size)
119 {
120   /* This is currently broken. I don't know why yet. */
121   return;
122
123   g_return_if_fail (ebml->cache == NULL);
124
125   ebml->cache = gst_buffer_new_and_alloc (size);
126   GST_BUFFER_SIZE (ebml->cache) = 0;
127   GST_BUFFER_OFFSET (ebml->cache) = ebml->pos;
128   ebml->handled = 0;
129 }
130
131 void
132 gst_ebml_write_flush_cache (GstEbmlWrite * ebml)
133 {
134   if (!ebml->cache)
135     return;
136
137   /* this is very important. It may fail, in which case the client
138    * programmer didn't use the cache somewhere. That's fatal. */
139   g_assert (ebml->handled == GST_BUFFER_SIZE (ebml->cache));
140   g_assert (GST_BUFFER_SIZE (ebml->cache) +
141       GST_BUFFER_OFFSET (ebml->cache) == ebml->pos);
142
143   gst_pad_push (ebml->srcpad, GST_DATA (ebml->cache));
144   ebml->cache = NULL;
145   ebml->handled = 0;
146 }
147
148 /*
149  * One-element buffer, in case of no cache. If there is
150  * a cache, use that instead.
151  */
152
153 static GstBuffer *
154 gst_ebml_write_element_new (GstEbmlWrite * ebml, guint size)
155 {
156   /* Create new buffer of size + ID + length */
157   GstBuffer *buf;
158
159   /* length, ID */
160   size += 12;
161
162   /* prefer cache */
163   if (ebml->cache) {
164     if (GST_BUFFER_MAXSIZE (ebml->cache) - GST_BUFFER_SIZE (ebml->cache) < size) {
165       GST_LOG ("Cache available, but too small. Clearing...");
166       gst_ebml_write_flush_cache (ebml);
167     } else {
168       return ebml->cache;
169     }
170   }
171
172   /* else, use a one-element buffer. This is slower */
173   buf = gst_buffer_new_and_alloc (size);
174   GST_BUFFER_SIZE (buf) = 0;
175
176   return buf;
177 }
178
179 /*
180  * Write element ID into a buffer.
181  */
182
183 static void
184 gst_ebml_write_element_id (GstBuffer * buf, guint32 id)
185 {
186   guint8 *data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
187   guint bytes = 4, mask = 0x10;
188
189   /* get ID length */
190   while (!(id & (mask << ((bytes - 1) * 8))) && bytes > 0) {
191     mask <<= 1;
192     bytes--;
193   }
194
195   /* if invalid ID, use dummy */
196   if (bytes == 0) {
197     GST_WARNING ("Invalid ID, voiding");
198     bytes = 1;
199     id = GST_EBML_ID_VOID;
200   }
201
202   /* write out, BE */
203   GST_BUFFER_SIZE (buf) += bytes;
204   while (bytes--) {
205     data[bytes] = id & 0xff;
206     id >>= 8;
207   }
208 }
209
210 /*
211  * Write element length into a buffer.
212  */
213
214 static void
215 gst_ebml_write_element_size (GstBuffer * buf, guint64 size)
216 {
217   guint8 *data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
218   guint bytes = 1, mask = 0x80;
219
220   /* how many bytes? */
221   while ((size >> ((bytes - 1) * 8)) >= mask && bytes <= 8) {
222     mask >>= 1;
223     bytes++;
224   }
225
226   /* if invalid size, use max. */
227   if (bytes > 8) {
228     GST_WARNING ("Invalid size, maximizing");
229     mask = 0x01;
230     bytes = 8;
231     /* Now here's a real FIXME: we cannot read those yet! */
232     size = 0x00ffffffffffffffLLU;
233   }
234
235   /* write out, BE, with length size marker */
236   GST_BUFFER_SIZE (buf) += bytes;
237   while (bytes-- > 0) {
238     data[bytes] = size & 0xff;
239     size >>= 8;
240     if (!bytes)
241       *data |= mask;
242   }
243 }
244
245 /*
246  * Write element data into a buffer.
247  */
248
249 static void
250 gst_ebml_write_element_data (GstBuffer * buf, guint8 * write, guint64 length)
251 {
252   guint8 *data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
253
254   memcpy (data, write, length);
255   GST_BUFFER_SIZE (buf) += length;
256 }
257
258 /*
259  * Write out buffer by moving it to the next element.
260  */
261
262 static void
263 gst_ebml_write_element_push (GstEbmlWrite * ebml, GstBuffer * buf)
264 {
265   guint data_size = GST_BUFFER_SIZE (buf) - ebml->handled;
266
267   ebml->pos += data_size;
268   if (buf == ebml->cache) {
269     ebml->handled += data_size;
270   }
271
272   /* if there's no cache, then don't push it! */
273   if (ebml->cache) {
274     g_assert (buf == ebml->cache);
275     return;
276   }
277
278   gst_pad_push (ebml->srcpad, GST_DATA (buf));
279 }
280
281 /*
282  * Seek.
283  */
284
285 void
286 gst_ebml_write_seek (GstEbmlWrite * ebml, guint64 pos)
287 {
288   GstEvent *seek;
289
290   /* Cache seeking. A bit dangerous, we assume the client writer
291    * knows what he's doing... */
292   if (ebml->cache) {
293     /* within bounds? */
294     if (pos >= GST_BUFFER_OFFSET (ebml->cache) &&
295         pos <
296         GST_BUFFER_OFFSET (ebml->cache) + GST_BUFFER_MAXSIZE (ebml->cache)) {
297       GST_BUFFER_SIZE (ebml->cache) = pos - GST_BUFFER_OFFSET (ebml->cache);
298       if (ebml->pos > pos)
299         ebml->handled -= ebml->pos - pos;
300       else
301         ebml->handled += pos - ebml->pos;
302       ebml->pos = pos;
303     } else {
304       GST_LOG ("Seek outside cache range. Clearing...");
305       gst_ebml_write_flush_cache (ebml);
306     }
307   }
308
309   seek = gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_SET, pos);
310   gst_pad_push (ebml->srcpad, GST_DATA (seek));
311   ebml->pos = pos;
312 }
313
314 /*
315  * Get no. bytes needed to write a uint.
316  */
317
318 static guint
319 gst_ebml_write_get_uint_size (guint64 num)
320 {
321   guint size = 1;
322
323   /* get size */
324   while (num >= (1LLU << (size * 8)) && size < 8) {
325     size++;
326   }
327
328   return size;
329 }
330
331
332 /*
333  * Write an uint into a buffer.
334  */
335
336 static void
337 gst_ebml_write_set_uint (GstBuffer * buf, guint64 num, guint size)
338 {
339   guint8 *data;
340
341   data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
342   GST_BUFFER_SIZE (buf) += size;
343   while (size-- > 0) {
344     data[size] = num & 0xff;
345     num >>= 8;
346   }
347 }
348
349 /*
350  * Data type wrappers.
351  */
352
353 void
354 gst_ebml_write_uint (GstEbmlWrite * ebml, guint32 id, guint64 num)
355 {
356   GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num));
357   guint size = gst_ebml_write_get_uint_size (num);
358
359   /* write */
360   gst_ebml_write_element_id (buf, id);
361   gst_ebml_write_element_size (buf, size);
362   gst_ebml_write_set_uint (buf, num, size);
363   gst_ebml_write_element_push (ebml, buf);
364 }
365
366 void
367 gst_ebml_write_sint (GstEbmlWrite * ebml, guint32 id, gint64 num)
368 {
369   GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num));
370
371   /* if the signed number is on the edge of a extra-byte,
372    * then we'll fall over when detecting it. Example: if I
373    * have a number (-)0x8000 (G_MINSHORT), then my abs()<<1
374    * will be 0x10000; this is G_MAXUSHORT+1! So: if (<0) -1. */
375   guint64 unum = (num < 0 ? (-num - 1) << 1 : num << 1);
376   guint size = gst_ebml_write_get_uint_size (unum);
377
378   /* make unsigned */
379   if (num >= 0) {
380     unum = num;
381   } else {
382     unum = 0x80 << (size - 1);
383     unum += num;
384     unum |= 0x80 << (size - 1);
385   }
386
387   /* write */
388   gst_ebml_write_element_id (buf, id);
389   gst_ebml_write_element_size (buf, size);
390   gst_ebml_write_set_uint (buf, unum, size);
391   gst_ebml_write_element_push (ebml, buf);
392 }
393
394 void
395 gst_ebml_write_float (GstEbmlWrite * ebml, guint32 id, gdouble num)
396 {
397 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
398   gint n;
399 #endif
400   GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num));
401
402   gst_ebml_write_element_id (buf, id);
403   gst_ebml_write_element_size (buf, 8);
404 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
405   for (n = 0; n < 8; n++)
406     GST_BUFFER_DATA (buf)[GST_BUFFER_SIZE (buf)] = ((guint8 *) & num)[7 - n];
407   GST_BUFFER_SIZE (buf) += 8;
408 #else
409   gst_ebml_write_element_data (buf, (guint8 *) & num, 8);
410 #endif
411   gst_ebml_write_element_push (ebml, buf);
412 }
413
414 void
415 gst_ebml_write_ascii (GstEbmlWrite * ebml, guint32 id, const gchar * str)
416 {
417   gint len = strlen (str) + 1;  /* add trailing '\0' */
418   GstBuffer *buf = gst_ebml_write_element_new (ebml, len);
419
420   gst_ebml_write_element_id (buf, id);
421   gst_ebml_write_element_size (buf, len);
422   gst_ebml_write_element_data (buf, (guint8 *) str, len);
423   gst_ebml_write_element_push (ebml, buf);
424 }
425
426 void
427 gst_ebml_write_utf8 (GstEbmlWrite * ebml, guint32 id, const gchar * str)
428 {
429   gst_ebml_write_ascii (ebml, id, str);
430 }
431
432 void
433 gst_ebml_write_date (GstEbmlWrite * ebml, guint32 id, gint64 date)
434 {
435   gst_ebml_write_sint (ebml, id, date);
436 }
437
438 /*
439  * Master writing is annoying. We use a size marker of
440  * the max. allowed length, so that we can later fill it
441  * in validly. 
442  */
443
444 guint64
445 gst_ebml_write_master_start (GstEbmlWrite * ebml, guint32 id)
446 {
447   guint64 pos = ebml->pos, t;
448   GstBuffer *buf = gst_ebml_write_element_new (ebml, 0);
449
450   t = GST_BUFFER_SIZE (buf);
451   gst_ebml_write_element_id (buf, id);
452   pos += GST_BUFFER_SIZE (buf) - t;
453   gst_ebml_write_element_size (buf, -1);
454   gst_ebml_write_element_push (ebml, buf);
455
456   return pos;
457 }
458
459 void
460 gst_ebml_write_master_finish (GstEbmlWrite * ebml, guint64 startpos)
461 {
462   guint64 pos = ebml->pos;
463   GstBuffer *buf;
464
465   gst_ebml_write_seek (ebml, startpos);
466   buf = gst_ebml_write_element_new (ebml, 0);
467   startpos = GUINT64_TO_BE ((1LLU << 56) | (pos - startpos - 8));
468   memcpy (GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf),
469       (guint8 *) & startpos, 8);
470   GST_BUFFER_SIZE (buf) += 8;
471   gst_ebml_write_element_push (ebml, buf);
472   gst_ebml_write_seek (ebml, pos);
473 }
474
475 void
476 gst_ebml_write_binary (GstEbmlWrite * ebml,
477     guint32 id, guint8 * binary, guint64 length)
478 {
479   GstBuffer *buf = gst_ebml_write_element_new (ebml, length);
480
481   gst_ebml_write_element_id (buf, id);
482   gst_ebml_write_element_size (buf, length);
483   gst_ebml_write_element_data (buf, binary, length);
484   gst_ebml_write_element_push (ebml, buf);
485 }
486
487 /*
488  * For things like video frames and audio samples,
489  * you want to use this function, as it doesn't have
490  * the overhead of memcpy() that other functions
491  * such as write_binary() do have.
492  */
493
494 void
495 gst_ebml_write_buffer_header (GstEbmlWrite * ebml, guint32 id, guint64 length)
496 {
497   GstBuffer *buf = gst_ebml_write_element_new (ebml, 0);
498
499   gst_ebml_write_element_id (buf, id);
500   gst_ebml_write_element_size (buf, length);
501   gst_ebml_write_element_push (ebml, buf);
502 }
503
504 void
505 gst_ebml_write_buffer (GstEbmlWrite * ebml, GstBuffer * data)
506 {
507   gst_ebml_write_element_push (ebml, data);
508 }
509
510 /*
511  * When replacing a uint, we assume that it is *always*
512  * 8-byte, since that's the safest guess we can do. This
513  * is just for simplicity.
514  *
515  * FIXME: this function needs to be replaced with something
516  * proper. This is a crude hack.
517  */
518
519 void
520 gst_ebml_replace_uint (GstEbmlWrite * ebml, guint64 pos, guint64 num)
521 {
522   guint64 oldpos = ebml->pos;
523   GstBuffer *buf = gst_buffer_new_and_alloc (8);
524
525   gst_ebml_write_seek (ebml, pos);
526   GST_BUFFER_SIZE (buf) = 0;
527   gst_ebml_write_set_uint (buf, num, 8);
528   gst_ebml_write_element_push (ebml, buf);
529   gst_ebml_write_seek (ebml, oldpos);
530 }
531
532 /*
533  * Write EBML header.
534  */
535
536 void
537 gst_ebml_write_header (GstEbmlWrite * ebml, gchar * doctype, guint version)
538 {
539   guint64 pos;
540
541   /* write the basic EBML header */
542   gst_ebml_write_set_cache (ebml, 0x40);
543   pos = gst_ebml_write_master_start (ebml, GST_EBML_ID_HEADER);
544 #if (GST_EBML_VERSION != 1)
545   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLVERSION, GST_EBML_VERSION);
546   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLREADVERSION, GST_EBML_VERSION);
547 #endif
548 #if 0
549   /* we don't write these until they're "non-default" (never!) */
550   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXIDLENGTH, sizeof (guint32));
551   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXSIZELENGTH, sizeof (guint64));
552 #endif
553   gst_ebml_write_ascii (ebml, GST_EBML_ID_DOCTYPE, doctype);
554   gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEVERSION, version);
555   gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEREADVERSION, version);
556   gst_ebml_write_master_finish (ebml, pos);
557   gst_ebml_write_flush_cache (ebml);
558 }