]> git.sesse.net Git - vlc/blobdiff - modules/stream_out/transcode.c
Fixed DMO wrapper.
[vlc] / modules / stream_out / transcode.c
index afcd0fe38fcb09cbb081664860c5d8dad605f13c..bc66396838b4d51f3f931cc3e356fc40f47e24e0 100644 (file)
@@ -167,73 +167,73 @@ vlc_module_begin ()
     set_category( CAT_SOUT )
     set_subcategory( SUBCAT_SOUT_STREAM )
     set_section( N_("Video"), NULL )
-    add_string( SOUT_CFG_PREFIX "venc", NULL, NULL, VENC_TEXT,
-                VENC_LONGTEXT, false );
+    add_module( SOUT_CFG_PREFIX "venc", "encoder", NULL, NULL, VENC_TEXT,
+                VENC_LONGTEXT, false )
     add_string( SOUT_CFG_PREFIX "vcodec", NULL, NULL, VCODEC_TEXT,
-                VCODEC_LONGTEXT, false );
+                VCODEC_LONGTEXT, false )
     add_integer( SOUT_CFG_PREFIX "vb", 800 * 1000, NULL, VB_TEXT,
-                 VB_LONGTEXT, false );
+                 VB_LONGTEXT, false )
     add_float( SOUT_CFG_PREFIX "scale", 1, NULL, SCALE_TEXT,
-               SCALE_LONGTEXT, false );
+               SCALE_LONGTEXT, false )
     add_float( SOUT_CFG_PREFIX "fps", 0, NULL, FPS_TEXT,
-               FPS_LONGTEXT, false );
+               FPS_LONGTEXT, false )
     add_bool( SOUT_CFG_PREFIX "hurry-up", true, NULL, HURRYUP_TEXT,
-               HURRYUP_LONGTEXT, false );
+               HURRYUP_LONGTEXT, false )
     add_bool( SOUT_CFG_PREFIX "deinterlace", 0, NULL, DEINTERLACE_TEXT,
-              DEINTERLACE_LONGTEXT, false );
+              DEINTERLACE_LONGTEXT, false )
     add_string( SOUT_CFG_PREFIX "deinterlace-module", "deinterlace", NULL,
                 DEINTERLACE_MODULE_TEXT, DEINTERLACE_MODULE_LONGTEXT,
-                false );
-        change_string_list( ppsz_deinterlace_type, 0, 0 );
+                false )
+        change_string_list( ppsz_deinterlace_type, 0, 0 )
     add_integer( SOUT_CFG_PREFIX "width", 0, NULL, WIDTH_TEXT,
-                 WIDTH_LONGTEXT, true );
+                 WIDTH_LONGTEXT, true )
     add_integer( SOUT_CFG_PREFIX "height", 0, NULL, HEIGHT_TEXT,
-                 HEIGHT_LONGTEXT, true );
+                 HEIGHT_LONGTEXT, true )
     add_integer( SOUT_CFG_PREFIX "maxwidth", 0, NULL, MAXWIDTH_TEXT,
-                 MAXWIDTH_LONGTEXT, true );
+                 MAXWIDTH_LONGTEXT, true )
     add_integer( SOUT_CFG_PREFIX "maxheight", 0, NULL, MAXHEIGHT_TEXT,
-                 MAXHEIGHT_LONGTEXT, true );
+                 MAXHEIGHT_LONGTEXT, true )
     add_module_list( SOUT_CFG_PREFIX "vfilter", "video filter2",
                      NULL, NULL,
-                     VFILTER_TEXT, VFILTER_LONGTEXT, false );
+                     VFILTER_TEXT, VFILTER_LONGTEXT, false )
 
     set_section( N_("Audio"), NULL )
-    add_string( SOUT_CFG_PREFIX "aenc", NULL, NULL, AENC_TEXT,
-                AENC_LONGTEXT, false );
+    add_module( SOUT_CFG_PREFIX "aenc", "encoder", NULL, NULL, AENC_TEXT,
+                AENC_LONGTEXT, false )
     add_string( SOUT_CFG_PREFIX "acodec", NULL, NULL, ACODEC_TEXT,
-                ACODEC_LONGTEXT, false );
+                ACODEC_LONGTEXT, false )
     add_integer( SOUT_CFG_PREFIX "ab", 0, NULL, AB_TEXT,
-                 AB_LONGTEXT, false );
+                 AB_LONGTEXT, false )
     add_integer( SOUT_CFG_PREFIX "channels", 0, NULL, ACHANS_TEXT,
-                 ACHANS_LONGTEXT, false );
+                 ACHANS_LONGTEXT, false )
     add_integer( SOUT_CFG_PREFIX "samplerate", 0, NULL, ARATE_TEXT,
-                 ARATE_LONGTEXT, true );
+                 ARATE_LONGTEXT, true )
     add_bool( SOUT_CFG_PREFIX "audio-sync", 0, NULL, ASYNC_TEXT,
-              ASYNC_LONGTEXT, false );
+              ASYNC_LONGTEXT, false )
     add_module_list( SOUT_CFG_PREFIX "afilter",  "audio filter2",
                      NULL, NULL,
-                     AFILTER_TEXT, AFILTER_LONGTEXT, false );
+                     AFILTER_TEXT, AFILTER_LONGTEXT, false )
 
     set_section( N_("Overlays/Subtitles"), NULL )
-    add_string( SOUT_CFG_PREFIX "senc", NULL, NULL, SENC_TEXT,
-                SENC_LONGTEXT, false );
+    add_module( SOUT_CFG_PREFIX "senc", "encoder", NULL, NULL, SENC_TEXT,
+                SENC_LONGTEXT, false )
     add_string( SOUT_CFG_PREFIX "scodec", NULL, NULL, SCODEC_TEXT,
-                SCODEC_LONGTEXT, false );
+                SCODEC_LONGTEXT, false )
     add_bool( SOUT_CFG_PREFIX "soverlay", 0, NULL, SCODEC_TEXT,
-               SCODEC_LONGTEXT, false );
+               SCODEC_LONGTEXT, false )
     add_module_list( SOUT_CFG_PREFIX "sfilter", "video filter",
                      NULL, NULL,
-                     SFILTER_TEXT, SFILTER_LONGTEXT, false );
+                     SFILTER_TEXT, SFILTER_LONGTEXT, false )
 
     set_section( N_("On Screen Display"), NULL )
     add_bool( SOUT_CFG_PREFIX "osd", 0, NULL, OSD_TEXT,
-              OSD_LONGTEXT, false );
+              OSD_LONGTEXT, false )
 
     set_section( N_("Miscellaneous"), NULL )
     add_integer( SOUT_CFG_PREFIX "threads", 0, NULL, THREADS_TEXT,
-                 THREADS_LONGTEXT, true );
+                 THREADS_LONGTEXT, true )
     add_bool( SOUT_CFG_PREFIX "high-priority", 0, NULL, HP_TEXT, HP_LONGTEXT,
-              true );
+              true )
 
 vlc_module_end ()
 
@@ -1056,12 +1056,107 @@ static int transcode_audio_filter_allocation_init( filter_t *p_filter,
     return VLC_SUCCESS;
 }
 
+static bool transcode_audio_filter_needed( const es_format_t *p_fmt1, const es_format_t *p_fmt2 )
+{
+    if( p_fmt1->i_codec != p_fmt2->i_codec ||
+        p_fmt1->audio.i_channels != p_fmt2->audio.i_channels ||
+        p_fmt1->audio.i_rate != p_fmt2->audio.i_rate )
+        return true;
+    return false;
+}
+static int transcode_audio_filter_chain_build( sout_stream_t *p_stream, filter_chain_t *p_chain,
+                                               const es_format_t *p_dst, const es_format_t *p_src )
+{
+    if( !transcode_audio_filter_needed( p_dst, p_src ) )
+        return VLC_SUCCESS;
+
+    es_format_t current = *p_src;
+
+    msg_Dbg( p_stream, "Looking for filter "
+             "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)",
+         (const char *)&p_src->i_codec,
+         (const char *)&p_dst->i_codec,
+         p_src->audio.i_channels,
+         p_dst->audio.i_channels,
+         p_src->audio.i_rate,
+         p_dst->audio.i_rate );
+
+    /* If any filter is needed, convert to fl32 */
+    if( current.i_codec != VLC_FOURCC('f','l','3','2') )
+    {
+        /* First step, convert to fl32 */
+        current.i_codec =
+        current.audio.i_format = VLC_FOURCC('f','l','3','2');
+
+        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
+        {
+            msg_Err( p_stream, "Failed to find conversion filter to fl32" );
+            return VLC_EGENERIC;
+        }
+        current = *filter_chain_GetFmtOut( p_chain );
+    }
+
+    /* Fix sample rate */
+    if( current.audio.i_rate != p_dst->audio.i_rate )
+    {
+        current.audio.i_rate = p_dst->audio.i_rate;
+        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
+        {
+            msg_Err( p_stream, "Failed to find conversion filter for resampling" );
+            return VLC_EGENERIC;
+        }
+        current = *filter_chain_GetFmtOut( p_chain );
+    }
+
+    /* Fix channels */
+    if( current.audio.i_channels != p_dst->audio.i_channels )
+    {
+        current.audio.i_channels = p_dst->audio.i_channels;
+        current.audio.i_physical_channels = p_dst->audio.i_physical_channels;
+        current.audio.i_original_channels = p_dst->audio.i_original_channels;
+
+        if( ( !current.audio.i_physical_channels || !current.audio.i_original_channels ) &&
+            current.audio.i_channels < 6 )
+            current.audio.i_physical_channels =
+            current.audio.i_original_channels = pi_channels_maps[current.audio.i_channels];
+
+        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
+        {
+            msg_Err( p_stream, "Failed to find conversion filter for channel mixing" );
+            return VLC_EGENERIC;
+        }
+        current = *filter_chain_GetFmtOut( p_chain );
+    }
+
+    /* And last step, convert to the requested codec */
+    if( current.i_codec != p_dst->i_codec )
+    {
+        current.i_codec = p_dst->i_codec;
+        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
+        {
+            msg_Err( p_stream, "Failed to find conversion filter to %4.4s",
+                     (const char*)&p_dst->i_codec);
+            return VLC_EGENERIC;
+        }
+        current = *filter_chain_GetFmtOut( p_chain );
+    }
+
+    if( transcode_audio_filter_needed( p_dst, &current ) )
+    {
+        /* Weird case, a filter has side effects, doomed */
+        msg_Err( p_stream, "Failed to create a valid audio filter chain" );
+        return VLC_EGENERIC;
+    }
+
+    msg_Dbg( p_stream, "Got complete audio filter chain" );
+    return VLC_SUCCESS;
+}
+
 static int transcode_audio_new( sout_stream_t *p_stream,
                                 sout_stream_id_t *id )
 {
     sout_stream_sys_t *p_sys = p_stream->p_sys;
     es_format_t fmt_last;
-    int i;
 
     /*
      * Open decoder
@@ -1127,137 +1222,39 @@ static int transcode_audio_new( sout_stream_t *p_stream,
     id->p_encoder->fmt_in.audio.i_bitspersample =
         aout_BitsPerSample( id->p_encoder->fmt_in.i_codec );
 
-    /* Init filter chain */
-    id->p_f_chain = filter_chain_New( p_stream, "audio filter2", true,
-                    transcode_audio_filter_allocation_init, NULL, NULL );
-    filter_chain_Reset( id->p_f_chain, &fmt_last, &id->p_encoder->fmt_in );
-
-    /* Load conversion filters */
-    if( fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels ||
-        fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate )
-    {
-        /* We'll have to go through fl32 first */
-        fmt_last.i_codec = fmt_last.audio.i_format = VLC_FOURCC('f','l','3','2');
-        fmt_last.audio.i_bitspersample = aout_BitsPerSample( fmt_last.i_codec );
-        filter_chain_AppendFilter( id->p_f_chain, NULL, NULL, NULL, &fmt_last );
-        fmt_last = *filter_chain_GetFmtOut( id->p_f_chain );
-    }
-
-    for( i = 0; i < 4; i++ )
-    {
-        if( (fmt_last.audio.i_channels !=
-            id->p_encoder->fmt_in.audio.i_channels) ||
-            (fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate) ||
-            (fmt_last.i_codec != id->p_encoder->fmt_in.i_codec) )
-        {
-            msg_Dbg( p_stream, "Looking for filter "
-                     "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)",
-                 (char *)&fmt_last.i_codec,
-                 (char *)&id->p_encoder->fmt_in.i_codec,
-                 fmt_last.audio.i_channels,
-                 id->p_encoder->fmt_in.audio.i_channels,
-                 fmt_last.audio.i_rate,
-                 id->p_encoder->fmt_in.audio.i_rate );
-            filter_chain_AppendFilter( id->p_f_chain, NULL, NULL,
-                                       &fmt_last, &id->p_encoder->fmt_in );
-            fmt_last = *filter_chain_GetFmtOut( id->p_f_chain );
-        }
-        else break;
-    }
-
-    /* Final checks to see if conversions were successful */
-    if( fmt_last.i_codec != id->p_encoder->fmt_in.i_codec )
-    {
-        msg_Err( p_stream, "no audio filter found "
-                           "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)",
-                 (char *)&fmt_last.i_codec,
-                 (char *)&id->p_encoder->fmt_in.i_codec,
-                 fmt_last.audio.i_channels,
-                 id->p_encoder->fmt_in.audio.i_channels,
-                 fmt_last.audio.i_rate,
-                 id->p_encoder->fmt_in.audio.i_rate );
-        transcode_audio_close( id );
-        return VLC_EGENERIC;
-    }
-
-    /* Load user specified audio filters now */
+    /* Load user specified audio filters */
     if( p_sys->psz_af2 )
     {
-        id->p_uf_chain = filter_chain_New( p_stream, "audio filter2", false,
-                       transcode_audio_filter_allocation_init, NULL, NULL );
-        filter_chain_Reset( id->p_uf_chain, &fmt_last, &id->p_encoder->fmt_in );
-        filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_af2 );
-        fmt_last = *filter_chain_GetFmtOut( id->p_uf_chain );
-    }
-
-    if( fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels )
-    {
-#if 1
-        module_unneed( id->p_encoder, id->p_encoder->p_module );
-        id->p_encoder->p_module = NULL;
-
-        /* This might work, but only if the encoder is restarted */
-        id->p_encoder->fmt_in.audio.i_channels = fmt_last.audio.i_channels;
-        id->p_encoder->fmt_out.audio.i_channels = fmt_last.audio.i_channels;
-
-        id->p_encoder->fmt_in.audio.i_physical_channels =
-            id->p_encoder->fmt_in.audio.i_original_channels =
-                fmt_last.audio.i_physical_channels;
-        id->p_encoder->fmt_out.audio.i_physical_channels =
-            id->p_encoder->fmt_out.audio.i_original_channels =
-                fmt_last.audio.i_physical_channels;
-
-        msg_Dbg( p_stream, "number of audio channels for mixing changed, "
-                 "trying to reopen the encoder for mixing %i to %i channels",
-                 fmt_last.audio.i_channels,
-                 id->p_encoder->fmt_in.audio.i_channels );
-
-        /* reload encoder */
-        id->p_encoder->p_cfg = p_stream->p_sys->p_audio_cfg;
-        id->p_encoder->p_module =
-            module_need( id->p_encoder, "encoder", p_sys->psz_aenc, true );
-        if( !id->p_encoder->p_module ||
-            fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels  ||
-            fmt_last.i_codec != id->p_encoder->fmt_in.i_codec )
+        es_format_t fmt_fl32 = fmt_last;
+        fmt_fl32.i_codec =
+        fmt_fl32.audio.i_format = VLC_FOURCC('f','l','3','2');
+        if( transcode_audio_filter_chain_build( p_stream, id->p_uf_chain,
+                                                &fmt_fl32, &fmt_last ) )
         {
-            if( id->p_encoder->p_module )
-            {
-                module_unneed( id->p_encoder, id->p_encoder->p_module );
-                id->p_encoder->p_module = NULL;
-            }
-            msg_Err( p_stream, "cannot find audio encoder (module:%s fourcc:%4.4s)",
-                     p_sys->psz_aenc ? p_sys->psz_aenc : "any",
-                     (char *)&p_sys->i_acodec );
             transcode_audio_close( id );
             return VLC_EGENERIC;
         }
-        id->p_encoder->fmt_in.audio.i_format = id->p_encoder->fmt_in.i_codec;
-        id->p_encoder->fmt_in.audio.i_bitspersample =
-            aout_BitsPerSample( id->p_encoder->fmt_in.i_codec );
-#else
-        msg_Err( p_stream, "no audio filter found for mixing from"
-                 " %i to %i channels", fmt_last.audio.i_channels,
-                 id->p_encoder->fmt_in.audio.i_channels );
+        fmt_last = fmt_fl32;
 
-        transcode_audio_close( id );
-        return VLC_EGENERIC;
-#endif
+        id->p_uf_chain = filter_chain_New( p_stream, "audio filter2", false,
+                                           transcode_audio_filter_allocation_init, NULL, NULL );
+        filter_chain_Reset( id->p_uf_chain, &fmt_last, &fmt_fl32 );
+        if( filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_af2 ) > 0 )
+            fmt_last = *filter_chain_GetFmtOut( id->p_uf_chain );
     }
 
-    if( fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate )
+    /* Load conversion filters */
+    id->p_f_chain = filter_chain_New( p_stream, "audio filter2", true,
+                    transcode_audio_filter_allocation_init, NULL, NULL );
+    filter_chain_Reset( id->p_f_chain, &fmt_last, &id->p_encoder->fmt_in );
+
+    if( transcode_audio_filter_chain_build( p_stream, id->p_f_chain,
+                                            &id->p_encoder->fmt_in, &fmt_last ) )
     {
-        msg_Err( p_stream, "no audio filter found for resampling from"
-                 " %iHz to %iHz", fmt_last.audio.i_rate,
-                 id->p_encoder->fmt_in.audio.i_rate );
-#if 0
-        /* FIXME : this might work, but only if the encoder is restarted */
-        id->p_encoder->fmt_in.audio.i_rate = fmt_last.audio.i_rate;
-        id->p_encoder->fmt_out.audio.i_rate = fmt_last.audio.i_rate;
-#else
         transcode_audio_close( id );
         return VLC_EGENERIC;
-#endif
     }
+    fmt_last = id->p_encoder->fmt_in;
 
     /* FIXME: Hack for mp3 transcoding support */
     if( id->p_encoder->fmt_out.i_codec == VLC_FOURCC( 'm','p','3',' ' ) )
@@ -1285,10 +1282,10 @@ static void transcode_audio_close( sout_stream_id_t *id )
     id->p_encoder->p_module = NULL;
 
     /* Close filters */
-    if( id->p_f_chain )
-        filter_chain_Delete( id->p_f_chain );
     if( id->p_uf_chain )
         filter_chain_Delete( id->p_uf_chain );
+    if( id->p_f_chain )
+        filter_chain_Delete( id->p_f_chain );
 }
 
 static int transcode_audio_process( sout_stream_t *p_stream,
@@ -1329,9 +1326,13 @@ static int transcode_audio_process( sout_stream_t *p_stream,
         p_audio_block->i_samples = p_audio_buf->i_nb_samples;
 
         /* Run filter chain */
-        p_audio_block = filter_chain_AudioFilter( id->p_f_chain, p_audio_block );
         if( id->p_uf_chain )
+        {
             p_audio_block = filter_chain_AudioFilter( id->p_uf_chain, p_audio_block );
+            assert( p_audio_block );
+        }
+
+        p_audio_block = filter_chain_AudioFilter( id->p_f_chain, p_audio_block );
         assert( p_audio_block );
 
         p_audio_buf->p_buffer = p_audio_block->p_buffer;
@@ -2184,12 +2185,12 @@ static picture_t *video_new_buffer( vlc_object_t *p_this, picture_t **pp_ring,
         i = 0;
     }
 
+    p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
     p_pic = picture_New( p_dec->fmt_out.video.i_chroma,
                          p_dec->fmt_out.video.i_width,
                          p_dec->fmt_out.video.i_height,
                          p_dec->fmt_out.video.i_aspect );
     if( !p_pic ) return NULL;
-    p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
     p_pic->p_sys = calloc( 1, sizeof(picture_sys_t) );
     if( !p_pic->p_sys )
     {