b650486707bd70aec69ac5b26db0aeaa43708ff9
[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   /* FILL ME */
33   LAST_SIGNAL
34 };
35
36 static void gst_ebml_write_class_init   (GstEbmlWriteClass *klass);
37 static void gst_ebml_write_init         (GstEbmlWrite      *ebml);
38 static GstElementStateReturn
39             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,
119                           guint         size)
120 {
121   /* This is currently broken. I don't know why yet. */
122   return;
123
124   g_return_if_fail (ebml->cache == NULL);
125
126   ebml->cache = gst_buffer_new_and_alloc (size);
127   GST_BUFFER_SIZE (ebml->cache) = 0;
128   GST_BUFFER_OFFSET (ebml->cache) = ebml->pos;
129   ebml->handled = 0;
130 }
131
132 void
133 gst_ebml_write_flush_cache (GstEbmlWrite *ebml)
134 {
135   if (!ebml->cache)
136     return;
137
138   /* this is very important. It may fail, in which case the client
139    * programmer didn't use the cache somewhere. That's fatal. */
140   g_assert (ebml->handled == GST_BUFFER_SIZE (ebml->cache));
141   g_assert (GST_BUFFER_SIZE (ebml->cache) +
142                 GST_BUFFER_OFFSET (ebml->cache) == ebml->pos);
143
144   gst_pad_push (ebml->srcpad, GST_DATA (ebml->cache));
145   ebml->cache = NULL;
146   ebml->handled = 0;
147 }
148
149 /*
150  * One-element buffer, in case of no cache. If there is
151  * a cache, use that instead.
152  */
153
154 static GstBuffer *
155 gst_ebml_write_element_new (GstEbmlWrite *ebml,
156                             guint         size)
157 {
158   /* Create new buffer of size + ID + length */
159   GstBuffer *buf;
160
161   /* length, ID */
162   size += 12;
163
164   /* prefer cache */
165   if (ebml->cache) {
166     if (GST_BUFFER_MAXSIZE (ebml->cache) -
167                 GST_BUFFER_SIZE (ebml->cache) < size) {
168       GST_LOG ("Cache available, but too small. Clearing...");
169       gst_ebml_write_flush_cache (ebml);
170     } else {
171       return ebml->cache;
172     }
173   }
174
175   /* else, use a one-element buffer. This is slower */
176   buf = gst_buffer_new_and_alloc (size);
177   GST_BUFFER_SIZE (buf) = 0;
178
179   return buf;
180 }
181
182 /*
183  * Write element ID into a buffer.
184  */
185
186 static void
187 gst_ebml_write_element_id (GstBuffer *buf,
188                            guint32    id)
189 {
190   guint8 *data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
191   guint bytes = 4, mask = 0x10;
192
193   /* get ID length */
194   while (!(id & (mask << ((bytes - 1) * 8))) && bytes > 0) {
195     mask <<= 1;
196     bytes--;
197   }
198
199   /* if invalid ID, use dummy */
200   if (bytes == 0) {
201     GST_WARNING ("Invalid ID, voiding");
202     bytes = 1;
203     id = GST_EBML_ID_VOID;
204   }
205
206   /* write out, BE */
207   GST_BUFFER_SIZE (buf) += bytes;
208   while (bytes--) {
209     data[bytes] = id & 0xff;
210     id >>= 8;
211   }
212 }
213
214 /*
215  * Write element length into a buffer.
216  */
217
218 static void
219 gst_ebml_write_element_size (GstBuffer    *buf,
220                              guint64       size)
221 {
222   guint8 *data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
223   guint bytes = 1, mask = 0x80;
224
225   /* how many bytes? */
226   while ((size >> ((bytes - 1) * 8)) >= mask && bytes <= 8) {
227     mask >>= 1;
228     bytes++;
229   }
230
231   /* if invalid size, use max. */
232   if (bytes > 8) {
233     GST_WARNING ("Invalid size, maximizing");
234     mask = 0x01;
235     bytes = 8;
236     /* Now here's a real FIXME: we cannot read those yet! */
237     size = 0x00ffffffffffffffLLU;
238   }
239
240   /* write out, BE, with length size marker */
241   GST_BUFFER_SIZE (buf) += bytes;
242   while (bytes-- > 0) {
243     data[bytes] = size & 0xff;
244     size >>= 8;
245     if (!bytes)
246       *data |= mask;
247   }
248 }
249
250 /*
251  * Write element data into a buffer.
252  */
253
254 static void
255 gst_ebml_write_element_data (GstBuffer    *buf,
256                              guint8       *write,
257                              guint64       length)
258 {
259   guint8 *data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
260
261   memcpy (data, write, length);
262   GST_BUFFER_SIZE (buf) += length;
263 }
264
265 /*
266  * Write out buffer by moving it to the next element.
267  */
268
269 static void
270 gst_ebml_write_element_push (GstEbmlWrite *ebml,
271                              GstBuffer    *buf)
272 {
273   guint data_size = GST_BUFFER_SIZE (buf) - ebml->handled;
274
275   ebml->pos += data_size;
276   if (buf == ebml->cache) {
277     ebml->handled += data_size;
278   }
279
280   /* if there's no cache, then don't push it! */
281   if (ebml->cache) {
282     g_assert (buf == ebml->cache);
283     return;
284   }
285
286   gst_pad_push (ebml->srcpad, GST_DATA (buf));
287 }
288
289 /*
290  * Seek.
291  */
292
293 void
294 gst_ebml_write_seek (GstEbmlWrite *ebml,
295                      guint64       pos)
296 {
297   GstEvent *seek;
298
299   /* Cache seeking. A bit dangerous, we assume the client writer
300    * knows what he's doing... */
301   if (ebml->cache) {
302     /* within bounds? */
303     if (pos >= GST_BUFFER_OFFSET (ebml->cache) &&
304         pos < GST_BUFFER_OFFSET (ebml->cache) + GST_BUFFER_MAXSIZE (ebml->cache)) {
305       GST_BUFFER_SIZE (ebml->cache) = pos - GST_BUFFER_OFFSET (ebml->cache);
306       if (ebml->pos > pos)
307         ebml->handled -= ebml->pos - pos;
308       else
309         ebml->handled += pos - ebml->pos;
310       ebml->pos = pos;
311     } else {
312       GST_LOG ("Seek outside cache range. Clearing...");
313       gst_ebml_write_flush_cache (ebml);
314     }
315   }
316
317   seek = gst_event_new_seek (GST_FORMAT_BYTES |
318                              GST_SEEK_METHOD_SET,
319                              pos);
320   gst_pad_push (ebml->srcpad, GST_DATA (seek));
321   ebml->pos = pos;
322 }
323
324 /*
325  * Get no. bytes needed to write a uint.
326  */
327
328 static guint
329 gst_ebml_write_get_uint_size (guint64 num)
330 {
331   guint size = 1;
332
333   /* get size */
334   while (num >= (1LLU << (size * 8)) && size < 8) {
335     size++;
336   }
337
338   return size;
339 }
340
341
342 /*
343  * Write an uint into a buffer.
344  */
345
346 static void
347 gst_ebml_write_set_uint (GstBuffer *buf,
348                          guint64    num,
349                          guint      size)
350 {
351   guint8 *data;
352
353   data = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
354   GST_BUFFER_SIZE (buf) += size;
355   while (size-- > 0) {
356     data[size] = num & 0xff;
357     num >>= 8;
358   }
359 }
360
361 /*
362  * Data type wrappers.
363  */
364
365 void
366 gst_ebml_write_uint (GstEbmlWrite *ebml,
367                      guint32       id,
368                      guint64       num)
369 {
370   GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num));
371   guint size = gst_ebml_write_get_uint_size (num);
372
373   /* write */
374   gst_ebml_write_element_id (buf, id);
375   gst_ebml_write_element_size (buf, size);
376   gst_ebml_write_set_uint (buf, num, size);
377   gst_ebml_write_element_push (ebml, buf);
378 }
379
380 void
381 gst_ebml_write_sint (GstEbmlWrite *ebml,
382                      guint32       id,
383                      gint64        num)
384 {
385   GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num));
386   /* if the signed number is on the edge of a extra-byte,
387    * then we'll fall over when detecting it. Example: if I
388    * have a number (-)0x8000 (G_MINSHORT), then my abs()<<1
389    * will be 0x10000; this is G_MAXUSHORT+1! So: if (<0) -1. */
390   guint64 unum = (num < 0 ? (-num - 1) << 1 : num << 1);
391   guint size = gst_ebml_write_get_uint_size (unum);
392
393   /* make unsigned */
394   if (num >= 0) {
395     unum = num;
396   } else {
397     unum = 0x80 << (size - 1);
398     unum += num;
399     unum |= 0x80 << (size - 1);
400   }
401
402   /* write */
403   gst_ebml_write_element_id (buf, id);
404   gst_ebml_write_element_size (buf, size);
405   gst_ebml_write_set_uint (buf, unum, size);
406   gst_ebml_write_element_push (ebml, buf);
407 }
408
409 void
410 gst_ebml_write_float (GstEbmlWrite *ebml,
411                       guint32       id,
412                       gdouble       num)
413 {
414 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
415   gint n;
416 #endif
417   GstBuffer *buf = gst_ebml_write_element_new (ebml, sizeof (num));
418
419   gst_ebml_write_element_id (buf, id);
420   gst_ebml_write_element_size (buf, 8);
421 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
422   for (n = 0; n < 8; n++)
423     GST_BUFFER_DATA (buf)[GST_BUFFER_SIZE (buf)] = ((guint8 *) &num)[7-n];
424   GST_BUFFER_SIZE (buf) += 8;
425 #else
426   gst_ebml_write_element_data (buf, (guint8 *) &num, 8);
427 #endif
428   gst_ebml_write_element_push (ebml, buf);
429 }
430
431 void
432 gst_ebml_write_ascii (GstEbmlWrite *ebml,
433                       guint32       id,
434                       const gchar  *str)
435 {
436   gint len = strlen (str) + 1; /* add trailing '\0' */
437   GstBuffer *buf = gst_ebml_write_element_new (ebml, len);
438
439   gst_ebml_write_element_id (buf, id);
440   gst_ebml_write_element_size (buf, len);
441   gst_ebml_write_element_data (buf, (guint8 *) str, len);
442   gst_ebml_write_element_push (ebml, buf);
443 }
444
445 void
446 gst_ebml_write_utf8 (GstEbmlWrite *ebml,
447                      guint32       id,
448                      const gchar  *str)
449 {
450   gst_ebml_write_ascii (ebml, id, str);
451 }
452
453 void
454 gst_ebml_write_date (GstEbmlWrite *ebml,
455                      guint32       id,
456                      gint64        date)
457 {
458   gst_ebml_write_sint (ebml, id, date);
459 }
460
461 /*
462  * Master writing is annoying. We use a size marker of
463  * the max. allowed length, so that we can later fill it
464  * in validly. 
465  */
466
467 guint64
468 gst_ebml_write_master_start (GstEbmlWrite *ebml,
469                              guint32       id)
470 {
471   guint64 pos = ebml->pos, t;
472   GstBuffer *buf = gst_ebml_write_element_new (ebml, 0);
473
474   t = GST_BUFFER_SIZE (buf);
475   gst_ebml_write_element_id (buf, id);
476   pos += GST_BUFFER_SIZE (buf) - t;
477   gst_ebml_write_element_size (buf, -1);
478   gst_ebml_write_element_push (ebml, buf);
479
480   return pos;
481 }
482
483 void
484 gst_ebml_write_master_finish (GstEbmlWrite *ebml,
485                               guint64       startpos)
486 {
487   guint64 pos = ebml->pos;
488   GstBuffer *buf;
489
490   gst_ebml_write_seek (ebml, startpos);
491   buf = gst_ebml_write_element_new (ebml, 0);
492   startpos = GUINT64_TO_BE ((1LLU << 56) | (pos - startpos - 8));
493   memcpy (GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf),
494           (guint8 *) &startpos, 8);
495   GST_BUFFER_SIZE (buf) += 8;
496   gst_ebml_write_element_push (ebml, buf);
497   gst_ebml_write_seek (ebml, pos);
498 }
499
500 void
501 gst_ebml_write_binary (GstEbmlWrite *ebml,
502                        guint32       id,
503                        guint8       *binary,
504                        guint64       length)
505 {
506   GstBuffer *buf = gst_ebml_write_element_new (ebml, length);
507
508   gst_ebml_write_element_id (buf, id);
509   gst_ebml_write_element_size (buf, length);
510   gst_ebml_write_element_data (buf, binary, length);
511   gst_ebml_write_element_push (ebml, buf);
512 }
513
514 /*
515  * For things like video frames and audio samples,
516  * you want to use this function, as it doesn't have
517  * the overhead of memcpy() that other functions
518  * such as write_binary() do have.
519  */
520
521 void
522 gst_ebml_write_buffer_header (GstEbmlWrite *ebml,
523                               guint32       id,
524                               guint64       length)
525 {
526   GstBuffer *buf = gst_ebml_write_element_new (ebml, 0);
527
528   gst_ebml_write_element_id (buf, id);
529   gst_ebml_write_element_size (buf, length);
530   gst_ebml_write_element_push (ebml, buf);
531 }
532
533 void
534 gst_ebml_write_buffer (GstEbmlWrite *ebml,
535                        GstBuffer    *data)
536 {
537   gst_ebml_write_element_push (ebml, data);
538 }
539
540 /*
541  * When replacing a uint, we assume that it is *always*
542  * 8-byte, since that's the safest guess we can do. This
543  * is just for simplicity.
544  *
545  * FIXME: this function needs to be replaced with something
546  * proper. This is a crude hack.
547  */
548
549 void
550 gst_ebml_replace_uint (GstEbmlWrite *ebml,
551                        guint64       pos,
552                        guint64       num)
553 {
554   guint64 oldpos = ebml->pos;
555   GstBuffer *buf = gst_buffer_new_and_alloc (8);
556
557   gst_ebml_write_seek (ebml, pos);
558   GST_BUFFER_SIZE (buf) = 0;
559   gst_ebml_write_set_uint (buf, num, 8);
560   gst_ebml_write_element_push (ebml, buf);
561   gst_ebml_write_seek (ebml, oldpos);
562 }
563
564 /*
565  * Write EBML header.
566  */
567
568 void
569 gst_ebml_write_header (GstEbmlWrite *ebml,
570                        gchar        *doctype,
571                        guint         version)
572 {
573   guint64 pos;
574
575   /* write the basic EBML header */
576   gst_ebml_write_set_cache (ebml, 0x40);
577   pos = gst_ebml_write_master_start (ebml, GST_EBML_ID_HEADER);
578 #if (GST_EBML_VERSION != 1)
579   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLVERSION, GST_EBML_VERSION);
580   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLREADVERSION, GST_EBML_VERSION);
581 #endif
582 #if 0
583   /* we don't write these until they're "non-default" (never!) */
584   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXIDLENGTH, sizeof (guint32));
585   gst_ebml_write_uint (ebml, GST_EBML_ID_EBMLMAXSIZELENGTH, sizeof (guint64));
586 #endif
587   gst_ebml_write_ascii (ebml, GST_EBML_ID_DOCTYPE, doctype);
588   gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEVERSION, version);
589   gst_ebml_write_uint (ebml, GST_EBML_ID_DOCTYPEREADVERSION, version);
590   gst_ebml_write_master_finish (ebml, pos);
591   gst_ebml_write_flush_cache (ebml);
592 }