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