1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2005 Mike Matsnev
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.
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.
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 *****************************************************************************/
23 #include "common/osdep.h"
24 #include "matroska_ebml.h"
26 #define CLSIZE 1048576
35 struct mk_context *next, **prev, *parent;
40 unsigned d_cur, d_max;
43 typedef struct mk_context mk_context;
49 unsigned duration_ptr;
51 mk_context *root, *cluster, *frame;
57 int64_t cluster_tc_scaled;
58 int64_t frame_tc, prev_frame_tc_scaled, max_frame_tc;
60 char wrote_header, in_frame, keyframe;
63 static mk_context *mk_create_context( mk_writer *w, mk_context *parent, unsigned id )
70 w->freelist = w->freelist->next;
74 c = malloc( sizeof(*c) );
77 memset( c, 0, sizeof(*c) );
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;
93 static int mk_append_context_data( mk_context *c, const void *data, unsigned size )
95 unsigned ns = c->d_cur + size;
100 unsigned dn = c->d_max ? c->d_max << 1 : 16;
104 dp = realloc( c->data, dn );
112 memcpy( (char*)c->data + c->d_cur, data, size );
119 static int mk_write_id( mk_context *c, unsigned id )
121 unsigned char c_id[4] = { id >> 24, id >> 16, id >> 8, id };
124 return mk_append_context_data( c, c_id, 4 );
126 return mk_append_context_data( c, c_id+1, 3 );
128 return mk_append_context_data( c, c_id+2, 2 );
129 return mk_append_context_data( c, c_id+3, 1 );
132 static int mk_write_size( mk_context *c, unsigned size )
134 unsigned char c_size[5] = { 0x08, size >> 24, size >> 16, size >> 8, size };
139 return mk_append_context_data( c, c_size+4, 1 );
144 return mk_append_context_data( c, c_size+3, 2 );
146 if( size < 0x1fffff )
149 return mk_append_context_data( c, c_size+2, 3 );
151 if( size < 0x0fffffff )
154 return mk_append_context_data( c, c_size+1, 4 );
156 return mk_append_context_data( c, c_size, 5 );
159 static int mk_flush_context_id( mk_context *c )
161 unsigned char ff = 0xff;
166 CHECK( mk_write_id( c->parent, c->id ) );
167 CHECK( mk_append_context_data( c->parent, &ff, 1 ) );
174 static int mk_flush_context_data( mk_context *c )
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 )
189 static int mk_close_context( mk_context *c, unsigned *off )
193 CHECK( mk_write_id( c->parent, c->id ) );
194 CHECK( mk_write_size( c->parent, c->d_cur ) );
197 if( c->parent && off )
198 *off += c->parent->d_cur;
200 CHECK( mk_flush_context_data( c ) );
203 c->next->prev = c->prev;
204 *(c->prev) = c->next;
205 c->next = c->owner->freelist;
206 c->owner->freelist = c;
211 static void mk_destroy_contexts( mk_writer *w )
213 mk_context *cur, *next;
215 for( cur = w->freelist; cur; cur = next )
222 for( cur = w->actlist; cur; cur = next )
229 w->freelist = w->actlist = w->root = NULL;
232 static int mk_write_string( mk_context *c, unsigned id, const char *str )
234 size_t len = strlen( str );
236 CHECK( mk_write_id( c, id ) );
237 CHECK( mk_write_size( c, len ) );
238 CHECK( mk_append_context_data( c, str, len ) );
242 static int mk_write_bin( mk_context *c, unsigned id, const void *data, unsigned size )
244 CHECK( mk_write_id( c, id ) );
245 CHECK( mk_write_size( c, size ) );
246 CHECK( mk_append_context_data( c, data, size ) ) ;
250 static int mk_write_uint( mk_context *c, unsigned id, int64_t ui )
252 unsigned char c_ui[8] = { ui >> 56, ui >> 48, ui >> 40, ui >> 32, ui >> 24, ui >> 16, ui >> 8, ui };
255 CHECK( mk_write_id( c, id ) );
256 while( i < 7 && !c_ui[i] )
258 CHECK( mk_write_size( c, 8 - i ) );
259 CHECK( mk_append_context_data( c, c_ui+i, 8 - i ) );
263 static int mk_write_sint( mk_context *c, unsigned id, int64_t si )
265 unsigned char c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
268 CHECK( mk_write_id( c, id ) );
270 while( i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80 )
273 while( i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80 ) )
275 CHECK( mk_write_size( c, 8 - i ) );
276 CHECK( mk_append_context_data( c, c_si+i, 8 - i ) );
280 static int mk_write_float_raw( mk_context *c, float f )
287 unsigned char c_f[4];
295 return mk_append_context_data( c, c_f, 4 );
298 static int mk_write_float( mk_context *c, unsigned id, float f )
300 CHECK( mk_write_id( c, id ) );
301 CHECK( mk_write_size( c, 4 ) );
302 CHECK( mk_write_float_raw( c, f ) );
306 static unsigned mk_ebml_size_size( unsigned s )
319 static unsigned mk_ebml_sint_size( int64_t si )
321 unsigned char c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
325 while( i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80 )
328 while( i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80) )
334 mk_writer *mk_create_writer( const char *filename )
336 mk_writer *w = malloc( sizeof(*w) );
340 memset( w, 0, sizeof(*w) );
342 w->root = mk_create_context( w, NULL, 0 );
349 w->fp = fopen( filename, "wb" );
352 mk_destroy_contexts( w );
357 w->timescale = 1000000;
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,
367 unsigned width, unsigned height,
368 unsigned d_width, unsigned d_height )
370 mk_context *c, *ti, *v;
372 if( w->wrote_header )
375 w->timescale = timescale;
376 w->def_duration = default_frame_duration;
378 if( !(c = mk_create_context( w, w->root, 0x1a45dfa3 )) ) // EBML
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 ) );
389 if( !(c = mk_create_context( w, w->root, 0x18538067 )) ) // Segment
391 CHECK( mk_flush_context_id( c ) );
392 CHECK( mk_close_context( c, 0 ) );
394 if( !(c = mk_create_context( w, w->root, 0x1549a966 )) ) // SegmentInfo
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 ) );
403 if( !(c = mk_create_context( w, w->root, 0x1654ae6b )) ) // tracks
405 if( !(ti = mk_create_context( w, c, 0xae )) ) // TrackEntry
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
417 if( !(v = mk_create_context( w, ti, 0xe0 ) ) ) // Video
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 ) );
425 CHECK( mk_close_context( ti, 0 ) );
427 CHECK( mk_close_context( c, 0 ) );
429 CHECK( mk_flush_context_data( w->root ) );
436 static int mk_close_cluster( mk_writer *w )
438 if( w->cluster == NULL )
440 CHECK( mk_close_context( w->cluster, 0 ) );
442 CHECK( mk_flush_context_data( w->root ) );
446 static int mk_flush_frame( mk_writer *w )
448 int64_t delta, ref = 0;
449 unsigned fsize, bgsize;
450 unsigned char c_delta_flags[3];
455 delta = w->frame_tc/w->timescale - w->cluster_tc_scaled;
456 if( delta > 32767ll || delta < -32768ll )
457 CHECK( mk_close_cluster( w ) );
461 w->cluster_tc_scaled = w->frame_tc / w->timescale;
462 w->cluster = mk_create_context( w, w->root, 0x1f43b675 ); // Cluster
466 CHECK( mk_write_uint( w->cluster, 0xe7, w->cluster_tc_scaled ) ); // Timecode
471 fsize = w->frame ? w->frame->d_cur : 0;
472 bgsize = fsize + 4 + mk_ebml_size_size( fsize + 4 ) + 1;
475 ref = w->prev_frame_tc_scaled - w->cluster_tc_scaled - delta;
476 bgsize += 1 + 1 + mk_ebml_sint_size( ref );
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
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 ) );
491 CHECK( mk_append_context_data( w->cluster, w->frame->data, w->frame->d_cur ) );
495 CHECK( mk_write_sint( w->cluster, 0xfb, ref ) ); // ReferenceBlock
498 w->prev_frame_tc_scaled = w->cluster_tc_scaled + delta;
500 if( w->cluster->d_cur > CLSIZE )
501 CHECK( mk_close_cluster( w ) );
506 int mk_start_frame( mk_writer *w )
508 if( mk_flush_frame( w ) < 0 )
517 int mk_set_frame_flags( mk_writer *w, int64_t timestamp, int keyframe )
522 w->frame_tc = timestamp;
523 w->keyframe = keyframe != 0;
525 if( w->max_frame_tc < timestamp )
526 w->max_frame_tc = timestamp;
531 int mk_add_frame_data( mk_writer *w, const void *data, unsigned size )
537 if( !(w->frame = mk_create_context( w, NULL, 0 )) )
540 return mk_append_context_data( w->frame, data, size );
543 int mk_close( mk_writer *w )
546 if( mk_flush_frame( w ) < 0 || mk_close_cluster( w ) < 0 )
548 if( w->wrote_header )
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 )
555 mk_destroy_contexts( w );