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