[vlc-devel] [PATCH 2/2] dec: hide owners and callbacks from modules

Thomas Guillem thomas at gllm.fr
Wed May 16 14:50:39 CEST 2018


---
 include/vlc_codec.h                      | 156 ++++++++--------
 modules/stream_out/mosaic_bridge.c       |  82 ++++-----
 modules/stream_out/transcode/audio.c     |  20 ++-
 modules/stream_out/transcode/spu.c       |  17 +-
 modules/stream_out/transcode/transcode.c |   7 +-
 modules/stream_out/transcode/transcode.h |  12 ++
 modules/stream_out/transcode/video.c     |  26 ++-
 src/input/decoder.c                      | 220 ++++++++++++-----------
 src/misc/image.c                         |  41 +++--
 9 files changed, 338 insertions(+), 243 deletions(-)

diff --git a/include/vlc_codec.h b/include/vlc_codec.h
index 0f7f7c280b..98caeb9556 100644
--- a/include/vlc_codec.h
+++ b/include/vlc_codec.h
@@ -41,10 +41,56 @@
  * Decoder and encoder modules interface
  */
 
-typedef struct decoder_owner_sys_t decoder_owner_sys_t;
-
 typedef struct decoder_cc_desc_t decoder_cc_desc_t;
 
+struct decoder_owner_callbacks
+{
+    union
+    {
+        struct
+        {
+            int         (*pf_format_update)( decoder_t * );
+
+            /* cf. decoder_NewPicture */
+            picture_t*  (*pf_buffer_new)( decoder_t * );
+            /* cf.decoder_QueueVideo */
+            void        (*pf_queue)( decoder_t *, picture_t * );
+            /* cf.decoder_QueueCC */
+            void        (*pf_queue_cc)( decoder_t *, block_t *,
+                                            const decoder_cc_desc_t * );
+
+            /* Display date
+             * cf. decoder_GetDisplayDate */
+            mtime_t     (*pf_get_display_date)( decoder_t *, mtime_t );
+            /* Display rate
+             * cf. decoder_GetDisplayRate */
+            int         (*pf_get_display_rate)( decoder_t * );
+        } video;
+        struct
+        {
+            int     (*pf_format_update)( decoder_t * );
+
+            /* cf.decoder_QueueAudio */
+            void    (*pf_queue)( decoder_t *, block_t * );
+        } audio;
+        struct
+        {
+            /* cf. decoder_NewSubpicture */
+            subpicture_t*   (*pf_buffer_new)( decoder_t *,
+                                              const subpicture_updater_t * );
+
+            /* cf.decoder_QueueSub */
+            void            (*pf_queue)( decoder_t *, subpicture_t *);
+        } spu;
+    };
+
+    /* Input attachments
+     * cf. decoder_GetInputAttachments */
+    int (*pf_get_attachments)( decoder_t *p_dec,
+                               input_attachment_t ***ppp_attachment,
+                               int *pi_attachment );
+};
+
 /*
  * BIG FAT WARNING : the code relies in the first 4 members of filter_t
  * and decoder_t to be the same, so if you have anything to add, do it
@@ -67,6 +113,12 @@ struct decoder_t
     /* Tell the decoder if it is allowed to drop frames */
     bool                b_frame_drop_allowed;
 
+    /**
+     * Number of extra (ie in addition to the DPB) picture buffers
+     * needed for decoding.
+     */
+    int                 i_extra_picture_buffers;
+
 #   define VLCDEC_SUCCESS   VLC_SUCCESS
 #   define VLCDEC_ECRITICAL VLC_EGENERIC
 #   define VLCDEC_RELOAD    (-100)
@@ -138,53 +190,8 @@ struct decoder_t
      */
     vlc_meta_t          *p_description;
 
-    /*
-     * Owner fields
-     * XXX You MUST not use them directly.
-     */
-
-    /* Video output callbacks
-     * XXX use decoder_NewPicture */
-    int             (*pf_vout_format_update)( decoder_t * );
-    picture_t      *(*pf_vout_buffer_new)( decoder_t * );
-
-    /**
-     * Number of extra (ie in addition to the DPB) picture buffers
-     * needed for decoding.
-     */
-    int             i_extra_picture_buffers;
-
-    /* Audio output callbacks */
-    int             (*pf_aout_format_update)( decoder_t * );
-
-    /* SPU output callbacks
-     * XXX use decoder_NewSubpicture */
-    subpicture_t   *(*pf_spu_buffer_new)( decoder_t *, const subpicture_updater_t * );
-
-    /* Input attachments
-     * XXX use decoder_GetInputAttachments */
-    int             (*pf_get_attachments)( decoder_t *p_dec, input_attachment_t ***ppp_attachment, int *pi_attachment );
-
-    /* Display date
-     * XXX use decoder_GetDisplayDate */
-    mtime_t         (*pf_get_display_date)( decoder_t *, mtime_t );
-
-    /* Display rate
-     * XXX use decoder_GetDisplayRate */
-    int             (*pf_get_display_rate)( decoder_t * );
-
-    /* XXX use decoder_QueueVideo or decoder_QueueVideoWithCc */
-    void            (*pf_queue_video)( decoder_t *, picture_t * );
-    /* XXX use decoder_QueueAudio */
-    void            (*pf_queue_audio)( decoder_t *, block_t * );
-    /* XXX use decoder_QueueCC */
-    void            (*pf_queue_cc)( decoder_t *, block_t *, const decoder_cc_desc_t * );
-    /* XXX use decoder_QueueSub */
-    void            (*pf_queue_sub)( decoder_t *, subpicture_t *);
-    void             *p_queue_ctx;
-
     /* Private structure for the owner of the decoder */
-    decoder_owner_sys_t *p_owner;
+    const struct decoder_owner_callbacks *cbs;
 };
 
 /* struct for packetizer get_cc polling/decoder queue_cc
@@ -260,9 +267,9 @@ struct encoder_t
 VLC_USED
 static inline int decoder_UpdateVideoFormat( decoder_t *dec )
 {
-    assert( dec->fmt_in.i_cat == VIDEO_ES );
-    if( dec->fmt_in.i_cat == VIDEO_ES && dec->pf_vout_format_update != NULL )
-        return dec->pf_vout_format_update( dec );
+    assert( dec->fmt_in.i_cat == VIDEO_ES && dec->cbs != NULL );
+    if( dec->fmt_in.i_cat == VIDEO_ES && dec->cbs->video.pf_format_update != NULL )
+        return dec->cbs->video.pf_format_update( dec );
     else
         return -1;
 }
@@ -287,7 +294,8 @@ static inline int decoder_UpdateVideoFormat( decoder_t *dec )
 VLC_USED
 static inline picture_t *decoder_NewPicture( decoder_t *dec )
 {
-    return dec->pf_vout_buffer_new( dec );
+    assert( dec->fmt_in.i_cat == VIDEO_ES && dec->cbs != NULL );
+    return dec->cbs->video.pf_buffer_new( dec );
 }
 
 /**
@@ -309,9 +317,10 @@ VLC_API void decoder_AbortPictures( decoder_t *dec, bool b_abort );
  */
 static inline void decoder_QueueVideo( decoder_t *dec, picture_t *p_pic )
 {
+    assert( dec->fmt_in.i_cat == VIDEO_ES && dec->cbs != NULL );
     assert( p_pic->p_next == NULL );
-    assert( dec->pf_queue_video != NULL );
-    dec->pf_queue_video( dec, p_pic );
+    assert( dec->cbs->video.pf_queue != NULL );
+    dec->cbs->video.pf_queue( dec, p_pic );
 }
 
 /**
@@ -324,10 +333,11 @@ static inline void decoder_QueueVideo( decoder_t *dec, picture_t *p_pic )
 static inline void decoder_QueueCc( decoder_t *dec, block_t *p_cc,
                                    const decoder_cc_desc_t *p_desc )
 {
-    if( dec->pf_queue_cc == NULL )
+    assert( dec->fmt_in.i_cat == VIDEO_ES && dec->cbs != NULL );
+    if( dec->cbs->video.pf_queue_cc == NULL )
         block_Release( p_cc );
     else
-        dec->pf_queue_cc( dec, p_cc, p_desc );
+        dec->cbs->video.pf_queue_cc( dec, p_cc, p_desc );
 }
 
 /**
@@ -339,9 +349,10 @@ static inline void decoder_QueueCc( decoder_t *dec, block_t *p_cc,
  */
 static inline void decoder_QueueAudio( decoder_t *dec, block_t *p_aout_buf )
 {
+    assert( dec->fmt_in.i_cat == AUDIO_ES && dec->cbs != NULL );
     assert( p_aout_buf->p_next == NULL );
-    assert( dec->pf_queue_audio != NULL );
-    dec->pf_queue_audio( dec, p_aout_buf );
+    assert( dec->cbs->audio.pf_queue != NULL );
+    dec->cbs->audio.pf_queue( dec, p_aout_buf );
 }
 
 /**
@@ -353,9 +364,10 @@ static inline void decoder_QueueAudio( decoder_t *dec, block_t *p_aout_buf )
  */
 static inline void decoder_QueueSub( decoder_t *dec, subpicture_t *p_spu )
 {
+    assert( dec->fmt_in.i_cat == SPU_ES && dec->cbs != NULL );
     assert( p_spu->p_next == NULL );
-    assert( dec->pf_queue_sub != NULL );
-    dec->pf_queue_sub( dec, p_spu );
+    assert( dec->cbs->spu.pf_queue != NULL );
+    dec->cbs->spu.pf_queue( dec, p_spu );
 }
 
 /**
@@ -366,9 +378,9 @@ static inline void decoder_QueueSub( decoder_t *dec, subpicture_t *p_spu )
 VLC_USED
 static inline int decoder_UpdateAudioFormat( decoder_t *dec )
 {
-    assert(dec->fmt_in.i_cat == AUDIO_ES);
-    if( dec->fmt_in.i_cat == AUDIO_ES && dec->pf_aout_format_update != NULL )
-        return dec->pf_aout_format_update( dec );
+    assert( dec->fmt_in.i_cat == AUDIO_ES && dec->cbs != NULL );
+    if( dec->fmt_in.i_cat == AUDIO_ES && dec->cbs->audio.pf_format_update != NULL )
+        return dec->cbs->audio.pf_format_update( dec );
     else
         return -1;
 }
@@ -389,7 +401,8 @@ VLC_USED
 static inline subpicture_t *decoder_NewSubpicture( decoder_t *dec,
                                                    const subpicture_updater_t *p_dyn )
 {
-    subpicture_t *p_subpicture = dec->pf_spu_buffer_new( dec, p_dyn );
+    assert( dec->fmt_in.i_cat == SPU_ES && dec->cbs != NULL );
+    subpicture_t *p_subpicture = dec->cbs->spu.pf_buffer_new( dec, p_dyn );
     if( !p_subpicture )
         msg_Warn( dec, "can't get output subpicture" );
     return p_subpicture;
@@ -404,10 +417,11 @@ static inline int decoder_GetInputAttachments( decoder_t *dec,
                                                input_attachment_t ***ppp_attachment,
                                                int *pi_attachment )
 {
-    if( !dec->pf_get_attachments )
+    assert( dec->cbs != NULL );
+    if( !dec->cbs->pf_get_attachments )
         return VLC_EGENERIC;
 
-    return dec->pf_get_attachments( dec, ppp_attachment, pi_attachment );
+    return dec->cbs->pf_get_attachments( dec, ppp_attachment, pi_attachment );
 }
 
 /**
@@ -418,10 +432,11 @@ static inline int decoder_GetInputAttachments( decoder_t *dec,
 VLC_USED
 static inline mtime_t decoder_GetDisplayDate( decoder_t *dec, mtime_t i_ts )
 {
-    if( !dec->pf_get_display_date )
+    assert( dec->fmt_in.i_cat == VIDEO_ES && dec->cbs != NULL );
+    if( !dec->cbs->video.pf_get_display_date )
         return VLC_TS_INVALID;
 
-    return dec->pf_get_display_date( dec, i_ts );
+    return dec->cbs->video.pf_get_display_date( dec, i_ts );
 }
 
 /**
@@ -431,10 +446,11 @@ static inline mtime_t decoder_GetDisplayDate( decoder_t *dec, mtime_t i_ts )
 VLC_USED
 static inline int decoder_GetDisplayRate( decoder_t *dec )
 {
-    if( !dec->pf_get_display_rate )
+    assert( dec->fmt_in.i_cat == VIDEO_ES && dec->cbs != NULL );
+    if( !dec->cbs->video.pf_get_display_rate )
         return 1000 /* XXX: INPUT_RATE_DEFAULT */;
 
-    return dec->pf_get_display_rate( dec );
+    return dec->cbs->video.pf_get_display_rate( dec );
 }
 
 /** @} */
diff --git a/modules/stream_out/mosaic_bridge.c b/modules/stream_out/mosaic_bridge.c
index 1d0c7a5944..e3d75a6a44 100644
--- a/modules/stream_out/mosaic_bridge.c
+++ b/modules/stream_out/mosaic_bridge.c
@@ -62,12 +62,19 @@ typedef struct
     filter_chain_t *p_vf2;
 } sout_stream_sys_t;
 
-struct decoder_owner_sys_t
+struct decoder_owner
 {
+    decoder_t dec;
     /* Current format in use by the output */
     video_format_t video;
+    sout_stream_t *p_stream;
 };
 
+static inline struct decoder_owner *dec_get_owner( decoder_t *p_dec )
+{
+    return container_of( p_dec, struct decoder_owner, dec );
+}
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -77,12 +84,11 @@ static void *Add( sout_stream_t *, const es_format_t * );
 static void  Del( sout_stream_t *, void * );
 static int   Send( sout_stream_t *, void *, block_t * );
 
-static int decoder_queue_video( decoder_t *p_dec, picture_t *p_pic );
+static void decoder_queue_video( decoder_t *p_dec, picture_t *p_pic );
 inline static int video_update_format_decoder( decoder_t *p_dec );
 inline static picture_t *video_new_buffer_decoder( decoder_t * );
 inline static picture_t *video_new_buffer_filter( filter_t * );
-static int video_update_format( vlc_object_t *, decoder_owner_sys_t *,
-                                es_format_t * );
+static int video_update_format( vlc_object_t *, video_format_t *, es_format_t * );
 
 static int HeightCallback( vlc_object_t *, char const *,
                            vlc_value_t, vlc_value_t, void * );
@@ -282,9 +288,10 @@ static void *Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
         return NULL;
 
     /* Create decoder object */
-    p_sys->p_decoder = vlc_object_create( p_stream, sizeof( decoder_t ) );
-    if( !p_sys->p_decoder )
+    struct decoder_owner *p_owner = vlc_object_create( p_stream, sizeof( *p_owner ) );
+    if( !p_owner )
         return NULL;
+    p_sys->p_decoder = &p_owner->dec;
     p_sys->p_decoder->p_module = NULL;
     p_sys->p_decoder->fmt_in = *p_fmt;
     p_sys->p_decoder->b_frame_drop_allowed = true;
@@ -292,18 +299,19 @@ static void *Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
     p_sys->p_decoder->fmt_out.i_extra = 0;
     p_sys->p_decoder->fmt_out.p_extra = 0;
     p_sys->p_decoder->pf_decode = NULL;
-    p_sys->p_decoder->pf_queue_video = decoder_queue_video;
-    p_sys->p_decoder->p_queue_ctx = p_stream;
-    p_sys->p_decoder->pf_vout_format_update = video_update_format_decoder;
-    p_sys->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
-    p_sys->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) );
-    if( !p_sys->p_decoder->p_owner )
-    {
-        vlc_object_release( p_sys->p_decoder );
-        return NULL;
-    }
 
-    p_sys->p_decoder->p_owner->video = p_fmt->video;
+    static const struct decoder_owner_callbacks dec_cbs =
+    {
+        .video = {
+            video_update_format_decoder,
+            video_new_buffer_decoder,
+            decoder_queue_video,
+        },
+    };
+    p_sys->p_decoder->cbs = &dec_cbs;
+
+    p_owner->video = p_fmt->video;
+    p_owner->p_stream = p_stream;
     //p_sys->p_decoder->p_cfg = p_sys->p_video_cfg;
 
     p_sys->p_decoder->p_module =
@@ -312,7 +320,6 @@ static void *Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
     if( !p_sys->p_decoder->p_module )
     {
         msg_Err( p_stream, "cannot find decoder" );
-        free( p_sys->p_decoder->p_owner );
         vlc_object_release( p_sys->p_decoder );
         return NULL;
     }
@@ -381,7 +388,7 @@ static void *Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
     if( psz_chain )
     {
         filter_owner_t owner = {
-            .sys = p_sys->p_decoder->p_owner,
+            .sys = p_owner,
             .video = {
                 .buffer_new = video_new_buffer_filter,
             },
@@ -422,16 +429,12 @@ static void Del( sout_stream_t *p_stream, void *id )
 
     if( p_sys->p_decoder != NULL )
     {
-        decoder_owner_sys_t *p_owner = p_sys->p_decoder->p_owner;
-
         if( p_sys->p_decoder->p_module )
             module_unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
         if( p_sys->p_decoder->p_description )
             vlc_meta_Delete( p_sys->p_decoder->p_description );
 
         vlc_object_release( p_sys->p_decoder );
-
-        free( p_owner );
     }
 
     /* Destroy user specified video filters */
@@ -480,9 +483,10 @@ static void Del( sout_stream_t *p_stream, void *id )
     p_sys->b_inited = false;
 }
 
-static int decoder_queue_video( decoder_t *p_dec, picture_t *p_pic )
+static void decoder_queue_video( decoder_t *p_dec, picture_t *p_pic )
 {
-    sout_stream_t *p_stream = p_dec->p_queue_ctx;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
+    sout_stream_t *p_stream = p_owner->p_stream;
     sout_stream_sys_t *p_sys = p_stream->p_sys;
     picture_t *p_new_pic;
     const video_format_t *p_fmt_in = &p_sys->p_decoder->fmt_out.video;
@@ -531,7 +535,7 @@ static int decoder_queue_video( decoder_t *p_dec, picture_t *p_pic )
         {
             msg_Err( p_stream, "image conversion failed" );
             picture_Release( p_pic );
-            return -1;
+            return;
         }
     }
     else
@@ -546,7 +550,7 @@ static int decoder_queue_video( decoder_t *p_dec, picture_t *p_pic )
         {
             picture_Release( p_pic );
             msg_Err( p_stream, "image allocation failed" );
-            return -1;
+            return;
         }
 
         picture_Copy( p_new_pic, p_pic );
@@ -563,7 +567,6 @@ static int decoder_queue_video( decoder_t *p_dec, picture_t *p_pic )
     p_new_pic->p_next = NULL;
     p_es->pp_last = &p_new_pic->p_next;
     vlc_global_unlock( VLC_MOSAIC_MUTEX );
-    return 0;
 }
 
 static int Send( sout_stream_t *p_stream, void *id, block_t *p_buffer )
@@ -582,9 +585,9 @@ static int Send( sout_stream_t *p_stream, void *id, block_t *p_buffer )
 
 inline static int video_update_format_decoder( decoder_t *p_dec )
 {
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     return video_update_format( VLC_OBJECT( p_dec ),
-                                (decoder_owner_sys_t *)p_dec->p_owner,
-                                &p_dec->fmt_out );
+                                &p_owner->video, &p_dec->fmt_out );
 }
 
 inline static picture_t *video_new_buffer_decoder( decoder_t *p_dec )
@@ -594,9 +597,9 @@ inline static picture_t *video_new_buffer_decoder( decoder_t *p_dec )
 
 inline static picture_t *video_new_buffer_filter( filter_t *p_filter )
 {
+    struct decoder_owner *p_owner = p_filter->owner.sys;
     if( video_update_format( VLC_OBJECT( p_filter ),
-                             (decoder_owner_sys_t *)p_filter->owner.sys,
-                             &p_filter->fmt_out ) ) {
+                             &p_owner->video, &p_filter->fmt_out ) ) {
         msg_Warn( p_filter, "can't get output picture" );
         return NULL;
     }
@@ -604,15 +607,14 @@ inline static picture_t *video_new_buffer_filter( filter_t *p_filter )
 }
 
 static int video_update_format( vlc_object_t *p_this,
-                                    decoder_owner_sys_t *p_sys,
-                                    es_format_t *fmt_out )
+                                video_format_t *video, es_format_t *fmt_out )
 {
     VLC_UNUSED(p_this);
-    if( fmt_out->video.i_width != p_sys->video.i_width ||
-        fmt_out->video.i_height != p_sys->video.i_height ||
-        fmt_out->video.i_chroma != p_sys->video.i_chroma ||
-        (int64_t)fmt_out->video.i_sar_num * p_sys->video.i_sar_den !=
-        (int64_t)fmt_out->video.i_sar_den * p_sys->video.i_sar_num )
+    if( fmt_out->video.i_width != video->i_width ||
+        fmt_out->video.i_height != video->i_height ||
+        fmt_out->video.i_chroma != video->i_chroma ||
+        (int64_t)fmt_out->video.i_sar_num * video->i_sar_den !=
+        (int64_t)fmt_out->video.i_sar_den * video->i_sar_num )
     {
         vlc_ureduce( &fmt_out->video.i_sar_num,
                      &fmt_out->video.i_sar_den,
@@ -627,7 +629,7 @@ static int video_update_format( vlc_object_t *p_this,
         }
 
         fmt_out->video.i_chroma = fmt_out->i_codec;
-        p_sys->video = fmt_out->video;
+        *video = fmt_out->video;
     }
 
     /* */
diff --git a/modules/stream_out/transcode/audio.c b/modules/stream_out/transcode/audio.c
index 55dc975e9e..60523d47e2 100644
--- a/modules/stream_out/transcode/audio.c
+++ b/modules/stream_out/transcode/audio.c
@@ -57,7 +57,8 @@ static const int pi_channels_maps[9] =
 
 static int audio_update_format( decoder_t *p_dec )
 {
-    sout_stream_id_sys_t *id     = p_dec->p_queue_ctx;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
+    sout_stream_id_sys_t *id = p_owner->id;
 
     p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
     aout_FormatPrepare( &p_dec->fmt_out.audio );
@@ -158,7 +159,8 @@ static int transcode_audio_initialize_encoder( sout_stream_id_sys_t *id, sout_st
 
 static void decoder_queue_audio( decoder_t *p_dec, block_t *p_audio )
 {
-    sout_stream_id_sys_t *id = p_dec->p_queue_ctx;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
+    sout_stream_id_sys_t *id = p_owner->id;
 
     vlc_mutex_lock(&id->fifo.lock);
     *id->fifo.audio.last = p_audio;
@@ -185,12 +187,18 @@ static int transcode_audio_new( sout_stream_t *p_stream,
     /*
      * Open decoder
      */
+    dec_get_owner( id->p_decoder )->id = id;
+
+    static const struct decoder_owner_callbacks dec_cbs =
+    {
+        .audio = {
+            audio_update_format,
+            decoder_queue_audio,
+        },
+    };
+    id->p_decoder->cbs = &dec_cbs;
 
-    /* Initialization of decoder structures */
     id->p_decoder->pf_decode = NULL;
-    id->p_decoder->pf_queue_audio = decoder_queue_audio;
-    id->p_decoder->p_queue_ctx = id;
-    id->p_decoder->pf_aout_format_update = audio_update_format;
     /* id->p_decoder->p_cfg = p_sys->p_audio_cfg; */
     id->p_decoder->p_module =
         module_need_var( id->p_decoder, "audio decoder", "codec" );
diff --git a/modules/stream_out/transcode/spu.c b/modules/stream_out/transcode/spu.c
index 539c4f1828..66d3cb5fa4 100644
--- a/modules/stream_out/transcode/spu.c
+++ b/modules/stream_out/transcode/spu.c
@@ -47,7 +47,8 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec,
 
 static void decoder_queue_sub( decoder_t *p_dec, subpicture_t *p_spu )
 {
-    sout_stream_id_sys_t *id = p_dec->p_queue_ctx;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
+    sout_stream_id_sys_t *id = p_owner->id;
 
     vlc_mutex_lock(&id->fifo.lock);
     *id->fifo.spu.last = p_spu;
@@ -73,12 +74,18 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_sys_t *id
     /*
      * Open decoder
      */
+    dec_get_owner( id->p_decoder )->id = id;
+
+    static const struct decoder_owner_callbacks dec_cbs =
+    {
+        .spu = {
+            spu_new_buffer,
+            decoder_queue_sub,
+        },
+    };
+    id->p_decoder->cbs = &dec_cbs;
 
-    /* Initialization of decoder structures */
     id->p_decoder->pf_decode = NULL;
-    id->p_decoder->pf_spu_buffer_new = spu_new_buffer;
-    id->p_decoder->pf_queue_sub = decoder_queue_sub;
-    id->p_decoder->p_queue_ctx = id;
     /* id->p_decoder->p_cfg = p_sys->p_spu_cfg; */
 
     id->p_decoder->p_module =
diff --git a/modules/stream_out/transcode/transcode.c b/modules/stream_out/transcode/transcode.c
index 1eee324a9e..ea8f7d4b5a 100644
--- a/modules/stream_out/transcode/transcode.c
+++ b/modules/stream_out/transcode/transcode.c
@@ -499,9 +499,12 @@ static void *Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
     id->p_encoder = NULL;
 
     /* Create decoder object */
-    id->p_decoder = vlc_object_create( p_stream, sizeof( decoder_t ) );
-    if( !id->p_decoder )
+    struct decoder_owner * p_owner = vlc_object_create( p_stream, sizeof( *p_owner ) );
+    if( !p_owner )
         goto error;
+    p_owner->p_stream = p_stream;
+
+    id->p_decoder = &p_owner->dec;
     id->p_decoder->p_module = NULL;
     es_format_Init( &id->p_decoder->fmt_out, p_fmt->i_cat, 0 );
     es_format_Copy( &id->p_decoder->fmt_in, p_fmt );
diff --git a/modules/stream_out/transcode/transcode.h b/modules/stream_out/transcode/transcode.h
index e4a778d84c..071f5d20bf 100644
--- a/modules/stream_out/transcode/transcode.h
+++ b/modules/stream_out/transcode/transcode.h
@@ -132,6 +132,18 @@ struct sout_stream_id_sys_t
 
 };
 
+struct decoder_owner
+{
+    decoder_t dec;
+    sout_stream_t *p_stream;
+    sout_stream_id_sys_t *id;
+};
+
+static inline struct decoder_owner *dec_get_owner( decoder_t *p_dec )
+{
+    return container_of( p_dec, struct decoder_owner, dec );
+}
+
 /* SPU */
 
 void transcode_spu_close  ( sout_stream_t *, sout_stream_id_sys_t * );
diff --git a/modules/stream_out/transcode/video.c b/modules/stream_out/transcode/video.c
index 323bdfcb01..05da35115f 100644
--- a/modules/stream_out/transcode/video.c
+++ b/modules/stream_out/transcode/video.c
@@ -52,9 +52,10 @@ static const video_format_t* video_output_format( sout_stream_id_sys_t *id,
 
 static int video_update_format_decoder( decoder_t *p_dec )
 {
-    sout_stream_t        *stream = (sout_stream_t*) p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
+    sout_stream_id_sys_t *id = p_owner->id;
+    sout_stream_t        *stream = p_owner->p_stream;
     sout_stream_sys_t    *sys    = stream->p_sys;
-    sout_stream_id_sys_t *id     = p_dec->p_queue_ctx;
     filter_chain_t       *test_chain;
 
     filter_owner_t filter_owner = {
@@ -154,7 +155,8 @@ static void* EncoderThread( void *obj )
 
 static void decoder_queue_video( decoder_t *p_dec, picture_t *p_pic )
 {
-    sout_stream_id_sys_t *id = p_dec->p_queue_ctx;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
+    sout_stream_id_sys_t *id = p_owner->id;
 
     vlc_mutex_lock(&id->fifo.lock);
     *id->fifo.pic.last = p_pic;
@@ -178,15 +180,21 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_sys_t *i
     sout_stream_sys_t *p_sys = p_stream->p_sys;
 
     /* Open decoder
-     * Initialization of decoder structures
      */
+    dec_get_owner( id->p_decoder )->id = id;
+
+    static const struct decoder_owner_callbacks dec_cbs =
+    {
+        .video = {
+            video_update_format_decoder,
+            video_new_buffer_decoder,
+            decoder_queue_video,
+        },
+    };
+    id->p_decoder->cbs = &dec_cbs;
+
     id->p_decoder->pf_decode = NULL;
-    id->p_decoder->pf_queue_video = decoder_queue_video;
-    id->p_decoder->p_queue_ctx = id;
     id->p_decoder->pf_get_cc = NULL;
-    id->p_decoder->pf_vout_format_update = video_update_format_decoder;
-    id->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
-    id->p_decoder->p_owner = (decoder_owner_sys_t*) p_stream;
 
     id->p_decoder->p_module =
         module_need_var( id->p_decoder, "video decoder", "codec" );
diff --git a/src/input/decoder.c b/src/input/decoder.c
index ee559043e9..32b91b63e8 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -63,8 +63,9 @@ enum reload
     RELOAD_DECODER_AOUT /* Stop the aout and reload the decoder module */
 };
 
-struct decoder_owner_sys_t
+struct decoder_owner
 {
+    decoder_t        dec;
     input_thread_t  *p_input;
     input_resource_t*p_resource;
     input_clock_t   *p_clock;
@@ -79,7 +80,7 @@ struct decoder_owner_sys_t
 
     vlc_thread_t     thread;
 
-    void (*pf_update_stat)( decoder_owner_sys_t *, unsigned decoded, unsigned lost );
+    void (*pf_update_stat)( struct decoder_owner *, unsigned decoded, unsigned lost );
 
     /* Some decoders require already packetized data (ie. not truncated) */
     decoder_t *p_packetizer;
@@ -153,6 +154,11 @@ struct decoder_owner_sys_t
 
 #define VLC_TS_OLDEST  (VLC_TS_INVALID + 1)
 
+static inline struct decoder_owner *dec_get_owner( decoder_t *p_dec )
+{
+    return container_of( p_dec, struct decoder_owner, dec );
+}
+
 /**
  * Load a decoder module
  */
@@ -218,20 +224,20 @@ static int ReloadDecoder( decoder_t *p_dec, bool b_packetizer,
                           const es_format_t *restrict p_fmt, enum reload reload )
 {
     /* Copy p_fmt since it can be destroyed by UnloadDecoder */
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     es_format_t fmt_in;
     if( es_format_Copy( &fmt_in, p_fmt ) != VLC_SUCCESS )
     {
-        p_dec->p_owner->error = true;
+        p_owner->error = true;
         return VLC_EGENERIC;
     }
 
     /* Restart the decoder module */
     UnloadDecoder( p_dec );
-    p_dec->p_owner->error = false;
+    p_owner->error = false;
 
     if( reload == RELOAD_DECODER_AOUT )
     {
-        decoder_owner_sys_t *p_owner = p_dec->p_owner;
         assert( p_owner->fmt.i_cat == AUDIO_ES );
         audio_output_t *p_aout = p_owner->p_aout;
 
@@ -247,7 +253,7 @@ static int ReloadDecoder( decoder_t *p_dec, bool b_packetizer,
 
     if( LoadDecoder( p_dec, b_packetizer, &fmt_in ) )
     {
-        p_dec->p_owner->error = true;
+        p_owner->error = true;
         es_format_Clean( &fmt_in );
         return VLC_EGENERIC;
     }
@@ -257,7 +263,7 @@ static int ReloadDecoder( decoder_t *p_dec, bool b_packetizer,
 
 static void DecoderUpdateFormatLocked( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_assert_locked( &p_owner->lock );
 
@@ -284,7 +290,7 @@ static vout_thread_t *aout_request_vout( void *p_private,
                                          const video_format_t *p_fmt, bool b_recyle )
 {
     decoder_t *p_dec = p_private;
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     input_thread_t *p_input = p_owner->p_input;
 
     p_vout = input_resource_RequestVout( p_owner->p_resource, p_vout, p_fmt, 1,
@@ -311,7 +317,7 @@ static bool aout_replaygain_changed( const audio_replay_gain_t *a,
 
 static int aout_update_format( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     if( p_owner->p_aout &&
        ( !AOUT_FMTS_IDENTICAL(&p_dec->fmt_out.audio, &p_owner->fmt.audio) ||
@@ -407,7 +413,7 @@ static int aout_update_format( decoder_t *p_dec )
 
 static int vout_update_format( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     if( p_owner->p_vout == NULL
      || p_dec->fmt_out.video.i_width != p_owner->fmt.video.i_width
@@ -553,7 +559,7 @@ static int vout_update_format( decoder_t *p_dec )
 
 static picture_t *vout_new_buffer( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     assert( p_owner->p_vout );
 
     return vout_GetPicture( p_owner->p_vout );
@@ -562,7 +568,7 @@ static picture_t *vout_new_buffer( decoder_t *p_dec )
 static subpicture_t *spu_new_buffer( decoder_t *p_dec,
                                      const subpicture_updater_t *p_updater )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     vout_thread_t *p_vout = NULL;
     subpicture_t *p_subpic;
     int i_attempts = 30;
@@ -609,7 +615,8 @@ static int DecoderGetInputAttachments( decoder_t *p_dec,
                                        input_attachment_t ***ppp_attachment,
                                        int *pi_attachment )
 {
-    input_thread_t *p_input = p_dec->p_owner->p_input;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
+    input_thread_t *p_input = p_owner->p_input;
 
     if( unlikely(p_input == NULL) )
         return VLC_ENOOBJ;
@@ -619,7 +626,7 @@ static int DecoderGetInputAttachments( decoder_t *p_dec,
 
 static mtime_t DecoderGetDisplayDate( decoder_t *p_dec, mtime_t i_ts )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_mutex_lock( &p_owner->lock );
     if( p_owner->b_waiting || p_owner->paused )
@@ -639,7 +646,7 @@ static mtime_t DecoderGetDisplayDate( decoder_t *p_dec, mtime_t i_ts )
 
 static int DecoderGetDisplayRate( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     if( !p_owner->p_clock )
         return INPUT_RATE_DEFAULT;
@@ -667,7 +674,7 @@ block_t *decoder_NewAudioBuffer( decoder_t *dec, int samples )
 
 static void RequestReload( decoder_t * p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     /* Don't override reload if it's RELOAD_DECODER_AOUT */
     int expected = RELOAD_NO_REQUEST;
     atomic_compare_exchange_strong( &p_owner->reload, &expected, RELOAD_DECODER );
@@ -675,7 +682,7 @@ static void RequestReload( decoder_t * p_dec )
 
 void decoder_AbortPictures( decoder_t *p_dec, bool b_abort )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_mutex_lock( &p_owner->lock );
     if( p_owner->p_vout != NULL )
@@ -685,7 +692,7 @@ void decoder_AbortPictures( decoder_t *p_dec, bool b_abort )
 
 static void DecoderWaitUnblock( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_assert_locked( &p_owner->lock );
 
@@ -701,7 +708,7 @@ static void DecoderWaitUnblock( decoder_t *p_dec )
  * Returns VLC_SUCCESS if wait was not interrupted, and VLC_EGENERIC otherwise */
 static int DecoderTimedWait( decoder_t *p_dec, mtime_t deadline )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     if (deadline - mdate() <= 0)
         return VLC_SUCCESS;
@@ -732,7 +739,7 @@ static inline void DecoderUpdatePreroll( mtime_t *pi_preroll, const block_t *p )
 static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1,
                           mtime_t *pi_duration, int *pi_rate, mtime_t i_ts_bound )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     input_clock_t   *p_clock = p_owner->p_clock;
 
     vlc_assert_locked( &p_owner->lock );
@@ -782,7 +789,7 @@ static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1,
 #ifdef ENABLE_SOUT
 static int DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     assert( p_owner->p_clock );
     assert( !p_sout_block->p_next );
@@ -809,7 +816,7 @@ static int DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block )
  */
 static void DecoderProcessSout( decoder_t *p_dec, block_t *p_block )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     block_t *p_sout_block;
     block_t **pp_block = p_block ? &p_block : NULL;
 
@@ -879,7 +886,7 @@ static void DecoderProcessSout( decoder_t *p_dec, block_t *p_block )
 static void DecoderPlayCc( decoder_t *p_dec, block_t *p_cc,
                            const decoder_cc_desc_t *p_desc )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_mutex_lock( &p_owner->lock );
 
@@ -893,16 +900,17 @@ static void DecoderPlayCc( decoder_t *p_dec, block_t *p_cc,
     for( int i=0; i_bitmap > 0; i_bitmap >>= 1, i++ )
     {
         decoder_t *p_ccdec = p_owner->cc.pp_decoder[i];
+        struct decoder_owner *p_ccowner = dec_get_owner( p_ccdec );
         if( !p_ccdec )
             continue;
 
         if( i_bitmap > 1 )
         {
-            block_FifoPut( p_ccdec->p_owner->p_fifo, block_Duplicate(p_cc) );
+            block_FifoPut( p_ccowner->p_fifo, block_Duplicate(p_cc) );
         }
         else
         {
-            block_FifoPut( p_ccdec->p_owner->p_fifo, p_cc );
+            block_FifoPut( p_ccowner->p_fifo, p_cc );
             p_cc = NULL; /* was last dec */
         }
     }
@@ -915,7 +923,7 @@ static void DecoderPlayCc( decoder_t *p_dec, block_t *p_cc,
 
 static void PacketizerGetCc( decoder_t *p_dec, decoder_t *p_dec_cc )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     block_t *p_cc;
     decoder_cc_desc_t desc;
 
@@ -934,7 +942,7 @@ static void PacketizerGetCc( decoder_t *p_dec, decoder_t *p_dec_cc )
 static void DecoderQueueCc( decoder_t *p_videodec, block_t *p_cc,
                            const decoder_cc_desc_t *p_desc )
 {
-    decoder_owner_sys_t *p_owner = p_videodec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_videodec );
 
     if( unlikely( p_cc != NULL ) )
     {
@@ -949,7 +957,7 @@ static void DecoderQueueCc( decoder_t *p_videodec, block_t *p_cc,
 static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture,
                              unsigned *restrict pi_lost_sum )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     vout_thread_t  *p_vout = p_owner->p_vout;
     bool prerolled;
 
@@ -1043,7 +1051,7 @@ discard:
     picture_Release( p_picture );
 }
 
-static void DecoderUpdateStatVideo( decoder_owner_sys_t *p_owner,
+static void DecoderUpdateStatVideo( struct decoder_owner *p_owner,
                                     unsigned decoded, unsigned lost )
 {
     input_thread_t *p_input = p_owner->p_input;
@@ -1078,7 +1086,7 @@ static void DecoderQueueVideo( decoder_t *p_dec, picture_t *p_pic )
 {
     assert( p_pic );
     unsigned i_lost = 0;
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     DecoderPlayVideo( p_dec, p_pic, &i_lost );
 
@@ -1088,7 +1096,7 @@ static void DecoderQueueVideo( decoder_t *p_dec, picture_t *p_pic )
 static void DecoderPlayAudio( decoder_t *p_dec, block_t *p_audio,
                              unsigned *restrict pi_lost_sum )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     bool prerolled;
 
     assert( p_audio != NULL );
@@ -1168,7 +1176,7 @@ static void DecoderPlayAudio( decoder_t *p_dec, block_t *p_audio,
     return;
 }
 
-static void DecoderUpdateStatAudio( decoder_owner_sys_t *p_owner,
+static void DecoderUpdateStatAudio( struct decoder_owner *p_owner,
                                     unsigned decoded, unsigned lost )
 {
     input_thread_t *p_input = p_owner->p_input;
@@ -1202,7 +1210,7 @@ static void DecoderUpdateStatAudio( decoder_owner_sys_t *p_owner,
 static void DecoderQueueAudio( decoder_t *p_dec, block_t *p_aout_buf )
 {
     unsigned lost = 0;
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     DecoderPlayAudio( p_dec, p_aout_buf, &lost );
 
@@ -1211,7 +1219,7 @@ static void DecoderQueueAudio( decoder_t *p_dec, block_t *p_aout_buf )
 
 static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     vout_thread_t *p_vout = p_owner->p_spu_vout;
 
     /* */
@@ -1246,7 +1254,7 @@ static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic )
     vout_PutSubpicture( p_vout, p_subpic );
 }
 
-static void DecoderUpdateStatSpu( decoder_owner_sys_t *p_owner,
+static void DecoderUpdateStatSpu( struct decoder_owner *p_owner,
                                   unsigned decoded, unsigned lost )
 {
     (void) p_owner; (void) decoded; (void) lost;
@@ -1255,7 +1263,7 @@ static void DecoderUpdateStatSpu( decoder_owner_sys_t *p_owner,
 static void DecoderQueueSpu( decoder_t *p_dec, subpicture_t *p_spu )
 {
     assert( p_spu );
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vout_thread_t *p_vout = input_resource_HoldVout( p_owner->p_resource );
     if( p_vout && p_owner->p_spu_vout == p_vout )
@@ -1286,7 +1294,7 @@ static void DecoderQueueSpu( decoder_t *p_dec, subpicture_t *p_spu )
 static void DecoderProcess( decoder_t *p_dec, block_t *p_block );
 static void DecoderDecode( decoder_t *p_dec, block_t *p_block )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     int ret = p_dec->pf_decode( p_dec, p_block );
     switch( ret )
@@ -1322,7 +1330,7 @@ static void DecoderDecode( decoder_t *p_dec, block_t *p_block )
  */
 static void DecoderProcess( decoder_t *p_dec, block_t *p_block )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     if( p_owner->error )
         goto error;
@@ -1421,7 +1429,7 @@ error:
 
 static void DecoderProcessFlush( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     decoder_t *p_packetizer = p_owner->p_packetizer;
 
     if( p_owner->error )
@@ -1487,7 +1495,7 @@ static void DecoderProcessFlush( decoder_t *p_dec )
 static void *DecoderThread( void *p_data )
 {
     decoder_t *p_dec = (decoder_t *)p_data;
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     float rate = 1.f;
     bool paused = false;
 
@@ -1608,6 +1616,35 @@ static void *DecoderThread( void *p_data )
     vlc_assert_unreachable();
 }
 
+static const struct decoder_owner_callbacks dec_video_cbs =
+{
+    .video = {
+        vout_update_format,
+        vout_new_buffer,
+        DecoderQueueVideo,
+        DecoderQueueCc,
+        DecoderGetDisplayDate,
+        DecoderGetDisplayRate
+    },
+    DecoderGetInputAttachments,
+};
+static const struct decoder_owner_callbacks dec_audio_cbs =
+{
+    .audio = {
+        aout_update_format,
+        DecoderQueueAudio,
+    },
+    DecoderGetInputAttachments,
+};
+static const struct decoder_owner_callbacks dec_spu_cbs =
+{
+    .spu = {
+        spu_new_buffer,
+        DecoderQueueSpu
+    },
+    DecoderGetInputAttachments,
+};
+
 /**
  * Create a decoder object
  *
@@ -1623,19 +1660,13 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
                                   sout_instance_t *p_sout )
 {
     decoder_t *p_dec;
-    decoder_owner_sys_t *p_owner;
+    struct decoder_owner *p_owner;
 
-    p_dec = vlc_custom_create( p_parent, sizeof( *p_dec ), "decoder" );
-    if( p_dec == NULL )
+    p_owner = vlc_custom_create( p_parent, sizeof( *p_owner ), "decoder" );
+    if( p_owner == NULL )
         return NULL;
+    p_dec = &p_owner->dec;
 
-    /* Allocate our private structure for the decoder */
-    p_dec->p_owner = p_owner = malloc( sizeof( decoder_owner_sys_t ) );
-    if( unlikely(p_owner == NULL) )
-    {
-        vlc_object_release( p_dec );
-        return NULL;
-    }
     p_owner->i_preroll_end = (mtime_t)INT64_MIN;
     p_owner->i_last_rate = INPUT_RATE_DEFAULT;
     p_owner->p_input = p_input;
@@ -1675,7 +1706,6 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
     p_owner->p_fifo = block_FifoNew();
     if( unlikely(p_owner->p_fifo == NULL) )
     {
-        free( p_owner );
         vlc_object_release( p_dec );
         return NULL;
     }
@@ -1686,16 +1716,6 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
     vlc_cond_init( &p_owner->wait_fifo );
     vlc_cond_init( &p_owner->wait_timed );
 
-    /* Set buffers allocation callbacks for the decoders */
-    p_dec->pf_aout_format_update = aout_update_format;
-    p_dec->pf_vout_format_update = vout_update_format;
-    p_dec->pf_vout_buffer_new = vout_new_buffer;
-    p_dec->pf_spu_buffer_new  = spu_new_buffer;
-    /* */
-    p_dec->pf_get_attachments  = DecoderGetInputAttachments;
-    p_dec->pf_get_display_date = DecoderGetDisplayDate;
-    p_dec->pf_get_display_rate = DecoderGetDisplayRate;
-
     /* Load a packetizer module if the input is not already packetized */
     if( p_sout == NULL && !fmt->b_packetized )
     {
@@ -1716,30 +1736,31 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
         }
     }
 
-    /* Find a suitable decoder/packetizer module */
-    if( LoadDecoder( p_dec, p_sout != NULL, fmt ) )
-        return p_dec;
-
-    switch( p_dec->fmt_out.i_cat )
+    switch( fmt->i_cat )
     {
         case VIDEO_ES:
-            p_dec->pf_queue_video = DecoderQueueVideo;
-            p_dec->pf_queue_cc = DecoderQueueCc;
+            p_dec->cbs = &dec_video_cbs;
             p_owner->pf_update_stat = DecoderUpdateStatVideo;
             break;
         case AUDIO_ES:
-            p_dec->pf_queue_audio = DecoderQueueAudio;
+            p_dec->cbs = &dec_audio_cbs;
             p_owner->pf_update_stat = DecoderUpdateStatAudio;
             break;
         case SPU_ES:
-            p_dec->pf_queue_sub = DecoderQueueSpu;
+            p_dec->cbs = &dec_spu_cbs;
             p_owner->pf_update_stat = DecoderUpdateStatSpu;
             break;
         default:
             msg_Err( p_dec, "unknown ES format" );
-            UnloadDecoder( p_dec );
             return p_dec;
     }
+
+    /* Find a suitable decoder/packetizer module */
+    if( LoadDecoder( p_dec, p_sout != NULL, fmt ) )
+        return p_dec;
+
+    assert( p_dec->fmt_in.i_cat == p_dec->fmt_out.i_cat && fmt->i_cat == p_dec->fmt_in.i_cat);
+
     /* Copy ourself the input replay gain */
     if( fmt->i_cat == AUDIO_ES )
     {
@@ -1777,7 +1798,7 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
  */
 static void DeleteDecoder( decoder_t * p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     msg_Dbg( p_dec, "killing decoder fourcc `%4.4s'",
              (char*)&p_dec->fmt_in.i_codec );
@@ -1845,8 +1866,6 @@ static void DeleteDecoder( decoder_t * p_dec )
     vlc_mutex_destroy( &p_owner->lock );
 
     vlc_object_release( p_dec );
-
-    free( p_owner );
 }
 
 /* */
@@ -1895,7 +1914,8 @@ static decoder_t *decoder_New( vlc_object_t *p_parent, input_thread_t *p_input,
         return NULL;
     }
 
-    p_dec->p_owner->p_clock = p_clock;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
+    p_owner->p_clock = p_clock;
     assert( p_dec->fmt_out.i_cat != UNKNOWN_ES );
 
     if( p_dec->fmt_out.i_cat == AUDIO_ES )
@@ -1908,7 +1928,6 @@ static decoder_t *decoder_New( vlc_object_t *p_parent, input_thread_t *p_input,
     if( p_sout && fmt->b_packetized &&
         (fmt->i_cat != VIDEO_ES && fmt->i_cat != AUDIO_ES) )
     {
-        decoder_owner_sys_t *p_owner = p_dec->p_owner;
         p_owner->p_sout_input = sout_InputNew( p_owner->p_sout, fmt );
         if( p_owner->p_sout_input == NULL )
         {
@@ -1920,7 +1939,7 @@ static decoder_t *decoder_New( vlc_object_t *p_parent, input_thread_t *p_input,
 #endif
 
     /* Spawn the decoder thread */
-    if( vlc_clone( &p_dec->p_owner->thread, DecoderThread, p_dec, i_priority ) )
+    if( vlc_clone( &p_owner->thread, DecoderThread, p_dec, i_priority ) )
     {
         msg_Err( p_dec, "cannot spawn decoder thread" );
         DeleteDecoder( p_dec );
@@ -1965,7 +1984,7 @@ decoder_t *input_DecoderCreate( vlc_object_t *p_parent, const es_format_t *fmt,
  */
 void input_DecoderDelete( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_cancel( p_owner->thread );
 
@@ -1994,7 +2013,7 @@ void input_DecoderDelete( decoder_t *p_dec )
     vlc_join( p_owner->thread, NULL );
 
     /* */
-    if( p_dec->p_owner->cc.b_supported )
+    if( p_owner->cc.b_supported )
     {
         for( int i = 0; i < MAX_CC_DECODERS; i++ )
             input_DecoderSetCcState( p_dec, VLC_CODEC_CEA608, i, false );
@@ -2013,7 +2032,7 @@ void input_DecoderDelete( decoder_t *p_dec )
  */
 void input_DecoderDecode( decoder_t *p_dec, block_t *p_block, bool b_do_pace )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_fifo_Lock( p_owner->p_fifo );
     if( !b_do_pace )
@@ -2044,12 +2063,12 @@ void input_DecoderDecode( decoder_t *p_dec, block_t *p_block, bool b_do_pace )
 
 bool input_DecoderIsEmpty( decoder_t * p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     assert( !p_owner->b_waiting );
 
     vlc_fifo_Lock( p_owner->p_fifo );
-    if( !vlc_fifo_IsEmpty( p_dec->p_owner->p_fifo ) || p_owner->b_draining )
+    if( !vlc_fifo_IsEmpty( p_owner->p_fifo ) || p_owner->b_draining )
     {
         vlc_fifo_Unlock( p_owner->p_fifo );
         return false;
@@ -2085,7 +2104,7 @@ bool input_DecoderIsEmpty( decoder_t * p_dec )
  */
 void input_DecoderDrain( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_fifo_Lock( p_owner->p_fifo );
     p_owner->b_draining = true;
@@ -2099,7 +2118,7 @@ void input_DecoderDrain( decoder_t *p_dec )
  */
 void input_DecoderFlush( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_fifo_Lock( p_owner->p_fifo );
 
@@ -2127,7 +2146,7 @@ void input_DecoderFlush( decoder_t *p_dec )
 
 void input_DecoderGetCcDesc( decoder_t *p_dec, decoder_cc_desc_t *p_desc )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_mutex_lock( &p_owner->lock );
     *p_desc = p_owner->cc.desc;
@@ -2137,7 +2156,7 @@ void input_DecoderGetCcDesc( decoder_t *p_dec, decoder_cc_desc_t *p_desc )
 static bool input_DecoderHasCCChanFlag( decoder_t *p_dec,
                                         vlc_fourcc_t codec, int i_channel )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     int i_max_channels;
     uint64_t i_bitmap;
@@ -2160,7 +2179,7 @@ static bool input_DecoderHasCCChanFlag( decoder_t *p_dec,
 int input_DecoderSetCcState( decoder_t *p_dec, vlc_fourcc_t codec,
                              int i_channel, bool b_decode )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     //msg_Warn( p_dec, "input_DecoderSetCcState: %d @%x", b_decode, i_channel );
 
@@ -2176,7 +2195,7 @@ int input_DecoderSetCcState( decoder_t *p_dec, vlc_fourcc_t codec,
         fmt.subs.cc.i_channel = i_channel;
         fmt.subs.cc.i_reorder_depth = p_owner->cc.desc.i_reorder_depth;
         p_cc = input_DecoderNew( p_owner->p_input, &fmt,
-                              p_dec->p_owner->p_clock, p_owner->p_sout );
+                                 p_owner->p_clock, p_owner->p_sout );
         if( !p_cc )
         {
             msg_Err( p_dec, "could not create decoder" );
@@ -2191,7 +2210,8 @@ int input_DecoderSetCcState( decoder_t *p_dec, vlc_fourcc_t codec,
             input_DecoderDelete(p_cc);
             return VLC_EGENERIC;
         }
-        p_cc->p_owner->p_clock = p_owner->p_clock;
+        struct decoder_owner *p_ccowner = dec_get_owner( p_cc );
+        p_ccowner->p_clock = p_owner->p_clock;
 
         vlc_mutex_lock( &p_owner->lock );
         p_owner->cc.pp_decoder[i_channel] = p_cc;
@@ -2215,7 +2235,7 @@ int input_DecoderSetCcState( decoder_t *p_dec, vlc_fourcc_t codec,
 int input_DecoderGetCcState( decoder_t *p_dec, vlc_fourcc_t codec,
                              int i_channel, bool *pb_decode )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     if( !input_DecoderHasCCChanFlag( p_dec, codec, i_channel ) )
         return VLC_EGENERIC;
@@ -2228,7 +2248,7 @@ int input_DecoderGetCcState( decoder_t *p_dec, vlc_fourcc_t codec,
 
 void input_DecoderChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     /* Normally, p_owner->b_paused != b_paused here. But if a track is added
      * while the input is paused (e.g. add sub file), then b_paused is
@@ -2243,7 +2263,7 @@ void input_DecoderChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date )
 
 void input_DecoderChangeRate( decoder_t *dec, float rate )
 {
-    decoder_owner_sys_t *owner = dec->p_owner;
+    struct decoder_owner *owner = dec_get_owner( dec );
 
     vlc_fifo_Lock( owner->p_fifo );
     owner->rate = rate;
@@ -2253,7 +2273,7 @@ void input_DecoderChangeRate( decoder_t *dec, float rate )
 
 void input_DecoderChangeDelay( decoder_t *p_dec, mtime_t i_delay )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_mutex_lock( &p_owner->lock );
     p_owner->i_ts_delay = i_delay;
@@ -2262,7 +2282,7 @@ void input_DecoderChangeDelay( decoder_t *p_dec, mtime_t i_delay )
 
 void input_DecoderStartWait( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     assert( !p_owner->b_waiting );
 
@@ -2276,7 +2296,7 @@ void input_DecoderStartWait( decoder_t *p_dec )
 
 void input_DecoderStopWait( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     assert( p_owner->b_waiting );
 
@@ -2288,7 +2308,7 @@ void input_DecoderStopWait( decoder_t *p_dec )
 
 void input_DecoderWait( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     assert( p_owner->b_waiting );
 
@@ -2314,7 +2334,7 @@ void input_DecoderWait( decoder_t *p_dec )
 
 void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     assert( p_owner->paused );
     *pi_duration = 0;
@@ -2335,7 +2355,7 @@ void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration )
 
 bool input_DecoderHasFormatChanged( decoder_t *p_dec, es_format_t *p_fmt, vlc_meta_t **pp_meta )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
     bool b_changed;
 
     vlc_mutex_lock( &p_owner->lock );
@@ -2363,7 +2383,7 @@ bool input_DecoderHasFormatChanged( decoder_t *p_dec, es_format_t *p_fmt, vlc_me
 
 size_t input_DecoderGetFifoSize( decoder_t *p_dec )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     return block_FifoSize( p_owner->p_fifo );
 }
@@ -2371,7 +2391,7 @@ size_t input_DecoderGetFifoSize( decoder_t *p_dec )
 void input_DecoderGetObjects( decoder_t *p_dec,
                               vout_thread_t **pp_vout, audio_output_t **pp_aout )
 {
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
 
     vlc_mutex_lock( &p_owner->lock );
     if( pp_vout )
diff --git a/src/misc/image.c b/src/misc/image.c
index 721a1e6118..2d55ec51d1 100644
--- a/src/misc/image.c
+++ b/src/misc/image.c
@@ -49,6 +49,17 @@
 #include <libvlc.h>
 #include <vlc_modules.h>
 
+struct decoder_owner
+{
+    decoder_t dec;
+    image_handler_t *p_image;
+};
+
+static inline struct decoder_owner *dec_get_owner( decoder_t *p_dec )
+{
+    return container_of( p_dec, struct decoder_owner, dec );
+}
+
 static picture_t *ImageRead( image_handler_t *, block_t *,
                              const video_format_t *, video_format_t * );
 static picture_t *ImageReadUrl( image_handler_t *, const char *,
@@ -61,7 +72,7 @@ static int ImageWriteUrl( image_handler_t *, picture_t *,
 static picture_t *ImageConvert( image_handler_t *, picture_t *,
                                 const video_format_t *, video_format_t * );
 
-static decoder_t *CreateDecoder( vlc_object_t *, const video_format_t * );
+static decoder_t *CreateDecoder( image_handler_t *, const video_format_t * );
 static void DeleteDecoder( decoder_t * );
 static encoder_t *CreateEncoder( vlc_object_t *, const video_format_t *,
                                  const video_format_t * );
@@ -123,8 +134,8 @@ void image_HandlerDelete( image_handler_t *p_image )
 
 static void ImageQueueVideo( decoder_t *p_dec, picture_t *p_pic )
 {
-    image_handler_t *p_image = p_dec->p_queue_ctx;
-    picture_fifo_Push( p_image->outfifo, p_pic );
+    struct decoder_owner *p_owner = dec_get_owner( p_dec );
+    picture_fifo_Push( p_owner->p_image->outfifo, p_pic );
 }
 
 static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
@@ -144,7 +155,7 @@ static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
     /* Start a decoder */
     if( !p_image->p_dec )
     {
-        p_image->p_dec = CreateDecoder( p_image->p_parent, p_fmt_in );
+        p_image->p_dec = CreateDecoder( p_image, p_fmt_in );
         if( !p_image->p_dec )
         {
             block_Release(p_block);
@@ -157,8 +168,6 @@ static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
             block_Release(p_block);
             return NULL;
         }
-        p_image->p_dec->pf_queue_video = ImageQueueVideo;
-        p_image->p_dec->p_queue_ctx = p_image;
     }
 
     p_block->i_pts = p_block->i_dts = mdate();
@@ -661,21 +670,31 @@ static picture_t *video_new_buffer( decoder_t *p_dec )
     return picture_NewFromFormat( &p_dec->fmt_out.video );
 }
 
-static decoder_t *CreateDecoder( vlc_object_t *p_this, const video_format_t *fmt )
+static decoder_t *CreateDecoder( image_handler_t *p_image, const video_format_t *fmt )
 {
     decoder_t *p_dec;
+    struct decoder_owner *p_owner;
 
-    p_dec = vlc_custom_create( p_this, sizeof( *p_dec ), "image decoder" );
-    if( p_dec == NULL )
+    p_owner = vlc_custom_create( p_image->p_parent, sizeof( *p_owner ), "image decoder" );
+    if( p_owner == NULL )
         return NULL;
+    p_dec = &p_owner->dec;
+    p_owner->p_image = p_image;
 
     p_dec->p_module = NULL;
     es_format_InitFromVideo( &p_dec->fmt_in, fmt );
     es_format_Init( &p_dec->fmt_out, VIDEO_ES, 0 );
     p_dec->b_frame_drop_allowed = false;
 
-    p_dec->pf_vout_format_update = video_update_format;
-    p_dec->pf_vout_buffer_new = video_new_buffer;
+    static const struct decoder_owner_callbacks dec_cbs =
+    {
+        .video = {
+            video_update_format,
+            video_new_buffer,
+            ImageQueueVideo,
+        },
+    };
+    p_dec->cbs = &dec_cbs;
 
     /* Find a suitable decoder module */
     p_dec->p_module = module_need_var( p_dec, "video decoder", "codec" );
-- 
2.17.0



More information about the vlc-devel mailing list