[vlc-commits] mmal: move the converter/resizer in its own file

Steve Lhomme git at videolan.org
Fri Jan 24 14:15:40 CET 2020


vlc | branch: master | Steve Lhomme <robux4 at ycbcr.xyz> | Wed Jan 22 15:40:38 2020 +0100| [c5ccfafef43a915a4a4d0c04f73c4cadced790ac] | committer: Steve Lhomme

mmal: move the converter/resizer in its own file

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=c5ccfafef43a915a4a4d0c04f73c4cadced790ac
---

 modules/hw/mmal/Makefile.am    |   2 +-
 modules/hw/mmal/codec.c        | 919 -----------------------------------------
 modules/hw/mmal/converter.c    | 913 ++++++++++++++++++++++++++++++++++++++++
 modules/hw/mmal/mmal_picture.c |  33 ++
 modules/hw/mmal/mmal_picture.h |  10 +
 5 files changed, 957 insertions(+), 920 deletions(-)

diff --git a/modules/hw/mmal/Makefile.am b/modules/hw/mmal/Makefile.am
index 5335ff33cf..7ed83e1bdc 100644
--- a/modules/hw/mmal/Makefile.am
+++ b/modules/hw/mmal/Makefile.am
@@ -11,7 +11,7 @@ libmmal_vout_plugin_la_LDFLAGS = $(AM_LDFLAGS) -lm
 libmmal_vout_plugin_la_LIBADD = $(LIBS_mmal)
 mmal_LTLIBRARIES = libmmal_vout_plugin.la
 
-libmmal_codec_plugin_la_SOURCES = codec.c subpic.c subpic.h mmal_picture.c mmal_picture.h \
+libmmal_codec_plugin_la_SOURCES = codec.c converter.c subpic.c subpic.h mmal_picture.c mmal_picture.h \
   mmal_cma.c mmal_cma.h
 libmmal_codec_plugin_la_CFLAGS = $(AM_CFLAGS)
 libmmal_codec_plugin_la_LDFLAGS = $(AM_LDFLAGS)
diff --git a/modules/hw/mmal/codec.c b/modules/hw/mmal/codec.c
index 15f53ef8d6..d03533d4cf 100644
--- a/modules/hw/mmal/codec.c
+++ b/modules/hw/mmal/codec.c
@@ -37,36 +37,22 @@
 #include <interface/mmal/util/mmal_util.h>
 #include <interface/mmal/util/mmal_default_components.h>
 
-#include "mmal_cma.h"
 #include "mmal_picture.h"
 
-#include "subpic.h"
-
 /*
  * This seems to be a bit high, but reducing it causes instabilities
  */
 #define NUM_EXTRA_BUFFERS 5
 //#define NUM_EXTRA_BUFFERS 10
-#define NUM_DECODER_BUFFER_HEADERS 30
-
-#define CONVERTER_BUFFERS 4  // Buffers on the output of the converter
-
-#define MMAL_SLICE_HEIGHT 16
-#define MMAL_ALIGN_W      32
-#define MMAL_ALIGN_H      16
 
-#define MMAL_RESIZE_NAME "mmal-resize"
 #define MMAL_RESIZE_TEXT N_("Use mmal resizer rather than hvs.")
 #define MMAL_RESIZE_LONGTEXT N_("Use mmal resizer rather than isp. This uses less gpu memory than the ISP but is slower.")
 
-#define MMAL_ISP_NAME "mmal-isp"
 #define MMAL_ISP_TEXT N_("Use mmal isp rather than hvs.")
 #define MMAL_ISP_LONGTEXT N_("Use mmal isp rather than Hardware Video Scaler. This may be faster but has no blend.")
 
 static int OpenDecoder(vlc_object_t *);
 static void CloseDecoder(vlc_object_t *);
-static int OpenConverter(vlc_object_t *);
-static void CloseConverter(vlc_object_t *);
 
 vlc_module_begin()
     set_category( CAT_INPUT )
@@ -197,39 +183,6 @@ static MMAL_FOURCC_T vlc_to_mmal_es_fourcc(const unsigned int fcc)
     return 0;
 }
 
-static MMAL_FOURCC_T pic_to_slice_mmal_fourcc(const MMAL_FOURCC_T fcc)
-{
-    switch (fcc){
-    case MMAL_ENCODING_I420:
-        return MMAL_ENCODING_I420_SLICE;
-    case MMAL_ENCODING_I422:
-        return MMAL_ENCODING_I422_SLICE;
-    case MMAL_ENCODING_ARGB:
-        return MMAL_ENCODING_ARGB_SLICE;
-    case MMAL_ENCODING_RGBA:
-        return MMAL_ENCODING_RGBA_SLICE;
-    case MMAL_ENCODING_ABGR:
-        return MMAL_ENCODING_ABGR_SLICE;
-    case MMAL_ENCODING_BGRA:
-        return MMAL_ENCODING_BGRA_SLICE;
-    case MMAL_ENCODING_RGB16:
-        return MMAL_ENCODING_RGB16_SLICE;
-    case MMAL_ENCODING_RGB24:
-        return MMAL_ENCODING_RGB24_SLICE;
-    case MMAL_ENCODING_RGB32:
-        return MMAL_ENCODING_RGB32_SLICE;
-    case MMAL_ENCODING_BGR16:
-        return MMAL_ENCODING_BGR16_SLICE;
-    case MMAL_ENCODING_BGR24:
-        return MMAL_ENCODING_BGR24_SLICE;
-    case MMAL_ENCODING_BGR32:
-        return MMAL_ENCODING_BGR32_SLICE;
-    default:
-        break;
-    }
-    return 0;
-}
-
 // Buffer either attached to pic or released
 static picture_t * alloc_opaque_pic(decoder_t * const dec, MMAL_BUFFER_HEADER_T * const buf)
 {
@@ -755,875 +708,3 @@ fail:
     CloseDecoder(p_this);
     return ret;
 }
-
-// ----------------------------
-
-#define CONV_MAX_LATENCY 1  // In frames
-
-typedef struct pic_fifo_s {
-    picture_t * head;
-    picture_t * tail;
-} pic_fifo_t;
-
-static picture_t * pic_fifo_get(pic_fifo_t * const pf)
-{
-    picture_t * const pic = pf->head;;
-    if (pic != NULL) {
-        pf->head = pic->p_next;
-        pic->p_next = NULL;
-    }
-    return pic;
-}
-
-static void pic_fifo_release_all(pic_fifo_t * const pf)
-{
-    picture_t * pic;
-    while ((pic = pic_fifo_get(pf)) != NULL) {
-        picture_Release(pic);
-    }
-}
-
-static void pic_fifo_init(pic_fifo_t * const pf)
-{
-    pf->head = NULL;
-    pf->tail = NULL;  // Not strictly needed
-}
-
-static void pic_fifo_put(pic_fifo_t * const pf, picture_t * pic)
-{
-    pic->p_next = NULL;
-    if (pf->head == NULL)
-        pf->head = pic;
-    else
-        pf->tail->p_next = pic;
-    pf->tail = pic;
-}
-
-#define SUBS_MAX 3
-
-typedef enum filter_resizer_e {
-    FILTER_RESIZER_RESIZER,
-    FILTER_RESIZER_ISP,
-    FILTER_RESIZER_HVS,
-} filter_resizer_t;
-
-typedef struct conv_frame_stash_s
-{
-    mtime_t pts;
-    MMAL_BUFFER_HEADER_T * sub_bufs[SUBS_MAX];
-} conv_frame_stash_t;
-
-typedef struct
-{
-    filter_resizer_t resizer_type;
-    MMAL_COMPONENT_T *component;
-    MMAL_PORT_T *input;
-    MMAL_PORT_T *output;
-    MMAL_POOL_T *out_pool;  // Free output buffers
-    MMAL_POOL_T *in_pool;   // Input pool to get BH for replication
-
-    cma_buf_pool_t * cma_in_pool;
-    cma_buf_pool_t * cma_out_pool;
-
-    subpic_reg_stash_t subs[SUBS_MAX];
-
-    pic_fifo_t ret_pics;
-
-    unsigned int pic_n;
-    vlc_sem_t sem;
-    vlc_mutex_t lock;
-
-    MMAL_STATUS_T err_stream;
-
-    bool needs_copy_in;
-    bool is_sliced;
-    bool out_fmt_set;
-    const char * component_name;
-    MMAL_PORT_BH_CB_T in_port_cb_fn;
-    MMAL_PORT_BH_CB_T out_port_cb_fn;
-
-    uint64_t frame_seq;
-    conv_frame_stash_t stash[16];
-
-    // Slice specific tracking stuff
-    struct {
-        pic_fifo_t pics;
-        unsigned int line;  // Lines filled
-    } slice;
-
-    vcsm_init_type_t vcsm_init_type;
-} converter_sys_t;
-
-
-static MMAL_STATUS_T pic_to_format(MMAL_ES_FORMAT_T * const es_fmt, const picture_t * const pic)
-{
-    unsigned int bpp = (pic->format.i_bits_per_pixel + 7) >> 3;
-    MMAL_VIDEO_FORMAT_T * const v_fmt = &es_fmt->es->video;
-
-    es_fmt->type = MMAL_ES_TYPE_VIDEO;
-    es_fmt->encoding = vlc_to_mmal_video_fourcc(&pic->format);
-    es_fmt->encoding_variant = 0;
-
-    // Fill in crop etc.
-    hw_mmal_vlc_fmt_to_mmal_fmt(es_fmt, &pic->format);
-    // Override width / height with strides if appropriate
-    if (bpp != 0) {
-        v_fmt->width = pic->p[0].i_pitch / bpp;
-        v_fmt->height = pic->p[0].i_lines;
-    }
-    return MMAL_SUCCESS;
-}
-
-
-static MMAL_STATUS_T conv_enable_in(filter_t * const p_filter, converter_sys_t * const sys)
-{
-    MMAL_STATUS_T err = MMAL_SUCCESS;
-
-    if (!sys->input->is_enabled &&
-        (err = mmal_port_enable(sys->input, sys->in_port_cb_fn)) != MMAL_SUCCESS)
-    {
-        msg_Err(p_filter, "Failed to enable input port %s (status=%"PRIx32" %s)",
-                sys->input->name, err, mmal_status_to_string(err));
-    }
-    return err;
-}
-
-static MMAL_STATUS_T conv_enable_out(filter_t * const p_filter, converter_sys_t * const sys)
-{
-    MMAL_STATUS_T err = MMAL_SUCCESS;
-
-    {
-        cma_buf_pool_deletez(&sys->cma_out_pool);
-    }
-
-    if (!sys->output->is_enabled &&
-        (err = mmal_port_enable(sys->output, sys->out_port_cb_fn)) != MMAL_SUCCESS)
-    {
-        msg_Err(p_filter, "Failed to enable output port %s (status=%"PRIx32" %s)",
-                sys->output->name, err, mmal_status_to_string(err));
-    }
-    return err;
-}
-
-static void conv_control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
-{
-    filter_t * const p_filter = (filter_t *)port->userdata;
-
-    if (buffer->cmd == MMAL_EVENT_ERROR) {
-        MMAL_STATUS_T status = *(uint32_t *)buffer->data;
-
-        converter_sys_t * sys = p_filter->p_sys;
-        sys->err_stream = status;
-
-        msg_Err(p_filter, "MMAL error %"PRIx32" \"%s\"", status,
-                mmal_status_to_string(status));
-    }
-
-    mmal_buffer_header_release(buffer);
-}
-
-static void conv_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
-{
-    VLC_UNUSED(port);
-
-    mmal_buffer_header_release(buf);
-}
-
-static void conv_out_q_pic(converter_sys_t * const sys, picture_t * const pic)
-{
-    pic->p_next = NULL;
-
-    vlc_mutex_lock(&sys->lock);
-    pic_fifo_put(&sys->ret_pics, pic);
-    vlc_mutex_unlock(&sys->lock);
-
-    vlc_sem_post(&sys->sem);
-}
-
-static void conv_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
-{
-    filter_t * const p_filter = (filter_t *)port->userdata;
-    converter_sys_t * const sys = p_filter->p_sys;
-
-    if (buf->cmd == 0) {
-        picture_t * const pic = (picture_t *)buf->user_data;
-
-        if (pic == NULL) {
-            msg_Err(p_filter, "Buffer has no attached picture");
-        }
-        else if (buf->data != NULL && buf->length != 0)
-        {
-            buf_to_pic_copy_props(pic, buf);
-
-            buf->user_data = NULL;  // Responsability for this pic no longer with buffer
-            conv_out_q_pic(sys, pic);
-        }
-    }
-
-    mmal_buffer_header_release(buf);
-}
-
-
-static void slice_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
-{
-    filter_t * const p_filter = (filter_t *)port->userdata;
-    converter_sys_t * const sys = p_filter->p_sys;
-
-    if (buf->cmd != 0)
-    {
-        mmal_buffer_header_release(buf);
-        return;
-    }
-
-    if (buf->data != NULL && buf->length != 0)
-    {
-        // Got slice
-        picture_t *pic = sys->slice.pics.head;
-        const unsigned int scale_lines = sys->output->format->es->video.height;  // Expected lines of callback
-
-        if (pic == NULL) {
-            msg_Err(p_filter, "No output picture");
-            goto fail;
-        }
-
-        // Copy lines
-        // * single plane only - fix for I420
-        {
-            const unsigned int scale_n = __MIN(scale_lines - sys->slice.line, MMAL_SLICE_HEIGHT);
-            const unsigned int pic_lines = pic->p[0].i_lines;
-            const unsigned int copy_n = sys->slice.line + scale_n <= pic_lines ? scale_n :
-                sys->slice.line >= pic_lines ? 0 :
-                    pic_lines - sys->slice.line;
-
-            const unsigned int src_stride = buf->type->video.pitch[0];
-            const unsigned int dst_stride = pic->p[0].i_pitch;
-            uint8_t *dst = pic->p[0].p_pixels + sys->slice.line * dst_stride;
-            const uint8_t *src = buf->data + buf->type->video.offset[0];
-
-            if (src_stride == dst_stride) {
-                if (copy_n != 0)
-                    memcpy(dst, src, src_stride * copy_n);
-            }
-            else {
-                unsigned int i;
-                for (i = 0; i != copy_n; ++i) {
-                    memcpy(dst, src, __MIN(dst_stride, src_stride));
-                    dst += dst_stride;
-                    src += src_stride;
-                }
-            }
-            sys->slice.line += scale_n;
-        }
-
-        if ((buf->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) != 0 || sys->slice.line >= scale_lines) {
-
-            if ((buf->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) == 0 || sys->slice.line != scale_lines) {
-                // Stuff doesn't add up...
-                msg_Err(p_filter, "Line count (%d/%d) & EOF disagree (flags=%#x)", sys->slice.line, scale_lines, buf->flags);
-                goto fail;
-            }
-            else {
-                sys->slice.line = 0;
-
-                vlc_mutex_lock(&sys->lock);
-                pic_fifo_get(&sys->slice.pics);  // Remove head from Q
-                vlc_mutex_unlock(&sys->lock);
-
-                buf_to_pic_copy_props(pic, buf);
-                conv_out_q_pic(sys, pic);
-            }
-        }
-    }
-
-    // Put back
-    buf->user_data = NULL; // Zap here to make sure we can't reuse later
-    mmal_buffer_header_reset(buf);
-
-    if (mmal_port_send_buffer(sys->output, buf) != MMAL_SUCCESS) {
-        mmal_buffer_header_release(buf);
-    }
-    return;
-
-fail:
-    sys->err_stream = MMAL_EIO;
-    vlc_sem_post(&sys->sem);  // If we were waiting then break us out - the flush should fix sem values
-}
-
-
-static void conv_flush(filter_t * p_filter)
-{
-    converter_sys_t * const sys = p_filter->p_sys;
-    unsigned int i;
-
-    if (sys->resizer_type == FILTER_RESIZER_HVS)
-    {
-        for (i = 0; i != SUBS_MAX; ++i) {
-            hw_mmal_subpic_flush(sys->subs + i);
-        }
-    }
-
-    if (sys->input != NULL && sys->input->is_enabled)
-        mmal_port_disable(sys->input);
-
-    if (sys->output != NULL && sys->output->is_enabled)
-        mmal_port_disable(sys->output);
-
-//    cma_buf_pool_deletez(&sys->cma_out_pool);
-
-    // Free up anything we may have already lying around
-    // Don't need lock as the above disables should have prevented anything
-    // happening in the background
-
-    for (i = 0; i != 16; ++i) {
-        conv_frame_stash_t *const stash = sys->stash + i;
-        unsigned int sub_no;
-
-        stash->pts = MMAL_TIME_UNKNOWN;
-        for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
-            if (stash->sub_bufs[sub_no] != NULL) {
-                mmal_buffer_header_release(stash->sub_bufs[sub_no]);
-                stash->sub_bufs[sub_no] = NULL;
-            }
-        }
-    }
-
-    pic_fifo_release_all(&sys->slice.pics);
-    pic_fifo_release_all(&sys->ret_pics);
-
-    // Reset sem values - easiest & most reliable way is to just kill & re-init
-    vlc_sem_destroy(&sys->sem);
-    vlc_sem_init(&sys->sem, 0);
-    sys->pic_n = 0;
-
-    // Reset error status
-    sys->err_stream = MMAL_SUCCESS;
-}
-
-static void conv_stash_fixup(filter_t * const p_filter, converter_sys_t * const sys, picture_t * const p_pic)
-{
-    conv_frame_stash_t * const stash = sys->stash + (p_pic->date & 0xf);
-    unsigned int sub_no;
-    VLC_UNUSED(p_filter);
-
-    p_pic->date = stash->pts;
-    for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
-        if (stash->sub_bufs[sub_no] != NULL) {
-            // **** Do stashed blend
-            // **** Aaargh, bother... need to rescale subs too
-
-            mmal_buffer_header_release(stash->sub_bufs[sub_no]);
-            stash->sub_bufs[sub_no] = NULL;
-        }
-    }
-}
-
-// Output buffers may contain a pic ref on error or flush
-// Free it
-static MMAL_BOOL_T out_buffer_pre_release_cb(MMAL_BUFFER_HEADER_T *header, void *userdata)
-{
-    VLC_UNUSED(userdata);
-
-    picture_t * const pic = header->user_data;
-    header->user_data = NULL;
-
-    if (pic != NULL)
-        picture_Release(pic);
-
-    return MMAL_FALSE;
-}
-
-static MMAL_STATUS_T conv_set_output(filter_t * const p_filter, converter_sys_t * const sys, picture_t * const pic)
-{
-    MMAL_STATUS_T status;
-
-    sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)p_filter;
-    sys->output->format->type = MMAL_ES_TYPE_VIDEO;
-    sys->output->format->encoding = vlc_to_mmal_video_fourcc(&p_filter->fmt_out.video);
-    sys->output->format->encoding_variant = 0;
-    hw_mmal_vlc_fmt_to_mmal_fmt(sys->output->format, &p_filter->fmt_out.video);
-
-    if (pic != NULL)
-    {
-        // Override default format width/height if we have a pic we need to match
-        if ((status = pic_to_format(sys->output->format, pic)) != MMAL_SUCCESS)
-        {
-            msg_Err(p_filter, "Bad format desc: %4.4s, pic=%p, bits=%d", (const char*)&pic->format.i_chroma, pic, pic->format.i_bits_per_pixel);
-            return status;
-        }
-    }
-
-    if (sys->is_sliced) {
-        // Override height for slice
-        sys->output->format->es->video.height = MMAL_SLICE_HEIGHT;
-    }
-
-    mmal_log_dump_format(sys->output->format);
-
-    status = mmal_port_format_commit(sys->output);
-    if (status != MMAL_SUCCESS) {
-        msg_Err(p_filter, "Failed to commit format for output port %s (status=%"PRIx32" %s)",
-                sys->output->name, status, mmal_status_to_string(status));
-        return status;
-    }
-
-    sys->output->buffer_num = __MAX(sys->is_sliced ? 16 : 2, sys->output->buffer_num_recommended);
-    sys->output->buffer_size = sys->output->buffer_size_recommended;
-
-    if ((status = conv_enable_out(p_filter, sys)) != MMAL_SUCCESS)
-        return status;
-
-    return MMAL_SUCCESS;
-}
-
-static picture_t *conv_filter(filter_t *p_filter, picture_t *p_pic)
-{
-    converter_sys_t * const sys = p_filter->p_sys;
-    picture_t * ret_pics;
-    MMAL_STATUS_T err;
-    const uint64_t frame_seq = ++sys->frame_seq;
-    conv_frame_stash_t * const stash = sys->stash + (frame_seq & 0xf);
-    MMAL_BUFFER_HEADER_T * out_buf = NULL;
-
-    if (sys->err_stream != MMAL_SUCCESS) {
-        goto stream_fail;
-    }
-
-    // Check pic fmt corresponds to what we have set up
-    // ??? ISP may require flush (disable) but actually seems quite happy
-    //     without
-    if (hw_mmal_vlc_pic_to_mmal_fmt_update(sys->input->format, p_pic))
-    {
-        msg_Dbg(p_filter, "Reset input port format");
-        mmal_port_format_commit(sys->input);
-    }
-
-    if (p_pic->context == NULL) {
-        // Can't have stashed subpics if not one of our pics
-        if (!sys->needs_copy_in)
-            msg_Dbg(p_filter, "No context");
-    }
-    else if (sys->resizer_type == FILTER_RESIZER_HVS)
-    {
-        unsigned int sub_no = 0;
-
-        for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
-            int rv;
-            if ((rv = hw_mmal_subpic_update(VLC_OBJECT(p_filter),
-                                            hw_mmal_pic_sub_buf_get(p_pic, sub_no),
-                                            sys->subs + sub_no,
-                                            &p_pic->format,
-                                            &sys->output->format->es->video.crop,
-                                            frame_seq)) == 0)
-                break;
-            else if (rv < 0)
-                goto fail;
-        }
-    }
-    else
-    {
-        unsigned int sub_no = 0;
-        for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
-            if ((stash->sub_bufs[sub_no] = hw_mmal_pic_sub_buf_get(p_pic, sub_no)) != NULL) {
-                mmal_buffer_header_acquire(stash->sub_bufs[sub_no]);
-            }
-        }
-    }
-
-    if (!sys->out_fmt_set) {
-        sys->out_fmt_set = true;
-
-        if (sys->is_sliced) {
-            // If zc then we will do stride conversion when we copy to arm side
-            // so no need to worry about actual pic dimensions here
-            if ((err = conv_set_output(p_filter, sys, NULL)) != MMAL_SUCCESS)
-                goto fail;
-
-            sys->out_pool = mmal_port_pool_create(sys->output, sys->output->buffer_num, sys->output->buffer_size);
-        }
-        else {
-            picture_t *pic = filter_NewPicture(p_filter);
-            err = conv_set_output(p_filter, sys, pic);
-            picture_Release(pic);
-            if (err != MMAL_SUCCESS)
-                goto fail;
-
-            sys->out_pool = mmal_pool_create(sys->output->buffer_num, 0);
-        }
-
-        if (sys->out_pool == NULL) {
-            msg_Err(p_filter, "Failed to create output pool");
-            goto fail;
-        }
-    }
-
-    // Reenable stuff if the last thing we did was flush
-    if ((err = conv_enable_out(p_filter, sys)) != MMAL_SUCCESS ||
-        (err = conv_enable_in(p_filter, sys)) != MMAL_SUCCESS)
-        goto fail;
-
-    // We attach pic to buf before stuffing the output port
-    // We could attach the pic on output for cma, but it is a lot easier to keep
-    // the code common.
-    {
-        picture_t * const out_pic = filter_NewPicture(p_filter);
-
-        if (out_pic == NULL)
-        {
-            msg_Err(p_filter, "Failed to alloc required filter output pic");
-            goto fail;
-        }
-
-        out_pic->format.i_sar_den = p_filter->fmt_out.video.i_sar_den;
-        out_pic->format.i_sar_num = p_filter->fmt_out.video.i_sar_num;
-
-        if (sys->is_sliced) {
-            vlc_mutex_lock(&sys->lock);
-            pic_fifo_put(&sys->slice.pics, out_pic);
-            vlc_mutex_unlock(&sys->lock);
-
-            // Poke any returned pic buffers into output
-            // In general this should only happen immediately after enable
-            while ((out_buf = mmal_queue_get(sys->out_pool->queue)) != NULL)
-                mmal_port_send_buffer(sys->output, out_buf);
-        }
-        else
-        {
-            // 1 in - 1 out
-            if ((out_buf = mmal_queue_wait(sys->out_pool->queue)) == NULL)
-            {
-                msg_Err(p_filter, "Failed to get output buffer");
-                picture_Release(out_pic);
-                goto fail;
-            }
-            mmal_buffer_header_reset(out_buf);
-
-            // Attach out_pic to the buffer & ensure it is freed when the buffer is released
-            // On a good send callback the pic will be extracted to avoid this
-            out_buf->user_data = out_pic;
-            mmal_buffer_header_pre_release_cb_set(out_buf, out_buffer_pre_release_cb, NULL);
-
-            {
-                out_buf->data = out_pic->p[0].p_pixels;
-                out_buf->alloc_size = out_pic->p[0].i_pitch * out_pic->p[0].i_lines;
-                //**** stride ????
-            }
-
-            if ((err = mmal_port_send_buffer(sys->output, out_buf)) != MMAL_SUCCESS)
-            {
-                msg_Err(p_filter, "Send buffer to output failed");
-                goto fail;
-            }
-            out_buf = NULL;
-        }
-    }
-
-
-    // Stuff into input
-    // We assume the BH is already set up with values reflecting pic date etc.
-    stash->pts = p_pic->date;
-    {
-        MMAL_BUFFER_HEADER_T *const pic_buf = sys->needs_copy_in ?
-            hw_mmal_pic_buf_copied(p_pic, sys->in_pool, sys->input, sys->cma_in_pool) :
-            hw_mmal_pic_buf_replicated(p_pic, sys->in_pool);
-
-        // Whether or not we extracted the pic_buf we are done with the picture
-        picture_Release(p_pic);
-        p_pic = NULL;
-
-        if (pic_buf == NULL) {
-            msg_Err(p_filter, "Pic has no attached buffer");
-            goto fail;
-        }
-
-        pic_buf->pts = frame_seq;
-
-        if ((err = mmal_port_send_buffer(sys->input, pic_buf)) != MMAL_SUCCESS)
-        {
-            msg_Err(p_filter, "Send buffer to input failed");
-            mmal_buffer_header_release(pic_buf);
-            goto fail;
-        }
-    }
-
-    // We have a 1 pic latency for everything except the 1st pic which we
-    // wait for.
-    // This means we get a single static pic out
-    if (sys->pic_n++ == 1) {
-        return NULL;
-    }
-    vlc_sem_wait(&sys->sem);
-
-    // Return a single pending buffer
-    vlc_mutex_lock(&sys->lock);
-    ret_pics = pic_fifo_get(&sys->ret_pics);
-    vlc_mutex_unlock(&sys->lock);
-
-    if (sys->err_stream != MMAL_SUCCESS)
-        goto stream_fail;
-
-    conv_stash_fixup(p_filter, sys, ret_pics);
-
-    return ret_pics;
-
-stream_fail:
-    msg_Err(p_filter, "MMAL error reported by callback");
-fail:
-    if (out_buf != NULL)
-        mmal_buffer_header_release(out_buf);
-    if (p_pic != NULL)
-        picture_Release(p_pic);
-    conv_flush(p_filter);
-    return NULL;
-}
-
-static void CloseConverter(vlc_object_t * obj)
-{
-    filter_t * const p_filter = (filter_t *)obj;
-    converter_sys_t * const sys = p_filter->p_sys;
-
-    if (sys == NULL)
-        return;
-
-    // Disables input & output ports
-    conv_flush(p_filter);
-
-    cma_buf_pool_deletez(&sys->cma_in_pool);
-    cma_buf_pool_deletez(&sys->cma_out_pool);
-
-    if (sys->component && sys->component->control->is_enabled)
-        mmal_port_disable(sys->component->control);
-
-    if (sys->component && sys->component->is_enabled)
-        mmal_component_disable(sys->component);
-
-    if (sys->resizer_type == FILTER_RESIZER_HVS)
-    {
-        for (size_t i = 0; i != SUBS_MAX; ++i) {
-            hw_mmal_subpic_close(sys->subs + i);
-        }
-    }
-
-    if (sys->out_pool)
-    {
-        if (sys->is_sliced)
-            mmal_port_pool_destroy(sys->output, sys->out_pool);
-        else
-            mmal_pool_destroy(sys->out_pool);
-    }
-
-    if (sys->in_pool != NULL)
-        mmal_pool_destroy(sys->in_pool);
-
-    if (sys->component)
-        mmal_component_release(sys->component);
-
-    cma_vcsm_exit(sys->vcsm_init_type);
-
-    vlc_sem_destroy(&sys->sem);
-    vlc_mutex_destroy(&sys->lock);
-
-    p_filter->p_sys = NULL;
-    free(sys);
-}
-
-
-static MMAL_FOURCC_T filter_enc_in(const video_format_t * const fmt)
-{
-    if (hw_mmal_chroma_is_mmal(fmt->i_chroma) || fmt->i_chroma == VLC_CODEC_I420)
-        return vlc_to_mmal_video_fourcc(fmt);
-
-    if (fmt->i_chroma == VLC_CODEC_I420_10L)
-        return MMAL_ENCODING_I420;
-
-    return 0;
-}
-
-
-static int OpenConverter(vlc_object_t * obj)
-{
-    filter_t * const p_filter = (filter_t *)obj;
-    int ret = VLC_EGENERIC;
-    converter_sys_t *sys;
-    MMAL_STATUS_T status;
-    if (p_filter->fmt_out.video.i_chroma == VLC_CODEC_I420)
-        return VLC_EGENERIC;
-    const MMAL_FOURCC_T enc_out = vlc_to_mmal_video_fourcc(&p_filter->fmt_out.video);
-    const MMAL_FOURCC_T enc_in = filter_enc_in(&p_filter->fmt_in.video);
-    bool use_resizer;
-    bool use_isp;
-
-    // At least in principle we should deal with any mmal format as input
-    if (enc_in == 0 || enc_out == 0)
-        return VLC_EGENERIC;
-
-    use_resizer = var_InheritBool(p_filter, MMAL_RESIZE_NAME);
-    use_isp = var_InheritBool(p_filter, MMAL_ISP_NAME);
-
-retry:
-    // ** Make more generic by checking supported encs
-    //
-    // Must use ISP - HVS can't do this, nor can resizer
-    if (enc_in == MMAL_ENCODING_YUVUV64_10) {
-        // If resizer selected then just give up
-        if (use_resizer)
-            return VLC_EGENERIC;
-        // otherwise downgrade HVS to ISP
-        use_isp = true;
-    }
-    // HVS can't do I420
-    if (enc_out == MMAL_ENCODING_I420) {
-        use_isp = true;
-    }
-    // Only HVS can deal with SAND30
-    if (enc_in == MMAL_ENCODING_YUV10_COL) {
-        if (use_isp || use_resizer)
-            return VLC_EGENERIC;
-    }
-
-
-    if (use_resizer) {
-        // use resizer overrides use_isp
-        use_isp = false;
-    }
-
-    // Check we have a sliced version of the fourcc if we want the resizer
-    if (use_resizer && pic_to_slice_mmal_fourcc(enc_out) == 0) {
-        return VLC_EGENERIC;
-    }
-
-    sys = calloc(1, sizeof(converter_sys_t));
-    if (!sys) {
-        ret = VLC_ENOMEM;
-        goto fail;
-    }
-    p_filter->p_sys = sys;
-
-    // Init stuff the we destroy unconditionaly in Close first
-    vlc_mutex_init(&sys->lock);
-    vlc_sem_init(&sys->sem, 0);
-    sys->err_stream = MMAL_SUCCESS;
-    pic_fifo_init(&sys->ret_pics);
-    pic_fifo_init(&sys->slice.pics);
-
-    sys->needs_copy_in = !hw_mmal_chroma_is_mmal(p_filter->fmt_in.video.i_chroma);
-    sys->in_port_cb_fn = conv_input_port_cb;
-
-    if ((sys->vcsm_init_type = cma_vcsm_init()) == VCSM_INIT_NONE) {
-        msg_Err(p_filter, "VCSM init failed");
-        goto fail;
-    }
-
-    if (use_resizer) {
-        sys->resizer_type = FILTER_RESIZER_RESIZER;
-        sys->is_sliced = true;
-        sys->component_name = MMAL_COMPONENT_DEFAULT_RESIZER;
-        sys->out_port_cb_fn = slice_output_port_cb;
-    }
-    else if (use_isp) {
-        sys->resizer_type = FILTER_RESIZER_ISP;
-        sys->is_sliced = false;  // Copy directly into filter picture
-        sys->component_name = MMAL_COMPONENT_ISP_RESIZER;
-        sys->out_port_cb_fn = conv_output_port_cb;
-    } else {
-        sys->resizer_type = FILTER_RESIZER_HVS;
-        sys->is_sliced = false;  // Copy directly into filter picture
-        sys->component_name = MMAL_COMPONENT_HVS;
-        sys->out_port_cb_fn = conv_output_port_cb;
-    }
-
-    status = mmal_component_create(sys->component_name, &sys->component);
-    if (status != MMAL_SUCCESS) {
-        if (!use_isp && !use_resizer) {
-            msg_Warn(p_filter, "Failed to rcreate HVS resizer - retrying with ISP");
-            CloseConverter(obj);
-            use_isp = true;
-            goto retry;
-        }
-        msg_Err(p_filter, "Failed to create MMAL component %s (status=%"PRIx32" %s)",
-                MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status));
-        goto fail;
-    }
-    sys->output = sys->component->output[0];
-    sys->input  = sys->component->input[0];
-
-    sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)p_filter;
-    status = mmal_port_enable(sys->component->control, conv_control_port_cb);
-    if (status != MMAL_SUCCESS) {
-        msg_Err(p_filter, "Failed to enable control port %s (status=%"PRIx32" %s)",
-                sys->component->control->name, status, mmal_status_to_string(status));
-        goto fail;
-    }
-
-    if (sys->needs_copy_in &&
-        (sys->cma_in_pool = cma_buf_pool_new(2, 2, true, "conv-copy-in")) == NULL)
-    {
-        msg_Err(p_filter, "Failed to allocate input CMA pool");
-        goto fail;
-    }
-
-    sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)p_filter;
-    sys->input->format->type = MMAL_ES_TYPE_VIDEO;
-    sys->input->format->encoding = enc_in;
-    sys->input->format->encoding_variant = MMAL_ENCODING_I420;
-    hw_mmal_vlc_fmt_to_mmal_fmt(sys->input->format, &p_filter->fmt_in.video);
-    port_parameter_set_bool(sys->input, MMAL_PARAMETER_ZERO_COPY, 1);
-
-    mmal_log_dump_format(sys->input->format);
-
-    status = mmal_port_format_commit(sys->input);
-    if (status != MMAL_SUCCESS) {
-        msg_Err(p_filter, "Failed to commit format for input port %s (status=%"PRIx32" %s)",
-                sys->input->name, status, mmal_status_to_string(status));
-        goto fail;
-    }
-    sys->input->buffer_size = sys->input->buffer_size_recommended;
-    sys->input->buffer_num = NUM_DECODER_BUFFER_HEADERS;
-
-    if ((status = conv_enable_in(p_filter, sys)) != MMAL_SUCCESS)
-        goto fail;
-
-    port_parameter_set_bool(sys->output, MMAL_PARAMETER_ZERO_COPY, sys->is_sliced);
-
-    status = mmal_component_enable(sys->component);
-    if (status != MMAL_SUCCESS) {
-        msg_Err(p_filter, "Failed to enable component %s (status=%"PRIx32" %s)",
-                sys->component->name, status, mmal_status_to_string(status));
-        goto fail;
-    }
-
-    if ((sys->in_pool = mmal_pool_create(sys->input->buffer_num, 0)) == NULL)
-    {
-        msg_Err(p_filter, "Failed to create input pool");
-        goto fail;
-    }
-
-    if (sys->resizer_type == FILTER_RESIZER_HVS)
-    {
-        unsigned int i;
-        for (i = 0; i != SUBS_MAX; ++i) {
-            if (hw_mmal_subpic_open(VLC_OBJECT(p_filter), sys->subs + i, sys->component->input[i + 1], -1, i + 1) != MMAL_SUCCESS)
-            {
-                msg_Err(p_filter, "Failed to open subpic %d", i);
-                goto fail;
-            }
-        }
-    }
-
-    p_filter->pf_video_filter = conv_filter;
-    p_filter->pf_flush = conv_flush;
-    // video_drain NIF in filter structure
-
-    return VLC_SUCCESS;
-
-fail:
-    CloseConverter(obj);
-
-    if (!use_resizer && status == MMAL_ENOMEM) {
-        use_resizer = true;
-        msg_Warn(p_filter, "Lack of memory to use HVS/ISP: trying resizer");
-        goto retry;
-    }
-
-    return ret;
-}
-
diff --git a/modules/hw/mmal/converter.c b/modules/hw/mmal/converter.c
new file mode 100644
index 0000000000..5ba1d7fa9c
--- /dev/null
+++ b/modules/hw/mmal/converter.c
@@ -0,0 +1,913 @@
+/*****************************************************************************
+ * converter.c: MMAL-based resizer
+ *****************************************************************************
+ * Copyright © 2014 jusst technologies GmbH
+ *
+ * Authors: Dennis Hamester <dennis.hamester at gmail.com>
+ *          Julian Scheel <julian at jusst.de>
+ *          John Cox <jc at kynesim.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdatomic.h>
+
+#include <vlc_common.h>
+#include <vlc_codec.h>
+#include <vlc_filter.h>
+
+#include <interface/mmal/mmal.h>
+#include <interface/mmal/util/mmal_util.h>
+#include <interface/mmal/util/mmal_default_components.h>
+
+#include "mmal_picture.h"
+
+#include "subpic.h"
+
+#define MMAL_SLICE_HEIGHT 16
+
+#define CONV_MAX_LATENCY 1  // In frames
+
+typedef struct pic_fifo_s {
+    picture_t * head;
+    picture_t * tail;
+} pic_fifo_t;
+
+static picture_t * pic_fifo_get(pic_fifo_t * const pf)
+{
+    picture_t * const pic = pf->head;;
+    if (pic != NULL) {
+        pf->head = pic->p_next;
+        pic->p_next = NULL;
+    }
+    return pic;
+}
+
+static void pic_fifo_release_all(pic_fifo_t * const pf)
+{
+    picture_t * pic;
+    while ((pic = pic_fifo_get(pf)) != NULL) {
+        picture_Release(pic);
+    }
+}
+
+static void pic_fifo_init(pic_fifo_t * const pf)
+{
+    pf->head = NULL;
+    pf->tail = NULL;  // Not strictly needed
+}
+
+static void pic_fifo_put(pic_fifo_t * const pf, picture_t * pic)
+{
+    pic->p_next = NULL;
+    if (pf->head == NULL)
+        pf->head = pic;
+    else
+        pf->tail->p_next = pic;
+    pf->tail = pic;
+}
+
+#define SUBS_MAX 3
+
+typedef enum filter_resizer_e {
+    FILTER_RESIZER_RESIZER,
+    FILTER_RESIZER_ISP,
+    FILTER_RESIZER_HVS,
+} filter_resizer_t;
+
+typedef struct conv_frame_stash_s
+{
+    mtime_t pts;
+    MMAL_BUFFER_HEADER_T * sub_bufs[SUBS_MAX];
+} conv_frame_stash_t;
+
+typedef struct
+{
+    filter_resizer_t resizer_type;
+    MMAL_COMPONENT_T *component;
+    MMAL_PORT_T *input;
+    MMAL_PORT_T *output;
+    MMAL_POOL_T *out_pool;  // Free output buffers
+    MMAL_POOL_T *in_pool;   // Input pool to get BH for replication
+
+    cma_buf_pool_t * cma_in_pool;
+    cma_buf_pool_t * cma_out_pool;
+
+    subpic_reg_stash_t subs[SUBS_MAX];
+
+    pic_fifo_t ret_pics;
+
+    unsigned int pic_n;
+    vlc_sem_t sem;
+    vlc_mutex_t lock;
+
+    MMAL_STATUS_T err_stream;
+
+    bool needs_copy_in;
+    bool is_sliced;
+    bool out_fmt_set;
+    const char * component_name;
+    MMAL_PORT_BH_CB_T in_port_cb_fn;
+    MMAL_PORT_BH_CB_T out_port_cb_fn;
+
+    uint64_t frame_seq;
+    conv_frame_stash_t stash[16];
+
+    // Slice specific tracking stuff
+    struct {
+        pic_fifo_t pics;
+        unsigned int line;  // Lines filled
+    } slice;
+
+    vcsm_init_type_t vcsm_init_type;
+} converter_sys_t;
+
+
+static MMAL_STATUS_T pic_to_format(MMAL_ES_FORMAT_T * const es_fmt, const picture_t * const pic)
+{
+    unsigned int bpp = (pic->format.i_bits_per_pixel + 7) >> 3;
+    MMAL_VIDEO_FORMAT_T * const v_fmt = &es_fmt->es->video;
+
+    es_fmt->type = MMAL_ES_TYPE_VIDEO;
+    es_fmt->encoding = vlc_to_mmal_video_fourcc(&pic->format);
+    es_fmt->encoding_variant = 0;
+
+    // Fill in crop etc.
+    hw_mmal_vlc_fmt_to_mmal_fmt(es_fmt, &pic->format);
+    // Override width / height with strides if appropriate
+    if (bpp != 0) {
+        v_fmt->width = pic->p[0].i_pitch / bpp;
+        v_fmt->height = pic->p[0].i_lines;
+    }
+    return MMAL_SUCCESS;
+}
+
+
+static MMAL_STATUS_T conv_enable_in(filter_t * const p_filter, converter_sys_t * const sys)
+{
+    MMAL_STATUS_T err = MMAL_SUCCESS;
+
+    if (!sys->input->is_enabled &&
+        (err = mmal_port_enable(sys->input, sys->in_port_cb_fn)) != MMAL_SUCCESS)
+    {
+        msg_Err(p_filter, "Failed to enable input port %s (status=%"PRIx32" %s)",
+                sys->input->name, err, mmal_status_to_string(err));
+    }
+    return err;
+}
+
+static MMAL_STATUS_T conv_enable_out(filter_t * const p_filter, converter_sys_t * const sys)
+{
+    MMAL_STATUS_T err = MMAL_SUCCESS;
+
+    {
+        cma_buf_pool_deletez(&sys->cma_out_pool);
+    }
+
+    if (!sys->output->is_enabled &&
+        (err = mmal_port_enable(sys->output, sys->out_port_cb_fn)) != MMAL_SUCCESS)
+    {
+        msg_Err(p_filter, "Failed to enable output port %s (status=%"PRIx32" %s)",
+                sys->output->name, err, mmal_status_to_string(err));
+    }
+    return err;
+}
+
+static void conv_control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+    filter_t * const p_filter = (filter_t *)port->userdata;
+
+    if (buffer->cmd == MMAL_EVENT_ERROR) {
+        MMAL_STATUS_T status = *(uint32_t *)buffer->data;
+
+        converter_sys_t * sys = p_filter->p_sys;
+        sys->err_stream = status;
+
+        msg_Err(p_filter, "MMAL error %"PRIx32" \"%s\"", status,
+                mmal_status_to_string(status));
+    }
+
+    mmal_buffer_header_release(buffer);
+}
+
+static void conv_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
+{
+    VLC_UNUSED(port);
+
+    mmal_buffer_header_release(buf);
+}
+
+static void conv_out_q_pic(converter_sys_t * const sys, picture_t * const pic)
+{
+    pic->p_next = NULL;
+
+    vlc_mutex_lock(&sys->lock);
+    pic_fifo_put(&sys->ret_pics, pic);
+    vlc_mutex_unlock(&sys->lock);
+
+    vlc_sem_post(&sys->sem);
+}
+
+static void conv_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
+{
+    filter_t * const p_filter = (filter_t *)port->userdata;
+    converter_sys_t * const sys = p_filter->p_sys;
+
+    if (buf->cmd == 0) {
+        picture_t * const pic = (picture_t *)buf->user_data;
+
+        if (pic == NULL) {
+            msg_Err(p_filter, "Buffer has no attached picture");
+        }
+        else if (buf->data != NULL && buf->length != 0)
+        {
+            buf_to_pic_copy_props(pic, buf);
+
+            buf->user_data = NULL;  // Responsability for this pic no longer with buffer
+            conv_out_q_pic(sys, pic);
+        }
+    }
+
+    mmal_buffer_header_release(buf);
+}
+
+
+static void slice_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
+{
+    filter_t * const p_filter = (filter_t *)port->userdata;
+    converter_sys_t * const sys = p_filter->p_sys;
+
+    if (buf->cmd != 0)
+    {
+        mmal_buffer_header_release(buf);
+        return;
+    }
+
+    if (buf->data != NULL && buf->length != 0)
+    {
+        // Got slice
+        picture_t *pic = sys->slice.pics.head;
+        const unsigned int scale_lines = sys->output->format->es->video.height;  // Expected lines of callback
+
+        if (pic == NULL) {
+            msg_Err(p_filter, "No output picture");
+            goto fail;
+        }
+
+        // Copy lines
+        // * single plane only - fix for I420
+        {
+            const unsigned int scale_n = __MIN(scale_lines - sys->slice.line, MMAL_SLICE_HEIGHT);
+            const unsigned int pic_lines = pic->p[0].i_lines;
+            const unsigned int copy_n = sys->slice.line + scale_n <= pic_lines ? scale_n :
+                sys->slice.line >= pic_lines ? 0 :
+                    pic_lines - sys->slice.line;
+
+            const unsigned int src_stride = buf->type->video.pitch[0];
+            const unsigned int dst_stride = pic->p[0].i_pitch;
+            uint8_t *dst = pic->p[0].p_pixels + sys->slice.line * dst_stride;
+            const uint8_t *src = buf->data + buf->type->video.offset[0];
+
+            if (src_stride == dst_stride) {
+                if (copy_n != 0)
+                    memcpy(dst, src, src_stride * copy_n);
+            }
+            else {
+                unsigned int i;
+                for (i = 0; i != copy_n; ++i) {
+                    memcpy(dst, src, __MIN(dst_stride, src_stride));
+                    dst += dst_stride;
+                    src += src_stride;
+                }
+            }
+            sys->slice.line += scale_n;
+        }
+
+        if ((buf->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) != 0 || sys->slice.line >= scale_lines) {
+
+            if ((buf->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) == 0 || sys->slice.line != scale_lines) {
+                // Stuff doesn't add up...
+                msg_Err(p_filter, "Line count (%d/%d) & EOF disagree (flags=%#x)", sys->slice.line, scale_lines, buf->flags);
+                goto fail;
+            }
+            else {
+                sys->slice.line = 0;
+
+                vlc_mutex_lock(&sys->lock);
+                pic_fifo_get(&sys->slice.pics);  // Remove head from Q
+                vlc_mutex_unlock(&sys->lock);
+
+                buf_to_pic_copy_props(pic, buf);
+                conv_out_q_pic(sys, pic);
+            }
+        }
+    }
+
+    // Put back
+    buf->user_data = NULL; // Zap here to make sure we can't reuse later
+    mmal_buffer_header_reset(buf);
+
+    if (mmal_port_send_buffer(sys->output, buf) != MMAL_SUCCESS) {
+        mmal_buffer_header_release(buf);
+    }
+    return;
+
+fail:
+    sys->err_stream = MMAL_EIO;
+    vlc_sem_post(&sys->sem);  // If we were waiting then break us out - the flush should fix sem values
+}
+
+
+static void conv_flush(filter_t * p_filter)
+{
+    converter_sys_t * const sys = p_filter->p_sys;
+    unsigned int i;
+
+    if (sys->resizer_type == FILTER_RESIZER_HVS)
+    {
+        for (i = 0; i != SUBS_MAX; ++i) {
+            hw_mmal_subpic_flush(sys->subs + i);
+        }
+    }
+
+    if (sys->input != NULL && sys->input->is_enabled)
+        mmal_port_disable(sys->input);
+
+    if (sys->output != NULL && sys->output->is_enabled)
+        mmal_port_disable(sys->output);
+
+//    cma_buf_pool_deletez(&sys->cma_out_pool);
+
+    // Free up anything we may have already lying around
+    // Don't need lock as the above disables should have prevented anything
+    // happening in the background
+
+    for (i = 0; i != ARRAY_SIZE(sys->stash); ++i) {
+        conv_frame_stash_t *const stash = sys->stash + i;
+        unsigned int sub_no;
+
+        stash->pts = MMAL_TIME_UNKNOWN;
+        for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
+            if (stash->sub_bufs[sub_no] != NULL) {
+                mmal_buffer_header_release(stash->sub_bufs[sub_no]);
+                stash->sub_bufs[sub_no] = NULL;
+            }
+        }
+    }
+
+    pic_fifo_release_all(&sys->slice.pics);
+    pic_fifo_release_all(&sys->ret_pics);
+
+    // Reset sem values - easiest & most reliable way is to just kill & re-init
+    vlc_sem_destroy(&sys->sem);
+    vlc_sem_init(&sys->sem, 0);
+    sys->pic_n = 0;
+
+    // Reset error status
+    sys->err_stream = MMAL_SUCCESS;
+}
+
+static void conv_stash_fixup(filter_t * const p_filter, converter_sys_t * const sys, picture_t * const p_pic)
+{
+    conv_frame_stash_t * const stash = sys->stash + (p_pic->date & 0xf);
+    unsigned int sub_no;
+    VLC_UNUSED(p_filter);
+
+    p_pic->date = stash->pts;
+    for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
+        if (stash->sub_bufs[sub_no] != NULL) {
+            // **** Do stashed blend
+            // **** Aaargh, bother... need to rescale subs too
+
+            mmal_buffer_header_release(stash->sub_bufs[sub_no]);
+            stash->sub_bufs[sub_no] = NULL;
+        }
+    }
+}
+
+// Output buffers may contain a pic ref on error or flush
+// Free it
+static MMAL_BOOL_T out_buffer_pre_release_cb(MMAL_BUFFER_HEADER_T *header, void *userdata)
+{
+    VLC_UNUSED(userdata);
+
+    picture_t * const pic = header->user_data;
+    header->user_data = NULL;
+
+    if (pic != NULL)
+        picture_Release(pic);
+
+    return MMAL_FALSE;
+}
+
+static MMAL_STATUS_T conv_set_output(filter_t * const p_filter, converter_sys_t * const sys, picture_t * const pic)
+{
+    MMAL_STATUS_T status;
+
+    sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)p_filter;
+    sys->output->format->type = MMAL_ES_TYPE_VIDEO;
+    sys->output->format->encoding = vlc_to_mmal_video_fourcc(&p_filter->fmt_out.video);
+    sys->output->format->encoding_variant = 0;
+    hw_mmal_vlc_fmt_to_mmal_fmt(sys->output->format, &p_filter->fmt_out.video);
+
+    if (pic != NULL)
+    {
+        // Override default format width/height if we have a pic we need to match
+        if ((status = pic_to_format(sys->output->format, pic)) != MMAL_SUCCESS)
+        {
+            msg_Err(p_filter, "Bad format desc: %4.4s, pic=%p, bits=%d", (const char*)&pic->format.i_chroma, pic, pic->format.i_bits_per_pixel);
+            return status;
+        }
+    }
+
+    if (sys->is_sliced) {
+        // Override height for slice
+        sys->output->format->es->video.height = MMAL_SLICE_HEIGHT;
+    }
+
+    mmal_log_dump_format(sys->output->format);
+
+    status = mmal_port_format_commit(sys->output);
+    if (status != MMAL_SUCCESS) {
+        msg_Err(p_filter, "Failed to commit format for output port %s (status=%"PRIx32" %s)",
+                sys->output->name, status, mmal_status_to_string(status));
+        return status;
+    }
+
+    sys->output->buffer_num = __MAX(sys->is_sliced ? 16 : 2, sys->output->buffer_num_recommended);
+    sys->output->buffer_size = sys->output->buffer_size_recommended;
+
+    if ((status = conv_enable_out(p_filter, sys)) != MMAL_SUCCESS)
+        return status;
+
+    return MMAL_SUCCESS;
+}
+
+static picture_t *conv_filter(filter_t *p_filter, picture_t *p_pic)
+{
+    converter_sys_t * const sys = p_filter->p_sys;
+    picture_t * ret_pics;
+    MMAL_STATUS_T err;
+    const uint64_t frame_seq = ++sys->frame_seq;
+    conv_frame_stash_t * const stash = sys->stash + (frame_seq & 0xf);
+    MMAL_BUFFER_HEADER_T * out_buf = NULL;
+
+    if (sys->err_stream != MMAL_SUCCESS) {
+        goto stream_fail;
+    }
+
+    // Check pic fmt corresponds to what we have set up
+    // ??? ISP may require flush (disable) but actually seems quite happy
+    //     without
+    if (hw_mmal_vlc_pic_to_mmal_fmt_update(sys->input->format, p_pic))
+    {
+        msg_Dbg(p_filter, "Reset input port format");
+        mmal_port_format_commit(sys->input);
+    }
+
+    if (p_pic->context == NULL) {
+        // Can't have stashed subpics if not one of our pics
+        if (!sys->needs_copy_in)
+            msg_Dbg(p_filter, "No context");
+    }
+    else if (sys->resizer_type == FILTER_RESIZER_HVS)
+    {
+        unsigned int sub_no = 0;
+
+        for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
+            int rv;
+            if ((rv = hw_mmal_subpic_update(VLC_OBJECT(p_filter),
+                                            hw_mmal_pic_sub_buf_get(p_pic, sub_no),
+                                            sys->subs + sub_no,
+                                            &p_pic->format,
+                                            &sys->output->format->es->video.crop,
+                                            frame_seq)) == 0)
+                break;
+            else if (rv < 0)
+                goto fail;
+        }
+    }
+    else
+    {
+        unsigned int sub_no = 0;
+        for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
+            if ((stash->sub_bufs[sub_no] = hw_mmal_pic_sub_buf_get(p_pic, sub_no)) != NULL) {
+                mmal_buffer_header_acquire(stash->sub_bufs[sub_no]);
+            }
+        }
+    }
+
+    if (!sys->out_fmt_set) {
+        sys->out_fmt_set = true;
+
+        if (sys->is_sliced) {
+            // If zc then we will do stride conversion when we copy to arm side
+            // so no need to worry about actual pic dimensions here
+            if ((err = conv_set_output(p_filter, sys, NULL)) != MMAL_SUCCESS)
+                goto fail;
+
+            sys->out_pool = mmal_port_pool_create(sys->output, sys->output->buffer_num, sys->output->buffer_size);
+        }
+        else {
+            picture_t *pic = filter_NewPicture(p_filter);
+            err = conv_set_output(p_filter, sys, pic);
+            picture_Release(pic);
+            if (err != MMAL_SUCCESS)
+                goto fail;
+
+            sys->out_pool = mmal_pool_create(sys->output->buffer_num, 0);
+        }
+
+        if (sys->out_pool == NULL) {
+            msg_Err(p_filter, "Failed to create output pool");
+            goto fail;
+        }
+    }
+
+    // Reenable stuff if the last thing we did was flush
+    if ((err = conv_enable_out(p_filter, sys)) != MMAL_SUCCESS ||
+        (err = conv_enable_in(p_filter, sys)) != MMAL_SUCCESS)
+        goto fail;
+
+    // We attach pic to buf before stuffing the output port
+    // We could attach the pic on output for cma, but it is a lot easier to keep
+    // the code common.
+    {
+        picture_t * const out_pic = filter_NewPicture(p_filter);
+
+        if (out_pic == NULL)
+        {
+            msg_Err(p_filter, "Failed to alloc required filter output pic");
+            goto fail;
+        }
+
+        out_pic->format.i_sar_den = p_filter->fmt_out.video.i_sar_den;
+        out_pic->format.i_sar_num = p_filter->fmt_out.video.i_sar_num;
+
+        if (sys->is_sliced) {
+            vlc_mutex_lock(&sys->lock);
+            pic_fifo_put(&sys->slice.pics, out_pic);
+            vlc_mutex_unlock(&sys->lock);
+
+            // Poke any returned pic buffers into output
+            // In general this should only happen immediately after enable
+            while ((out_buf = mmal_queue_get(sys->out_pool->queue)) != NULL)
+                mmal_port_send_buffer(sys->output, out_buf);
+        }
+        else
+        {
+            // 1 in - 1 out
+            if ((out_buf = mmal_queue_wait(sys->out_pool->queue)) == NULL)
+            {
+                msg_Err(p_filter, "Failed to get output buffer");
+                picture_Release(out_pic);
+                goto fail;
+            }
+            mmal_buffer_header_reset(out_buf);
+
+            // Attach out_pic to the buffer & ensure it is freed when the buffer is released
+            // On a good send callback the pic will be extracted to avoid this
+            out_buf->user_data = out_pic;
+            mmal_buffer_header_pre_release_cb_set(out_buf, out_buffer_pre_release_cb, NULL);
+
+            {
+                out_buf->data = out_pic->p[0].p_pixels;
+                out_buf->alloc_size = out_pic->p[0].i_pitch * out_pic->p[0].i_lines;
+                //**** stride ????
+            }
+
+            if ((err = mmal_port_send_buffer(sys->output, out_buf)) != MMAL_SUCCESS)
+            {
+                msg_Err(p_filter, "Send buffer to output failed");
+                goto fail;
+            }
+            out_buf = NULL;
+        }
+    }
+
+
+    // Stuff into input
+    // We assume the BH is already set up with values reflecting pic date etc.
+    stash->pts = p_pic->date;
+    {
+        MMAL_BUFFER_HEADER_T *const pic_buf = sys->needs_copy_in ?
+            hw_mmal_pic_buf_copied(p_pic, sys->in_pool, sys->input, sys->cma_in_pool) :
+            hw_mmal_pic_buf_replicated(p_pic, sys->in_pool);
+
+        // Whether or not we extracted the pic_buf we are done with the picture
+        picture_Release(p_pic);
+        p_pic = NULL;
+
+        if (pic_buf == NULL) {
+            msg_Err(p_filter, "Pic has no attached buffer");
+            goto fail;
+        }
+
+        pic_buf->pts = frame_seq;
+
+        if ((err = mmal_port_send_buffer(sys->input, pic_buf)) != MMAL_SUCCESS)
+        {
+            msg_Err(p_filter, "Send buffer to input failed");
+            mmal_buffer_header_release(pic_buf);
+            goto fail;
+        }
+    }
+
+    // We have a 1 pic latency for everything except the 1st pic which we
+    // wait for.
+    // This means we get a single static pic out
+    if (sys->pic_n++ == 1) {
+        return NULL;
+    }
+    vlc_sem_wait(&sys->sem);
+
+    // Return a single pending buffer
+    vlc_mutex_lock(&sys->lock);
+    ret_pics = pic_fifo_get(&sys->ret_pics);
+    vlc_mutex_unlock(&sys->lock);
+
+    if (sys->err_stream != MMAL_SUCCESS)
+        goto stream_fail;
+
+    conv_stash_fixup(p_filter, sys, ret_pics);
+
+    return ret_pics;
+
+stream_fail:
+    msg_Err(p_filter, "MMAL error reported by callback");
+fail:
+    if (out_buf != NULL)
+        mmal_buffer_header_release(out_buf);
+    if (p_pic != NULL)
+        picture_Release(p_pic);
+    conv_flush(p_filter);
+    return NULL;
+}
+
+void CloseConverter(vlc_object_t * obj)
+{
+    filter_t * const p_filter = (filter_t *)obj;
+    converter_sys_t * const sys = p_filter->p_sys;
+
+    if (sys == NULL)
+        return;
+
+    // Disables input & output ports
+    conv_flush(p_filter);
+
+    cma_buf_pool_deletez(&sys->cma_in_pool);
+    cma_buf_pool_deletez(&sys->cma_out_pool);
+
+    if (sys->component && sys->component->control->is_enabled)
+        mmal_port_disable(sys->component->control);
+
+    if (sys->component && sys->component->is_enabled)
+        mmal_component_disable(sys->component);
+
+    if (sys->resizer_type == FILTER_RESIZER_HVS)
+    {
+        for (size_t i = 0; i != SUBS_MAX; ++i) {
+            hw_mmal_subpic_close(sys->subs + i);
+        }
+    }
+
+    if (sys->out_pool)
+    {
+        if (sys->is_sliced)
+            mmal_port_pool_destroy(sys->output, sys->out_pool);
+        else
+            mmal_pool_destroy(sys->out_pool);
+    }
+
+    if (sys->in_pool != NULL)
+        mmal_pool_destroy(sys->in_pool);
+
+    if (sys->component)
+        mmal_component_release(sys->component);
+
+    cma_vcsm_exit(sys->vcsm_init_type);
+
+    vlc_sem_destroy(&sys->sem);
+    vlc_mutex_destroy(&sys->lock);
+
+    p_filter->p_sys = NULL;
+    free(sys);
+}
+
+
+static MMAL_FOURCC_T filter_enc_in(const video_format_t * const fmt)
+{
+    if (hw_mmal_chroma_is_mmal(fmt->i_chroma) || fmt->i_chroma == VLC_CODEC_I420)
+        return vlc_to_mmal_video_fourcc(fmt);
+
+    if (fmt->i_chroma == VLC_CODEC_I420_10L)
+        return MMAL_ENCODING_I420;
+
+    return 0;
+}
+
+
+int OpenConverter(vlc_object_t * obj)
+{
+    filter_t * const p_filter = (filter_t *)obj;
+    int ret = VLC_EGENERIC;
+    converter_sys_t *sys;
+    MMAL_STATUS_T status;
+    if (p_filter->fmt_out.video.i_chroma == VLC_CODEC_I420)
+        return VLC_EGENERIC;
+    const MMAL_FOURCC_T enc_out = vlc_to_mmal_video_fourcc(&p_filter->fmt_out.video);
+    const MMAL_FOURCC_T enc_in = filter_enc_in(&p_filter->fmt_in.video);
+    bool use_resizer;
+    bool use_isp;
+
+    // At least in principle we should deal with any mmal format as input
+    if (enc_in == 0 || enc_out == 0)
+        return VLC_EGENERIC;
+
+    use_resizer = var_InheritBool(p_filter, MMAL_RESIZE_NAME);
+    use_isp = var_InheritBool(p_filter, MMAL_ISP_NAME);
+
+retry:
+    // ** Make more generic by checking supported encs
+    //
+    // Must use ISP - HVS can't do this, nor can resizer
+    if (enc_in == MMAL_ENCODING_YUVUV64_10) {
+        // If resizer selected then just give up
+        if (use_resizer)
+            return VLC_EGENERIC;
+        // otherwise downgrade HVS to ISP
+        use_isp = true;
+    }
+    // HVS can't do I420
+    if (enc_out == MMAL_ENCODING_I420) {
+        use_isp = true;
+    }
+    // Only HVS can deal with SAND30
+    if (enc_in == MMAL_ENCODING_YUV10_COL) {
+        if (use_isp || use_resizer)
+            return VLC_EGENERIC;
+    }
+
+
+    if (use_resizer) {
+        // use resizer overrides use_isp
+        use_isp = false;
+    }
+
+    // Check we have a sliced version of the fourcc if we want the resizer
+    if (use_resizer && pic_to_slice_mmal_fourcc(enc_out) == 0) {
+        return VLC_EGENERIC;
+    }
+
+    sys = calloc(1, sizeof(converter_sys_t));
+    if (!sys) {
+        ret = VLC_ENOMEM;
+        goto fail;
+    }
+    p_filter->p_sys = sys;
+
+    // Init stuff the we destroy unconditionaly in Close first
+    vlc_mutex_init(&sys->lock);
+    vlc_sem_init(&sys->sem, 0);
+    sys->err_stream = MMAL_SUCCESS;
+    pic_fifo_init(&sys->ret_pics);
+    pic_fifo_init(&sys->slice.pics);
+
+    sys->needs_copy_in = !hw_mmal_chroma_is_mmal(p_filter->fmt_in.video.i_chroma);
+    sys->in_port_cb_fn = conv_input_port_cb;
+
+    if ((sys->vcsm_init_type = cma_vcsm_init()) == VCSM_INIT_NONE) {
+        msg_Err(p_filter, "VCSM init failed");
+        goto fail;
+    }
+
+    if (use_resizer) {
+        sys->resizer_type = FILTER_RESIZER_RESIZER;
+        sys->is_sliced = true;
+        sys->component_name = MMAL_COMPONENT_DEFAULT_RESIZER;
+        sys->out_port_cb_fn = slice_output_port_cb;
+    }
+    else if (use_isp) {
+        sys->resizer_type = FILTER_RESIZER_ISP;
+        sys->is_sliced = false;  // Copy directly into filter picture
+        sys->component_name = MMAL_COMPONENT_ISP_RESIZER;
+        sys->out_port_cb_fn = conv_output_port_cb;
+    } else {
+        sys->resizer_type = FILTER_RESIZER_HVS;
+        sys->is_sliced = false;  // Copy directly into filter picture
+        sys->component_name = MMAL_COMPONENT_HVS;
+        sys->out_port_cb_fn = conv_output_port_cb;
+    }
+
+    status = mmal_component_create(sys->component_name, &sys->component);
+    if (status != MMAL_SUCCESS) {
+        if (!use_isp && !use_resizer) {
+            msg_Warn(p_filter, "Failed to rcreate HVS resizer - retrying with ISP");
+            CloseConverter(obj);
+            use_isp = true;
+            goto retry;
+        }
+        msg_Err(p_filter, "Failed to create MMAL component %s (status=%"PRIx32" %s)",
+                MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status));
+        goto fail;
+    }
+    sys->output = sys->component->output[0];
+    sys->input  = sys->component->input[0];
+
+    sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)p_filter;
+    status = mmal_port_enable(sys->component->control, conv_control_port_cb);
+    if (status != MMAL_SUCCESS) {
+        msg_Err(p_filter, "Failed to enable control port %s (status=%"PRIx32" %s)",
+                sys->component->control->name, status, mmal_status_to_string(status));
+        goto fail;
+    }
+
+    if (sys->needs_copy_in &&
+        (sys->cma_in_pool = cma_buf_pool_new(2, 2, true, "conv-copy-in")) == NULL)
+    {
+        msg_Err(p_filter, "Failed to allocate input CMA pool");
+        goto fail;
+    }
+
+    sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)p_filter;
+    sys->input->format->type = MMAL_ES_TYPE_VIDEO;
+    sys->input->format->encoding = enc_in;
+    sys->input->format->encoding_variant = MMAL_ENCODING_I420;
+    hw_mmal_vlc_fmt_to_mmal_fmt(sys->input->format, &p_filter->fmt_in.video);
+    port_parameter_set_bool(sys->input, MMAL_PARAMETER_ZERO_COPY, 1);
+
+    mmal_log_dump_format(sys->input->format);
+
+    status = mmal_port_format_commit(sys->input);
+    if (status != MMAL_SUCCESS) {
+        msg_Err(p_filter, "Failed to commit format for input port %s (status=%"PRIx32" %s)",
+                sys->input->name, status, mmal_status_to_string(status));
+        goto fail;
+    }
+    sys->input->buffer_size = sys->input->buffer_size_recommended;
+    sys->input->buffer_num = NUM_DECODER_BUFFER_HEADERS;
+
+    if ((status = conv_enable_in(p_filter, sys)) != MMAL_SUCCESS)
+        goto fail;
+
+    port_parameter_set_bool(sys->output, MMAL_PARAMETER_ZERO_COPY, sys->is_sliced);
+
+    status = mmal_component_enable(sys->component);
+    if (status != MMAL_SUCCESS) {
+        msg_Err(p_filter, "Failed to enable component %s (status=%"PRIx32" %s)",
+                sys->component->name, status, mmal_status_to_string(status));
+        goto fail;
+    }
+
+    if ((sys->in_pool = mmal_pool_create(sys->input->buffer_num, 0)) == NULL)
+    {
+        msg_Err(p_filter, "Failed to create input pool");
+        goto fail;
+    }
+
+    if (sys->resizer_type == FILTER_RESIZER_HVS)
+    {
+        unsigned int i;
+        for (i = 0; i != SUBS_MAX; ++i) {
+            if (hw_mmal_subpic_open(VLC_OBJECT(p_filter), sys->subs + i, sys->component->input[i + 1], -1, i + 1) != MMAL_SUCCESS)
+            {
+                msg_Err(p_filter, "Failed to open subpic %d", i);
+                goto fail;
+            }
+        }
+    }
+
+    p_filter->pf_video_filter = conv_filter;
+    p_filter->pf_flush = conv_flush;
+    // video_drain NIF in filter structure
+
+    return VLC_SUCCESS;
+
+fail:
+    CloseConverter(obj);
+
+    if (!use_resizer && status == MMAL_ENOMEM) {
+        use_resizer = true;
+        msg_Warn(p_filter, "Lack of memory to use HVS/ISP: trying resizer");
+        goto retry;
+    }
+
+    return ret;
+}
+
diff --git a/modules/hw/mmal/mmal_picture.c b/modules/hw/mmal/mmal_picture.c
index 65b068876f..d477d5751e 100644
--- a/modules/hw/mmal/mmal_picture.c
+++ b/modules/hw/mmal/mmal_picture.c
@@ -1279,3 +1279,36 @@ const char * cma_vcsm_init_str(const vcsm_init_type_t init_mode)
     }
     return "???";
 }
+
+MMAL_FOURCC_T pic_to_slice_mmal_fourcc(MMAL_FOURCC_T fcc)
+{
+    switch (fcc){
+    case MMAL_ENCODING_I420:
+        return MMAL_ENCODING_I420_SLICE;
+    case MMAL_ENCODING_I422:
+        return MMAL_ENCODING_I422_SLICE;
+    case MMAL_ENCODING_ARGB:
+        return MMAL_ENCODING_ARGB_SLICE;
+    case MMAL_ENCODING_RGBA:
+        return MMAL_ENCODING_RGBA_SLICE;
+    case MMAL_ENCODING_ABGR:
+        return MMAL_ENCODING_ABGR_SLICE;
+    case MMAL_ENCODING_BGRA:
+        return MMAL_ENCODING_BGRA_SLICE;
+    case MMAL_ENCODING_RGB16:
+        return MMAL_ENCODING_RGB16_SLICE;
+    case MMAL_ENCODING_RGB24:
+        return MMAL_ENCODING_RGB24_SLICE;
+    case MMAL_ENCODING_RGB32:
+        return MMAL_ENCODING_RGB32_SLICE;
+    case MMAL_ENCODING_BGR16:
+        return MMAL_ENCODING_BGR16_SLICE;
+    case MMAL_ENCODING_BGR24:
+        return MMAL_ENCODING_BGR24_SLICE;
+    case MMAL_ENCODING_BGR32:
+        return MMAL_ENCODING_BGR32_SLICE;
+    default:
+        break;
+    }
+    return 0;
+}
\ No newline at end of file
diff --git a/modules/hw/mmal/mmal_picture.h b/modules/hw/mmal/mmal_picture.h
index 2f9fc9b6a9..75ad981886 100644
--- a/modules/hw/mmal/mmal_picture.h
+++ b/modules/hw/mmal/mmal_picture.h
@@ -145,6 +145,10 @@ void hw_mmal_vzc_pool_ref(vzc_pool_ctl_t * const pc);
 vzc_pool_ctl_t * hw_mmal_vzc_pool_new(void);
 
 
+#define NUM_DECODER_BUFFER_HEADERS 30
+
+MMAL_FOURCC_T pic_to_slice_mmal_fourcc(MMAL_FOURCC_T);
+
 bool rpi_is_model_pi4(void);
 
 typedef enum vcsm_init_type_e {
@@ -158,6 +162,12 @@ void cma_vcsm_exit(const vcsm_init_type_t init_mode);
 vcsm_init_type_t cma_vcsm_type(void);
 const char * cma_vcsm_init_str(const vcsm_init_type_t init_mode);
 
+#define MMAL_RESIZE_NAME "mmal-resize"
+#define MMAL_ISP_NAME    "mmal-isp"
+
+int OpenConverter(vlc_object_t *);
+void CloseConverter(vlc_object_t *);
+
 
 #define MMAL_COMPONENT_DEFAULT_RESIZER "vc.ril.resize"
 #define MMAL_COMPONENT_ISP_RESIZER     "vc.ril.isp"



More information about the vlc-commits mailing list