]> git.sesse.net Git - x264/blob - output/matroska_ebml.c
Fix GPAC support on Windows
[x264] / output / matroska_ebml.c
1 /*****************************************************************************
2  * matroska_ebml.c: matroska muxer utilities
3  *****************************************************************************
4  * Copyright (C) 2005-2013 x264 project
5  *
6  * Authors: Mike Matsnev <mike@haali.su>
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 licensing@x264.com.
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 = malloc( sizeof(*c) );
78         if( !c )
79             return NULL;
80         memset( c, 0, sizeof(*c) );
81     }
82
83     c->parent = parent;
84     c->owner = w;
85     c->id = id;
86
87     if( c->owner->actlist )
88         c->owner->actlist->prev = &c->next;
89     c->next = c->owner->actlist;
90     c->prev = &c->owner->actlist;
91     c->owner->actlist = c;
92
93     return c;
94 }
95
96 static int mk_append_context_data( mk_context *c, const void *data, unsigned size )
97 {
98     unsigned ns = c->d_cur + size;
99
100     if( ns > c->d_max )
101     {
102         void *dp;
103         unsigned dn = c->d_max ? c->d_max << 1 : 16;
104         while( ns > dn )
105             dn <<= 1;
106
107         dp = realloc( c->data, dn );
108         if( !dp )
109             return -1;
110
111         c->data = dp;
112         c->d_max = dn;
113     }
114
115     memcpy( (char*)c->data + c->d_cur, data, size );
116
117     c->d_cur = ns;
118
119     return 0;
120 }
121
122 static int mk_write_id( mk_context *c, unsigned id )
123 {
124     unsigned char c_id[4] = { id >> 24, id >> 16, id >> 8, id };
125
126     if( c_id[0] )
127         return mk_append_context_data( c, c_id, 4 );
128     if( c_id[1] )
129         return mk_append_context_data( c, c_id+1, 3 );
130     if( c_id[2] )
131         return mk_append_context_data( c, c_id+2, 2 );
132     return mk_append_context_data( c, c_id+3, 1 );
133 }
134
135 static int mk_write_size( mk_context *c, unsigned size )
136 {
137     unsigned char c_size[5] = { 0x08, size >> 24, size >> 16, size >> 8, size };
138
139     if( size < 0x7f )
140     {
141         c_size[4] |= 0x80;
142         return mk_append_context_data( c, c_size+4, 1 );
143     }
144     if( size < 0x3fff )
145     {
146         c_size[3] |= 0x40;
147         return mk_append_context_data( c, c_size+3, 2 );
148     }
149     if( size < 0x1fffff )
150     {
151         c_size[2] |= 0x20;
152         return mk_append_context_data( c, c_size+2, 3 );
153     }
154     if( size < 0x0fffffff )
155     {
156         c_size[1] |= 0x10;
157         return mk_append_context_data( c, c_size+1, 4 );
158     }
159     return mk_append_context_data( c, c_size, 5 );
160 }
161
162 static int mk_flush_context_id( mk_context *c )
163 {
164     unsigned char ff = 0xff;
165
166     if( !c->id )
167         return 0;
168
169     CHECK( mk_write_id( c->parent, c->id ) );
170     CHECK( mk_append_context_data( c->parent, &ff, 1 ) );
171
172     c->id = 0;
173
174     return 0;
175 }
176
177 static int mk_flush_context_data( mk_context *c )
178 {
179     if( !c->d_cur )
180         return 0;
181
182     if( c->parent )
183         CHECK( mk_append_context_data( c->parent, c->data, c->d_cur ) );
184     else if( fwrite( c->data, c->d_cur, 1, c->owner->fp ) != 1 )
185         return -1;
186
187     c->d_cur = 0;
188
189     return 0;
190 }
191
192 static int mk_close_context( mk_context *c, unsigned *off )
193 {
194     if( c->id )
195     {
196         CHECK( mk_write_id( c->parent, c->id ) );
197         CHECK( mk_write_size( c->parent, c->d_cur ) );
198     }
199
200     if( c->parent && off )
201         *off += c->parent->d_cur;
202
203     CHECK( mk_flush_context_data( c ) );
204
205     if( c->next )
206         c->next->prev = c->prev;
207     *(c->prev) = c->next;
208     c->next = c->owner->freelist;
209     c->owner->freelist = c;
210
211     return 0;
212 }
213
214 static void mk_destroy_contexts( mk_writer *w )
215 {
216     mk_context *next;
217
218     for( mk_context *cur = w->freelist; cur; cur = next )
219     {
220         next = cur->next;
221         free( cur->data );
222         free( cur );
223     }
224
225     for( mk_context *cur = w->actlist; cur; cur = next )
226     {
227         next = cur->next;
228         free( cur->data );
229         free( cur );
230     }
231
232     w->freelist = w->actlist = w->root = NULL;
233 }
234
235 static int mk_write_string( mk_context *c, unsigned id, const char *str )
236 {
237     size_t len = strlen( str );
238
239     CHECK( mk_write_id( c, id ) );
240     CHECK( mk_write_size( c, len ) );
241     CHECK( mk_append_context_data( c, str, len ) );
242     return 0;
243 }
244
245 static int mk_write_bin( mk_context *c, unsigned id, const void *data, unsigned size )
246 {
247     CHECK( mk_write_id( c, id ) );
248     CHECK( mk_write_size( c, size ) );
249     CHECK( mk_append_context_data( c, data, size ) ) ;
250     return 0;
251 }
252
253 static int mk_write_uint( mk_context *c, unsigned id, int64_t ui )
254 {
255     unsigned char c_ui[8] = { ui >> 56, ui >> 48, ui >> 40, ui >> 32, ui >> 24, ui >> 16, ui >> 8, ui };
256     unsigned i = 0;
257
258     CHECK( mk_write_id( c, id ) );
259     while( i < 7 && !c_ui[i] )
260         ++i;
261     CHECK( mk_write_size( c, 8 - i ) );
262     CHECK( mk_append_context_data( c, c_ui+i, 8 - i ) );
263     return 0;
264 }
265
266 static int mk_write_float_raw( mk_context *c, float f )
267 {
268     union
269     {
270         float f;
271         unsigned u;
272     } u;
273     unsigned char c_f[4];
274
275     u.f = f;
276     c_f[0] = u.u >> 24;
277     c_f[1] = u.u >> 16;
278     c_f[2] = u.u >> 8;
279     c_f[3] = u.u;
280
281     return mk_append_context_data( c, c_f, 4 );
282 }
283
284 static int mk_write_float( mk_context *c, unsigned id, float f )
285 {
286     CHECK( mk_write_id( c, id ) );
287     CHECK( mk_write_size( c, 4 ) );
288     CHECK( mk_write_float_raw( c, f ) );
289     return 0;
290 }
291
292 mk_writer *mk_create_writer( const char *filename )
293 {
294     mk_writer *w = malloc( sizeof(*w) );
295     if( !w )
296         return NULL;
297
298     memset( w, 0, sizeof(*w) );
299
300     w->root = mk_create_context( w, NULL, 0 );
301     if( !w->root )
302     {
303         free( w );
304         return NULL;
305     }
306
307     if( !strcmp( filename, "-" ) )
308         w->fp = stdout;
309     else
310         w->fp = x264_fopen( filename, "wb" );
311     if( !w->fp )
312     {
313         mk_destroy_contexts( w );
314         free( w );
315         return NULL;
316     }
317
318     w->timescale = 1000000;
319
320     return w;
321 }
322
323 int mk_write_header( mk_writer *w, const char *writing_app,
324                      const char *codec_id,
325                      const void *codec_private, unsigned codec_private_size,
326                      int64_t default_frame_duration,
327                      int64_t timescale,
328                      unsigned width, unsigned height,
329                      unsigned d_width, unsigned d_height, int display_size_units )
330 {
331     mk_context  *c, *ti, *v;
332
333     if( w->wrote_header )
334         return -1;
335
336     w->timescale = timescale;
337     w->def_duration = default_frame_duration;
338
339     if( !(c = mk_create_context( w, w->root, 0x1a45dfa3 )) ) // EBML
340         return -1;
341     CHECK( mk_write_uint( c, 0x4286, 1 ) ); // EBMLVersion
342     CHECK( mk_write_uint( c, 0x42f7, 1 ) ); // EBMLReadVersion
343     CHECK( mk_write_uint( c, 0x42f2, 4 ) ); // EBMLMaxIDLength
344     CHECK( mk_write_uint( c, 0x42f3, 8 ) ); // EBMLMaxSizeLength
345     CHECK( mk_write_string( c, 0x4282, "matroska") ); // DocType
346     CHECK( mk_write_uint( c, 0x4287, 2 ) ); // DocTypeVersion
347     CHECK( mk_write_uint( c, 0x4285, 2 ) ); // DocTypeReadversion
348     CHECK( mk_close_context( c, 0 ) );
349
350     if( !(c = mk_create_context( w, w->root, 0x18538067 )) ) // Segment
351         return -1;
352     CHECK( mk_flush_context_id( c ) );
353     CHECK( mk_close_context( c, 0 ) );
354
355     if( !(c = mk_create_context( w, w->root, 0x1549a966 )) ) // SegmentInfo
356         return -1;
357     CHECK( mk_write_string( c, 0x4d80, "Haali Matroska Writer b0" ) );
358     CHECK( mk_write_string( c, 0x5741, writing_app ) );
359     CHECK( mk_write_uint( c, 0x2ad7b1, w->timescale ) );
360     CHECK( mk_write_float( c, 0x4489, 0) );
361     w->duration_ptr = c->d_cur - 4;
362     CHECK( mk_close_context( c, &w->duration_ptr ) );
363
364     if( !(c = mk_create_context( w, w->root, 0x1654ae6b )) ) // tracks
365         return -1;
366     if( !(ti = mk_create_context( w, c, 0xae )) ) // TrackEntry
367         return -1;
368     CHECK( mk_write_uint( ti, 0xd7, 1 ) ); // TrackNumber
369     CHECK( mk_write_uint( ti, 0x73c5, 1 ) ); // TrackUID
370     CHECK( mk_write_uint( ti, 0x83, 1 ) ); // TrackType
371     CHECK( mk_write_uint( ti, 0x9c, 0 ) ); // FlagLacing
372     CHECK( mk_write_string( ti, 0x86, codec_id ) ); // codec_id
373     if( codec_private_size )
374         CHECK( mk_write_bin( ti, 0x63a2, codec_private, codec_private_size ) ); // codec_private
375     if( default_frame_duration )
376         CHECK( mk_write_uint( ti, 0x23e383, default_frame_duration ) ); // DefaultDuration
377
378     if( !(v = mk_create_context( w, ti, 0xe0 ) ) ) // Video
379         return -1;
380     CHECK( mk_write_uint( v, 0xb0, width ) );
381     CHECK( mk_write_uint( v, 0xba, height ) );
382     CHECK( mk_write_uint( v, 0x54b2, display_size_units ) );
383     CHECK( mk_write_uint( v, 0x54b0, d_width ) );
384     CHECK( mk_write_uint( v, 0x54ba, d_height ) );
385     CHECK( mk_close_context( v, 0 ) );
386
387     CHECK( mk_close_context( ti, 0 ) );
388
389     CHECK( mk_close_context( c, 0 ) );
390
391     CHECK( mk_flush_context_data( w->root ) );
392
393     w->wrote_header = 1;
394
395     return 0;
396 }
397
398 static int mk_close_cluster( mk_writer *w )
399 {
400     if( w->cluster == NULL )
401         return 0;
402     CHECK( mk_close_context( w->cluster, 0 ) );
403     w->cluster = NULL;
404     CHECK( mk_flush_context_data( w->root ) );
405     return 0;
406 }
407
408 static int mk_flush_frame( mk_writer *w )
409 {
410     int64_t delta;
411     unsigned fsize;
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_close_cluster( w ) );
420
421     if( !w->cluster )
422     {
423         w->cluster_tc_scaled = w->frame_tc / w->timescale;
424         w->cluster = mk_create_context( w, w->root, 0x1f43b675 ); // Cluster
425         if( !w->cluster )
426             return -1;
427
428         CHECK( mk_write_uint( w->cluster, 0xe7, w->cluster_tc_scaled ) ); // Timecode
429
430         delta = 0;
431     }
432
433     fsize = w->frame ? w->frame->d_cur : 0;
434
435     CHECK( mk_write_id( w->cluster, 0xa3 ) ); // SimpleBlock
436     CHECK( mk_write_size( w->cluster, fsize + 4 ) );
437     CHECK( mk_write_size( w->cluster, 1 ) ); // track number
438
439     c_delta_flags[0] = delta >> 8;
440     c_delta_flags[1] = delta;
441     c_delta_flags[2] = (w->keyframe << 7) | w->skippable;
442     CHECK( mk_append_context_data( w->cluster, c_delta_flags, 3 ) );
443     if( w->frame )
444     {
445         CHECK( mk_append_context_data( w->cluster, w->frame->data, w->frame->d_cur ) );
446         w->frame->d_cur = 0;
447     }
448
449     w->in_frame = 0;
450
451     if( w->cluster->d_cur > CLSIZE )
452         CHECK( mk_close_cluster( w ) );
453
454     return 0;
455 }
456
457 int mk_start_frame( mk_writer *w )
458 {
459     if( mk_flush_frame( w ) < 0 )
460         return -1;
461
462     w->in_frame  = 1;
463     w->keyframe  = 0;
464     w->skippable = 0;
465
466     return 0;
467 }
468
469 int mk_set_frame_flags( mk_writer *w, int64_t timestamp, int keyframe, int skippable )
470 {
471     if( !w->in_frame )
472         return -1;
473
474     w->frame_tc  = timestamp;
475     w->keyframe  = keyframe  != 0;
476     w->skippable = skippable != 0;
477
478     if( w->max_frame_tc < timestamp )
479         w->max_frame_tc = timestamp;
480
481     return 0;
482 }
483
484 int mk_add_frame_data( mk_writer *w, const void *data, unsigned size )
485 {
486     if( !w->in_frame )
487         return -1;
488
489     if( !w->frame )
490         if( !(w->frame = mk_create_context( w, NULL, 0 )) )
491         return -1;
492
493     return mk_append_context_data( w->frame, data, size );
494 }
495
496 int mk_close( mk_writer *w, int64_t last_delta )
497 {
498     int ret = 0;
499     if( mk_flush_frame( w ) < 0 || mk_close_cluster( w ) < 0 )
500         ret = -1;
501     if( w->wrote_header && x264_is_regular_file( w->fp ) )
502     {
503         fseek( w->fp, w->duration_ptr, SEEK_SET );
504         int64_t last_frametime = w->def_duration ? w->def_duration : last_delta;
505         int64_t total_duration = w->max_frame_tc+last_frametime;
506         if( mk_write_float_raw( w->root, (float)((double)total_duration / w->timescale) ) < 0 ||
507             mk_flush_context_data( w->root ) < 0 )
508             ret = -1;
509     }
510     mk_destroy_contexts( w );
511     fclose( w->fp );
512     free( w );
513     return ret;
514 }