Commit d758eadc authored by Gildas Bazin's avatar Gildas Bazin

* modules/mux/mp4.c: store the display size using the proper aspect-ratio.
   Size optimization for the generation of the stsc table.
   Some more clean-up.
parent 2150d8db
......@@ -2,7 +2,7 @@
* mp4.c: mp4/mov muxer
*****************************************************************************
* Copyright (C) 2001, 2002, 2003 VideoLAN
* $Id: mp4.c,v 1.10 2004/01/23 17:56:14 gbazin Exp $
* $Id: mp4.c,v 1.11 2004/01/24 11:56:16 gbazin Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin at videolan dot org>
......@@ -392,306 +392,30 @@ static bo_t *GetUdtaTag( sout_mux_t *p_mux )
return udta;
}
static uint32_t mvhd_matrix[9] =
{ 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
static bo_t *GetMoovTag( sout_mux_t *p_mux )
static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
{
sout_mux_sys_t *p_sys = p_mux->p_sys;
bo_t *moov, *mvhd;
unsigned int i;
int i_trak, i_index;
uint32_t i_movie_timescale = 90000;
int64_t i_movie_duration = 0;
moov = box_new( "moov" );
/* *** add /moov/mvhd *** */
if( !p_sys->b_64_ext )
{
mvhd = box_full_new( "mvhd", 0, 0 );
bo_add_32be( mvhd, get_timestamp() ); // creation time
bo_add_32be( mvhd, get_timestamp() ); // modification time
bo_add_32be( mvhd, i_movie_timescale); // timescale
bo_add_32be( mvhd, i_movie_duration ); // duration
}
else
{
mvhd = box_full_new( "mvhd", 1, 0 );
bo_add_64be( mvhd, get_timestamp() ); // creation time
bo_add_64be( mvhd, get_timestamp() ); // modification time
bo_add_32be( mvhd, i_movie_timescale); // timescale
bo_add_64be( mvhd, i_movie_duration ); // duration
}
bo_add_32be( mvhd, 0x10000 ); // rate
bo_add_16be( mvhd, 0x100 ); // volume
bo_add_16be( mvhd, 0 ); // reserved
for( i = 0; i < 2; i++ )
{
bo_add_32be( mvhd, 0 ); // reserved
}
for( i = 0; i < 9; i++ )
{
bo_add_32be( mvhd, mvhd_matrix[i] );// matrix
}
for( i = 0; i < 6; i++ )
{
bo_add_32be( mvhd, 0 ); // pre-defined
}
/* Find the 1st track id */
for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
{
mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
if( p_stream->p_fmt->i_cat == AUDIO_ES ||
p_stream->p_fmt->i_cat == VIDEO_ES )
{
/* Found it */
bo_add_32be( mvhd, p_stream->i_track_id ); // next-track-id
break;
}
}
if( i_trak == p_sys->i_nb_streams ) /* Just for sanity reasons */
bo_add_32be( mvhd, 0xffffffff );
box_fix( mvhd );
box_gather( moov, mvhd );
for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
{
mp4_stream_t *p_stream;
uint32_t i_timescale;
uint32_t i_chunk_count;
unsigned int i_chunk;
bo_t *trak;
bo_t *tkhd;
bo_t *mdia;
bo_t *mdhd, *hdlr;
bo_t *minf;
bo_t *dinf;
bo_t *dref;
bo_t *url;
bo_t *stbl;
bo_t *stsd;
bo_t *stts;
bo_t *stco;
bo_t *stsc;
bo_t *stsz;
p_stream = p_sys->pp_streams[i_trak];
if( p_stream->p_fmt->i_cat != AUDIO_ES &&
p_stream->p_fmt->i_cat != VIDEO_ES )
{
msg_Err( p_mux, "FIXME ignoring trak (noaudio&&novideo)" );
continue;
}
if( p_stream->p_fmt->i_cat == AUDIO_ES )
{
i_timescale = p_stream->p_fmt->audio.i_rate;
}
else
{
i_timescale = 1001;
}
/* *** add /moov/trak *** */
trak = box_new( "trak" );
/* *** add /moov/trak/tkhd *** */
if( !p_sys->b_64_ext )
{
if( p_sys->b_mov )
tkhd = box_full_new( "tkhd", 0, 0x0f );
else
tkhd = box_full_new( "tkhd", 0, 1 );
bo_add_32be( tkhd, get_timestamp() ); // creation time
bo_add_32be( tkhd, get_timestamp() ); // modification time
bo_add_32be( tkhd, p_stream->i_track_id );
bo_add_32be( tkhd, 0 ); // reserved 0
bo_add_32be( tkhd, p_stream->i_duration *
(int64_t)i_movie_timescale /
(mtime_t)1000000 ); // duration
}
else
{
if( p_sys->b_mov )
tkhd = box_full_new( "tkhd", 1, 0x0f );
else
tkhd = box_full_new( "tkhd", 1, 1 );
bo_add_64be( tkhd, get_timestamp() ); // creation time
bo_add_64be( tkhd, get_timestamp() ); // modification time
bo_add_32be( tkhd, p_stream->i_track_id );
bo_add_32be( tkhd, 0 ); // reserved 0
bo_add_64be( tkhd, p_stream->i_duration *
(int64_t)i_movie_timescale /
(mtime_t)1000000 ); // duration
}
for( i = 0; i < 2; i++ )
{
bo_add_32be( tkhd, 0 ); // reserved
}
bo_add_16be( tkhd, 0 ); // layer
bo_add_16be( tkhd, 0 ); // pre-defined
bo_add_16be( tkhd, p_stream->p_fmt->i_cat == AUDIO_ES ? 0x100 : 0 ); // volume
bo_add_16be( tkhd, 0 ); // reserved
for( i = 0; i < 9; i++ )
{
bo_add_32be( tkhd, mvhd_matrix[i] ); // matrix
}
if( p_stream->p_fmt->i_cat == AUDIO_ES )
{
bo_add_32be( tkhd, 0 ); // width (presentation)
bo_add_32be( tkhd, 0 ); // height(presentation)
}
else
{
bo_add_32be( tkhd, p_stream->p_fmt->video.i_width << 16 ); // width (presentation)
bo_add_32be( tkhd, p_stream->p_fmt->video.i_height << 16 ); // height(presentation)
}
box_fix( tkhd );
box_gather( trak, tkhd );
/* *** add /moov/trak/mdia *** */
mdia = box_new( "mdia" );
/* media header */
if( !p_sys->b_64_ext )
{
mdhd = box_full_new( "mdhd", 0, 0 );
bo_add_32be( mdhd, get_timestamp() ); // creation time
bo_add_32be( mdhd, get_timestamp() ); // modification time
bo_add_32be( mdhd, i_timescale); // timescale
bo_add_32be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
(mtime_t)1000000 ); // duration
}
else
{
mdhd = box_full_new( "mdhd", 1, 0 );
bo_add_64be( mdhd, get_timestamp() ); // creation time
bo_add_64be( mdhd, get_timestamp() ); // modification time
bo_add_32be( mdhd, i_timescale); // timescale
bo_add_64be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
(mtime_t)1000000 ); // duration
}
bo_add_16be( mdhd, 0 ); // language FIXME
bo_add_16be( mdhd, 0 ); // predefined
box_fix( mdhd );
box_gather( mdia, mdhd );
/* handler reference */
hdlr = box_full_new( "hdlr", 0, 0 );
bo_add_fourcc( hdlr, "mhlr" ); // media handler
if( p_stream->p_fmt->i_cat == AUDIO_ES )
{
bo_add_fourcc( hdlr, "soun" );
}
else
{
bo_add_fourcc( hdlr, "vide" );
}
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_8( hdlr, 13 );
bo_add_mem( hdlr, 13, "SoundHandler" );
}
else
{
bo_add_8( hdlr, 13 );
bo_add_mem( hdlr, 13, "VideoHandler" );
}
box_fix( hdlr );
box_gather( mdia, hdlr );
/* minf*/
minf = box_new( "minf" );
/* add smhd|vmhd */
if( p_stream->p_fmt->i_cat == AUDIO_ES )
{
bo_t *smhd;
smhd = box_full_new( "smhd", 0, 0 );
bo_add_16be( smhd, 0 ); // balance
bo_add_16be( smhd, 0 ); // reserved
box_fix( smhd );
box_gather( minf, smhd );
}
else if( p_stream->p_fmt->i_cat == VIDEO_ES )
{
bo_t *vmhd;
vmhd = box_full_new( "vmhd", 0, 1 );
bo_add_16be( vmhd, 0 ); // graphicsmode
for( i = 0; i < 3; i++ )
{
bo_add_16be( vmhd, 0 ); // opcolor
}
box_fix( vmhd );
box_gather( minf, vmhd );
}
/* dinf */
dinf = box_new( "dinf" );
dref = box_full_new( "dref", 0, 0 );
bo_add_32be( dref, 1 );
url = box_full_new( "url ", 0, 0x01 );
box_fix( url );
box_gather( dref, url );
box_fix( dref );
box_gather( dinf, dref );
/* append dinf to mdia */
box_fix( dinf );
box_gather( minf, dinf );
/* add stbl */
stbl = box_new( "stbl" );
stsd = box_full_new( "stsd", 0, 0 );
bo_add_32be( stsd, 1 );
if( p_stream->p_fmt->i_cat == AUDIO_ES )
{
vlc_bool_t b_descr = VLC_FALSE;
bo_t *soun;
char fcc[4] = " ";
int i;
vlc_bool_t b_mpeg4_hdr;
switch( p_stream->p_fmt->i_codec )
{
case VLC_FOURCC( 'm', 'p', '4', 'a' ):
case VLC_FOURCC('m','p','4','a'):
memcpy( fcc, "mp4a", 4 );
b_mpeg4_hdr = VLC_TRUE;
b_descr = VLC_TRUE;
break;
case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
case VLC_FOURCC('m','p','g','a'):
if( p_sys->b_mov )
memcpy( fcc, ".mp3 ", 4 );
memcpy( fcc, ".mp3", 4 );
else
memcpy( fcc, "mp4a", 4 );
b_mpeg4_hdr = VLC_FALSE;
break;
default:
memcpy( fcc, (char*)&p_stream->p_fmt->i_codec, 4 );
b_mpeg4_hdr = VLC_FALSE;
break;
}
......@@ -704,7 +428,7 @@ static bo_t *GetMoovTag( sout_mux_t *p_mux )
/* SoundDescription */
if( p_sys->b_mov &&
p_stream->p_fmt->i_codec == VLC_FOURCC( 'm', 'p', '4', 'a' ) )
p_stream->p_fmt->i_codec == VLC_FOURCC('m','p','4','a') )
{
bo_add_16be( soun, 1 ); // version 1;
}
......@@ -714,7 +438,8 @@ static bo_t *GetMoovTag( sout_mux_t *p_mux )
}
bo_add_16be( soun, 0 ); // revision level (0)
bo_add_32be( soun, 0 ); // vendor
bo_add_16be( soun, p_stream->p_fmt->audio.i_channels ); // channel-count
// channel-count
bo_add_16be( soun, p_stream->p_fmt->audio.i_channels );
// sample size
bo_add_16be( soun, p_stream->p_fmt->audio.i_bitspersample ?
p_stream->p_fmt->audio.i_bitspersample : 16 );
......@@ -725,17 +450,18 @@ static bo_t *GetMoovTag( sout_mux_t *p_mux )
/* Extended data for SoundDescription V1 */
if( p_sys->b_mov &&
p_stream->p_fmt->i_codec == VLC_FOURCC( 'm', 'p', '4', 'a' ) )
p_stream->p_fmt->i_codec == VLC_FOURCC('m','p','4','a') )
{
bo_add_32be( soun, p_stream->p_fmt->audio.i_frame_length ); /* samples per packet */
/* samples per packet */
bo_add_32be( soun, p_stream->p_fmt->audio.i_frame_length );
bo_add_32be( soun, 1536 ); /* bytes per packet */
bo_add_32be( soun, 2 ); /* bytes per frame */
/* bytes per sample */
bo_add_32be( soun, 2 /*p_stream->p_fmt->audio.i_bitspersample/8 */);
}
/* add an ES Descriptor */
if( b_mpeg4_hdr )
/* Add an ES Descriptor */
if( b_descr )
{
bo_t *box;
......@@ -753,26 +479,29 @@ static bo_t *GetMoovTag( sout_mux_t *p_mux )
}
box_fix( soun );
box_gather( stsd, soun );
}
else if( p_stream->p_fmt->i_cat == VIDEO_ES )
{
return soun;
}
static bo_t *GetVideBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
{
bo_t *vide;
char fcc[4] = " ";
int i;
switch( p_stream->p_fmt->i_codec )
{
case VLC_FOURCC( 'm', 'p', '4', 'v' ):
case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
case VLC_FOURCC('m','p','4','v'):
case VLC_FOURCC('m','p','g','v'):
memcpy( fcc, "mp4v", 4 );
break;
case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
case VLC_FOURCC('M','J','P','G'):
memcpy( fcc, "mjpa", 4 );
break;
case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
case VLC_FOURCC('S','V','Q','3'):
memcpy( fcc, "SVQ3", 4 );
break;
......@@ -792,186 +521,471 @@ static bo_t *GetMoovTag( sout_mux_t *p_mux )
bo_add_16be( vide, 0 ); // reserved;
for( i = 0; i < 3; i++ )
{
bo_add_32be( vide, 0 ); // predefined;
bo_add_32be( vide, 0 ); // predefined;
}
bo_add_16be( vide, p_stream->p_fmt->video.i_width ); // i_width
bo_add_16be( vide, p_stream->p_fmt->video.i_height ); // i_height
bo_add_32be( vide, 0x00480000 ); // h 72dpi
bo_add_32be( vide, 0x00480000 ); // v 72dpi
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 );
}
bo_add_16be( vide, 0x18 ); // depth
bo_add_16be( vide, 0xffff ); // predefined
/* add an ES Descriptor */
switch( p_stream->p_fmt->i_codec )
{
case VLC_FOURCC('m','p','4','v'):
case VLC_FOURCC('m','p','g','v'):
{
bo_t *esds = GetESDS( p_stream );
box_fix( esds );
box_gather( vide, esds );
}
break;
case VLC_FOURCC('S','V','Q','3'):
{
bo_t *esds = GetSVQ3Tag( p_stream );
box_fix( esds );
box_gather( vide, esds );
}
break;
default:
break;
}
box_fix( vide );
return vide;
}
static bo_t *GetStblBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
{
sout_mux_sys_t *p_sys = p_mux->p_sys;
unsigned int i_chunk, i_stsc_last_val, i_stsc_entries, i, i_index;
bo_t *stbl, *stsd, *stts, *stco, *stsc, *stsz;
uint32_t i_timescale;
stbl = box_new( "stbl" );
stsd = box_full_new( "stsd", 0, 0 );
bo_add_32be( stsd, 1 );
if( p_stream->p_fmt->i_cat == AUDIO_ES )
{
bo_t *soun = GetSounBox( p_mux, p_stream );
box_gather( stsd, soun );
}
else if( p_stream->p_fmt->i_cat == VIDEO_ES )
{
bo_t *vide = GetVideBox( p_mux, p_stream );
box_gather( stsd, vide );
}
/* append stsd to stbl */
box_fix( stsd );
box_gather( stbl, stsd );
/* chunk offset table */
p_stream->i_stco_pos = stbl->i_buffer + 16;
if( p_sys->i_pos >= (((uint64_t)0x1) << 32) )
{
/* 64 bits version */
p_stream->b_stco64 = VLC_TRUE;
stco = box_full_new( "co64", 0, 0 );
}
else
{
/* 32 bits version */
p_stream->b_stco64 = VLC_FALSE;
stco = box_full_new( "stco", 0, 0 );
}
bo_add_32be( stco, 0 ); // entry-count (fixed latter)
/* sample to chunk table */
stsc = box_full_new( "stsc", 0, 0 );
bo_add_32be( stsc, 0 ); // entry-count (fixed latter)
for( i_chunk = 0, i_stsc_last_val = 0, i_stsc_entries = 0, i = 0;
i < p_stream->i_entry_count; i_chunk++ )
{
int i_first = i;
if( p_stream->b_stco64 )
bo_add_64be( stco, p_stream->entry[i].i_pos );
else
bo_add_32be( stco, p_stream->entry[i].i_pos );
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++;
}
/* Add entry to the stsc table */
if( i_stsc_last_val != i - i_first )
{
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
i_stsc_last_val = i - i_first;
i_stsc_entries++;
}
}
/* Fix stco entry count */
bo_fix_32be( stco, 12, i_chunk );
msg_Dbg( p_mux, "created %d chunks (stco)", i_chunk );
/* append stco to stbl */
box_fix( stco );
box_gather( stbl, stco );
/* Fix stsc entry count */
bo_fix_32be( stsc, 12, i_stsc_entries );
/* append stsc to stbl */
box_fix( stsc );
box_gather( stbl, stsc );
/* add stts */
stts = box_full_new( "stts", 0, 0 );
bo_add_32be( stts, 0 ); // entry-count (fixed latter)
if( p_stream->p_fmt->i_cat == AUDIO_ES )
i_timescale = p_stream->p_fmt->audio.i_rate;
else
i_timescale = 1001;
for( i = 0, i_index = 0; i < p_stream->i_entry_count; i_index++)
{
int64_t i_delta;
int i_first;
i_first = i;
i_delta = p_stream->entry[i].i_length;
while( i < p_stream->i_entry_count )
{
if( i + 1 < p_stream->i_entry_count &&
p_stream->entry[i + 1].i_length != i_delta )
{
i++;
break;
}
i++;
}
bo_add_32be( stts, i - i_first ); // sample-count
bo_add_32be( stts, i_delta * (int64_t)i_timescale /
(int64_t)1000000 ); // sample-delta
}
bo_fix_32be( stts, 12, i_index );
/* append stts to stbl */
box_fix( stts );
box_gather( stbl, stts );
/* FIXME add ctts ?? FIXME */
stsz = box_full_new( "stsz", 0, 0 );
bo_add_32be( stsz, 0 ); // sample-size
bo_add_32be( stsz, p_stream->i_entry_count ); // sample-count
for( i = 0; i < p_stream->i_entry_count; i++ )
{
bo_add_32be( stsz, p_stream->entry[i].i_size ); // sample-size
}
/* append stsz to stbl */
box_fix( stsz );
box_gather( stbl, stsz );
box_fix( stbl );
return stbl;
}
static uint32_t mvhd_matrix[9] =
{ 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
static bo_t *GetMoovBox( sout_mux_t *p_mux )
{
sout_mux_sys_t *p_sys = p_mux->p_sys;
bo_t *moov, *mvhd;
int i_trak, i;
uint32_t i_movie_timescale = 90000;
int64_t i_movie_duration = 0;
moov = box_new( "moov" );
/* *** add /moov/mvhd *** */
if( !p_sys->b_64_ext )
{
mvhd = box_full_new( "mvhd", 0, 0 );
bo_add_32be( mvhd, get_timestamp() ); // creation time
bo_add_32be( mvhd, get_timestamp() ); // modification time
bo_add_32be( mvhd, i_movie_timescale); // timescale
bo_add_32be( mvhd, i_movie_duration ); // duration
}
else
{
mvhd = box_full_new( "mvhd", 1, 0 );
bo_add_64be( mvhd, get_timestamp() ); // creation time
bo_add_64be( mvhd, get_timestamp() ); // modification time
bo_add_32be( mvhd, i_movie_timescale); // timescale
bo_add_64be( mvhd, i_movie_duration ); // duration
}
bo_add_32be( mvhd, 0x10000 ); // rate
bo_add_16be( mvhd, 0x100 ); // volume
bo_add_16be( mvhd, 0 ); // reserved
for( i = 0; i < 2; i++ )
{
bo_add_32be( mvhd, 0 ); // reserved
}
for( i = 0; i < 9; i++ )
{
bo_add_32be( mvhd, mvhd_matrix[i] );// matrix
}
for( i = 0; i < 6; i++ )
{
bo_add_32be( mvhd, 0 ); // pre-defined
}
/* Find the 1st track id */
for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
{
mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
if( p_stream->p_fmt->i_cat == AUDIO_ES ||
p_stream->p_fmt->i_cat == VIDEO_ES )
{
/* Found it */
bo_add_32be( mvhd, p_stream->i_track_id ); // next-track-id
break;
}
}
if( i_trak == p_sys->i_nb_streams ) /* Just for sanity reasons */
bo_add_32be( mvhd, 0xffffffff );
bo_add_16be( vide, p_stream->p_fmt->video.i_width ); // i_width
bo_add_16be( vide, p_stream->p_fmt->video.i_height ); // i_height
box_fix( mvhd );
box_gather( moov, mvhd );
bo_add_32be( vide, 0x00480000 ); // h 72dpi
bo_add_32be( vide, 0x00480000 ); // v 72dpi
for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
{
mp4_stream_t *p_stream;
uint32_t i_timescale;
bo_add_32be( vide, 0 ); // data size, always 0
bo_add_16be( vide, 1 ); // frames count per sample
bo_t *trak, *tkhd, *mdia, *mdhd, *hdlr;
bo_t *minf, *dinf, *dref, *url, *stbl;
// compressor name;
for( i = 0; i < 32; i++ )
p_stream = p_sys->pp_streams[i_trak];
if( p_stream->p_fmt->i_cat != AUDIO_ES &&
p_stream->p_fmt->i_cat != VIDEO_ES )
{
bo_add_8( vide, 0 );
msg_Err( p_mux, "FIXME ignoring trak (noaudio&&novideo)" );
continue;
}
bo_add_16be( vide, 0x18 ); // depth
bo_add_16be( vide, 0xffff ); // predefined
/* add an ES Descriptor */
switch( p_stream->p_fmt->i_codec )
{
case VLC_FOURCC( 'm', 'p', '4', 'v' ):
case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
{
bo_t *esds = GetESDS( p_stream );
if( p_stream->p_fmt->i_cat == AUDIO_ES )
i_timescale = p_stream->p_fmt->audio.i_rate;
else
i_timescale = 1001;
box_fix( esds );
box_gather( vide, esds );
}
break;
/* *** add /moov/trak *** */
trak = box_new( "trak" );
case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
/* *** add /moov/trak/tkhd *** */
if( !p_sys->b_64_ext )
{
bo_t *esds = GetSVQ3Tag( p_stream );
if( p_sys->b_mov )
tkhd = box_full_new( "tkhd", 0, 0x0f );
else
tkhd = box_full_new( "tkhd", 0, 1 );
box_fix( esds );
box_gather( vide, esds );
bo_add_32be( tkhd, get_timestamp() ); // creation time
bo_add_32be( tkhd, get_timestamp() ); // modification time
bo_add_32be( tkhd, p_stream->i_track_id );
bo_add_32be( tkhd, 0 ); // reserved 0
bo_add_32be( tkhd, p_stream->i_duration *
(int64_t)i_movie_timescale /
(mtime_t)1000000 ); // duration
}
break;
else
{
if( p_sys->b_mov )
tkhd = box_full_new( "tkhd", 1, 0x0f );
else
tkhd = box_full_new( "tkhd", 1, 1 );
default:
break;
bo_add_64be( tkhd, get_timestamp() ); // creation time
bo_add_64be( tkhd, get_timestamp() ); // modification time
bo_add_32be( tkhd, p_stream->i_track_id );
bo_add_32be( tkhd, 0 ); // reserved 0
bo_add_64be( tkhd, p_stream->i_duration *
(int64_t)i_movie_timescale /
(mtime_t)1000000 ); // duration
}
box_fix( vide );
box_gather( stsd, vide );
for( i = 0; i < 2; i++ )
{
bo_add_32be( tkhd, 0 ); // reserved
}
/* append stsd to stbl */
box_fix( stsd );
box_gather( stbl, stsd );
/* we will create chunk table and stsc table
* FIXME optim stsc table FIXME */
i_chunk_count = 0;
for( i = 0; i < p_stream->i_entry_count; )
bo_add_16be( tkhd, 0 ); // layer
bo_add_16be( tkhd, 0 ); // pre-defined
// volume
bo_add_16be( tkhd, p_stream->p_fmt->i_cat == AUDIO_ES ? 0x100 : 0 );
bo_add_16be( tkhd, 0 ); // reserved
for( i = 0; i < 9; i++ )
{
while( i < p_stream->i_entry_count )
bo_add_32be( tkhd, mvhd_matrix[i] ); // matrix
}
if( p_stream->p_fmt->i_cat == AUDIO_ES )
{
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 )
bo_add_32be( tkhd, 0 ); // width (presentation)
bo_add_32be( tkhd, 0 ); // height(presentation)
}
else
{
i++;
break;
// width (presentation)
bo_add_32be( tkhd, p_stream->p_fmt->video.i_aspect *
p_stream->p_fmt->video.i_height /
VOUT_ASPECT_FACTOR << 16 );
// height(presentation)
bo_add_32be( tkhd, p_stream->p_fmt->video.i_height << 16 );
}
box_fix( tkhd );
box_gather( trak, tkhd );
i++;
}
i_chunk_count++;
}
/* *** add /moov/trak/mdia *** */
mdia = box_new( "mdia" );
/* chunk offset table */
p_stream->i_stco_pos = stbl->i_buffer + 16;
if( p_sys->i_pos >= (((uint64_t)0x1) << 32) )
/* media header */
if( !p_sys->b_64_ext )
{
/* 64 bits version */
msg_Dbg( p_mux, "creating %d chunk (co64)", i_chunk_count );
p_stream->b_stco64 = VLC_TRUE;
stco = box_full_new( "co64", 0, 0 );
mdhd = box_full_new( "mdhd", 0, 0 );
bo_add_32be( mdhd, get_timestamp() ); // creation time
bo_add_32be( mdhd, get_timestamp() ); // modification time
bo_add_32be( mdhd, i_timescale); // timescale
bo_add_32be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
(mtime_t)1000000 ); // duration
}
else
{
/* 32 bits version */
msg_Dbg( p_mux, "creating %d chunk (stco)", i_chunk_count );
p_stream->b_stco64 = VLC_FALSE;
stco = box_full_new( "stco", 0, 0 );
mdhd = box_full_new( "mdhd", 1, 0 );
bo_add_64be( mdhd, get_timestamp() ); // creation time
bo_add_64be( mdhd, get_timestamp() ); // modification time
bo_add_32be( mdhd, i_timescale); // timescale
bo_add_64be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
(mtime_t)1000000 ); // duration
}
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;
if( p_stream->b_stco64 )
bo_add_64be( stco, p_stream->entry[i].i_pos );
else
bo_add_32be( stco, p_stream->entry[i].i_pos );
bo_add_16be( mdhd, 0 ); // language FIXME
bo_add_16be( mdhd, 0 ); // predefined
box_fix( mdhd );
box_gather( mdia, mdhd );
i_first = i;
/* handler reference */
hdlr = box_full_new( "hdlr", 0, 0 );
while( i < p_stream->i_entry_count )
bo_add_fourcc( hdlr, "mhlr" ); // media handler
if( p_stream->p_fmt->i_cat == AUDIO_ES )
{
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 )
bo_add_fourcc( hdlr, "soun" );
}
else
{
i++;
break;
bo_add_fourcc( hdlr, "vide" );
}
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_8( hdlr, 13 );
bo_add_mem( hdlr, 13, "SoundHandler" );
}
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
else
{
bo_add_8( hdlr, 13 );
bo_add_mem( hdlr, 13, "VideoHandler" );
}
/* append stco to stbl */
box_fix( stco );
box_gather( stbl, stco );
box_fix( hdlr );
box_gather( mdia, hdlr );
/* append stsc to stbl */
box_fix( stsc );
box_gather( stbl, stsc );
/* minf*/
minf = box_new( "minf" );
/* add stts */
stts = box_full_new( "stts", 0, 0 );
bo_add_32be( stts, 0 ); // fixed latter
for( i = 0, i_index = 0; i < p_stream->i_entry_count; i_index++)
/* add smhd|vmhd */
if( p_stream->p_fmt->i_cat == AUDIO_ES )
{
int64_t i_delta;
int i_first;
bo_t *smhd;
i_first = i;
i_delta = p_stream->entry[i].i_length;
smhd = box_full_new( "smhd", 0, 0 );
bo_add_16be( smhd, 0 ); // balance
bo_add_16be( smhd, 0 ); // reserved
box_fix( smhd );
while( i < p_stream->i_entry_count )
{
if( i + 1 < p_stream->i_entry_count &&
p_stream->entry[i + 1].i_length != i_delta )
{
i++;
break;
box_gather( minf, smhd );
}
else if( p_stream->p_fmt->i_cat == VIDEO_ES )
{
bo_t *vmhd;
i++;
vmhd = box_full_new( "vmhd", 0, 1 );
bo_add_16be( vmhd, 0 ); // graphicsmode
for( i = 0; i < 3; i++ )
{
bo_add_16be( vmhd, 0 ); // opcolor
}
box_fix( vmhd );
bo_add_32be( stts, i - i_first ); // sample-count
bo_add_32be( stts, i_delta * (int64_t)i_timescale /
(int64_t)1000000 ); // sample-delta
box_gather( minf, vmhd );
}
bo_fix_32be( stts, 12, i_index );
/* append stts to stbl */
box_fix( stts );
box_gather( stbl, stts );
/* dinf */
dinf = box_new( "dinf" );
dref = box_full_new( "dref", 0, 0 );
bo_add_32be( dref, 1 );
url = box_full_new( "url ", 0, 0x01 );
box_fix( url );
box_gather( dref, url );
box_fix( dref );
box_gather( dinf, dref );
/* FIXME add ctts ?? FIXME */
/* append dinf to mdia */
box_fix( dinf );
box_gather( minf, dinf );
stsz = box_full_new( "stsz", 0, 0 );
bo_add_32be( stsz, 0 ); // sample-size
bo_add_32be( stsz, p_stream->i_entry_count ); // sample-count
for( i = 0; i < p_stream->i_entry_count; i++ )
{
bo_add_32be( stsz, p_stream->entry[i].i_size ); // sample-size
}
/* append stsz to stbl */
box_fix( stsz );
box_gather( stbl, stsz );
/* add stbl */
stbl = GetStblBox( p_mux, p_stream );
/* append stbl to minf */
box_fix( stbl );
p_stream->i_stco_pos += minf->i_buffer;
box_gather( minf, stbl );
......@@ -1052,7 +1066,7 @@ static void Close( vlc_object_t * p_this )
/* Create MOOV header */
i_moov_pos = p_sys->i_pos;
moov = GetMoovTag( p_mux );
moov = GetMoovBox( p_mux );
/* Check we need to create "fast start" files */
var_Create( p_this, "mp4-faststart", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
......@@ -1273,7 +1287,6 @@ static int Mux( sout_mux_t *p_mux )
p_stream = (mp4_stream_t*)p_input->p_sys;
p_data = sout_FifoGet( p_input->p_fifo );
//msg_Dbg( p_mux, "stream=%d size=%6d pos=%8lld", i_stream, p_data->i_size, p_sys->i_pos );
/* add index entry */
p_stream->entry[p_stream->i_entry_count].i_pos = p_sys->i_pos;
......
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