]> git.sesse.net Git - x264/blob - matroska.c
68bef0bc31b46026af5f87d3f364cfeb2ccd83b9
[x264] / matroska.c
1 /*****************************************************************************
2  * matroska.c:
3  *****************************************************************************
4  * Copyright (C) 2005 Mike Matsnev
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
19  *****************************************************************************/
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include "common/osdep.h"
24 #include "matroska.h"
25
26 #define CLSIZE    1048576
27 #define CHECK(x)  do { if ((x) < 0) return -1; } while (0)
28
29 struct mk_Context {
30   struct mk_Context *next, **prev, *parent;
31   struct mk_Writer  *owner;
32   unsigned          id;
33
34   void              *data;
35   unsigned          d_cur, d_max;
36 };
37
38 typedef struct mk_Context mk_Context;
39
40 struct mk_Writer {
41   FILE                *fp;
42
43   unsigned            duration_ptr;
44
45   mk_Context          *root, *cluster, *frame;
46   mk_Context          *freelist;
47   mk_Context          *actlist;
48
49   int64_t             def_duration;
50   int64_t             timescale;
51   int64_t             cluster_tc_scaled;
52   int64_t             frame_tc, prev_frame_tc_scaled, max_frame_tc;
53
54   char                wrote_header, in_frame, keyframe;
55 };
56
57 static mk_Context *mk_createContext(mk_Writer *w, mk_Context *parent, unsigned id) {
58   mk_Context  *c;
59
60   if (w->freelist) {
61     c = w->freelist;
62     w->freelist = w->freelist->next;
63   } else {
64     c = malloc(sizeof(*c));
65     if (c == NULL)
66       return NULL;
67     memset(c, 0, sizeof(*c));
68   }
69
70   c->parent = parent;
71   c->owner = w;
72   c->id = id;
73
74   if (c->owner->actlist)
75     c->owner->actlist->prev = &c->next;
76   c->next = c->owner->actlist;
77   c->prev = &c->owner->actlist;
78   c->owner->actlist = c;
79
80   return c;
81 }
82
83 static int        mk_appendContextData(mk_Context *c, const void *data, unsigned size) {
84   unsigned  ns = c->d_cur + size;
85
86   if (ns > c->d_max) {
87     void      *dp;
88     unsigned  dn = c->d_max ? c->d_max << 1 : 16;
89     while (ns > dn)
90       dn <<= 1;
91
92     dp = realloc(c->data, dn);
93     if (dp == NULL)
94       return -1;
95
96     c->data = dp;
97     c->d_max = dn;
98   }
99
100   memcpy((char*)c->data + c->d_cur, data, size);
101
102   c->d_cur = ns;
103
104   return 0;
105 }
106
107 static int        mk_writeID(mk_Context *c, unsigned id) {
108   unsigned char   c_id[4] = { id >> 24, id >> 16, id >> 8, id };
109
110   if (c_id[0])
111     return mk_appendContextData(c, c_id, 4);
112   if (c_id[1])
113     return mk_appendContextData(c, c_id+1, 3);
114   if (c_id[2])
115     return mk_appendContextData(c, c_id+2, 2);
116   return mk_appendContextData(c, c_id+3, 1);
117 }
118
119 static int        mk_writeSize(mk_Context *c, unsigned size) {
120   unsigned char   c_size[5] = { 0x08, size >> 24, size >> 16, size >> 8, size };
121
122   if (size < 0x7f) {
123     c_size[4] |= 0x80;
124     return mk_appendContextData(c, c_size+4, 1);
125   }
126   if (size < 0x3fff) {
127     c_size[3] |= 0x40;
128     return mk_appendContextData(c, c_size+3, 2);
129   }
130   if (size < 0x1fffff) {
131     c_size[2] |= 0x20;
132     return mk_appendContextData(c, c_size+2, 3);
133   }
134   if (size < 0x0fffffff) {
135     c_size[1] |= 0x10;
136     return mk_appendContextData(c, c_size+1, 4);
137   }
138   return mk_appendContextData(c, c_size, 5);
139 }
140
141 static int        mk_flushContextID(mk_Context *c) {
142   unsigned char ff = 0xff;
143
144   if (c->id == 0)
145     return 0;
146
147   CHECK(mk_writeID(c->parent, c->id));
148   CHECK(mk_appendContextData(c->parent, &ff, 1));
149
150   c->id = 0;
151
152   return 0;
153 }
154
155 static int        mk_flushContextData(mk_Context *c) {
156   if (c->d_cur == 0)
157     return 0;
158
159   if (c->parent)
160     CHECK(mk_appendContextData(c->parent, c->data, c->d_cur));
161   else
162     if (fwrite(c->data, c->d_cur, 1, c->owner->fp) != 1)
163       return -1;
164
165   c->d_cur = 0;
166
167   return 0;
168 }
169
170 static int        mk_closeContext(mk_Context *c, unsigned *off) {
171   if (c->id) {
172     CHECK(mk_writeID(c->parent, c->id));
173     CHECK(mk_writeSize(c->parent, c->d_cur));
174   }
175
176   if (c->parent && off != NULL)
177     *off += c->parent->d_cur;
178
179   CHECK(mk_flushContextData(c));
180
181   if (c->next)
182     c->next->prev = c->prev;
183   *(c->prev) = c->next;
184   c->next = c->owner->freelist;
185   c->owner->freelist = c;
186
187   return 0;
188 }
189
190 static void       mk_destroyContexts(mk_Writer *w) {
191   mk_Context  *cur, *next;
192
193   for (cur = w->freelist; cur; cur = next) {
194     next = cur->next;
195     free(cur->data);
196     free(cur);
197   }
198
199   for (cur = w->actlist; cur; cur = next) {
200     next = cur->next;
201     free(cur->data);
202     free(cur);
203   }
204
205   w->freelist = w->actlist = w->root = NULL;
206 }
207
208 static int        mk_writeStr(mk_Context *c, unsigned id, const char *str) {
209   size_t  len = strlen(str);
210
211   CHECK(mk_writeID(c, id));
212   CHECK(mk_writeSize(c, len));
213   CHECK(mk_appendContextData(c, str, len));
214   return 0;
215 }
216
217 static int        mk_writeBin(mk_Context *c, unsigned id, const void *data, unsigned size) {
218   CHECK(mk_writeID(c, id));
219   CHECK(mk_writeSize(c, size));
220   CHECK(mk_appendContextData(c, data, size));
221   return 0;
222 }
223
224 static int        mk_writeUInt(mk_Context *c, unsigned id, int64_t ui) {
225   unsigned char   c_ui[8] = { ui >> 56, ui >> 48, ui >> 40, ui >> 32, ui >> 24, ui >> 16, ui >> 8, ui };
226   unsigned        i = 0;
227
228   CHECK(mk_writeID(c, id));
229   while (i < 7 && c_ui[i] == 0)
230     ++i;
231   CHECK(mk_writeSize(c, 8 - i));
232   CHECK(mk_appendContextData(c, c_ui+i, 8 - i));
233   return 0;
234 }
235
236 static int        mk_writeSInt(mk_Context *c, unsigned id, int64_t si) {
237   unsigned char   c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
238   unsigned        i = 0;
239
240   CHECK(mk_writeID(c, id));
241   if (si < 0)
242     while (i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80)
243       ++i;
244   else
245     while (i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80))
246       ++i;
247   CHECK(mk_writeSize(c, 8 - i));
248   CHECK(mk_appendContextData(c, c_si+i, 8 - i));
249   return 0;
250 }
251
252 static int        mk_writeFloatRaw(mk_Context *c, float f) {
253   union {
254     float f;
255     unsigned u;
256   } u;
257   unsigned char c_f[4];
258
259   u.f = f;
260   c_f[0] = u.u >> 24;
261   c_f[1] = u.u >> 16;
262   c_f[2] = u.u >> 8;
263   c_f[3] = u.u;
264
265   return mk_appendContextData(c, c_f, 4);
266 }
267
268 static int        mk_writeFloat(mk_Context *c, unsigned id, float f) {
269   CHECK(mk_writeID(c, id));
270   CHECK(mk_writeSize(c, 4));
271   CHECK(mk_writeFloatRaw(c, f));
272   return 0;
273 }
274
275 static unsigned   mk_ebmlSizeSize(unsigned s) {
276   if (s < 0x7f)
277     return 1;
278   if (s < 0x3fff)
279     return 2;
280   if (s < 0x1fffff)
281     return 3;
282   if (s < 0x0fffffff)
283     return 4;
284   return 5;
285 }
286
287 static unsigned   mk_ebmlSIntSize(int64_t si) {
288   unsigned char   c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
289   unsigned        i = 0;
290
291   if (si < 0)
292     while (i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80)
293       ++i;
294   else
295     while (i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80))
296       ++i;
297
298   return 8 - i;
299 }
300
301 mk_Writer *mk_createWriter(const char *filename) {
302   mk_Writer *w = malloc(sizeof(*w));
303   if (w == NULL)
304     return NULL;
305
306   memset(w, 0, sizeof(*w));
307
308   w->root = mk_createContext(w, NULL, 0);
309   if (w->root == NULL) {
310     free(w);
311     return NULL;
312   }
313
314   w->fp = fopen(filename, "wb");
315   if (w->fp == NULL) {
316     mk_destroyContexts(w);
317     free(w);
318     return NULL;
319   }
320
321   w->timescale = 1000000;
322
323   return w;
324 }
325
326 int       mk_writeHeader(mk_Writer *w, const char *writingApp,
327                          const char *codecID,
328                          const void *codecPrivate, unsigned codecPrivateSize,
329                          int64_t default_frame_duration,
330                          int64_t timescale,
331                          unsigned width, unsigned height,
332                          unsigned d_width, unsigned d_height)
333 {
334   mk_Context  *c, *ti, *v;
335
336   if (w->wrote_header)
337     return -1;
338
339   w->timescale = timescale;
340   w->def_duration = default_frame_duration;
341
342   if ((c = mk_createContext(w, w->root, 0x1a45dfa3)) == NULL) // EBML
343     return -1;
344   CHECK(mk_writeUInt(c, 0x4286, 1)); // EBMLVersion
345   CHECK(mk_writeUInt(c, 0x42f7, 1)); // EBMLReadVersion
346   CHECK(mk_writeUInt(c, 0x42f2, 4)); // EBMLMaxIDLength
347   CHECK(mk_writeUInt(c, 0x42f3, 8)); // EBMLMaxSizeLength
348   CHECK(mk_writeStr(c, 0x4282, "matroska")); // DocType
349   CHECK(mk_writeUInt(c, 0x4287, 1)); // DocTypeVersion
350   CHECK(mk_writeUInt(c, 0x4285, 1)); // DocTypeReadversion
351   CHECK(mk_closeContext(c, 0));
352
353   if ((c = mk_createContext(w, w->root, 0x18538067)) == NULL) // Segment
354     return -1;
355   CHECK(mk_flushContextID(c));
356   CHECK(mk_closeContext(c, 0));
357
358   if ((c = mk_createContext(w, w->root, 0x1549a966)) == NULL) // SegmentInfo
359     return -1;
360   CHECK(mk_writeStr(c, 0x4d80, "Haali Matroska Writer b0"));
361   CHECK(mk_writeStr(c, 0x5741, writingApp));
362   CHECK(mk_writeUInt(c, 0x2ad7b1, w->timescale));
363   CHECK(mk_writeFloat(c, 0x4489, 0));
364   w->duration_ptr = c->d_cur - 4;
365   CHECK(mk_closeContext(c, &w->duration_ptr));
366
367   if ((c = mk_createContext(w, w->root, 0x1654ae6b)) == NULL) // tracks
368     return -1;
369   if ((ti = mk_createContext(w, c, 0xae)) == NULL) // TrackEntry
370     return -1;
371   CHECK(mk_writeUInt(ti, 0xd7, 1)); // TrackNumber
372   CHECK(mk_writeUInt(ti, 0x73c5, 1)); // TrackUID
373   CHECK(mk_writeUInt(ti, 0x83, 1)); // TrackType
374   CHECK(mk_writeUInt(ti, 0x9c, 0)); // FlagLacing
375   CHECK(mk_writeStr(ti, 0x86, codecID)); // CodecID
376   if (codecPrivateSize)
377     CHECK(mk_writeBin(ti, 0x63a2, codecPrivate, codecPrivateSize)); // CodecPrivate
378   if (default_frame_duration)
379     CHECK(mk_writeUInt(ti, 0x23e383, default_frame_duration)); // DefaultDuration
380
381   if ((v = mk_createContext(w, ti, 0xe0)) == NULL) // Video
382     return -1;
383   CHECK(mk_writeUInt(v, 0xb0, width));
384   CHECK(mk_writeUInt(v, 0xba, height));
385   CHECK(mk_writeUInt(v, 0x54b0, d_width));
386   CHECK(mk_writeUInt(v, 0x54ba, d_height));
387   CHECK(mk_closeContext(v, 0));
388
389   CHECK(mk_closeContext(ti, 0));
390
391   CHECK(mk_closeContext(c, 0));
392
393   CHECK(mk_flushContextData(w->root));
394
395   w->wrote_header = 1;
396
397   return 0;
398 }
399
400 static int mk_closeCluster(mk_Writer *w) {
401   if (w->cluster == NULL)
402     return 0;
403   CHECK(mk_closeContext(w->cluster, 0));
404   w->cluster = NULL;
405   CHECK(mk_flushContextData(w->root));
406   return 0;
407 }
408
409 static int mk_flushFrame(mk_Writer *w) {
410   int64_t       delta, ref = 0;
411   unsigned      fsize, bgsize;
412   unsigned char c_delta_flags[3];
413
414   if (!w->in_frame)
415     return 0;
416
417   delta = w->frame_tc/w->timescale - w->cluster_tc_scaled;
418   if (delta > 32767ll || delta < -32768ll)
419     CHECK(mk_closeCluster(w));
420
421   if (w->cluster == NULL) {
422     w->cluster_tc_scaled = w->frame_tc / w->timescale;
423     w->cluster = mk_createContext(w, w->root, 0x1f43b675); // Cluster
424     if (w->cluster == NULL)
425       return -1;
426
427     CHECK(mk_writeUInt(w->cluster, 0xe7, w->cluster_tc_scaled)); // Timecode
428
429     delta = 0;
430   }
431
432   fsize = w->frame ? w->frame->d_cur : 0;
433   bgsize = fsize + 4 + mk_ebmlSizeSize(fsize + 4) + 1;
434   if (!w->keyframe) {
435     ref = w->prev_frame_tc_scaled - w->cluster_tc_scaled - delta;
436     bgsize += 1 + 1 + mk_ebmlSIntSize(ref);
437   }
438
439   CHECK(mk_writeID(w->cluster, 0xa0)); // BlockGroup
440   CHECK(mk_writeSize(w->cluster, bgsize));
441   CHECK(mk_writeID(w->cluster, 0xa1)); // Block
442   CHECK(mk_writeSize(w->cluster, fsize + 4));
443   CHECK(mk_writeSize(w->cluster, 1)); // track number
444
445   c_delta_flags[0] = delta >> 8;
446   c_delta_flags[1] = delta;
447   c_delta_flags[2] = 0;
448   CHECK(mk_appendContextData(w->cluster, c_delta_flags, 3));
449   if (w->frame) {
450     CHECK(mk_appendContextData(w->cluster, w->frame->data, w->frame->d_cur));
451     w->frame->d_cur = 0;
452   }
453   if (!w->keyframe)
454     CHECK(mk_writeSInt(w->cluster, 0xfb, ref)); // ReferenceBlock
455
456   w->in_frame = 0;
457   w->prev_frame_tc_scaled = w->cluster_tc_scaled + delta;
458
459   if (w->cluster->d_cur > CLSIZE)
460     CHECK(mk_closeCluster(w));
461
462   return 0;
463 }
464
465 int       mk_startFrame(mk_Writer *w) {
466   if (mk_flushFrame(w) < 0)
467     return -1;
468
469   w->in_frame = 1;
470   w->keyframe = 0;
471
472   return 0;
473 }
474
475 int       mk_setFrameFlags(mk_Writer *w,int64_t timestamp, int keyframe) {
476   if (!w->in_frame)
477     return -1;
478
479   w->frame_tc = timestamp;
480   w->keyframe = keyframe != 0;
481
482   if (w->max_frame_tc < timestamp)
483     w->max_frame_tc = timestamp;
484
485   return 0;
486 }
487
488 int       mk_addFrameData(mk_Writer *w, const void *data, unsigned size) {
489   if (!w->in_frame)
490     return -1;
491
492   if (w->frame == NULL)
493     if ((w->frame = mk_createContext(w, NULL, 0)) == NULL)
494       return -1;
495
496   return mk_appendContextData(w->frame, data, size);
497 }
498
499 int       mk_close(mk_Writer *w) {
500   int   ret = 0;
501   if (mk_flushFrame(w) < 0 || mk_closeCluster(w) < 0)
502     ret = -1;
503   if (w->wrote_header) {
504     fseek(w->fp, w->duration_ptr, SEEK_SET);
505     if (mk_writeFloatRaw(w->root, (float)((double)(w->max_frame_tc+w->def_duration) / w->timescale)) < 0 ||
506         mk_flushContextData(w->root) < 0)
507       ret = -1;
508   }
509   mk_destroyContexts(w);
510   fclose(w->fp);
511   free(w);
512   return ret;
513 }
514