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