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