commit bc72c5e844ee2b7982fd071206fc82e1db850281
Author: Nicolas Chauvet <kwizart(a)gmail.com>
Date: Mon Oct 14 17:00:47 2019 +0200
Update mmal patch
mmal_8.patch => mmal_10.patch | 3084 +++++++++++++++++++++++++++++------------
1 file changed, 2234 insertions(+), 850 deletions(-)
---
diff --git a/mmal_8.patch b/mmal_10.patch
similarity index 86%
rename from mmal_8.patch
rename to mmal_10.patch
index 8744fcb..6ed981e 100644
--- a/mmal_8.patch
+++ b/mmal_10.patch
@@ -1,6 +1,6 @@
--- a/configure.ac
+++ b/configure.ac
-@@ -3419,6 +3419,9 @@
+@@ -3420,6 +3420,9 @@
AC_ARG_ENABLE(mmal,
AS_HELP_STRING([--enable-mmal],
[Multi-Media Abstraction Layer (MMAL) hardware plugin (default enable)]))
@@ -10,7 +10,7 @@
if test "${enable_mmal}" != "no"; then
VLC_SAVE_FLAGS
LDFLAGS="${LDFLAGS} -L/opt/vc/lib -lvchostif"
-@@ -3429,7 +3432,7 @@
+@@ -3430,7 +3433,7 @@
VLC_ADD_PLUGIN([mmal])
VLC_ADD_LDFLAGS([mmal],[ -L/opt/vc/lib ])
VLC_ADD_CFLAGS([mmal],[ -isystem /opt/vc/include -isystem
/opt/vc/include/interface/vcos/pthreads -isystem /opt/vc/include/interface/vmcs_host/linux
])
@@ -19,7 +19,7 @@
AS_IF([test "${enable_mmal}" = "yes"],
[ AC_MSG_ERROR([Cannot find bcm library...]) ],
[ AC_MSG_WARN([Cannot find bcm library...]) ])
-@@ -3441,6 +3444,7 @@
+@@ -3442,6 +3445,7 @@
VLC_RESTORE_FLAGS
fi
AM_CONDITIONAL([HAVE_MMAL], [test "${have_mmal}" = "yes"])
@@ -29,19 +29,20 @@
dnl evas plugin
--- a/include/vlc_fourcc.h
+++ b/include/vlc_fourcc.h
-@@ -365,6 +365,9 @@
+@@ -365,6 +365,10 @@
/* Broadcom MMAL opaque buffer type */
#define VLC_CODEC_MMAL_OPAQUE
VLC_FOURCC('M','M','A','L')
+#define VLC_CODEC_MMAL_ZC_SAND8
VLC_FOURCC('Z','S','D','8')
+#define VLC_CODEC_MMAL_ZC_SAND10
VLC_FOURCC('Z','S','D','0')
+#define VLC_CODEC_MMAL_ZC_I420
VLC_FOURCC('Z','4','2','0')
++#define VLC_CODEC_MMAL_ZC_RGB32
VLC_FOURCC('Z','R','G','B')
/* DXVA2 opaque video surface for use with D3D9 */
#define VLC_CODEC_D3D9_OPAQUE
VLC_FOURCC('D','X','A','9') /* 4:2:0 8 bpc */
--- a/modules/hw/mmal/Makefile.am
+++ b/modules/hw/mmal/Makefile.am
-@@ -1,23 +1,39 @@
+@@ -1,23 +1,46 @@
include $(top_srcdir)/modules/common.am
mmaldir = $(pluginsdir)/mmal
@@ -58,7 +59,8 @@
mmal_LTLIBRARIES = libmmal_vout_plugin.la
-libmmal_codec_plugin_la_SOURCES = codec.c
-+libmmal_codec_plugin_la_SOURCES = codec.c subpic.c mmal_picture.c blend_rgba_neon.S
subpic.h mmal_picture.h
++libmmal_codec_plugin_la_SOURCES = codec.c subpic.c mmal_picture.c blend_rgba_neon.S
subpic.h mmal_picture.h\
++ mmal_cma.c mmal_cma.h
libmmal_codec_plugin_la_CFLAGS = $(AM_CFLAGS)
libmmal_codec_plugin_la_LDFLAGS = $(AM_LDFLAGS)
libmmal_codec_plugin_la_LIBADD = $(LIBS_mmal)
@@ -77,6 +79,12 @@
+libmmal_xsplitter_plugin_la_LIBADD = $(LIBS_mmal)
+mmal_LTLIBRARIES += libmmal_xsplitter_plugin.la
+
++libmmal_converter_plugin_la_SOURCES = converter_mmal.c mmal_cma.c mmal_picture.c
mmal_cma.h mmal_picture.h
++libmmal_converter_plugin_la_CFLAGS = $(AM_CFLAGS)
++libmmal_converter_plugin_la_LDFLAGS = $(AM_LDFLAGS)
++libmmal_converter_plugin_la_LIBADD = $(LIBS_mmal)
++mmal_LTLIBRARIES += libmmal_converter_plugin.la
++
+if HAVE_MMAL_AVCODEC
+libmmal_avcodec_plugin_la_SOURCES = mmal_avcodec.c mmal_picture.c mmal_picture.h
+libmmal_avcodec_plugin_la_CFLAGS = $(AM_CFLAGS)
@@ -88,7 +96,7 @@
+
--- /dev/null
+++ b/modules/hw/mmal/blend_rgba_neon.S
-@@ -0,0 +1,200 @@
+@@ -0,0 +1,197 @@
+ .syntax unified
+ .arm
+// .thumb
@@ -142,7 +150,6 @@
+ vld4.8 {d16, d17, d18, d19}, [r1]
+
+1:
-+ @ Alpha ends up in d19
+ vmull.u8 q15, \sA, d7
+
+ vld4.8 {d20, d21, d22, d23}, [r0]
@@ -189,26 +196,27 @@
+ mov r2, r0
+ bcc 1f
+ vld4.8 {d16[0], d17[0], d18[0], d19[0]}, [r1]!
-+ vld4.8 {d20[0], d21[0], d22[0], d23[0]}, [r0]!
++ vld4.8 {d20[0], d21[0], d22[0], d23[0]}, [r2]!
+ vld4.8 {d16[1], d17[1], d18[1], d19[1]}, [r1]!
-+ vld4.8 {d20[1], d21[1], d22[1], d23[1]}, [r0]!
++ vld4.8 {d20[1], d21[1], d22[1], d23[1]}, [r2]!
+ vld4.8 {d16[2], d17[2], d18[2], d19[2]}, [r1]!
-+ vld4.8 {d20[2], d21[2], d22[2], d23[2]}, [r0]!
++ vld4.8 {d20[2], d21[2], d22[2], d23[2]}, [r2]!
+ vld4.8 {d16[3], d17[3], d18[3], d19[3]}, [r1]!
-+ vld4.8 {d20[3], d21[3], d22[3], d23[3]}, [r0]!
++ vld4.8 {d20[3], d21[3], d22[3], d23[3]}, [r2]!
+1:
+ bpl 1f
+ vld4.8 {d16[4], d17[4], d18[4], d19[4]}, [r1]!
-+ vld4.8 {d20[4], d21[4], d22[4], d23[4]}, [r0]!
++ vld4.8 {d20[4], d21[4], d22[4], d23[4]}, [r2]!
+ vld4.8 {d16[5], d17[5], d18[5], d19[5]}, [r1]!
-+ vld4.8 {d20[5], d21[5], d22[5], d23[5]}, [r0]!
++ vld4.8 {d20[5], d21[5], d22[5], d23[5]}, [r2]!
+1:
+ tst r3, #1
+ beq 1f
+ vld4.8 {d16[6], d17[6], d18[6], d19[6]}, [r1]!
-+ vld4.8 {d20[6], d21[6], d22[6], d23[6]}, [r0]!
++ vld4.8 {d20[6], d21[6], d22[6], d23[6]}, [r2]!
+1:
-+ @ Alpha ends up in d19
++ @ Set conditions for later
++ lsls r2, r3, #30 @ b2 -> C, b1 -> N
+
+ vmull.u8 q15, \sA, d7
+ vsra.u16 q15, q15, #8
@@ -232,9 +240,6 @@
+ vrshrn.u16 \dB, q14, #8
+ vmov.u8 \dA, #0xff
+
-+ mov r0, r2
-+ lsls r2, r3, #30 @ b2 -> C, b1 -> N
-+ mov r2, r0
+ bcc 1f
+ vst4.8 {d20[0], d21[0], d22[0], d23[0]}, [r0]!
+ vst4.8 {d20[1], d21[1], d22[1], d23[1]}, [r0]!
@@ -246,9 +251,9 @@
+ vst4.8 {d20[5], d21[5], d22[5], d23[5]}, [r0]!
+1:
+ tst r3, #1
-+ beq 1f
++ bxeq lr
+ vst4.8 {d20[6], d21[6], d22[6], d23[6]}, [r0]!
-+1:
++
+ bx lr
+
+.endm
@@ -508,15 +513,20 @@
#include <vlc_threads.h>
#include <bcm_host.h>
-@@ -38,255 +40,393 @@
+@@ -37,256 +39,383 @@
+ #include <interface/mmal/util/mmal_util.h>
#include <interface/mmal/util/mmal_default_components.h>
++#include <interface/vcsm/user-vcsm.h>
++
++#include "mmal_cma.h"
#include "mmal_picture.h"
+
+#include "subpic.h"
+#include "blend_rgba_neon.h"
+
+#define TRACE_ALL 0
-
++
/*
* This seems to be a bit high, but reducing it causes instabilities
*/
@@ -554,7 +564,7 @@
- add_bool(MMAL_OPAQUE_NAME, true, MMAL_OPAQUE_TEXT, MMAL_OPAQUE_LONGTEXT, false)
- set_callbacks(OpenDecoder, CloseDecoder)
-vlc_module_end()
-
+-
-struct decoder_sys_t {
- bool opaque;
+typedef struct decoder_sys_t
@@ -574,6 +584,8 @@
+ bool b_flushed;
+
++ vcsm_init_type_t vcsm_init_type;
++
+ // Lock to avoid pic update & allocate happenening simultainiously
+ // * We should be able to arrange life s.t. this isn't needed
+ // but while we are confused apply belt & braces
@@ -583,22 +595,8 @@
- int output_in_transit;
- int input_in_transit;
atomic_bool started;
+-};
+} decoder_sys_t;
-+
-+
-+typedef struct supported_mmal_enc_s {
-+ struct {
-+ MMAL_PARAMETER_HEADER_T header;
-+ MMAL_FOURCC_T encodings[64];
-+ } supported;
-+ int n;
-+} supported_mmal_enc_t;
-+
-+static supported_mmal_enc_t supported_mmal_enc =
-+{
-+ {{MMAL_PARAMETER_SUPPORTED_ENCODINGS, sizeof(((supported_mmal_enc_t
*)0)->supported)}, {0}},
-+ -1
- };
-/* Utilities */
-static int change_output_format(decoder_t *dec);
@@ -613,46 +611,46 @@
-static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
-static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
-static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
-+static inline char safe_char(const unsigned int c0)
-+{
-+ const unsigned int c = c0 & 0xff;
-+ return c > ' ' && c < 0x7f ? c : '.';
-+}
-static int OpenDecoder(decoder_t *dec)
-+static const char * str_fourcc(char * buf, unsigned int fcc)
- {
+-{
- int ret = VLC_SUCCESS;
- decoder_sys_t *sys;
- MMAL_PARAMETER_UINT32_T extra_buffers;
- MMAL_STATUS_T status;
-+ if (fcc == 0)
-+ return "----";
-+ buf[0] = safe_char(fcc >> 0);
-+ buf[1] = safe_char(fcc >> 8);
-+ buf[2] = safe_char(fcc >> 16);
-+ buf[3] = safe_char(fcc >> 24);
-+ buf[4] = 0;
-+ return buf;
++typedef struct supported_mmal_enc_s {
++ struct {
++ MMAL_PARAMETER_HEADER_T header;
++ MMAL_FOURCC_T encodings[64];
++ } supported;
++ int n;
++} supported_mmal_enc_t;
++
++#define SUPPORTED_MMAL_ENC_INIT \
++{ \
++ {{MMAL_PARAMETER_SUPPORTED_ENCODINGS, sizeof(((supported_mmal_enc_t
*)0)->supported)}, {0}}, \
++ -1 \
+}
- if (dec->fmt_in.i_codec != VLC_CODEC_MPGV &&
- dec->fmt_in.i_codec != VLC_CODEC_H264)
- return VLC_EGENERIC;
-+static bool is_enc_supported(const MMAL_FOURCC_T fcc)
-+{
-+ int i;
++static supported_mmal_enc_t supported_decode_in_enc = SUPPORTED_MMAL_ENC_INIT;
- sys = calloc(1, sizeof(decoder_sys_t));
- if (!sys) {
- ret = VLC_ENOMEM;
- goto out;
++static bool is_enc_supported(supported_mmal_enc_t * const support, const MMAL_FOURCC_T
fcc)
++{
++ int i;
++
+ if (fcc == 0)
+ return false;
-+ if (supported_mmal_enc.n == -1)
++ if (support->n == -1)
+ return true; // Unknown - say OK
-+ for (i = 0; i < supported_mmal_enc.n; ++i) {
-+ if (supported_mmal_enc.supported.encodings[i] == fcc)
++ for (i = 0; i < support->n; ++i) {
++ if (support->supported.encodings[i] == fcc)
+ return true;
}
- dec->p_sys = sys;
@@ -661,15 +659,15 @@
- sys->opaque = var_InheritBool(dec, MMAL_OPAQUE_NAME);
- bcm_host_init();
-+static bool set_and_test_enc_supported(MMAL_PORT_T * port, const MMAL_FOURCC_T fcc)
++static bool set_and_test_enc_supported(supported_mmal_enc_t * const support, MMAL_PORT_T
* port, const MMAL_FOURCC_T fcc)
+{
-+ if (supported_mmal_enc.n >= 0)
++ if (support->n >= 0)
+ /* already done */;
-+ else if (mmal_port_parameter_get(port, (MMAL_PARAMETER_HEADER_T
*)&supported_mmal_enc.supported) != MMAL_SUCCESS)
-+ supported_mmal_enc.n = 0;
++ else if (mmal_port_parameter_get(port, (MMAL_PARAMETER_HEADER_T
*)&support->supported) != MMAL_SUCCESS)
++ support->n = 0;
+ else
-+ supported_mmal_enc.n = (supported_mmal_enc.supported.header.size -
sizeof(supported_mmal_enc.supported.header)) /
-+ sizeof(supported_mmal_enc.supported.encodings[0]);
++ support->n = (support->supported.header.size -
sizeof(support->supported.header)) /
++ sizeof(support->supported.encodings[0]);
- status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER,
&sys->component);
- if (status != MMAL_SUCCESS) {
@@ -678,7 +676,7 @@
- ret = VLC_EGENERIC;
- goto out;
- }
-+ return is_enc_supported(fcc);
++ return is_enc_supported(support, fcc);
+}
- sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)dec;
@@ -1071,7 +1069,7 @@
if (atomic_load(&sys->started)) {
mmal_format_full_copy(sys->output->format, sys->output_format);
status = mmal_port_format_commit(sys->output);
-@@ -300,7 +440,9 @@
+@@ -300,7 +429,9 @@
}
port_reset:
@@ -1081,7 +1079,7 @@
status = mmal_port_disable(sys->output);
if (status != MMAL_SUCCESS) {
msg_Err(dec, "Failed to disable output port (status=%"PRIx32"
%s)",
-@@ -318,18 +460,10 @@
+@@ -318,18 +449,10 @@
goto out;
}
@@ -1102,7 +1100,7 @@
if (status != MMAL_SUCCESS) {
msg_Err(dec, "Failed to enable output port (status=%"PRIx32"
%s)",
status, mmal_status_to_string(status));
-@@ -338,25 +472,14 @@
+@@ -338,25 +461,14 @@
}
if (!atomic_load(&sys->started)) {
@@ -1131,7 +1129,7 @@
}
apply_fmt:
-@@ -382,12 +505,19 @@
+@@ -382,12 +494,19 @@
sys->b_progressive = (interlace_type.eMode == MMAL_InterlaceProgressive);
sys->b_top_field_first = sys->b_progressive ? true :
(interlace_type.eMode == MMAL_InterlaceFieldsInterleavedUpperFirst);
@@ -1151,7 +1149,7 @@
out:
mmal_format_free(sys->output_format);
sys->output_format = NULL;
-@@ -395,144 +525,85 @@
+@@ -395,144 +514,85 @@
return ret;
}
@@ -1201,7 +1199,7 @@
- ret = VLC_EGENERIC;
- goto err;
- }
--
+
- if (!sys->opaque)
- buffer->data = picture->p[0].p_pixels;
- } else {
@@ -1215,7 +1213,7 @@
- }
- buffer->user_data = picture;
- buffer->cmd = 0;
-
+-
- status = mmal_port_send_buffer(sys->output, buffer);
+ status = mmal_port_format_commit(sys->input);
if (status != MMAL_SUCCESS) {
@@ -1302,6 +1300,10 @@
- MMAL_BUFFER_HEADER_T *buffer;
- MMAL_STATUS_T status;
+ decoder_sys_t *const sys = dec->p_sys;
++
++#if TRACE_ALL
++ msg_Dbg(dec, "%s: <<<", __func__);
++#endif
- msg_Dbg(dec, "Flushing decoder ports...");
- mmal_port_flush(sys->output);
@@ -1310,10 +1312,6 @@
- while (atomic_load(&sys->output_in_transit) ||
- atomic_load(&sys->input_in_transit))
- vlc_sem_wait(&sys->sem);
-+#if TRACE_ALL
-+ msg_Dbg(dec, "%s: <<<", __func__);
-+#endif
-+
+ if (!sys->b_flushed) {
+ mmal_port_disable(sys->input);
+ mmal_port_disable(sys->output);
@@ -1349,7 +1347,7 @@
/*
* Configure output port if necessary
*/
-@@ -541,18 +612,50 @@
+@@ -541,18 +601,50 @@
msg_Err(dec, "Failed to change output port format");
}
@@ -1403,7 +1401,7 @@
if (atomic_load(&sys->started))
fill_output_port(dec);
-@@ -563,18 +666,21 @@
+@@ -563,18 +655,21 @@
if (block->i_flags & BLOCK_FLAG_CORRUPTED)
flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED;
@@ -1430,7 +1428,7 @@
len = block->i_buffer;
if (len > buffer->alloc_size)
-@@ -590,89 +696,1443 @@
+@@ -590,89 +685,1549 @@
}
buffer->flags = flags;
@@ -1499,6 +1497,8 @@
+
+ hw_mmal_port_pool_ref_release(sys->ppr, false);
+
++ cma_vcsm_exit(sys->vcsm_init_type);
++
+ vlc_mutex_destroy(&sys->pic_lock);
+ free(sys);
+
@@ -1527,7 +1527,7 @@
+ }
+#endif
+
-+ if (!is_enc_supported(in_fcc))
++ if (!is_enc_supported(&supported_decode_in_enc, in_fcc))
+ return VLC_EGENERIC;
+
+ sys = calloc(1, sizeof(decoder_sys_t));
@@ -1540,6 +1540,12 @@
+
+ bcm_host_init();
+
++ if ((sys->vcsm_init_type = cma_vcsm_init()) == VCSM_INIT_NONE) {
++ msg_Err(dec, "VCSM init failed");
++ goto fail;
++ }
++ msg_Info(dec, "VCSM init succeeded: %s",
cma_vcsm_init_str(sys->vcsm_init_type));
++
+ sys->err_stream = MMAL_SUCCESS;
+
+ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER,
&sys->component);
@@ -1555,7 +1561,7 @@
+ sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)dec;
+ sys->input->format->encoding = in_fcc;
+
-+ if (!set_and_test_enc_supported(sys->input, in_fcc)) {
++ if (!set_and_test_enc_supported(&supported_decode_in_enc, sys->input,
in_fcc)) {
+#if TRACE_ALL
+ char cbuf[5];
+ msg_Dbg(dec, "Format not supported: %s", str_fourcc(cbuf, in_fcc));
@@ -1696,6 +1702,8 @@
+ MMAL_POOL_T *out_pool; // Free output buffers
+ MMAL_POOL_T *in_pool; // Input pool to get BH for replication
+
++ cma_pool_fixed_t * cma_out_pool;
++
+ subpic_reg_stash_t subs[SUBS_MAX];
+
+ pic_fifo_t ret_pics;
@@ -1709,6 +1717,7 @@
+ MMAL_STATUS_T err_stream;
+ int in_count;
+
++ bool is_cma;
+ bool is_sliced;
+ bool out_fmt_set;
+ bool latency_set;
@@ -1733,18 +1742,17 @@
+ unsigned int bpp = (pic->format.i_bits_per_pixel + 7) >> 3;
+ MMAL_VIDEO_FORMAT_T * const v_fmt = &es_fmt->es->video;
+
-+ if (bpp < 1 || bpp > 4)
-+ return MMAL_EINVAL;
-+
+ 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.
+ vlc_to_mmal_video_fmt(es_fmt, &pic->format);
-+ // Override width / height with strides
-+ v_fmt->width = pic->p[0].i_pitch / bpp;
-+ v_fmt->height = pic->p[0].i_lines;
++ // 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;
+}
+
@@ -1766,6 +1774,20 @@
+{
+ MMAL_STATUS_T err = MMAL_SUCCESS;
+
++ if (sys->is_cma)
++ {
++ if (sys->cma_out_pool == NULL &&
++ (sys->cma_out_pool = cma_buf_pool_new()) == NULL)
++ {
++ msg_Err(p_filter, "Failed to alloc cma buf pool");
++ return MMAL_ENOMEM;
++ }
++ }
++ else
++ {
++ 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)
+ {
@@ -1837,7 +1859,10 @@
}
-static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
-+static void conv_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
++static const uint8_t shift_00[] = {0,0,0,0};
++static const uint8_t shift_01[] = {0,1,1,1};
++
++static int cma_pic_set_data(filter_t * const p_filter, picture_t * const pic, const
MMAL_BUFFER_HEADER_T * const buf)
{
- decoder_t *dec = (decoder_t *)port->userdata;
- decoder_sys_t *sys = dec->p_sys;
@@ -1859,6 +1884,61 @@
- buffer->alloc_size = 0;
- buffer->data = NULL;
- mmal_buffer_header_release(buffer);
+- }
+- }
+- atomic_fetch_sub(&sys->output_in_transit, 1);
+- vlc_sem_post(&sys->sem);
+- } else if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) {
+- fmt = mmal_event_format_changed_get(buffer);
++ filter_sys_t *const sys = p_filter->p_sys;
++ const MMAL_VIDEO_FORMAT_T * const mm_fmt =
&sys->output->format->es->video;
++ const MMAL_BUFFER_HEADER_VIDEO_SPECIFIC_T *const buf_vid =
&buf->type->video;
++
++ uint8_t * const data = cma_buf_pic_addr(pic);
++ if (data == NULL) {
++ return VLC_ENOMEM;
++ }
++
++ const uint8_t * ws = shift_00;
++ const uint8_t * hs = shift_00;
++ int pb = 1;
++
++ switch (p_filter->fmt_out.video.i_chroma)
++ {
++ case VLC_CODEC_MMAL_ZC_RGB32:
++ pb = 4;
++ break;
+
+- format = mmal_format_alloc();
+- mmal_format_full_copy(format, fmt->format);
++ case VLC_CODEC_MMAL_ZC_I420:
++ case VLC_CODEC_MMAL_ZC_SAND8:
++ hs = shift_01;
++ break;
+
+- if (sys->opaque)
+- format->encoding = MMAL_ENCODING_OPAQUE;
++ default:
++ msg_Err(p_filter, "%s: Unexpected format", __func__);
++ return VLC_EGENERIC;
++ }
++
++ pic->i_planes = buf_vid->planes;
++ for (unsigned int i = 0; i != buf_vid->planes; ++i) {
++ pic->p[i] = (plane_t){
++ .p_pixels = data + buf_vid->offset[i],
++ .i_lines = mm_fmt->height >> hs[i],
++ .i_pitch = buf_vid->pitch[i],
++ .i_pixel_pitch = pb,
++ .i_visible_lines = mm_fmt->crop.height >> hs[i],
++ .i_visible_pitch = mm_fmt->crop.width >> ws[i]
++ };
++ }
++ return VLC_SUCCESS;
++}
++
++static void conv_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
++{
+ filter_t * const p_filter = (filter_t *)port->userdata;
+ filter_sys_t * const sys = p_filter->p_sys;
+
@@ -1884,6 +1964,11 @@
+ {
+ buf_to_pic_copy_props(pic, buf);
+
++ if (sys->is_cma) {
++ if (cma_pic_set_data(p_filter, pic, buf) != VLC_SUCCESS)
++ msg_Err(p_filter, "Failed to set data");
++ }
++
+// draw_corners(pic->p[0].p_pixels, pic->p[0].i_pitch / 4, 0, 0,
pic->p[0].i_visible_pitch / 4, pic->p[0].i_visible_lines);
+#if DEBUG_SQUARES
+ draw_square(pic->p[0].p_pixels, pic->p[0].i_pitch / 4, 0, 0, 32, 32,
0xffff0000);
@@ -1949,7 +2034,7 @@
+ 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) {
@@ -1959,18 +2044,10 @@
+ }
+ }
+ sys->slice.line += scale_n;
- }
-- atomic_fetch_sub(&sys->output_in_transit, 1);
-- vlc_sem_post(&sys->sem);
-- } else if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) {
-- fmt = mmal_event_format_changed_get(buffer);
-
-- format = mmal_format_alloc();
-- mmal_format_full_copy(format, fmt->format);
++ }
++
+ if ((buf->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) != 0 ||
sys->slice.line >= scale_lines) {
-
-- if (sys->opaque)
-- format->encoding = MMAL_ENCODING_OPAQUE;
++
+ 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);
@@ -1988,7 +2065,8 @@
+ }
+ }
+ }
-+
+
+- sys->output_format = format;
+ // Put back
+ buf->user_data = NULL; // Zap here to make sure we can't reuse later
+ mmal_buffer_header_reset(buf);
@@ -2026,6 +2104,8 @@
+ 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
@@ -2101,7 +2181,7 @@
+ if ((status = pic_to_format(sys->output->format, pic)) != MMAL_SUCCESS)
+ {
+ char cbuf[5];
-+ msg_Err(p_filter, "Bad format desc: %s, bits=%d", str_fourcc(cbuf,
pic->format.i_chroma), pic->format.i_bits_per_pixel);
++ msg_Err(p_filter, "Bad format desc: %s, pic=%p, bits=%d",
str_fourcc(cbuf, pic->format.i_chroma), pic, pic->format.i_bits_per_pixel);
+ return status;
+ }
+
@@ -2120,11 +2200,11 @@
+
+ sys->output->buffer_num = __MAX(sys->is_sliced ? 16 : 2,
sys->output->buffer_num_recommended);
+ sys->output->buffer_size = sys->output->buffer_size_recommended;
-+
+
+- mmal_buffer_header_release(buffer);
+ if ((status = conv_enable_out(p_filter, sys)) != MMAL_SUCCESS)
+ return status;
-
-- sys->output_format = format;
++
+ return MMAL_SUCCESS;
+}
+
@@ -2167,8 +2247,12 @@
+
+ for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
+ int rv;
-+ if ((rv = hw_mmal_subpic_update(VLC_OBJECT(p_filter), p_pic, sub_no,
sys->subs + sub_no,
-+
&sys->output->format->es->video.crop, frame_seq)) == 0)
++ 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;
@@ -2201,7 +2285,6 @@
+ goto fail;
+ }
+
-+ msg_Dbg(p_filter, "Outpool: zc=%d, num=%d, size=%d",
sys->is_sliced, sys->output->buffer_num, sys->output->buffer_size);
+ sys->out_pool = sys->is_sliced ?
+ mmal_port_pool_create(sys->output, sys->output->buffer_num,
sys->output->buffer_size) :
+ mmal_pool_create(sys->output->buffer_num, 0);
@@ -2291,13 +2374,35 @@
+
+ mmal_buffer_header_reset(out_buf);
+ out_buf->user_data = out_pic;
-+ 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 (sys->is_cma) {
++ int rv;
++ if ((rv = cma_buf_pic_attach(sys->cma_out_pool, out_pic,
sys->output->buffer_size)) != VLC_SUCCESS)
++ {
++ char dbuf0[5];
++ msg_Err(p_filter, "Failed to attach CMA to pic: fmt=%s
err=%d",
++ str_fourcc(dbuf0, out_pic->format.i_chroma),
++ rv);
++ goto fail;
++ }
++ const unsigned int vc_h = cma_buf_pic_vc_handle(out_pic);
++ if (vc_h == 0)
++ {
++ msg_Err(p_filter, "Pic has no vc handle");
++ goto fail;
++ }
++ out_buf->data = (uint8_t *)vc_h;
++ out_buf->alloc_size = sys->output->buffer_size;
++ }
++ else {
++ 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 TRACE_ALL
-+ msg_Dbg(p_filter, "Out buf send: pic=%p, buf=%p, flags=%#x, len=%d/%d,
pts=%lld",
-+ p_pic, out_buf->user_data, out_buf->flags,
++ msg_Dbg(p_filter, "Out buf send: pic=%p, data=%p, user=%p, flags=%#x,
len=%d/%d, pts=%lld",
++ p_pic, out_buf->data, out_buf->user_data, out_buf->flags,
+ out_buf->length, out_buf->alloc_size, (long
long)out_buf->pts);
+#endif
+
@@ -2365,8 +2470,7 @@
+#if TRACE_ALL
+ msg_Dbg(p_filter, ">>> %s: pic=%p", __func__, ret_pics);
+#endif
-
-- mmal_buffer_header_release(buffer);
++
+ return ret_pics;
+
+stream_fail:
@@ -2488,6 +2592,8 @@
+ 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
@@ -2496,6 +2602,11 @@
+ // otherwise downgrade HVS to ISP
+ use_isp = true;
+ }
++ // HVS can't do I420
++ if (enc_out == MMAL_ENCODING_I420) {
++ use_isp = true;
++ }
++
+
+ if (use_resizer) {
+ // use resizer overrides use_isp
@@ -2543,6 +2654,7 @@
+ pic_fifo_init(&sys->slice.pics);
+
+ sys->in_port_cb_fn = conv_input_port_cb;
++
+ if (use_resizer) {
+ sys->resizer_type = FILTER_RESIZER_RESIZER;
+ sys->is_sliced = true;
@@ -2561,6 +2673,7 @@
+ sys->component_name = MMAL_COMPONENT_HVS;
+ sys->out_port_cb_fn = conv_output_port_cb;
+ }
++ sys->is_cma = is_cma_buf_pic_chroma(p_filter->fmt_out.video.i_chroma);
+
+ status = mmal_component_create(sys->component_name, &sys->component);
+ if (status != MMAL_SUCCESS) {
@@ -2573,7 +2686,7 @@
+ 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];
+
@@ -2583,7 +2696,7 @@
+ 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;
-+ }
+ }
+
+ sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)p_filter;
+ sys->input->format->type = MMAL_ES_TYPE_VIDEO;
@@ -2606,7 +2719,7 @@
+ 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);
++ port_parameter_set_bool(sys->output, MMAL_PARAMETER_ZERO_COPY, sys->is_sliced
|| sys->is_cma);
+
+ status = mmal_component_enable(sys->component);
+ if (status != MMAL_SUCCESS) {
@@ -2685,24 +2798,15 @@
+ else
+ {
+ // cast away src const so we can ref it
-+ MMAL_BUFFER_HEADER_T *buf = hw_mmal_vzc_buf_from_pic(sys->vzc, (picture_t
*)src, dst,
++ MMAL_BUFFER_HEADER_T *buf = hw_mmal_vzc_buf_from_pic(sys->vzc, (picture_t
*)src,
++
vis_mmal_rect(&dst->format),
++ x_offset, y_offset,
++ alpha,
+ dst != sys->last_dst ||
!hw_mmal_pic_has_sub_bufs(dst));
+ if (buf == NULL) {
+ msg_Err(p_filter, "Failed to allocate vzc buffer for subpic");
+ return;
+ }
-+ MMAL_DISPLAYREGION_T * const reg = hw_mmal_vzc_buf_region(buf);
-+
-+ reg->set |=
-+ MMAL_DISPLAY_SET_ALPHA | MMAL_DISPLAY_SET_FULLSCREEN |
MMAL_DISPLAY_SET_DEST_RECT;
-+
-+ reg->fullscreen = 0;
-+
-+ reg->alpha = (uint32_t)(alpha & 0xff) | (1U << 31);
-+
-+ hw_mmal_vzc_buf_set_dest_rect(buf, x_offset, y_offset,
src->format.i_visible_width, src->format.i_visible_height);
-+
-+ reg->dest_rect = (MMAL_RECT_T){0, 0, 0, 0};
+
+ hw_mmal_pic_sub_buf_add(dst, buf);
+
@@ -2767,7 +2871,7 @@
+
+ hw_mmal_vzc_pool_release(sys->vzc);
+ free(sys);
-+}
+ }
+
+// ---------------------------------------------------------------------------
+
@@ -2825,7 +2929,7 @@
+static void CloseBlendNeon(vlc_object_t *object)
+{
+ VLC_UNUSED(object);
- }
++}
+
+static int OpenBlendNeon(vlc_object_t *object)
+{
@@ -2860,7 +2964,9 @@
+ }
+
+ if (blend_fn == (blend_neon_fn *)0)
++ {
+ return VLC_EGENERIC;
++ }
+
+ p_filter->p_sys = (void *)blend_fn;
+ p_filter->pf_video_blend = FilterBlendNeon;
@@ -2925,87 +3031,538 @@
+vlc_module_end()
+
+
---- a/modules/hw/mmal/deinterlace.c
-+++ b/modules/hw/mmal/deinterlace.c
-@@ -26,11 +26,12 @@
- #include "config.h"
- #endif
-
--#include <vlc_picture_pool.h>
-+#include <stdatomic.h>
+--- /dev/null
++++ b/modules/hw/mmal/converter_mmal.c
+@@ -0,0 +1,448 @@
++#ifdef HAVE_CONFIG_H
++# include "config.h"
++#endif
+
- #include <vlc_common.h>
-+#include <vlc_picture_pool.h>
- #include <vlc_plugin.h>
- #include <vlc_filter.h>
--#include <vlc_atomic.h>
-
- #include "mmal_picture.h"
-
-@@ -41,466 +42,569 @@
-
- #define MIN_NUM_BUFFERS_IN_TRANSIT 2
-
--#define MMAL_DEINTERLACE_QPU "mmal-deinterlace-adv-qpu"
--#define MMAL_DEINTERLACE_QPU_TEXT N_("Use QPUs for advanced HD
deinterlacing.")
--#define MMAL_DEINTERLACE_QPU_LONGTEXT N_("Make use of the QPUs to allow higher
quality deinterlacing of HD content.")
-+#define MMAL_DEINTERLACE_NO_QPU "mmal-deinterlace-no-qpu"
-+#define MMAL_DEINTERLACE_NO_QPU_TEXT N_("Do not use QPUs for advanced HD
deinterlacing.")
-+#define MMAL_DEINTERLACE_NO_QPU_LONGTEXT N_("Do not make use of the QPUs to allow
higher quality deinterlacing of HD content.")
-
--static int Open(filter_t *filter);
--static void Close(filter_t *filter);
-+#define MMAL_DEINTERLACE_ADV "mmal-deinterlace-adv"
-+#define MMAL_DEINTERLACE_ADV_TEXT N_("Force advanced deinterlace")
-+#define MMAL_DEINTERLACE_ADV_LONGTEXT N_("Force advanced deinterlace")
-
--vlc_module_begin()
-- set_shortname(N_("MMAL deinterlace"))
-- set_description(N_("MMAL-based deinterlace filter plugin"))
-- set_capability("video filter", 0)
-- set_category(CAT_VIDEO)
-- set_subcategory(SUBCAT_VIDEO_VFILTER)
-- set_callbacks(Open, Close)
-- add_shortcut("deinterlace")
-- add_bool(MMAL_DEINTERLACE_QPU, false, MMAL_DEINTERLACE_QPU_TEXT,
-- MMAL_DEINTERLACE_QPU_LONGTEXT, true);
--vlc_module_end()
-+#define MMAL_DEINTERLACE_FAST "mmal-deinterlace-fast"
-+#define MMAL_DEINTERLACE_FAST_TEXT N_("Force fast deinterlace")
-+#define MMAL_DEINTERLACE_FAST_LONGTEXT N_("Force fast deinterlace")
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/ioctl.h>
++#include <sys/mman.h>
+
-+#define MMAL_DEINTERLACE_NONE "mmal-deinterlace-none"
-+#define MMAL_DEINTERLACE_NONE_TEXT N_("Force no deinterlace")
-+#define MMAL_DEINTERLACE_NONE_LONGTEXT N_("Force no interlace. Simply strips off
the interlace markers and passes the frame straight through. "\
-+ "This is the default for > SD if < 96M gpu-mem")
++#include <interface/vcsm/user-vcsm.h>
+
-+#define MMAL_DEINTERLACE_HALF_RATE "mmal-deinterlace-half-rate"
-+#define MMAL_DEINTERLACE_HALF_RATE_TEXT N_("Halve output framerate")
-+#define MMAL_DEINTERLACE_HALF_RATE_LONGTEXT N_("Halve output framerate. 1 output
frame for each pair of interlaced fields input")
++#include <vlc_common.h>
++#include <vlc_picture.h>
+
-+#define MMAL_DEINTERLACE_FULL_RATE "mmal-deinterlace-full-rate"
-+#define MMAL_DEINTERLACE_FULL_RATE_TEXT N_("Full output framerate")
-+#define MMAL_DEINTERLACE_FULL_RATE_LONGTEXT N_("Full output framerate. 1 output
frame for each interlaced field input")
-
--struct filter_sys_t {
++#include <libdrm/drm_fourcc.h>
++#include <EGL/egl.h>
++#include <EGL/eglext.h>
++#include <GLES2/gl2.h>
++#include <GLES2/gl2ext.h>
+
-+typedef struct filter_sys_t
-+{
- MMAL_COMPONENT_T *component;
- MMAL_PORT_T *input;
- MMAL_PORT_T *output;
-+ MMAL_POOL_T *in_pool;
-+ hw_mmal_port_pool_ref_t *out_ppr;
-
-- MMAL_QUEUE_T *filtered_pictures;
-- vlc_sem_t sem;
-+ MMAL_QUEUE_T * out_q;
-
-- atomic_bool started;
-+ bool half_rate;
-+ bool use_qpu;
-+ bool use_fast;
-+ bool use_passthrough;
++#include "mmal_cma.h"
++
++#include "../../video_output/opengl/converter.h"
++
++#include "mmal_picture.h"
++
++#include <assert.h>
++
++#define OPT_SAND 0
++#define OPT_I420 1
++#define OPT_RGB32 0
++
++
++#if OPT_SAND
++#define FMT_IN VLC_CODEC_MMAL_ZC_SAND8
++#elif OPT_I420
++#define FMT_IN VLC_CODEC_MMAL_ZC_I420
++#elif OPT_RGB32
++#define FMT_IN VLC_CODEC_MMAL_ZC_RGB32
++#elif
++#error Missing input format
++#endif
++
++#define TRACE_ALL 0
++
++typedef struct mmal_gl_converter_s
++{
++ EGLint drm_fourcc;
++ vcsm_init_type_t vcsm_init_type;
++ struct cma_pic_context_s * last_ctx_ref;
++
++ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
++} mmal_gl_converter_t;
++
++
++static EGLint vlc_to_gl_fourcc(const video_format_t * const fmt)
++{
++ // Converting to mmal selects the right RGB32 varient
++ switch(vlc_to_mmal_video_fourcc(fmt))
++ {
++ case MMAL_ENCODING_I420:
++ return MMAL_FOURCC('Y','U','1','2');
++ case MMAL_ENCODING_YV12:
++ return MMAL_FOURCC('Y','V','1','2');
++ case MMAL_ENCODING_I422:
++ return MMAL_FOURCC('Y','U','1','6');
++ case MMAL_ENCODING_YUVUV128:
++ case MMAL_ENCODING_NV12:
++ return MMAL_FOURCC('N','V','1','2');
++ case MMAL_ENCODING_NV21:
++ return MMAL_FOURCC('N','V','2','1');
++ case MMAL_ENCODING_RGB16:
++ return MMAL_FOURCC('R','G','1','6');
++ case MMAL_ENCODING_RGB24:
++ return MMAL_FOURCC('B','G','2','4');
++ case MMAL_ENCODING_BGR24:
++ return MMAL_FOURCC('R','G','2','4');
++ case MMAL_ENCODING_BGR32:
++ case MMAL_ENCODING_BGRA:
++ return MMAL_FOURCC('X','R','2','4');
++ case MMAL_ENCODING_RGB32:
++ case MMAL_ENCODING_RGBA:
++ return MMAL_FOURCC('X','B','2','4');
++ default:
++ break;
++ }
++ return 0;
++}
++
++typedef struct tex_context_s {
++ picture_context_t cmn;
++ GLuint texture;
++
++ PFNGLDELETETEXTURESPROC DeleteTextures; // Copy fn pointer so we don't need tc
on delete
++} tex_context_t;
++
++static void tex_context_delete(tex_context_t * const tex)
++{
++ tex->DeleteTextures(1, &tex->texture);
++
++ free(tex);
++}
++
++static void tex_context_destroy(picture_context_t * pic_ctx)
++{
++ tex_context_delete((tex_context_t *)pic_ctx);
++}
++
++static picture_context_t * tex_context_copy(picture_context_t * pic_ctx)
++{
++ return pic_ctx;
++}
++
++static tex_context_t * get_tex_context(const opengl_tex_converter_t * const tc,
picture_t * const pic)
++{
++ mmal_gl_converter_t * const sys = tc->priv;
++
++ tex_context_t * tex = (tex_context_t *)cma_buf_pic_context2(pic);
++ if (tex != NULL)
++ return tex;
++
++ if ((tex = malloc(sizeof(*tex))) == NULL)
++ return NULL;
++
++ *tex = (tex_context_t){
++ .cmn = {
++ .destroy = tex_context_destroy,
++ .copy = tex_context_copy
++ },
++ .texture = 0,
++ .DeleteTextures = tc->vt->DeleteTextures
++ };
++
++ {
++ EGLint attribs[30];
++ EGLint * a = attribs;
++ const int fd = cma_buf_pic_fd(pic);
++ uint8_t * base_addr = cma_buf_pic_addr(pic);
++
++ if (pic->i_planes >= 4 || pic->i_planes <= 0)
++ {
++ msg_Err(tc, "%s: Bad planes", __func__);
++ goto fail;
++ }
++
++ *a++ = EGL_WIDTH;
++ *a++ = pic->format.i_visible_width;
++ *a++ = EGL_HEIGHT;
++ *a++ = pic->format.i_visible_height;
++ *a++ = EGL_LINUX_DRM_FOURCC_EXT;
++ *a++ = sys->drm_fourcc;
++
++ if (pic->format.i_chroma == VLC_CODEC_MMAL_ZC_SAND8)
++ {
++ // Sand is its own very special bunny :-(
++ static const EGLint attnames[] = {
++ EGL_DMA_BUF_PLANE0_FD_EXT,
++ EGL_DMA_BUF_PLANE0_OFFSET_EXT,
++ EGL_DMA_BUF_PLANE0_PITCH_EXT,
++ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
++ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
++ EGL_DMA_BUF_PLANE1_FD_EXT,
++ EGL_DMA_BUF_PLANE1_OFFSET_EXT,
++ EGL_DMA_BUF_PLANE1_PITCH_EXT,
++ EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
++ EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT
++ };
++
++ const EGLint * n = attnames;
++
++ for (int i = 0; i < pic->i_planes; ++i)
++ {
++ const uint64_t mod =
DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(pic->p[i].i_pitch >> 7);
++
++ *a++ = *n++;
++ *a++ = fd;
++ *a++ = *n++;
++ *a++ = pic->p[i].p_pixels - base_addr;
++ *a++ = *n++;
++ *a++ = pic->format.i_width;
++ *a++ = *n++;
++ *a++ = (EGLint)(mod >> 32);
++ *a++ = *n++;
++ *a++ = (EGLint)(mod & 0xffffffff);
++ }
++ }
++ else
++ {
++ static const EGLint attnames[] = {
++ EGL_DMA_BUF_PLANE0_FD_EXT,
++ EGL_DMA_BUF_PLANE0_OFFSET_EXT,
++ EGL_DMA_BUF_PLANE0_PITCH_EXT,
++ EGL_DMA_BUF_PLANE1_FD_EXT,
++ EGL_DMA_BUF_PLANE1_OFFSET_EXT,
++ EGL_DMA_BUF_PLANE1_PITCH_EXT,
++ EGL_DMA_BUF_PLANE2_FD_EXT,
++ EGL_DMA_BUF_PLANE2_OFFSET_EXT,
++ EGL_DMA_BUF_PLANE2_PITCH_EXT,
++ EGL_DMA_BUF_PLANE3_FD_EXT,
++ EGL_DMA_BUF_PLANE3_OFFSET_EXT,
++ EGL_DMA_BUF_PLANE3_PITCH_EXT
++ };
++
++ const EGLint * n = attnames;
++
++ for (int i = 0; i < pic->i_planes; ++i)
++ {
++ *a++ = *n++;
++ *a++ = fd;
++ *a++ = *n++;
++ *a++ = pic->p[i].p_pixels - base_addr;
++ *a++ = *n++;
++ *a++ = pic->p[i].i_pitch;
++ }
++ }
++
++ *a = EGL_NONE;
++
++ const EGLImage image = tc->gl->egl.createImageKHR(tc->gl,
EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
++ if (!image) {
++ msg_Err(tc, "Failed to import fd %d: Err=%#x", fd,
tc->vt->GetError());
++ goto fail;
++ }
++
++ // ** ?? tc->tex_target
++ tc->vt->GenTextures(1, &tex->texture);
++ tc->vt->BindTexture(GL_TEXTURE_EXTERNAL_OES, tex->texture);
++ tc->vt->TexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER,
GL_LINEAR);
++ tc->vt->TexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER,
GL_LINEAR);
++ sys->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
++
++ tc->gl->egl.destroyImageKHR(tc->gl, image);
++ }
++
++ if (cma_buf_pic_add_context2(pic, &tex->cmn) != VLC_SUCCESS)
++ {
++ msg_Err(tc, "%s: add_context2 failed", __func__);
++ goto fail;
++ }
++ return tex;
++
++fail:
++ tex_context_delete(tex);
++ return NULL;
++}
++
++
++static int
++tc_mmal_update(const opengl_tex_converter_t *tc, GLuint *textures,
++ const GLsizei *tex_width, const GLsizei *tex_height,
++ picture_t *pic, const size_t *plane_offset)
++{
++ mmal_gl_converter_t * const sys = tc->priv;
++#if TRACE_ALL
++ msg_Err(tc, "%s: %d*%dx%d : %d*%dx%d", __func__, tc->tex_count,
tex_width[0], tex_height[0], pic->i_planes, pic->p[0].i_pitch,
pic->p[0].i_lines);
++#endif
++ VLC_UNUSED(tex_width);
++ VLC_UNUSED(tex_height);
++ VLC_UNUSED(plane_offset);
++
++ if (!is_cma_buf_pic_chroma(pic->format.i_chroma))
++ {
++ char cbuf[5];
++ msg_Err(tc, "Pic with unexpected chroma: %s", str_fourcc(cbuf,
pic->format.i_chroma));
++ return VLC_EGENERIC;
++ }
++
++ tex_context_t * const tex = get_tex_context(tc, pic);
++ if (tex == NULL)
++ return VLC_EGENERIC;
++
++// tc->vt->BindTexture(GL_TEXTURE_EXTERNAL_OES, tex->texture);
++
++ cma_buf_pic_context_unref(sys->last_ctx_ref); // ?? Needed ??
++ sys->last_ctx_ref = cma_buf_pic_context_ref(pic);
++
++ textures[0] = tex->texture;
++ return VLC_SUCCESS;
++}
++
++static int
++tc_mmal_fetch_locations(opengl_tex_converter_t *tc, GLuint program)
++{
++ tc->uloc.Texture[0] = tc->vt->GetUniformLocation(program,
"Texture0");
++ return tc->uloc.Texture[0] != -1 ? VLC_SUCCESS : VLC_EGENERIC;
++}
++
++static void
++tc_mmal_prepare_shader(const opengl_tex_converter_t *tc,
++ const GLsizei *tex_width, const GLsizei *tex_height,
++ float alpha)
++{
++ (void) tex_width; (void) tex_height; (void) alpha;
++ VLC_UNUSED(tc);
++// tc->vt->Uniform1i(tc->uloc.Texture[0], 0);
++}
++
++static GLuint
++tc_fragment_shader_init(opengl_tex_converter_t * const tc, const GLenum tex_target,
++ const vlc_fourcc_t chroma, const video_color_space_t yuv_space)
++{
++ VLC_UNUSED(yuv_space);
++
++ tc->tex_count = 1;
++ tc->tex_target = tex_target;
++ tc->texs[0] = (struct opengl_tex_cfg) {
++ { 1, 1 }, { 1, 1 }, GL_RGB, chroma, GL_UNSIGNED_SHORT //** ??
++ };
++
++ tc->pf_fetch_locations = tc_mmal_fetch_locations;
++ tc->pf_prepare_shader = tc_mmal_prepare_shader;
++
++
++ const char fs[] =
++ "#extension GL_OES_EGL_image_external : enable\n"
++ "precision mediump float;\n"
++ "uniform samplerExternalOES Texture0;\n"
++ "varying vec2 TexCoord0;\n"
++ "void main() {\n"
++ " gl_FragColor = texture2D(Texture0, TexCoord0);\n"
++ "}\n";
++
++
++ const char *code = fs;
++
++ GLuint fragment_shader = tc->vt->CreateShader(GL_FRAGMENT_SHADER);
++ tc->vt->ShaderSource(fragment_shader, 1, &code, NULL);
++ tc->vt->CompileShader(fragment_shader);
++ return fragment_shader;
++}
++
++
++static void
++CloseGLConverter(vlc_object_t *obj)
++{
++ opengl_tex_converter_t * const tc = (opengl_tex_converter_t *)obj;
++ mmal_gl_converter_t * const sys = tc->priv;
++
++ if (sys == NULL)
++ return;
++
++ cma_buf_pic_context_unref(sys->last_ctx_ref);
++ cma_vcsm_exit(sys->vcsm_init_type);
++ free(sys);
++}
++
++static int
++OpenGLConverter(vlc_object_t *obj)
++{
++ opengl_tex_converter_t * const tc = (opengl_tex_converter_t *)obj;
++ int rv = VLC_EGENERIC;
++ const EGLint eglfmt = vlc_to_gl_fourcc(&tc->fmt);
++
++ // Accept Opaque (as it can definitely be converted) or what we actually want
++ if (!(tc->fmt.i_chroma == FMT_IN ||
++ tc->fmt.i_chroma == VLC_CODEC_MMAL_OPAQUE))
++ {
++ return rv;
++ }
++
++ if (tc->gl->ext != VLC_GL_EXT_EGL ||
++ !tc->gl->egl.createImageKHR || !tc->gl->egl.destroyImageKHR)
++ {
++ // Missing an important callback
++ msg_Dbg(tc, "Missing EGL xxxImageKHR calls");
++ return rv;
++ }
++
++ {
++ char dbuf0[5], dbuf1[5];
++ msg_Dbg(tc, ">>> %s: V:%s/E:%s,%dx%d [(%d,%d) %d/%d]
sar:%d/%d", __func__,
++ str_fourcc(dbuf0, tc->fmt.i_chroma),
++ str_fourcc(dbuf1, eglfmt),
++ tc->fmt.i_width, tc->fmt.i_height,
++ tc->fmt.i_x_offset, tc->fmt.i_y_offset,
++ tc->fmt.i_visible_width, tc->fmt.i_visible_height,
++ tc->fmt.i_sar_num, tc->fmt.i_sar_den);
++ }
++
++ if ((tc->priv = calloc(1, sizeof(mmal_gl_converter_t))) == NULL)
++ {
++ msg_Err(tc, "priv alloc failure");
++ rv = VLC_ENOMEM;
++ goto fail;
++ }
++ mmal_gl_converter_t * const sys = tc->priv;
++
++ sys->drm_fourcc = eglfmt;
++
++ if ((sys->vcsm_init_type = cma_vcsm_init()) != VCSM_INIT_CMA) {
++ msg_Dbg(tc, "VCSM init failed");
++ goto fail;
++ }
++
++ if ((sys->glEGLImageTargetTexture2DOES = vlc_gl_GetProcAddress(tc->gl,
"glEGLImageTargetTexture2DOES")) == NULL)
++ {
++ msg_Err(tc, "Failed to bind GL fns");
++ goto fail;
++ }
++
++ if ((tc->fshader = tc_fragment_shader_init(tc, GL_TEXTURE_EXTERNAL_OES,
++ eglfmt == 0 ? VLC_CODEC_RGB32 :
tc->fmt.i_chroma,
++ eglfmt == 0 ? COLOR_SPACE_SRGB :
tc->fmt.space)) == 0)
++ {
++ msg_Err(tc, "Failed to make shader");
++ goto fail;
++ }
++
++ if (eglfmt == 0)
++ {
++ tc->fmt.i_chroma = FMT_IN;
++ tc->fmt.i_bits_per_pixel = 8;
++ if (tc->fmt.i_chroma == VLC_CODEC_MMAL_ZC_RGB32)
++ {
++ tc->fmt.i_rmask = 0xff0000;
++ tc->fmt.i_gmask = 0xff00;
++ tc->fmt.i_bmask = 0xff;
++ tc->fmt.space = COLOR_SPACE_SRGB;
++ }
++ else
++ {
++ tc->fmt.i_rmask = 0;
++ tc->fmt.i_gmask = 0;
++ tc->fmt.i_bmask = 0;
++ tc->fmt.space = COLOR_SPACE_UNDEF;
++ }
++ sys->drm_fourcc = vlc_to_gl_fourcc(&tc->fmt);
++ }
++
++ tc->handle_texs_gen = true; // We manage the texs
++ tc->pf_update = tc_mmal_update;
++ return VLC_SUCCESS;
++
++fail:
++ CloseGLConverter(obj);
++ return rv;
++}
++
++vlc_module_begin ()
++ set_description("MMAL OpenGL surface converter")
++ set_shortname (N_("MMALGLConverter"))
++ set_capability("glconv", 900)
++ set_callbacks(OpenGLConverter, CloseGLConverter)
++ set_category(CAT_VIDEO)
++ set_subcategory(SUBCAT_VIDEO_VOUT)
++ add_shortcut("mmal_gl_converter")
++vlc_module_end ()
++
+--- a/modules/hw/mmal/deinterlace.c
++++ b/modules/hw/mmal/deinterlace.c
+@@ -26,11 +26,12 @@
+ #include "config.h"
+ #endif
+
+-#include <vlc_picture_pool.h>
++#include <stdatomic.h>
++
+ #include <vlc_common.h>
++#include <vlc_picture_pool.h>
+ #include <vlc_plugin.h>
+ #include <vlc_filter.h>
+-#include <vlc_atomic.h>
+
+ #include "mmal_picture.h"
+
+@@ -41,466 +42,569 @@
+
+ #define MIN_NUM_BUFFERS_IN_TRANSIT 2
+
+-#define MMAL_DEINTERLACE_QPU "mmal-deinterlace-adv-qpu"
+-#define MMAL_DEINTERLACE_QPU_TEXT N_("Use QPUs for advanced HD
deinterlacing.")
+-#define MMAL_DEINTERLACE_QPU_LONGTEXT N_("Make use of the QPUs to allow higher
quality deinterlacing of HD content.")
++#define MMAL_DEINTERLACE_NO_QPU "mmal-deinterlace-no-qpu"
++#define MMAL_DEINTERLACE_NO_QPU_TEXT N_("Do not use QPUs for advanced HD
deinterlacing.")
++#define MMAL_DEINTERLACE_NO_QPU_LONGTEXT N_("Do not make use of the QPUs to allow
higher quality deinterlacing of HD content.")
+
+-static int Open(filter_t *filter);
+-static void Close(filter_t *filter);
++#define MMAL_DEINTERLACE_ADV "mmal-deinterlace-adv"
++#define MMAL_DEINTERLACE_ADV_TEXT N_("Force advanced deinterlace")
++#define MMAL_DEINTERLACE_ADV_LONGTEXT N_("Force advanced deinterlace")
+
+-vlc_module_begin()
+- set_shortname(N_("MMAL deinterlace"))
+- set_description(N_("MMAL-based deinterlace filter plugin"))
+- set_capability("video filter", 0)
+- set_category(CAT_VIDEO)
+- set_subcategory(SUBCAT_VIDEO_VFILTER)
+- set_callbacks(Open, Close)
+- add_shortcut("deinterlace")
+- add_bool(MMAL_DEINTERLACE_QPU, false, MMAL_DEINTERLACE_QPU_TEXT,
+- MMAL_DEINTERLACE_QPU_LONGTEXT, true);
+-vlc_module_end()
++#define MMAL_DEINTERLACE_FAST "mmal-deinterlace-fast"
++#define MMAL_DEINTERLACE_FAST_TEXT N_("Force fast deinterlace")
++#define MMAL_DEINTERLACE_FAST_LONGTEXT N_("Force fast deinterlace")
++
++#define MMAL_DEINTERLACE_NONE "mmal-deinterlace-none"
++#define MMAL_DEINTERLACE_NONE_TEXT N_("Force no deinterlace")
++#define MMAL_DEINTERLACE_NONE_LONGTEXT N_("Force no interlace. Simply strips off
the interlace markers and passes the frame straight through. "\
++ "This is the default for > SD if < 96M gpu-mem")
++
++#define MMAL_DEINTERLACE_HALF_RATE "mmal-deinterlace-half-rate"
++#define MMAL_DEINTERLACE_HALF_RATE_TEXT N_("Halve output framerate")
++#define MMAL_DEINTERLACE_HALF_RATE_LONGTEXT N_("Halve output framerate. 1 output
frame for each pair of interlaced fields input")
++
++#define MMAL_DEINTERLACE_FULL_RATE "mmal-deinterlace-full-rate"
++#define MMAL_DEINTERLACE_FULL_RATE_TEXT N_("Full output framerate")
++#define MMAL_DEINTERLACE_FULL_RATE_LONGTEXT N_("Full output framerate. 1 output
frame for each interlaced field input")
+
+-struct filter_sys_t {
++
++typedef struct filter_sys_t
++{
+ MMAL_COMPONENT_T *component;
+ MMAL_PORT_T *input;
+ MMAL_PORT_T *output;
++ MMAL_POOL_T *in_pool;
++ hw_mmal_port_pool_ref_t *out_ppr;
+
+- MMAL_QUEUE_T *filtered_pictures;
+- vlc_sem_t sem;
++ MMAL_QUEUE_T * out_q;
+
+- atomic_bool started;
++ bool half_rate;
++ bool use_qpu;
++ bool use_fast;
++ bool use_passthrough;
+ unsigned int seq_in;
+ unsigned int seq_out;
+} filter_sys_t;
@@ -6146,48 +6703,548 @@
+ set_callbacks(MmalAvcodecOpenDecoder, MmalAvcodecCloseDecoder)
+vlc_module_end()
+
---- a/modules/hw/mmal/mmal_picture.c
-+++ b/modules/hw/mmal/mmal_picture.c
-@@ -21,25 +21,961 @@
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-+// We would really like to use vlc_thread.h but the detach thread stuff can't be
-+// used here :-(
-+#include <pthread.h>
+--- /dev/null
++++ b/modules/hw/mmal/mmal_cma.c
+@@ -0,0 +1,377 @@
++#ifdef HAVE_CONFIG_H
++# include "config.h"
++#endif
+
+#include <stdatomic.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/ioctl.h>
++#include <sys/mman.h>
+
- #include <vlc_common.h>
- #include <vlc_picture.h>
- #include <interface/mmal/mmal.h>
-+#include <interface/mmal/util/mmal_util.h>
-+#include <interface/mmal/util/mmal_default_components.h>
-+#include <interface/vmcs_host/vcgencmd.h>
+#include <interface/vcsm/user-vcsm.h>
-
- #include "mmal_picture.h"
-
--int mmal_picture_lock(picture_t *picture)
+
-+static void flush_range(void * start, size_t len)
++#include <vlc_common.h>
++#include <vlc_picture.h>
++
++#include "mmal_cma.h"
++
++#include <assert.h>
++
++
++typedef void * cma_pool_alloc_fn(void * v, size_t size);
++typedef void cma_pool_free_fn(void * v, void * el, size_t size);
++
++// Pool structure
++// Ref count is held by pool owner and pool els that have been got
++// Els in the pool do not count towards its ref count
++struct cma_pool_fixed_s
++{
++ atomic_int ref_count;
++
++ vlc_mutex_t lock;
++ unsigned int n_in;
++ unsigned int n_out;
++ unsigned int pool_size;
++ size_t el_size;
++ void ** pool;
++
++ void * alloc_v;
++ cma_pool_alloc_fn * el_alloc_fn;
++ cma_pool_free_fn * el_free_fn;
++};
++
++typedef struct cma_buf_s {
++ size_t size;
++ unsigned int vcsm_h; // VCSM handle from initial alloc
++ unsigned int vc_h; // VC handle for ZC mmal buffers
++ int fd; // dmabuf handle for GL
++ void * mmap; // ARM mapped address
++ picture_context_t *ctx2;
++} cma_buf_t;
++
++static int free_pool(const cma_pool_fixed_t * const p, void ** pool, unsigned int n,
size_t el_size)
++{
++ int i = 0;
++ assert(pool != NULL);
++
++ while (pool[n] != NULL)
++ {
++ p->el_free_fn(p->alloc_v, pool[n], el_size);
++ pool[n] = NULL;
++ n = n + 1 < p->pool_size ? n + 1 : 0;
++ ++i;
++ }
++ free(pool);
++ return i;
++}
++
++// Just kill this - no checks
++static void cma_pool_fixed_delete(cma_pool_fixed_t * const p)
++{
++ if (p->pool != NULL)
++ free_pool(p, p->pool, p->n_in, p->el_size);
++
++ vlc_mutex_destroy(&p->lock);
++ free(p);
++}
++
++void cma_pool_fixed_unref(cma_pool_fixed_t * const p)
++{
++ if (atomic_fetch_sub(&p->ref_count, 1) <= 1)
++ cma_pool_fixed_delete(p);
++}
++
++void cma_pool_fixed_ref(cma_pool_fixed_t * const p)
++{
++ atomic_fetch_add(&p->ref_count, 1);
++}
++
++void * cma_pool_fixed_get(cma_pool_fixed_t * const p, const size_t req_el_size)
++{
++ void * v = NULL;
++ void ** deadpool = NULL;
++ size_t dead_size = 0;
++ unsigned int dead_n = 0;
++
++ vlc_mutex_lock(&p->lock);
++
++ if (req_el_size != p->el_size)
++ {
++ deadpool = p->pool;
++ dead_n = p->n_in;
++ dead_size = p->el_size;
++
++ p->pool = NULL;
++ p->n_in = 0;
++ p->n_out = 0;
++ p->el_size = req_el_size;
++ }
++ else if (p->pool != NULL)
++ {
++ v = p->pool[p->n_in];
++ if (v != NULL)
++ {
++ p->pool[p->n_in] = NULL;
++ p->n_in = p->n_in + 1 < p->pool_size ? p->n_in + 1 : 0;
++ }
++ }
++
++ vlc_mutex_unlock(&p->lock);
++
++ // Do the free old op outside the mutex in case the free is slow
++ if (deadpool != NULL)
++ free_pool(p, deadpool, dead_n, dead_size);
++
++ if (v == NULL && req_el_size != 0)
++ v = p->el_alloc_fn(p->alloc_v, req_el_size);
++
++ // Tag ref
++ if (v != NULL)
++ cma_pool_fixed_ref(p);
++
++ return v;
++}
++
++void cma_pool_fixed_put(cma_pool_fixed_t * const p, void * v, const size_t el_size)
++{
++ vlc_mutex_lock(&p->lock);
++
++ if (el_size == p->el_size && (p->pool == NULL ||
p->pool[p->n_out] == NULL))
++ {
++ if (p->pool == NULL)
++ p->pool = calloc(p->pool_size, sizeof(void*));
++
++ p->pool[p->n_out] = v;
++ p->n_out = p->n_out + 1 < p->pool_size ? p->n_out + 1 : 0;
++ v = NULL;
++ }
++
++ vlc_mutex_unlock(&p->lock);
++
++ if (v != NULL)
++ p->el_free_fn(p->alloc_v, v, el_size);
++
++ cma_pool_fixed_unref(p);
++}
++
++// Purge pool & unref
++void cma_pool_fixed_kill(cma_pool_fixed_t * const p)
++{
++ // This flush is not strictly needed but it reclaims what memory we can reclaim
asap
++ cma_pool_fixed_get(p, 0);
++ cma_pool_fixed_unref(p);
++}
++
++cma_pool_fixed_t*
++cma_pool_fixed_new(const unsigned int pool_size, void * const alloc_v,
++ cma_pool_alloc_fn * const alloc_fn, cma_pool_free_fn * const
free_fn)
++{
++ cma_pool_fixed_t* const p = calloc(1, sizeof(cma_pool_fixed_t));
++ if (p == NULL)
++ return NULL;
++
++ atomic_store(&p->ref_count, 1);
++ vlc_mutex_init(&p->lock);
++
++ p->pool_size = pool_size;
++
++ p->alloc_v = alloc_v;
++ p->el_alloc_fn = alloc_fn;
++ p->el_free_fn = free_fn;
++
++ return p;
++}
++
++
++static void cma_pool_delete(cma_buf_t * const cb)
++{
++ if (cb->ctx2 != NULL)
++ cb->ctx2->destroy(cb->ctx2);
++
++ if (cb->mmap != MAP_FAILED)
++ munmap(cb->mmap, cb->size);
++ if (cb->fd != -1)
++ close(cb->fd);
++ if (cb->vcsm_h != 0)
++ vcsm_free(cb->vcsm_h);
++ free(cb);
++}
++
++static void cma_pool_free_cb(void * v, void * el, size_t size)
++{
++ VLC_UNUSED(v);
++ VLC_UNUSED(size);
++
++ cma_pool_delete(el);
++}
++
++static void * cma_pool_alloc_cb(void * v, size_t size)
++{
++ VLC_UNUSED(v);
++
++ cma_buf_t * const cb = malloc(sizeof(cma_buf_t));
++ if (cb == NULL)
++ return NULL;
++
++ *cb = (cma_buf_t){
++ .size = size,
++ .vcsm_h = 0,
++ .vc_h = 0,
++ .fd = -1,
++ .mmap = MAP_FAILED,
++ .ctx2 = NULL
++ };
++
++ if ((cb->vcsm_h = vcsm_malloc_cache(size, VCSM_CACHE_TYPE_HOST, (char*)"VLC
frame")) == 0)
++ goto fail;
++
++ if ((cb->vc_h = vcsm_vc_hdl_from_hdl(cb->vcsm_h)) == 0)
++ goto fail;
++
++ if ((cb->fd = vcsm_export_dmabuf(cb->vcsm_h)) == -1)
++ goto fail;
++
++ if ((cb->mmap = mmap(NULL, cb->size, PROT_READ | PROT_WRITE, MAP_SHARED |
MAP_LOCKED, cb->fd, 0)) == MAP_FAILED)
++ goto fail;
++
++ return cb;
++
++fail:
++ cma_pool_delete(cb);
++ return NULL;
++}
++
++void cma_buf_pool_delete(cma_pool_fixed_t * const p)
++{
++ assert(p != NULL);
++
++ cma_pool_fixed_kill(p);
++}
++
++cma_pool_fixed_t * cma_buf_pool_new(void)
++{
++ return cma_pool_fixed_new(5, NULL, cma_pool_alloc_cb, cma_pool_free_cb);
++}
++
++
++typedef struct cma_pic_context_s {
++ picture_context_t cmn;
++
++ atomic_int ref_count;
++ cma_pool_fixed_t * p;
++ cma_buf_t * cb;
++} cma_pic_context_t;
++
++
++static void cma_buf_pic_ctx_ref(cma_pic_context_t * const ctx)
+{
-+ struct vcsm_user_clean_invalid2_s * b = calloc(1,
-+ sizeof(struct vcsm_user_clean_invalid2_s) + sizeof(struct
vcsm_user_clean_invalid2_block_s));
++ atomic_fetch_add(&ctx->ref_count, 1);
++}
+
-+ b->op_count = 1,
++static void cma_buf_pic_ctx_unref(cma_pic_context_t * const ctx)
++{
++ if (atomic_fetch_sub(&ctx->ref_count, 1) > 0)
++ return;
++
++ if (ctx->cb != NULL)
++ cma_pool_fixed_put(ctx->p, ctx->cb, ctx->cb->size);
++
++ free(ctx);
++}
++
++static picture_context_t * cma_buf_pic_ctx_copy(picture_context_t * pic_ctx)
++{
++ cma_buf_pic_ctx_ref((cma_pic_context_t *)pic_ctx);
++ return pic_ctx;
++}
++
++static void cma_buf_pic_ctx_destroy(picture_context_t * pic_ctx)
++{
++ cma_buf_pic_ctx_unref((cma_pic_context_t *)pic_ctx);
++}
++
++int cma_buf_pic_attach(cma_pool_fixed_t * const p, picture_t * const pic, const size_t
size)
++{
++ if (!is_cma_buf_pic_chroma(pic->format.i_chroma))
++ return VLC_EGENERIC;
++ if (pic->context != NULL)
++ return VLC_EBADVAR;
++
++ cma_buf_t * const cb = cma_pool_fixed_get(p, size);
++ if (cb == NULL)
++ return VLC_ENOMEM;
++
++ cma_pic_context_t * const ctx = malloc(sizeof(cma_pic_context_t));
++ if (ctx == NULL)
++ goto fail;
++
++ *ctx = (cma_pic_context_t){
++ .cmn = {
++ .destroy = cma_buf_pic_ctx_destroy,
++ .copy = cma_buf_pic_ctx_copy
++ },
++ .ref_count = 0,
++ .p = p,
++ .cb = cb
++ };
++
++ pic->context = &ctx->cmn;
++ return VLC_SUCCESS;
++
++fail:
++ cma_pool_fixed_put(p, cb, size);
++ return VLC_EGENERIC;
++}
++
++int cma_buf_pic_add_context2(picture_t *const pic, picture_context_t * const ctx2)
++{
++ cma_pic_context_t *const ctx = (cma_pic_context_t *)pic->context;
++ if (!is_cma_buf_pic_chroma(pic->format.i_chroma) || ctx == NULL || ctx->cb ==
NULL || ctx->cb->ctx2 != NULL)
++ return VLC_EGENERIC;
++
++ ctx->cb->ctx2 = ctx2;
++ return VLC_SUCCESS;
++}
++
++unsigned int cma_buf_pic_vc_handle(const picture_t * const pic)
++{
++ cma_pic_context_t *const ctx = (cma_pic_context_t *)pic->context;
++ return !is_cma_buf_pic_chroma(pic->format.i_chroma) || ctx == NULL ? 0 :
ctx->cb == NULL ? 0 : ctx->cb->vc_h;
++}
++
++int cma_buf_pic_fd(const picture_t * const pic)
++{
++ cma_pic_context_t *const ctx = (cma_pic_context_t *)pic->context;
++ return !is_cma_buf_pic_chroma(pic->format.i_chroma) || ctx == NULL ? -1 :
ctx->cb == NULL ? -1 : ctx->cb->fd;
++}
++
++void * cma_buf_pic_addr(const picture_t * const pic)
++{
++ cma_pic_context_t *const ctx = (cma_pic_context_t *)pic->context;
++ return !is_cma_buf_pic_chroma(pic->format.i_chroma) || ctx == NULL ? NULL :
ctx->cb == NULL ? NULL : ctx->cb->mmap;
++}
++
++picture_context_t * cma_buf_pic_context2(const picture_t * const pic)
++{
++ cma_pic_context_t *const ctx = (cma_pic_context_t *)pic->context;
++ return !is_cma_buf_pic_chroma(pic->format.i_chroma) || ctx == NULL ? NULL :
ctx->cb == NULL ? NULL : ctx->cb->ctx2;
++}
++
++cma_pic_context_t * cma_buf_pic_context_ref(const picture_t * const pic)
++{
++ cma_pic_context_t *const ctx = (cma_pic_context_t *)pic->context;
++
++ if (!is_cma_buf_pic_chroma(pic->format.i_chroma) || ctx == NULL || ctx->cb ==
NULL)
++ return NULL;
++
++ cma_buf_pic_ctx_ref(ctx);
++ return ctx;
++}
++
++void cma_buf_pic_context_unref(cma_pic_context_t * const ctx)
++{
++ if (ctx != NULL)
++ cma_buf_pic_ctx_unref(ctx);
++}
++
++
+--- /dev/null
++++ b/modules/hw/mmal/mmal_cma.h
+@@ -0,0 +1,45 @@
++
++struct cma_pool_fixed_s;
++typedef struct cma_pool_fixed_s cma_pool_fixed_t;
++
++typedef void * cma_pool_alloc_fn(void * v, size_t size);
++typedef void cma_pool_free_fn(void * v, void * el, size_t size);
++
++void cma_pool_fixed_unref(cma_pool_fixed_t * const p);
++void cma_pool_fixed_ref(cma_pool_fixed_t * const p);
++void * cma_pool_fixed_get(cma_pool_fixed_t * const p, const size_t req_el_size);
++void cma_pool_fixed_put(cma_pool_fixed_t * const p, void * v, const size_t el_size);
++void cma_pool_fixed_kill(cma_pool_fixed_t * const p);
++cma_pool_fixed_t* cma_pool_fixed_new(const unsigned int pool_size, void * const
alloc_v,
++ cma_pool_alloc_fn * const alloc_fn, cma_pool_free_fn * const free_fn);
++
++void cma_buf_pool_delete(cma_pool_fixed_t * const p);
++cma_pool_fixed_t * cma_buf_pool_new(void);
++
++int cma_buf_pic_attach(cma_pool_fixed_t * const p, picture_t * const pic, const size_t
size);
++int cma_buf_pic_add_context2(picture_t *const pic, picture_context_t * const ctx2);
++unsigned int cma_buf_pic_vc_handle(const picture_t * const pic);
++int cma_buf_pic_fd(const picture_t * const pic);
++void * cma_buf_pic_addr(const picture_t * const pic);
++picture_context_t * cma_buf_pic_context2(const picture_t * const pic);
++struct cma_pic_context_s;
++struct cma_pic_context_s * cma_buf_pic_context_ref(const picture_t * const pic);
++void cma_buf_pic_context_unref(struct cma_pic_context_s * const ctx);
++
++#include <vlc_fourcc.h>
++
++static inline bool is_cma_buf_pic_chroma(const uint32_t chroma)
++{
++ return chroma == VLC_CODEC_MMAL_ZC_RGB32 || chroma == VLC_CODEC_MMAL_ZC_SAND8 ||
chroma == VLC_CODEC_MMAL_ZC_I420;
++}
++
++static inline void cma_buf_pool_deletez(cma_pool_fixed_t ** const pp)
++{
++ cma_pool_fixed_t * const p = *pp;
++ if (p != NULL) {
++ *pp = NULL;
++ cma_buf_pool_delete(p);
++ }
++}
++
++
+--- /dev/null
++++ b/modules/hw/mmal/mmal_gl.h
+@@ -0,0 +1,45 @@
++// Trim this include list!
++
++#include <libdrm/drm.h>
++#include <libdrm/drm_mode.h>
++#include <libdrm/drm_fourcc.h>
++//#include <xf86drm.h>
++//#include <xf86drmMode.h>
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++#include <X11/Xlib-xcb.h>
++#include <epoxy/gl.h>
++#include <epoxy/egl.h>
++#include <xcb/xcb.h>
++#include <xcb/dri3.h>
++
++struct mmal_gl_converter_s;
++
++typedef struct cma_buf_s {
++ struct mmal_gl_converter_s * sys;
++
++ size_t size;
++ __u32 h_dumb;
++ int fd;
++ unsigned int h_vcsm;
++ void * mapped_addr;
++ GLuint texture;
++} cma_buf_t;
++
++typedef struct cma_pic_sys_s {
++ cma_buf_t * cmabuf;
++} cma_pic_sys_t;
++
++static inline unsigned int
++hw_mmal_h_vcsm(const picture_t * const pic)
++{
++ const cma_pic_sys_t *const pic_sys = (cma_pic_sys_t *)pic->p_sys;
++
++ if (pic->format.i_chroma != VLC_CODEC_MMAL_GL_RGB32 ||
++ pic_sys == NULL || pic_sys->cmabuf == NULL) {
++ return 0;
++ }
++
++ return pic_sys->cmabuf->h_vcsm;
++}
++
+--- a/modules/hw/mmal/mmal_picture.c
++++ b/modules/hw/mmal/mmal_picture.c
+@@ -21,25 +21,1034 @@
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
++// We would really like to use vlc_thread.h but the detach thread stuff can't be
++// used here :-(
++#include <pthread.h>
++
++#include <stdatomic.h>
++#include <unistd.h>
++#include <fcntl.h>
++
+ #include <vlc_common.h>
+ #include <vlc_picture.h>
+ #include <interface/mmal/mmal.h>
++#include <interface/mmal/util/mmal_util.h>
++#include <interface/mmal/util/mmal_default_components.h>
++#include <interface/vmcs_host/vcgencmd.h>
++#include <interface/vcsm/user-vcsm.h>
++
++#include "mmal_cma.h" // **************
+
+ #include "mmal_picture.h"
+
+-int mmal_picture_lock(picture_t *picture)
++#define UINT64_SIZE(s) (((s) + sizeof(uint64_t) - 1)/sizeof(uint64_t))
++
++static inline char safe_char(const unsigned int c0)
++{
++ const unsigned int c = c0 & 0xff;
++ return c > ' ' && c < 0x7f ? c : '.';
++}
++
++const char * str_fourcc(char * const buf, const unsigned int fcc)
++{
++ if (fcc == 0)
++ return "----";
++ buf[0] = safe_char(fcc >> 0);
++ buf[1] = safe_char(fcc >> 8);
++ buf[2] = safe_char(fcc >> 16);
++ buf[3] = safe_char(fcc >> 24);
++ buf[4] = 0;
++ return buf;
++}
++
++// WB + Inv
++static inline void flush_range(void * const start, const size_t len)
++{
++ uint64_t buf[UINT64_SIZE(sizeof(struct vcsm_user_clean_invalid2_s) + sizeof(struct
vcsm_user_clean_invalid2_block_s))];
++ struct vcsm_user_clean_invalid2_s * const b = (struct vcsm_user_clean_invalid2_s
*)buf;
++
++ *b = (struct vcsm_user_clean_invalid2_s){
++ .op_count = 1
++ };
+
+ b->s[0] = (struct vcsm_user_clean_invalid2_block_s){
-+ .invalidate_mode = 3,
++ .invalidate_mode = 3, // wb + invalidate
+ .block_count = 1,
-+ .start_address = start,
++ .start_address = start, // Rely on clean inv to fix up align & size
boundries
+ .block_size = len,
+ .inter_block_stride = 0
+ };
+
+ vcsm_clean_invalid2(b);
-+
-+ free(b);
+}
+
+MMAL_FOURCC_T vlc_to_mmal_color_space(const video_color_space_t vlc_cs)
@@ -6207,6 +7264,7 @@
+MMAL_FOURCC_T vlc_to_mmal_video_fourcc(const video_frame_format_t * const vf_vlc)
+{
+ switch (vf_vlc->i_chroma) {
++ case VLC_CODEC_MMAL_ZC_RGB32:
+ case VLC_CODEC_RGB32:
+ {
+ // VLC RGB32 aka RV32 means we have to look at the mask values
@@ -6223,6 +7281,8 @@
+ return MMAL_ENCODING_ARGB;
+ break;
+ }
++ case VLC_CODEC_MMAL_ZC_I420:
++ return MMAL_ENCODING_I420;
+ case VLC_CODEC_RGBA:
+ return MMAL_ENCODING_RGBA;
+ case VLC_CODEC_BGRA:
@@ -6347,7 +7407,9 @@
+ hw_mmal_port_pool_ref_t ** pppr,
+ MMAL_PORT_T * const port,
+ const unsigned int extra_buffers, MMAL_PORT_BH_CB_T
callback)
-+{
+ {
+- picture_sys_t *pic_sys = picture->p_sys;
+- MMAL_BUFFER_HEADER_T *buffer = pic_sys->buffer;
+ MMAL_STATUS_T status;
+
+ port->userdata = (struct MMAL_PORT_USERDATA_T *)obj;
@@ -6382,14 +7444,20 @@
+ msg_Err(obj, "Failed to create output pool");
+ return status;
+ }
-+
+
+- int offset = 0;
+- picture->p[0].p_pixels = buffer->data;
+- for (int i = 1; i < picture->i_planes; i++) {
+- offset = offset + picture->p[i - 1].i_pitch * picture->p[i - 1].i_lines;
+- picture->p[i].p_pixels = (ptrdiff_t)buffer->data + offset;
+ status = mmal_port_enable(port, callback);
+ if (status != MMAL_SUCCESS) {
+ msg_Err(obj, "Failed to enable output port %s (status=%"PRIx32"
%s)",
+ port->name, status, mmal_status_to_string(status));
+ return status;
-+ }
-+
+ }
+
+- pic_sys->displayed = false;
+ return MMAL_SUCCESS;
+}
+
@@ -6443,7 +7511,8 @@
+
+ return MMAL_TRUE;
+}
-+
+
+- return VLC_SUCCESS;
+// Buffer belongs to context on successful return from this fn
+// is still valid on failure
+picture_context_t *
@@ -6683,7 +7752,7 @@
+ ent = ent->prev;
+ }
+ return NULL;
-+}
+ }
+
+#define POOL_ENT_ALLOC_BLOCK 0x10000
+
@@ -6800,6 +7869,8 @@
+}
+
+
++const vlc_fourcc_t hw_mmal_vzc_subpicture_chromas[] = { VLC_CODEC_RGBA, VLC_CODEC_BGRA,
VLC_CODEC_ARGB, 0 };
++
+void hw_mmal_vzc_buf_get_wh(MMAL_BUFFER_HEADER_T * const buf, int * const pW, int *
const pH)
+{
+ const pool_ent_t *const ent = ((vzc_subbuf_ent_t *)buf->user_data)->ent;
@@ -6841,15 +7912,6 @@
+ return &sb->dreg;
+}
+
-+void hw_mmal_vzc_buf_set_dest_rect(MMAL_BUFFER_HEADER_T * const buf, const int x, const
int y, const int w, const int h)
-+{
-+ vzc_subbuf_ent_t * sb = buf->user_data;
-+ sb->orig_dest_rect.x = x;
-+ sb->orig_dest_rect.y = y;
-+ sb->orig_dest_rect.width = w;
-+ sb->orig_dest_rect.height = h;
-+}
-+
+static inline int rescale_x(int x, int mul, int div)
+{
+ return div == 0 ? x * mul : (x * mul + div/2) / div;
@@ -6864,9 +7926,7 @@
+}
+
+void hw_mmal_vzc_buf_scale_dest_rect(MMAL_BUFFER_HEADER_T * const buf, const MMAL_RECT_T
* const scale_rect)
- {
-- picture_sys_t *pic_sys = picture->p_sys;
-- MMAL_BUFFER_HEADER_T *buffer = pic_sys->buffer;
++{
+ vzc_subbuf_ent_t * sb = buf->user_data;
+ if (scale_rect == NULL) {
+ sb->dreg.dest_rect = sb->orig_dest_rect;
@@ -6891,7 +7951,14 @@
+// no rules governing the order in which things are blended) so we must deal
+// (fairly) gracefully with it never (or always) being set.
+
-+MMAL_BUFFER_HEADER_T * hw_mmal_vzc_buf_from_pic(vzc_pool_ctl_t * const pc, picture_t *
const pic, const picture_t * const dst_pic, const bool is_first)
++// dst_fmt gives the number space in which the destination pixels are specified
++
++MMAL_BUFFER_HEADER_T * hw_mmal_vzc_buf_from_pic(vzc_pool_ctl_t * const pc,
++ picture_t * const pic,
++ const MMAL_RECT_T dst_pic_rect,
++ const int x_offset, const int y_offset,
++ const unsigned int alpha,
++ const bool is_first)
+{
+ MMAL_BUFFER_HEADER_T * const buf = mmal_queue_get(pc->buf_pool->queue);
+ vzc_subbuf_ent_t * sb;
@@ -6967,22 +8034,33 @@
+ };
+
+ // Remember offsets
-+ sb->dreg.set = MMAL_DISPLAY_SET_SRC_RECT;
++ sb->dreg.set = MMAL_DISPLAY_SET_SRC_RECT |
++ MMAL_DISPLAY_SET_DEST_RECT |
++ MMAL_DISPLAY_SET_FULLSCREEN |
++ MMAL_DISPLAY_SET_ALPHA;
++
++ sb->dreg.fullscreen = 0;
++ // Will be set later - zero now to avoid any confusion
++ sb->dreg.dest_rect = (MMAL_RECT_T){0, 0, 0, 0};
++
++ sb->dreg.alpha = (uint32_t)(alpha & 0xff) |
MMAL_DISPLAY_ALPHA_FLAGS_MIX;
+
+// printf("+++ bpp:%d, vis:%dx%d wxh:%dx%d, d:%dx%d\n", bpp,
fmt->i_visible_width, fmt->i_visible_height, fmt->i_width, fmt->i_height,
dst_stride, dst_lines);
+
+ sb->dreg.src_rect = (MMAL_RECT_T){
-+ .x = (fmt->i_x_offset - xl),
-+ .y = 0,
-+ .width = fmt->i_visible_width,
++ .x = (fmt->i_x_offset - xl),
++ .y = 0,
++ .width = fmt->i_visible_width,
+ .height = fmt->i_visible_height
+ };
+
-+ sb->pic_rect = (MMAL_RECT_T){
-+ .x = dst_pic->format.i_x_offset,
-+ .y = dst_pic->format.i_y_offset,
-+ .width = dst_pic->format.i_visible_width,
-+ .height = dst_pic->format.i_visible_height
++ sb->pic_rect = dst_pic_rect;
++
++ sb->orig_dest_rect = (MMAL_RECT_T){
++ .x = x_offset,
++ .y = y_offset,
++ .width = fmt->i_visible_width,
++ .height = fmt->i_visible_height
+ };
+
+ if (needs_copy)
@@ -7021,12 +8099,7 @@
+ pool_recycle_list(pc, &pc->ents_prev);
+ pool_recycle_list(pc, &pc->ents_cur);
+}
-
-- int offset = 0;
-- picture->p[0].p_pixels = buffer->data;
-- for (int i = 1; i < picture->i_planes; i++) {
-- offset = offset + picture->p[i - 1].i_pitch * picture->p[i - 1].i_lines;
-- picture->p[i].p_pixels = (ptrdiff_t)buffer->data + offset;
++
+static void hw_mmal_vzc_pool_delete(vzc_pool_ctl_t * const pc)
+{
+
@@ -7107,22 +8180,55 @@
+ {
+ hw_mmal_vzc_pool_delete(pc);
+ return NULL;
- }
-
-- pic_sys->displayed = false;
++ }
++
+ atomic_store(&pc->ref_count, 1);
+
+ mmal_pool_callback_set(pc->buf_pool, vcz_pool_release_cb, pc);
-
-- return VLC_SUCCESS;
++
+ return pc;
- }
++}
++
+
++//----------------------------------------------------------------------------
++
++vcsm_init_type_t cma_vcsm_init(void)
++{
++ if (vcsm_init_ex(1, -1) == 0) {
++ return VCSM_INIT_CMA;
++ }
++ else if (vcsm_init_ex(0, -1) == 0) {
++ return VCSM_INIT_LEGACY;
++ }
++ return VCSM_INIT_NONE;
++}
++
++void cma_vcsm_exit(const vcsm_init_type_t init_mode)
++{
++ if (init_mode != VCSM_INIT_NONE)
++ vcsm_exit();
++}
++
++const char * cma_vcsm_init_str(const vcsm_init_type_t init_mode)
++{
++ switch (init_mode)
++ {
++ case VCSM_INIT_CMA:
++ return "CMA";
++ case VCSM_INIT_LEGACY:
++ return "Legacy";
++ case VCSM_INIT_NONE:
++ return "none";
++ default:
++ break;
++ }
++ return "???";
++}
+
+
--- a/modules/hw/mmal/mmal_picture.h
+++ b/modules/hw/mmal/mmal_picture.h
-@@ -24,19 +24,243 @@
+@@ -24,19 +24,275 @@
#ifndef VLC_MMAL_MMAL_PICTURE_H_
#define VLC_MMAL_MMAL_PICTURE_H_
@@ -7158,10 +8264,7 @@
+
+
+#define CTX_BUFS_MAX 4
-
-- MMAL_BUFFER_HEADER_T *buffer;
-- bool displayed;
--};
++
+typedef struct pic_ctx_mmal_s {
+ picture_context_t cmn; // PARENT: Common els at start
+
@@ -7180,8 +8283,9 @@
+ vlc_object_t * obj;
+#endif
+} pic_ctx_mmal_t;
-
--int mmal_picture_lock(picture_t *picture);
++
++const char * str_fourcc(char * const buf, const unsigned int fcc);
++
+MMAL_FOURCC_T vlc_to_mmal_video_fourcc(const video_frame_format_t * const vf_vlc);
+MMAL_FOURCC_T vlc_to_mmal_color_space(const video_color_space_t vlc_cs);
+void vlc_to_mmal_video_fmt(MMAL_ES_FORMAT_T *const es_fmt, const video_frame_format_t *
const vf_vlc);
@@ -7230,7 +8334,8 @@
+ return pic->format.i_chroma == VLC_CODEC_MMAL_OPAQUE ||
+ pic->format.i_chroma == VLC_CODEC_MMAL_ZC_SAND8 ||
+ pic->format.i_chroma == VLC_CODEC_MMAL_ZC_SAND10 ||
-+ pic->format.i_chroma == VLC_CODEC_MMAL_ZC_I420;
++ pic->format.i_chroma == VLC_CODEC_MMAL_ZC_I420 ||
++ pic->format.i_chroma == VLC_CODEC_MMAL_ZC_RGB32;
+}
+
+static inline MMAL_FOURCC_T hw_mmal_pic_format(const picture_t *const pic)
@@ -7341,21 +8446,28 @@
+struct vzc_pool_ctl_s;
+typedef struct vzc_pool_ctl_s vzc_pool_ctl_t;
+
++// At the moment we cope with any mono-planar RGBA thing
++// We could cope with many other things but they currently don't occur
++extern const vlc_fourcc_t hw_mmal_vzc_subpicture_chromas[];
+static inline bool hw_mmal_vzc_subpic_fmt_valid(const video_frame_format_t * const
vf_vlc)
+{
+ const vlc_fourcc_t vfcc_src = vf_vlc->i_chroma;
-+ // At the moment we cope with any mono-planar RGBA thing
-+ // We could cope with many other things but they currently don't occur
-+ return vfcc_src == VLC_CODEC_RGBA || vfcc_src == VLC_CODEC_BGRA || vfcc_src ==
VLC_CODEC_ARGB;
++ for (const vlc_fourcc_t * p = hw_mmal_vzc_subpicture_chromas; *p != 0; ++p)
++ if (*p == vfcc_src)
++ return true;
++
++ return false;
+}
+
+bool hw_mmal_vzc_buf_set_format(MMAL_BUFFER_HEADER_T * const buf, MMAL_ES_FORMAT_T *
const es_fmt);
+MMAL_DISPLAYREGION_T * hw_mmal_vzc_buf_region(MMAL_BUFFER_HEADER_T * const buf);
-+void hw_mmal_vzc_buf_set_dest_rect(MMAL_BUFFER_HEADER_T * const buf, const int x, const
int y, const int w, const int h);
+void hw_mmal_vzc_buf_scale_dest_rect(MMAL_BUFFER_HEADER_T * const buf, const MMAL_RECT_T
* const scale_rect);
+void hw_mmal_vzc_buf_get_wh(MMAL_BUFFER_HEADER_T * const buf, int * const pW, int *
const pH);
+unsigned int hw_mmal_vzc_buf_seq(MMAL_BUFFER_HEADER_T * const buf);
-+MMAL_BUFFER_HEADER_T * hw_mmal_vzc_buf_from_pic(vzc_pool_ctl_t * const pc, picture_t *
const pic, const picture_t * const dst_pic, const bool is_first);
++MMAL_BUFFER_HEADER_T * hw_mmal_vzc_buf_from_pic(vzc_pool_ctl_t * const pc, picture_t *
const pic,
++ const MMAL_RECT_T dst_pic_rect,
++ const int x_offset, const int y_offset,
++ const unsigned int alpha, const bool
is_first);
+void hw_mmal_vzc_buf_frame_size(MMAL_BUFFER_HEADER_T * const buf,
+ uint32_t * const pWidth, uint32_t * const pHeight);
+
@@ -7364,9 +8476,35 @@
+void hw_mmal_vzc_pool_ref(vzc_pool_ctl_t * const pc);
+vzc_pool_ctl_t * hw_mmal_vzc_pool_new(void);
+
++
++static inline MMAL_RECT_T vis_mmal_rect(const video_format_t * const fmt)
++{
++ return (MMAL_RECT_T){
++ .x = fmt->i_x_offset,
++ .y = fmt->i_y_offset,
++ .width = fmt->i_visible_width,
++ .height = fmt->i_visible_height
++ };
++}
++
++typedef enum vcsm_init_type_e {
++ VCSM_INIT_NONE = 0,
++ VCSM_INIT_LEGACY,
++ VCSM_INIT_CMA
++} vcsm_init_type_t;
++
++vcsm_init_type_t cma_vcsm_init(void);
++void cma_vcsm_exit(const vcsm_init_type_t init_mode);
++const char * cma_vcsm_init_str(const vcsm_init_type_t init_mode);
++
+
+- MMAL_BUFFER_HEADER_T *buffer;
+- bool displayed;
+-};
+#define VOUT_DISPLAY_CHANGE_MMAL_BASE 1024
+#define VOUT_DISPLAY_CHANGE_MMAL_HIDE (VOUT_DISPLAY_CHANGE_MMAL_BASE + 0)
-+
+
+-int mmal_picture_lock(picture_t *picture);
+#define MMAL_COMPONENT_DEFAULT_RESIZER "vc.ril.resize"
+#define MMAL_COMPONENT_ISP_RESIZER "vc.ril.isp"
+#define MMAL_COMPONENT_HVS "vc.ril.hvs"
@@ -7487,7 +8625,7 @@
+
--- /dev/null
+++ b/modules/hw/mmal/subpic.c
-@@ -0,0 +1,222 @@
+@@ -0,0 +1,227 @@
+/*****************************************************************************
+ * mmal.c: MMAL-based decoder plugin for Raspberry Pi
+ *****************************************************************************
@@ -7595,13 +8733,13 @@
+
+
+int hw_mmal_subpic_update(vlc_object_t * const p_filter,
-+ picture_t * const p_pic, const unsigned int sub_no,
++ MMAL_BUFFER_HEADER_T * const sub_buf,
+ subpic_reg_stash_t * const spe,
++ const video_format_t * const fmt,
+ const MMAL_RECT_T * const scale_out,
+ const uint64_t pts)
+{
+ MMAL_STATUS_T err;
-+ MMAL_BUFFER_HEADER_T * const sub_buf = hw_mmal_pic_sub_buf_get(p_pic, sub_no);
+
+ if (sub_buf == NULL)
+ {
@@ -7647,24 +8785,29 @@
+ MMAL_DISPLAYREGION_T * const dreg = hw_mmal_vzc_buf_region(sub_buf);
+ MMAL_VIDEO_FORMAT_T *const v_fmt =
&spe->port->format->es->video;
+
-+ v_fmt->frame_rate.den = p_pic->format.i_frame_rate_base;
-+ v_fmt->frame_rate.num = p_pic->format.i_frame_rate;
-+ v_fmt->par.den = p_pic->format.i_sar_den;
-+ v_fmt->par.num = p_pic->format.i_sar_num;
++ v_fmt->frame_rate.den = fmt->i_frame_rate_base;
++ v_fmt->frame_rate.num = fmt->i_frame_rate;
++ v_fmt->par.den = fmt->i_sar_den;
++ v_fmt->par.num = fmt->i_sar_num;
+ v_fmt->color_space = MMAL_COLOR_SPACE_UNKNOWN;
+
-+
+ if (needs_update || dreg->alpha != spe->alpha ||
!cmp_rect(&dreg->dest_rect, &spe->dest_rect)) {
+
+ spe->alpha = dreg->alpha;
+ spe->dest_rect = dreg->dest_rect;
+ needs_update = true;
-+#if TRACE_ALL
-+ msg_Dbg(p_filter, "Update region for sub %d", sub_no);
-+#endif
++
+ dreg->layer = spe->layer;
+ dreg->set |= MMAL_DISPLAY_SET_LAYER;
+
++#if TRACE_ALL
++ msg_Dbg(p_filter, "%s: Update region: Set=%x, dest=%dx%d @ (%d,%d),
src=%dx%d @ (%d,%d), layer=%d, alpha=%#x",
++ __func__, dreg->set,
++ dreg->dest_rect.width, dreg->dest_rect.height,
dreg->dest_rect.x, dreg->dest_rect.y,
++ dreg->src_rect.width, dreg->src_rect.height,
dreg->src_rect.x, dreg->src_rect.y,
++ dreg->layer, dreg->alpha);
++#endif
++
+ if ((err = mmal_port_parameter_set(spe->port, &dreg->hdr)) !=
MMAL_SUCCESS)
+ {
+ msg_Err(p_filter, "Set display region on subput failed");
@@ -7712,7 +8855,7 @@
+
--- /dev/null
+++ b/modules/hw/mmal/subpic.h
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,29 @@
+#ifndef VLC_HW_MMAL_SUBPIC_H_
+#define VLC_HW_MMAL_SUBPIC_H_
+
@@ -7728,10 +8871,11 @@
+} subpic_reg_stash_t;
+
+int hw_mmal_subpic_update(vlc_object_t * const p_filter,
-+ picture_t * const p_pic, const unsigned int sub_no,
-+ subpic_reg_stash_t * const stash,
-+ const MMAL_RECT_T * const scale_out,
-+ const uint64_t pts);
++ MMAL_BUFFER_HEADER_T * const sub_buf,
++ subpic_reg_stash_t * const spe,
++ const video_format_t * const fmt,
++ const MMAL_RECT_T * const scale_out,
++ const uint64_t pts);
+
+void hw_mmal_subpic_flush(vlc_object_t * const p_filter, subpic_reg_stash_t * const
spe);
+
@@ -7744,385 +8888,385 @@
--- /dev/null
+++ b/modules/hw/mmal/v7_pmu.S
@@ -0,0 +1,263 @@
-+/*------------------------------------------------------------
-+Performance Monitor Block
-+------------------------------------------------------------*/
-+ .arm @ Make sure we are in ARM mode.
-+ .text
-+ .align 2
-+ .global getPMN @ export this function for the linker
-+
-+/* Returns the number of progammable counters uint32_t getPMN(void) */
-+
-+getPMN:
-+ MRC p15, 0, r0, c9, c12, 0 /* Read PMNC Register */
-+ MOV r0, r0, LSR #11 /* Shift N field down to bit 0 */
-+ AND r0, r0, #0x1F /* Mask to leave just the 5 N bits */
-+ BX lr
-+
-+
-+
-+ .global pmn_config @ export this function for the linker
-+ /* Sets the event for a programmable counter to record */
-+ /* void pmn_config(unsigned counter, uint32_t event) */
-+ /* counter = r0 = Which counter to program (e.g. 0 for PMN0, 1 for PMN1 */
-+ /* event = r1 = The event code */
-+pmn_config:
-+ AND r0, r0, #0x1F /* Mask to leave only bits 4:0 */
-+ MCR p15, 0, r0, c9, c12, 5 /* Write PMNXSEL Register */
-+ MCR p15, 0, r1, c9, c13, 1 /* Write EVTSELx Register */
-+ BX lr
-+
-+
-+
-+ .global ccnt_divider @ export this function for the linker
-+ /* Enables/disables the divider (1/64) on CCNT */
-+ /* void ccnt_divider(int divider) */
-+ /* divider = r0 = If 0 disable divider, else enable dvider */
-+ccnt_divider:
-+ MRC p15, 0, r1, c9, c12, 0 /* Read PMNC */
-+
-+ CMP r0, #0x0 /* IF (r0 == 0) */
-+ BICEQ r1, r1, #0x08 /* THEN: Clear the D bit (disables the */
-+ ORRNE r1, r1, #0x08 /* ELSE: Set the D bit (enables the di */
-+
-+ MCR p15, 0, r1, c9, c12, 0 /* Write PMNC */
-+ BX lr
-+
-+
-+ /* --------------------------------------------------------------- */
-+ /* Enable/Disable */
-+ /* --------------------------------------------------------------- */
-+
-+ .global enable_pmu @ export this function for the linker
-+ /* Global PMU enable */
-+ /* void enable_pmu(void) */
-+enable_pmu:
-+ MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
-+ ORR r0, r0, #0x01 /* Set E bit */
-+ MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
-+ BX lr
-+
-+
-+
-+ .global disable_pmu @ export this function for the linker
-+ /* Global PMU disable */
-+ /* void disable_pmu(void) */
-+disable_pmu:
-+ MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
-+ BIC r0, r0, #0x01 /* Clear E bit */
-+ MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
-+ BX lr
-+
-+
-+
-+ .global enable_ccnt @ export this function for the linker
-+ /* Enable the CCNT */
-+ /* void enable_ccnt(void) */
-+enable_ccnt:
-+ MOV r0, #0x80000000 /* Set C bit */
-+ MCR p15, 0, r0, c9, c12, 1 /* Write CNTENS Register */
-+ BX lr
-+
-+
-+
-+ .global disable_ccnt @ export this function for the linker
-+ /* Disable the CCNT */
-+ /* void disable_ccnt(void) */
-+disable_ccnt:
-+ MOV r0, #0x80000000 /* Clear C bit */
-+ MCR p15, 0, r0, c9, c12, 2 /* Write CNTENC Register */
-+ BX lr
-+
-+
-+
-+ .global enable_pmn @ export this function for the linker
-+ /* Enable PMN{n} */
-+ /* void enable_pmn(uint32_t counter) */
-+ /* counter = r0 = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
-+enable_pmn: */
-+ MOV r1, #0x1 /* Use arg (r0) to set which counter t */
-+ MOV r1, r1, LSL r0
-+
-+ MCR p15, 0, r1, c9, c12, 1 /* Write CNTENS Register */
-+ BX lr
-+
-+
-+
-+ .global disable_pmn @ export this function for the linker
-+ /* Enable PMN{n} */
-+ /* void disable_pmn(uint32_t counter) */
-+ /* counter = r0 = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
-+disable_pmn: */
-+ MOV r1, #0x1 /* Use arg (r0) to set which counter t */
-+ MOV r1, r1, LSL r0
-+
-+ MCR p15, 0, r1, c9, c12, 1 /* Write CNTENS Register */
-+ BX lr
-+
-+
-+
-+ .global enable_pmu_user_access @ export this function for the linker
-+ /* Enables User mode access to the PMU (must be called in a priviledge */
-+ /* void enable_pmu_user_access(void) */
-+enable_pmu_user_access:
-+ MRC p15, 0, r0, c9, c14, 0 /* Read PMUSERENR Register */
-+ ORR r0, r0, #0x01 /* Set EN bit (bit 0) */
-+ MCR p15, 0, r0, c9, c14, 0 /* Write PMUSERENR Register */
-+ BX lr
-+
-+
-+
-+ .global disable_pmu_user_access @ export this function for the linke
-+ /* Disables User mode access to the PMU (must be called in a priviledg */
-+ /* void disable_pmu_user_access(void) */
-+disable_pmu_user_access:
-+ MRC p15, 0, r0, c9, c14, 0 /* Read PMUSERENR Register */
-+ BIC r0, r0, #0x01 /* Clear EN bit (bit 0) */
-+ MCR p15, 0, r0, c9, c14, 0 /* Write PMUSERENR Register */
-+ BX lr
-+
-+
-+ /* --------------------------------------------------------------- */
-+ /* Counter read registers */
-+ /* --------------------------------------------------------------- */
-+
-+ .global read_ccnt @ export this function for the linker
-+ /* Returns the value of CCNT */
-+ /* uint32_t read_ccnt(void) */
-+read_ccnt:
-+ MRC p15, 0, r0, c9, c13, 0 /* Read CCNT Register */
-+ BX lr
-+
-+
-+ .global read_pmn @ export this function for the linker
-+ /* Returns the value of PMN{n} */
-+ /* uint32_t read_pmn(uint32_t counter) */
-+ /* counter = r0 = The counter to read (e.g. 0 for PMN0, 1 for PMN1) *
-+read_pmn: */
-+ AND r0, r0, #0x1F /* Mask to leave only bits 4:0 */
-+ MCR p15, 0, r0, c9, c12, 5 /* Write PMNXSEL Register */
-+ MRC p15, 0, r0, c9, c13, 2 /* Read current PMNx Register */
-+ BX lr
-+
-+
-+ /* --------------------------------------------------------------- */
-+ /* Software Increment */
-+ /* --------------------------------------------------------------- */
-+
-+ .global pmu_software_increment @ export this function for the linker
-+ /* Writes to software increment register */
-+ /* void pmu_software_increment(uint32_t counter) */
-+ /* counter = r0 = The counter to increment (e.g. 0 for PMN0, 1 for PMN
-+pmu_software_increment: */
-+ MOV r1, #0x01
-+ MOV r1, r1, LSL r0
-+ MCR p15, 0, r1, c9, c12, 4 /* Write SWINCR Register */
-+ BX lr
-+
-+ /* --------------------------------------------------------------- */
-+ /* Overflow & Interrupt Generation */
-+ /* --------------------------------------------------------------- */
-+
-+ .global read_flags @ export this function for the linker
-+ /* Returns the value of the overflow flags */
-+ /* uint32_t read_flags(void) */
-+read_flags:
-+ MRC p15, 0, r0, c9, c12, 3 /* Read FLAG Register */
-+ BX lr
-+
-+
-+ .global write_flags @ export this function for the linker
-+ /* Writes the overflow flags */
-+ /* void write_flags(uint32_t flags) */
-+write_flags:
-+ MCR p15, 0, r0, c9, c12, 3 /* Write FLAG Register */
-+ BX lr
-+
-+
-+ .global enable_ccnt_irq @ export this function for the linker
-+ /* Enables interrupt generation on overflow of the CCNT */
-+ /* void enable_ccnt_irq(void) */
-+enable_ccnt_irq:
-+ MOV r0, #0x80000000
-+ MCR p15, 0, r0, c9, c14, 1 /* Write INTENS Register */
-+ BX lr
-+
-+ .global disable_ccnt_irq @ export this function for the linker
-+ /* Disables interrupt generation on overflow of the CCNT */
-+ /* void disable_ccnt_irq(void) */
-+disable_ccnt_irq:
-+ MOV r0, #0x80000000
-+ MCR p15, 0, r0, c9, c14, 2 /* Write INTENC Register */
-+ BX lr
-+
-+
-+ .global enable_pmn_irq @ export this function for the linker
-+ /* Enables interrupt generation on overflow of PMN{x} */
-+ /* void enable_pmn_irq(uint32_t counter) */
-+ /* counter = r0 = The counter to enable the interrupt for (e.g. 0 for
-+enable_pmn_irq: */
-+ MOV r1, #0x1 /* Use arg (r0) to set which counter */
-+ MOV r0, r1, LSL r0
-+ MCR p15, 0, r0, c9, c14, 1 /* Write INTENS Register */
-+ BX lr
-+
-+ .global disable_pmn_irq @ export this function for the linker
-+ /* Disables interrupt generation on overflow of PMN{x} */
-+ /* void disable_pmn_irq(uint32_t counter) */
-+ /* counter = r0 = The counter to disable the interrupt for (e.g. 0 fo
-+disable_pmn_irq: */
-+ MOV r1, #0x1 /* Use arg (r0) to set which counter t */
-+ MOV r0, r1, LSL r0
-+ MCR p15, 0, r0, c9, c14, 2 /* Write INTENC Register */
-+ BX lr
-+
-+ /* --------------------------------------------------------------- */
-+ /* Reset Functions */
-+ /* --------------------------------------------------------------- */
-+
-+ .global reset_pmn @ export this function for the linker
-+ /* Resets the programmable counters */
-+ /* void reset_pmn(void) */
-+reset_pmn:
-+ MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
-+ ORR r0, r0, #0x02 /* Set P bit (Event Counter Reset) */
-+ MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
-+ BX lr
-+
-+
-+ .global reset_ccnt @ export this function for the linker
-+ /* Resets the CCNT */
-+ /* void reset_ccnt(void) */
-+reset_ccnt:
-+ MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
-+ ORR r0, r0, #0x04 /* Set C bit (Event Counter Reset) */
-+ MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
-+ BX lr
-+
-+
-+ .end @end of code, this line is optional.
-+/* ------------------------------------------------------------ */
-+/* End of v7_pmu.s */
-+/* ------------------------------------------------------------ */
-+
-+
++/*------------------------------------------------------------
++Performance Monitor Block
++------------------------------------------------------------*/
++ .arm @ Make sure we are in ARM mode.
++ .text
++ .align 2
++ .global getPMN @ export this function for the linker
++
++/* Returns the number of progammable counters uint32_t getPMN(void) */
++
++getPMN:
++ MRC p15, 0, r0, c9, c12, 0 /* Read PMNC Register */
++ MOV r0, r0, LSR #11 /* Shift N field down to bit 0 */
++ AND r0, r0, #0x1F /* Mask to leave just the 5 N bits */
++ BX lr
++
++
++
++ .global pmn_config @ export this function for the linker
++ /* Sets the event for a programmable counter to record */
++ /* void pmn_config(unsigned counter, uint32_t event) */
++ /* counter = r0 = Which counter to program (e.g. 0 for PMN0, 1 for PMN1 */
++ /* event = r1 = The event code */
++pmn_config:
++ AND r0, r0, #0x1F /* Mask to leave only bits 4:0 */
++ MCR p15, 0, r0, c9, c12, 5 /* Write PMNXSEL Register */
++ MCR p15, 0, r1, c9, c13, 1 /* Write EVTSELx Register */
++ BX lr
++
++
++
++ .global ccnt_divider @ export this function for the linker
++ /* Enables/disables the divider (1/64) on CCNT */
++ /* void ccnt_divider(int divider) */
++ /* divider = r0 = If 0 disable divider, else enable dvider */
++ccnt_divider:
++ MRC p15, 0, r1, c9, c12, 0 /* Read PMNC */
++
++ CMP r0, #0x0 /* IF (r0 == 0) */
++ BICEQ r1, r1, #0x08 /* THEN: Clear the D bit (disables the */
++ ORRNE r1, r1, #0x08 /* ELSE: Set the D bit (enables the di */
++
++ MCR p15, 0, r1, c9, c12, 0 /* Write PMNC */
++ BX lr
++
++
++ /* --------------------------------------------------------------- */
++ /* Enable/Disable */
++ /* --------------------------------------------------------------- */
++
++ .global enable_pmu @ export this function for the linker
++ /* Global PMU enable */
++ /* void enable_pmu(void) */
++enable_pmu:
++ MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
++ ORR r0, r0, #0x01 /* Set E bit */
++ MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
++ BX lr
++
++
++
++ .global disable_pmu @ export this function for the linker
++ /* Global PMU disable */
++ /* void disable_pmu(void) */
++disable_pmu:
++ MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
++ BIC r0, r0, #0x01 /* Clear E bit */
++ MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
++ BX lr
++
++
++
++ .global enable_ccnt @ export this function for the linker
++ /* Enable the CCNT */
++ /* void enable_ccnt(void) */
++enable_ccnt:
++ MOV r0, #0x80000000 /* Set C bit */
++ MCR p15, 0, r0, c9, c12, 1 /* Write CNTENS Register */
++ BX lr
++
++
++
++ .global disable_ccnt @ export this function for the linker
++ /* Disable the CCNT */
++ /* void disable_ccnt(void) */
++disable_ccnt:
++ MOV r0, #0x80000000 /* Clear C bit */
++ MCR p15, 0, r0, c9, c12, 2 /* Write CNTENC Register */
++ BX lr
++
++
++
++ .global enable_pmn @ export this function for the linker
++ /* Enable PMN{n} */
++ /* void enable_pmn(uint32_t counter) */
++ /* counter = r0 = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
++enable_pmn: */
++ MOV r1, #0x1 /* Use arg (r0) to set which counter t */
++ MOV r1, r1, LSL r0
++
++ MCR p15, 0, r1, c9, c12, 1 /* Write CNTENS Register */
++ BX lr
++
++
++
++ .global disable_pmn @ export this function for the linker
++ /* Enable PMN{n} */
++ /* void disable_pmn(uint32_t counter) */
++ /* counter = r0 = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
++disable_pmn: */
++ MOV r1, #0x1 /* Use arg (r0) to set which counter t */
++ MOV r1, r1, LSL r0
++
++ MCR p15, 0, r1, c9, c12, 1 /* Write CNTENS Register */
++ BX lr
++
++
++
++ .global enable_pmu_user_access @ export this function for the linker
++ /* Enables User mode access to the PMU (must be called in a priviledge */
++ /* void enable_pmu_user_access(void) */
++enable_pmu_user_access:
++ MRC p15, 0, r0, c9, c14, 0 /* Read PMUSERENR Register */
++ ORR r0, r0, #0x01 /* Set EN bit (bit 0) */
++ MCR p15, 0, r0, c9, c14, 0 /* Write PMUSERENR Register */
++ BX lr
++
++
++
++ .global disable_pmu_user_access @ export this function for the linke
++ /* Disables User mode access to the PMU (must be called in a priviledg */
++ /* void disable_pmu_user_access(void) */
++disable_pmu_user_access:
++ MRC p15, 0, r0, c9, c14, 0 /* Read PMUSERENR Register */
++ BIC r0, r0, #0x01 /* Clear EN bit (bit 0) */
++ MCR p15, 0, r0, c9, c14, 0 /* Write PMUSERENR Register */
++ BX lr
++
++
++ /* --------------------------------------------------------------- */
++ /* Counter read registers */
++ /* --------------------------------------------------------------- */
++
++ .global read_ccnt @ export this function for the linker
++ /* Returns the value of CCNT */
++ /* uint32_t read_ccnt(void) */
++read_ccnt:
++ MRC p15, 0, r0, c9, c13, 0 /* Read CCNT Register */
++ BX lr
++
++
++ .global read_pmn @ export this function for the linker
++ /* Returns the value of PMN{n} */
++ /* uint32_t read_pmn(uint32_t counter) */
++ /* counter = r0 = The counter to read (e.g. 0 for PMN0, 1 for PMN1) *
++read_pmn: */
++ AND r0, r0, #0x1F /* Mask to leave only bits 4:0 */
++ MCR p15, 0, r0, c9, c12, 5 /* Write PMNXSEL Register */
++ MRC p15, 0, r0, c9, c13, 2 /* Read current PMNx Register */
++ BX lr
++
++
++ /* --------------------------------------------------------------- */
++ /* Software Increment */
++ /* --------------------------------------------------------------- */
++
++ .global pmu_software_increment @ export this function for the linker
++ /* Writes to software increment register */
++ /* void pmu_software_increment(uint32_t counter) */
++ /* counter = r0 = The counter to increment (e.g. 0 for PMN0, 1 for PMN
++pmu_software_increment: */
++ MOV r1, #0x01
++ MOV r1, r1, LSL r0
++ MCR p15, 0, r1, c9, c12, 4 /* Write SWINCR Register */
++ BX lr
++
++ /* --------------------------------------------------------------- */
++ /* Overflow & Interrupt Generation */
++ /* --------------------------------------------------------------- */
++
++ .global read_flags @ export this function for the linker
++ /* Returns the value of the overflow flags */
++ /* uint32_t read_flags(void) */
++read_flags:
++ MRC p15, 0, r0, c9, c12, 3 /* Read FLAG Register */
++ BX lr
++
++
++ .global write_flags @ export this function for the linker
++ /* Writes the overflow flags */
++ /* void write_flags(uint32_t flags) */
++write_flags:
++ MCR p15, 0, r0, c9, c12, 3 /* Write FLAG Register */
++ BX lr
++
++
++ .global enable_ccnt_irq @ export this function for the linker
++ /* Enables interrupt generation on overflow of the CCNT */
++ /* void enable_ccnt_irq(void) */
++enable_ccnt_irq:
++ MOV r0, #0x80000000
++ MCR p15, 0, r0, c9, c14, 1 /* Write INTENS Register */
++ BX lr
++
++ .global disable_ccnt_irq @ export this function for the linker
++ /* Disables interrupt generation on overflow of the CCNT */
++ /* void disable_ccnt_irq(void) */
++disable_ccnt_irq:
++ MOV r0, #0x80000000
++ MCR p15, 0, r0, c9, c14, 2 /* Write INTENC Register */
++ BX lr
++
++
++ .global enable_pmn_irq @ export this function for the linker
++ /* Enables interrupt generation on overflow of PMN{x} */
++ /* void enable_pmn_irq(uint32_t counter) */
++ /* counter = r0 = The counter to enable the interrupt for (e.g. 0 for
++enable_pmn_irq: */
++ MOV r1, #0x1 /* Use arg (r0) to set which counter */
++ MOV r0, r1, LSL r0
++ MCR p15, 0, r0, c9, c14, 1 /* Write INTENS Register */
++ BX lr
++
++ .global disable_pmn_irq @ export this function for the linker
++ /* Disables interrupt generation on overflow of PMN{x} */
++ /* void disable_pmn_irq(uint32_t counter) */
++ /* counter = r0 = The counter to disable the interrupt for (e.g. 0 fo
++disable_pmn_irq: */
++ MOV r1, #0x1 /* Use arg (r0) to set which counter t */
++ MOV r0, r1, LSL r0
++ MCR p15, 0, r0, c9, c14, 2 /* Write INTENC Register */
++ BX lr
++
++ /* --------------------------------------------------------------- */
++ /* Reset Functions */
++ /* --------------------------------------------------------------- */
++
++ .global reset_pmn @ export this function for the linker
++ /* Resets the programmable counters */
++ /* void reset_pmn(void) */
++reset_pmn:
++ MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
++ ORR r0, r0, #0x02 /* Set P bit (Event Counter Reset) */
++ MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
++ BX lr
++
++
++ .global reset_ccnt @ export this function for the linker
++ /* Resets the CCNT */
++ /* void reset_ccnt(void) */
++reset_ccnt:
++ MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
++ ORR r0, r0, #0x04 /* Set C bit (Event Counter Reset) */
++ MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
++ BX lr
++
++
++ .end @end of code, this line is optional.
++/* ------------------------------------------------------------ */
++/* End of v7_pmu.s */
++/* ------------------------------------------------------------ */
++
++
--- /dev/null
+++ b/modules/hw/mmal/v7_pmu.h
@@ -0,0 +1,113 @@
-+// ------------------------------------------------------------
-+// PMU for Cortex-A/R (v7-A/R)
-+// ------------------------------------------------------------
-+
-+#ifndef _V7_PMU_H
-+#define _V7_PMU_H
-+
-+// Returns the number of progammable counters
-+unsigned int getPMN(void);
-+
-+// Sets the event for a programmable counter to record
-+// counter = r0 = Which counter to program (e.g. 0 for PMN0, 1 for PMN1)
-+// event = r1 = The event code (from appropiate TRM or ARM Architecture Reference
Manual)
-+void pmn_config(unsigned int counter, unsigned int event);
-+
-+// Enables/disables the divider (1/64) on CCNT
-+// divider = r0 = If 0 disable divider, else enable dvider
-+void ccnt_divider(int divider);
-+
-+//
-+// Enables and disables
-+//
-+
-+// Global PMU enable
-+// On ARM11 this enables the PMU, and the counters start immediately
-+// On Cortex this enables the PMU, there are individual enables for the counters
-+void enable_pmu(void);
-+
-+// Global PMU disable
-+// On Cortex, this overrides the enable state of the individual counters
-+void disable_pmu(void);
-+
-+// Enable the CCNT
-+void enable_ccnt(void);
-+
-+// Disable the CCNT
-+void disable_ccnt(void);
-+
-+// Enable PMN{n}
-+// counter = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
-+void enable_pmn(unsigned int counter);
-+
-+// Enable PMN{n}
-+// counter = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
-+void disable_pmn(unsigned int counter);
-+
-+//
-+// Read counter values
-+//
-+
-+// Returns the value of CCNT
-+unsigned int read_ccnt(void);
-+
-+// Returns the value of PMN{n}
-+// counter = The counter to read (e.g. 0 for PMN0, 1 for PMN1)
-+unsigned int read_pmn(unsigned int counter);
-+
-+//
-+// Overflow and interrupts
-+//
-+
-+// Returns the value of the overflow flags
-+unsigned int read_flags(void);
-+
-+// Writes the overflow flags
-+void write_flags(unsigned int flags);
-+
-+// Enables interrupt generation on overflow of the CCNT
-+void enable_ccnt_irq(void);
-+
-+// Disables interrupt generation on overflow of the CCNT
-+void disable_ccnt_irq(void);
-+
-+// Enables interrupt generation on overflow of PMN{x}
-+// counter = The counter to enable the interrupt for (e.g. 0 for PMN0, 1 for PMN1)
-+void enable_pmn_irq(unsigned int counter);
-+
-+// Disables interrupt generation on overflow of PMN{x}
-+// counter = r0 = The counter to disable the interrupt for (e.g. 0 for PMN0, 1 for
PMN1)
-+void disable_pmn_irq(unsigned int counter);
-+
-+//
-+// Counter reset functions
-+//
-+
-+// Resets the programmable counters
-+void reset_pmn(void);
-+
-+// Resets the CCNT
-+void reset_ccnt(void);
-+
-+//
-+// Software Increment
-+
-+// Writes to software increment register
-+// counter = The counter to increment (e.g. 0 for PMN0, 1 for PMN1)
-+void pmu_software_increment(unsigned int counter);
-+
-+//
-+// User mode access
-+//
-+
-+// Enables User mode access to the PMU (must be called in a priviledged mode)
-+void enable_pmu_user_access(void);
-+
-+// Disables User mode access to the PMU (must be called in a priviledged mode)
-+void disable_pmu_user_access(void);
-+
-+#endif
-+// ------------------------------------------------------------
-+// End of v7_pmu.h
-+// ------------------------------------------------------------
-+
++// ------------------------------------------------------------
++// PMU for Cortex-A/R (v7-A/R)
++// ------------------------------------------------------------
++
++#ifndef _V7_PMU_H
++#define _V7_PMU_H
++
++// Returns the number of progammable counters
++unsigned int getPMN(void);
++
++// Sets the event for a programmable counter to record
++// counter = r0 = Which counter to program (e.g. 0 for PMN0, 1 for PMN1)
++// event = r1 = The event code (from appropiate TRM or ARM Architecture Reference
Manual)
++void pmn_config(unsigned int counter, unsigned int event);
++
++// Enables/disables the divider (1/64) on CCNT
++// divider = r0 = If 0 disable divider, else enable dvider
++void ccnt_divider(int divider);
++
++//
++// Enables and disables
++//
++
++// Global PMU enable
++// On ARM11 this enables the PMU, and the counters start immediately
++// On Cortex this enables the PMU, there are individual enables for the counters
++void enable_pmu(void);
++
++// Global PMU disable
++// On Cortex, this overrides the enable state of the individual counters
++void disable_pmu(void);
++
++// Enable the CCNT
++void enable_ccnt(void);
++
++// Disable the CCNT
++void disable_ccnt(void);
++
++// Enable PMN{n}
++// counter = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
++void enable_pmn(unsigned int counter);
++
++// Enable PMN{n}
++// counter = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
++void disable_pmn(unsigned int counter);
++
++//
++// Read counter values
++//
++
++// Returns the value of CCNT
++unsigned int read_ccnt(void);
++
++// Returns the value of PMN{n}
++// counter = The counter to read (e.g. 0 for PMN0, 1 for PMN1)
++unsigned int read_pmn(unsigned int counter);
++
++//
++// Overflow and interrupts
++//
++
++// Returns the value of the overflow flags
++unsigned int read_flags(void);
++
++// Writes the overflow flags
++void write_flags(unsigned int flags);
++
++// Enables interrupt generation on overflow of the CCNT
++void enable_ccnt_irq(void);
++
++// Disables interrupt generation on overflow of the CCNT
++void disable_ccnt_irq(void);
++
++// Enables interrupt generation on overflow of PMN{x}
++// counter = The counter to enable the interrupt for (e.g. 0 for PMN0, 1 for PMN1)
++void enable_pmn_irq(unsigned int counter);
++
++// Disables interrupt generation on overflow of PMN{x}
++// counter = r0 = The counter to disable the interrupt for (e.g. 0 for PMN0, 1 for
PMN1)
++void disable_pmn_irq(unsigned int counter);
++
++//
++// Counter reset functions
++//
++
++// Resets the programmable counters
++void reset_pmn(void);
++
++// Resets the CCNT
++void reset_ccnt(void);
++
++//
++// Software Increment
++
++// Writes to software increment register
++// counter = The counter to increment (e.g. 0 for PMN0, 1 for PMN1)
++void pmu_software_increment(unsigned int counter);
++
++//
++// User mode access
++//
++
++// Enables User mode access to the PMU (must be called in a priviledged mode)
++void enable_pmu_user_access(void);
++
++// Disables User mode access to the PMU (must be called in a priviledged mode)
++void disable_pmu_user_access(void);
++
++#endif
++// ------------------------------------------------------------
++// End of v7_pmu.h
++// ------------------------------------------------------------
++
--- a/modules/hw/mmal/vout.c
+++ b/modules/hw/mmal/vout.c
@@ -27,21 +27,24 @@
@@ -8170,8 +9314,7 @@
-static int Open(vlc_object_t *);
-static void Close(vlc_object_t *);
-+#define SUBS_MAX 4
-
+-
-vlc_module_begin()
- set_shortname(N_("MMAL vout"))
- set_description(N_("MMAL-based vout plugin for Raspberry Pi"))
@@ -8186,7 +9329,8 @@
- MMAL_NATIVE_INTERLACE_LONGTEXT, false)
- set_callbacks(Open, Close)
-vlc_module_end()
--
++#define SUBS_MAX 4
+
-struct dmx_region_t {
- struct dmx_region_t *next;
- picture_t *picture;
@@ -8213,13 +9357,14 @@
- picture_t **pictures; /* Actual list of alloced pictures passed into picture_pool
*/
- picture_pool_t *picture_pool;
-
++ vcsm_init_type_t init_type;
MMAL_COMPONENT_T *component;
MMAL_PORT_T *input;
MMAL_POOL_T *pool; /* mmal buffer headers, used for pushing pictures to component*/
- struct dmx_region_t *dmx_region;
int i_planes; /* Number of actually used planes, 1 for opaque, 3 for i420 */
- uint32_t buffer_size; /* size of actual mmal buffers */
+- uint32_t buffer_size; /* size of actual mmal buffers */
int buffers_in_transit; /* number of buffers currently pushed to mmal component */
unsigned num_buffers; /* number of buffers allocated at mmal port */
@@ -8236,7 +9381,7 @@
int next_phase_check; /* lowpass for phase check frequency */
int phase_offset; /* currently applied offset to presentation time in ns */
-@@ -136,264 +100,415 @@
+@@ -136,264 +100,451 @@
bool native_interlaced;
bool b_top_field_first; /* cached interlaced settings to detect changes for native
mode */
bool b_progressive;
@@ -8247,7 +9392,11 @@
-static const vlc_fourcc_t subpicture_chromas[] = {
- VLC_CODEC_RGBA,
- 0
+-};
+ vout_subpic_t subs[SUBS_MAX];
++ // Stash for subpics derived from the passed subpicture rather than
++ // included with the main pic
++ MMAL_BUFFER_HEADER_T * subpic_bufs[SUBS_MAX];
+
+ picture_pool_t * pic_pool;
+
@@ -8260,12 +9409,13 @@
+ MMAL_POOL_T * out_pool;
+ bool pending;
+ } isp;
- };
-/* Utility functions */
-static inline uint32_t align(uint32_t x, uint32_t y);
-static int configure_display(vout_display_t *vd, const vout_display_cfg_t *cfg,
- const video_format_t *fmt);
++ MMAL_POOL_T * copy_pool;
++ MMAL_BUFFER_HEADER_T * copy_buf;
-/* VLC vout display callbacks */
-static picture_pool_t *vd_pool(vout_display_t *vd, unsigned count);
@@ -8279,7 +9429,9 @@
-/* MMAL callbacks */
-static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
-static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
-+// ISP setup
++ // Subpic blend if we have to do it here
++ vzc_pool_ctl_t * vzc;
++};
-/* TV service */
-static int query_resolution(vout_display_t *vd, unsigned *width, unsigned *height);
@@ -8287,10 +9439,6 @@
- uint32_t param2);
-static void adjust_refresh_rate(vout_display_t *vd, const video_format_t *fmt);
-static int set_latency_target(vout_display_t *vd, bool enable);
-+static inline bool want_isp(const vout_display_t * const vd)
-+{
-+ return (vd->fmt.i_chroma == VLC_CODEC_MMAL_ZC_SAND10);
-+}
-/* DispManX */
-static void display_subpicture(vout_display_t *vd, subpicture_t *subpicture);
@@ -8303,6 +9451,56 @@
- DISPMANX_UPDATE_HANDLE_T update);
-static void show_background(vout_display_t *vd, bool enable);
-static void maintain_phase_sync(vout_display_t *vd);
++// ISP setup
+
+-static int Open(vlc_object_t *object)
++static inline bool want_isp(const vout_display_t * const vd)
+ {
+- vout_display_t *vd = (vout_display_t *)object;
+- vout_display_sys_t *sys;
+- uint32_t buffer_pitch, buffer_height;
+- vout_display_place_t place;
+- MMAL_DISPLAYREGION_T display_region;
+- MMAL_STATUS_T status;
+- int ret = VLC_SUCCESS;
+- unsigned i;
++ return (vd->fmt.i_chroma == VLC_CODEC_MMAL_ZC_SAND10);
++}
+
+- if (vout_display_IsWindowed(vd))
+- return VLC_EGENERIC;
++static inline bool want_copy(const vout_display_t * const vd)
++{
++ return (vd->fmt.i_chroma == VLC_CODEC_I420);
++}
+
+- sys = calloc(1, sizeof(struct vout_display_sys_t));
+- if (!sys)
+- return VLC_ENOMEM;
+- vd->sys = sys;
++// Do a stride converting copy - if the strides are the same and line_len is
++// close then do a single block copy - we don't expect to have to preserve
++// pixels in the output frame
++static inline void mem_copy_2d(uint8_t * d_ptr, const size_t d_stride, const uint8_t *
s_ptr, const size_t s_stride, size_t lines, const size_t line_len)
++{
++ if (s_stride == d_stride && s_stride < line_len + 32)
++ {
++ memcpy(d_ptr, s_ptr, s_stride * lines);
++ }
++ else
++ {
++ while (lines-- != 0) {
++ memcpy(d_ptr, s_ptr, line_len);
++ d_ptr += d_stride;
++ s_ptr += s_stride;
++ }
++ }
++}
+
+- sys->layer = var_InheritInteger(vd, MMAL_LAYER_NAME);
+- bcm_host_init();
+
+- sys->opaque = vd->fmt.i_chroma == VLC_CODEC_MMAL_OPAQUE;
+static MMAL_FOURCC_T vout_vlc_to_mmal_pic_fourcc(const unsigned int fcc)
+{
+ switch (fcc){
@@ -8312,23 +9510,22 @@
+ return MMAL_ENCODING_YUVUV128;
+ case VLC_CODEC_MMAL_ZC_SAND10:
+ return MMAL_ENCODING_YUVUV64_10; // It will be after we've converted it...
++ case VLC_CODEC_I420:
++ return MMAL_ENCODING_I420;
+ default:
+ break;
+ }
+ return 0;
+}
--static int Open(vlc_object_t *object)
+- status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER,
&sys->component);
+- if (status != MMAL_SUCCESS) {
+- msg_Err(vd, "Failed to create MMAL component %s (status=%"PRIx32"
%s)",
+- MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, status,
mmal_status_to_string(status));
+- ret = VLC_EGENERIC;
+- goto out;
+static void display_set_format(const vout_display_t * const vd, MMAL_ES_FORMAT_T *const
es_fmt, const bool is_intermediate)
- {
-- vout_display_t *vd = (vout_display_t *)object;
-- vout_display_sys_t *sys;
-- uint32_t buffer_pitch, buffer_height;
-- vout_display_place_t place;
-- MMAL_DISPLAYREGION_T display_region;
-- MMAL_STATUS_T status;
-- int ret = VLC_SUCCESS;
-- unsigned i;
++{
+ const unsigned int w = is_intermediate ? vd->fmt.i_visible_width :
vd->fmt.i_width ;
+ const unsigned int h = is_intermediate ? vd->fmt.i_visible_height :
vd->fmt.i_height;
+ MMAL_VIDEO_FORMAT_T * const v_fmt = &es_fmt->es->video;
@@ -8349,14 +9546,19 @@
+ } else {
+ v_fmt->par.num = vd->fmt.i_sar_num;
+ v_fmt->par.den = vd->fmt.i_sar_den;
-+ }
+ }
+ v_fmt->frame_rate.num = vd->fmt.i_frame_rate;
+ v_fmt->frame_rate.den = vd->fmt.i_frame_rate_base;
+ v_fmt->color_space = vlc_to_mmal_color_space(vd->fmt.space);
+}
-- if (vout_display_IsWindowed(vd))
-- return VLC_EGENERIC;
+- sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)vd;
+- status = mmal_port_enable(sys->component->control, control_port_cb);
+- if (status != MMAL_SUCCESS) {
+- msg_Err(vd, "Failed to enable control port %s (status=%"PRIx32"
%s)",
+- sys->component->control->name, status,
mmal_status_to_string(status));
+- ret = VLC_EGENERIC;
+- goto out;
+static void display_src_rect(const vout_display_t * const vd, MMAL_RECT_T *const rect)
+{
+ const bool wants_isp = want_isp(vd);
@@ -8365,11 +9567,7 @@
+ rect->width = vd->fmt.i_visible_width;
+ rect->height = vd->fmt.i_visible_height;
+}
-
-- sys = calloc(1, sizeof(struct vout_display_sys_t));
-- if (!sys)
-- return VLC_ENOMEM;
-- vd->sys = sys;
++
+static void isp_input_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
+{
+#if TRACE_ALL
@@ -8380,36 +9578,19 @@
+#else
+ VLC_UNUSED(port);
+#endif
-
-- sys->layer = var_InheritInteger(vd, MMAL_LAYER_NAME);
-- bcm_host_init();
++
+ mmal_buffer_header_release(buf);
-
-- sys->opaque = vd->fmt.i_chroma == VLC_CODEC_MMAL_OPAQUE;
++
+#if TRACE_ALL
+ msg_Dbg(vd, ">>> %s", __func__);
+#endif
+}
-
-- status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER,
&sys->component);
-- if (status != MMAL_SUCCESS) {
-- msg_Err(vd, "Failed to create MMAL component %s (status=%"PRIx32"
%s)",
-- MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, status,
mmal_status_to_string(status));
-- ret = VLC_EGENERIC;
-- goto out;
-- }
++
+static void isp_control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+ vout_display_t *vd = (vout_display_t *)port->userdata;
+ MMAL_STATUS_T status;
-
-- sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)vd;
-- status = mmal_port_enable(sys->component->control, control_port_cb);
-- if (status != MMAL_SUCCESS) {
-- msg_Err(vd, "Failed to enable control port %s (status=%"PRIx32"
%s)",
-- sys->component->control->name, status,
mmal_status_to_string(status));
-- ret = VLC_EGENERIC;
-- goto out;
++
+ if (buffer->cmd == MMAL_EVENT_ERROR) {
+ status = *(uint32_t *)buffer->data;
+ msg_Err(vd, "MMAL error %"PRIx32" \"%s\"", status,
mmal_status_to_string(status));
@@ -8846,7 +10027,7 @@
if (fmt) {
sys->input->format->es->video.par.num = fmt->i_sar_num;
-@@ -412,22 +527,29 @@
+@@ -412,22 +563,29 @@
if (!cfg)
cfg = vd->cfg;
@@ -8882,7 +10063,7 @@
status = mmal_port_parameter_set(sys->input, &display_region.hdr);
if (status != MMAL_SUCCESS) {
msg_Err(vd, "Failed to set display region (status=%"PRIx32"
%s)",
-@@ -435,7 +557,6 @@
+@@ -435,7 +593,6 @@
return -EINVAL;
}
@@ -8890,7 +10071,7 @@
sys->adjust_refresh_rate = var_InheritBool(vd, MMAL_ADJUST_REFRESHRATE_NAME);
sys->native_interlaced = var_InheritBool(vd, MMAL_NATIVE_INTERLACED);
if (sys->adjust_refresh_rate) {
-@@ -446,191 +567,130 @@
+@@ -446,192 +603,153 @@
return 0;
}
@@ -8970,8 +10151,8 @@
- msg_Err(vd, "Failed to enable component %s (status=%"PRIx32"
%s)",
- sys->component->name, status,
mmal_status_to_string(status));
- goto out;
-+ // Not expecting subpictures in the current setup
-+ // Subpics should be attached to the main pic
++ // If we had subpics then we have attached them to the main pic in prepare
++ // so all we have to do here is delete the refs
+ if (subpicture != NULL) {
+ subpicture_Delete(subpicture);
}
@@ -9005,16 +10186,16 @@
+ }
+ // Stuff into input
+ // We assume the BH is already set up with values reflecting pic date etc.
-+ if (sys->isp.pending) {
-+ MMAL_BUFFER_HEADER_T *const buf = mmal_queue_wait(sys->isp.out_q);
-+ sys->isp.pending = false;
++ if (sys->copy_buf != NULL) {
++ MMAL_BUFFER_HEADER_T *const buf = sys->copy_buf;
++ sys->copy_buf = NULL;
+#if TRACE_ALL
-+ msg_Dbg(vd, "--- %s: ISP stuff", __func__);
++ msg_Dbg(vd, "--- %s: Copy stuff", __func__);
+#endif
+ if (mmal_port_send_buffer(sys->input, buf) != MMAL_SUCCESS)
+ {
+ mmal_buffer_header_release(buf);
-+ msg_Err(vd, "Send ISP buffer to render input failed");
++ msg_Err(vd, "Send copy buffer to render input failed");
+ goto fail;
+ }
}
@@ -9031,22 +10212,23 @@
- msg_Err(vd, "Failed to create picture");
- free(picture_res.p_sys);
- goto out;
-+ else
-+ {
-+ MMAL_BUFFER_HEADER_T * const pic_buf = pic_mmal_buffer(p_pic);
++ else if (sys->isp.pending) {
++ MMAL_BUFFER_HEADER_T *const buf = mmal_queue_wait(sys->isp.out_q);
++ sys->isp.pending = false;
+#if TRACE_ALL
-+ msg_Dbg(vd, "--- %s: Buf stuff", __func__);
++ msg_Dbg(vd, "--- %s: ISP stuff", __func__);
+#endif
-+ if ((err = port_send_replicated(sys->input, sys->pool, pic_buf,
pic_buf->pts)) != MMAL_SUCCESS)
++ if (mmal_port_send_buffer(sys->input, buf) != MMAL_SUCCESS)
+ {
-+ msg_Err(vd, "Send buffer to input failed");
++ mmal_buffer_header_release(buf);
++ msg_Err(vd, "Send ISP buffer to render input failed");
+ goto fail;
}
-
- sys->pictures[i]->i_planes = sys->i_planes;
- memcpy(sys->pictures[i]->p, sys->planes, sys->i_planes *
sizeof(plane_t));
}
-
+-
- memset(&picture_pool_cfg, 0, sizeof(picture_pool_configuration_t));
- picture_pool_cfg.picture_count = sys->num_buffers;
- picture_pool_cfg.picture = sys->pictures;
@@ -9056,12 +10238,18 @@
- if (!sys->picture_pool) {
- msg_Err(vd, "Failed to create picture pool");
- goto out;
-+ if (p_pic->context == NULL) {
-+ msg_Dbg(vd, "%s: No context", __func__);
- }
+ else
+ {
-+ unsigned int sub_no = 0;
++ MMAL_BUFFER_HEADER_T * const pic_buf = pic_mmal_buffer(p_pic);
++#if TRACE_ALL
++ msg_Dbg(vd, "--- %s: Buf stuff", __func__);
++#endif
++ if ((err = port_send_replicated(sys->input, sys->pool, pic_buf,
pic_buf->pts)) != MMAL_SUCCESS)
++ {
++ msg_Err(vd, "Send buffer to input failed");
++ goto fail;
++ }
+ }
-out:
- return sys->picture_pool;
@@ -9112,9 +10300,20 @@
- if (status != MMAL_SUCCESS) {
- msg_Err(vd, "Failed to send buffer to input port. Frame
dropped");
- picture_Release(picture);
++ {
++ unsigned int sub_no = 0;
++ MMAL_BUFFER_HEADER_T **psub_bufs2 = sys->subpic_bufs;
++ const bool is_mmal_pic = hw_mmal_pic_is_mmal(p_pic);
++
+ for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
+ int rv;
-+ if ((rv = hw_mmal_subpic_update(VLC_OBJECT(vd), p_pic, sub_no,
&sys->subs[sub_no].sub,
++ MMAL_BUFFER_HEADER_T * const sub_buf = !is_mmal_pic ? NULL :
++ hw_mmal_pic_sub_buf_get(p_pic, sub_no);
++
++ if ((rv = hw_mmal_subpic_update(VLC_OBJECT(vd),
++ sub_buf != NULL ? sub_buf : *psub_bufs2++,
++ &sys->subs[sub_no].sub,
++ &p_pic->format,
+ &(MMAL_RECT_T){.width =
sys->display_width, .height = sys->display_height},
+ p_pic->date)) == 0)
+ break;
@@ -9128,7 +10327,12 @@
}
- display_subpicture(vd, subpicture);
--
++fail:
++ for (unsigned int i = 0; i != SUBS_MAX && sys->subpic_bufs[i] != NULL;
++i) {
++ mmal_buffer_header_release(sys->subpic_bufs[i]);
++ sys->subpic_bufs[i] = NULL;
++ }
+
- if (subpicture)
- subpicture_Delete(subpicture);
+ picture_Release(p_pic);
@@ -9136,15 +10340,13 @@
if (sys->next_phase_check == 0 && sys->adjust_refresh_rate)
maintain_phase_sync(vd);
sys->next_phase_check = (sys->next_phase_check + 1) % PHASE_CHECK_INTERVAL;
-
+-
- if (sys->opaque) {
- vlc_mutex_lock(&sys->buffer_mutex);
- while (atomic_load(&sys->buffers_in_transit) >=
MAX_BUFFERS_IN_TRANSIT)
- vlc_cond_wait(&sys->buffer_cond, &sys->buffer_mutex);
- vlc_mutex_unlock(&sys->buffer_mutex);
- }
-+fail:
-+ /* NOP */;
}
static int vd_control(vout_display_t *vd, int query, va_list args)
@@ -9167,12 +10369,15 @@
- if (configure_display(vd, &cfg, NULL) >= 0)
- ret = VLC_SUCCESS;
- }
++ {
+ // Ignore this - we just use full screen anyway
+ ret = VLC_SUCCESS;
break;
++ }
case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
-@@ -640,10 +700,37 @@
+ case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
+@@ -640,11 +758,38 @@
break;
case VOUT_DISPLAY_RESET_PICTURES:
@@ -9186,8 +10391,8 @@
case VOUT_DISPLAY_CHANGE_ZOOM:
msg_Warn(vd, "Unsupported control query %d", query);
+ ret = VLC_SUCCESS;
-+ break;
-+
+ break;
+
+ case VOUT_DISPLAY_CHANGE_MMAL_HIDE:
+ {
+ MMAL_STATUS_T err;
@@ -9206,12 +10411,13 @@
+ }
+ sys->force_config = true;
+ ret = VLC_SUCCESS;
- break;
++ break;
+ }
-
++
default:
msg_Warn(vd, "Unknown control query %d", query);
-@@ -661,13 +748,11 @@
+ break;
+@@ -661,13 +806,11 @@
vlc_mutex_lock(&sys->manage_mutex);
if (sys->need_configure_display) {
@@ -9227,11 +10433,69 @@
}
sys->need_configure_display = false;
-@@ -676,56 +761,76 @@
+@@ -676,56 +819,164 @@
vlc_mutex_unlock(&sys->manage_mutex);
}
-static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
++
++static int attach_subpics(vout_display_t * const vd, vout_display_sys_t * const sys,
++ subpicture_t * const subpicture)
+ {
+- vout_display_t *vd = (vout_display_t *)port->userdata;
+- MMAL_STATUS_T status;
++ unsigned int n = 0;
+
+- if (buffer->cmd == MMAL_EVENT_ERROR) {
+- status = *(uint32_t *)buffer->data;
+- msg_Err(vd, "MMAL error %"PRIx32" \"%s\"", status,
mmal_status_to_string(status));
++ if (sys->vzc == NULL) {
++ if ((sys->vzc = hw_mmal_vzc_pool_new()) == NULL)
++ {
++ msg_Err(vd, "Failed to allocate VZC");
++ return VLC_ENOMEM;
++ }
+ }
+
+- mmal_buffer_header_release(buffer);
++ // Attempt to import the subpics
++ for (subpicture_t * spic = subpicture; spic != NULL; spic = spic->p_next)
++ {
++ for (subpicture_region_t *sreg = spic->p_region; sreg != NULL; sreg =
sreg->p_next) {
++ picture_t *const src = sreg->p_picture;
++
++#if 0
++ char dbuf0[5];
++ msg_Dbg(vd, " [%p:%p] Pos=%d,%d src=%dx%d/%dx%d, vd=%dx%d/%dx%d,
Alpha=%d, Fmt=%s", src, src->p[0].p_pixels,
++ sreg->i_x, sreg->i_y,
++ src->format.i_visible_width, src->format.i_visible_height,
++ src->format.i_width, src->format.i_height,
++ vd->fmt.i_visible_width, vd->fmt.i_visible_height,
++ vd->fmt.i_width, vd->fmt.i_height,
++ sreg->i_alpha,
++ str_fourcc(dbuf0, src->format.i_chroma));
++#endif
++
++ if ((sys->subpic_bufs[n] = hw_mmal_vzc_buf_from_pic(sys->vzc,
++ src,
++ (MMAL_RECT_T){.width = vd->cfg->display.width,
.height=vd->cfg->display.height},
++ sreg->i_x, sreg->i_y,
++ sreg->i_alpha,
++ n == 0)) == NULL)
++ {
++ msg_Err(vd, "Failed to allocate vzc buffer for subpic");
++ return VLC_ENOMEM;
++ }
++
++ if (++n == SUBS_MAX)
++ return VLC_SUCCESS;
++ }
++ }
++ return VLC_SUCCESS;
+ }
+
+-static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
++
+static void vd_prepare(vout_display_t *vd, picture_t *p_pic,
+#if VLC_VER_3
+ subpicture_t *subpicture
@@ -9241,24 +10505,55 @@
+ )
{
- vout_display_t *vd = (vout_display_t *)port->userdata;
-- MMAL_STATUS_T status;
+ MMAL_STATUS_T err;
+ vout_display_sys_t * const sys = vd->sys;
-
-- if (buffer->cmd == MMAL_EVENT_ERROR) {
-- status = *(uint32_t *)buffer->data;
-- msg_Err(vd, "MMAL error %"PRIx32" \"%s\"", status,
mmal_status_to_string(status));
-+ VLC_UNUSED(subpicture);
-+// VLC_UNUSED(date);
+
+ vd_manage(vd);
+
++ // Subpics can either turn up attached to the main pic or in the
++ // subpic list here - if they turn up here then process inrto temp
++ // buffers
++ if (subpicture != NULL) {
++ attach_subpics(vd, sys, subpicture);
++ }
++
++ // *****
++ if (want_copy(vd)) {
++ if (sys->copy_buf != NULL) {
++ msg_Err(vd, "Copy buf not NULL");
++ mmal_buffer_header_release(sys->copy_buf);
++ sys->copy_buf = NULL;
++ }
++
++ MMAL_BUFFER_HEADER_T * const buf =
mmal_queue_wait(sys->copy_pool->queue);
++ // Copy 2d
++ unsigned int y_size = sys->input->format->es->video.width *
sys->input->format->es->video.height;
++
++ buf->flags = MMAL_BUFFER_HEADER_FLAG_FRAME_END;
++ buf->length = sys->input->buffer_size;
++
++ mem_copy_2d(buf->data, sys->input->format->es->video.width,
++ p_pic->p[0].p_pixels, p_pic->p[0].i_pitch,
++ sys->input->format->es->video.crop.height,
++ sys->input->format->es->video.crop.width);
++
++ mem_copy_2d(buf->data + y_size,
sys->input->format->es->video.width / 2,
++ p_pic->p[1].p_pixels, p_pic->p[1].i_pitch,
++ sys->input->format->es->video.crop.height / 2,
++ sys->input->format->es->video.crop.width / 2);
++
++ mem_copy_2d(buf->data + y_size + y_size / 4,
sys->input->format->es->video.width / 2,
++ p_pic->p[2].p_pixels, p_pic->p[2].i_pitch,
++ sys->input->format->es->video.crop.height / 2,
++ sys->input->format->es->video.crop.width / 2);
++
++ sys->copy_buf = buf;
++ }
++
+ if (isp_check(vd, sys) != MMAL_SUCCESS) {
+ return;
- }
-
-- mmal_buffer_header_release(buffer);
--}
++ }
++
+ if (want_isp(vd))
+ {
+ struct vout_isp_conf_s * const isp = &sys->isp;
@@ -9267,10 +10562,7 @@
+ // This should be empty - make it so if it isn't
+ isp_empty_out_q(isp);
+ isp->pending = false;
-
--static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
--{
-- vout_display_t *vd = (vout_display_t *)port->userdata;
++
+ // Stuff output
+ if (isp_prepare(vd, isp) != MMAL_SUCCESS)
+ return;
@@ -9340,7 +10632,7 @@
}
static void tvservice_cb(void *callback_data, uint32_t reason, uint32_t param1, uint32_t
param2)
-@@ -828,148 +933,12 @@
+@@ -828,148 +1079,12 @@
}
}
@@ -9490,7 +10782,7 @@
((double)vd->sys->i_frame_rate /
vd->sys->i_frame_rate_base);
vout_display_sys_t *sys = vd->sys;
-@@ -1012,32 +981,260 @@
+@@ -1012,32 +1127,286 @@
}
}
@@ -9534,28 +10826,36 @@
+
+ vc_tv_unregister_callback_full(tvservice_cb, vd);
+
-+ if (sys->component && sys->component->control->is_enabled)
-+ mmal_port_disable(sys->component->control);
-+
-+ {
-+ unsigned int i;
-+ for (i = 0; i != SUBS_MAX; ++i) {
-+ vout_subpic_t * const sub = sys->subs + i;
-+ if (sub->component != NULL) {
-+ hw_mmal_subpic_close(VLC_OBJECT(vd), &sub->sub);
-+ if (sub->component->control->is_enabled)
-+ mmal_port_disable(sub->component->control);
-+ if (sub->component->is_enabled)
-+ mmal_component_disable(sub->component);
-+ mmal_component_release(sub->component);
-+ sub->component = NULL;
-+ }
++ // Shouldn't be anything here - but just in case
++ for (unsigned int i = 0; i != SUBS_MAX; ++i)
++ if (sys->subpic_bufs[i] != NULL)
++ mmal_buffer_header_release(sys->subpic_bufs[i]);
++
++ for (unsigned int i = 0; i != SUBS_MAX; ++i) {
++ vout_subpic_t * const sub = sys->subs + i;
++ if (sub->component != NULL) {
++ hw_mmal_subpic_close(VLC_OBJECT(vd), &sub->sub);
++ if (sub->component->control->is_enabled)
++ mmal_port_disable(sub->component->control);
++ if (sub->component->is_enabled)
++ mmal_component_disable(sub->component);
++ mmal_component_release(sub->component);
++ sub->component = NULL;
+ }
}
+
+ if (sys->input && sys->input->is_enabled)
+ mmal_port_disable(sys->input);
+
++ if (sys->component && sys->component->control->is_enabled)
++ mmal_port_disable(sys->component->control);
++
++ if (sys->copy_buf != NULL)
++ mmal_buffer_header_release(sys->copy_buf);
++
++ if (sys->input != NULL && sys->copy_pool != NULL)
++ mmal_port_pool_destroy(sys->input, sys->copy_pool);
++
+ if (sys->component && sys->component->is_enabled)
+ mmal_component_disable(sys->component);
+
@@ -9567,6 +10867,8 @@
+
+ isp_close(vd, sys);
+
++ hw_mmal_vzc_pool_release(sys->vzc);
++
+ vlc_mutex_destroy(&sys->manage_mutex);
+
+ if (sys->native_interlaced) {
@@ -9575,14 +10877,14 @@
+ msg_Warn(vd, "Could not reset hvs field mode");
+ }
+
-+ free(sys);
++ cma_vcsm_exit(sys->init_type);;
+
-+ bcm_host_deinit();
++ free(sys);
+
+#if TRACE_ALL
+ msg_Dbg(vd, ">>> %s", __func__);
+#endif
- }
++}
+
+static int OpenMmalVout(vlc_object_t *object)
+{
@@ -9600,7 +10902,8 @@
+ if (enc_in == 0)
+ {
+#if TRACE_ALL
-+ msg_Dbg(vd, ">>> %s: Format not MMAL", __func__);
++ char dbuf0[5];
++ msg_Dbg(vd, ">>> %s: Format %s not MMAL", __func__,
str_fourcc(dbuf0, vd->fmt.i_chroma));
+#endif
+ return VLC_EGENERIC;
+ }
@@ -9610,7 +10913,11 @@
+ return VLC_ENOMEM;
+ vd->sys = sys;
+
-+ bcm_host_init();
++ if ((sys->init_type = cma_vcsm_init()) == VCSM_INIT_NONE)
++ {
++ msg_Err(vd, "VCSM init fail");
++ goto fail;
++ }
+
+ sys->layer = var_InheritInteger(vd, MMAL_LAYER_NAME);
+
@@ -9635,7 +10942,6 @@
+ sys->input->format->encoding = enc_in;
+ sys->input->format->encoding_variant = 0;
+ sys->i_planes = 1;
-+ sys->buffer_size = sys->input->buffer_size_recommended;
+
+ display_set_format(vd, sys->input->format, want_isp(vd));
+
@@ -9652,8 +10958,20 @@
+ sys->input->name, status, mmal_status_to_string(status));
+ goto fail;
+ }
++
+ sys->input->buffer_size = sys->input->buffer_size_recommended;
-+ sys->input->buffer_num = 30;
++
++ if (!want_copy(vd)) {
++ sys->input->buffer_num = 30;
++ }
++ else {
++ sys->input->buffer_num = 2;
++ if ((sys->copy_pool = mmal_port_pool_create(sys->input, 2,
sys->input->buffer_size)) == NULL)
++ {
++ msg_Err(vd, "Cannot create copy pool");
++ goto fail;
++ }
++ }
+
+ vout_display_PlacePicture(&place, &vd->source, vd->cfg, false);
+ display_region.hdr.id = MMAL_PARAMETER_DISPLAYREGION;
@@ -9729,7 +11047,7 @@
+ .has_double_click = false,
+ .needs_hide_mouse = false,
+ .has_pictures_invalid = true,
-+ .subpicture_chromas = NULL
++ .subpicture_chromas = hw_mmal_vzc_subpicture_chromas
+ };
+
+ vd->pool = vd_pool;
@@ -9754,7 +11072,7 @@
+ msg_Dbg(vd, ">>> %s: rv=%d", __func__, ret);
+
+ return ret == VLC_SUCCESS ? VLC_EGENERIC : ret;
-+}
+ }
+
+vlc_module_begin()
+
@@ -9762,7 +11080,7 @@
+
+ set_shortname(N_("MMAL vout"))
+ set_description(N_("MMAL-based vout plugin for Raspberry Pi"))
-+ set_capability("vout display", 0)
++ set_capability("vout display", 16) // 1 point better than ASCII art
+ add_shortcut("mmal_vout")
+ set_category( CAT_VIDEO )
+ set_subcategory( SUBCAT_VIDEO_VOUT )
@@ -9779,7 +11097,7 @@
+
--- /dev/null
+++ b/modules/hw/mmal/xsplitter.c
-@@ -0,0 +1,403 @@
+@@ -0,0 +1,437 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
@@ -9808,21 +11126,9 @@
+ vout_display_t * mmal_vout;
+ vout_display_t * x_vout;
+ uint32_t changed;
++ vlc_fourcc_t subpicture_chromas[16];
+} mmal_x11_sys_t;
+
-+static const char * str_fourcc(char * buf, unsigned int fcc)
-+{
-+ if (fcc == 0)
-+ return "----";
-+ buf[0] = (fcc >> 0) & 0xff;
-+ buf[1] = (fcc >> 8) & 0xff;
-+ buf[2] = (fcc >> 16) & 0xff;
-+ buf[3] = (fcc >> 24) & 0xff;
-+ buf[4] = 0;
-+ return buf;
-+}
-+
-+
+static void unload_display_module(vout_display_t * const x_vout)
+{
+ if (x_vout != NULL) {
@@ -9858,6 +11164,12 @@
+#if TRACE_ALL
+ msg_Dbg(vd, "<<< %s (cmd=%d)", __func__, cmd);
+#endif
++
++ // Do not fall into the display assert if Invalid not supported
++ if (cmd == VOUT_DISPLAY_EVENT_PICTURES_INVALID &&
++ !vd->info.has_pictures_invalid)
++ return;
++
+ vd->owner.event(vd, cmd, args);
+}
+
@@ -9985,7 +11297,10 @@
+ is_mmal_pic, sys->use_mmal);
+#endif
+
-+ if (sys->use_mmal != is_mmal_pic) {
++ if (x_vd->fmt.i_chroma != pic->format.i_chroma ||
++ x_vd->fmt.i_width != pic->format.i_width ||
++ x_vd->fmt.i_height != pic->format.i_height)
++ {
+ msg_Dbg(vd, "%s: Picture dropped", __func__);
+ picture_Release(pic);
+ if (sub != NULL)
@@ -10011,7 +11326,7 @@
+
+static bool want_mmal_vout(vout_display_t * vd, const mmal_x11_sys_t * const sys)
+{
-+ return sys->mmal_vout != NULL && var_InheritBool(vd,
"fullscreen");
++ return sys->mmal_vout != NULL && (sys->x_vout == NULL ||
var_InheritBool(vd, "fullscreen"));
+}
+
+/* Control on the module (mandatory) */
@@ -10030,19 +11345,20 @@
+ switch (ctl) {
+ case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
+ {
-+ const vout_display_cfg_t * cfg = va_arg(va, const vout_display_cfg_t *);
++ const vout_display_cfg_t * const cfg = va_arg(va, const vout_display_cfg_t
*);
+ const bool want_mmal = want_mmal_vout(vd, sys);
-+ vout_display_t *new_vd = want_mmal ? sys->mmal_vout : sys->x_vout;
++ const bool swap_vout = (sys->use_mmal != want_mmal);
++ vout_display_t * const new_vd = want_mmal ? sys->mmal_vout :
sys->x_vout;
+
+ msg_Dbg(vd, "Change size: %d, %d: mmal_vout=%p, want_mmal=%d,
fs=%d",
+ cfg->display.width, cfg->display.height, sys->mmal_vout,
want_mmal,
+ var_InheritBool(vd, "fullscreen"));
+
-+ if (sys->use_mmal != want_mmal) {
++ if (swap_vout) {
+ if (sys->use_mmal) {
+ vout_display_Control(x_vd, VOUT_DISPLAY_CHANGE_MMAL_HIDE);
+ }
-+ vout_display_SendEventPicturesInvalid(x_vd);
++ vout_display_SendEventPicturesInvalid(vd);
+ }
+
+ rv = vout_display_Control(new_vd, ctl, cfg);
@@ -10053,7 +11369,7 @@
+ }
+
+ // Repeat any control calls that we sent to the previous vd
-+ if (sys->changed != 0) {
++ if (swap_vout && sys->changed != 0) {
+ const uint32_t changed = sys->changed;
+ sys->changed = 0;
+ if ((changed & (1 << VOUT_DISPLAY_CHANGE_DISPLAY_FILLED)) !=
0)
@@ -10074,20 +11390,24 @@
+ }
+
+ case VOUT_DISPLAY_RESET_PICTURES:
-+ msg_Dbg(vd, "Reset pictures");
-+// rv = x_vd->control(x_vd, ctl, va);
-+ rv = sys->x_vout->control(sys->x_vout, ctl, va);
-+ if (sys->mmal_vout)
-+ rv = sys->mmal_vout->control(sys->mmal_vout, ctl, va);
+ msg_Dbg(vd, "<<< %s: Pic reset: fmt: %dx%d<-%dx%d, source:
%dx%d/%dx%d", __func__,
+ vd->fmt.i_width, vd->fmt.i_height, x_vd->fmt.i_width,
x_vd->fmt.i_height,
+ vd->source.i_width, vd->source.i_height,
x_vd->source.i_width, x_vd->source.i_height);
-+ vd->fmt = x_vd->fmt;
++ // If the display doesn't have has_pictures_invalid then it doesn't
++ // expect RESET_PICTURES
++ if (sys->x_vout->info.has_pictures_invalid) {
++ rv = sys->x_vout->control(sys->x_vout, ctl, va);
++ }
++ if (sys->mmal_vout &&
sys->mmal_vout->info.has_pictures_invalid) {
++ rv = sys->mmal_vout->control(sys->mmal_vout, ctl, va);
++ }
++ vd->fmt = x_vd->fmt;
+ break;
+
+ case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
+ case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
+ x_vd->source = vd->source;
++ /* FALLTHRU */
+ default:
+ rv = x_vd->control(x_vd, ctl, va);
+// vd->fmt = x_vd->fmt;
@@ -10133,14 +11453,18 @@
+ .subpicture_chromas = NULL
+ };
+
-+ if ((sys->x_vout = load_display_module(vd, "vout display",
"xcb_x11")) == NULL)
-+ goto fail;
++ if ((sys->x_vout = load_display_module(vd, "vout display",
"opengles2")) != NULL)
++ msg_Dbg(vd, "Opengles2 output found");
++ else if ((sys->x_vout = load_display_module(vd, "vout display",
"xcb_x11")) != NULL)
++ msg_Dbg(vd, "X11 XCB output found");
+
-+ if ((sys->mmal_vout = load_display_module(vd, "vout display",
"mmal_vout")) == NULL)
-+ {
-+ // Winge but do no more than that - route everything to X
++ if ((sys->mmal_vout = load_display_module(vd, "vout display",
"mmal_vout")) != NULL)
++ msg_Dbg(vd, "MMAL output found");
++
++ if (sys->mmal_vout == NULL && sys->x_vout == NULL) {
+ char dbuf0[5], dbuf1[5];
-+ msg_Info(vd, "Not a valid format for mmal vout (%s/%s)",
str_fourcc(dbuf0, vd->fmt.i_chroma), str_fourcc(dbuf1, vd->source.i_chroma));
++ msg_Info(vd, "No valid output found for vout (%s/%s)",
str_fourcc(dbuf0, vd->fmt.i_chroma), str_fourcc(dbuf1, vd->source.i_chroma));
++ goto fail;
+ }
+
+ vd->pool = mmal_x11_pool;
@@ -10160,7 +11484,35 @@
+ sys->use_mmal = false;
+ }
+
-+ vd->info = sys->cur_vout->info;
++ if (sys->mmal_vout == NULL || sys->x_vout == NULL) {
++ vd->info = sys->cur_vout->info;
++ vd->info.has_pictures_invalid = true; // Should make this unwanted
++ }
++ else {
++ // We have both - construct a combination
++ vd->info = (vout_display_info_t){
++ .is_slow = false,
++ .has_double_click = sys->mmal_vout->info.has_double_click ||
sys->x_vout->info.has_double_click,
++ .needs_hide_mouse = sys->mmal_vout->info.needs_hide_mouse ||
sys->x_vout->info.needs_hide_mouse,
++ .has_pictures_invalid = true,
++ };
++ // Construct intersection of subpicture chromas
++ // sys calloced so no need to add the terminating zero
++ if (sys->mmal_vout->info.subpicture_chromas != NULL &&
sys->x_vout->info.subpicture_chromas != NULL) {
++ unsigned int n = 0;
++ // N^2 - fix if we ever care
++ for (const vlc_fourcc_t * p1 =
sys->mmal_vout->info.subpicture_chromas; *p1 != 0 && n != 15; ++p1) {
++ for (const vlc_fourcc_t * p2 =
sys->x_vout->info.subpicture_chromas; *p2 != 0; ++p2) {
++ if (*p1 == *p2) {
++ sys->subpicture_chromas[n++] = *p1;
++ break;
++ }
++ }
++ }
++ if (n != 0)
++ vd->info.subpicture_chromas = sys->subpicture_chromas;
++ }
++ }
+ vd->fmt = sys->cur_vout->fmt;
+
+ return VLC_SUCCESS;
@@ -10176,21 +11528,53 @@
+vlc_module_begin()
+ set_shortname(N_("MMAL x11 splitter"))
+ set_description(N_("MMAL x11 splitter for Raspberry Pi"))
-+ set_capability("vout display", 900)
++ set_capability("vout display", 300) // Between GLES & GL
+ add_shortcut("mmal_x11")
+ set_category( CAT_VIDEO )
+ set_subcategory( SUBCAT_VIDEO_VOUT )
+ set_callbacks(OpenMmalX11, CloseMmalX11)
+vlc_module_end()
+
+--- a/modules/video_output/opengl/egl.c
++++ b/modules/video_output/opengl/egl.c
+@@ -43,6 +43,8 @@
+ # include "../android/utils.h"
+ #endif
+
++#define REQUIRE_DMA_BUF_IMPORT 1
++
+ typedef struct vlc_gl_sys_t
+ {
+ EGLDisplay display;
+@@ -354,6 +356,14 @@
+ goto error;
+ }
+
++#if REQUIRE_DMA_BUF_IMPORT
++ if (!CheckToken(ext, "EGL_EXT_image_dma_buf_import"))
++ {
++ msg_Dbg(obj, "No dma_buf_import - fall back to X");
++ goto error;
++ }
++#endif
++
+ const EGLint conf_attr[] = {
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 5,
--- a/src/misc/fourcc.c
+++ b/src/misc/fourcc.c
-@@ -756,6 +756,8 @@
+@@ -755,8 +755,12 @@
+ { { VLC_CODEC_VDPAU_VIDEO_420, VLC_CODEC_VDPAU_VIDEO_422,
VLC_CODEC_VDPAU_VIDEO_444, VLC_CODEC_VDPAU_OUTPUT },
FAKE_FMT() },
- { { VLC_CODEC_ANDROID_OPAQUE, VLC_CODEC_MMAL_OPAQUE,
-+ VLC_CODEC_MMAL_ZC_SAND8, VLC_CODEC_MMAL_ZC_SAND10,
-+ VLC_CODEC_MMAL_ZC_I420,
- VLC_CODEC_D3D9_OPAQUE, VLC_CODEC_D3D11_OPAQUE },
+- { { VLC_CODEC_ANDROID_OPAQUE, VLC_CODEC_MMAL_OPAQUE,
+- VLC_CODEC_D3D9_OPAQUE, VLC_CODEC_D3D11_OPAQUE },
++ { { VLC_CODEC_ANDROID_OPAQUE, VLC_CODEC_MMAL_OPAQUE },
++ FAKE_FMT() },
++ { { VLC_CODEC_MMAL_ZC_I420, VLC_CODEC_MMAL_ZC_SAND8,
++ VLC_CODEC_MMAL_ZC_SAND10, VLC_CODEC_MMAL_ZC_RGB32 },
++ FAKE_FMT() },
++ { { VLC_CODEC_D3D9_OPAQUE, VLC_CODEC_D3D11_OPAQUE },
FAKE_FMT() },
{ { VLC_CODEC_D3D11_OPAQUE_10B, VLC_CODEC_D3D9_OPAQUE_10B },
+ FAKE_FMT() },