Commit 7102ee9b authored by Gildas Bazin's avatar Gildas Bazin

* modules/mux/mp4.c: mp4 muxer now produces quicktime player readable files....

* modules/mux/mp4.c: mp4 muxer now produces quicktime player readable files. Only works with mpeg4 video and audio right now, also currently won't work when transcoding as the DecoderSpecificInfo is not available.
parent b6e18dc3
/***************************************************************************** /*****************************************************************************
* mp4.c * mp4.c: mp4/mov muxer
***************************************************************************** *****************************************************************************
* Copyright (C) 2001, 2002, 2003 VideoLAN * 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> * Authors: Laurent Aimar <fenrir@via.ecp.fr>
* *
...@@ -117,6 +117,7 @@ static void bo_add_64be ( bo_t *, uint64_t ); ...@@ -117,6 +117,7 @@ static void bo_add_64be ( bo_t *, uint64_t );
static void bo_add_fourcc(bo_t *, char * ); static void bo_add_fourcc(bo_t *, char * );
static void bo_add_bo ( bo_t *, bo_t * ); static void bo_add_bo ( bo_t *, bo_t * );
static void bo_add_mem ( bo_t *, int , uint8_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 ); static void bo_fix_32be ( bo_t *, int , uint32_t );
...@@ -169,6 +170,10 @@ static int Open( vlc_object_t *p_this ) ...@@ -169,6 +170,10 @@ static int Open( vlc_object_t *p_this )
p_sys->i_mdat_pos = p_sys->i_pos; p_sys->i_mdat_pos = p_sys->i_pos;
box_send( p_mux, box ); 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 */ /* Now add mdat header */
...@@ -182,15 +187,16 @@ static int Open( vlc_object_t *p_this ) ...@@ -182,15 +187,16 @@ static int Open( vlc_object_t *p_this )
return VLC_SUCCESS; return VLC_SUCCESS;
} }
static uint32_t GetDescriptorLength24b( int i_length ) static int GetDescrLength( int i_size )
{ {
uint32_t i_l1, i_l2, i_l3; if( i_size < 0x00000080 )
return 2 + i_size;
i_l1 = i_length&0x7f; else if( i_size < 0x00004000 )
i_l2 = ( i_length >> 7 )&0x7f; return 3 + i_size;
i_l3 = ( i_length >> 14 )&0x7f; else if( i_size < 0x00200000 )
return 4 + i_size;
return( 0x808000 | ( i_l3 << 16 ) | ( i_l2 << 8 ) | i_l1 ); else
return 5 + i_size;
} }
static bo_t *GetESDS( mp4_stream_t *p_stream ) static bo_t *GetESDS( mp4_stream_t *p_stream )
...@@ -202,7 +208,8 @@ static bo_t *GetESDS( mp4_stream_t *p_stream ) ...@@ -202,7 +208,8 @@ static bo_t *GetESDS( mp4_stream_t *p_stream )
if( p_stream->p_fmt->i_extra_data > 0 ) 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 else
{ {
...@@ -211,15 +218,15 @@ static bo_t *GetESDS( mp4_stream_t *p_stream ) ...@@ -211,15 +218,15 @@ static bo_t *GetESDS( mp4_stream_t *p_stream )
esds = box_full_new( "esds", 0, 0 ); esds = box_full_new( "esds", 0, 0 );
bo_add_8 ( esds, 0x03 ); // ES_DescrTag /* ES_Descr */
bo_add_24be( esds, bo_add_descr( esds, 0x03, 3 +
GetDescriptorLength24b( 25 + i_decoder_specific_info_size ) ); GetDescrLength( 13 + i_decoder_specific_info_size ) +
GetDescrLength( 1 ) );
bo_add_16be( esds, p_stream->i_track_id ); bo_add_16be( esds, p_stream->i_track_id );
bo_add_8 ( esds, 0x1f ); // flags=0|streamPriority=0x1f bo_add_8 ( esds, 0x1f ); // flags=0|streamPriority=0x1f
bo_add_8 ( esds, 0x04 ); // DecoderConfigDescrTag /* DecoderConfigDescr */
bo_add_24be( esds, bo_add_descr( esds, 0x04, 13 + i_decoder_specific_info_size );
GetDescriptorLength24b( 13 + i_decoder_specific_info_size ) );
switch( p_stream->p_fmt->i_fourcc ) switch( p_stream->p_fmt->i_fourcc )
{ {
...@@ -253,9 +260,9 @@ static bo_t *GetESDS( mp4_stream_t *p_stream ) ...@@ -253,9 +260,9 @@ static bo_t *GetESDS( mp4_stream_t *p_stream )
if( p_stream->p_fmt->i_extra_data > 0 ) if( p_stream->p_fmt->i_extra_data > 0 )
{ {
int i; int i;
bo_add_8 ( esds, 0x05 ); // DecoderSpecificInfo
bo_add_24be( esds, /* DecoderSpecificInfo */
GetDescriptorLength24b( p_stream->p_fmt->i_extra_data ) ); bo_add_descr( esds, 0x05, p_stream->p_fmt->i_extra_data );
for( i = 0; i < p_stream->p_fmt->i_extra_data; i++ ) for( i = 0; i < p_stream->p_fmt->i_extra_data; i++ )
{ {
...@@ -264,8 +271,7 @@ static bo_t *GetESDS( mp4_stream_t *p_stream ) ...@@ -264,8 +271,7 @@ static bo_t *GetESDS( mp4_stream_t *p_stream )
} }
/* SL_Descr mandatory */ /* SL_Descr mandatory */
bo_add_8 ( esds, 0x06 ); // SLConfigDescriptorTag bo_add_descr( esds, 0x06, 1 );
bo_add_24be( esds, GetDescriptorLength24b( 1 ) );
bo_add_8 ( esds, 0x02 ); // sl_predefined bo_add_8 ( esds, 0x02 ); // sl_predefined
box_fix( esds ); box_fix( esds );
...@@ -480,7 +486,7 @@ static void Close( vlc_object_t * p_this ) ...@@ -480,7 +486,7 @@ static void Close( vlc_object_t * p_this )
/* *** add /moov/trak/mdia *** */ /* *** add /moov/trak/mdia *** */
mdia = box_new( "mdia" ); mdia = box_new( "mdia" );
/* */ /* media header */
if( p_sys->b_mov ) if( p_sys->b_mov )
{ {
mdhd = box_full_new( "mdhd", 0, 0 ); mdhd = box_full_new( "mdhd", 0, 0 );
...@@ -505,9 +511,10 @@ static void Close( vlc_object_t * p_this ) ...@@ -505,9 +511,10 @@ static void Close( vlc_object_t * p_this )
box_fix( mdhd ); box_fix( mdhd );
box_gather( mdia, mdhd ); box_gather( mdia, mdhd );
/* */ /* handler reference */
hdlr = box_full_new( "hdlr", 0, 0 ); 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 ) if( p_stream->p_fmt->i_cat == AUDIO_ES )
{ {
bo_add_fourcc( hdlr, "soun" ); bo_add_fourcc( hdlr, "soun" );
...@@ -516,11 +523,19 @@ static void Close( vlc_object_t * p_this ) ...@@ -516,11 +523,19 @@ static void Close( vlc_object_t * p_this )
{ {
bo_add_fourcc( hdlr, "vide" ); 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
bo_add_32be( hdlr, 0 ); // reserved
if( p_stream->p_fmt->i_cat == AUDIO_ES )
{
bo_add_mem( hdlr, 13, "SoundHandler" );
}
else
{
bo_add_mem( hdlr, 13, "VideoHandler" );
} }
bo_add_mem( hdlr, 2, "?" );
box_fix( hdlr ); box_fix( hdlr );
box_gather( mdia, hdlr ); box_gather( mdia, hdlr );
...@@ -608,12 +623,15 @@ static void Close( vlc_object_t * p_this ) ...@@ -608,12 +623,15 @@ static void Close( vlc_object_t * p_this )
bo_add_8( soun, 0 ); // reserved; bo_add_8( soun, 0 ); // reserved;
} }
bo_add_16be( soun, 1 ); // data-reference-index 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, p_stream->p_fmt->i_channels ); // channel-count
bo_add_16be( soun, 16); // FIXME sample size bo_add_16be( soun, 16); // FIXME sample size
bo_add_16be( soun, 0 ); // predefined bo_add_16be( soun, -2 ); // compression id
bo_add_16be( soun, 0 ); // reserved bo_add_16be( soun, 0 ); // packet size (0)
bo_add_16be( soun, p_stream->p_fmt->i_sample_rate ); // sampleratehi bo_add_16be( soun, p_stream->p_fmt->i_sample_rate ); // sampleratehi
bo_add_16be( soun, 0 ); // sampleratelo bo_add_16be( soun, 0 ); // sampleratelo
...@@ -677,12 +695,15 @@ static void Close( vlc_object_t * p_this ) ...@@ -677,12 +695,15 @@ static void Close( vlc_object_t * p_this )
bo_add_32be( vide, 0x00480000 ); // h 72dpi bo_add_32be( vide, 0x00480000 ); // h 72dpi
bo_add_32be( vide, 0x00480000 ); // v 72dpi bo_add_32be( vide, 0x00480000 ); // v 72dpi
bo_add_32be( vide, 0 ); // reserved bo_add_32be( vide, 0 ); // data size, always 0
bo_add_16be( vide, 1 ); // predefined bo_add_16be( vide, 1 ); // frames count per sample
// compressor name;
for( i = 0; i < 32; i++ ) 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, 0x18 ); // depth
bo_add_16be( vide, 0xffff ); // predefined bo_add_16be( vide, 0xffff ); // predefined
...@@ -724,8 +745,10 @@ static void Close( vlc_object_t * p_this ) ...@@ -724,8 +745,10 @@ static void Close( vlc_object_t * p_this )
i_chunk_count++; 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 *co64;
bo_t *stsc; bo_t *stsc;
...@@ -747,7 +770,9 @@ static void Close( vlc_object_t * p_this ) ...@@ -747,7 +770,9 @@ static void Close( vlc_object_t * p_this )
while( i < p_stream->i_entry_count ) 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++; i++;
break; break;
...@@ -767,10 +792,52 @@ static void Close( vlc_object_t * p_this ) ...@@ -767,10 +792,52 @@ static void Close( vlc_object_t * p_this )
box_fix( stsc ); box_fix( stsc );
box_gather( stbl, stsc ); box_gather( stbl, stsc );
} }
// else else
// { {
// FIXME implement it /* 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 */ /* add stts */
...@@ -1102,6 +1169,47 @@ static void bo_add_mem( bo_t *p_bo, int i_size, uint8_t *p_mem ) ...@@ -1102,6 +1169,47 @@ static void bo_add_mem( bo_t *p_bo, int i_size, uint8_t *p_mem )
bo_add_8( p_bo, p_mem[i] ); 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 ) static void bo_add_bo( bo_t *p_bo, bo_t *p_bo2 )
{ {
int i; int i;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment