/*****************************************************************************
- * mp4.c
+ * mp4.c: mp4/mov muxer
*****************************************************************************
* Copyright (C) 2001, 2002, 2003 VideoLAN
- * $Id: mp4.c,v 1.3 2003/08/01 20:06:43 gbazin Exp $
+ * $Id: mp4.c,v 1.4 2003/09/02 16:00:24 gbazin Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
static void bo_add_fourcc(bo_t *, char * );
static void bo_add_bo ( bo_t *, bo_t * );
static void bo_add_mem ( bo_t *, int , uint8_t * );
+static void bo_add_descr ( bo_t *, uint8_t , uint32_t );
static void bo_fix_32be ( bo_t *, int , uint32_t );
p_sys->i_mdat_pos = p_sys->i_pos;
box_send( p_mux, box );
+
+ /* FIXME FIXME
+ * Quicktime actually doesn't like the 64 bits extensions !!! */
+ p_sys->b_mov = VLC_TRUE;
}
/* Now add mdat header */
return VLC_SUCCESS;
}
-static uint32_t GetDescriptorLength24b( int i_length )
+static int GetDescrLength( int i_size )
{
- uint32_t i_l1, i_l2, i_l3;
-
- i_l1 = i_length&0x7f;
- i_l2 = ( i_length >> 7 )&0x7f;
- i_l3 = ( i_length >> 14 )&0x7f;
-
- return( 0x808000 | ( i_l3 << 16 ) | ( i_l2 << 8 ) | i_l1 );
+ if( i_size < 0x00000080 )
+ return 2 + i_size;
+ else if( i_size < 0x00004000 )
+ return 3 + i_size;
+ else if( i_size < 0x00200000 )
+ return 4 + i_size;
+ else
+ return 5 + i_size;
}
static bo_t *GetESDS( mp4_stream_t *p_stream )
if( p_stream->p_fmt->i_extra_data > 0 )
{
- i_decoder_specific_info_size = p_stream->p_fmt->i_extra_data + 4;
+ i_decoder_specific_info_size =
+ GetDescrLength( p_stream->p_fmt->i_extra_data );
}
else
{
esds = box_full_new( "esds", 0, 0 );
- bo_add_8 ( esds, 0x03 ); // ES_DescrTag
- bo_add_24be( esds,
- GetDescriptorLength24b( 25 + i_decoder_specific_info_size ) );
+ /* ES_Descr */
+ bo_add_descr( esds, 0x03, 3 +
+ GetDescrLength( 13 + i_decoder_specific_info_size ) +
+ GetDescrLength( 1 ) );
bo_add_16be( esds, p_stream->i_track_id );
bo_add_8 ( esds, 0x1f ); // flags=0|streamPriority=0x1f
- bo_add_8 ( esds, 0x04 ); // DecoderConfigDescrTag
- bo_add_24be( esds,
- GetDescriptorLength24b( 13 + i_decoder_specific_info_size ) );
+ /* DecoderConfigDescr */
+ bo_add_descr( esds, 0x04, 13 + i_decoder_specific_info_size );
switch( p_stream->p_fmt->i_fourcc )
{
if( p_stream->p_fmt->i_extra_data > 0 )
{
int i;
- bo_add_8 ( esds, 0x05 ); // DecoderSpecificInfo
- bo_add_24be( esds,
- GetDescriptorLength24b( p_stream->p_fmt->i_extra_data ) );
+
+ /* DecoderSpecificInfo */
+ bo_add_descr( esds, 0x05, p_stream->p_fmt->i_extra_data );
for( i = 0; i < p_stream->p_fmt->i_extra_data; i++ )
{
}
/* SL_Descr mandatory */
- bo_add_8 ( esds, 0x06 ); // SLConfigDescriptorTag
- bo_add_24be( esds, GetDescriptorLength24b( 1 ) );
- bo_add_8 ( esds, 0x02 ); // sl_predefined
+ bo_add_descr( esds, 0x06, 1 );
+ bo_add_8 ( esds, 0x02 ); // sl_predefined
box_fix( esds );
/* *** add /moov/trak/mdia *** */
mdia = box_new( "mdia" );
- /* */
+ /* media header */
if( p_sys->b_mov )
{
mdhd = box_full_new( "mdhd", 0, 0 );
box_fix( mdhd );
box_gather( mdia, mdhd );
- /* */
+ /* handler reference */
hdlr = box_full_new( "hdlr", 0, 0 );
- bo_add_32be( hdlr, 0 ); // predefined
+
+ bo_add_fourcc( hdlr, "mhlr" ); // media handler
if( p_stream->p_fmt->i_cat == AUDIO_ES )
{
bo_add_fourcc( hdlr, "soun" );
{
bo_add_fourcc( hdlr, "vide" );
}
- for( i = 0; i < 3; i++ )
+
+ bo_add_32be( hdlr, 0 ); // reserved
+ bo_add_32be( hdlr, 0 ); // reserved
+ bo_add_32be( hdlr, 0 ); // reserved
+
+ if( p_stream->p_fmt->i_cat == AUDIO_ES )
+ {
+ bo_add_mem( hdlr, 13, "SoundHandler" );
+ }
+ else
{
- bo_add_32be( hdlr, 0 ); // reserved
+ bo_add_mem( hdlr, 13, "VideoHandler" );
}
- bo_add_mem( hdlr, 2, "?" );
box_fix( hdlr );
box_gather( mdia, hdlr );
bo_add_8( soun, 0 ); // reserved;
}
bo_add_16be( soun, 1 ); // data-reference-index
- bo_add_32be( soun, 0 ); // reserved;
- bo_add_32be( soun, 0 ); // reserved;
+
+ /* SoundDescriptionV1 */
+ bo_add_16be( soun, 1 ); // version;
+ bo_add_16be( soun, 0 ); // revision level (0)
+ bo_add_32be( soun, 0 ); // vendor
bo_add_16be( soun, p_stream->p_fmt->i_channels ); // channel-count
bo_add_16be( soun, 16); // FIXME sample size
- bo_add_16be( soun, 0 ); // predefined
- bo_add_16be( soun, 0 ); // reserved
+ bo_add_16be( soun, -2 ); // compression id
+ bo_add_16be( soun, 0 ); // packet size (0)
bo_add_16be( soun, p_stream->p_fmt->i_sample_rate ); // sampleratehi
bo_add_16be( soun, 0 ); // sampleratelo
bo_add_32be( vide, 0x00480000 ); // h 72dpi
bo_add_32be( vide, 0x00480000 ); // v 72dpi
- bo_add_32be( vide, 0 ); // reserved
- bo_add_16be( vide, 1 ); // predefined
+ bo_add_32be( vide, 0 ); // data size, always 0
+ bo_add_16be( vide, 1 ); // frames count per sample
+
+ // compressor name;
for( i = 0; i < 32; i++ )
{
- bo_add_8( vide, 0 ); // compressor name;
+ bo_add_8( vide, 0 );
}
+
bo_add_16be( vide, 0x18 ); // depth
bo_add_16be( vide, 0xffff ); // predefined
i_chunk_count++;
}
-// if( p_sys->i_pos >= 0xffffffff )
+ /* chunk offset table */
+ if( p_sys->i_pos >= (((uint64_t)0x1) << 32) )
{
+ /* 64 bits version */
bo_t *co64;
bo_t *stsc;
while( i < p_stream->i_entry_count )
{
- if( i + 1 < p_stream->i_entry_count && p_stream->entry[i].i_pos + p_stream->entry[i].i_size != p_stream->entry[i + 1].i_pos )
+ if( i + 1 < p_stream->i_entry_count &&
+ p_stream->entry[i].i_pos + p_stream->entry[i].i_size
+ != p_stream->entry[i + 1].i_pos )
{
i++;
break;
box_fix( stsc );
box_gather( stbl, stsc );
}
-// else
-// {
-// FIXME implement it
-// }
+ else
+ {
+ /* 32 bits version */
+ bo_t *stco;
+ bo_t *stsc;
+
+ unsigned int i_chunk;
+
+ msg_Dbg( p_mux, "creating %d chunk (stco)", i_chunk_count );
+
+ stco = box_full_new( "stco", 0, 0 );
+ bo_add_32be( stco, i_chunk_count );
+
+ stsc = box_full_new( "stsc", 0, 0 );
+ bo_add_32be( stsc, i_chunk_count ); // entry-count
+ for( i_chunk = 0, i = 0; i < p_stream->i_entry_count; i_chunk++ )
+ {
+ int i_first;
+ bo_add_32be( stco, p_stream->entry[i].i_pos );
+
+ i_first = i;
+
+ while( i < p_stream->i_entry_count )
+ {
+ if( i + 1 < p_stream->i_entry_count &&
+ p_stream->entry[i].i_pos + p_stream->entry[i].i_size
+ != p_stream->entry[i + 1].i_pos )
+ {
+ i++;
+ break;
+ }
+
+ i++;
+ }
+ bo_add_32be( stsc, 1 + i_chunk ); // first-chunk
+ bo_add_32be( stsc, i - i_first ) ; // samples-per-chunk
+ bo_add_32be( stsc, 1 ); // sample-descr-index
+ }
+ /* append stco to stbl */
+ box_fix( stco );
+ box_gather( stbl, stco );
+
+ /* append stsc to stbl */
+ box_fix( stsc );
+ box_gather( stbl, stsc );
+ }
/* add stts */
bo_add_8( p_bo, p_mem[i] );
}
}
+
+static void bo_add_descr( bo_t *p_bo, uint8_t tag, uint32_t i_size )
+{
+ uint32_t i_length;
+ uint8_t vals[4];
+
+ i_length = i_size;
+ vals[3] = (unsigned char)(i_length & 0x7f);
+ i_length >>= 7;
+ vals[2] = (unsigned char)((i_length & 0x7f) | 0x80);
+ i_length >>= 7;
+ vals[1] = (unsigned char)((i_length & 0x7f) | 0x80);
+ i_length >>= 7;
+ vals[0] = (unsigned char)((i_length & 0x7f) | 0x80);
+
+ bo_add_8( p_bo, tag );
+
+ if( i_size < 0x00000080 )
+ {
+ bo_add_8( p_bo, vals[3] );
+ }
+ else if( i_size < 0x00004000 )
+ {
+ bo_add_8( p_bo, vals[2] );
+ bo_add_8( p_bo, vals[3] );
+ }
+ else if( i_size < 0x00200000 )
+ {
+ bo_add_8( p_bo, vals[1] );
+ bo_add_8( p_bo, vals[2] );
+ bo_add_8( p_bo, vals[3] );
+ }
+ else if( i_size < 0x10000000 )
+ {
+ bo_add_8( p_bo, vals[0] );
+ bo_add_8( p_bo, vals[1] );
+ bo_add_8( p_bo, vals[2] );
+ bo_add_8( p_bo, vals[3] );
+ }
+}
+
static void bo_add_bo( bo_t *p_bo, bo_t *p_bo2 )
{
int i;