]> git.sesse.net Git - x264/blob - muxers.c
Overhaul syntax in muxers.c/matroska.c
[x264] / muxers.c
1 /*****************************************************************************
2  * muxers.c: h264 file i/o plugins
3  *****************************************************************************
4  * Copyright (C) 2003-2008 x264 project
5  *
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  *          Loren Merritt <lorenm@u.washington.edu>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #include "common/common.h"
25 #include "x264.h"
26 #include "matroska.h"
27 #include "muxers.h"
28
29 #ifndef _MSC_VER
30 #include "config.h"
31 #endif
32
33 #include <sys/types.h>
34
35 #ifdef AVIS_INPUT
36 #include <windows.h>
37 #include <vfw.h>
38 #endif
39
40 #ifdef MP4_OUTPUT
41 #include <gpac/isomedia.h>
42 #endif
43
44 static int64_t gcd( int64_t a, int64_t b )
45 {
46     while( 1 )
47     {
48         int64_t c = a % b;
49         if( !c )
50             return b;
51         a = b;
52         b = c;
53     }
54 }
55
56 typedef struct
57 {
58     FILE *fh;
59     int width, height;
60     int next_frame;
61 } yuv_input_t;
62
63 /* raw 420 yuv file operation */
64 int open_file_yuv( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
65 {
66     yuv_input_t *h = malloc( sizeof(yuv_input_t) );
67     if( !h )
68         return -1;
69     h->width = p_param->i_width;
70     h->height = p_param->i_height;
71     h->next_frame = 0;
72
73     if( !strcmp( psz_filename, "-" ) )
74         h->fh = stdin;
75     else
76         h->fh = fopen( psz_filename, "rb" );
77     if( h->fh == NULL )
78         return -1;
79
80     *p_handle = (hnd_t)h;
81     return 0;
82 }
83
84 int get_frame_total_yuv( hnd_t handle )
85 {
86     yuv_input_t *h = handle;
87     int i_frame_total = 0;
88
89     if( !fseek( h->fh, 0, SEEK_END ) )
90     {
91         uint64_t i_size = ftell( h->fh );
92         fseek( h->fh, 0, SEEK_SET );
93         i_frame_total = (int)(i_size / ( h->width * h->height * 3 / 2 ));
94     }
95
96     return i_frame_total;
97 }
98
99 int read_frame_yuv( x264_picture_t *p_pic, hnd_t handle, int i_frame )
100 {
101     yuv_input_t *h = handle;
102
103     if( i_frame != h->next_frame )
104         if( fseek( h->fh, (uint64_t)i_frame * h->width * h->height * 3 / 2, SEEK_SET ) )
105             return -1;
106
107     if( fread( p_pic->img.plane[0], 1, h->width * h->height, h->fh ) <= 0
108      || fread( p_pic->img.plane[1], 1, h->width * h->height / 4, h->fh ) <= 0
109      || fread( p_pic->img.plane[2], 1, h->width * h->height / 4, h->fh ) <= 0 )
110         return -1;
111
112     h->next_frame = i_frame+1;
113
114     return 0;
115 }
116
117 int close_file_yuv(hnd_t handle)
118 {
119     yuv_input_t *h = handle;
120     if( !h || !h->fh )
121         return 0;
122     fclose( h->fh );
123     free( h );
124     return 0;
125 }
126
127 /* YUV4MPEG2 raw 420 yuv file operation */
128 typedef struct
129 {
130     FILE *fh;
131     int width, height;
132     int next_frame;
133     int seq_header_len, frame_header_len;
134     int frame_size;
135 } y4m_input_t;
136
137 #define Y4M_MAGIC "YUV4MPEG2"
138 #define MAX_YUV4_HEADER 80
139 #define Y4M_FRAME_MAGIC "FRAME"
140 #define MAX_FRAME_HEADER 80
141
142 int open_file_y4m( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
143 {
144     int  i, n, d;
145     char header[MAX_YUV4_HEADER+10];
146     char *tokstart, *tokend, *header_end;
147     y4m_input_t *h = malloc( sizeof(y4m_input_t) );
148     if( !h )
149         return -1;
150
151     h->next_frame = 0;
152
153     if( !strcmp( psz_filename, "-" ) )
154         h->fh = stdin;
155     else
156         h->fh = fopen(psz_filename, "rb");
157     if( h->fh == NULL )
158         return -1;
159
160     h->frame_header_len = strlen(Y4M_FRAME_MAGIC)+1;
161
162     /* Read header */
163     for( i = 0; i < MAX_YUV4_HEADER; i++ )
164     {
165         header[i] = fgetc(h->fh);
166         if( header[i] == '\n' )
167         {
168             /* Add a space after last option. Makes parsing "444" vs
169                "444alpha" easier. */
170             header[i+1] = 0x20;
171             header[i+2] = 0;
172             break;
173         }
174     }
175     if( i == MAX_YUV4_HEADER || strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC)) )
176         return -1;
177
178     /* Scan properties */
179     header_end = &header[i+1]; /* Include space */
180     h->seq_header_len = i+1;
181     for( tokstart = &header[strlen(Y4M_MAGIC)+1]; tokstart < header_end; tokstart++ )
182     {
183         if( *tokstart == 0x20 )
184             continue;
185         switch(*tokstart++)
186         {
187             case 'W': /* Width. Required. */
188                 h->width = p_param->i_width = strtol( tokstart, &tokend, 10 );
189                 tokstart=tokend;
190                 break;
191             case 'H': /* Height. Required. */
192                 h->height = p_param->i_height = strtol( tokstart, &tokend, 10 );
193                 tokstart=tokend;
194                 break;
195             case 'C': /* Color space */
196                 if( strncmp( "420", tokstart, 3 ) )
197                 {
198                     fprintf( stderr, "Colorspace unhandled\n" );
199                     return -1;
200                 }
201                 tokstart = strchr( tokstart, 0x20 );
202                 break;
203             case 'I': /* Interlace type */
204                 switch( *tokstart++ )
205                 {
206                     case 'p': break;
207                     case '?':
208                     case 't':
209                     case 'b':
210                     case 'm':
211                     default:
212                         fprintf( stderr, "Warning, this sequence might be interlaced\n" );
213                 }
214                 break;
215             case 'F': /* Frame rate - 0:0 if unknown */
216                 if( sscanf( tokstart, "%d:%d", &n, &d ) == 2 && n && d )
217                 {
218                     x264_reduce_fraction( &n, &d );
219                     p_param->i_fps_num = n;
220                     p_param->i_fps_den = d;
221                 }
222                 tokstart = strchr( tokstart, 0x20 );
223                 break;
224             case 'A': /* Pixel aspect - 0:0 if unknown */
225                 /* Don't override the aspect ratio if sar has been explicitly set on the commandline. */
226                 if( sscanf( tokstart, "%d:%d", &n, &d ) == 2 && n && d && !p_param->vui.i_sar_width && !p_param->vui.i_sar_height )
227                 {
228                     x264_reduce_fraction( &n, &d );
229                     p_param->vui.i_sar_width = n;
230                     p_param->vui.i_sar_height = d;
231                 }
232                 tokstart = strchr( tokstart, 0x20 );
233                 break;
234             case 'X': /* Vendor extensions */
235                 if( !strncmp( "YSCSS=", tokstart, 6 ) )
236                 {
237                     /* Older nonstandard pixel format representation */
238                     tokstart += 6;
239                     if( strncmp( "420JPEG",tokstart, 7 ) &&
240                         strncmp( "420MPEG2",tokstart, 8 ) &&
241                         strncmp( "420PALDV",tokstart, 8 ) )
242                     {
243                         fprintf( stderr, "Unsupported extended colorspace\n" );
244                         return -1;
245                     }
246                 }
247                 tokstart = strchr(tokstart, 0x20);
248                 break;
249         }
250     }
251
252     fprintf( stderr, "yuv4mpeg: %ix%i@%i/%ifps, %i:%i\n",
253              h->width, h->height, p_param->i_fps_num, p_param->i_fps_den,
254              p_param->vui.i_sar_width, p_param->vui.i_sar_height );
255
256     *p_handle = (hnd_t)h;
257     return 0;
258 }
259
260 /* Most common case: frame_header = "FRAME" */
261 int get_frame_total_y4m( hnd_t handle )
262 {
263     y4m_input_t *h             = handle;
264     int          i_frame_total = 0;
265     uint64_t     init_pos      = ftell(h->fh);
266
267     if( !fseek( h->fh, 0, SEEK_END ) )
268     {
269         uint64_t i_size = ftell( h->fh );
270         fseek( h->fh, init_pos, SEEK_SET );
271         i_frame_total = (int)((i_size - h->seq_header_len) /
272                               (3*(h->width*h->height)/2+h->frame_header_len));
273     }
274
275     return i_frame_total;
276 }
277
278 int read_frame_y4m( x264_picture_t *p_pic, hnd_t handle, int i_frame )
279 {
280     int          slen = strlen(Y4M_FRAME_MAGIC);
281     int          i    = 0;
282     char         header[16];
283     y4m_input_t *h    = handle;
284
285     if( i_frame != h->next_frame )
286     {
287         if( fseek( h->fh, (uint64_t)i_frame*(3*(h->width*h->height)/2+h->frame_header_len)
288                  + h->seq_header_len, SEEK_SET ) )
289             return -1;
290     }
291
292     /* Read frame header - without terminating '\n' */
293     if( fread( header, 1, slen, h->fh ) != slen )
294         return -1;
295
296     header[slen] = 0;
297     if( strncmp( header, Y4M_FRAME_MAGIC, slen ) )
298     {
299         fprintf( stderr, "Bad header magic (%"PRIx32" <=> %s)\n",
300                 *((uint32_t*)header), header );
301         return -1;
302     }
303
304     /* Skip most of it */
305     while( i<MAX_FRAME_HEADER && fgetc(h->fh) != '\n' )
306         i++;
307     if( i == MAX_FRAME_HEADER )
308     {
309         fprintf( stderr, "Bad frame header!\n" );
310         return -1;
311     }
312     h->frame_header_len = i+slen+1;
313
314     if( fread( p_pic->img.plane[0], 1, h->width*h->height, h->fh ) <= 0
315      || fread( p_pic->img.plane[1], 1, h->width * h->height / 4, h->fh ) <= 0
316      || fread( p_pic->img.plane[2], 1, h->width * h->height / 4, h->fh ) <= 0)
317         return -1;
318
319     h->next_frame = i_frame+1;
320
321     return 0;
322 }
323
324 int close_file_y4m(hnd_t handle)
325 {
326     y4m_input_t *h = handle;
327     if( !h || !h->fh )
328         return 0;
329     fclose( h->fh );
330     free( h );
331     return 0;
332 }
333
334 /* avs/avi input file support under cygwin */
335
336 #ifdef AVIS_INPUT
337 typedef struct
338 {
339     PAVISTREAM p_avi;
340     int width, height;
341 } avis_input_t;
342
343 int open_file_avis( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
344 {
345     avis_input_t *h = malloc( sizeof(avis_input_t) );
346     if( !h )
347         return -1;
348     AVISTREAMINFO info;
349     int i;
350
351     *p_handle = (hnd_t)h;
352
353     AVIFileInit();
354     if( AVIStreamOpenFromFile( &h->p_avi, psz_filename, streamtypeVIDEO, 0, OF_READ, NULL ) )
355     {
356         AVIFileExit();
357         return -1;
358     }
359
360     if( AVIStreamInfo( h->p_avi, &info, sizeof(AVISTREAMINFO) ) )
361     {
362         AVIStreamRelease(h->p_avi);
363         AVIFileExit();
364         return -1;
365     }
366
367     // check input format
368     if( info.fccHandler != MAKEFOURCC('Y', 'V', '1', '2') )
369     {
370         fprintf( stderr, "avis [error]: unsupported input format (%c%c%c%c)\n",
371             (char)(info.fccHandler & 0xff), (char)((info.fccHandler >> 8) & 0xff),
372             (char)((info.fccHandler >> 16) & 0xff), (char)((info.fccHandler >> 24)) );
373
374         AVIStreamRelease( h->p_avi );
375         AVIFileExit();
376
377         return -1;
378     }
379
380     h->width =
381     p_param->i_width = info.rcFrame.right - info.rcFrame.left;
382     h->height =
383     p_param->i_height = info.rcFrame.bottom - info.rcFrame.top;
384     i = gcd(info.dwRate, info.dwScale);
385     p_param->i_fps_den = info.dwScale / i;
386     p_param->i_fps_num = info.dwRate / i;
387
388     fprintf( stderr, "avis [info]: %dx%d @ %.2f fps (%d frames)\n",
389              p_param->i_width, p_param->i_height,
390              (double)p_param->i_fps_num / (double)p_param->i_fps_den,
391              (int)info.dwLength );
392
393     return 0;
394 }
395
396 int get_frame_total_avis( hnd_t handle )
397 {
398     avis_input_t *h = handle;
399     AVISTREAMINFO info;
400
401     if( AVIStreamInfo( h->p_avi, &info, sizeof(AVISTREAMINFO) ) )
402         return -1;
403
404     return info.dwLength;
405 }
406
407 int read_frame_avis( x264_picture_t *p_pic, hnd_t handle, int i_frame )
408 {
409     avis_input_t *h = handle;
410
411     p_pic->img.i_csp = X264_CSP_YV12;
412
413     if( AVIStreamRead( h->p_avi, i_frame, 1, p_pic->img.plane[0], h->width * h->height * 3 / 2, NULL, NULL ) )
414         return -1;
415
416     return 0;
417 }
418
419 int close_file_avis( hnd_t handle )
420 {
421     avis_input_t *h = handle;
422     AVIStreamRelease( h->p_avi );
423     AVIFileExit();
424     free( h );
425     return 0;
426 }
427 #endif
428
429
430 #ifdef HAVE_PTHREAD
431 typedef struct
432 {
433     int (*p_read_frame)( x264_picture_t *p_pic, hnd_t handle, int i_frame );
434     int (*p_close_infile)( hnd_t handle );
435     hnd_t p_handle;
436     x264_picture_t pic;
437     x264_pthread_t tid;
438     int next_frame;
439     int frame_total;
440     int in_progress;
441     struct thread_input_arg_t *next_args;
442 } thread_input_t;
443
444 typedef struct thread_input_arg_t
445 {
446     thread_input_t *h;
447     x264_picture_t *pic;
448     int i_frame;
449     int status;
450 } thread_input_arg_t;
451
452 int open_file_thread( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
453 {
454     thread_input_t *h = malloc( sizeof(thread_input_t) );
455     if( !h || x264_picture_alloc( &h->pic, X264_CSP_I420, p_param->i_width, p_param->i_height ) < 0 )
456     {
457         fprintf( stderr, "x264 [error]: malloc failed\n" );
458         return -1;
459     }
460     h->p_read_frame = p_read_frame;
461     h->p_close_infile = p_close_infile;
462     h->p_handle = *p_handle;
463     h->in_progress = 0;
464     h->next_frame = -1;
465     h->next_args = malloc(sizeof(thread_input_arg_t));
466     if( !h->next_args )
467         return -1;
468     h->next_args->h = h;
469     h->next_args->status = 0;
470     h->frame_total = p_get_frame_total( h->p_handle );
471
472     *p_handle = (hnd_t)h;
473     return 0;
474 }
475
476 int get_frame_total_thread( hnd_t handle )
477 {
478     thread_input_t *h = handle;
479     return h->frame_total;
480 }
481
482 static void read_frame_thread_int( thread_input_arg_t *i )
483 {
484     i->status = i->h->p_read_frame( i->pic, i->h->p_handle, i->i_frame );
485 }
486
487 int read_frame_thread( x264_picture_t *p_pic, hnd_t handle, int i_frame )
488 {
489     thread_input_t *h = handle;
490     int ret = 0;
491
492     if( h->next_frame >= 0 )
493     {
494         x264_pthread_join( h->tid, NULL );
495         ret |= h->next_args->status;
496         h->in_progress = 0;
497     }
498
499     if( h->next_frame == i_frame )
500     {
501         XCHG( x264_picture_t, *p_pic, h->pic );
502     }
503     else
504     {
505         ret |= h->p_read_frame( p_pic, h->p_handle, i_frame );
506     }
507
508     if( !h->frame_total || i_frame+1 < h->frame_total )
509     {
510         h->next_frame =
511         h->next_args->i_frame = i_frame+1;
512         h->next_args->pic = &h->pic;
513         if( x264_pthread_create( &h->tid, NULL, (void*)read_frame_thread_int, h->next_args ) )
514             return -1;
515         h->in_progress = 1;
516     }
517     else
518         h->next_frame = -1;
519
520     return ret;
521 }
522
523 int close_file_thread( hnd_t handle )
524 {
525     thread_input_t *h = handle;
526     if( h->in_progress )
527         x264_pthread_join( h->tid, NULL );
528     h->p_close_infile( h->p_handle );
529     x264_picture_clean( &h->pic );
530     free( h->next_args );
531     free( h );
532     return 0;
533 }
534 #endif
535
536
537 int open_file_bsf( char *psz_filename, hnd_t *p_handle )
538 {
539     if( !(*p_handle = fopen(psz_filename, "w+b")) )
540         return -1;
541
542     return 0;
543 }
544
545 int set_param_bsf( hnd_t handle, x264_param_t *p_param )
546 {
547     return 0;
548 }
549
550 int write_nalu_bsf( hnd_t handle, uint8_t *p_nalu, int i_size )
551 {
552     if( fwrite( p_nalu, i_size, 1, (FILE*)handle ) > 0 )
553         return i_size;
554     return -1;
555 }
556
557 int set_eop_bsf( hnd_t handle,  x264_picture_t *p_picture )
558 {
559     return 0;
560 }
561
562 int close_file_bsf( hnd_t handle )
563 {
564     if( !handle || handle == stdout )
565         return 0;
566
567     return fclose( (FILE*)handle );
568 }
569
570 /* -- mp4 muxing support ------------------------------------------------- */
571 #ifdef MP4_OUTPUT
572
573 typedef struct
574 {
575     GF_ISOFile *p_file;
576     GF_AVCConfig *p_config;
577     GF_ISOSample *p_sample;
578     int i_track;
579     uint32_t i_descidx;
580     int i_time_inc;
581     int i_time_res;
582     int i_numframe;
583     int i_init_delay;
584     uint8_t b_sps;
585     uint8_t b_pps;
586 } mp4_t;
587
588
589 static void recompute_bitrate_mp4(GF_ISOFile *p_file, int i_track)
590 {
591     u32 i, count, di, timescale, time_wnd, rate;
592     u64 offset;
593     Double br;
594     GF_ESD *esd;
595
596     esd = gf_isom_get_esd( p_file, i_track, 1 );
597     if( !esd )
598         return;
599
600     esd->decoderConfig->avgBitrate = 0;
601     esd->decoderConfig->maxBitrate = 0;
602     rate = time_wnd = 0;
603
604     timescale = gf_isom_get_media_timescale( p_file, i_track );
605     count = gf_isom_get_sample_count( p_file, i_track );
606     for( i = 0; i < count; i++ )
607     {
608         GF_ISOSample *samp = gf_isom_get_sample_info( p_file, i_track, i+1, &di, &offset );
609
610         if( samp->dataLength>esd->decoderConfig->bufferSizeDB )
611             esd->decoderConfig->bufferSizeDB = samp->dataLength;
612
613         if( esd->decoderConfig->bufferSizeDB < samp->dataLength )
614             esd->decoderConfig->bufferSizeDB = samp->dataLength;
615
616         esd->decoderConfig->avgBitrate += samp->dataLength;
617         rate += samp->dataLength;
618         if( samp->DTS > time_wnd + timescale )
619         {
620             if( rate > esd->decoderConfig->maxBitrate )
621                 esd->decoderConfig->maxBitrate = rate;
622             time_wnd = samp->DTS;
623             rate = 0;
624         }
625
626         gf_isom_sample_del( &samp );
627     }
628
629     br = (Double)(s64)gf_isom_get_media_duration( p_file, i_track );
630     br /= timescale;
631     esd->decoderConfig->avgBitrate = (u32)(esd->decoderConfig->avgBitrate / br);
632     /*move to bps*/
633     esd->decoderConfig->avgBitrate *= 8;
634     esd->decoderConfig->maxBitrate *= 8;
635
636     gf_isom_change_mpeg4_description( p_file, i_track, 1, esd );
637     gf_odf_desc_del( (GF_Descriptor*)esd );
638 }
639
640
641 int close_file_mp4( hnd_t handle )
642 {
643     mp4_t *p_mp4 = (mp4_t*)handle;
644
645     if( !p_mp4 )
646         return 0;
647
648     if( p_mp4->p_config )
649         gf_odf_avc_cfg_del( p_mp4->p_config );
650
651     if( p_mp4->p_sample )
652     {
653         if( p_mp4->p_sample->data )
654             free( p_mp4->p_sample->data );
655
656         gf_isom_sample_del( &p_mp4->p_sample );
657     }
658
659     if( p_mp4->p_file )
660     {
661         recompute_bitrate_mp4( p_mp4->p_file, p_mp4->i_track );
662         gf_isom_set_pl_indication( p_mp4->p_file, GF_ISOM_PL_VISUAL, 0x15 );
663         gf_isom_set_storage_mode( p_mp4->p_file, GF_ISOM_STORE_FLAT );
664         gf_isom_close( p_mp4->p_file );
665     }
666
667     free( p_mp4 );
668
669     return 0;
670 }
671
672 int open_file_mp4( char *psz_filename, hnd_t *p_handle )
673 {
674     mp4_t *p_mp4;
675
676     *p_handle = NULL;
677
678     if( !(p_mp4 = malloc(sizeof(mp4_t))) )
679         return -1;
680
681     memset( p_mp4, 0, sizeof(mp4_t) );
682     p_mp4->p_file = gf_isom_open( psz_filename, GF_ISOM_OPEN_WRITE, NULL );
683
684     if( !(p_mp4->p_sample = gf_isom_sample_new()) )
685     {
686         close_file_mp4( p_mp4 );
687         return -1;
688     }
689
690     gf_isom_set_brand_info( p_mp4->p_file, GF_ISOM_BRAND_AVC1, 0 );
691
692     *p_handle = p_mp4;
693
694     return 0;
695 }
696
697
698 int set_param_mp4( hnd_t handle, x264_param_t *p_param )
699 {
700     mp4_t *p_mp4 = (mp4_t*)handle;
701
702     p_mp4->i_track = gf_isom_new_track( p_mp4->p_file, 0, GF_ISOM_MEDIA_VISUAL,
703                                         p_param->i_fps_num );
704
705     p_mp4->p_config = gf_odf_avc_cfg_new();
706     gf_isom_avc_config_new( p_mp4->p_file, p_mp4->i_track, p_mp4->p_config,
707                             NULL, NULL, &p_mp4->i_descidx );
708
709     gf_isom_set_track_enabled( p_mp4->p_file, p_mp4->i_track, 1 );
710
711     gf_isom_set_visual_info( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx,
712                              p_param->i_width, p_param->i_height );
713
714     if( p_param->vui.i_sar_width && p_param->vui.i_sar_height )
715     {
716         uint64_t dw = p_param->i_width << 16;
717         uint64_t dh = p_param->i_height << 16;
718         double sar = (double)p_param->vui.i_sar_width / p_param->vui.i_sar_height;
719         if( sar > 1.0 )
720             dw *= sar ;
721         else
722             dh /= sar;
723         gf_isom_set_track_layout_info( p_mp4->p_file, p_mp4->i_track, dw, dh, 0, 0, 0 );
724     }
725
726     p_mp4->p_sample->data = malloc( p_param->i_width * p_param->i_height * 3 / 2 );
727     if( !p_mp4->p_sample->data )
728         return -1;
729
730     p_mp4->i_time_res = p_param->i_fps_num;
731     p_mp4->i_time_inc = p_param->i_fps_den;
732     p_mp4->i_init_delay = p_param->i_bframe ? (p_param->b_bframe_pyramid ? 2 : 1) : 0;
733     p_mp4->i_init_delay *= p_mp4->i_time_inc;
734     fprintf( stderr, "mp4 [info]: initial delay %d (scale %d)\n",
735              p_mp4->i_init_delay, p_mp4->i_time_res );
736
737     return 0;
738 }
739
740
741 int write_nalu_mp4( hnd_t handle, uint8_t *p_nalu, int i_size )
742 {
743     mp4_t *p_mp4 = (mp4_t*)handle;
744     GF_AVCConfigSlot *p_slot;
745     uint8_t type = p_nalu[4] & 0x1f;
746     int psize;
747
748     switch( type )
749     {
750         // sps
751         case 0x07:
752             if( !p_mp4->b_sps )
753             {
754                 p_mp4->p_config->configurationVersion = 1;
755                 p_mp4->p_config->AVCProfileIndication = p_nalu[5];
756                 p_mp4->p_config->profile_compatibility = p_nalu[6];
757                 p_mp4->p_config->AVCLevelIndication = p_nalu[7];
758                 p_slot = malloc( sizeof(GF_AVCConfigSlot) );
759                 if( !p_slot )
760                     return -1;
761                 p_slot->size = i_size - 4;
762                 p_slot->data = malloc( p_slot->size );
763                 if( !p_slot->data )
764                     return -1;
765                 memcpy( p_slot->data, p_nalu + 4, i_size - 4 );
766                 gf_list_add( p_mp4->p_config->sequenceParameterSets, p_slot );
767                 p_slot = NULL;
768                 p_mp4->b_sps = 1;
769             }
770             break;
771
772         // pps
773         case 0x08:
774             if( !p_mp4->b_pps )
775             {
776                 p_slot = malloc( sizeof(GF_AVCConfigSlot) );
777                 if( !p_slot )
778                     return -1;
779                 p_slot->size = i_size - 4;
780                 p_slot->data = malloc( p_slot->size );
781                 if( !p_slot->data )
782                     return -1;
783                 memcpy( p_slot->data, p_nalu + 4, i_size - 4 );
784                 gf_list_add( p_mp4->p_config->pictureParameterSets, p_slot );
785                 p_slot = NULL;
786                 p_mp4->b_pps = 1;
787                 if( p_mp4->b_sps )
788                     gf_isom_avc_config_update( p_mp4->p_file, p_mp4->i_track, 1, p_mp4->p_config );
789             }
790             break;
791
792         // slice, sei
793         case 0x1:
794         case 0x5:
795         case 0x6:
796             psize = i_size - 4 ;
797             memcpy( p_mp4->p_sample->data + p_mp4->p_sample->dataLength, p_nalu, i_size );
798             p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 0] = psize >> 24;
799             p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 1] = psize >> 16;
800             p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 2] = psize >>  8;
801             p_mp4->p_sample->data[p_mp4->p_sample->dataLength + 3] = psize >>  0;
802             p_mp4->p_sample->dataLength += i_size;
803             break;
804     }
805
806     return i_size;
807 }
808
809 int set_eop_mp4( hnd_t handle, x264_picture_t *p_picture )
810 {
811     mp4_t *p_mp4 = (mp4_t*)handle;
812     uint64_t dts = (uint64_t)p_mp4->i_numframe * p_mp4->i_time_inc;
813     uint64_t pts = (uint64_t)p_picture->i_pts;
814     int32_t offset = p_mp4->i_init_delay + pts - dts;
815
816     p_mp4->p_sample->IsRAP = p_picture->i_type == X264_TYPE_IDR ? 1 : 0;
817     p_mp4->p_sample->DTS = dts;
818     p_mp4->p_sample->CTS_Offset = offset;
819     gf_isom_add_sample( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx, p_mp4->p_sample );
820
821     p_mp4->p_sample->dataLength = 0;
822     p_mp4->i_numframe++;
823
824     return 0;
825 }
826
827 #endif
828
829
830 /* -- mkv muxing support ------------------------------------------------- */
831 typedef struct
832 {
833     mk_writer *w;
834
835     uint8_t *sps, *pps;
836     int sps_len, pps_len;
837
838     int width, height, d_width, d_height;
839
840     int64_t frame_duration;
841     int fps_num;
842
843     int b_header_written;
844     char b_writing_frame;
845 } mkv_t;
846
847 static int write_header_mkv( mkv_t *p_mkv )
848 {
849     int ret;
850     uint8_t *avcC;
851     int avcC_len;
852
853     if( !p_mkv->sps || !p_mkv->pps ||
854         !p_mkv->width || !p_mkv->height ||
855         !p_mkv->d_width || !p_mkv->d_height )
856         return -1;
857
858     avcC_len = 5 + 1 + 2 + p_mkv->sps_len + 1 + 2 + p_mkv->pps_len;
859     avcC = malloc( avcC_len );
860     if( !avcC )
861         return -1;
862
863     avcC[0] = 1;
864     avcC[1] = p_mkv->sps[1];
865     avcC[2] = p_mkv->sps[2];
866     avcC[3] = p_mkv->sps[3];
867     avcC[4] = 0xff; // nalu size length is four bytes
868     avcC[5] = 0xe1; // one sps
869
870     avcC[6] = p_mkv->sps_len >> 8;
871     avcC[7] = p_mkv->sps_len;
872
873     memcpy( avcC+8, p_mkv->sps, p_mkv->sps_len );
874
875     avcC[8+p_mkv->sps_len] = 1; // one pps
876     avcC[9+p_mkv->sps_len] = p_mkv->pps_len >> 8;
877     avcC[10+p_mkv->sps_len] = p_mkv->pps_len;
878
879     memcpy( avcC+11+p_mkv->sps_len, p_mkv->pps, p_mkv->pps_len );
880
881     ret = mk_writeHeader( p_mkv->w, "x264", "V_MPEG4/ISO/AVC",
882                           avcC, avcC_len, p_mkv->frame_duration, 50000,
883                           p_mkv->width, p_mkv->height,
884                           p_mkv->d_width, p_mkv->d_height );
885
886     free( avcC );
887
888     p_mkv->b_header_written = 1;
889
890     return ret;
891 }
892
893 int open_file_mkv( char *psz_filename, hnd_t *p_handle )
894 {
895     mkv_t *p_mkv;
896
897     *p_handle = NULL;
898
899     p_mkv  = malloc( sizeof(*p_mkv) );
900     if( !p_mkv )
901         return -1;
902
903     memset( p_mkv, 0, sizeof(*p_mkv) );
904
905     p_mkv->w = mk_create_writer( psz_filename );
906     if( !p_mkv->w )
907     {
908         free( p_mkv );
909         return -1;
910     }
911
912     *p_handle = p_mkv;
913
914     return 0;
915 }
916
917 int set_param_mkv( hnd_t handle, x264_param_t *p_param )
918 {
919     mkv_t   *p_mkv = handle;
920     int64_t dw, dh;
921
922     if( p_param->i_fps_num > 0 )
923     {
924         p_mkv->frame_duration = (int64_t)p_param->i_fps_den *
925                                 (int64_t)1000000000 / p_param->i_fps_num;
926         p_mkv->fps_num = p_param->i_fps_num;
927     }
928     else
929     {
930         p_mkv->frame_duration = 0;
931         p_mkv->fps_num = 1;
932     }
933
934     p_mkv->width = p_param->i_width;
935     p_mkv->height = p_param->i_height;
936
937     if( p_param->vui.i_sar_width && p_param->vui.i_sar_height )
938     {
939         dw = (int64_t)p_param->i_width  * p_param->vui.i_sar_width;
940         dh = (int64_t)p_param->i_height * p_param->vui.i_sar_height;
941     }
942     else
943     {
944         dw = p_param->i_width;
945         dh = p_param->i_height;
946     }
947
948     if( dw > 0 && dh > 0 )
949     {
950         int64_t x = gcd( dw, dh );
951         dw /= x;
952         dh /= x;
953     }
954
955     p_mkv->d_width = (int)dw;
956     p_mkv->d_height = (int)dh;
957
958     return 0;
959 }
960
961 int write_nalu_mkv( hnd_t handle, uint8_t *p_nalu, int i_size )
962 {
963     mkv_t *p_mkv = handle;
964     uint8_t type = p_nalu[4] & 0x1f;
965     uint8_t dsize[4];
966     int psize;
967
968     switch( type )
969     {
970         // sps
971         case 0x07:
972             if( !p_mkv->sps )
973             {
974                 p_mkv->sps = malloc( i_size - 4 );
975                 if( !p_mkv->sps )
976                     return -1;
977                 p_mkv->sps_len = i_size - 4;
978                 memcpy( p_mkv->sps, p_nalu + 4, i_size - 4 );
979             }
980             break;
981
982         // pps
983         case 0x08:
984             if( !p_mkv->pps )
985             {
986                 p_mkv->pps = malloc( i_size - 4 );
987                 if( !p_mkv->pps )
988                     return -1;
989                 p_mkv->pps_len = i_size - 4;
990                 memcpy( p_mkv->pps, p_nalu + 4, i_size - 4 );
991             }
992             break;
993
994         // slice, sei
995         case 0x1:
996         case 0x5:
997         case 0x6:
998             if( !p_mkv->b_writing_frame )
999             {
1000                 if( mk_start_frame( p_mkv->w ) < 0 )
1001                     return -1;
1002                 p_mkv->b_writing_frame = 1;
1003             }
1004             psize = i_size - 4 ;
1005             dsize[0] = psize >> 24;
1006             dsize[1] = psize >> 16;
1007             dsize[2] = psize >> 8;
1008             dsize[3] = psize;
1009             if( mk_add_frame_data( p_mkv->w, dsize, 4 ) < 0 ||
1010                 mk_add_frame_data( p_mkv->w, p_nalu + 4, i_size - 4 ) < 0 )
1011                 return -1;
1012             break;
1013
1014         default:
1015             break;
1016     }
1017
1018     if( !p_mkv->b_header_written && p_mkv->pps && p_mkv->sps &&
1019         write_header_mkv( p_mkv ) < 0 )
1020         return -1;
1021
1022     return i_size;
1023 }
1024
1025 int set_eop_mkv( hnd_t handle, x264_picture_t *p_picture )
1026 {
1027     mkv_t *p_mkv = handle;
1028     int64_t i_stamp = (int64_t)(p_picture->i_pts * 1e9 / p_mkv->fps_num);
1029
1030     p_mkv->b_writing_frame = 0;
1031
1032     return mk_set_frame_flags( p_mkv->w, i_stamp, p_picture->i_type == X264_TYPE_IDR );
1033 }
1034
1035 int close_file_mkv( hnd_t handle )
1036 {
1037     mkv_t *p_mkv = handle;
1038     int   ret;
1039
1040     if( p_mkv->sps )
1041         free( p_mkv->sps );
1042     if( p_mkv->pps )
1043         free( p_mkv->pps );
1044
1045     ret = mk_close( p_mkv->w );
1046
1047     free( p_mkv );
1048
1049     return ret;
1050 }
1051