[demux/avi] Enable dirac support (Set PTS on first output block)
[vlc/davidf-public.git] / modules / mux / mp4.c
blobab8526f98a1113f31d5b3ac141e6727b2ca0b89f
1 /*****************************************************************************
2 * mp4.c: mp4/mov muxer
3 *****************************************************************************
4 * Copyright (C) 2001, 2002, 2003, 2006 the VideoLAN team
5 * $Id$
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Gildas Bazin <gbazin at videolan dot org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_sout.h>
36 #include <vlc_block.h>
38 #ifdef HAVE_TIME_H
39 #include <time.h>
40 #endif
42 #include <vlc_iso_lang.h>
43 #include "vlc_meta.h"
45 /*****************************************************************************
46 * Module descriptor
47 *****************************************************************************/
48 #define FASTSTART_TEXT N_("Create \"Fast Start\" files")
49 #define FASTSTART_LONGTEXT N_( \
50 "Create \"Fast Start\" files. " \
51 "\"Fast Start\" files are optimized for downloads and allow the user " \
52 "to start previewing the file while it is downloading.")
54 static int Open ( vlc_object_t * );
55 static void Close ( vlc_object_t * );
57 #define SOUT_CFG_PREFIX "sout-mp4-"
59 vlc_module_begin();
60 set_description( N_("MP4/MOV muxer") );
61 set_category( CAT_SOUT );
62 set_subcategory( SUBCAT_SOUT_MUX );
63 set_shortname( "MP4" );
65 add_bool( SOUT_CFG_PREFIX "faststart", 1, NULL,
66 FASTSTART_TEXT, FASTSTART_LONGTEXT,
67 true );
68 set_capability( "sout mux", 5 );
69 add_shortcut( "mp4" );
70 add_shortcut( "mov" );
71 add_shortcut( "3gp" );
72 set_callbacks( Open, Close );
73 vlc_module_end();
75 /*****************************************************************************
76 * Exported prototypes
77 *****************************************************************************/
78 static const char *const ppsz_sout_options[] = {
79 "faststart", NULL
82 static int Control( sout_mux_t *, int, va_list );
83 static int AddStream( sout_mux_t *, sout_input_t * );
84 static int DelStream( sout_mux_t *, sout_input_t * );
85 static int Mux ( sout_mux_t * );
87 /*****************************************************************************
88 * Local prototypes
89 *****************************************************************************/
90 typedef struct
92 uint64_t i_pos;
93 int i_size;
95 mtime_t i_pts_dts;
96 mtime_t i_length;
97 unsigned int i_flags;
99 } mp4_entry_t;
101 typedef struct
103 es_format_t fmt;
104 int i_track_id;
106 /* index */
107 unsigned int i_entry_count;
108 unsigned int i_entry_max;
109 mp4_entry_t *entry;
110 int64_t i_length_neg;
112 /* stats */
113 int64_t i_dts_start;
114 int64_t i_duration;
116 /* for later stco fix-up (fast start files) */
117 uint64_t i_stco_pos;
118 bool b_stco64;
120 /* for spu */
121 int64_t i_last_dts;
123 } mp4_stream_t;
125 struct sout_mux_sys_t
127 bool b_mov;
128 bool b_3gp;
129 bool b_64_ext;
130 bool b_fast_start;
132 uint64_t i_mdat_pos;
133 uint64_t i_pos;
135 int64_t i_dts_start;
137 int i_nb_streams;
138 mp4_stream_t **pp_streams;
141 typedef struct bo_t
143 bool b_grow;
145 int i_buffer_size;
146 int i_buffer;
147 uint8_t *p_buffer;
149 } bo_t;
151 static void bo_init ( bo_t *, int , uint8_t *, bool );
152 static void bo_add_8 ( bo_t *, uint8_t );
153 static void bo_add_16be ( bo_t *, uint16_t );
154 static void bo_add_24be ( bo_t *, uint32_t );
155 static void bo_add_32be ( bo_t *, uint32_t );
156 static void bo_add_64be ( bo_t *, uint64_t );
157 static void bo_add_fourcc(bo_t *, const char * );
158 static void bo_add_bo ( bo_t *, bo_t * );
159 static void bo_add_mem ( bo_t *, int , uint8_t * );
160 static void bo_add_descr( bo_t *, uint8_t , uint32_t );
162 static void bo_fix_32be ( bo_t *, int , uint32_t );
164 static bo_t *box_new ( const char *fcc );
165 static bo_t *box_full_new( const char *fcc, uint8_t v, uint32_t f );
166 static void box_fix ( bo_t *box );
167 static void box_free ( bo_t *box );
168 static void box_gather ( bo_t *box, bo_t *box2 );
170 static void box_send( sout_mux_t *p_mux, bo_t *box );
172 static block_t *bo_to_sout( sout_instance_t *p_sout, bo_t *box );
174 static bo_t *GetMoovBox( sout_mux_t *p_mux );
176 static block_t *ConvertSUBT( block_t *);
177 static block_t *ConvertAVC1( block_t * );
179 /*****************************************************************************
180 * Open:
181 *****************************************************************************/
182 static int Open( vlc_object_t *p_this )
184 sout_mux_t *p_mux = (sout_mux_t*)p_this;
185 sout_mux_sys_t *p_sys;
186 bo_t *box;
188 msg_Dbg( p_mux, "Mp4 muxer opened" );
189 config_ChainParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
191 p_mux->pf_control = Control;
192 p_mux->pf_addstream = AddStream;
193 p_mux->pf_delstream = DelStream;
194 p_mux->pf_mux = Mux;
195 p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
196 if( !p_sys )
197 return VLC_ENOMEM;
198 p_sys->i_pos = 0;
199 p_sys->i_nb_streams = 0;
200 p_sys->pp_streams = NULL;
201 p_sys->i_mdat_pos = 0;
202 p_sys->b_mov = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mov" );
203 p_sys->b_3gp = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "3gp" );
204 p_sys->i_dts_start = 0;
207 if( !p_sys->b_mov )
209 /* Now add ftyp header */
210 box = box_new( "ftyp" );
211 if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
212 else bo_add_fourcc( box, "isom" );
213 bo_add_32be ( box, 0 );
214 if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
215 else bo_add_fourcc( box, "mp41" );
216 box_fix( box );
218 p_sys->i_pos += box->i_buffer;
219 p_sys->i_mdat_pos = p_sys->i_pos;
221 box_send( p_mux, box );
224 /* FIXME FIXME
225 * Quicktime actually doesn't like the 64 bits extensions !!! */
226 p_sys->b_64_ext = false;
228 /* Now add mdat header */
229 box = box_new( "mdat" );
230 bo_add_64be ( box, 0 ); // enough to store an extended size
232 p_sys->i_pos += box->i_buffer;
234 box_send( p_mux, box );
236 return VLC_SUCCESS;
239 /*****************************************************************************
240 * Close:
241 *****************************************************************************/
242 static void Close( vlc_object_t * p_this )
244 sout_mux_t *p_mux = (sout_mux_t*)p_this;
245 sout_mux_sys_t *p_sys = p_mux->p_sys;
246 block_t *p_hdr;
247 bo_t bo, *moov;
248 vlc_value_t val;
250 int i_trak;
251 uint64_t i_moov_pos;
253 msg_Dbg( p_mux, "Close" );
255 /* Update mdat size */
256 bo_init( &bo, 0, NULL, true );
257 if( p_sys->i_pos - p_sys->i_mdat_pos >= (((uint64_t)1)<<32) )
259 /* Extended size */
260 bo_add_32be ( &bo, 1 );
261 bo_add_fourcc( &bo, "mdat" );
262 bo_add_64be ( &bo, p_sys->i_pos - p_sys->i_mdat_pos );
264 else
266 bo_add_32be ( &bo, 8 );
267 bo_add_fourcc( &bo, "wide" );
268 bo_add_32be ( &bo, p_sys->i_pos - p_sys->i_mdat_pos - 8 );
269 bo_add_fourcc( &bo, "mdat" );
271 p_hdr = bo_to_sout( p_mux->p_sout, &bo );
272 free( bo.p_buffer );
274 sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos );
275 sout_AccessOutWrite( p_mux->p_access, p_hdr );
277 /* Create MOOV header */
278 i_moov_pos = p_sys->i_pos;
279 moov = GetMoovBox( p_mux );
281 /* Check we need to create "fast start" files */
282 var_Get( p_this, SOUT_CFG_PREFIX "faststart", &val );
283 p_sys->b_fast_start = val.b_bool;
284 while( p_sys->b_fast_start )
286 /* Move data to the end of the file so we can fit the moov header
287 * at the start */
288 block_t *p_buf;
289 int64_t i_chunk, i_size = p_sys->i_pos - p_sys->i_mdat_pos;
290 int i_moov_size = moov->i_buffer;
292 while( i_size > 0 )
294 i_chunk = __MIN( 32768, i_size );
295 p_buf = block_New( p_mux, i_chunk );
296 sout_AccessOutSeek( p_mux->p_access,
297 p_sys->i_mdat_pos + i_size - i_chunk );
298 if( sout_AccessOutRead( p_mux->p_access, p_buf ) < i_chunk )
300 msg_Warn( p_this, "read() not supported by access output, "
301 "won't create a fast start file" );
302 p_sys->b_fast_start = false;
303 block_Release( p_buf );
304 break;
306 sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos + i_size +
307 i_moov_size - i_chunk );
308 sout_AccessOutWrite( p_mux->p_access, p_buf );
309 i_size -= i_chunk;
312 if( !p_sys->b_fast_start ) break;
314 /* Fix-up samples to chunks table in MOOV header */
315 for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
317 mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
318 unsigned int i;
319 int i_chunk;
321 moov->i_buffer = p_stream->i_stco_pos;
322 for( i_chunk = 0, i = 0; i < p_stream->i_entry_count; i_chunk++ )
324 if( p_stream->b_stco64 )
325 bo_add_64be( moov, p_stream->entry[i].i_pos + i_moov_size);
326 else
327 bo_add_32be( moov, p_stream->entry[i].i_pos + i_moov_size);
329 while( i < p_stream->i_entry_count )
331 if( i + 1 < p_stream->i_entry_count &&
332 p_stream->entry[i].i_pos + p_stream->entry[i].i_size
333 != p_stream->entry[i + 1].i_pos )
335 i++;
336 break;
339 i++;
344 moov->i_buffer = i_moov_size;
345 i_moov_pos = p_sys->i_mdat_pos;
346 p_sys->b_fast_start = false;
349 /* Write MOOV header */
350 sout_AccessOutSeek( p_mux->p_access, i_moov_pos );
351 box_send( p_mux, moov );
353 /* Clean-up */
354 for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
356 mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
358 es_format_Clean( &p_stream->fmt );
359 free( p_stream->entry );
360 free( p_stream );
362 if( p_sys->i_nb_streams ) free( p_sys->pp_streams );
363 free( p_sys );
366 /*****************************************************************************
367 * Control:
368 *****************************************************************************/
369 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
371 VLC_UNUSED(p_mux);
372 bool *pb_bool;
374 switch( i_query )
376 case MUX_CAN_ADD_STREAM_WHILE_MUXING:
377 pb_bool = (bool*)va_arg( args, bool * );
378 *pb_bool = false;
379 return VLC_SUCCESS;
381 case MUX_GET_ADD_STREAM_WAIT:
382 pb_bool = (bool*)va_arg( args, bool * );
383 *pb_bool = true;
384 return VLC_SUCCESS;
386 case MUX_GET_MIME: /* Not needed, as not streamable */
387 default:
388 return VLC_EGENERIC;
392 /*****************************************************************************
393 * AddStream:
394 *****************************************************************************/
395 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
397 sout_mux_sys_t *p_sys = p_mux->p_sys;
398 mp4_stream_t *p_stream;
400 switch( p_input->p_fmt->i_codec )
402 case VLC_FOURCC( 'm', 'p', '4', 'a' ):
403 case VLC_FOURCC( 'm', 'p', '4', 'v' ):
404 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
405 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
406 case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
407 case VLC_FOURCC( 'm', 'j', 'p', 'b' ):
408 case VLC_FOURCC( 'S', 'V', 'Q', '1' ):
409 case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
410 case VLC_FOURCC( 'H', '2', '6', '3' ):
411 case VLC_FOURCC( 'h', '2', '6', '4' ):
412 case VLC_FOURCC( 's', 'a', 'm', 'r' ):
413 case VLC_FOURCC( 's', 'a', 'w', 'b' ):
414 case VLC_FOURCC( 'Y', 'V', '1', '2' ):
415 case VLC_FOURCC( 'Y', 'U', 'Y', '2' ):
416 break;
417 case VLC_FOURCC( 's', 'u', 'b', 't' ):
418 msg_Warn( p_mux, "subtitle track added like in .mov (even when creating .mp4)" );
419 break;
420 default:
421 msg_Err( p_mux, "unsupported codec %4.4s in mp4",
422 (char*)&p_input->p_fmt->i_codec );
423 return VLC_EGENERIC;
426 p_stream = malloc( sizeof( mp4_stream_t ) );
427 if( !p_stream )
428 return VLC_ENOMEM;
429 es_format_Copy( &p_stream->fmt, p_input->p_fmt );
430 p_stream->i_track_id = p_sys->i_nb_streams + 1;
431 p_stream->i_length_neg = 0;
432 p_stream->i_entry_count = 0;
433 p_stream->i_entry_max = 1000;
434 p_stream->entry =
435 calloc( p_stream->i_entry_max, sizeof( mp4_entry_t ) );
436 p_stream->i_dts_start = 0;
437 p_stream->i_duration = 0;
439 p_input->p_sys = p_stream;
441 msg_Dbg( p_mux, "adding input" );
443 TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, p_stream );
444 return VLC_SUCCESS;
447 /*****************************************************************************
448 * DelStream:
449 *****************************************************************************/
450 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
452 VLC_UNUSED(p_input);
453 msg_Dbg( p_mux, "removing input" );
454 return VLC_SUCCESS;
457 static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
459 mtime_t i_dts;
460 int i_stream, i;
462 for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
464 block_fifo_t *p_fifo = p_mux->pp_inputs[i]->p_fifo;
465 block_t *p_buf;
467 if( block_FifoCount( p_fifo ) <= 1 )
469 if( p_mux->pp_inputs[i]->p_fmt->i_cat != SPU_ES )
471 return -1; // wait that all fifo have at least 2 packets
473 /* For SPU, we wait only 1 packet */
474 continue;
477 p_buf = block_FifoShow( p_fifo );
478 if( i_stream < 0 || p_buf->i_dts < i_dts )
480 i_dts = p_buf->i_dts;
481 i_stream = i;
484 if( pi_stream )
486 *pi_stream = i_stream;
488 if( pi_dts )
490 *pi_dts = i_dts;
492 return i_stream;
495 /*****************************************************************************
496 * Mux:
497 *****************************************************************************/
498 static int Mux( sout_mux_t *p_mux )
500 sout_mux_sys_t *p_sys = p_mux->p_sys;
502 for( ;; )
504 sout_input_t *p_input;
505 int i_stream;
506 mp4_stream_t *p_stream;
507 block_t *p_data;
508 mtime_t i_dts;
510 if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 )
512 return( VLC_SUCCESS );
515 p_input = p_mux->pp_inputs[i_stream];
516 p_stream = (mp4_stream_t*)p_input->p_sys;
518 again:
519 p_data = block_FifoGet( p_input->p_fifo );
520 if( p_stream->fmt.i_codec == VLC_FOURCC( 'h', '2', '6', '4' ) )
522 p_data = ConvertAVC1( p_data );
524 else if( p_stream->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) )
526 p_data = ConvertSUBT( p_data );
528 if( p_data == NULL ) goto again;
530 if( p_stream->fmt.i_cat != SPU_ES )
532 /* Fix length of the sample */
533 if( block_FifoCount( p_input->p_fifo ) > 0 )
535 block_t *p_next = block_FifoShow( p_input->p_fifo );
536 int64_t i_diff = p_next->i_dts - p_data->i_dts;
538 if( i_diff < INT64_C(1000000 ) ) /* protection */
540 p_data->i_length = i_diff;
543 if( p_data->i_length <= 0 )
545 msg_Warn( p_mux, "i_length <= 0" );
546 p_stream->i_length_neg += p_data->i_length - 1;
547 p_data->i_length = 1;
549 else if( p_stream->i_length_neg < 0 )
551 int64_t i_recover = __MIN( p_data->i_length / 4, - p_stream->i_length_neg );
553 p_data->i_length -= i_recover;
554 p_stream->i_length_neg += i_recover;
558 /* Save starting time */
559 if( p_stream->i_entry_count == 0 )
561 p_stream->i_dts_start = p_data->i_dts;
563 /* Update global dts_start */
564 if( p_sys->i_dts_start <= 0 ||
565 p_stream->i_dts_start < p_sys->i_dts_start )
567 p_sys->i_dts_start = p_stream->i_dts_start;
571 if( p_stream->fmt.i_cat == SPU_ES && p_stream->i_entry_count > 0 )
573 int64_t i_length = p_data->i_dts - p_stream->i_last_dts;
575 if( i_length <= 0 )
577 /* FIXME handle this broken case */
578 i_length = 1;
581 /* Fix last entry */
582 if( p_stream->entry[p_stream->i_entry_count-1].i_length <= 0 )
584 p_stream->entry[p_stream->i_entry_count-1].i_length = i_length;
589 /* add index entry */
590 p_stream->entry[p_stream->i_entry_count].i_pos = p_sys->i_pos;
591 p_stream->entry[p_stream->i_entry_count].i_size = p_data->i_buffer;
592 p_stream->entry[p_stream->i_entry_count].i_pts_dts=
593 __MAX( p_data->i_pts - p_data->i_dts, 0 );
594 p_stream->entry[p_stream->i_entry_count].i_length = p_data->i_length;
595 p_stream->entry[p_stream->i_entry_count].i_flags = p_data->i_flags;
597 p_stream->i_entry_count++;
598 /* XXX: -1 to always have 2 entry for easy adding of empty SPU */
599 if( p_stream->i_entry_count >= p_stream->i_entry_max - 1 )
601 p_stream->i_entry_max += 1000;
602 p_stream->entry =
603 realloc( p_stream->entry,
604 p_stream->i_entry_max * sizeof( mp4_entry_t ) );
607 /* update */
608 p_stream->i_duration += p_data->i_length;
609 p_sys->i_pos += p_data->i_buffer;
611 /* Save the DTS */
612 p_stream->i_last_dts = p_data->i_dts;
614 /* write data */
615 sout_AccessOutWrite( p_mux->p_access, p_data );
617 if( p_stream->fmt.i_cat == SPU_ES )
619 int64_t i_length = p_stream->entry[p_stream->i_entry_count-1].i_length;
621 if( i_length != 0 )
623 /* TODO */
624 msg_Dbg( p_mux, "writing an empty sub" ) ;
626 /* Append a idx entry */
627 p_stream->entry[p_stream->i_entry_count].i_pos = p_sys->i_pos;
628 p_stream->entry[p_stream->i_entry_count].i_size = 3;
629 p_stream->entry[p_stream->i_entry_count].i_pts_dts= 0;
630 p_stream->entry[p_stream->i_entry_count].i_length = 0;
631 p_stream->entry[p_stream->i_entry_count].i_flags = 0;
633 /* XXX: No need to grow the entry here */
634 p_stream->i_entry_count++;
636 /* Fix last dts */
637 p_stream->i_last_dts += i_length;
639 /* Write a " " */
640 p_data = block_New( p_mux, 3 );
641 p_data->p_buffer[0] = 0;
642 p_data->p_buffer[1] = 1;
643 p_data->p_buffer[2] = ' ';
645 p_sys->i_pos += p_data->i_buffer;
647 sout_AccessOutWrite( p_mux->p_access, p_data );
650 /* Fix duration */
651 p_stream->i_duration = p_stream->i_last_dts - p_stream->i_dts_start;
655 return( VLC_SUCCESS );
658 /*****************************************************************************
660 *****************************************************************************/
661 static block_t *ConvertSUBT( block_t *p_block )
663 p_block = block_Realloc( p_block, 2, p_block->i_buffer );
665 /* No trailling '\0' */
666 if( p_block->i_buffer > 2 && p_block->p_buffer[p_block->i_buffer-1] == '\0' )
667 p_block->i_buffer--;
669 p_block->p_buffer[0] = ( (p_block->i_buffer - 2) >> 8 )&0xff;
670 p_block->p_buffer[1] = ( (p_block->i_buffer - 2) )&0xff;
672 return p_block;
675 static block_t *ConvertAVC1( block_t *p_block )
677 uint8_t *last = p_block->p_buffer; /* Assume it starts with 0x00000001 */
678 uint8_t *dat = &p_block->p_buffer[4];
679 uint8_t *end = &p_block->p_buffer[p_block->i_buffer];
682 /* Replace the 4 bytes start code with 4 bytes size,
683 * FIXME are all startcodes 4 bytes ? (I don't think :( */
684 while( dat < end )
686 int i_size;
688 while( dat < end - 4 )
690 if( dat[0] == 0x00 && dat[1] == 0x00 &&
691 dat[2] == 0x00 && dat[3] == 0x01 )
693 break;
695 dat++;
697 if( dat >= end - 4 )
699 dat = end;
702 /* Fix size */
703 i_size = dat - &last[4];
704 last[0] = ( i_size >> 24 )&0xff;
705 last[1] = ( i_size >> 16 )&0xff;
706 last[2] = ( i_size >> 8 )&0xff;
707 last[3] = ( i_size )&0xff;
709 /* Skip blocks with SPS/PPS */
710 if( (last[4]&0x1f) == 7 || (last[4]&0x1f) == 8 )
712 ; // FIXME Find a way to skip dat without frelling everything
714 last = dat;
715 dat += 4;
717 return p_block;
720 static int GetDescrLength( int i_size )
722 if( i_size < 0x00000080 )
723 return 2 + i_size;
724 else if( i_size < 0x00004000 )
725 return 3 + i_size;
726 else if( i_size < 0x00200000 )
727 return 4 + i_size;
728 else
729 return 5 + i_size;
732 static bo_t *GetESDS( mp4_stream_t *p_stream )
734 bo_t *esds;
735 int i_stream_type;
736 int i_object_type_indication;
737 int i_decoder_specific_info_size;
738 unsigned int i;
739 int64_t i_bitrate_avg = 0;
740 int64_t i_bitrate_max = 0;
742 /* Compute avg/max bitrate */
743 for( i = 0; i < p_stream->i_entry_count; i++ )
745 i_bitrate_avg += p_stream->entry[i].i_size;
746 if( p_stream->entry[i].i_length > 0)
748 int64_t i_bitrate = INT64_C(8000000) * p_stream->entry[i].i_size / p_stream->entry[i].i_length;
749 if( i_bitrate > i_bitrate_max )
750 i_bitrate_max = i_bitrate;
754 if( p_stream->i_duration > 0 )
755 i_bitrate_avg = INT64_C(8000000) * i_bitrate_avg / p_stream->i_duration;
756 else
757 i_bitrate_avg = 0;
758 if( i_bitrate_max <= 1 )
759 i_bitrate_max = 0x7fffffff;
761 /* */
762 if( p_stream->fmt.i_extra > 0 )
764 i_decoder_specific_info_size =
765 GetDescrLength( p_stream->fmt.i_extra );
767 else
769 i_decoder_specific_info_size = 0;
772 esds = box_full_new( "esds", 0, 0 );
774 /* ES_Descr */
775 bo_add_descr( esds, 0x03, 3 +
776 GetDescrLength( 13 + i_decoder_specific_info_size ) +
777 GetDescrLength( 1 ) );
778 bo_add_16be( esds, p_stream->i_track_id );
779 bo_add_8 ( esds, 0x1f ); // flags=0|streamPriority=0x1f
781 /* DecoderConfigDescr */
782 bo_add_descr( esds, 0x04, 13 + i_decoder_specific_info_size );
784 switch( p_stream->fmt.i_codec )
786 case VLC_FOURCC( 'm', 'p', '4', 'v' ):
787 i_object_type_indication = 0x20;
788 break;
789 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
790 /* FIXME MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
791 i_object_type_indication = 0x60;
792 break;
793 case VLC_FOURCC( 'm', 'p', '4', 'a' ):
794 /* FIXME for mpeg2-aac == 0x66->0x68 */
795 i_object_type_indication = 0x40;
796 break;
797 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
798 i_object_type_indication =
799 p_stream->fmt.audio.i_rate < 32000 ? 0x69 : 0x6b;
800 break;
801 default:
802 i_object_type_indication = 0x00;
803 break;
805 i_stream_type = p_stream->fmt.i_cat == VIDEO_ES ? 0x04 : 0x05;
807 bo_add_8 ( esds, i_object_type_indication );
808 bo_add_8 ( esds, ( i_stream_type << 2 ) | 1 );
809 bo_add_24be( esds, 1024 * 1024 ); // bufferSizeDB
810 bo_add_32be( esds, i_bitrate_max ); // maxBitrate
811 bo_add_32be( esds, i_bitrate_avg ); // avgBitrate
813 if( p_stream->fmt.i_extra > 0 )
815 int i;
817 /* DecoderSpecificInfo */
818 bo_add_descr( esds, 0x05, p_stream->fmt.i_extra );
820 for( i = 0; i < p_stream->fmt.i_extra; i++ )
822 bo_add_8( esds, ((uint8_t*)p_stream->fmt.p_extra)[i] );
826 /* SL_Descr mandatory */
827 bo_add_descr( esds, 0x06, 1 );
828 bo_add_8 ( esds, 0x02 ); // sl_predefined
830 box_fix( esds );
832 return esds;
835 static bo_t *GetWaveTag( mp4_stream_t *p_stream )
837 bo_t *wave;
838 bo_t *box;
840 wave = box_new( "wave" );
842 box = box_new( "frma" );
843 bo_add_fourcc( box, "mp4a" );
844 box_fix( box );
845 box_gather( wave, box );
847 box = box_new( "mp4a" );
848 bo_add_32be( box, 0 );
849 box_fix( box );
850 box_gather( wave, box );
852 box = GetESDS( p_stream );
853 box_fix( box );
854 box_gather( wave, box );
856 box = box_new( "srcq" );
857 bo_add_32be( box, 0x40 );
858 box_fix( box );
859 box_gather( wave, box );
861 /* wazza ? */
862 bo_add_32be( wave, 8 ); /* new empty box */
863 bo_add_32be( wave, 0 ); /* box label */
865 box_fix( wave );
867 return wave;
870 static bo_t *GetDamrTag( mp4_stream_t *p_stream )
872 bo_t *damr;
874 damr = box_new( "damr" );
876 bo_add_fourcc( damr, "REFC" );
877 bo_add_8( damr, 0 );
879 if( p_stream->fmt.i_codec == VLC_FOURCC( 's', 'a', 'm', 'r' ) )
880 bo_add_16be( damr, 0x81ff ); /* Mode set (all modes for AMR_NB) */
881 else
882 bo_add_16be( damr, 0x83ff ); /* Mode set (all modes for AMR_WB) */
883 bo_add_16be( damr, 0x1 ); /* Mode change period (no restriction) */
885 box_fix( damr );
887 return damr;
890 static bo_t *GetD263Tag( void )
892 bo_t *d263;
894 d263 = box_new( "d263" );
896 bo_add_fourcc( d263, "VLC " );
897 bo_add_16be( d263, 0xa );
898 bo_add_8( d263, 0 );
900 box_fix( d263 );
902 return d263;
905 static bo_t *GetAvcCTag( mp4_stream_t *p_stream )
907 bo_t *avcC = NULL;
908 uint8_t *p_sps = NULL;
909 uint8_t *p_pps = NULL;
910 int i_sps_size = 0;
911 int i_pps_size = 0;
913 if( p_stream->fmt.i_extra > 0 )
915 /* FIXME: take into account multiple sps/pps */
916 uint8_t *p_buffer = p_stream->fmt.p_extra;
917 int i_buffer = p_stream->fmt.i_extra;
919 while( i_buffer > 4 &&
920 p_buffer[0] == 0 && p_buffer[1] == 0 &&
921 p_buffer[2] == 0 && p_buffer[3] == 1 )
923 const int i_nal_type = p_buffer[4]&0x1f;
924 int i_offset = 1;
925 int i_size = 0;
926 int i_startcode = 0;
928 //msg_Dbg( p_stream, "we found a startcode for NAL with TYPE:%d", i_nal_type );
930 for( i_offset = 1; i_offset+3 < i_buffer ; i_offset++)
932 if( p_buffer[i_offset] == 0 && p_buffer[i_offset+1] == 0 &&
933 p_buffer[i_offset+2] == 0 && p_buffer[i_offset+3] == 1 )
935 /* we found another startcode */
936 i_startcode = i_offset;
937 break;
940 i_size = i_startcode ? i_startcode : i_buffer;
941 if( i_nal_type == 7 )
943 p_sps = &p_buffer[4];
944 i_sps_size = i_size - 4;
946 if( i_nal_type == 8 )
948 p_pps = &p_buffer[4];
949 i_pps_size = i_size - 4;
951 i_buffer -= i_size;
952 p_buffer += i_size;
956 /* FIXME use better value */
957 avcC = box_new( "avcC" );
958 bo_add_8( avcC, 1 ); /* configuration version */
959 bo_add_8( avcC, i_sps_size ? p_sps[1] : 77 );
960 bo_add_8( avcC, i_sps_size ? p_sps[2] : 64 );
961 bo_add_8( avcC, i_sps_size ? p_sps[3] : 30 ); /* level, 5.1 */
962 bo_add_8( avcC, 0xff ); /* 0b11111100 | lengthsize = 0x11 */
964 bo_add_8( avcC, 0xe0 | (i_sps_size > 0 ? 1 : 0) ); /* 0b11100000 | sps_count */
965 if( i_sps_size > 0 )
967 bo_add_16be( avcC, i_sps_size );
968 bo_add_mem( avcC, i_sps_size, p_sps );
971 bo_add_8( avcC, (i_pps_size > 0 ? 1 : 0) ); /* pps_count */
972 if( i_pps_size > 0 )
974 bo_add_16be( avcC, i_pps_size );
975 bo_add_mem( avcC, i_pps_size, p_pps );
977 box_fix( avcC );
979 return avcC;
982 /* TODO: No idea about these values */
983 static bo_t *GetSVQ3Tag( mp4_stream_t *p_stream )
985 bo_t *smi = box_new( "SMI " );
987 if( p_stream->fmt.i_extra > 0x4e )
989 uint8_t *p_end = &((uint8_t*)p_stream->fmt.p_extra)[p_stream->fmt.i_extra];
990 uint8_t *p = &((uint8_t*)p_stream->fmt.p_extra)[0x46];
992 while( p + 8 < p_end )
994 int i_size = GetDWBE( p );
995 if( i_size <= 1 )
997 /* FIXME handle 1 as long size */
998 break;
1000 if( !strncmp( (const char *)&p[4], "SMI ", 4 ) )
1002 bo_add_mem( smi, p_end - p - 8, &p[8] );
1003 return smi;
1005 p += i_size;
1009 /* Create a dummy one in fallback */
1010 bo_add_fourcc( smi, "SEQH" );
1011 bo_add_32be( smi, 0x5 );
1012 bo_add_32be( smi, 0xe2c0211d );
1013 bo_add_8( smi, 0xc0 );
1014 box_fix( smi );
1016 return smi;
1019 static bo_t *GetUdtaTag( sout_mux_t *p_mux )
1021 sout_mux_sys_t *p_sys = p_mux->p_sys;
1022 bo_t *udta = box_new( "udta" );
1023 vlc_meta_t *p_meta = p_mux->p_sout->p_meta;
1024 int i_track;
1026 /* Requirements */
1027 for( i_track = 0; i_track < p_sys->i_nb_streams; i_track++ )
1029 mp4_stream_t *p_stream = p_sys->pp_streams[i_track];
1031 if( p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','v') ||
1032 p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
1034 bo_t *box = box_new( "\251req" );
1035 /* String length */
1036 bo_add_16be( box, sizeof("QuickTime 6.0 or greater") - 1);
1037 bo_add_16be( box, 0 );
1038 bo_add_mem( box, sizeof("QuickTime 6.0 or greater") - 1,
1039 (uint8_t *)"QuickTime 6.0 or greater" );
1040 box_fix( box );
1041 box_gather( udta, box );
1042 break;
1046 /* Encoder */
1048 bo_t *box = box_new( "\251enc" );
1049 /* String length */
1050 bo_add_16be( box, sizeof(PACKAGE_STRING " stream output") - 1);
1051 bo_add_16be( box, 0 );
1052 bo_add_mem( box, sizeof(PACKAGE_STRING " stream output") - 1,
1053 (uint8_t*)PACKAGE_STRING " stream output" );
1054 box_fix( box );
1055 box_gather( udta, box );
1058 /* Misc atoms */
1059 if( p_meta )
1061 #define ADD_META_BOX( type, box_string ) { \
1062 bo_t *box = NULL; \
1063 if( vlc_meta_Get( p_meta, vlc_meta_##type ) ) box = box_new( "\251" box_string ); \
1064 if( box ) \
1066 bo_add_16be( box, strlen( vlc_meta_Get( p_meta, vlc_meta_##type ) )); \
1067 bo_add_16be( box, 0 ); \
1068 bo_add_mem( box, strlen( vlc_meta_Get( p_meta, vlc_meta_##type ) ), \
1069 (uint8_t*)(vlc_meta_Get( p_meta, vlc_meta_##type ) ) ); \
1070 box_fix( box ); \
1071 box_gather( udta, box ); \
1074 ADD_META_BOX( Title, "nam" );
1075 ADD_META_BOX( Artist, "ART" );
1076 ADD_META_BOX( Genre, "gen" );
1077 ADD_META_BOX( Copyright, "cpy" );
1078 ADD_META_BOX( Description, "des" );
1079 ADD_META_BOX( Date, "day" );
1080 ADD_META_BOX( URL, "url" );
1081 #undef ADD_META_BOX
1084 box_fix( udta );
1085 return udta;
1088 static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
1090 sout_mux_sys_t *p_sys = p_mux->p_sys;
1091 bool b_descr = false;
1092 bo_t *soun;
1093 char fcc[4] = " ";
1094 int i;
1096 switch( p_stream->fmt.i_codec )
1098 case VLC_FOURCC('m','p','4','a'):
1099 memcpy( fcc, "mp4a", 4 );
1100 b_descr = true;
1101 break;
1103 case VLC_FOURCC('s','a','m','r'):
1104 case VLC_FOURCC('s','a','w','b'):
1105 memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
1106 b_descr = true;
1107 break;
1109 case VLC_FOURCC('m','p','g','a'):
1110 if( p_sys->b_mov )
1111 memcpy( fcc, ".mp3", 4 );
1112 else
1114 memcpy( fcc, "mp4a", 4 );
1115 b_descr = true;
1117 break;
1119 default:
1120 memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
1121 break;
1124 soun = box_new( fcc );
1125 for( i = 0; i < 6; i++ )
1127 bo_add_8( soun, 0 ); // reserved;
1129 bo_add_16be( soun, 1 ); // data-reference-index
1131 /* SoundDescription */
1132 if( p_sys->b_mov &&
1133 p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
1135 bo_add_16be( soun, 1 ); // version 1;
1137 else
1139 bo_add_16be( soun, 0 ); // version 0;
1141 bo_add_16be( soun, 0 ); // revision level (0)
1142 bo_add_32be( soun, 0 ); // vendor
1143 // channel-count
1144 bo_add_16be( soun, p_stream->fmt.audio.i_channels );
1145 // sample size
1146 bo_add_16be( soun, p_stream->fmt.audio.i_bitspersample ?
1147 p_stream->fmt.audio.i_bitspersample : 16 );
1148 bo_add_16be( soun, -2 ); // compression id
1149 bo_add_16be( soun, 0 ); // packet size (0)
1150 bo_add_16be( soun, p_stream->fmt.audio.i_rate ); // sampleratehi
1151 bo_add_16be( soun, 0 ); // sampleratelo
1153 /* Extended data for SoundDescription V1 */
1154 if( p_sys->b_mov &&
1155 p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
1157 /* samples per packet */
1158 bo_add_32be( soun, p_stream->fmt.audio.i_frame_length );
1159 bo_add_32be( soun, 1536 ); /* bytes per packet */
1160 bo_add_32be( soun, 2 ); /* bytes per frame */
1161 /* bytes per sample */
1162 bo_add_32be( soun, 2 /*p_stream->fmt.audio.i_bitspersample/8 */);
1165 /* Add an ES Descriptor */
1166 if( b_descr )
1168 bo_t *box;
1170 if( p_sys->b_mov &&
1171 p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
1173 box = GetWaveTag( p_stream );
1175 else if( p_stream->fmt.i_codec == VLC_FOURCC('s','a','m','r') )
1177 box = GetDamrTag( p_stream );
1179 else
1181 box = GetESDS( p_stream );
1183 box_fix( box );
1184 box_gather( soun, box );
1187 box_fix( soun );
1189 return soun;
1192 static bo_t *GetVideBox( mp4_stream_t *p_stream )
1195 bo_t *vide;
1196 char fcc[4] = " ";
1197 int i;
1199 switch( p_stream->fmt.i_codec )
1201 case VLC_FOURCC('m','p','4','v'):
1202 case VLC_FOURCC('m','p','g','v'):
1203 memcpy( fcc, "mp4v", 4 );
1204 break;
1206 case VLC_FOURCC('M','J','P','G'):
1207 memcpy( fcc, "mjpa", 4 );
1208 break;
1210 case VLC_FOURCC('S','V','Q','1'):
1211 memcpy( fcc, "SVQ1", 4 );
1212 break;
1214 case VLC_FOURCC('S','V','Q','3'):
1215 memcpy( fcc, "SVQ3", 4 );
1216 break;
1218 case VLC_FOURCC('H','2','6','3'):
1219 memcpy( fcc, "s263", 4 );
1220 break;
1222 case VLC_FOURCC('h','2','6','4'):
1223 memcpy( fcc, "avc1", 4 );
1224 break;
1226 case VLC_FOURCC('Y','V','1','2'):
1227 memcpy( fcc, "yv12", 4 );
1228 break;
1230 case VLC_FOURCC('Y','U','Y','2'):
1231 memcpy( fcc, "yuy2", 4 );
1232 break;
1234 default:
1235 memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
1236 break;
1239 vide = box_new( fcc );
1240 for( i = 0; i < 6; i++ )
1242 bo_add_8( vide, 0 ); // reserved;
1244 bo_add_16be( vide, 1 ); // data-reference-index
1246 bo_add_16be( vide, 0 ); // predefined;
1247 bo_add_16be( vide, 0 ); // reserved;
1248 for( i = 0; i < 3; i++ )
1250 bo_add_32be( vide, 0 ); // predefined;
1253 bo_add_16be( vide, p_stream->fmt.video.i_width ); // i_width
1254 bo_add_16be( vide, p_stream->fmt.video.i_height ); // i_height
1256 bo_add_32be( vide, 0x00480000 ); // h 72dpi
1257 bo_add_32be( vide, 0x00480000 ); // v 72dpi
1259 bo_add_32be( vide, 0 ); // data size, always 0
1260 bo_add_16be( vide, 1 ); // frames count per sample
1262 // compressor name;
1263 for( i = 0; i < 32; i++ )
1265 bo_add_8( vide, 0 );
1268 bo_add_16be( vide, 0x18 ); // depth
1269 bo_add_16be( vide, 0xffff ); // predefined
1271 /* add an ES Descriptor */
1272 switch( p_stream->fmt.i_codec )
1274 case VLC_FOURCC('m','p','4','v'):
1275 case VLC_FOURCC('m','p','g','v'):
1277 bo_t *esds = GetESDS( p_stream );
1279 box_fix( esds );
1280 box_gather( vide, esds );
1282 break;
1284 case VLC_FOURCC('H','2','6','3'):
1286 bo_t *d263 = GetD263Tag();
1288 box_fix( d263 );
1289 box_gather( vide, d263 );
1291 break;
1293 case VLC_FOURCC('S','V','Q','3'):
1295 bo_t *esds = GetSVQ3Tag( p_stream );
1297 box_fix( esds );
1298 box_gather( vide, esds );
1300 break;
1302 case VLC_FOURCC('h','2','6','4'):
1303 box_gather( vide, GetAvcCTag( p_stream ) );
1304 break;
1306 default:
1307 break;
1310 box_fix( vide );
1312 return vide;
1315 static bo_t *GetTextBox( void )
1318 bo_t *text = box_new( "text" );
1319 int i;
1321 for( i = 0; i < 6; i++ )
1323 bo_add_8( text, 0 ); // reserved;
1325 bo_add_16be( text, 1 ); // data-reference-index
1327 bo_add_32be( text, 0 ); // display flags
1328 bo_add_32be( text, 0 ); // justification
1329 for( i = 0; i < 3; i++ )
1331 bo_add_16be( text, 0 ); // back ground color
1334 bo_add_16be( text, 0 ); // box text
1335 bo_add_16be( text, 0 ); // box text
1336 bo_add_16be( text, 0 ); // box text
1337 bo_add_16be( text, 0 ); // box text
1339 bo_add_64be( text, 0 ); // reserved
1340 for( i = 0; i < 3; i++ )
1342 bo_add_16be( text, 0xff ); // foreground color
1345 bo_add_8 ( text, 9 );
1346 bo_add_mem( text, 9, (uint8_t*)"Helvetica" );
1348 box_fix( text );
1350 return text;
1353 static bo_t *GetStblBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
1355 sout_mux_sys_t *p_sys = p_mux->p_sys;
1356 unsigned int i_chunk, i_stsc_last_val, i_stsc_entries, i, i_index;
1357 bo_t *stbl, *stsd, *stts, *stco, *stsc, *stsz, *stss;
1358 uint32_t i_timescale;
1359 int64_t i_dts, i_dts_q;
1361 stbl = box_new( "stbl" );
1363 /* sample description */
1364 stsd = box_full_new( "stsd", 0, 0 );
1365 bo_add_32be( stsd, 1 );
1366 if( p_stream->fmt.i_cat == AUDIO_ES )
1368 bo_t *soun = GetSounBox( p_mux, p_stream );
1369 box_gather( stsd, soun );
1371 else if( p_stream->fmt.i_cat == VIDEO_ES )
1373 bo_t *vide = GetVideBox( p_stream );
1374 box_gather( stsd, vide );
1376 else if( p_stream->fmt.i_cat == SPU_ES )
1378 box_gather( stsd, GetTextBox() );
1380 box_fix( stsd );
1382 /* chunk offset table */
1383 if( p_sys->i_pos >= (((uint64_t)0x1) << 32) )
1385 /* 64 bits version */
1386 p_stream->b_stco64 = true;
1387 stco = box_full_new( "co64", 0, 0 );
1389 else
1391 /* 32 bits version */
1392 p_stream->b_stco64 = false;
1393 stco = box_full_new( "stco", 0, 0 );
1395 bo_add_32be( stco, 0 ); // entry-count (fixed latter)
1397 /* sample to chunk table */
1398 stsc = box_full_new( "stsc", 0, 0 );
1399 bo_add_32be( stsc, 0 ); // entry-count (fixed latter)
1401 for( i_chunk = 0, i_stsc_last_val = 0, i_stsc_entries = 0, i = 0;
1402 i < p_stream->i_entry_count; i_chunk++ )
1404 int i_first = i;
1406 if( p_stream->b_stco64 )
1407 bo_add_64be( stco, p_stream->entry[i].i_pos );
1408 else
1409 bo_add_32be( stco, p_stream->entry[i].i_pos );
1411 while( i < p_stream->i_entry_count )
1413 if( i + 1 < p_stream->i_entry_count &&
1414 p_stream->entry[i].i_pos + p_stream->entry[i].i_size
1415 != p_stream->entry[i + 1].i_pos )
1417 i++;
1418 break;
1421 i++;
1424 /* Add entry to the stsc table */
1425 if( i_stsc_last_val != i - i_first )
1427 bo_add_32be( stsc, 1 + i_chunk ); // first-chunk
1428 bo_add_32be( stsc, i - i_first ) ; // samples-per-chunk
1429 bo_add_32be( stsc, 1 ); // sample-descr-index
1430 i_stsc_last_val = i - i_first;
1431 i_stsc_entries++;
1435 /* Fix stco entry count */
1436 bo_fix_32be( stco, 12, i_chunk );
1437 msg_Dbg( p_mux, "created %d chunks (stco)", i_chunk );
1438 box_fix( stco );
1440 /* Fix stsc entry count */
1441 bo_fix_32be( stsc, 12, i_stsc_entries );
1442 box_fix( stsc );
1444 /* add stts */
1445 stts = box_full_new( "stts", 0, 0 );
1446 bo_add_32be( stts, 0 ); // entry-count (fixed latter)
1448 if( p_stream->fmt.i_cat == AUDIO_ES )
1449 i_timescale = p_stream->fmt.audio.i_rate;
1450 else
1451 i_timescale = 1001;
1453 /* first, create quantified length */
1454 for( i = 0, i_dts = 0, i_dts_q = 0; i < p_stream->i_entry_count; i++ )
1456 int64_t i_dts_deq = i_dts_q * INT64_C(1000000) / (int64_t)i_timescale;
1457 int64_t i_delta = p_stream->entry[i].i_length + i_dts - i_dts_deq;
1459 i_dts += p_stream->entry[i].i_length;
1461 p_stream->entry[i].i_length =
1462 i_delta * (int64_t)i_timescale / INT64_C(1000000);
1464 i_dts_q += p_stream->entry[i].i_length;
1466 /* then write encoded table */
1467 for( i = 0, i_index = 0; i < p_stream->i_entry_count; i_index++)
1469 int i_first = i;
1470 int64_t i_delta = p_stream->entry[i].i_length;
1472 while( i < p_stream->i_entry_count )
1474 i++;
1475 if( i >= p_stream->i_entry_count ||
1476 p_stream->entry[i].i_length != i_delta )
1478 break;
1482 bo_add_32be( stts, i - i_first ); // sample-count
1483 bo_add_32be( stts, i_delta ); // sample-delta
1485 bo_fix_32be( stts, 12, i_index );
1486 box_fix( stts );
1488 /* FIXME add ctts ?? FIXME */
1490 stsz = box_full_new( "stsz", 0, 0 );
1491 bo_add_32be( stsz, 0 ); // sample-size
1492 bo_add_32be( stsz, p_stream->i_entry_count ); // sample-count
1493 for( i = 0; i < p_stream->i_entry_count; i++ )
1495 bo_add_32be( stsz, p_stream->entry[i].i_size ); // sample-size
1497 box_fix( stsz );
1499 /* create stss table */
1500 stss = NULL;
1501 for( i = 0, i_index = 0; i < p_stream->i_entry_count; i++ )
1503 if( p_stream->entry[i].i_flags & BLOCK_FLAG_TYPE_I )
1505 if( stss == NULL )
1507 stss = box_full_new( "stss", 0, 0 );
1508 bo_add_32be( stss, 0 ); /* fixed later */
1510 bo_add_32be( stss, 1 + i );
1511 i_index++;
1514 if( stss )
1516 bo_fix_32be( stss, 12, i_index );
1517 box_fix( stss );
1520 /* Now gather all boxes into stbl */
1521 box_gather( stbl, stsd );
1522 box_gather( stbl, stts );
1523 if( stss )
1525 box_gather( stbl, stss );
1527 box_gather( stbl, stsc );
1528 box_gather( stbl, stsz );
1529 p_stream->i_stco_pos = stbl->i_buffer + 16;
1530 box_gather( stbl, stco );
1532 /* finish stbl */
1533 box_fix( stbl );
1535 return stbl;
1538 static int64_t get_timestamp(void);
1540 static const uint32_t mvhd_matrix[9] =
1541 { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
1543 static bo_t *GetMoovBox( sout_mux_t *p_mux )
1545 sout_mux_sys_t *p_sys = p_mux->p_sys;
1547 bo_t *moov, *mvhd;
1548 int i_trak, i;
1550 uint32_t i_movie_timescale = 90000;
1551 int64_t i_movie_duration = 0;
1553 moov = box_new( "moov" );
1555 /* Create general info */
1556 for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
1558 mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1559 i_movie_duration = __MAX( i_movie_duration, p_stream->i_duration );
1561 msg_Dbg( p_mux, "movie duration %ds",
1562 (uint32_t)( i_movie_duration / (mtime_t)1000000 ) );
1564 i_movie_duration = i_movie_duration * i_movie_timescale / 1000000;
1566 /* *** add /moov/mvhd *** */
1567 if( !p_sys->b_64_ext )
1569 mvhd = box_full_new( "mvhd", 0, 0 );
1570 bo_add_32be( mvhd, get_timestamp() ); // creation time
1571 bo_add_32be( mvhd, get_timestamp() ); // modification time
1572 bo_add_32be( mvhd, i_movie_timescale); // timescale
1573 bo_add_32be( mvhd, i_movie_duration ); // duration
1575 else
1577 mvhd = box_full_new( "mvhd", 1, 0 );
1578 bo_add_64be( mvhd, get_timestamp() ); // creation time
1579 bo_add_64be( mvhd, get_timestamp() ); // modification time
1580 bo_add_32be( mvhd, i_movie_timescale); // timescale
1581 bo_add_64be( mvhd, i_movie_duration ); // duration
1583 bo_add_32be( mvhd, 0x10000 ); // rate
1584 bo_add_16be( mvhd, 0x100 ); // volume
1585 bo_add_16be( mvhd, 0 ); // reserved
1586 for( i = 0; i < 2; i++ )
1588 bo_add_32be( mvhd, 0 ); // reserved
1590 for( i = 0; i < 9; i++ )
1592 bo_add_32be( mvhd, mvhd_matrix[i] );// matrix
1594 for( i = 0; i < 6; i++ )
1596 bo_add_32be( mvhd, 0 ); // pre-defined
1599 /* Next available track id */
1600 bo_add_32be( mvhd, p_sys->i_nb_streams + 1 ); // next-track-id
1602 box_fix( mvhd );
1603 box_gather( moov, mvhd );
1605 for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
1607 mp4_stream_t *p_stream;
1608 uint32_t i_timescale;
1610 bo_t *trak, *tkhd, *edts, *elst, *mdia, *mdhd, *hdlr;
1611 bo_t *minf, *dinf, *dref, *url, *stbl;
1613 p_stream = p_sys->pp_streams[i_trak];
1615 if( p_stream->fmt.i_cat == AUDIO_ES )
1616 i_timescale = p_stream->fmt.audio.i_rate;
1617 else
1618 i_timescale = 1001;
1620 /* *** add /moov/trak *** */
1621 trak = box_new( "trak" );
1623 /* *** add /moov/trak/tkhd *** */
1624 if( !p_sys->b_64_ext )
1626 if( p_sys->b_mov )
1627 tkhd = box_full_new( "tkhd", 0, 0x0f );
1628 else
1629 tkhd = box_full_new( "tkhd", 0, 1 );
1631 bo_add_32be( tkhd, get_timestamp() ); // creation time
1632 bo_add_32be( tkhd, get_timestamp() ); // modification time
1633 bo_add_32be( tkhd, p_stream->i_track_id );
1634 bo_add_32be( tkhd, 0 ); // reserved 0
1635 bo_add_32be( tkhd, p_stream->i_duration *
1636 (int64_t)i_movie_timescale /
1637 (mtime_t)1000000 ); // duration
1639 else
1641 if( p_sys->b_mov )
1642 tkhd = box_full_new( "tkhd", 1, 0x0f );
1643 else
1644 tkhd = box_full_new( "tkhd", 1, 1 );
1646 bo_add_64be( tkhd, get_timestamp() ); // creation time
1647 bo_add_64be( tkhd, get_timestamp() ); // modification time
1648 bo_add_32be( tkhd, p_stream->i_track_id );
1649 bo_add_32be( tkhd, 0 ); // reserved 0
1650 bo_add_64be( tkhd, p_stream->i_duration *
1651 (int64_t)i_movie_timescale /
1652 (mtime_t)1000000 ); // duration
1655 for( i = 0; i < 2; i++ )
1657 bo_add_32be( tkhd, 0 ); // reserved
1659 bo_add_16be( tkhd, 0 ); // layer
1660 bo_add_16be( tkhd, 0 ); // pre-defined
1661 // volume
1662 bo_add_16be( tkhd, p_stream->fmt.i_cat == AUDIO_ES ? 0x100 : 0 );
1663 bo_add_16be( tkhd, 0 ); // reserved
1664 for( i = 0; i < 9; i++ )
1666 bo_add_32be( tkhd, mvhd_matrix[i] ); // matrix
1668 if( p_stream->fmt.i_cat == AUDIO_ES )
1670 bo_add_32be( tkhd, 0 ); // width (presentation)
1671 bo_add_32be( tkhd, 0 ); // height(presentation)
1673 else if( p_stream->fmt.i_cat == VIDEO_ES )
1675 int i_width = p_stream->fmt.video.i_width << 16;
1676 if( p_stream->fmt.video.i_aspect > 0 )
1678 i_width = (int64_t)p_stream->fmt.video.i_aspect *
1679 ((int64_t)p_stream->fmt.video.i_height << 16) /
1680 VOUT_ASPECT_FACTOR;
1682 // width (presentation)
1683 bo_add_32be( tkhd, i_width );
1684 // height(presentation)
1685 bo_add_32be( tkhd, p_stream->fmt.video.i_height << 16 );
1687 else
1689 int i_width = 320 << 16;
1690 int i_height = 200;
1691 int i;
1692 for( i = 0; i < p_sys->i_nb_streams; i++ )
1694 mp4_stream_t *tk = p_sys->pp_streams[i];
1695 if( tk->fmt.i_cat == VIDEO_ES )
1697 if( p_stream->fmt.video.i_aspect )
1698 i_width = (int64_t)p_stream->fmt.video.i_aspect *
1699 ((int64_t)p_stream->fmt.video.i_height<<16) / VOUT_ASPECT_FACTOR;
1700 else
1701 i_width = p_stream->fmt.video.i_width << 16;
1702 i_height = p_stream->fmt.video.i_height;
1703 break;
1706 bo_add_32be( tkhd, i_width ); // width (presentation)
1707 bo_add_32be( tkhd, i_height << 16 ); // height(presentation)
1710 box_fix( tkhd );
1711 box_gather( trak, tkhd );
1713 /* *** add /moov/trak/edts and elst */
1714 edts = box_new( "edts" );
1715 elst = box_full_new( "elst", p_sys->b_64_ext ? 1 : 0, 0 );
1716 if( p_stream->i_dts_start > p_sys->i_dts_start )
1718 bo_add_32be( elst, 2 );
1720 if( p_sys->b_64_ext )
1722 bo_add_64be( elst, (p_stream->i_dts_start-p_sys->i_dts_start) *
1723 i_movie_timescale / INT64_C(1000000) );
1724 bo_add_64be( elst, -1 );
1726 else
1728 bo_add_32be( elst, (p_stream->i_dts_start-p_sys->i_dts_start) *
1729 i_movie_timescale / INT64_C(1000000) );
1730 bo_add_32be( elst, -1 );
1732 bo_add_16be( elst, 1 );
1733 bo_add_16be( elst, 0 );
1735 else
1737 bo_add_32be( elst, 1 );
1739 if( p_sys->b_64_ext )
1741 bo_add_64be( elst, p_stream->i_duration *
1742 i_movie_timescale / INT64_C(1000000) );
1743 bo_add_64be( elst, 0 );
1745 else
1747 bo_add_32be( elst, p_stream->i_duration *
1748 i_movie_timescale / INT64_C(1000000) );
1749 bo_add_32be( elst, 0 );
1751 bo_add_16be( elst, 1 );
1752 bo_add_16be( elst, 0 );
1754 box_fix( elst );
1755 box_gather( edts, elst );
1756 box_fix( edts );
1757 box_gather( trak, edts );
1759 /* *** add /moov/trak/mdia *** */
1760 mdia = box_new( "mdia" );
1762 /* media header */
1763 if( !p_sys->b_64_ext )
1765 mdhd = box_full_new( "mdhd", 0, 0 );
1766 bo_add_32be( mdhd, get_timestamp() ); // creation time
1767 bo_add_32be( mdhd, get_timestamp() ); // modification time
1768 bo_add_32be( mdhd, i_timescale); // timescale
1769 bo_add_32be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
1770 (mtime_t)1000000 ); // duration
1772 else
1774 mdhd = box_full_new( "mdhd", 1, 0 );
1775 bo_add_64be( mdhd, get_timestamp() ); // creation time
1776 bo_add_64be( mdhd, get_timestamp() ); // modification time
1777 bo_add_32be( mdhd, i_timescale); // timescale
1778 bo_add_64be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
1779 (mtime_t)1000000 ); // duration
1782 if( p_stream->fmt.psz_language )
1784 char *psz = p_stream->fmt.psz_language;
1785 const iso639_lang_t *pl = NULL;
1786 uint16_t lang = 0x0;
1788 if( strlen( psz ) == 2 )
1790 pl = GetLang_1( psz );
1792 else if( strlen( psz ) == 3 )
1794 pl = GetLang_2B( psz );
1795 if( !strcmp( pl->psz_iso639_1, "??" ) )
1797 pl = GetLang_2T( psz );
1800 if( pl && strcmp( pl->psz_iso639_1, "??" ) )
1802 lang = ( ( pl->psz_iso639_2T[0] - 0x60 ) << 10 ) |
1803 ( ( pl->psz_iso639_2T[1] - 0x60 ) << 5 ) |
1804 ( ( pl->psz_iso639_2T[2] - 0x60 ) );
1806 bo_add_16be( mdhd, lang ); // language
1808 else
1810 bo_add_16be( mdhd, 0 ); // language
1812 bo_add_16be( mdhd, 0 ); // predefined
1813 box_fix( mdhd );
1814 box_gather( mdia, mdhd );
1816 /* handler reference */
1817 hdlr = box_full_new( "hdlr", 0, 0 );
1819 if( p_sys->b_mov )
1820 bo_add_fourcc( hdlr, "mhlr" ); // media handler
1821 else
1822 bo_add_32be( hdlr, 0 );
1824 if( p_stream->fmt.i_cat == AUDIO_ES )
1825 bo_add_fourcc( hdlr, "soun" );
1826 else if( p_stream->fmt.i_cat == VIDEO_ES )
1827 bo_add_fourcc( hdlr, "vide" );
1828 else if( p_stream->fmt.i_cat == SPU_ES )
1829 bo_add_fourcc( hdlr, "text" );
1831 bo_add_32be( hdlr, 0 ); // reserved
1832 bo_add_32be( hdlr, 0 ); // reserved
1833 bo_add_32be( hdlr, 0 ); // reserved
1835 if( p_sys->b_mov )
1836 bo_add_8( hdlr, 12 ); /* Pascal string for .mov */
1838 if( p_stream->fmt.i_cat == AUDIO_ES )
1839 bo_add_mem( hdlr, 12, (uint8_t*)"SoundHandler" );
1840 else if( p_stream->fmt.i_cat == VIDEO_ES )
1841 bo_add_mem( hdlr, 12, (uint8_t*)"VideoHandler" );
1842 else
1843 bo_add_mem( hdlr, 12, (uint8_t*)"Text Handler" );
1845 if( !p_sys->b_mov )
1846 bo_add_8( hdlr, 0 ); /* asciiz string for .mp4, yes that's BRAIN DAMAGED F**K MP4 */
1848 box_fix( hdlr );
1849 box_gather( mdia, hdlr );
1851 /* minf*/
1852 minf = box_new( "minf" );
1854 /* add smhd|vmhd */
1855 if( p_stream->fmt.i_cat == AUDIO_ES )
1857 bo_t *smhd;
1859 smhd = box_full_new( "smhd", 0, 0 );
1860 bo_add_16be( smhd, 0 ); // balance
1861 bo_add_16be( smhd, 0 ); // reserved
1862 box_fix( smhd );
1864 box_gather( minf, smhd );
1866 else if( p_stream->fmt.i_cat == VIDEO_ES )
1868 bo_t *vmhd;
1870 vmhd = box_full_new( "vmhd", 0, 1 );
1871 bo_add_16be( vmhd, 0 ); // graphicsmode
1872 for( i = 0; i < 3; i++ )
1874 bo_add_16be( vmhd, 0 ); // opcolor
1876 box_fix( vmhd );
1878 box_gather( minf, vmhd );
1880 else if( p_stream->fmt.i_cat == SPU_ES )
1882 bo_t *gmhd = box_new( "gmhd" );
1883 bo_t *gmin = box_full_new( "gmin", 0, 1 );
1885 bo_add_16be( gmin, 0 ); // graphicsmode
1886 for( i = 0; i < 3; i++ )
1888 bo_add_16be( gmin, 0 ); // opcolor
1890 bo_add_16be( gmin, 0 ); // balance
1891 bo_add_16be( gmin, 0 ); // reserved
1892 box_fix( gmin );
1894 box_gather( gmhd, gmin );
1895 box_fix( gmhd );
1897 box_gather( minf, gmhd );
1900 /* dinf */
1901 dinf = box_new( "dinf" );
1902 dref = box_full_new( "dref", 0, 0 );
1903 bo_add_32be( dref, 1 );
1904 url = box_full_new( "url ", 0, 0x01 );
1905 box_fix( url );
1906 box_gather( dref, url );
1907 box_fix( dref );
1908 box_gather( dinf, dref );
1910 /* append dinf to mdia */
1911 box_fix( dinf );
1912 box_gather( minf, dinf );
1914 /* add stbl */
1915 stbl = GetStblBox( p_mux, p_stream );
1917 /* append stbl to minf */
1918 p_stream->i_stco_pos += minf->i_buffer;
1919 box_gather( minf, stbl );
1921 /* append minf to mdia */
1922 box_fix( minf );
1923 p_stream->i_stco_pos += mdia->i_buffer;
1924 box_gather( mdia, minf );
1926 /* append mdia to trak */
1927 box_fix( mdia );
1928 p_stream->i_stco_pos += trak->i_buffer;
1929 box_gather( trak, mdia );
1931 /* append trak to moov */
1932 box_fix( trak );
1933 p_stream->i_stco_pos += moov->i_buffer;
1934 box_gather( moov, trak );
1937 /* Add user data tags */
1938 box_gather( moov, GetUdtaTag( p_mux ) );
1940 box_fix( moov );
1941 return moov;
1944 /****************************************************************************/
1946 static void bo_init( bo_t *p_bo, int i_size, uint8_t *p_buffer,
1947 bool b_grow )
1949 if( !p_buffer )
1951 p_bo->i_buffer_size = __MAX( i_size, 1024 );
1952 p_bo->p_buffer = malloc( p_bo->i_buffer_size );
1954 else
1956 p_bo->i_buffer_size = i_size;
1957 p_bo->p_buffer = p_buffer;
1960 p_bo->b_grow = b_grow;
1961 p_bo->i_buffer = 0;
1964 static void bo_add_8( bo_t *p_bo, uint8_t i )
1966 if( p_bo->i_buffer < p_bo->i_buffer_size )
1968 p_bo->p_buffer[p_bo->i_buffer] = i;
1970 else if( p_bo->b_grow )
1972 p_bo->i_buffer_size += 1024;
1973 p_bo->p_buffer = realloc( p_bo->p_buffer, p_bo->i_buffer_size );
1975 p_bo->p_buffer[p_bo->i_buffer] = i;
1978 p_bo->i_buffer++;
1981 static void bo_add_16be( bo_t *p_bo, uint16_t i )
1983 bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1984 bo_add_8( p_bo, i &0xff );
1987 static void bo_add_24be( bo_t *p_bo, uint32_t i )
1989 bo_add_8( p_bo, ( ( i >> 16) &0xff ) );
1990 bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1991 bo_add_8( p_bo, ( i &0xff ) );
1993 static void bo_add_32be( bo_t *p_bo, uint32_t i )
1995 bo_add_16be( p_bo, ( ( i >> 16) &0xffff ) );
1996 bo_add_16be( p_bo, i &0xffff );
1999 static void bo_fix_32be ( bo_t *p_bo, int i_pos, uint32_t i)
2001 p_bo->p_buffer[i_pos ] = ( i >> 24 )&0xff;
2002 p_bo->p_buffer[i_pos + 1] = ( i >> 16 )&0xff;
2003 p_bo->p_buffer[i_pos + 2] = ( i >> 8 )&0xff;
2004 p_bo->p_buffer[i_pos + 3] = ( i )&0xff;
2007 static void bo_add_64be( bo_t *p_bo, uint64_t i )
2009 bo_add_32be( p_bo, ( ( i >> 32) &0xffffffff ) );
2010 bo_add_32be( p_bo, i &0xffffffff );
2013 static void bo_add_fourcc( bo_t *p_bo, const char *fcc )
2015 bo_add_8( p_bo, fcc[0] );
2016 bo_add_8( p_bo, fcc[1] );
2017 bo_add_8( p_bo, fcc[2] );
2018 bo_add_8( p_bo, fcc[3] );
2021 static void bo_add_mem( bo_t *p_bo, int i_size, uint8_t *p_mem )
2023 int i;
2025 for( i = 0; i < i_size; i++ )
2027 bo_add_8( p_bo, p_mem[i] );
2031 static void bo_add_descr( bo_t *p_bo, uint8_t tag, uint32_t i_size )
2033 uint32_t i_length;
2034 uint8_t vals[4];
2036 i_length = i_size;
2037 vals[3] = (unsigned char)(i_length & 0x7f);
2038 i_length >>= 7;
2039 vals[2] = (unsigned char)((i_length & 0x7f) | 0x80);
2040 i_length >>= 7;
2041 vals[1] = (unsigned char)((i_length & 0x7f) | 0x80);
2042 i_length >>= 7;
2043 vals[0] = (unsigned char)((i_length & 0x7f) | 0x80);
2045 bo_add_8( p_bo, tag );
2047 if( i_size < 0x00000080 )
2049 bo_add_8( p_bo, vals[3] );
2051 else if( i_size < 0x00004000 )
2053 bo_add_8( p_bo, vals[2] );
2054 bo_add_8( p_bo, vals[3] );
2056 else if( i_size < 0x00200000 )
2058 bo_add_8( p_bo, vals[1] );
2059 bo_add_8( p_bo, vals[2] );
2060 bo_add_8( p_bo, vals[3] );
2062 else if( i_size < 0x10000000 )
2064 bo_add_8( p_bo, vals[0] );
2065 bo_add_8( p_bo, vals[1] );
2066 bo_add_8( p_bo, vals[2] );
2067 bo_add_8( p_bo, vals[3] );
2071 static void bo_add_bo( bo_t *p_bo, bo_t *p_bo2 )
2073 int i;
2075 for( i = 0; i < p_bo2->i_buffer; i++ )
2077 bo_add_8( p_bo, p_bo2->p_buffer[i] );
2081 static bo_t * box_new( const char *fcc )
2083 bo_t *box;
2085 if( ( box = malloc( sizeof( bo_t ) ) ) )
2087 bo_init( box, 0, NULL, true );
2089 bo_add_32be ( box, 0 );
2090 bo_add_fourcc( box, fcc );
2093 return box;
2096 static bo_t * box_full_new( const char *fcc, uint8_t v, uint32_t f )
2098 bo_t *box;
2100 if( ( box = malloc( sizeof( bo_t ) ) ) )
2102 bo_init( box, 0, NULL, true );
2104 bo_add_32be ( box, 0 );
2105 bo_add_fourcc( box, fcc );
2106 bo_add_8 ( box, v );
2107 bo_add_24be ( box, f );
2110 return box;
2113 static void box_fix( bo_t *box )
2115 bo_t box_tmp;
2117 memcpy( &box_tmp, box, sizeof( bo_t ) );
2119 box_tmp.i_buffer = 0;
2120 bo_add_32be( &box_tmp, box->i_buffer );
2123 static void box_free( bo_t *box )
2125 free( box->p_buffer );
2126 free( box );
2129 static void box_gather ( bo_t *box, bo_t *box2 )
2131 bo_add_bo( box, box2 );
2132 box_free( box2 );
2135 static block_t * bo_to_sout( sout_instance_t *p_sout, bo_t *box )
2137 (void)p_sout;
2138 block_t *p_buf;
2140 p_buf = block_New( p_sout, box->i_buffer );
2141 if( box->i_buffer > 0 )
2143 memcpy( p_buf->p_buffer, box->p_buffer, box->i_buffer );
2146 return p_buf;
2149 static void box_send( sout_mux_t *p_mux, bo_t *box )
2151 block_t *p_buf;
2153 p_buf = bo_to_sout( p_mux->p_sout, box );
2154 box_free( box );
2156 sout_AccessOutWrite( p_mux->p_access, p_buf );
2159 static int64_t get_timestamp(void)
2161 int64_t i_timestamp = 0;
2163 #ifdef HAVE_TIME_H
2164 i_timestamp = time(NULL);
2165 i_timestamp += 2082844800; // MOV/MP4 start date is 1/1/1904
2166 // 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
2167 #endif
2169 return i_timestamp;