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