~ubuntu-branches/ubuntu/edgy/x264/edgy

1 by Reinhard Tartler
Import upstream version 0.cvs20060210
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