]> git.sesse.net Git - vlc/blobdiff - modules/mux/mp4.c
* modules/video_output/directx/events.c: fixes for VOUT_REPARENT.
[vlc] / modules / mux / mp4.c
index 414fa1916f2d20dcbd1340526244aa0a2ade33cb..e86809b93bb46a3db518fa628328103e9899d00b 100644 (file)
@@ -54,12 +54,16 @@ static void Close  ( vlc_object_t * );
 
 vlc_module_begin();
     set_description( _("MP4/MOV muxer") );
+    set_category( CAT_SOUT );
+    set_subcategory( SUBCAT_SOUT_MUX );
+    set_shortname( "MP4" );
 
     add_bool( SOUT_CFG_PREFIX "faststart", 1, NULL, FASTSTART_TEXT, FASTSTART_LONGTEXT,
               VLC_TRUE );
     set_capability( "sout mux", 5 );
     add_shortcut( "mp4" );
     add_shortcut( "mov" );
+    add_shortcut( "3gp" );
     set_callbacks( Open, Close );
 vlc_module_end();
 
@@ -70,7 +74,7 @@ static const char *ppsz_sout_options[] = {
     "faststart", NULL
 };
 
-static int Capability(sout_mux_t *, int, void *, void * );
+static int Control( sout_mux_t *, int, va_list );
 static int AddStream( sout_mux_t *, sout_input_t * );
 static int DelStream( sout_mux_t *, sout_input_t * );
 static int Mux      ( sout_mux_t * );
@@ -128,6 +132,7 @@ typedef struct
 struct sout_mux_sys_t
 {
     vlc_bool_t b_mov;
+    vlc_bool_t b_3gp;
     vlc_bool_t b_64_ext;
     vlc_bool_t b_fast_start;
 
@@ -188,9 +193,9 @@ static int Open( vlc_object_t *p_this )
     bo_t            *box;
 
     msg_Dbg( p_mux, "Mp4 muxer opend" );
-    sout_ParseCfg( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
+    sout_CfgParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
 
-    p_mux->pf_capacity  = Capability;
+    p_mux->pf_control   = Control;
     p_mux->pf_addstream = AddStream;
     p_mux->pf_delstream = DelStream;
     p_mux->pf_mux       = Mux;
@@ -200,6 +205,7 @@ static int Open( vlc_object_t *p_this )
     p_sys->pp_streams   = NULL;
     p_sys->i_mdat_pos   = 0;
     p_sys->b_mov        = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mov" );
+    p_sys->b_3gp        = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "3gp" );
     p_sys->i_dts_start  = 0;
 
 
@@ -207,9 +213,11 @@ static int Open( vlc_object_t *p_this )
     {
         /* Now add ftyp header */
         box = box_new( "ftyp" );
-        bo_add_fourcc( box, "isom" );
+        if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
+        else bo_add_fourcc( box, "isom" );
         bo_add_32be  ( box, 0 );
-        bo_add_fourcc( box, "mp41" );
+        if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
+        else bo_add_fourcc( box, "mp41" );
         box_fix( box );
 
         p_sys->i_pos += box->i_buffer;
@@ -363,23 +371,27 @@ static void Close( vlc_object_t * p_this )
 }
 
 /*****************************************************************************
- * Capability:
+ * Control:
  *****************************************************************************/
-static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
-                       void *p_answer )
+static int Control( sout_mux_t *p_mux, int i_query, va_list args )
 {
+    vlc_bool_t *pb_bool;
+
    switch( i_query )
    {
-        case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
-            *(vlc_bool_t*)p_answer = VLC_TRUE;
-            return SOUT_MUX_CAP_ERR_OK;
+       case MUX_CAN_ADD_STREAM_WHILE_MUXING:
+           pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
+           *pb_bool = VLC_FALSE;
+           return VLC_SUCCESS;
 
-        case SOUT_MUX_CAP_GET_ADD_STREAM_WAIT:
-            *(vlc_bool_t*)p_answer = VLC_TRUE;
-            return( SOUT_MUX_CAP_ERR_OK );
+       case MUX_GET_ADD_STREAM_WAIT:
+           pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
+           *pb_bool = VLC_TRUE;
+           return VLC_SUCCESS;
 
+       case MUX_GET_MIME:   /* Not needed, as not streamable */
         default:
-            return SOUT_MUX_CAP_ERR_UNIMPLEMENTED;
+            return VLC_EGENERIC;
    }
 }
 
@@ -697,7 +709,7 @@ static void ConvertAVC1( sout_mux_t *p_mux, mp4_stream_t *tk, block_t *p_block )
         last[2] = ( i_size >>  8 )&0xff;
         last[3] = ( i_size       )&0xff;
 
-        if( last[4] == 7 && tk->avc.i_sps <= 0 )  /* SPS */
+        if( (last[4]&0x1f) == 7 && tk->avc.i_sps <= 0 )  /* SPS */
         {
             tk->avc.i_sps = i_size;
             tk->avc.sps = malloc( i_size );
@@ -706,7 +718,7 @@ static void ConvertAVC1( sout_mux_t *p_mux, mp4_stream_t *tk, block_t *p_block )
             tk->avc.i_profile = tk->avc.sps[1];
             tk->avc.i_level   = tk->avc.sps[3];
         }
-        else if( last[4] == 8 && tk->avc.i_pps <= 0 )   /* PPS */
+        else if( (last[4]&0x1f) == 8 && tk->avc.i_pps <= 0 )   /* PPS */
         {
             tk->avc.i_pps = i_size;
             tk->avc.pps = malloc( i_size );
@@ -738,7 +750,30 @@ static bo_t *GetESDS( mp4_stream_t *p_stream )
     int  i_stream_type;
     int  i_object_type_indication;
     int  i_decoder_specific_info_size;
+    unsigned int i;
+    int64_t i_bitrate_avg = 0;
+    int64_t i_bitrate_max = 0;
 
+    /* Compute avg/max bitrate */
+    for( i = 0; i < p_stream->i_entry_count; i++ )
+    {
+        i_bitrate_avg += p_stream->entry[i].i_size;
+        if( p_stream->entry[i].i_length > 0)
+        {
+            int64_t i_bitrate = I64C(8000000) * p_stream->entry[i].i_size / p_stream->entry[i].i_length;
+            if( i_bitrate > i_bitrate_max )
+                i_bitrate_max = i_bitrate;
+        }
+    }
+
+    if( p_stream->i_duration > 0 )
+        i_bitrate_avg = I64C(8000000) * i_bitrate_avg / p_stream->i_duration;
+    else
+        i_bitrate_avg = 0;
+    if( i_bitrate_max <= 1 )
+        i_bitrate_max = 0x7fffffff;
+
+    /* */
     if( p_stream->fmt.i_extra > 0 )
     {
         i_decoder_specific_info_size =
@@ -787,8 +822,8 @@ static bo_t *GetESDS( mp4_stream_t *p_stream )
     bo_add_8   ( esds, i_object_type_indication );
     bo_add_8   ( esds, ( i_stream_type << 2 ) | 1 );
     bo_add_24be( esds, 1024 * 1024 );       // bufferSizeDB
-    bo_add_32be( esds, 0x7fffffff );        // maxBitrate
-    bo_add_32be( esds, 0 );                 // avgBitrate
+    bo_add_32be( esds, i_bitrate_max );     // maxBitrate
+    bo_add_32be( esds, i_bitrate_avg );     // avgBitrate
 
     if( p_stream->fmt.i_extra > 0 )
     {
@@ -1550,12 +1585,12 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
         }
         else if( p_stream->fmt.i_cat == VIDEO_ES )
         {
-            int i_width = p_stream->fmt.video.i_width;
+            int i_width = p_stream->fmt.video.i_width << 16;
             if( p_stream->fmt.video.i_aspect > 0 )
             {
-                i_width = p_stream->fmt.video.i_aspect *
-                          p_stream->fmt.video.i_height /
-                          VOUT_ASPECT_FACTOR << 16;
+                i_width = (int64_t)p_stream->fmt.video.i_aspect *
+                          ((int64_t)p_stream->fmt.video.i_height << 16) /
+                          VOUT_ASPECT_FACTOR;
             }
             // width (presentation)
             bo_add_32be( tkhd, i_width );
@@ -1564,7 +1599,7 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
         }
         else
         {
-            int i_width = 320;
+            int i_width = 320 << 16;
             int i_height = 200;
             int i;
             for( i = 0; i < p_sys->i_nb_streams; i++ )
@@ -1573,15 +1608,15 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
                 if( tk->fmt.i_cat == VIDEO_ES )
                 {
                     if( p_stream->fmt.video.i_aspect )
-                        i_width = p_stream->fmt.video.i_aspect *
-                                  p_stream->fmt.video.i_height / VOUT_ASPECT_FACTOR;
+                        i_width = (int64_t)p_stream->fmt.video.i_aspect *
+                                   ((int64_t)p_stream->fmt.video.i_height<<16) / VOUT_ASPECT_FACTOR;
                     else
-                        i_width = p_stream->fmt.video.i_width;
+                        i_width = p_stream->fmt.video.i_width << 16;
                     i_height = p_stream->fmt.video.i_height;
                     break;
                 }
             }
-            bo_add_32be( tkhd, i_width << 16 );     // width (presentation)
+            bo_add_32be( tkhd, i_width );     // width (presentation)
             bo_add_32be( tkhd, i_height << 16 );    // height(presentation)
         }
 
@@ -1694,25 +1729,25 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
         /* handler reference */
         hdlr = box_full_new( "hdlr", 0, 0 );
 
-        bo_add_fourcc( hdlr, "mhlr" );         // media handler
+        if( p_sys->b_mov )
+            bo_add_fourcc( hdlr, "mhlr" );         // media handler
+        else
+            bo_add_32be( hdlr, 0 );
+
         if( p_stream->fmt.i_cat == AUDIO_ES )
-        {
             bo_add_fourcc( hdlr, "soun" );
-        }
         else if( p_stream->fmt.i_cat == VIDEO_ES )
-        {
             bo_add_fourcc( hdlr, "vide" );
-        }
         else if( p_stream->fmt.i_cat == SPU_ES )
-        {
             bo_add_fourcc( hdlr, "text" );
-        }
 
         bo_add_32be( hdlr, 0 );         // reserved
         bo_add_32be( hdlr, 0 );         // reserved
         bo_add_32be( hdlr, 0 );         // reserved
 
-        bo_add_8( hdlr, 12 );
+        if( p_sys->b_mov )
+            bo_add_8( hdlr, 12 );   /* Pascal string for .mov */
+
         if( p_stream->fmt.i_cat == AUDIO_ES )
             bo_add_mem( hdlr, 12, "SoundHandler" );
         else if( p_stream->fmt.i_cat == VIDEO_ES )
@@ -1720,6 +1755,9 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
         else
             bo_add_mem( hdlr, 12, "Text Handler" );
 
+        if( !p_sys->b_mov )
+            bo_add_8( hdlr, 0 );   /* asciiz string for .mp4, yes that's BRAIN DAMAGED F**K MP4 */
+
         box_fix( hdlr );
         box_gather( mdia, hdlr );