[vlc] Update mmal patch
by Nicolas Chauvet
commit efb3858b10ebd84c4cebbe0cd643b7a42fe95e64
Author: Nicolas Chauvet <kwizart(a)gmail.com>
Date: Fri Mar 29 09:49:51 2019 +0100
Update mmal patch
mmal_1.patch => mmal_8.patch | 5536 ++++++++++++++++++++++++++++++++++--------
1 file changed, 4581 insertions(+), 955 deletions(-)
---
diff --git a/mmal_1.patch b/mmal_8.patch
similarity index 58%
rename from mmal_1.patch
rename to mmal_8.patch
index 35bdeb2..8744fcb 100644
--- a/mmal_1.patch
+++ b/mmal_8.patch
@@ -1,6 +1,16 @@
--- a/configure.ac
+++ b/configure.ac
-@@ -3406,7 +3406,7 @@
+@@ -3419,6 +3419,9 @@
+ AC_ARG_ENABLE(mmal,
+ AS_HELP_STRING([--enable-mmal],
+ [Multi-Media Abstraction Layer (MMAL) hardware plugin (default enable)]))
++AC_ARG_ENABLE(mmal_avcodec,
++ AS_HELP_STRING([--enable-mmal-avcodec],
++ [Use MMAL enabled avcodec libs (default disable)]))
+ if test "${enable_mmal}" != "no"; then
+ VLC_SAVE_FLAGS
+ LDFLAGS="${LDFLAGS} -L/opt/vc/lib -lvchostif"
+@@ -3429,7 +3432,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 ])
@@ -9,9 +19,29 @@
AS_IF([test "${enable_mmal}" = "yes"],
[ AC_MSG_ERROR([Cannot find bcm library...]) ],
[ AC_MSG_WARN([Cannot find bcm library...]) ])
+@@ -3441,6 +3444,7 @@
+ VLC_RESTORE_FLAGS
+ fi
+ AM_CONDITIONAL([HAVE_MMAL], [test "${have_mmal}" = "yes"])
++AM_CONDITIONAL([HAVE_MMAL_AVCODEC], [test "${enable_mmal_avcodec}" = "yes"])
+
+ dnl
+ dnl evas plugin
+--- a/include/vlc_fourcc.h
++++ b/include/vlc_fourcc.h
+@@ -365,6 +365,9 @@
+
+ /* 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')
+
+ /* 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,30 @@
+@@ -1,23 +1,39 @@
include $(top_srcdir)/modules/common.am
mmaldir = $(pluginsdir)/mmal
@@ -47,197 +77,221 @@
+libmmal_xsplitter_plugin_la_LIBADD = $(LIBS_mmal)
+mmal_LTLIBRARIES += libmmal_xsplitter_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)
++libmmal_avcodec_plugin_la_LDFLAGS = $(AM_LDFLAGS)
++libmmal_avcodec_plugin_la_LIBADD = $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(LIBS_mmal)
++mmal_LTLIBRARIES += libmmal_avcodec_plugin.la
++endif
++
++
--- /dev/null
+++ b/modules/hw/mmal/blend_rgba_neon.S
-@@ -0,0 +1,185 @@
+@@ -0,0 +1,200 @@
+ .syntax unified
+ .arm
+// .thumb
+ .text
+ .align 16
++ .arch armv7-a
++ .fpu neon-vfpv4
+
-+@ Deal with tail
-+@ As the calculation on each pel is independant it doesn't matter
-+@ where the pels are in in the registers as long as we are consistant
-+@ with what we use for load & store. (Unused register fields will just
-+@ calculate garbage that we then ignore.)
++@ blend_rgbx_rgba_neon
+
-+tail_rgbx_rgba:
-+ lsls r2, r3, #30 @ b2 -> C, b1 -> N
-+ mov r12, r0
-+ vldmcs r1!, {d2,d3}
-+ vldmcs r0!, {d30, d31}
-+ vldmmi r1!, {d1}
-+ vldmmi r0!, {d29}
-+ tst r3, #1
-+ vldrne s1, [r1]
-+ vldrne s9, [r0]
-+ addne r1, #4
-+ addne r0, #4
-+
-+ @ Alpha in hi byte of each word
-+ vshr.u32 q9, q1, #24
-+ vshr.u32 q8, q0, #24
-+ vmov d28, d4 @ Can't load "s57" so cheat
-+ vmul.u32 q9, q9, d8[0]
-+ vmul.u32 q8, q8, d8[0]
-+ vrshr.u32 q9, q9, #16
-+ vrshr.u32 q8, q8, #16 @ 4 mix alpha values
-+ vmul.u32 q9, q10
-+ vmul.u32 q8, q10 @ dup every alpha into all 4 bytes of its word
-+
-+ vmull.u8 q3, d3, d19
-+ vmull.u8 q2, d2, d18
-+ vsub.u8 q9, q11, q9 @ gen the cplmnt
-+
-+ vmull.u8 q1, d1, d17
-+ vmull.u8 q0, d0, d16
-+ vsub.u8 q8, q11, q8
-+
-+ vmlal.u8 q3, d31, d19
-+ vmlal.u8 q2, d30, d18
-+ vmlal.u8 q1, d29, d17
-+ vmlal.u8 q0, d28, d16
-+
-+ vsra.u16 q3, q3, #8
-+ vsra.u16 q2, q2, #8
-+ vsra.u16 q1, q1, #8
-+ vsra.u16 q0, q0, #8
-+
-+ vrshrn.u16 d7, q3, #8
-+ vrshrn.u16 d6, q2, #8
-+ vrshrn.u16 d5, q1, #8
-+ vrshrn.u16 d4, q0, #8
-+
-+ vbit q3, q12, q12 @ Set alpha to #255
-+ vbit q2, q12, q12
++@ Implements /255 as ((x * 257) + 0x8000) >> 16
++@ This generates something in the range [(x+126)/255, (x+127)/255] which is good enough
+
-+ lsls r2, r3, #30 @ b2 -> C, b1 -> N
-+ vstmcs r12!, {d6,d7}
-+ vstmmi r12!, {d5}
-+ tst r3, #1
-+ vstrne s9, [r12]
-+ bx lr
++@ There is advantage to aligning src and/or dest - dest gives a bit more due to being used twice
+
+
-+@ blend_rgbx_rgba_neon
+
-+@ [r0] RGBx dest (Byte order: R, G, B, x)
-+@ [r1] RGBA src merge (Byte order: R, G, B, A)
++@ [r0] RGBx dest loaded into d20-d23
++@ [r1] RGBA src merge loaded into d16-d19
+@ r2 plane alpha
+@ r3 count (pixels)
+
-+@ Whilst specified as RGBx+RGBA the only important part is the position of
-+@ alpha, the other components are all treated the same
-+@ Assumes little endian i.e. Alpha ends up in hi 8 bits of uint32_t
-+
-+#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
-+#error Only little endian written (should be easy fix)
-+#endif
-+
-+@ Implements /255 as ((x * 257) + 0x8000) >> 16
-+@ This generates something in the range [(x+126)/255, (x+127)/255] which is good enough
-+
-+@ There is advantage to aligning src and/or dest - dest gives a bit more due to being used twice
++.macro blend_main sR, sG, sB, sA, dR, dG, dB, dA
+
-+ .align 16
-+ .global blend_rgbx_rgba_neon
-+#ifdef __ELF__
-+ .type blend_rgbx_rgba_neon, %function
-+#endif
++ push { r4, lr }
+
-+blend_rgbx_rgba_neon:
++ vdup.u8 d7, r2
+
-+ push { r4, lr }
-+ vpush { q4 } @ With reworked reg alloc this could be avoided
-+ movw r12, #257
-+ vmov.i8 q11, #0xff
-+ mul r2, r12
-+ vmov.u8 q10, #1
+ subs r3, #8
-+ vmov s16, r2
-+ vmov.u32 q12, #0xff000000
++ vmov.u8 d6, #0xff
++
+ blt 2f
+
+ @ If < 16 bytes to move then don't bother trying to align
+ @ (a) This means the the align doesn't need to worry about r3 underflow
+ @ (b) The overhead would be greater than any gain
+ cmp r3, #8
++ mov r4, r3
+ ble 1f
+
+ @ Align r1 on a 32 byte boundary
-+ mov r4, r3
+ neg r3, r0
+ ubfx r3, r3, #2, #3
+
+ cmp r3, #0
-+ blne tail_rgbx_rgba
++ blne 10f
+
+ sub r3, r4, r3
+
+1:
-+ vld1.32 { q0,q1 }, [r1]
++ vld4.8 {d16, d17, d18, d19}, [r1]
+
+1:
-+ @ Alpha in hi byte of each word
-+ vshr.u32 q9, q1, #24
-+ vshr.u32 q8, q0, #24
-+ vmul.u32 q9, q9, d8[0]
-+ vmul.u32 q8, q8, d8[0]
-+
-+ vrshr.u32 q9, q9, #16
-+ vrshr.u32 q8, q8, #16 @ 4 mix alpha values
-+ vmul.u32 q9, q10
-+ vmul.u32 q8, q10 @ dup every alpha into all 4 bytes of its word
-+
-+ vld1.32 {q14,q15}, [r0]
-+ subs r3, #8
-+
-+ vmull.u8 q3, d3, d19
-+ vmull.u8 q2, d2, d18
-+ vsub.u8 q9, q11, q9 @ gen the cplmnt
++ @ Alpha ends up in d19
++ vmull.u8 q15, \sA, d7
+
-+ vmull.u8 q1, d1, d17
-+ vmull.u8 q0, d0, d16
-+ vsub.u8 q8, q11, q8
-+ addge r1, #32
++ vld4.8 {d20, d21, d22, d23}, [r0]
+
-+ vmlal.u8 q3, d31, d19
-+ vmlal.u8 q2, d30, d18
-+ vmlal.u8 q1, d29, d17
-+ vmlal.u8 q0, d28, d16
++ vsra.u16 q15, q15, #8
++ subs r3, #8
++ vrshrn.u16 d31, q15, #8
++ vsub.u8 d30, d6, d31
+
-+ vsra.u16 q3, q3, #8
-+ vsra.u16 q2, q2, #8
-+ vsra.u16 q1, q1, #8
-+ vsra.u16 q0, q0, #8
++ vmull.u8 q12, \sR, d31
++ vmull.u8 q13, \sG, d31
++ vmull.u8 q14, \sB, d31
++ addge r1, #32
+
-+ vrshrn.u16 d7, q3, #8
-+ vrshrn.u16 d6, q2, #8
-+ vrshrn.u16 d5, q1, #8
-+ vrshrn.u16 d4, q0, #8
++ vmlal.u8 q12, \dR, d30
++ vmlal.u8 q13, \dG, d30
++ vmlal.u8 q14, \dB, d30
++ vld4.8 {d16, d17, d18, d19}, [r1]
+
-+ vld1.32 { q0,q1 }, [r1]
++ vsra.u16 q12, q12, #8 @ * 257/256
++ vsra.u16 q13, q13, #8
++ vsra.u16 q14, q14, #8
+
-+ vbit q3, q12, q12 @ Set alpha to #255
-+ vbit q2, q12, q12
++ vrshrn.u16 \dR, q12, #8
++ vrshrn.u16 \dG, q13, #8
++ vrshrn.u16 \dB, q14, #8
++ vmov.u8 \dA, #0xff
+
-+ vst1.32 { q2,q3 }, [r0]!
++ vst4.8 {d20, d21, d22, d23}, [r0]!
+ bge 1b
+ add r1, #32
+
+2:
-+ cmp r3, #-8
-+ blgt tail_rgbx_rgba
++ cmp r3, #-8
++ blgt 10f
+
-+ vpop { q4 }
+ pop { r4, pc }
+
+
++// Partial version
++// Align @ start & deal with tail
++10:
++ lsls r2, r3, #30 @ b2 -> C, b1 -> N
++ 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 {d16[1], d17[1], d18[1], d19[1]}, [r1]!
++ vld4.8 {d20[1], d21[1], d22[1], d23[1]}, [r0]!
++ vld4.8 {d16[2], d17[2], d18[2], d19[2]}, [r1]!
++ vld4.8 {d20[2], d21[2], d22[2], d23[2]}, [r0]!
++ vld4.8 {d16[3], d17[3], d18[3], d19[3]}, [r1]!
++ vld4.8 {d20[3], d21[3], d22[3], d23[3]}, [r0]!
++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 {d16[5], d17[5], d18[5], d19[5]}, [r1]!
++ vld4.8 {d20[5], d21[5], d22[5], d23[5]}, [r0]!
++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]!
++1:
++ @ Alpha ends up in d19
++
++ vmull.u8 q15, \sA, d7
++ vsra.u16 q15, q15, #8
++ vrshrn.u16 d31, q15, #8
++ vsub.u8 d30, d6, d31
++
++ vmull.u8 q12, \sR, d31
++ vmull.u8 q13, \sG, d31
++ vmull.u8 q14, \sB, d31
++
++ vmlal.u8 q12, \dR, d30
++ vmlal.u8 q13, \dG, d30
++ vmlal.u8 q14, \dB, d30
++
++ vsra.u16 q12, q12, #8
++ vsra.u16 q13, q13, #8
++ vsra.u16 q14, q14, #8
++
++ vrshrn.u16 \dR, q12, #8
++ vrshrn.u16 \dG, q13, #8
++ 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]!
++ vst4.8 {d20[2], d21[2], d22[2], d23[2]}, [r0]!
++ vst4.8 {d20[3], d21[3], d22[3], d23[3]}, [r0]!
++1:
++ bpl 1f
++ vst4.8 {d20[4], d21[4], d22[4], d23[4]}, [r0]!
++ vst4.8 {d20[5], d21[5], d22[5], d23[5]}, [r0]!
++1:
++ tst r3, #1
++ beq 1f
++ vst4.8 {d20[6], d21[6], d22[6], d23[6]}, [r0]!
++1:
++ bx lr
++
++.endm
++
++
++@ [r0] RGBx dest (Byte order: R, G, B, x)
++@ [r1] RGBA src merge (Byte order: R, G, B, A)
++@ r2 plane alpha
++@ r3 count (pixels)
++
++@ Whilst specified as RGBx+RGBA the only important part is the position of
++@ alpha, the other components are all treated the same
++
++@ [r0] RGBx dest (Byte order: R, G, B, x)
++@ [r1] RGBA src merge (Byte order: R, G, B, A) - same as above
++@ r2 plane alpha
++@ r3 count (pixels)
++ .align 16
++ .global blend_rgbx_rgba_neon
++#ifdef __ELF__
++ .type blend_rgbx_rgba_neon, %function
++#endif
++blend_rgbx_rgba_neon:
++ blend_main d16, d17, d18, d19, d20, d21, d22, d23
++
++
++@ [r0] RGBx dest (Byte order: R, G, B, x)
++@ [r1] RGBA src merge (Byte order: B, G, R, A) - B / R swapped
++@ r2 plane alpha
++@ r3 count (pixels)
++ .align 16
++ .global blend_bgrx_rgba_neon
++#ifdef __ELF__
++ .type blend_bgrx_rgba_neon, %function
++#endif
++blend_bgrx_rgba_neon:
++ blend_main d18, d17, d16, d19, d20, d21, d22, d23
++
++
+
--- /dev/null
+++ b/modules/hw/mmal/blend_rgba_neon.h
-@@ -0,0 +1,15 @@
+@@ -0,0 +1,17 @@
+#ifndef HW_MMAL_BLEND_RGBA_NEON_H
+#define HW_MMAL_BLEND_RGBA_NEON_H
+
@@ -245,7 +299,9 @@
+extern "C" {
+#endif
+
-+extern void blend_rgbx_rgba_neon(void * dest, const void * src, int alpha, unsigned int n);
++typedef void blend_neon_fn(void * dest, const void * src, int alpha, unsigned int n);
++extern blend_neon_fn blend_rgbx_rgba_neon;
++extern blend_neon_fn blend_bgrx_rgba_neon;
+
+#ifdef __cplusplus
+}
@@ -255,7 +311,7 @@
+
--- /dev/null
+++ b/modules/hw/mmal/blend_test.c
-@@ -0,0 +1,116 @@
+@@ -0,0 +1,180 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <memory.h>
@@ -296,6 +352,25 @@
+ }
+}
+
++
++// Merge RGBA with BGRA
++static void merge_line2(void * dest, const void * src, int alpha, unsigned int n)
++{
++ unsigned int i;
++ const uint8_t * s_data = src;
++ uint8_t * d_data = dest;
++
++ for (i = 0; i != n; ++i) {
++ const uint32_t s_pel = ((const uint32_t *)s_data)[i];
++ const uint32_t d_pel = ((const uint32_t *)d_data)[i];
++ const unsigned int a = div255(alpha * (s_pel >> 24));
++ ((uint32_t *)d_data)[i] = 0xff000000 |
++ (a_merge((d_pel >> 0) & 0xff, (s_pel >> 16) & 0xff, a) << 0 ) |
++ (a_merge((d_pel >> 8) & 0xff, (s_pel >> 8) & 0xff, a) << 8 ) |
++ (a_merge((d_pel >> 16) & 0xff, (s_pel >> 0) & 0xff, a) << 16);
++ }
++}
++
+#define BUF_SIZE 256
+#define BUF_SLACK 16
+#define BUF_ALIGN 64
@@ -329,6 +404,35 @@
+ }
+}
+
++static void test_line2(const uint32_t * const dx, const unsigned int d_off,
++ const uint32_t * const sx, const unsigned int s_off,
++ const unsigned int alpha, const unsigned int len, const int prof_no)
++{
++ uint32_t d0_buf[BUF_ALLOC];
++ uint32_t d1_buf[BUF_ALLOC];
++ const uint32_t * const s0 = sx + s_off;
++
++ uint32_t * const d0 = (uint32_t *)(((uintptr_t)d0_buf + (BUF_ALIGN - 1)) & ~(BUF_ALIGN - 1)) + d_off;
++ uint32_t * const d1 = (uint32_t *)(((uintptr_t)d1_buf + (BUF_ALIGN - 1)) & ~(BUF_ALIGN - 1)) + d_off;
++ unsigned int i;
++
++ memcpy(d0, dx, (BUF_SIZE + BUF_SLACK*2)*4);
++ memcpy(d1, dx, (BUF_SIZE + BUF_SLACK*2)*4);
++
++ merge_line2(d0 + BUF_SLACK, s0 + BUF_SLACK, alpha, len);
++
++ PROFILE_START();
++ blend_bgrx_rgba_neon(d1 + BUF_SLACK, s0 + BUF_SLACK, alpha, len);
++ PROFILE_ACC_N(prof_no);
++
++ for (i = 0; i != BUF_SIZE + BUF_SLACK*2; ++i) {
++ if (d0[i] != d1[i]) {
++ printf("%3d: %08x + %08x * %02x: %08x / %08x: len=%d\n", (int)(i - BUF_SLACK), dx[i], s0[i], alpha, d0[i], d1[i], len);
++ }
++ }
++}
++
++
+
+int main(int argc, char *argv[])
+{
@@ -351,8 +455,9 @@
+
+ for (i = 0; i != BUF_ALLOC; ++i) {
+ d0_buf[i] = 0xff00 | i;
-+ s0_buf[i] = (i << 24) | 0xffffff;
++ s0_buf[i] = (i << 24) | 0x40ffc0;
+ }
++
+ for (i = 0; i != 256; ++i) {
+ test_line(d0, 0, s0, 0, i, 256, -1);
+ }
@@ -365,9 +470,24 @@
+ test_line(d0, j & 3, s0, j >> 2, i, 256, j);
+ }
+ PROFILE_PRINTF_N(j);
++ PROFILE_CLEAR_N(j);
+ }
++ printf("Done 1\n");
+
-+ printf("Done\n");
++ for (i = 0; i != 256; ++i) {
++ test_line2(d0, 0, s0, 0, i, 256, -1);
++ }
++ for (i = 0; i != 256; ++i) {
++ test_line2(d0, 0, s0, 0, 128, i, -1);
++ }
++
++ for (j = 0; j != 16; ++j) {
++ for (i = 0; i != 256; ++i) {
++ test_line2(d0, j & 3, s0, j >> 2, i, 256, j);
++ }
++ PROFILE_PRINTF_N(j);
++ }
++ printf("Done 2\n");
+
+ return 0;
+}
@@ -388,7 +508,7 @@
#include <vlc_threads.h>
#include <bcm_host.h>
-@@ -38,255 +40,380 @@
+@@ -38,255 +40,393 @@
#include <interface/mmal/util/mmal_default_components.h>
#include "mmal_picture.h"
@@ -408,10 +528,6 @@
#define MIN_NUM_BUFFERS_IN_TRANSIT 2
-+#define MMAL_COMPONENT_DEFAULT_RESIZER "vc.ril.resize"
-+#define MMAL_COMPONENT_ISP_RESIZER "vc.ril.isp"
-+#define MMAL_COMPONENT_HVS "vc.ril.hvs"
-+
+#define MMAL_SLICE_HEIGHT 16
+#define MMAL_ALIGN_W 32
+#define MMAL_ALIGN_H 16
@@ -458,12 +574,31 @@
+ bool b_flushed;
+
++ // 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
++ vlc_mutex_t pic_lock;
++
/* statistics */
- 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);
@@ -478,51 +613,40 @@
-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)
-+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 =
++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;
-+ {{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;
-+#if TRACE_ALL || 1
-+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[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;
+}
-+#endif
+
+- 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;
- sys = calloc(1, sizeof(decoder_sys_t));
- if (!sys) {
- ret = VLC_ENOMEM;
- goto out;
-+static bool is_enc_supported(const MMAL_FOURCC_T fcc)
-+{
-+ int i;
-+
+ if (fcc == 0)
+ return false;
+ if (supported_mmal_enc.n == -1)
@@ -606,42 +730,6 @@
- sys->input->format->encoding = MMAL_ENCODING_MP2V;
- else
- sys->input->format->encoding = MMAL_ENCODING_H264;
--
-- if (dec->fmt_in.i_codec == VLC_CODEC_H264) {
-- if (dec->fmt_in.i_extra > 0) {
-- status = mmal_format_extradata_alloc(sys->input->format,
-- dec->fmt_in.i_extra);
-- if (status == MMAL_SUCCESS) {
-- memcpy(sys->input->format->extradata, dec->fmt_in.p_extra,
-- dec->fmt_in.i_extra);
-- sys->input->format->extradata_size = dec->fmt_in.i_extra;
-- } else {
-- msg_Err(dec, "Failed to allocate extra format data on input port %s (status=%"PRIx32" %s)",
-- sys->input->name, status, mmal_status_to_string(status));
-- }
-- }
-+static MMAL_FOURCC_T vlc_to_mmal_pic_fourcc(const unsigned int fcc)
-+{
-+ switch (fcc){
-+ case VLC_CODEC_I420:
-+ return MMAL_ENCODING_I420;
-+ case VLC_CODEC_RGB32: // _RGB32 doesn't exist in mmal magic mapping table
-+ case VLC_CODEC_RGBA:
-+ return MMAL_ENCODING_BGRA;
-+ case VLC_CODEC_MMAL_OPAQUE:
-+ return MMAL_ENCODING_OPAQUE;
-+ default:
-+ break;
- }
-+ return 0;
-+}
-
-- status = mmal_port_format_commit(sys->input);
-- if (status != MMAL_SUCCESS) {
-- msg_Err(dec, "Failed to commit format for input port %s (status=%"PRIx32" %s)",
-- sys->input->name, status, mmal_status_to_string(status));
-- ret = VLC_EGENERIC;
-- goto out;
+static MMAL_FOURCC_T pic_to_slice_mmal_fourcc(const MMAL_FOURCC_T fcc)
+{
+ switch (fcc){
@@ -671,15 +759,41 @@
+ return MMAL_ENCODING_BGR32_SLICE;
+ default:
+ break;
- }
-- sys->input->buffer_size = sys->input->buffer_size_recommended;
-- sys->input->buffer_num = sys->input->buffer_num_recommended;
++ }
+ return 0;
+}
-- status = mmal_port_enable(sys->input, input_port_cb);
+- if (dec->fmt_in.i_codec == VLC_CODEC_H264) {
+- if (dec->fmt_in.i_extra > 0) {
+- status = mmal_format_extradata_alloc(sys->input->format,
+- dec->fmt_in.i_extra);
+- if (status == MMAL_SUCCESS) {
+- memcpy(sys->input->format->extradata, dec->fmt_in.p_extra,
+- dec->fmt_in.i_extra);
+- sys->input->format->extradata_size = dec->fmt_in.i_extra;
+- } else {
+- msg_Err(dec, "Failed to allocate extra format data on input port %s (status=%"PRIx32" %s)",
+- sys->input->name, status, mmal_status_to_string(status));
+- }
++#define DEBUG_SQUARES 0
++#if DEBUG_SQUARES
++static void draw_square(void * pic_buf, size_t pic_stride, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t val)
++{
++ uint32_t * p = (uint32_t *)pic_buf + y * pic_stride + x;
++ unsigned int i;
++ for (i = 0; i != h; ++i) {
++ unsigned int j;
++ for (j = 0; j != w; ++j) {
++ p[j] = val;
+ }
++ p += pic_stride;
+ }
++}
++#endif
+
+- status = mmal_port_format_commit(sys->input);
- if (status != MMAL_SUCCESS) {
-- msg_Err(dec, "Failed to enable input port %s (status=%"PRIx32" %s)",
+- msg_Err(dec, "Failed to commit format for input port %s (status=%"PRIx32" %s)",
- sys->input->name, status, mmal_status_to_string(status));
- ret = VLC_EGENERIC;
- goto out;
@@ -691,22 +805,20 @@
+ *p = ~0U;
+ p += inc;
}
+- sys->input->buffer_size = sys->input->buffer_size_recommended;
+- sys->input->buffer_num = sys->input->buffer_num_recommended;
+}
+- status = mmal_port_enable(sys->input, input_port_cb);
+- if (status != MMAL_SUCCESS) {
+- msg_Err(dec, "Failed to enable input port %s (status=%"PRIx32" %s)",
+- sys->input->name, status, mmal_status_to_string(status));
+- ret = VLC_EGENERIC;
+- goto out;
+- }
+
- sys->output = sys->component->output[0];
- sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)dec;
-
-- if (sys->opaque) {
-- extra_buffers.hdr.id = MMAL_PARAMETER_EXTRA_BUFFERS;
-- extra_buffers.hdr.size = sizeof(MMAL_PARAMETER_UINT32_T);
-- extra_buffers.value = NUM_EXTRA_BUFFERS;
-- status = mmal_port_parameter_set(sys->output, &extra_buffers.hdr);
-- if (status != MMAL_SUCCESS) {
-- msg_Err(dec, "Failed to set MMAL_PARAMETER_EXTRA_BUFFERS on output port (status=%"PRIx32" %s)",
-- status, mmal_status_to_string(status));
-- ret = VLC_EGENERIC;
-- goto out;
-- }
+static void draw_corners(void * pic_buf, size_t pic_stride, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
+{
+ const unsigned int len = 20;
@@ -721,16 +833,30 @@
+}
+#endif
+- if (sys->opaque) {
+- extra_buffers.hdr.id = MMAL_PARAMETER_EXTRA_BUFFERS;
+- extra_buffers.hdr.size = sizeof(MMAL_PARAMETER_UINT32_T);
+- extra_buffers.value = NUM_EXTRA_BUFFERS;
+- status = mmal_port_parameter_set(sys->output, &extra_buffers.hdr);
+- if (status != MMAL_SUCCESS) {
+- msg_Err(dec, "Failed to set MMAL_PARAMETER_EXTRA_BUFFERS on output port (status=%"PRIx32" %s)",
+- status, mmal_status_to_string(status));
+- ret = VLC_EGENERIC;
+- goto out;
+- }
++// Buffer either attached to pic or released
++static picture_t * alloc_opaque_pic(decoder_t * const dec, MMAL_BUFFER_HEADER_T * const buf)
++{
++ decoder_sys_t *const dec_sys = dec->p_sys;
+
- msg_Dbg(dec, "Activate zero-copy for output port");
- MMAL_PARAMETER_BOOLEAN_T zero_copy = {
- { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) },
- 1
- };
-+// Buffer either attached to pic or released
-+static picture_t * alloc_opaque_pic(decoder_t * const dec, MMAL_BUFFER_HEADER_T * const buf)
-+{
-+ decoder_sys_t *const dec_sys = dec->p_sys;
++ vlc_mutex_lock(&dec_sys->pic_lock);
+ picture_t * const pic = decoder_NewPicture(dec);
++ vlc_mutex_unlock(&dec_sys->pic_lock);
- status = mmal_port_parameter_set(sys->output, &zero_copy.hdr);
- if (status != MMAL_SUCCESS) {
@@ -760,7 +886,7 @@
- ret = VLC_EGENERIC;
- goto out;
- }
-+ if ((pic->context = hw_mmal_gen_context(buf, dec_sys->ppr)) == NULL)
++ if ((pic->context = hw_mmal_gen_context(MMAL_ENCODING_OPAQUE, buf, dec_sys->ppr)) == NULL)
+ goto fail2;
- sys->input_pool = mmal_pool_create(sys->input->buffer_num, 0);
@@ -781,8 +907,8 @@
+fail2:
+ picture_Release(pic);
+fail1:
-+ // * maybe should recycle rather than release?
-+ mmal_buffer_header_release(buf);
++ // Recycle rather than release to avoid buffer starvation if NewPic fails
++ hw_mmal_port_pool_ref_recycle(dec_sys->ppr, buf);
+ return NULL;
+}
+
@@ -806,23 +932,23 @@
- dec->pf_flush = flush_decoder;
+ mmal_buffer_header_release(buffer);
+}
-+
+
+- vlc_sem_init(&sys->sem, 0);
+static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+ block_t * const block = (block_t *)buffer->user_data;
-- vlc_sem_init(&sys->sem, 0);
-+ (void)port; // Unused
-
-out:
- if (ret != VLC_SUCCESS)
- CloseDecoder(dec);
++ (void)port; // Unused
+
+- return ret;
+#if TRACE_ALL
+ msg_Dbg((decoder_t *)port->userdata, "<<< %s: cmd=%d, data=%p, len=%d/%d, pts=%lld", __func__,
+ buffer->cmd, buffer->data, buffer->length, buffer->alloc_size, (long long)buffer->pts);
+#endif
-
-- return ret;
++
+ mmal_buffer_header_reset(buffer);
+ mmal_buffer_header_release(buffer);
+
@@ -831,19 +957,17 @@
}
-static void CloseDecoder(decoder_t *dec)
-+static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
++static void decoder_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
{
- decoder_sys_t *sys = dec->p_sys;
- MMAL_BUFFER_HEADER_T *buffer;
-+ // decoder structure only guaranteed valid if we have contents
++ decoder_t * const dec = (decoder_t *)port->userdata;
- if (!sys)
+ if (buffer->cmd == 0 && buffer->length != 0)
+ {
-+ decoder_t * const dec = (decoder_t *)port->userdata;
-+
+#if TRACE_ALL
-+ msg_Dbg((decoder_t *)port->userdata, "<<< %s: cmd=%d, data=%p, len=%d/%d, pts=%lld", __func__,
++ msg_Dbg(dec, "<<< %s: cmd=%d, data=%p, len=%d/%d, pts=%lld", __func__,
+ buffer->cmd, buffer->data, buffer->length, buffer->alloc_size, (long long)buffer->pts);
+#endif
+
@@ -858,15 +982,17 @@
+ // Buffer released or attached to pic - do not release again
return;
+ }
-+ else if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED)
+
+- if (sys->component && sys->component->control->is_enabled)
+- mmal_port_disable(sys->component->control);
++ if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED)
+ {
-+ decoder_t * const dec = (decoder_t *)port->userdata;
+ decoder_sys_t * const sys = dec->p_sys;
+ MMAL_EVENT_FORMAT_CHANGED_T * const fmt = mmal_event_format_changed_get(buffer);
+ MMAL_ES_FORMAT_T * const format = mmal_format_alloc();
-- if (sys->component && sys->component->control->is_enabled)
-- mmal_port_disable(sys->component->control);
+- if (sys->input && sys->input->is_enabled)
+- mmal_port_disable(sys->input);
+ if (format == NULL)
+ msg_Err(dec, "Failed to allocate new format");
+ else
@@ -874,38 +1000,45 @@
+ mmal_format_full_copy(format, fmt->format);
+ format->encoding = MMAL_ENCODING_OPAQUE;
-- if (sys->input && sys->input->is_enabled)
-- mmal_port_disable(sys->input);
+- if (sys->output && sys->output->is_enabled)
+- mmal_port_disable(sys->output);
+ if (sys->output_format != NULL)
+ mmal_format_free(sys->output_format);
-- if (sys->output && sys->output->is_enabled)
-- mmal_port_disable(sys->output);
+- if (sys->component && sys->component->is_enabled)
+- mmal_component_disable(sys->component);
+ sys->output_format = format;
+ }
+ }
++ else if (buffer->cmd != 0) {
++ char buf0[5];
++ msg_Warn(dec, "Unexpected output cb event: %s", str_fourcc(buf0, buffer->cmd));
++ }
-- if (sys->component && sys->component->is_enabled)
-- mmal_component_disable(sys->component);
+- if (sys->input_pool)
+- mmal_pool_destroy(sys->input_pool);
++ // If we get here then we were flushing (cmd == 0 && len == 0) or
++ // that was an EVENT - in either case we want to release the buffer
++ // back to its pool rather than recycle it.
+ mmal_buffer_header_reset(buffer);
+ buffer->user_data = NULL;
+ mmal_buffer_header_release(buffer);
+}
-- if (sys->input_pool)
-- mmal_pool_destroy(sys->input_pool);
-
- if (sys->output_format)
- mmal_format_free(sys->output_format);
- if (sys->output_pool)
- mmal_pool_destroy(sys->output_pool);
+
+- if (sys->component)
+- mmal_component_release(sys->component);
+static void fill_output_port(decoder_t *dec)
+{
+ decoder_sys_t *sys = dec->p_sys;
-- if (sys->component)
-- mmal_component_release(sys->component);
+- vlc_sem_destroy(&sys->sem);
+- free(sys);
+ if (decoder_UpdateVideoFormat(dec) != 0)
+ {
+ // If we have a new format don't bother stuffing the buffer
@@ -914,12 +1047,10 @@
+ msg_Dbg(dec, "%s: Updated", __func__);
+#endif
-- vlc_sem_destroy(&sys->sem);
-- free(sys);
+- bcm_host_deinit();
+ return;
+ }
-
-- bcm_host_deinit();
++
+ hw_mmal_port_pool_ref_fill(sys->ppr);
+ return;
}
@@ -940,7 +1071,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 +427,9 @@
+@@ -300,7 +440,9 @@
}
port_reset:
@@ -950,7 +1081,7 @@
status = mmal_port_disable(sys->output);
if (status != MMAL_SUCCESS) {
msg_Err(dec, "Failed to disable output port (status=%"PRIx32" %s)",
-@@ -318,15 +447,7 @@
+@@ -318,18 +460,10 @@
goto out;
}
@@ -966,8 +1097,12 @@
+ sys->output->buffer_num = NUM_DECODER_BUFFER_HEADERS;
sys->output->buffer_size = sys->output->buffer_size_recommended;
- status = mmal_port_enable(sys->output, output_port_cb);
-@@ -338,25 +459,14 @@
+- status = mmal_port_enable(sys->output, output_port_cb);
++ status = mmal_port_enable(sys->output, decoder_output_cb);
+ 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 @@
}
if (!atomic_load(&sys->started)) {
@@ -996,7 +1131,7 @@
}
apply_fmt:
-@@ -382,12 +492,17 @@
+@@ -382,12 +505,19 @@
sys->b_progressive = (interlace_type.eMode == MMAL_InterlaceProgressive);
sys->b_top_field_first = sys->b_progressive ? true :
(interlace_type.eMode == MMAL_InterlaceFieldsInterleavedUpperFirst);
@@ -1008,13 +1143,15 @@
+#endif
}
-+ // Tell the reset of the world we have changed format
++ // Tell the rest of the world we have changed format
++ vlc_mutex_lock(&sys->pic_lock);
+ ret = decoder_UpdateVideoFormat(dec);
++ vlc_mutex_unlock(&sys->pic_lock);
+
out:
mmal_format_free(sys->output_format);
sys->output_format = NULL;
-@@ -395,144 +510,85 @@
+@@ -395,144 +525,85 @@
return ret;
}
@@ -1029,7 +1166,7 @@
MMAL_STATUS_T status;
- unsigned buffer_size = 0;
- int ret = 0;
-
+-
- if (!sys->output->is_enabled)
- return VLC_EGENERIC;
-
@@ -1078,7 +1215,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) {
@@ -1182,7 +1319,7 @@
+ mmal_port_disable(sys->output);
+ // We can leave the input disabled, but we want the output enabled
+ // in order to sink any buffers returning from other modules
-+ mmal_port_enable(sys->output, output_port_cb);
++ mmal_port_enable(sys->output, decoder_output_cb);
+ sys->b_flushed = true;
+ }
+#if TRACE_ALL
@@ -1212,7 +1349,7 @@
/*
* Configure output port if necessary
*/
-@@ -541,18 +597,50 @@
+@@ -541,18 +612,50 @@
msg_Err(dec, "Failed to change output port format");
}
@@ -1240,7 +1377,7 @@
+ // Reenable stuff if the last thing we did was flush
+ if (!sys->output->is_enabled &&
-+ (status = mmal_port_enable(sys->output, output_port_cb)) != MMAL_SUCCESS)
++ (status = mmal_port_enable(sys->output, decoder_output_cb)) != MMAL_SUCCESS)
+ {
+ msg_Err(dec, "Output port enable failed");
+ goto fail;
@@ -1266,7 +1403,7 @@
if (atomic_load(&sys->started))
fill_output_port(dec);
-@@ -563,18 +651,21 @@
+@@ -563,18 +666,21 @@
if (block->i_flags & BLOCK_FLAG_CORRUPTED)
flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED;
@@ -1293,7 +1430,7 @@
len = block->i_buffer;
if (len > buffer->alloc_size)
-@@ -590,89 +681,1304 @@
+@@ -590,89 +696,1443 @@
}
buffer->flags = flags;
@@ -1362,6 +1499,7 @@
+
+ hw_mmal_port_pool_ref_release(sys->ppr, false);
+
++ vlc_mutex_destroy(&sys->pic_lock);
+ free(sys);
+
+ bcm_host_deinit();
@@ -1398,6 +1536,7 @@
+ goto fail;
+ }
+ dec->p_sys = sys;
++ vlc_mutex_init(&sys->pic_lock);
+
+ bcm_host_init();
+
@@ -1445,45 +1584,9 @@
+ goto fail;
+ }
+
-+ sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)dec;
-+
-+ status = port_parameter_set_uint32(sys->output, MMAL_PARAMETER_EXTRA_BUFFERS, NUM_EXTRA_BUFFERS);
-+ if (status != MMAL_SUCCESS) {
-+ msg_Err(dec, "Failed to set MMAL_PARAMETER_EXTRA_BUFFERS on output port (status=%"PRIx32" %s)",
-+ status, mmal_status_to_string(status));
-+ goto fail;
-+ }
-+
-+ status = port_parameter_set_bool(sys->output, MMAL_PARAMETER_ZERO_COPY, 1);
-+ if (status != MMAL_SUCCESS) {
-+ msg_Err(dec, "Failed to set zero copy on port %s (status=%"PRIx32" %s)",
-+ sys->output->name, status, mmal_status_to_string(status));
-+ goto fail;
-+ }
-+
-+ sys->output->format->encoding = MMAL_ENCODING_OPAQUE;
-+ if ((status = mmal_port_format_commit(sys->output)) != MMAL_SUCCESS)
-+ {
-+ msg_Err(dec, "Failed to commit format on port %s (status=%"PRIx32" %s)",
-+ sys->output->name, status, mmal_status_to_string(status));
-+ goto fail;
-+ }
-+
-+ sys->output->buffer_num = NUM_DECODER_BUFFER_HEADERS;
-+ sys->output->buffer_size = sys->output->buffer_size_recommended;
-+
-+ sys->ppr = hw_mmal_port_pool_ref_create(sys->output, NUM_DECODER_BUFFER_HEADERS, sys->output->buffer_size);
-+ if (sys->ppr == NULL) {
-+ msg_Err(dec, "Failed to create output pool");
-+ goto fail;
-+ }
-+
-+ status = mmal_port_enable(sys->output, output_port_cb);
-+ if (status != MMAL_SUCCESS) {
-+ msg_Err(dec, "Failed to enable output port %s (status=%"PRIx32" %s)",
-+ sys->output->name, status, mmal_status_to_string(status));
++ if ((status = hw_mmal_opaque_output(VLC_OBJECT(dec), &sys->ppr,
++ sys->output, NUM_EXTRA_BUFFERS, decoder_output_cb)) != MMAL_SUCCESS)
+ goto fail;
-+ }
+
+ status = mmal_component_enable(sys->component);
+ if (status != MMAL_SUCCESS) {
@@ -1573,7 +1676,20 @@
+
+#define SUBS_MAX 3
+
++typedef enum filter_resizer_e {
++ FILTER_RESIZER_RESIZER,
++ FILTER_RESIZER_ISP,
++ FILTER_RESIZER_HVS
++} filter_resizer_t;
++
++typedef struct conv_frame_stash_s
++{
++ mtime_t pts;
++ MMAL_BUFFER_HEADER_T * sub_bufs[SUBS_MAX];
++} conv_frame_stash_t;
++
+typedef struct filter_sys_t {
++ filter_resizer_t resizer_type;
+ MMAL_COMPONENT_T *component;
+ MMAL_PORT_T *input;
+ MMAL_PORT_T *output;
@@ -1593,13 +1709,15 @@
+ MMAL_STATUS_T err_stream;
+ int in_count;
+
-+ bool zero_copy;
++ bool is_sliced;
++ bool out_fmt_set;
++ bool latency_set;
+ const char * component_name;
+ MMAL_PORT_BH_CB_T in_port_cb_fn;
+ MMAL_PORT_BH_CB_T out_port_cb_fn;
+
+ uint64_t frame_seq;
-+ mtime_t pts_stash[16];
++ conv_frame_stash_t stash[16];
+
+ // Slice specific tracking stuff
+ struct {
@@ -1610,20 +1728,24 @@
+} filter_sys_t;
+
+
-+static void pic_to_format(MMAL_ES_FORMAT_T * const es_fmt, const picture_t * const pic)
++static MMAL_STATUS_T pic_to_format(MMAL_ES_FORMAT_T * const es_fmt, const picture_t * const pic)
+{
+ unsigned int bpp = (pic->format.i_bits_per_pixel + 7) >> 3;
+ MMAL_VIDEO_FORMAT_T * const v_fmt = &es_fmt->es->video;
+
++ if (bpp < 1 || bpp > 4)
++ return MMAL_EINVAL;
++
+ es_fmt->type = MMAL_ES_TYPE_VIDEO;
-+ es_fmt->encoding_variant = es_fmt->encoding =
-+ vlc_to_mmal_pic_fourcc(pic->format.i_chroma);
++ 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;
++ return MMAL_SUCCESS;
+}
+
+
@@ -1743,7 +1865,7 @@
+#if TRACE_ALL
+ msg_Dbg(p_filter, "<<< %s: cmd=%d, flags=%#x, pic=%p, data=%p, len=%d/%d, pts=%lld/%lld", __func__,
+ buf->cmd, buf->flags, buf->user_data, buf->data, buf->length, buf->alloc_size,
-+ (long long)buf->pts, (long long)sys->pts_stash[(unsigned int)(buf->pts & 0xf)]);
++ (long long)buf->pts, (long long)sys->stash[(unsigned int)(buf->pts & 0xf)].pts);
+#endif
+ if (buf->cmd == 0) {
+ picture_t * const pic = (picture_t *)buf->user_data;
@@ -1761,10 +1883,13 @@
+ else
+ {
+ buf_to_pic_copy_props(pic, buf);
-+ pic->date = sys->pts_stash[(unsigned int)(buf->pts & 0xf)];
+
+// 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);
++ draw_square(pic->p[0].p_pixels, pic->p[0].i_pitch / 4, 32, 0, 32, 32, 0xff00ff00);
++ draw_square(pic->p[0].p_pixels, pic->p[0].i_pitch / 4, 64, 0, 32, 32, 0xff0000ff);
++#endif
+ conv_out_q_pic(sys, pic);
+ }
+ }
@@ -1824,7 +1949,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) {
@@ -1832,7 +1957,7 @@
+ dst += dst_stride;
+ src += src_stride;
+ }
- }
++ }
+ sys->slice.line += scale_n;
}
- atomic_fetch_sub(&sys->output_in_transit, 1);
@@ -1888,8 +2013,11 @@
+ msg_Dbg(p_filter, "<<< %s", __func__);
+#endif
+
-+ for (i = 0; i != SUBS_MAX; ++i) {
-+ hw_mmal_subpic_flush(VLC_OBJECT(p_filter), sys->subs + i);
++ if (sys->resizer_type == FILTER_RESIZER_HVS)
++ {
++ for (i = 0; i != SUBS_MAX; ++i) {
++ hw_mmal_subpic_flush(VLC_OBJECT(p_filter), sys->subs + i);
++ }
+ }
+
+ if (sys->input != NULL && sys->input->is_enabled)
@@ -1902,6 +2030,19 @@
+ // Don't need lock as the above disables should have prevented anything
+ // happening in the background
+
++ for (i = 0; i != 16; ++i) {
++ conv_frame_stash_t *const stash = sys->stash + i;
++ unsigned int sub_no;
++
++ stash->pts = MMAL_TIME_UNKNOWN;
++ for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
++ if (stash->sub_bufs[sub_no] != NULL) {
++ mmal_buffer_header_release(stash->sub_bufs[sub_no]);
++ stash->sub_bufs[sub_no] = NULL;
++ }
++ }
++ }
++
+ pic_fifo_release_all(&sys->slice.pics);
+ pic_fifo_release_all(&sys->ret_pics);
+
@@ -1921,12 +2062,79 @@
+#endif
+}
+
++static void conv_flush_passthrough(filter_t * p_filter)
++{
++ VLC_UNUSED(p_filter);
++}
++
++static void conv_stash_fixup(filter_t * const p_filter, filter_sys_t * const sys, picture_t * const p_pic)
++{
++ conv_frame_stash_t * const stash = sys->stash + (p_pic->date & 0xf);
++ unsigned int sub_no;
++ VLC_UNUSED(p_filter);
++
++ p_pic->date = stash->pts;
++ for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
++ if (stash->sub_bufs[sub_no] != NULL) {
++ // **** Do stashed blend
++ // **** Aaargh, bother... need to rescale subs too
++
++ mmal_buffer_header_release(stash->sub_bufs[sub_no]);
++ stash->sub_bufs[sub_no] = NULL;
++ }
++ }
++}
++
++static MMAL_STATUS_T conv_set_output(filter_t * const p_filter, filter_sys_t * const sys, picture_t * const pic)
++{
++ MMAL_STATUS_T status;
++
++ sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)p_filter;
++ sys->output->format->type = MMAL_ES_TYPE_VIDEO;
++ sys->output->format->encoding = vlc_to_mmal_video_fourcc(&p_filter->fmt_out.video);
++ sys->output->format->encoding_variant = 0;
++ vlc_to_mmal_video_fmt(sys->output->format, &p_filter->fmt_out.video);
++
++ // Override default format width/height if we have a pic we need to match
++ if (pic != NULL)
++ {
++ 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);
++ return status;
++ }
++
++ MMAL_VIDEO_FORMAT_T *fmt = &sys->output->format->es->video;
++ msg_Dbg(p_filter, "%s: %dx%d [(0,0) %dx%d]", __func__, fmt->width, fmt->height, fmt->crop.width, fmt->crop.height);
++ }
++
++ mmal_log_dump_format(sys->output->format);
++
++ status = mmal_port_format_commit(sys->output);
++ if (status != MMAL_SUCCESS) {
++ msg_Err(p_filter, "Failed to commit format for output port %s (status=%"PRIx32" %s)",
++ sys->output->name, status, mmal_status_to_string(status));
++ return status;
++ }
++
++ sys->output->buffer_num = __MAX(sys->is_sliced ? 16 : 2, sys->output->buffer_num_recommended);
++ sys->output->buffer_size = sys->output->buffer_size_recommended;
++
++ if ((status = conv_enable_out(p_filter, sys)) != MMAL_SUCCESS)
++ return status;
+
+- sys->output_format = format;
++ return MMAL_SUCCESS;
++}
++
+static picture_t *conv_filter(filter_t *p_filter, picture_t *p_pic)
+{
+ filter_sys_t * const sys = p_filter->p_sys;
+ picture_t * ret_pics;
+ MMAL_STATUS_T err;
+ const uint64_t frame_seq = ++sys->frame_seq;
++ conv_frame_stash_t * const stash = sys->stash + (frame_seq & 0xf);
+
+#if TRACE_ALL
+ msg_Dbg(p_filter, "<<< %s", __func__);
@@ -1953,7 +2161,7 @@
+ if (p_pic->context == NULL) {
+ msg_Dbg(p_filter, "%s: No context", __func__);
+ }
-+ else
++ else if (sys->resizer_type == FILTER_RESIZER_HVS)
+ {
+ unsigned int sub_no = 0;
+
@@ -1966,6 +2174,43 @@
+ goto fail;
+ }
+ }
++ else
++ {
++ unsigned int sub_no = 0;
++ for (sub_no = 0; sub_no != SUBS_MAX; ++sub_no) {
++ if ((stash->sub_bufs[sub_no] = hw_mmal_pic_sub_buf_get(p_pic, sub_no)) != NULL) {
++ mmal_buffer_header_acquire(stash->sub_bufs[sub_no]);
++ }
++ }
++ }
++
++ if (!sys->out_fmt_set) {
++ sys->out_fmt_set = true;
++
++ if (sys->is_sliced) {
++ // If zc then we will do stride conversion when we copy to arm side
++ // so no need to worry about actual pic dimensions here
++ if ((err = conv_set_output(p_filter, sys, NULL)) != MMAL_SUCCESS)
++ goto fail;
++ }
++ else {
++ picture_t *pic = filter_NewPicture(p_filter);
++ err = conv_set_output(p_filter, sys, pic);
++ picture_Release(pic);
++ if (err != MMAL_SUCCESS)
++ goto fail;
++ }
++
++ 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);
++
++ if (sys->out_pool == NULL) {
++ msg_Err(p_filter, "Failed to create output pool");
++ goto fail;
++ }
++ }
+
+ // Reenable stuff if the last thing we did was flush
+ if ((err = conv_enable_out(p_filter, sys)) != MMAL_SUCCESS ||
@@ -1973,7 +2218,7 @@
+ goto fail;
+
+ // If ZC then we need to allocate the out pic before we stuff the input
-+ if (sys->zero_copy) {
++ if (sys->is_sliced) {
+ MMAL_BUFFER_HEADER_T * out_buf;
+ picture_t * const out_pic = filter_NewPicture(p_filter);
+
@@ -2008,7 +2253,7 @@
+ goto fail;
+ }
+
-+ sys->pts_stash[(frame_seq & 0xf)] = p_pic->date;
++ stash->pts = p_pic->date;
+ if ((err = port_send_replicated(sys->input, sys->in_pool, pic_buf, frame_seq)) != MMAL_SUCCESS)
+ {
+ msg_Err(p_filter, "Send buffer to input failed");
@@ -2020,14 +2265,13 @@
+ --sys->in_count;
+ }
+
-+ if (!sys->zero_copy) {
++ if (!sys->is_sliced) {
+ MMAL_BUFFER_HEADER_T * out_buf;
+
+ while ((out_buf = sys->in_count < 0 ?
+ mmal_queue_wait(sys->out_pool->queue) : mmal_queue_get(sys->out_pool->queue)) != NULL)
+ {
+ picture_t * const out_pic = filter_NewPicture(p_filter);
-+ char dbuf0[5];
+
+ if (out_pic == NULL) {
+ msg_Warn(p_filter, "Failed to alloc new filter output pic");
@@ -2036,6 +2280,7 @@
+ }
+
+#if 0
++ char dbuf0[5];
+ msg_Dbg(p_filter, "out_pic %s,%dx%d [(%d,%d) %d/%d] sar:%d/%d",
+ str_fourcc(dbuf0, out_pic->format.i_chroma),
+ out_pic->format.i_width, out_pic->format.i_height,
@@ -2076,6 +2321,15 @@
+ // Avoid being more than 1 pic behind
+ vlc_sem_wait(&sys->sem);
+
++ // Set sem for delayed scale if not already set
++ if (!sys->latency_set) {
++ unsigned int i;
++ sys->latency_set = true;
++ for (i = 0; i != CONV_MAX_LATENCY; ++i) {
++ vlc_sem_post(&sys->sem);
++ }
++ }
++
+ // Return all pending buffers
+ vlc_mutex_lock(&sys->lock);
+ ret_pics = pic_fifo_get_all(&sys->ret_pics);
@@ -2089,6 +2343,8 @@
+ if (ret_pics != NULL)
+ {
+ picture_t *next_pic = ret_pics->p_next;
++
++ conv_stash_fixup(p_filter, sys, ret_pics);
+#if 0
+ char dbuf0[5];
+
@@ -2101,6 +2357,7 @@
+#endif
+ while (next_pic != NULL) {
+ vlc_sem_wait(&sys->sem);
++ conv_stash_fixup(p_filter, sys, next_pic);
+ next_pic = next_pic->p_next;
+ }
+ }
@@ -2108,7 +2365,8 @@
+#if TRACE_ALL
+ msg_Dbg(p_filter, ">>> %s: pic=%p", __func__, ret_pics);
+#endif
-+
+
+- mmal_buffer_header_release(buffer);
+ return ret_pics;
+
+stream_fail:
@@ -2120,14 +2378,21 @@
+ return NULL;
+}
+
++static picture_t *conv_filter_passthrough(filter_t *p_filter, picture_t *p_pic)
++{
++ VLC_UNUSED(p_filter);
++#if TRACE_ALL
++ msg_Dbg(p_filter, "<<< %s", __func__);
++#endif
++ return p_pic;
++}
+
+static void CloseConverter(vlc_object_t * obj)
+{
+ filter_t * const p_filter = (filter_t *)obj;
+ filter_sys_t * const sys = p_filter->p_sys;
+ unsigned int i;
-
-- sys->output_format = format;
++
+#if TRACE_ALL
+ msg_Dbg(obj, "<<< %s", __func__);
+#endif
@@ -2144,13 +2409,16 @@
+ if (sys->component && sys->component->is_enabled)
+ mmal_component_disable(sys->component);
+
-+ for (i = 0; i != SUBS_MAX; ++i) {
-+ hw_mmal_subpic_close(VLC_OBJECT(p_filter), sys->subs + i);
++ if (sys->resizer_type == FILTER_RESIZER_HVS)
++ {
++ for (i = 0; i != SUBS_MAX; ++i) {
++ hw_mmal_subpic_close(VLC_OBJECT(p_filter), sys->subs + i);
++ }
+ }
+
+ if (sys->out_pool)
+ {
-+ if (sys->zero_copy)
++ if (sys->is_sliced)
+ mmal_port_pool_destroy(sys->output, sys->out_pool);
+ else
+ mmal_pool_destroy(sys->out_pool);
@@ -2169,41 +2437,30 @@
+}
+
+
-+static int conv_set_output(filter_t * const p_filter, filter_sys_t * const sys, picture_t * const pic, const MMAL_FOURCC_T pic_enc)
++static int open_converter_passthrough(filter_t * const p_filter)
+{
-+ MMAL_STATUS_T status;
-+
-+ sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)p_filter;
-+ sys->output->format->type = MMAL_ES_TYPE_VIDEO;
-+ sys->output->format->encoding = pic_enc;
-+ sys->output->format->encoding_variant = sys->output->format->encoding;
-+ vlc_to_mmal_video_fmt(sys->output->format, &p_filter->fmt_out.video);
-+
-+ // Override default format width/height if we have a pic we need to match
-+ if (pic != NULL)
+ {
-+ pic_to_format(sys->output->format, pic);
-+ MMAL_VIDEO_FORMAT_T *fmt = &sys->output->format->es->video;
-+ msg_Dbg(p_filter, "%s: %dx%d [(0,0) %dx%d]", __func__, fmt->width, fmt->height, fmt->crop.width, fmt->crop.height);
++ char dbuf0[5], dbuf1[5];
++ msg_Dbg(p_filter, "%s: (%s) %s,%dx%d [(%d,%d) %d/%d] sar:%d/%d->%s,%dx%d [(%d,%d) %dx%d] rgb:%#x:%#x:%#x sar:%d/%d", __func__,
++ "passthrough",
++ str_fourcc(dbuf0, p_filter->fmt_in.video.i_chroma),
++ p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
++ p_filter->fmt_in.video.i_x_offset, p_filter->fmt_in.video.i_y_offset,
++ p_filter->fmt_in.video.i_visible_width, p_filter->fmt_in.video.i_visible_height,
++ p_filter->fmt_in.video.i_sar_num, p_filter->fmt_in.video.i_sar_den,
++ str_fourcc(dbuf1, p_filter->fmt_out.video.i_chroma),
++ p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
++ p_filter->fmt_out.video.i_x_offset, p_filter->fmt_out.video.i_y_offset,
++ p_filter->fmt_out.video.i_visible_width, p_filter->fmt_out.video.i_visible_height,
++ p_filter->fmt_out.video.i_rmask, p_filter->fmt_out.video.i_gmask, p_filter->fmt_out.video.i_bmask,
++ p_filter->fmt_out.video.i_sar_num, p_filter->fmt_out.video.i_sar_den);
+ }
+
-+ mmal_log_dump_format(sys->output->format);
-+
-+ status = mmal_port_format_commit(sys->output);
-+ if (status != MMAL_SUCCESS) {
-+ msg_Err(p_filter, "Failed to commit format for output port %s (status=%"PRIx32" %s)",
-+ sys->output->name, status, mmal_status_to_string(status));
-+ return -1;
-+ }
+
-+ sys->output->buffer_num = __MAX(sys->zero_copy ? 16 : 2, sys->output->buffer_num_recommended);
-+ sys->output->buffer_size = sys->output->buffer_size_recommended;
-+
-+ if (conv_enable_out(p_filter, sys) != MMAL_SUCCESS)
-+ return -1;
-+
-+ return 0;
-+}
++ p_filter->pf_video_filter = conv_filter_passthrough;
++ p_filter->pf_flush = conv_flush_passthrough;
++ return VLC_SUCCESS;
++}
+
+static int OpenConverter(vlc_object_t * obj)
+{
@@ -2212,19 +2469,34 @@
+ filter_sys_t *sys;
+ MMAL_STATUS_T status;
+ MMAL_FOURCC_T enc_out;
-+ const MMAL_FOURCC_T enc_in = MMAL_ENCODING_OPAQUE;
++ const MMAL_FOURCC_T enc_in = vlc_to_mmal_video_fourcc(&p_filter->fmt_in.video);
+ bool use_resizer;
+ bool use_isp;
+ int gpu_mem;
+
-+ if (enc_in != vlc_to_mmal_pic_fourcc(p_filter->fmt_in.i_codec) ||
-+ (enc_out = vlc_to_mmal_pic_fourcc(p_filter->fmt_out.i_codec)) == 0)
++ if ((enc_in != MMAL_ENCODING_OPAQUE &&
++ enc_in != MMAL_ENCODING_YUVUV128 &&
++ enc_in != MMAL_ENCODING_YUVUV64_10) ||
++ (enc_out = vlc_to_mmal_video_fourcc(&p_filter->fmt_out.video)) == 0)
+ return VLC_EGENERIC;
-
-- mmal_buffer_header_release(buffer);
++
++ if (enc_in == enc_out) {
++ return open_converter_passthrough(p_filter);
++ }
++
+ use_resizer = var_InheritBool(p_filter, MMAL_RESIZE_NAME);
+ use_isp = var_InheritBool(p_filter, MMAL_ISP_NAME);
+
++retry:
++ // Must use ISP - HVS can't do this, nor can resizer
++ if (enc_in == MMAL_ENCODING_YUVUV64_10) {
++ // If resizer selected then just give up
++ if (use_resizer)
++ return VLC_EGENERIC;
++ // otherwise downgrade HVS to ISP
++ use_isp = true;
++ }
++
+ if (use_resizer) {
+ // use resizer overrides use_isp
+ use_isp = false;
@@ -2232,22 +2504,26 @@
+
+ // Check we have a sliced version of the fourcc if we want the resizer
+ if (use_resizer &&
-+ (enc_out = pic_to_slice_mmal_fourcc(enc_out)) == 0)
++ (enc_out = pic_to_slice_mmal_fourcc(enc_out)) == 0) {
+ return VLC_EGENERIC;
++ }
+
+ gpu_mem = hw_mmal_get_gpu_mem();
+
+ {
-+ char dbuf0[5], dbuf1[5];
-+ msg_Dbg(p_filter, "%s: (%s) %s,%dx%d [(%d,%d) %d/%d] sar:%d/%d->%s,%dx%d [(%d,%d) %dx%d] sar:%d/%d (gpu=%d)", __func__,
++ char dbuf0[5], dbuf1[5], dbuf2[5], dbuf3[5];
++ msg_Dbg(p_filter, "%s: (%s) %s/%s,%dx%d [(%d,%d) %d/%d] sar:%d/%d->%s/%s,%dx%d [(%d,%d) %dx%d] rgb:%#x:%#x:%#x sar:%d/%d (gpu=%d)", __func__,
+ use_resizer ? "resize" : use_isp ? "isp" : "hvs",
-+ str_fourcc(dbuf0, p_filter->fmt_in.video.i_chroma), p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
++ str_fourcc(dbuf0, p_filter->fmt_in.video.i_chroma), str_fourcc(dbuf2, enc_in),
++ p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
+ p_filter->fmt_in.video.i_x_offset, p_filter->fmt_in.video.i_y_offset,
+ p_filter->fmt_in.video.i_visible_width, p_filter->fmt_in.video.i_visible_height,
+ p_filter->fmt_in.video.i_sar_num, p_filter->fmt_in.video.i_sar_den,
-+ str_fourcc(dbuf1, p_filter->fmt_out.video.i_chroma), p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
++ str_fourcc(dbuf1, p_filter->fmt_out.video.i_chroma), str_fourcc(dbuf3, enc_out),
++ p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
+ p_filter->fmt_out.video.i_x_offset, p_filter->fmt_out.video.i_y_offset,
+ p_filter->fmt_out.video.i_visible_width, p_filter->fmt_out.video.i_visible_height,
++ p_filter->fmt_out.video.i_rmask, p_filter->fmt_out.video.i_gmask, p_filter->fmt_out.video.i_bmask,
+ p_filter->fmt_out.video.i_sar_num, p_filter->fmt_out.video.i_sar_den,
+ gpu_mem);
+ }
@@ -2261,34 +2537,43 @@
+
+ // Init stuff the we destroy unconditionaly in Close first
+ vlc_mutex_init(&sys->lock);
-+ vlc_sem_init(&sys->sem, CONV_MAX_LATENCY);
++ vlc_sem_init(&sys->sem, 0);
+ sys->err_stream = MMAL_SUCCESS;
+ pic_fifo_init(&sys->ret_pics);
+ pic_fifo_init(&sys->slice.pics);
+
+ sys->in_port_cb_fn = conv_input_port_cb;
+ if (use_resizer) {
-+ sys->zero_copy = true;
++ sys->resizer_type = FILTER_RESIZER_RESIZER;
++ sys->is_sliced = true;
+ sys->component_name = MMAL_COMPONENT_DEFAULT_RESIZER;
+ sys->out_port_cb_fn = slice_output_port_cb;
+ }
+ else if (use_isp) {
-+ sys->zero_copy = false; // Copy directly into filter picture
++ sys->resizer_type = FILTER_RESIZER_ISP;
++ sys->is_sliced = false; // Copy directly into filter picture
+ sys->component_name = MMAL_COMPONENT_ISP_RESIZER;
+ sys->out_port_cb_fn = conv_output_port_cb;
} else {
- mmal_buffer_header_release(buffer);
-+ sys->zero_copy = false; // Copy directly into filter picture
++ sys->resizer_type = FILTER_RESIZER_HVS;
++ sys->is_sliced = false; // Copy directly into filter picture
+ sys->component_name = MMAL_COMPONENT_HVS;
+ sys->out_port_cb_fn = conv_output_port_cb;
+ }
+
+ status = mmal_component_create(sys->component_name, &sys->component);
+ if (status != MMAL_SUCCESS) {
++ if (!use_isp && !use_resizer) {
++ msg_Warn(p_filter, "Failed to rcreate HVS resizer - retrying with ISP");
++ CloseConverter(obj);
++ use_isp = true;
++ goto retry;
++ }
+ msg_Err(p_filter, "Failed to create MMAL component %s (status=%"PRIx32" %s)",
+ MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status));
+ goto fail;
-+ }
+ }
+ sys->output = sys->component->output[0];
+ sys->input = sys->component->input[0];
+
@@ -2318,25 +2603,10 @@
+ sys->input->buffer_size = sys->input->buffer_size_recommended;
+ sys->input->buffer_num = NUM_DECODER_BUFFER_HEADERS;
+
-+ if (conv_enable_in(p_filter, sys) != MMAL_SUCCESS)
++ if ((status = conv_enable_in(p_filter, sys)) != MMAL_SUCCESS)
+ goto fail;
+
-+ port_parameter_set_bool(sys->output, MMAL_PARAMETER_ZERO_COPY, sys->zero_copy);
-+
-+ if (sys->zero_copy) {
-+ // If zc then we will do stride conversion when we copy to arm side
-+ // so no need to worry about actual pic dimensions here
-+ if (conv_set_output(p_filter, sys, NULL, enc_out) != 0)
-+ goto fail;
-+ }
-+ else {
-+ picture_t *pic = filter_NewPicture(p_filter);
-+ int err = conv_set_output(p_filter, sys, pic, enc_out);
-+ picture_Release(pic);
-+ if (err != 0) {
-+ goto fail;
-+ }
-+ }
++ port_parameter_set_bool(sys->output, MMAL_PARAMETER_ZERO_COPY, sys->is_sliced);
+
+ status = mmal_component_enable(sys->component);
+ if (status != MMAL_SUCCESS) {
@@ -2345,21 +2615,13 @@
+ goto fail;
+ }
+
-+ msg_Dbg(p_filter, "Outpool: zc=%d, num=%d, size=%d", sys->zero_copy, sys->output->buffer_num, sys->output->buffer_size);
-+ sys->out_pool = sys->zero_copy ?
-+ mmal_port_pool_create(sys->output, sys->output->buffer_num, sys->output->buffer_size) :
-+ mmal_pool_create(sys->output->buffer_num, 0);
-+
-+ if (sys->out_pool == NULL) {
-+ msg_Err(p_filter, "Failed to create output pool");
-+ goto fail;
-+ }
+ if ((sys->in_pool = mmal_pool_create(sys->input->buffer_num, 0)) == NULL)
+ {
+ msg_Err(p_filter, "Failed to create input pool");
+ goto fail;
+ }
+
++ if (sys->resizer_type == FILTER_RESIZER_HVS)
+ {
+ unsigned int i;
+ for (i = 0; i != SUBS_MAX; ++i) {
@@ -2383,8 +2645,15 @@
+
+fail:
+ CloseConverter(obj);
++
++ if (!use_resizer && status == MMAL_ENOMEM) {
++ use_resizer = true;
++ msg_Warn(p_filter, "Lack of memory to use HVS/ISP: trying resizer");
++ goto retry;
++ }
++
+#if TRACE_ALL
-+msg_Dbg(p_filter, ">>> %s: FAIL: %d", __func__, ret);
++ msg_Dbg(p_filter, ">>> %s: FAIL: %d", __func__, ret);
+#endif
+ return ret;
+}
@@ -2438,8 +2707,8 @@
+ hw_mmal_pic_sub_buf_add(dst, buf);
+
+ sys->last_dst = dst;
- }
- }
++ }
++}
+
+static void FlushBlendMmal(filter_t * p_filter)
+{
@@ -2451,9 +2720,16 @@
+static int OpenBlendMmal(vlc_object_t *object)
+{
+ filter_t * const p_filter = (filter_t *)object;
-+ const vlc_fourcc_t vfcc_src = p_filter->fmt_in.video.i_chroma;
+ const vlc_fourcc_t vfcc_dst = p_filter->fmt_out.video.i_chroma;
+
++ if ((vfcc_dst != VLC_CODEC_MMAL_OPAQUE &&
++ vfcc_dst != VLC_CODEC_MMAL_ZC_SAND8 &&
++ vfcc_dst != VLC_CODEC_MMAL_ZC_SAND10) ||
++ !hw_mmal_vzc_subpic_fmt_valid(&p_filter->fmt_in.video))
++ {
++ return VLC_EGENERIC;
++ }
++
+ {
+ char dbuf0[5], dbuf1[5];
+ msg_Dbg(p_filter, "%s: (%s) %s,%dx%d [(%d,%d) %dx%d]->%s,%dx%d [(%d,%d) %dx%d]", __func__,
@@ -2466,10 +2742,6 @@
+ p_filter->fmt_out.video.i_visible_width, p_filter->fmt_out.video.i_visible_height);
+ }
+
-+ if (vfcc_dst != VLC_CODEC_MMAL_OPAQUE || vfcc_src != VLC_CODEC_RGBA) {
-+ return VLC_EGENERIC;
-+ }
-+
+ {
+ blend_sys_t * const sys = calloc(1, sizeof (*sys));
+ if (sys == NULL)
@@ -2499,20 +2771,6 @@
+
+// ---------------------------------------------------------------------------
+
-+static inline unsigned div255(unsigned v)
-+{
-+ /* It is exact for 8 bits, and has a max error of 1 for 9 and 10 bits
-+ * while respecting full opacity/transparency */
-+ return ((v >> 8) + v + 1) >> 8;
-+ //return v / 255;
-+}
-+
-+static inline unsigned int a_merge(unsigned int dst, unsigned src, unsigned f)
-+{
-+ return div255((255 - f) * (dst) + src * f);
-+}
-+
-+
+static void FilterBlendNeon(filter_t *p_filter,
+ picture_t *dst_pic, const picture_t * src_pic,
+ int x_offset, int y_offset, int alpha)
@@ -2521,11 +2779,10 @@
+ uint8_t * d_data;
+ int width = src_pic->format.i_visible_width;
+ int height = src_pic->format.i_visible_height;
++ blend_neon_fn *const blend_fn = (blend_neon_fn * )p_filter->p_sys;
+
+#if TRACE_ALL
+ msg_Dbg(p_filter, "%s (%d,%d:%d) pic=%p, pts=%lld, force=%d", __func__, x_offset, y_offset, alpha, src_pic, src_pic->date, src_pic->b_force);
-+#else
-+ VLC_UNUSED(p_filter);
+#endif
+
+ if (alpha == 0 ||
@@ -2559,20 +2816,7 @@
+
+
+ do {
-+#if 1
-+ blend_rgbx_rgba_neon(d_data, s_data, alpha, width);
-+#else
-+ int i;
-+ for (i = 0; i != width; ++i) {
-+ const uint32_t s_pel = ((const uint32_t *)s_data)[i];
-+ const uint32_t d_pel = ((const uint32_t *)d_data)[i];
-+ const unsigned int a = div255(alpha * (s_pel >> 24));
-+ ((uint32_t *)d_data)[i] = 0xff000000 |
-+ (a_merge((d_pel >> 16) & 0xff, (s_pel >> 16) & 0xff, a) << 16) |
-+ (a_merge((d_pel >> 8) & 0xff, (s_pel >> 8) & 0xff, a) << 8 ) |
-+ (a_merge((d_pel >> 0) & 0xff, (s_pel >> 0) & 0xff, a) << 0 );
-+ }
-+#endif
++ blend_fn(d_data, s_data, alpha, width);
+ s_data += src_pic->p[0].i_pitch;
+ d_data += dst_pic->p[0].i_pitch;
+ } while (--height > 0);
@@ -2581,31 +2825,63 @@
+static void CloseBlendNeon(vlc_object_t *object)
+{
+ VLC_UNUSED(object);
-+}
+ }
+
+static int OpenBlendNeon(vlc_object_t *object)
+{
+ filter_t * const p_filter = (filter_t *)object;
-+ const vlc_fourcc_t vfcc_src = p_filter->fmt_in.video.i_chroma;
+ const vlc_fourcc_t vfcc_dst = p_filter->fmt_out.video.i_chroma;
++ MMAL_FOURCC_T mfcc_src = vlc_to_mmal_video_fourcc(&p_filter->fmt_in.video);
++ MMAL_FOURCC_T mfcc_dst = vlc_to_mmal_video_fourcc(&p_filter->fmt_out.video);
++ blend_neon_fn * blend_fn = (blend_neon_fn *)0;
++
++ // Non-alpha RGB only for dest
++ if (vfcc_dst != VLC_CODEC_RGB32)
++ return VLC_EGENERIC;
++
++ // Check we have appropriate blend fn (mmal doesn't have a non-alpha RGB32)
++ switch (mfcc_src) {
++ case MMAL_ENCODING_RGBA:
++ if (mfcc_dst == MMAL_ENCODING_RGBA)
++ blend_fn = blend_rgbx_rgba_neon;
++ else if (mfcc_dst == MMAL_ENCODING_BGRA)
++ blend_fn = blend_bgrx_rgba_neon;
++ break;
++
++ case MMAL_ENCODING_BGRA:
++ if (mfcc_dst == MMAL_ENCODING_BGRA)
++ blend_fn = blend_rgbx_rgba_neon;
++ else if (mfcc_dst == MMAL_ENCODING_RGBA)
++ blend_fn = blend_bgrx_rgba_neon;
++ break;
++
++ default:
++ break;
++ }
++
++ if (blend_fn == (blend_neon_fn *)0)
++ return VLC_EGENERIC;
++
++ p_filter->p_sys = (void *)blend_fn;
++ p_filter->pf_video_blend = FilterBlendNeon;
+
+ {
+ char dbuf0[5], dbuf1[5];
-+ msg_Dbg(p_filter, "%s: (%s) %s,%dx%d [(%d,%d) %dx%d]->%s,%dx%d [(%d,%d) %dx%d]", __func__,
++ char dbuf0a[5], dbuf1a[5];
++ msg_Dbg(p_filter, "%s: (%s) %s/%s,%dx%d [(%d,%d) %dx%d]->%s/%s,%dx%d [(%d,%d) %dx%d]", __func__,
+ "blend",
-+ str_fourcc(dbuf0, p_filter->fmt_in.video.i_chroma), p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
++ str_fourcc(dbuf0, p_filter->fmt_in.video.i_chroma),
++ str_fourcc(dbuf0a, mfcc_src),
++ p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
+ p_filter->fmt_in.video.i_x_offset, p_filter->fmt_in.video.i_y_offset,
+ p_filter->fmt_in.video.i_visible_width, p_filter->fmt_in.video.i_visible_height,
-+ str_fourcc(dbuf1, p_filter->fmt_out.video.i_chroma), p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
++ str_fourcc(dbuf1, p_filter->fmt_out.video.i_chroma),
++ str_fourcc(dbuf1a, mfcc_dst),
++ p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
+ p_filter->fmt_out.video.i_x_offset, p_filter->fmt_out.video.i_y_offset,
+ p_filter->fmt_out.video.i_visible_width, p_filter->fmt_out.video.i_visible_height);
+ }
+
-+ if (vfcc_dst != VLC_CODEC_RGB32 || vfcc_src != VLC_CODEC_RGBA) {
-+ return VLC_EGENERIC;
-+ }
-+
-+ p_filter->pf_video_blend = FilterBlendNeon;
+ return VLC_SUCCESS;
+}
+
@@ -2666,7 +2942,7 @@
#include "mmal_picture.h"
-@@ -41,466 +42,602 @@
+@@ -41,466 +42,569 @@
#define MIN_NUM_BUFFERS_IN_TRANSIT 2
@@ -2682,7 +2958,18 @@
+#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")
@@ -2700,19 +2987,8 @@
+#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")
--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()
-
-struct filter_sys_t {
++
+typedef struct filter_sys_t
+{
MMAL_COMPONENT_T *component;
@@ -2790,7 +3066,7 @@
- if (!sys)
- return VLC_ENOMEM;
- filter->p_sys = sys;
-+ if ((pic->context = hw_mmal_gen_context(buf, filter_sys->out_ppr)) == NULL)
++ if ((pic->context = hw_mmal_gen_context(MMAL_ENCODING_OPAQUE, buf, filter_sys->out_ppr)) == NULL)
+ goto fail2;
- bcm_host_init();
@@ -3033,6 +3309,7 @@
- sys->output->name, status, mmal_status_to_string(status));
- ret = VLC_EGENERIC;
- goto out;
+- }
+ // Return anything that is in the out Q
+ {
+ MMAL_BUFFER_HEADER_T * out_buf;
@@ -3051,56 +3328,77 @@
+ mmal_queue_put_back(sys->out_q, out_buf);
+ break;
+ }
-+
+
+- status = mmal_component_enable(sys->component);
+- if (status != MMAL_SUCCESS) {
+- msg_Err(filter, "Failed to enable component %s (status=%"PRIx32" %s)",
+- sys->component->name, status, mmal_status_to_string(status));
+- ret = VLC_EGENERIC;
+- goto out;
+- }
+#if TRACE_ALL
+ msg_Dbg(p_filter, "-- %s: Q pic=%p: seq_in=%d, seq_out=%d, delta=%d", __func__, out_pic, sys->seq_in, seq_out, seq_delta(sys->seq_in, seq_out));
+#endif
-+
+
+- sys->filtered_pictures = mmal_queue_create();
+ *pp_pic = out_pic;
+ pp_pic = &out_pic->p_next;
-+
+
+- filter->pf_video_filter = deinterlace;
+- filter->pf_flush = flush;
+ // Ignore 0 seqs
+ // Don't think these should actually happen
+ if (seq_out != 0)
+ sys->seq_out = seq_out;
+ }
- }
++ }
-- status = mmal_component_enable(sys->component);
-- if (status != MMAL_SUCCESS) {
-- msg_Err(filter, "Failed to enable component %s (status=%"PRIx32" %s)",
-- sys->component->name, status, mmal_status_to_string(status));
-- ret = VLC_EGENERIC;
-- goto out;
+- vlc_sem_init(&sys->sem, 0);
+#if TRACE_ALL
+ msg_Dbg(p_filter, ">>> %s: pic=%p", __func__, ret_pics);
+#endif
-+
+
+-out:
+- if (ret != VLC_SUCCESS)
+- Close(filter);
+ return ret_pics;
-+
+
+- return ret;
+fail:
+ picture_Release(p_pic);
+ return NULL;
-+}
-+
+ }
+
+-static void Close(filter_t *filter)
+static void di_flush(filter_t *p_filter)
-+{
+ {
+- filter_sys_t *sys = filter->p_sys;
+- MMAL_BUFFER_HEADER_T *buffer;
+ filter_sys_t * const sys = p_filter->p_sys;
-+
+
+- if (!sys)
+- return;
+-
+- if (sys->component && sys->component->control->is_enabled)
+- mmal_port_disable(sys->component->control);
+#if TRACE_ALL
+ msg_Dbg(p_filter, "<<< %s", __func__);
+#endif
-+
+
+- if (sys->input && sys->input->is_enabled)
+ if (sys->input != NULL && sys->input->is_enabled)
-+ mmal_port_disable(sys->input);
-+
+ mmal_port_disable(sys->input);
+
+- if (sys->output && sys->output->is_enabled)
+ if (sys->output != NULL && sys->output->is_enabled)
+ {
+ // Wedge anything we've got into the output port as that will free the underlying buffers
+ fill_output_from_q(p_filter, sys, sys->out_q);
+
-+ mmal_port_disable(sys->output);
-+
+ mmal_port_disable(sys->output);
+
+- if (sys->component && sys->component->is_enabled)
+- mmal_component_disable(sys->component);
+ // If that dumped anything real into the out_q then have another go
+ if (mmal_queue_length(sys->out_q) != 0)
+ {
@@ -3110,34 +3408,36 @@
+ // Out q should now be empty & should remain so until the input is reenabled
+ }
+ mmal_port_enable(sys->output, di_output_port_cb);
-+
+
+- while ((buffer = mmal_queue_get(sys->filtered_pictures))) {
+- picture_t *pic = (picture_t *)buffer->user_data;
+- picture_Release(pic);
+ // Leaving the input disabled is fine - but we want to leave the output enabled
+ // so we can retrieve buffers that are still bound to pictures
}
-- sys->filtered_pictures = mmal_queue_create();
+- if (sys->filtered_pictures)
+- mmal_queue_destroy(sys->filtered_pictures);
+ sys->seq_in = 1;
+ sys->seq_out = 1;
-- filter->pf_video_filter = deinterlace;
-- filter->pf_flush = flush;
+- if (sys->component)
+- mmal_component_release(sys->component);
+#if TRACE_ALL
+ msg_Dbg(p_filter, ">>> %s", __func__);
+#endif
+}
-- vlc_sem_init(&sys->sem, 0);
+- vlc_sem_destroy(&sys->sem);
+- free(sys);
--out:
-- if (ret != VLC_SUCCESS)
-- Close(filter);
+- bcm_host_deinit();
+static void pass_flush(filter_t *p_filter)
+{
+ // Nothing to do
+ VLC_UNUSED(p_filter);
+}
-
-- return ret;
++
+static picture_t * pass_deinterlace(filter_t * p_filter, picture_t * p_pic)
+{
+ VLC_UNUSED(p_filter);
@@ -3146,22 +3446,34 @@
+ return p_pic;
}
--static void Close(filter_t *filter)
+-static int send_output_buffer(filter_t *filter)
+
+static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
{
- filter_sys_t *sys = filter->p_sys;
- MMAL_BUFFER_HEADER_T *buffer;
+ filter_t *filter = (filter_t *)port->userdata;
-+ MMAL_STATUS_T status;
+ MMAL_STATUS_T status;
+- picture_t *picture;
+- int ret = 0;
-- if (!sys)
+- if (!sys->output->is_enabled) {
+- ret = VLC_EGENERIC;
+- goto out;
+ if (buffer->cmd == MMAL_EVENT_ERROR) {
+ status = *(uint32_t *)buffer->data;
+ msg_Err(filter, "MMAL error %"PRIx32" \"%s\"", status,
+ mmal_status_to_string(status));
-+ }
-+
+ }
+
+- picture = filter_NewPicture(filter);
+- if (!picture) {
+- msg_Warn(filter, "Failed to get new picture");
+- ret = -1;
+- goto out;
+- }
+- picture->format.i_frame_rate = filter->fmt_out.video.i_frame_rate;
+- picture->format.i_frame_rate_base = filter->fmt_out.video.i_frame_rate_base;
+ mmal_buffer_header_reset(buffer);
+ mmal_buffer_header_release(buffer);
+}
@@ -3169,87 +3481,101 @@
+static void CloseMmalDeinterlace(filter_t *filter)
+{
+ filter_sys_t * const sys = filter->p_sys;
-+
+
+- buffer = picture->p_sys->buffer;
+- buffer->user_data = picture;
+- buffer->cmd = 0;
+#if TRACE_ALL
+ msg_Dbg(filter, "<<< %s", __func__);
+#endif
-+
+
+- mmal_picture_lock(picture);
+ if (sys == NULL)
- return;
++ return;
-- if (sys->component && sys->component->control->is_enabled)
-- mmal_port_disable(sys->component->control);
+- status = mmal_port_send_buffer(sys->output, buffer);
+- if (status != MMAL_SUCCESS) {
+- msg_Err(filter, "Failed to send buffer to output port (status=%"PRIx32" %s)",
+- status, mmal_status_to_string(status));
+- mmal_buffer_header_release(buffer);
+- picture_Release(picture);
+- ret = -1;
+- } else {
+- atomic_fetch_add(&sys->output_in_transit, 1);
+- vlc_sem_post(&sys->sem);
+ if (sys->use_passthrough)
+ {
+ free(sys);
+ return;
-+ }
+ }
-- if (sys->input && sys->input->is_enabled)
-- mmal_port_disable(sys->input);
+-out:
+- return ret;
+ di_flush(filter);
-
-- if (sys->output && sys->output->is_enabled)
-- mmal_port_disable(sys->output);
++
+ if (sys->component && sys->component->control->is_enabled)
+ mmal_port_disable(sys->component->control);
-
- if (sys->component && sys->component->is_enabled)
- mmal_component_disable(sys->component);
-
-- while ((buffer = mmal_queue_get(sys->filtered_pictures))) {
-- picture_t *pic = (picture_t *)buffer->user_data;
-- picture_Release(pic);
-- }
++
++ if (sys->component && sys->component->is_enabled)
++ mmal_component_disable(sys->component);
++
+ if (sys->in_pool != NULL)
+ mmal_pool_destroy(sys->in_pool);
+
+ hw_mmal_port_pool_ref_release(sys->out_ppr, false);
+ // Once we exit filter & sys are invalid so mark as such
+ sys->output->userdata = NULL;
-
-- if (sys->filtered_pictures)
-- mmal_queue_destroy(sys->filtered_pictures);
++
+ if (sys->out_q != NULL)
+ mmal_queue_destroy(sys->out_q);
-
- if (sys->component)
- mmal_component_release(sys->component);
-
-- vlc_sem_destroy(&sys->sem);
- free(sys);
-
- bcm_host_deinit();
++
++ if (sys->component)
++ mmal_component_release(sys->component);
++
++ free(sys);
++
++ bcm_host_deinit();
}
--static int send_output_buffer(filter_t *filter)
+-static void fill_output_port(filter_t *filter)
+
+static int OpenMmalDeinterlace(filter_t *filter)
{
- filter_sys_t *sys = filter->p_sys;
-- MMAL_BUFFER_HEADER_T *buffer;
+- /* allow at least 2 buffers in transit */
+- unsigned max_buffers_in_transit = __MAX(2, MIN_NUM_BUFFERS_IN_TRANSIT);
+- int buffers_available = sys->output->buffer_num -
+- atomic_load(&sys->output_in_transit) -
+- mmal_queue_length(sys->filtered_pictures);
+- int buffers_to_send = max_buffers_in_transit - sys->output_in_transit;
+- int i;
+ int32_t frame_duration = filter->fmt_in.video.i_frame_rate != 0 ?
+ CLOCK_FREQ * filter->fmt_in.video.i_frame_rate_base /
+ filter->fmt_in.video.i_frame_rate : 0;
+
+ int ret = VLC_EGENERIC;
- MMAL_STATUS_T status;
-- picture_t *picture;
-- int ret = 0;
++ MMAL_STATUS_T status;
+ filter_sys_t *sys;
++
++ msg_Dbg(filter, "<<< %s", __func__);
-- if (!sys->output->is_enabled) {
-- ret = VLC_EGENERIC;
-- goto out;
-- }
+- if (buffers_to_send > buffers_available)
+- buffers_to_send = buffers_available;
+ if (filter->fmt_in.video.i_chroma != VLC_CODEC_MMAL_OPAQUE ||
+ filter->fmt_out.video.i_chroma != VLC_CODEC_MMAL_OPAQUE)
+ return VLC_EGENERIC;
-+
+
+-#ifndef NDEBUG
+- msg_Dbg(filter, "Send %d buffers to output port (available: %d, in_transit: %d, buffer_num: %d)",
+- buffers_to_send, buffers_available, sys->output_in_transit,
+- sys->output->buffer_num);
+#if TRACE_ALL
+ msg_Dbg(filter, "Try to open mmal_deinterlace filter. frame_duration: %d, QPU %s!",
+ frame_duration, use_qpu ? "used" : "unused");
-+#endif
+ #endif
+- for (i = 0; i < buffers_to_send; ++i) {
+- if (send_output_buffer(filter) < 0)
+- break;
+
+ sys = calloc(1, sizeof(filter_sys_t));
+ if (!sys)
@@ -3270,19 +3596,18 @@
+ // Also check we actually have enough memory to do this
+ if (hw_mmal_get_gpu_mem() < (96 << 20))
+ sys->use_passthrough = true;
-
-- picture = filter_NewPicture(filter);
-- if (!picture) {
-- msg_Warn(filter, "Failed to get new picture");
-- ret = -1;
-- goto out;
++
}
-- picture->format.i_frame_rate = filter->fmt_out.video.i_frame_rate;
-- picture->format.i_frame_rate_base = filter->fmt_out.video.i_frame_rate_base;
+-}
-- buffer = picture->p_sys->buffer;
-- buffer->user_data = picture;
-- buffer->cmd = 0;
+-static picture_t *deinterlace(filter_t *filter, picture_t *picture)
+-{
+- filter_sys_t *sys = filter->p_sys;
+- MMAL_BUFFER_HEADER_T *buffer;
+- picture_t *out_picture = NULL;
+- picture_t *ret = NULL;
+- MMAL_STATUS_T status;
+- unsigned i = 0;
+ if (var_InheritBool(filter, MMAL_DEINTERLACE_NO_QPU))
+ sys->use_qpu = false;
+ if (var_InheritBool(filter, MMAL_DEINTERLACE_ADV))
@@ -3308,40 +3633,21 @@
+ filter->pf_flush = pass_flush;
+ return 0;
+ }
-
-- mmal_picture_lock(picture);
++
+ bcm_host_init();
-- status = mmal_port_send_buffer(sys->output, buffer);
+- fill_output_port(filter);
+ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_DEINTERLACE, &sys->component);
- if (status != MMAL_SUCCESS) {
-- msg_Err(filter, "Failed to send buffer to output port (status=%"PRIx32" %s)",
-- status, mmal_status_to_string(status));
-- mmal_buffer_header_release(buffer);
-- picture_Release(picture);
-- ret = -1;
-- } else {
-- atomic_fetch_add(&sys->output_in_transit, 1);
-- vlc_sem_post(&sys->sem);
++ if (status != MMAL_SUCCESS) {
+ msg_Err(filter, "Failed to create MMAL component %s (status=%"PRIx32" %s)",
+ MMAL_COMPONENT_DEFAULT_DEINTERLACE, status, mmal_status_to_string(status));
+ goto fail;
- }
++ }
--out:
-- return ret;
--}
--
--static void fill_output_port(filter_t *filter)
--{
-- filter_sys_t *sys = filter->p_sys;
-- /* allow at least 2 buffers in transit */
-- unsigned max_buffers_in_transit = __MAX(2, MIN_NUM_BUFFERS_IN_TRANSIT);
-- int buffers_available = sys->output->buffer_num -
-- atomic_load(&sys->output_in_transit) -
-- mmal_queue_length(sys->filtered_pictures);
-- int buffers_to_send = max_buffers_in_transit - sys->output_in_transit;
-- int i;
+- buffer = picture->p_sys->buffer;
+- buffer->user_data = picture;
+- buffer->pts = picture->date;
+- buffer->cmd = 0;
+ {
+ const MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {
+ { MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, sizeof(imfx_param) },
@@ -3352,69 +3658,10 @@
+ { 5 /* Frame type: mixed */, frame_duration, sys->half_rate, sys->use_qpu }
+ };
-- if (buffers_to_send > buffers_available)
-- buffers_to_send = buffers_available;
-+ status = mmal_port_parameter_set(sys->component->output[0], &imfx_param.hdr);
-+ if (status != MMAL_SUCCESS) {
-+ msg_Err(filter, "Failed to configure MMAL component %s (status=%"PRIx32" %s)",
-+ MMAL_COMPONENT_DEFAULT_DEINTERLACE, status, mmal_status_to_string(status));
-+ goto fail;
-+ }
-+ }
-
--#ifndef NDEBUG
-- msg_Dbg(filter, "Send %d buffers to output port (available: %d, in_transit: %d, buffer_num: %d)",
-- buffers_to_send, buffers_available, sys->output_in_transit,
-- sys->output->buffer_num);
--#endif
-- for (i = 0; i < buffers_to_send; ++i) {
-- if (send_output_buffer(filter) < 0)
-- break;
-+ sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)filter;
-+ status = mmal_port_enable(sys->component->control, control_port_cb);
-+ if (status != MMAL_SUCCESS) {
-+ msg_Err(filter, "Failed to enable control port %s (status=%"PRIx32" %s)",
-+ sys->component->control->name, status, mmal_status_to_string(status));
-+ goto fail;
- }
--}
-
--static picture_t *deinterlace(filter_t *filter, picture_t *picture)
--{
-- filter_sys_t *sys = filter->p_sys;
-- MMAL_BUFFER_HEADER_T *buffer;
-- picture_t *out_picture = NULL;
-- picture_t *ret = NULL;
-- MMAL_STATUS_T status;
-- unsigned i = 0;
-+ sys->input = sys->component->input[0];
-+ sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)filter;
-+ if (filter->fmt_in.i_codec == VLC_CODEC_MMAL_OPAQUE)
-+ sys->input->format->encoding = MMAL_ENCODING_OPAQUE;
-+ vlc_to_mmal_video_fmt(sys->input->format, &filter->fmt_in.video);
-
-- fill_output_port(filter);
-+ es_format_Copy(&filter->fmt_out, &filter->fmt_in);
-+ if (!sys->half_rate)
-+ filter->fmt_out.video.i_frame_rate *= 2;
-
-- buffer = picture->p_sys->buffer;
-- buffer->user_data = picture;
-- buffer->pts = picture->date;
-- buffer->cmd = 0;
-+ status = mmal_port_format_commit(sys->input);
-+ if (status != MMAL_SUCCESS) {
-+ msg_Err(filter, "Failed to commit format for input port %s (status=%"PRIx32" %s)",
-+ sys->input->name, status, mmal_status_to_string(status));
-+ goto fail;
-+ }
-+ sys->input->buffer_size = sys->input->buffer_size_recommended;
-+ sys->input->buffer_num = 30;
-+// sys->input->buffer_num = sys->input->buffer_num_recommended;
-
- if (!picture->p_sys->displayed) {
- status = mmal_port_send_buffer(sys->input, buffer);
-- if (status != MMAL_SUCCESS) {
++ status = mmal_port_parameter_set(sys->component->output[0], &imfx_param.hdr);
+ if (status != MMAL_SUCCESS) {
- msg_Err(filter, "Failed to send buffer to input port (status=%"PRIx32" %s)",
- status, mmal_status_to_string(status));
- picture_Release(picture);
@@ -3422,14 +3669,12 @@
- picture->p_sys->displayed = true;
- atomic_fetch_add(&sys->input_in_transit, 1);
- vlc_sem_post(&sys->sem);
-- }
++ msg_Err(filter, "Failed to configure MMAL component %s (status=%"PRIx32" %s)",
++ MMAL_COMPONENT_DEFAULT_DEINTERLACE, status, mmal_status_to_string(status));
++ goto fail;
+ }
- } else {
- picture_Release(picture);
-+ status = port_parameter_set_bool(sys->input, MMAL_PARAMETER_ZERO_COPY, true);
-+ if (status != MMAL_SUCCESS) {
-+ msg_Err(filter, "Failed to set zero copy on port %s (status=%"PRIx32" %s)",
-+ sys->input->name, status, mmal_status_to_string(status));
-+ goto fail;
}
- /*
@@ -3450,10 +3695,11 @@
- msg_Dbg(filter, "Failed waiting for filtered picture");
- break;
- }
-+ status = mmal_port_enable(sys->input, di_input_port_cb);
++ sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)filter;
++ status = mmal_port_enable(sys->component->control, control_port_cb);
+ if (status != MMAL_SUCCESS) {
-+ msg_Err(filter, "Failed to enable input port %s (status=%"PRIx32" %s)",
-+ sys->input->name, status, mmal_status_to_string(status));
++ msg_Err(filter, "Failed to enable control port %s (status=%"PRIx32" %s)",
++ sys->component->control->name, status, mmal_status_to_string(status));
+ goto fail;
}
- if (out_picture)
@@ -3461,28 +3707,30 @@
- return ret;
-}
-+ sys->output = sys->component->output[0];
-+ sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)filter;
-+ mmal_format_full_copy(sys->output->format, sys->input->format);
++ sys->input = sys->component->input[0];
++ sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)filter;
++ if (filter->fmt_in.i_codec == VLC_CODEC_MMAL_OPAQUE)
++ sys->input->format->encoding = MMAL_ENCODING_OPAQUE;
++ vlc_to_mmal_video_fmt(sys->input->format, &filter->fmt_in.video);
-static void flush(filter_t *filter)
-{
- filter_sys_t *sys = filter->p_sys;
- MMAL_BUFFER_HEADER_T *buffer;
-+ status = port_parameter_set_uint32(sys->output, MMAL_PARAMETER_EXTRA_BUFFERS, 5);
-+ if (status != MMAL_SUCCESS) {
-+ msg_Err(filter, "Failed to set MMAL_PARAMETER_EXTRA_BUFFERS on output port (status=%"PRIx32" %s)",
-+ status, mmal_status_to_string(status));
-+ goto fail;
-+ }
++ es_format_Copy(&filter->fmt_out, &filter->fmt_in);
++ if (!sys->half_rate)
++ filter->fmt_out.video.i_frame_rate *= 2;
- msg_Dbg(filter, "flush deinterlace filter");
-+ status = port_parameter_set_bool(sys->output, MMAL_PARAMETER_ZERO_COPY, true);
++ status = mmal_port_format_commit(sys->input);
+ if (status != MMAL_SUCCESS) {
-+ msg_Err(filter, "Failed to set zero copy on port %s (status=%"PRIx32" %s)",
-+ sys->output->name, status, mmal_status_to_string(status));
-+ goto fail;
++ msg_Err(filter, "Failed to commit format for input port %s (status=%"PRIx32" %s)",
++ sys->input->name, status, mmal_status_to_string(status));
++ goto fail;
+ }
++ sys->input->buffer_size = sys->input->buffer_size_recommended;
++ sys->input->buffer_num = 30;
++// sys->input->buffer_num = sys->input->buffer_num_recommended;
- msg_Dbg(filter, "flush: flush ports (input: %d, output: %d in transit)",
- sys->input_in_transit, sys->output_in_transit);
@@ -3499,10 +3747,9 @@
- msg_Dbg(filter, "flush: release already filtered pic %p",
- (void *)pic);
- picture_Release(pic);
-+ status = mmal_port_format_commit(sys->output);
-+ if (status != MMAL_SUCCESS) {
-+ msg_Err(filter, "Failed to commit format for output port %s (status=%"PRIx32" %s)",
-+ sys->input->name, status, mmal_status_to_string(status));
++ if ((sys->in_pool = mmal_pool_create(sys->input->buffer_num, 0)) == NULL)
++ {
++ msg_Err(filter, "Failed to create input pool");
+ goto fail;
}
- atomic_store(&sys->started, false);
@@ -3513,36 +3760,35 @@
-{
- filter_t *filter = (filter_t *)port->userdata;
- MMAL_STATUS_T status;
-+ sys->output->buffer_size = sys->output->buffer_size_recommended;
-+ sys->output->buffer_num = 30;
-+// sys->output->buffer_num = sys->output->buffer_num_recommended;
++ status = port_parameter_set_bool(sys->input, MMAL_PARAMETER_ZERO_COPY, true);
++ if (status != MMAL_SUCCESS) {
++ msg_Err(filter, "Failed to set zero copy on port %s (status=%"PRIx32" %s)",
++ sys->input->name, status, mmal_status_to_string(status));
++ goto fail;
++ }
- if (buffer->cmd == MMAL_EVENT_ERROR) {
- status = *(uint32_t *)buffer->data;
- msg_Err(filter, "MMAL error %"PRIx32" \"%s\"", status,
- mmal_status_to_string(status));
-+ if ((sys->out_q = mmal_queue_create()) == NULL)
-+ {
-+ msg_Err(filter, "Failed to create out Q");
++ status = mmal_port_enable(sys->input, di_input_port_cb);
++ if (status != MMAL_SUCCESS) {
++ msg_Err(filter, "Failed to enable input port %s (status=%"PRIx32" %s)",
++ sys->input->name, status, mmal_status_to_string(status));
+ goto fail;
}
- mmal_buffer_header_release(buffer);
-}
-+ if ((sys->in_pool = mmal_pool_create(sys->input->buffer_num, 0)) == NULL)
-+ {
-+ msg_Err(filter, "Failed to create input pool");
-+ goto fail;
-+ }
-static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
-{
- picture_t *picture = (picture_t *)buffer->user_data;
- filter_t *filter = (filter_t *)port->userdata;
- filter_sys_t *sys = filter->p_sys;
-+ sys->out_ppr = hw_mmal_port_pool_ref_create(sys->output, sys->output->buffer_num, sys->output->buffer_size);
-+ if (sys->out_ppr == NULL) {
-+ msg_Err(filter, "Failed to create output pool");
++ if ((sys->out_q = mmal_queue_create()) == NULL)
++ {
++ msg_Err(filter, "Failed to create out Q");
+ goto fail;
+ }
@@ -3551,22 +3797,21 @@
- } else {
- msg_Warn(filter, "Got buffer without picture on input port - OOOPS");
- mmal_buffer_header_release(buffer);
-+ status = mmal_port_enable(sys->output, di_output_port_cb);
-+ if (status != MMAL_SUCCESS) {
-+ msg_Err(filter, "Failed to enable output port %s (status=%"PRIx32" %s)",
-+ sys->output->name, status, mmal_status_to_string(status));
++ sys->output = sys->component->output[0];
++ mmal_format_full_copy(sys->output->format, sys->input->format);
++
++ if ((status = hw_mmal_opaque_output(VLC_OBJECT(filter), &sys->out_ppr, sys->output, 5, di_output_port_cb)) != MMAL_SUCCESS)
+ goto fail;
- }
-
-- atomic_fetch_sub(&sys->input_in_transit, 1);
-- vlc_sem_post(&sys->sem);
++
+ status = mmal_component_enable(sys->component);
+ if (status != MMAL_SUCCESS) {
+ msg_Err(filter, "Failed to enable component %s (status=%"PRIx32" %s)",
+ sys->component->name, status, mmal_status_to_string(status));
+ goto fail;
-+ }
-+
+ }
+
+- atomic_fetch_sub(&sys->input_in_transit, 1);
+- vlc_sem_post(&sys->sem);
+ filter->pf_video_filter = deinterlace;
+ filter->pf_flush = di_flush;
+ return 0;
@@ -3623,9 +3868,2287 @@
- mmal_buffer_header_release(buffer);
- }
-}
+--- /dev/null
++++ b/modules/hw/mmal/mmal_avcodec.c
+@@ -0,0 +1,2275 @@
++/*****************************************************************************
++ * video.c: video decoder using the libavcodec library
++ *****************************************************************************
++ * Copyright (C) 1999-2001 VLC authors and VideoLAN
++ * $Id$
++ *
++ * Authors: Laurent Aimar <fenrir(a)via.ecp.fr>
++ * Gildas Bazin <gbazin(a)videolan.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as published by
++ * the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
++ *****************************************************************************/
++
++/*****************************************************************************
++ * Preamble
++ *****************************************************************************/
++#ifdef HAVE_CONFIG_H
++# include "config.h"
++#endif
++
++#include <vlc_plugin.h>
++#include <vlc_common.h>
++#include <vlc_codec.h>
++#include <vlc_avcodec.h>
++#include <vlc_cpu.h>
++#include <vlc_atomic.h>
++#include <assert.h>
++
++#include "../../codec/avcodec/avcommon.h"
++
++#include <interface/mmal/mmal.h>
++
++#include <libavcodec/avcodec.h>
++#include <libavutil/mem.h>
++#include <libavutil/pixdesc.h>
++#include <libavcodec/rpi_zc.h>
++#if (LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT( 55, 16, 101 ) )
++#include <libavutil/mastering_display_metadata.h>
++#endif
++
++#include "mmal_picture.h"
++
++#define TRACE_ALL 0
++
++#define AVPROVIDER(lib) ((lib##_VERSION_MICRO < 100) ? "libav" : "ffmpeg")
++
++#ifdef HAVE_LIBAVCODEC_AVCODEC_H
++#include <libavcodec/avcodec.h>
++
++/* LIBAVCODEC_VERSION_CHECK checks for the right version of libav and FFmpeg
++ * a is the major version
++ * b and c the minor and micro versions of libav
++ * d and e the minor and micro versions of FFmpeg */
++#define LIBAVCODEC_VERSION_CHECK( a, b, c, d, e ) \
++ ( (LIBAVCODEC_VERSION_MICRO < 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT( a, b, c ) ) || \
++ (LIBAVCODEC_VERSION_MICRO >= 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT( a, d, e ) ) )
++
++#ifndef AV_CODEC_FLAG_OUTPUT_CORRUPT
++# define AV_CODEC_FLAG_OUTPUT_CORRUPT CODEC_FLAG_OUTPUT_CORRUPT
++#endif
++#ifndef AV_CODEC_FLAG_GRAY
++# define AV_CODEC_FLAG_GRAY CODEC_FLAG_GRAY
++#endif
++#ifndef AV_CODEC_FLAG_DR1
++# define AV_CODEC_FLAG_DR1 CODEC_FLAG_DR1
++#endif
++#ifndef AV_CODEC_FLAG_DELAY
++# define AV_CODEC_FLAG_DELAY CODEC_FLAG_DELAY
++#endif
++#ifndef AV_CODEC_FLAG2_FAST
++# define AV_CODEC_FLAG2_FAST CODEC_FLAG2_FAST
++#endif
++#ifndef FF_INPUT_BUFFER_PADDING_SIZE
++# define FF_INPUT_BUFFER_PADDING_SIZE AV_INPUT_BUFFER_PADDING_SIZE
++#endif
++#ifndef AV_CODEC_FLAG_INTERLACED_DCT
++# define AV_CODEC_FLAG_INTERLACED_DCT CODEC_FLAG_INTERLACED_DCT
++#endif
++#ifndef AV_CODEC_FLAG_INTERLACED_ME
++# define AV_CODEC_FLAG_INTERLACED_ME CODEC_FLAG_INTERLACED_ME
++#endif
++#ifndef AV_CODEC_FLAG_GLOBAL_HEADER
++# define AV_CODEC_FLAG_GLOBAL_HEADER CODEC_FLAG_GLOBAL_HEADER
++#endif
++#ifndef AV_CODEC_FLAG_LOW_DELAY
++# define AV_CODEC_FLAG_LOW_DELAY CODEC_FLAG_LOW_DELAY
++#endif
++#ifndef AV_CODEC_CAP_SMALL_LAST_FRAME
++# define AV_CODEC_CAP_SMALL_LAST_FRAME CODEC_CAP_SMALL_LAST_FRAME
++#endif
++#ifndef AV_INPUT_BUFFER_MIN_SIZE
++# define AV_INPUT_BUFFER_MIN_SIZE FF_MIN_BUFFER_SIZE
++#endif
++#ifndef FF_MAX_B_FRAMES
++# define FF_MAX_B_FRAMES 16 // FIXME: remove this
++#endif
++
++#endif /* HAVE_LIBAVCODEC_AVCODEC_H */
++
++#ifdef HAVE_LIBAVUTIL_AVUTIL_H
++# include <libavutil/avutil.h>
++
++/* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg
++ * a is the major version
++ * b and c the minor and micro versions of libav
++ * d and e the minor and micro versions of FFmpeg */
++#define LIBAVUTIL_VERSION_CHECK( a, b, c, d, e ) \
++ ( (LIBAVUTIL_VERSION_MICRO < 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT( a, b, c ) ) || \
++ (LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT( a, d, e ) ) )
++
++#if !LIBAVUTIL_VERSION_CHECK( 52, 11, 0, 32, 100 )
++# define AV_PIX_FMT_FLAG_HWACCEL PIX_FMT_HWACCEL
++#endif
++
++#endif /* HAVE_LIBAVUTIL_AVUTIL_H */
++
++#if LIBAVUTIL_VERSION_MAJOR >= 55
++# define FF_API_AUDIOCONVERT 1
++#endif
++
++/* libavutil/pixfmt.h */
++#ifndef PixelFormat
++# define PixelFormat AVPixelFormat
++#endif
++
++#ifdef HAVE_LIBAVFORMAT_AVFORMAT_H
++# include <libavformat/avformat.h>
++
++#define LIBAVFORMAT_VERSION_CHECK( a, b, c, d, e ) \
++ ( (LIBAVFORMAT_VERSION_MICRO < 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT( a, b, c ) ) || \
++ (LIBAVFORMAT_VERSION_MICRO >= 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT( a, d, e ) ) )
++
++#endif
++
++/*****************************************************************************
++ * Codec fourcc -> libavcodec Codec_id mapping
++ * Sorted by AVCodecID enumeration order
++ *****************************************************************************/
++struct vlc_avcodec_fourcc
++{
++ vlc_fourcc_t i_fourcc;
++ unsigned i_codec;
++};
++
++/*
++ * Video Codecs
++ */
++static const struct vlc_avcodec_fourcc video_codecs[] =
++{
++ { VLC_CODEC_MP1V, AV_CODEC_ID_MPEG1VIDEO },
++ { VLC_CODEC_MP2V, AV_CODEC_ID_MPEG2VIDEO }, /* prefer MPEG2 over MPEG1 */
++ { VLC_CODEC_MPGV, AV_CODEC_ID_MPEG2VIDEO }, /* prefer MPEG2 over MPEG1 */
++ /* AV_CODEC_ID_MPEG2VIDEO_XVMC */
++ { VLC_CODEC_H261, AV_CODEC_ID_H261 },
++ { VLC_CODEC_H263, AV_CODEC_ID_H263 },
++ { VLC_CODEC_RV10, AV_CODEC_ID_RV10 },
++ { VLC_CODEC_RV13, AV_CODEC_ID_RV10 },
++ { VLC_CODEC_RV20, AV_CODEC_ID_RV20 },
++ { VLC_CODEC_MJPG, AV_CODEC_ID_MJPEG },
++ { VLC_CODEC_MJPGB, AV_CODEC_ID_MJPEGB },
++ { VLC_CODEC_LJPG, AV_CODEC_ID_LJPEG },
++ { VLC_CODEC_SP5X, AV_CODEC_ID_SP5X },
++ { VLC_CODEC_JPEGLS, AV_CODEC_ID_JPEGLS },
++ { VLC_CODEC_MP4V, AV_CODEC_ID_MPEG4 },
++ /* AV_CODEC_ID_RAWVIDEO */
++ { VLC_CODEC_DIV1, AV_CODEC_ID_MSMPEG4V1 },
++ { VLC_CODEC_DIV2, AV_CODEC_ID_MSMPEG4V2 },
++ { VLC_CODEC_DIV3, AV_CODEC_ID_MSMPEG4V3 },
++ { VLC_CODEC_WMV1, AV_CODEC_ID_WMV1 },
++ { VLC_CODEC_WMV2, AV_CODEC_ID_WMV2 },
++ { VLC_CODEC_H263P, AV_CODEC_ID_H263P },
++ { VLC_CODEC_H263I, AV_CODEC_ID_H263I },
++ { VLC_CODEC_FLV1, AV_CODEC_ID_FLV1 },
++ { VLC_CODEC_SVQ1, AV_CODEC_ID_SVQ1 },
++ { VLC_CODEC_SVQ3, AV_CODEC_ID_SVQ3 },
++ { VLC_CODEC_DV, AV_CODEC_ID_DVVIDEO },
++ { VLC_CODEC_HUFFYUV, AV_CODEC_ID_HUFFYUV },
++ { VLC_CODEC_CYUV, AV_CODEC_ID_CYUV },
++ { VLC_CODEC_H264, AV_CODEC_ID_H264 },
++ { VLC_CODEC_INDEO3, AV_CODEC_ID_INDEO3 },
++ { VLC_CODEC_VP3, AV_CODEC_ID_VP3 },
++ { VLC_CODEC_THEORA, AV_CODEC_ID_THEORA },
++#if ( !defined( WORDS_BIGENDIAN ) )
++ /* Asus Video (Another thing that doesn't work on PPC) */
++ { VLC_CODEC_ASV1, AV_CODEC_ID_ASV1 },
++ { VLC_CODEC_ASV2, AV_CODEC_ID_ASV2 },
++#endif
++ { VLC_CODEC_FFV1, AV_CODEC_ID_FFV1 },
++ { VLC_CODEC_4XM, AV_CODEC_ID_4XM },
++ { VLC_CODEC_VCR1, AV_CODEC_ID_VCR1 },
++ { VLC_CODEC_CLJR, AV_CODEC_ID_CLJR },
++ { VLC_CODEC_MDEC, AV_CODEC_ID_MDEC },
++ { VLC_CODEC_ROQ, AV_CODEC_ID_ROQ },
++ { VLC_CODEC_INTERPLAY, AV_CODEC_ID_INTERPLAY_VIDEO },
++ { VLC_CODEC_XAN_WC3, AV_CODEC_ID_XAN_WC3 },
++ { VLC_CODEC_XAN_WC4, AV_CODEC_ID_XAN_WC4 },
++ { VLC_CODEC_RPZA, AV_CODEC_ID_RPZA },
++ { VLC_CODEC_CINEPAK, AV_CODEC_ID_CINEPAK },
++ { VLC_CODEC_WS_VQA, AV_CODEC_ID_WS_VQA },
++ { VLC_CODEC_MSRLE, AV_CODEC_ID_MSRLE },
++ { VLC_CODEC_MSVIDEO1, AV_CODEC_ID_MSVIDEO1 },
++ { VLC_CODEC_IDCIN, AV_CODEC_ID_IDCIN },
++ { VLC_CODEC_8BPS, AV_CODEC_ID_8BPS },
++ { VLC_CODEC_SMC, AV_CODEC_ID_SMC },
++ { VLC_CODEC_FLIC, AV_CODEC_ID_FLIC },
++ { VLC_CODEC_TRUEMOTION1, AV_CODEC_ID_TRUEMOTION1 },
++ { VLC_CODEC_VMDVIDEO, AV_CODEC_ID_VMDVIDEO },
++ { VLC_CODEC_LCL_MSZH, AV_CODEC_ID_MSZH },
++ { VLC_CODEC_LCL_ZLIB, AV_CODEC_ID_ZLIB },
++ { VLC_CODEC_QTRLE, AV_CODEC_ID_QTRLE },
++ { VLC_CODEC_TSCC, AV_CODEC_ID_TSCC },
++ { VLC_CODEC_ULTI, AV_CODEC_ID_ULTI },
++ { VLC_CODEC_QDRAW, AV_CODEC_ID_QDRAW },
++ { VLC_CODEC_VIXL, AV_CODEC_ID_VIXL },
++ { VLC_CODEC_QPEG, AV_CODEC_ID_QPEG },
++ { VLC_CODEC_PNG, AV_CODEC_ID_PNG },
++ { VLC_CODEC_PPM, AV_CODEC_ID_PPM },
++ /* AV_CODEC_ID_PBM */
++ { VLC_CODEC_PGM, AV_CODEC_ID_PGM },
++ { VLC_CODEC_PGMYUV, AV_CODEC_ID_PGMYUV },
++ { VLC_CODEC_PAM, AV_CODEC_ID_PAM },
++ { VLC_CODEC_FFVHUFF, AV_CODEC_ID_FFVHUFF },
++ { VLC_CODEC_RV30, AV_CODEC_ID_RV30 },
++ { VLC_CODEC_RV40, AV_CODEC_ID_RV40 },
++ { VLC_CODEC_VC1, AV_CODEC_ID_VC1 },
++ { VLC_CODEC_WMVA, AV_CODEC_ID_VC1 },
++ { VLC_CODEC_WMV3, AV_CODEC_ID_WMV3 },
++ { VLC_CODEC_WMVP, AV_CODEC_ID_WMV3 },
++ { VLC_CODEC_LOCO, AV_CODEC_ID_LOCO },
++ { VLC_CODEC_WNV1, AV_CODEC_ID_WNV1 },
++ { VLC_CODEC_AASC, AV_CODEC_ID_AASC },
++ { VLC_CODEC_INDEO2, AV_CODEC_ID_INDEO2 },
++ { VLC_CODEC_FRAPS, AV_CODEC_ID_FRAPS },
++ { VLC_CODEC_TRUEMOTION2, AV_CODEC_ID_TRUEMOTION2 },
++ { VLC_CODEC_BMP, AV_CODEC_ID_BMP },
++ { VLC_CODEC_CSCD, AV_CODEC_ID_CSCD },
++ { VLC_CODEC_MMVIDEO, AV_CODEC_ID_MMVIDEO },
++ { VLC_CODEC_ZMBV, AV_CODEC_ID_ZMBV },
++ { VLC_CODEC_AVS, AV_CODEC_ID_AVS },
++ { VLC_CODEC_SMACKVIDEO, AV_CODEC_ID_SMACKVIDEO },
++ { VLC_CODEC_NUV, AV_CODEC_ID_NUV },
++ { VLC_CODEC_KMVC, AV_CODEC_ID_KMVC },
++ { VLC_CODEC_FLASHSV, AV_CODEC_ID_FLASHSV },
++ { VLC_CODEC_CAVS, AV_CODEC_ID_CAVS },
++ { VLC_CODEC_JPEG2000, AV_CODEC_ID_JPEG2000 },
++ { VLC_CODEC_VMNC, AV_CODEC_ID_VMNC },
++ { VLC_CODEC_VP5, AV_CODEC_ID_VP5 },
++ { VLC_CODEC_VP6, AV_CODEC_ID_VP6 },
++ { VLC_CODEC_VP6F, AV_CODEC_ID_VP6F },
++ { VLC_CODEC_TARGA, AV_CODEC_ID_TARGA },
++ { VLC_CODEC_DSICINVIDEO, AV_CODEC_ID_DSICINVIDEO },
++ { VLC_CODEC_TIERTEXSEQVIDEO, AV_CODEC_ID_TIERTEXSEQVIDEO },
++ { VLC_CODEC_TIFF, AV_CODEC_ID_TIFF },
++ { VLC_CODEC_GIF, AV_CODEC_ID_GIF },
++ { VLC_CODEC_DXA, AV_CODEC_ID_DXA },
++ { VLC_CODEC_DNXHD, AV_CODEC_ID_DNXHD },
++ { VLC_CODEC_THP, AV_CODEC_ID_THP },
++ { VLC_CODEC_SGI, AV_CODEC_ID_SGI },
++ { VLC_CODEC_C93, AV_CODEC_ID_C93 },
++ { VLC_CODEC_BETHSOFTVID, AV_CODEC_ID_BETHSOFTVID },
++ /* AV_CODEC_ID_PTX */
++ { VLC_CODEC_TXD, AV_CODEC_ID_TXD },
++ { VLC_CODEC_VP6A, AV_CODEC_ID_VP6A },
++ { VLC_CODEC_AMV, AV_CODEC_ID_AMV },
++ { VLC_CODEC_VB, AV_CODEC_ID_VB },
++ { VLC_CODEC_PCX, AV_CODEC_ID_PCX },
++ /* AV_CODEC_ID_SUNRAST */
++ { VLC_CODEC_INDEO4, AV_CODEC_ID_INDEO4 },
++ { VLC_CODEC_INDEO5, AV_CODEC_ID_INDEO5 },
++ { VLC_CODEC_MIMIC, AV_CODEC_ID_MIMIC },
++ { VLC_CODEC_RL2, AV_CODEC_ID_RL2 },
++ { VLC_CODEC_ESCAPE124, AV_CODEC_ID_ESCAPE124 },
++ { VLC_CODEC_DIRAC, AV_CODEC_ID_DIRAC },
++ { VLC_CODEC_BFI, AV_CODEC_ID_BFI },
++ { VLC_CODEC_CMV, AV_CODEC_ID_CMV },
++ { VLC_CODEC_MOTIONPIXELS, AV_CODEC_ID_MOTIONPIXELS },
++ { VLC_CODEC_TGV, AV_CODEC_ID_TGV },
++ { VLC_CODEC_TGQ, AV_CODEC_ID_TGQ },
++ { VLC_CODEC_TQI, AV_CODEC_ID_TQI },
++ { VLC_CODEC_AURA, AV_CODEC_ID_AURA },
++ /* AV_CODEC_ID_AURA2 */
++ /* AV_CODEC_ID_V210X */
++ { VLC_CODEC_TMV, AV_CODEC_ID_TMV },
++ { VLC_CODEC_V210, AV_CODEC_ID_V210 },
++ /* AV_CODEC_ID_DPX */
++ { VLC_CODEC_MAD, AV_CODEC_ID_MAD },
++ { VLC_CODEC_FRWU, AV_CODEC_ID_FRWU },
++ { VLC_CODEC_FLASHSV2, AV_CODEC_ID_FLASHSV2 },
++ /* AV_CODEC_ID_CDGRAPHICS */
++ /* AV_CODEC_ID_R210 */
++ { VLC_CODEC_ANM, AV_CODEC_ID_ANM },
++ { VLC_CODEC_BINKVIDEO, AV_CODEC_ID_BINKVIDEO },
++ /* AV_CODEC_ID_IFF_ILBM */
++ /* AV_CODEC_ID_IFF_BYTERUN1 */
++ { VLC_CODEC_KGV1, AV_CODEC_ID_KGV1 },
++ { VLC_CODEC_YOP, AV_CODEC_ID_YOP },
++ { VLC_CODEC_VP8, AV_CODEC_ID_VP8 },
++ /* AV_CODEC_ID_PICTOR */
++ /* AV_CODEC_ID_ANSI */
++ /* AV_CODEC_ID_A64_MULTI */
++ /* AV_CODEC_ID_A64_MULTI5 */
++ /* AV_CODEC_ID_R10K */
++ { VLC_CODEC_MXPEG, AV_CODEC_ID_MXPEG },
++ { VLC_CODEC_LAGARITH, AV_CODEC_ID_LAGARITH },
++ { VLC_CODEC_PRORES, AV_CODEC_ID_PRORES },
++ { VLC_CODEC_JV, AV_CODEC_ID_JV },
++ { VLC_CODEC_DFA, AV_CODEC_ID_DFA },
++ { VLC_CODEC_WMVP, AV_CODEC_ID_WMV3IMAGE },
++ { VLC_CODEC_WMVP2, AV_CODEC_ID_VC1IMAGE },
++ { VLC_CODEC_UTVIDEO, AV_CODEC_ID_UTVIDEO },
++ { VLC_CODEC_BMVVIDEO, AV_CODEC_ID_BMV_VIDEO },
++ { VLC_CODEC_VBLE, AV_CODEC_ID_VBLE },
++ { VLC_CODEC_DXTORY, AV_CODEC_ID_DXTORY },
++ /* AV_CODEC_ID_V410 */
++ /* AV_CODEC_ID_XWD */
++ { VLC_CODEC_CDXL, AV_CODEC_ID_CDXL },
++ /* AV_CODEC_ID_XBM */
++ /* AV_CODEC_ID_ZEROCODEC */
++ { VLC_CODEC_MSS1, AV_CODEC_ID_MSS1 },
++ { VLC_CODEC_MSA1, AV_CODEC_ID_MSA1 },
++ { VLC_CODEC_TSC2, AV_CODEC_ID_TSCC2 },
++ { VLC_CODEC_MTS2, AV_CODEC_ID_MTS2 },
++ { VLC_CODEC_CLLC, AV_CODEC_ID_CLLC },
++ { VLC_CODEC_MSS2, AV_CODEC_ID_MSS2 },
++ { VLC_CODEC_VP9, AV_CODEC_ID_VP9 },
++#if LIBAVCODEC_VERSION_CHECK( 57, 26, 0, 83, 101 )
++ { VLC_CODEC_AV1, AV_CODEC_ID_AV1 },
++#endif
++ { VLC_CODEC_ICOD, AV_CODEC_ID_AIC },
++ /* AV_CODEC_ID_ESCAPE130 */
++ { VLC_CODEC_G2M4, AV_CODEC_ID_G2M },
++ { VLC_CODEC_G2M2, AV_CODEC_ID_G2M },
++ { VLC_CODEC_G2M3, AV_CODEC_ID_G2M },
++ /* AV_CODEC_ID_WEBP */
++ { VLC_CODEC_HNM4_VIDEO, AV_CODEC_ID_HNM4_VIDEO },
++ { VLC_CODEC_HEVC, AV_CODEC_ID_HEVC },
++
++ { VLC_CODEC_FIC , AV_CODEC_ID_FIC },
++ /* AV_CODEC_ID_ALIAS_PIX */
++ /* AV_CODEC_ID_BRENDER_PIX */
++ /* AV_CODEC_ID_PAF_VIDEO */
++ /* AV_CODEC_ID_EXR */
++
++ { VLC_CODEC_VP7 , AV_CODEC_ID_VP7 },
++ /* AV_CODEC_ID_SANM */
++ /* AV_CODEC_ID_SGIRLE */
++ /* AV_CODEC_ID_MVC1 */
++ /* AV_CODEC_ID_MVC2 */
++ { VLC_CODEC_HQX, AV_CODEC_ID_HQX },
++
++ { VLC_CODEC_TDSC, AV_CODEC_ID_TDSC },
++
++ { VLC_CODEC_HQ_HQA, AV_CODEC_ID_HQ_HQA },
++
++ { VLC_CODEC_HAP, AV_CODEC_ID_HAP },
++ /* AV_CODEC_ID_DDS */
++
++ { VLC_CODEC_DXV, AV_CODEC_ID_DXV },
++
++ /* ffmpeg only: AV_CODEC_ID_BRENDER_PIX */
++ /* ffmpeg only: AV_CODEC_ID_Y41P */
++ /* ffmpeg only: AV_CODEC_ID_EXR */
++ /* ffmpeg only: AV_CODEC_ID_AVRP */
++ /* ffmpeg only: AV_CODEC_ID_012V */
++ /* ffmpeg only: AV_CODEC_ID_AVUI */
++ /* ffmpeg only: AV_CODEC_ID_AYUV */
++ /* ffmpeg only: AV_CODEC_ID_TARGA_Y216 */
++ /* ffmpeg only: AV_CODEC_ID_V308 */
++ /* ffmpeg only: AV_CODEC_ID_V408 */
++ /* ffmpeg only: AV_CODEC_ID_YUV4 */
++ /* ffmpeg only: AV_CODEC_ID_SANM */
++ /* ffmpeg only: AV_CODEC_ID_PAF_VIDEO */
++ /* ffmpeg only: AV_CODEC_ID_AVRN */
++ /* ffmpeg only: AV_CODEC_ID_CPIA */
++ /* ffmpeg only: AV_CODEC_ID_XFACE */
++ /* ffmpeg only: AV_CODEC_ID_SGIRLE */
++ /* ffmpeg only: AV_CODEC_ID_MVC1 */
++ /* ffmpeg only: AV_CODEC_ID_MVC2 */
++ /* ffmpeg only: AV_CODEC_ID_SNOW */
++ /* ffmpeg only: AV_CODEC_ID_SMVJPEG */
++
++#if LIBAVCODEC_VERSION_CHECK( 57, 999, 999, 24, 102 )
++ { VLC_CODEC_CINEFORM, AV_CODEC_ID_CFHD },
++#endif
++
++#if LIBAVCODEC_VERSION_CHECK( 57, 999, 999, 70, 100 )
++ { VLC_CODEC_PIXLET, AV_CODEC_ID_PIXLET },
++#endif
++
++#if LIBAVCODEC_VERSION_CHECK( 57, 999, 999, 71, 101 )
++ { VLC_CODEC_SPEEDHQ, AV_CODEC_ID_SPEEDHQ },
++#endif
++
++#if LIBAVCODEC_VERSION_CHECK( 57, 999, 999, 79, 100 )
++ { VLC_CODEC_FMVC, AV_CODEC_ID_FMVC },
++#endif
++};
++
++/*
++ * Audio Codecs
++ */
++static const struct vlc_avcodec_fourcc audio_codecs[] =
++{
++ /* PCM */
++ { VLC_CODEC_S16L, AV_CODEC_ID_PCM_S16LE },
++ { VLC_CODEC_S16B, AV_CODEC_ID_PCM_S16BE },
++ { VLC_CODEC_U16L, AV_CODEC_ID_PCM_U16LE },
++ { VLC_CODEC_U16B, AV_CODEC_ID_PCM_U16BE },
++ { VLC_CODEC_S8, AV_CODEC_ID_PCM_S8 },
++ { VLC_CODEC_U8, AV_CODEC_ID_PCM_U8 },
++ { VLC_CODEC_MULAW, AV_CODEC_ID_PCM_MULAW },
++ { VLC_CODEC_ALAW, AV_CODEC_ID_PCM_ALAW },
++ { VLC_CODEC_S32L, AV_CODEC_ID_PCM_S32LE },
++ { VLC_CODEC_S32B, AV_CODEC_ID_PCM_S32BE },
++ { VLC_CODEC_U32L, AV_CODEC_ID_PCM_U32LE },
++ { VLC_CODEC_U32B, AV_CODEC_ID_PCM_U32BE },
++ { VLC_CODEC_S24L, AV_CODEC_ID_PCM_S24LE },
++ { VLC_CODEC_S24B, AV_CODEC_ID_PCM_S24BE },
++ { VLC_CODEC_U24L, AV_CODEC_ID_PCM_U24LE },
++ { VLC_CODEC_U24B, AV_CODEC_ID_PCM_U24BE },
++ { VLC_CODEC_S24DAUD, AV_CODEC_ID_PCM_S24DAUD },
++ /* AV_CODEC_ID_PCM_ZORK */
++ { VLC_CODEC_S16L_PLANAR, AV_CODEC_ID_PCM_S16LE_PLANAR },
++ /* AV_CODEC_ID_PCM_DVD */
++ { VLC_CODEC_F32B, AV_CODEC_ID_PCM_F32BE },
++ { VLC_CODEC_F32L, AV_CODEC_ID_PCM_F32LE },
++ { VLC_CODEC_F64B, AV_CODEC_ID_PCM_F64BE },
++ { VLC_CODEC_F64L, AV_CODEC_ID_PCM_F64LE },
++ { VLC_CODEC_BD_LPCM, AV_CODEC_ID_PCM_BLURAY },
++ /* AV_CODEC_ID_PCM_LXF */
++ /* AV_CODEC_ID_S302M */
++ /* AV_CODEC_ID_PCM_S8_PLANAR */
++ /* AV_CODEC_ID_PCM_S24LE_PLANAR */
++ /* AV_CODEC_ID_PCM_S32LE_PLANAR */
++ /* ffmpeg only: AV_CODEC_ID_PCM_S16BE_PLANAR */
++
++ /* ADPCM */
++ { VLC_CODEC_ADPCM_IMA_QT, AV_CODEC_ID_ADPCM_IMA_QT },
++ { VLC_CODEC_ADPCM_IMA_WAV, AV_CODEC_ID_ADPCM_IMA_WAV },
++ /* AV_CODEC_ID_ADPCM_IMA_DK3 */
++ /* AV_CODEC_ID_ADPCM_IMA_DK4 */
++ { VLC_CODEC_ADPCM_IMA_WS, AV_CODEC_ID_ADPCM_IMA_WS },
++ /* AV_CODEC_ID_ADPCM_IMA_SMJPEG */
++ { VLC_CODEC_ADPCM_MS, AV_CODEC_ID_ADPCM_MS },
++ { VLC_CODEC_ADPCM_4XM, AV_CODEC_ID_ADPCM_4XM },
++ { VLC_CODEC_ADPCM_XA, AV_CODEC_ID_ADPCM_XA },
++ { VLC_CODEC_ADPCM_ADX, AV_CODEC_ID_ADPCM_ADX },
++ { VLC_CODEC_ADPCM_EA, AV_CODEC_ID_ADPCM_EA },
++ { VLC_CODEC_ADPCM_G726, AV_CODEC_ID_ADPCM_G726 },
++ { VLC_CODEC_ADPCM_CREATIVE, AV_CODEC_ID_ADPCM_CT },
++ { VLC_CODEC_ADPCM_SWF, AV_CODEC_ID_ADPCM_SWF },
++ { VLC_CODEC_ADPCM_YAMAHA, AV_CODEC_ID_ADPCM_YAMAHA },
++ { VLC_CODEC_ADPCM_SBPRO_4, AV_CODEC_ID_ADPCM_SBPRO_4 },
++ { VLC_CODEC_ADPCM_SBPRO_3, AV_CODEC_ID_ADPCM_SBPRO_3 },
++ { VLC_CODEC_ADPCM_SBPRO_2, AV_CODEC_ID_ADPCM_SBPRO_2 },
++ { VLC_CODEC_ADPCM_THP, AV_CODEC_ID_ADPCM_THP },
++ { VLC_CODEC_ADPCM_IMA_AMV, AV_CODEC_ID_ADPCM_IMA_AMV },
++ { VLC_CODEC_ADPCM_EA_R1, AV_CODEC_ID_ADPCM_EA_R1 },
++ /* AV_CODEC_ID_ADPCM_EA_R3 */
++ /* AV_CODEC_ID_ADPCM_EA_R2 */
++ { VLC_CODEC_ADPCM_IMA_EA_SEAD, AV_CODEC_ID_ADPCM_IMA_EA_SEAD },
++ /* AV_CODEC_ID_ADPCM_IMA_EA_EACS */
++ /* AV_CODEC_ID_ADPCM_EA_XAS */
++ /* AV_CODEC_ID_ADPCM_EA_MAXIS_XA */
++ /* AV_CODEC_ID_ADPCM_IMA_ISS */
++ { VLC_CODEC_ADPCM_G722, AV_CODEC_ID_ADPCM_G722 },
++ { VLC_CODEC_ADPCM_IMA_APC, AV_CODEC_ID_ADPCM_IMA_APC },
++ /* ffmpeg only: AV_CODEC_ID_VIMA */
++ /* ffmpeg only: AV_CODEC_ID_ADPCM_AFC */
++ /* ffmpeg only: AV_CODEC_ID_ADPCM_IMA_OKI */
++ /* ffmpeg only: AV_CODEC_ID_ADPCM_DTK */
++ /* ffmpeg only: AV_CODEC_ID_ADPCM_IMA_RAD */
++ /* ffmpeg only: AV_CODEC_ID_ADPCM_G726LE */
++
++ /* AMR */
++ { VLC_CODEC_AMR_NB, AV_CODEC_ID_AMR_NB },
++ { VLC_CODEC_AMR_WB, AV_CODEC_ID_AMR_WB },
++
++ /* RealAudio */
++ { VLC_CODEC_RA_144, AV_CODEC_ID_RA_144 },
++ { VLC_CODEC_RA_288, AV_CODEC_ID_RA_288 },
++
++ /* DPCM */
++ { VLC_CODEC_ROQ_DPCM, AV_CODEC_ID_ROQ_DPCM },
++ { VLC_CODEC_INTERPLAY_DPCM, AV_CODEC_ID_INTERPLAY_DPCM },
++ /* AV_CODEC_ID_XAN_DPCM */
++ /* AV_CODEC_ID_SOL_DPCM */
++
++ /* audio codecs */
++ { VLC_CODEC_MPGA, AV_CODEC_ID_MP2 },
++ { VLC_CODEC_MP2, AV_CODEC_ID_MP2 },
++ { VLC_CODEC_MP3, AV_CODEC_ID_MP3 },
++ { VLC_CODEC_MP4A, AV_CODEC_ID_AAC },
++ { VLC_CODEC_A52, AV_CODEC_ID_AC3 },
++ { VLC_CODEC_DTS, AV_CODEC_ID_DTS },
++ { VLC_CODEC_VORBIS, AV_CODEC_ID_VORBIS },
++ { VLC_CODEC_DVAUDIO, AV_CODEC_ID_DVAUDIO },
++ { VLC_CODEC_WMA1, AV_CODEC_ID_WMAV1 },
++ { VLC_CODEC_WMA2, AV_CODEC_ID_WMAV2 },
++ { VLC_CODEC_MACE3, AV_CODEC_ID_MACE3 },
++ { VLC_CODEC_MACE6, AV_CODEC_ID_MACE6 },
++ { VLC_CODEC_VMDAUDIO, AV_CODEC_ID_VMDAUDIO },
++ { VLC_CODEC_FLAC, AV_CODEC_ID_FLAC },
++ /* AV_CODEC_ID_MP3ADU */
++ /* AV_CODEC_ID_MP3ON4 */
++ { VLC_CODEC_SHORTEN, AV_CODEC_ID_SHORTEN },
++ { VLC_CODEC_ALAC, AV_CODEC_ID_ALAC },
++ /* AV_CODEC_ID_WESTWOOD_SND1 */
++ { VLC_CODEC_GSM, AV_CODEC_ID_GSM },
++ { VLC_CODEC_QDM2, AV_CODEC_ID_QDM2 },
++#if LIBAVCODEC_VERSION_CHECK( 57, 999, 999, 71, 100 )
++ { VLC_CODEC_QDMC, AV_CODEC_ID_QDMC },
++#endif
++ { VLC_CODEC_COOK, AV_CODEC_ID_COOK },
++ { VLC_CODEC_TRUESPEECH, AV_CODEC_ID_TRUESPEECH },
++ { VLC_CODEC_TTA, AV_CODEC_ID_TTA },
++ { VLC_CODEC_SMACKAUDIO, AV_CODEC_ID_SMACKAUDIO },
++ { VLC_CODEC_QCELP, AV_CODEC_ID_QCELP },
++ { VLC_CODEC_WAVPACK, AV_CODEC_ID_WAVPACK },
++ { VLC_CODEC_DSICINAUDIO, AV_CODEC_ID_DSICINAUDIO },
++ { VLC_CODEC_IMC, AV_CODEC_ID_IMC },
++ { VLC_CODEC_MUSEPACK7, AV_CODEC_ID_MUSEPACK7 },
++ { VLC_CODEC_MLP, AV_CODEC_ID_MLP },
++ { VLC_CODEC_GSM_MS, AV_CODEC_ID_GSM_MS },
++ { VLC_CODEC_ATRAC3, AV_CODEC_ID_ATRAC3 },
++ { VLC_CODEC_APE, AV_CODEC_ID_APE },
++ { VLC_CODEC_NELLYMOSER, AV_CODEC_ID_NELLYMOSER },
++ { VLC_CODEC_MUSEPACK8, AV_CODEC_ID_MUSEPACK8 },
++ { VLC_CODEC_SPEEX, AV_CODEC_ID_SPEEX },
++ { VLC_CODEC_WMAS, AV_CODEC_ID_WMAVOICE },
++ { VLC_CODEC_WMAP, AV_CODEC_ID_WMAPRO },
++ { VLC_CODEC_WMAL, AV_CODEC_ID_WMALOSSLESS },
++ { VLC_CODEC_ATRAC3P, AV_CODEC_ID_ATRAC3P },
++ { VLC_CODEC_EAC3, AV_CODEC_ID_EAC3 },
++ { VLC_CODEC_SIPR, AV_CODEC_ID_SIPR },
++ /* AV_CODEC_ID_MP1 */
++ { VLC_CODEC_TWINVQ, AV_CODEC_ID_TWINVQ },
++ { VLC_CODEC_TRUEHD, AV_CODEC_ID_TRUEHD },
++ { VLC_CODEC_ALS, AV_CODEC_ID_MP4ALS },
++ { VLC_CODEC_ATRAC1, AV_CODEC_ID_ATRAC1 },
++ { VLC_CODEC_BINKAUDIO_RDFT, AV_CODEC_ID_BINKAUDIO_RDFT },
++ { VLC_CODEC_BINKAUDIO_DCT, AV_CODEC_ID_BINKAUDIO_DCT },
++ { VLC_CODEC_MP4A, AV_CODEC_ID_AAC_LATM },
++ /* AV_CODEC_ID_QDMC */
++ /* AV_CODEC_ID_CELT */
++ { VLC_CODEC_G723_1, AV_CODEC_ID_G723_1 },
++ /* AV_CODEC_ID_G729 */
++ /* AV_CODEC_ID_8SVX_EXP */
++ /* AV_CODEC_ID_8SVX_FIB */
++ { VLC_CODEC_BMVAUDIO, AV_CODEC_ID_BMV_AUDIO },
++ { VLC_CODEC_RALF, AV_CODEC_ID_RALF },
++ { VLC_CODEC_INDEO_AUDIO, AV_CODEC_ID_IAC },
++ /* AV_CODEC_ID_ILBC */
++ { VLC_CODEC_OPUS, AV_CODEC_ID_OPUS },
++ /* AV_CODEC_ID_COMFORT_NOISE */
++ { VLC_CODEC_TAK, AV_CODEC_ID_TAK },
++ { VLC_CODEC_METASOUND, AV_CODEC_ID_METASOUND },
++ /* AV_CODEC_ID_PAF_AUDIO */
++ { VLC_CODEC_ON2AVC, AV_CODEC_ID_ON2AVC },
++
++ /* ffmpeg only: AV_CODEC_ID_FFWAVESYNTH */
++ /* ffmpeg only: AV_CODEC_ID_SONIC */
++ /* ffmpeg only: AV_CODEC_ID_SONIC_LS */
++ /* ffmpeg only: AV_CODEC_ID_PAF_AUDIO */
++ /* ffmpeg only: AV_CODEC_ID_EVRC */
++ /* ffmpeg only: AV_CODEC_ID_SMV */
++};
++
++/* Subtitle streams */
++static const struct vlc_avcodec_fourcc spu_codecs[] =
++{
++ { VLC_CODEC_SPU, AV_CODEC_ID_DVD_SUBTITLE },
++ { VLC_CODEC_DVBS, AV_CODEC_ID_DVB_SUBTITLE },
++ { VLC_CODEC_SUBT, AV_CODEC_ID_TEXT },
++ { VLC_CODEC_XSUB, AV_CODEC_ID_XSUB },
++ { VLC_CODEC_SSA, AV_CODEC_ID_SSA },
++ /* AV_CODEC_ID_MOV_TEXT */
++ { VLC_CODEC_BD_PG, AV_CODEC_ID_HDMV_PGS_SUBTITLE },
++#if LIBAVCODEC_VERSION_CHECK( 57, 999, 999, 71, 100 )
++ { VLC_CODEC_BD_TEXT, AV_CODEC_ID_HDMV_TEXT_SUBTITLE },
++#endif
++ { VLC_CODEC_TELETEXT, AV_CODEC_ID_DVB_TELETEXT },
++ /* AV_CODEC_ID_SRT */
++ /* ffmpeg only: AV_CODEC_ID_MICRODVD */
++ /* ffmpeg only: AV_CODEC_ID_EIA_608 */
++ /* ffmpeg only: AV_CODEC_ID_JACOSUB */
++ /* ffmpeg only: AV_CODEC_ID_SAMI */
++ /* ffmpeg only: AV_CODEC_ID_REALTEXT */
++ /* ffmpeg only: AV_CODEC_ID_SUBVIEWER1 */
++ /* ffmpeg only: AV_CODEC_ID_SUBVIEWER */
++ /* ffmpeg only: AV_CODEC_ID_SUBRIP */
++ /* ffmpeg only: AV_CODEC_ID_WEBVTT */
++ /* ffmpeg only: AV_CODEC_ID_MPL2 */
++ /* ffmpeg only: AV_CODEC_ID_VPLAYER */
++ /* ffmpeg only: AV_CODEC_ID_PJS */
++ /* ffmpeg only: AV_CODEC_ID_ASS */
++};
++
++static bool GetFfmpegCodec( enum es_format_category_e cat, vlc_fourcc_t i_fourcc,
++ unsigned *pi_ffmpeg_codec, const char **ppsz_name )
++{
++ const struct vlc_avcodec_fourcc *base;
++ size_t count;
++
++ switch( cat )
++ {
++ case VIDEO_ES:
++ base = video_codecs;
++ count = ARRAY_SIZE(video_codecs);
++ break;
++ case AUDIO_ES:
++ base = audio_codecs;
++ count = ARRAY_SIZE(audio_codecs);
++ break;
++ case SPU_ES:
++ base = spu_codecs;
++ count = ARRAY_SIZE(spu_codecs);
++ break;
++ default:
++ base = NULL;
++ count = 0;
++ }
++
++ i_fourcc = vlc_fourcc_GetCodec( cat, i_fourcc );
++
++ for( size_t i = 0; i < count; i++ )
++ {
++ if( base[i].i_fourcc == i_fourcc )
++ {
++ if( pi_ffmpeg_codec != NULL )
++ *pi_ffmpeg_codec = base[i].i_codec;
++ if( ppsz_name )
++ *ppsz_name = vlc_fourcc_GetDescription( cat, i_fourcc );
++ return true;
++ }
++ }
++ return false;
++}
++
++/*****************************************************************************
++ * Chroma fourcc -> libavutil pixfmt mapping
++ *****************************************************************************/
++#if defined(WORDS_BIGENDIAN)
++# define VLC_RGB_ES( fcc, leid, beid ) \
++ { fcc, beid, 0, 0, 0 },
++#else
++# define VLC_RGB_ES( fcc, leid, beid ) \
++ { fcc, leid, 0, 0, 0 },
++#endif
++
++#define VLC_RGB( fcc, leid, beid, rmask, gmask, bmask ) \
++ { fcc, leid, rmask, gmask, bmask }, \
++ { fcc, beid, bmask, gmask, rmask }, \
++ VLC_RGB_ES( fcc, leid, beid )
++
++
++static const struct
++{
++ vlc_fourcc_t i_chroma;
++ int i_chroma_id;
++ uint32_t i_rmask;
++ uint32_t i_gmask;
++ uint32_t i_bmask;
++
++} chroma_table[] =
++{
++ // Sand
++// {VLC_CODEC_MMAL_OPAQUE, AV_PIX_FMT_SAND128, 0, 0, 0 },
++ {VLC_CODEC_MMAL_ZC_SAND8, AV_PIX_FMT_SAND128, 0, 0, 0 },
++ {VLC_CODEC_MMAL_ZC_SAND10, AV_PIX_FMT_SAND64_10, 0, 0, 0 },
++
++ /* Planar YUV formats */
++ {VLC_CODEC_I444, AV_PIX_FMT_YUV444P, 0, 0, 0 },
++ {VLC_CODEC_J444, AV_PIX_FMT_YUVJ444P, 0, 0, 0 },
++
++ {VLC_CODEC_I440, AV_PIX_FMT_YUV440P, 0, 0, 0 },
++ {VLC_CODEC_J440, AV_PIX_FMT_YUVJ440P, 0, 0, 0 },
++
++ {VLC_CODEC_I422, AV_PIX_FMT_YUV422P, 0, 0, 0 },
++ {VLC_CODEC_J422, AV_PIX_FMT_YUVJ422P, 0, 0, 0 },
++
++ {VLC_CODEC_I420, AV_PIX_FMT_YUV420P, 0, 0, 0 },
++ {VLC_CODEC_YV12, AV_PIX_FMT_YUV420P, 0, 0, 0 },
++ {VLC_FOURCC('I','Y','U','V'), AV_PIX_FMT_YUV420P, 0, 0, 0 },
++ {VLC_CODEC_J420, AV_PIX_FMT_YUVJ420P, 0, 0, 0 },
++ {VLC_CODEC_I411, AV_PIX_FMT_YUV411P, 0, 0, 0 },
++ {VLC_CODEC_I410, AV_PIX_FMT_YUV410P, 0, 0, 0 },
++ {VLC_FOURCC('Y','V','U','9'), AV_PIX_FMT_YUV410P, 0, 0, 0 },
++
++ {VLC_CODEC_NV12, AV_PIX_FMT_NV12, 0, 0, 0 },
++ {VLC_CODEC_NV21, AV_PIX_FMT_NV21, 0, 0, 0 },
++
++ {VLC_CODEC_I420_9L, AV_PIX_FMT_YUV420P9LE, 0, 0, 0 },
++ {VLC_CODEC_I420_9B, AV_PIX_FMT_YUV420P9BE, 0, 0, 0 },
++ {VLC_CODEC_I420_10L, AV_PIX_FMT_YUV420P10LE, 0, 0, 0 },
++ {VLC_CODEC_I420_10B, AV_PIX_FMT_YUV420P10BE, 0, 0, 0 },
++#if (LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT( 54, 17, 100 ) )
++ {VLC_CODEC_I420_12L, AV_PIX_FMT_YUV420P12LE, 0, 0, 0 },
++ {VLC_CODEC_I420_12B, AV_PIX_FMT_YUV420P12BE, 0, 0, 0 },
++#endif
++ {VLC_CODEC_I420_16L, AV_PIX_FMT_YUV420P16LE, 0, 0, 0 },
++ {VLC_CODEC_I420_16B, AV_PIX_FMT_YUV420P16BE, 0, 0, 0 },
++#ifdef AV_PIX_FMT_P010
++ {VLC_CODEC_P010, AV_PIX_FMT_P010, 0, 0, 0 },
++#endif
++
++ {VLC_CODEC_I422_9L, AV_PIX_FMT_YUV422P9LE, 0, 0, 0 },
++ {VLC_CODEC_I422_9B, AV_PIX_FMT_YUV422P9BE, 0, 0, 0 },
++ {VLC_CODEC_I422_10L, AV_PIX_FMT_YUV422P10LE, 0, 0, 0 },
++ {VLC_CODEC_I422_10B, AV_PIX_FMT_YUV422P10BE, 0, 0, 0 },
++#if (LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT( 54, 17, 100 ) )
++ {VLC_CODEC_I422_12L, AV_PIX_FMT_YUV422P12LE, 0, 0, 0 },
++ {VLC_CODEC_I422_12B, AV_PIX_FMT_YUV422P12BE, 0, 0, 0 },
++#endif
++
++ {VLC_CODEC_YUV420A, AV_PIX_FMT_YUVA420P, 0, 0, 0 },
++ {VLC_CODEC_YUV422A, AV_PIX_FMT_YUVA422P, 0, 0, 0 },
++ {VLC_CODEC_YUVA, AV_PIX_FMT_YUVA444P, 0, 0, 0 },
++
++ {VLC_CODEC_YUVA_444_10L, AV_PIX_FMT_YUVA444P10LE, 0, 0, 0 },
++ {VLC_CODEC_YUVA_444_10B, AV_PIX_FMT_YUVA444P10BE, 0, 0, 0 },
++
++ {VLC_CODEC_I444_9L, AV_PIX_FMT_YUV444P9LE, 0, 0, 0 },
++ {VLC_CODEC_I444_9B, AV_PIX_FMT_YUV444P9BE, 0, 0, 0 },
++ {VLC_CODEC_I444_10L, AV_PIX_FMT_YUV444P10LE, 0, 0, 0 },
++ {VLC_CODEC_I444_10B, AV_PIX_FMT_YUV444P10BE, 0, 0, 0 },
++#if (LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT( 54, 17, 100 ) )
++ {VLC_CODEC_I444_12L, AV_PIX_FMT_YUV444P12LE, 0, 0, 0 },
++ {VLC_CODEC_I444_12B, AV_PIX_FMT_YUV444P12BE, 0, 0, 0 },
++#endif
++ {VLC_CODEC_I444_16L, AV_PIX_FMT_YUV444P16LE, 0, 0, 0 },
++ {VLC_CODEC_I444_16B, AV_PIX_FMT_YUV444P16BE, 0, 0, 0 },
++
++ /* Packed YUV formats */
++ {VLC_CODEC_YUYV, AV_PIX_FMT_YUYV422, 0, 0, 0 },
++ {VLC_FOURCC('Y','U','Y','V'), AV_PIX_FMT_YUYV422, 0, 0, 0 },
++ {VLC_CODEC_UYVY, AV_PIX_FMT_UYVY422, 0, 0, 0 },
++ {VLC_CODEC_YVYU, AV_PIX_FMT_YVYU422, 0, 0, 0 },
++ {VLC_FOURCC('Y','4','1','1'), AV_PIX_FMT_UYYVYY411, 0, 0, 0 },
++
++ /* Packed RGB formats */
++ VLC_RGB( VLC_FOURCC('R','G','B','4'), AV_PIX_FMT_RGB4, AV_PIX_FMT_BGR4, 0x10, 0x06, 0x01 )
++ VLC_RGB( VLC_CODEC_RGB8, AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, 0xC0, 0x38, 0x07 )
++
++ VLC_RGB( VLC_CODEC_RGB15, AV_PIX_FMT_RGB555, AV_PIX_FMT_BGR555, 0x7c00, 0x03e0, 0x001f )
++ VLC_RGB( VLC_CODEC_RGB16, AV_PIX_FMT_RGB565, AV_PIX_FMT_BGR565, 0xf800, 0x07e0, 0x001f )
++ VLC_RGB( VLC_CODEC_RGB24, AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, 0xff0000, 0x00ff00, 0x0000ff )
++
++ VLC_RGB( VLC_CODEC_RGB32, AV_PIX_FMT_RGB32, AV_PIX_FMT_BGR32, 0x00ff0000, 0x0000ff00, 0x000000ff )
++ VLC_RGB( VLC_CODEC_RGB32, AV_PIX_FMT_RGB32_1, AV_PIX_FMT_BGR32_1, 0xff000000, 0x00ff0000, 0x0000ff00 )
++
++#ifdef AV_PIX_FMT_0BGR32
++ VLC_RGB( VLC_CODEC_RGB32, AV_PIX_FMT_0BGR32, AV_PIX_FMT_0RGB32, 0x000000ff, 0x0000ff00, 0x00ff0000 )
++#endif
++
++ {VLC_CODEC_RGBA, AV_PIX_FMT_RGBA, 0, 0, 0 },
++ {VLC_CODEC_ARGB, AV_PIX_FMT_ARGB, 0, 0, 0 },
++ {VLC_CODEC_BGRA, AV_PIX_FMT_BGRA, 0, 0, 0 },
++ {VLC_CODEC_GREY, AV_PIX_FMT_GRAY8, 0, 0, 0},
++
++ /* Paletized RGB */
++ {VLC_CODEC_RGBP, AV_PIX_FMT_PAL8, 0, 0, 0},
++
++ {VLC_CODEC_GBR_PLANAR, AV_PIX_FMT_GBRP, 0, 0, 0 },
++ {VLC_CODEC_GBR_PLANAR_9L, AV_PIX_FMT_GBRP9LE, 0, 0, 0 },
++ {VLC_CODEC_GBR_PLANAR_9B, AV_PIX_FMT_GBRP9BE, 0, 0, 0 },
++ {VLC_CODEC_GBR_PLANAR_10L, AV_PIX_FMT_GBRP10LE, 0, 0, 0 },
++ {VLC_CODEC_GBR_PLANAR_10B, AV_PIX_FMT_GBRP10BE, 0, 0, 0 },
++
++ /* XYZ */
++#if LIBAVUTIL_VERSION_CHECK(52, 10, 0, 25, 100)
++ {VLC_CODEC_XYZ12, AV_PIX_FMT_XYZ12, 0xfff0, 0xfff0, 0xfff0},
++#endif
++ { 0, 0, 0, 0, 0 }
++};
++
++static int GetVlcChroma( video_format_t *fmt, int i_ffmpeg_chroma )
++{
++ /* TODO FIXME for rgb format we HAVE to set rgb mask/shift */
++ for( int i = 0; chroma_table[i].i_chroma != 0; i++ )
++ {
++ if( chroma_table[i].i_chroma_id == i_ffmpeg_chroma )
++ {
++ fmt->i_rmask = chroma_table[i].i_rmask;
++ fmt->i_gmask = chroma_table[i].i_gmask;
++ fmt->i_bmask = chroma_table[i].i_bmask;
++ fmt->i_chroma = chroma_table[i].i_chroma;
++ return VLC_SUCCESS;
++ }
++ }
++ return VLC_EGENERIC;
++}
++
++//#include "../codec/cc.h"
++
++static AVCodecContext *ffmpeg_AllocContext( decoder_t *p_dec,
++ const AVCodec **restrict codecp )
++{
++ unsigned i_codec_id;
++ const char *psz_namecodec;
++ const AVCodec *p_codec = NULL;
++
++ /* *** determine codec type *** */
++ if( !GetFfmpegCodec( p_dec->fmt_in.i_cat, p_dec->fmt_in.i_codec,
++ &i_codec_id, &psz_namecodec ) )
++ return NULL;
++
++ msg_Dbg( p_dec, "using %s %s", AVPROVIDER(LIBAVCODEC), LIBAVCODEC_IDENT );
++
++ /* Initialization must be done before avcodec_find_decoder() */
++ vlc_init_avcodec(VLC_OBJECT(p_dec));
++
++ /* *** ask ffmpeg for a decoder *** */
++ char *psz_decoder = var_InheritString( p_dec, "avcodec-codec" );
++ if( psz_decoder != NULL )
++ {
++ p_codec = avcodec_find_decoder_by_name( psz_decoder );
++ if( !p_codec )
++ msg_Err( p_dec, "Decoder `%s' not found", psz_decoder );
++ else if( p_codec->id != i_codec_id )
++ {
++ msg_Err( p_dec, "Decoder `%s' can't handle %4.4s",
++ psz_decoder, (char*)&p_dec->fmt_in.i_codec );
++ p_codec = NULL;
++ }
++ free( psz_decoder );
++ }
++ if( !p_codec )
++ p_codec = avcodec_find_decoder( i_codec_id );
++ if( !p_codec )
++ {
++ msg_Dbg( p_dec, "codec not found (%s)", psz_namecodec );
++ return NULL;
++ }
++
++ *codecp = p_codec;
++
++ /* *** get a p_context *** */
++ AVCodecContext *avctx = avcodec_alloc_context3(p_codec);
++ if( unlikely(avctx == NULL) )
++ return NULL;
++
++ avctx->debug = var_InheritInteger( p_dec, "avcodec-debug" );
++ avctx->opaque = p_dec;
++ return avctx;
++}
++
++static int ffmpeg_OpenCodec( decoder_t *p_dec, AVCodecContext *ctx,
++ const AVCodec *codec )
++{
++ char *psz_opts = var_InheritString( p_dec, "avcodec-options" );
++ AVDictionary *options = NULL;
++ int ret;
++
++ if (psz_opts) {
++ vlc_av_get_options(psz_opts, &options);
++ free(psz_opts);
++ }
++
++ if (av_rpi_zc_init(ctx) != 0)
++ {
++ msg_Err(p_dec, "Failed to init AV ZC");
++ return VLC_EGENERIC;
++ }
++
++ vlc_avcodec_lock();
++ ret = avcodec_open2( ctx, codec, options ? &options : NULL );
++ vlc_avcodec_unlock();
++
++ AVDictionaryEntry *t = NULL;
++ while ((t = av_dict_get(options, "", t, AV_DICT_IGNORE_SUFFIX))) {
++ msg_Err( p_dec, "Unknown option \"%s\"", t->key );
++ }
++ av_dict_free(&options);
++
++ if( ret < 0 )
++ {
++ msg_Err( p_dec, "cannot start codec (%s)", codec->name );
++ return VLC_EGENERIC;
++ }
++
++ msg_Dbg( p_dec, "codec (%s) started", codec->name );
++ return VLC_SUCCESS;
++}
++
++
++/*****************************************************************************
++ * decoder_sys_t : decoder descriptor
++ *****************************************************************************/
++struct decoder_sys_t
++{
++ AVCodecContext *p_context;
++ const AVCodec *p_codec;
++
++ /* Video decoder specific part */
++ date_t pts;
++
++ /* Closed captions for decoders */
++// cc_data_t cc;
++
++ /* for frame skipping algo */
++ bool b_hurry_up;
++ bool b_show_corrupted;
++ bool b_from_preroll;
++ enum AVDiscard i_skip_frame;
++
++ /* how many decoded frames are late */
++ int i_late_frames;
++ mtime_t i_late_frames_start;
++ mtime_t i_last_late_delay;
++
++ /* for direct rendering */
++ bool b_direct_rendering;
++ atomic_bool b_dr_failure;
++
++ /* Hack to force display of still pictures */
++ bool b_first_frame;
++
++
++ /* */
++ bool palette_sent;
++
++ /* VA API */
++// vlc_va_t *p_va;
++ enum AVPixelFormat pix_fmt;
++ int profile;
++ int level;
++
++ MMAL_POOL_T * out_pool;
++};
++
++/*****************************************************************************
++ * Local prototypes
++ *****************************************************************************/
++static void ffmpeg_InitCodec ( decoder_t * );
++static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *,
++ const enum PixelFormat * );
++static int DecodeVideo( decoder_t *, block_t * );
++static void Flush( decoder_t * );
++
++static uint32_t ffmpeg_CodecTag( vlc_fourcc_t fcc )
++{
++ uint8_t *p = (uint8_t*)&fcc;
++ return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
++}
++
++/*****************************************************************************
++ * Local Functions
++ *****************************************************************************/
++
++/**
++ * Sets the decoder output format.
++ */
++static int lavc_GetVideoFormat(decoder_t *dec, video_format_t *restrict fmt,
++ AVCodecContext *ctx, enum AVPixelFormat pix_fmt,
++ enum AVPixelFormat sw_pix_fmt)
++{
++ int width = ctx->coded_width;
++ int height = ctx->coded_height;
++
++ video_format_Init(fmt, 0);
++
++ if (pix_fmt == sw_pix_fmt)
++ { /* software decoding */
++ int aligns[AV_NUM_DATA_POINTERS];
++
++ if (GetVlcChroma(fmt, pix_fmt))
++ return -1;
++
++ /* The libavcodec palette can only be fetched when the first output
++ * frame is decoded. Assume that the current chroma is RGB32 while we
++ * are waiting for a valid palette. Indeed, fmt_out.video.p_palette
++ * doesn't trigger a new vout request, but a new chroma yes. */
++ if (pix_fmt == AV_PIX_FMT_PAL8 && !dec->fmt_out.video.p_palette)
++ fmt->i_chroma = VLC_CODEC_RGB32;
++
++ avcodec_align_dimensions2(ctx, &width, &height, aligns);
++ }
++// else /* hardware decoding */
++// fmt->i_chroma = vlc_va_GetChroma(pix_fmt, sw_pix_fmt);
++
++ if( width == 0 || height == 0 || width > 8192 || height > 8192 ||
++ width < ctx->width || height < ctx->height )
++ {
++ msg_Err(dec, "Invalid frame size %dx%d vsz %dx%d",
++ width, height, ctx->width, ctx->height );
++ return -1; /* invalid display size */
++ }
++
++ fmt->i_width = width;
++ fmt->i_height = height;
++ fmt->i_visible_width = ctx->width;
++ fmt->i_visible_height = ctx->height;
++
++ /* If an aspect-ratio was specified in the input format then force it */
++ if (dec->fmt_in.video.i_sar_num > 0 && dec->fmt_in.video.i_sar_den > 0)
++ {
++ fmt->i_sar_num = dec->fmt_in.video.i_sar_num;
++ fmt->i_sar_den = dec->fmt_in.video.i_sar_den;
++ }
++ else
++ {
++ fmt->i_sar_num = ctx->sample_aspect_ratio.num;
++ fmt->i_sar_den = ctx->sample_aspect_ratio.den;
++
++ if (fmt->i_sar_num == 0 || fmt->i_sar_den == 0)
++ fmt->i_sar_num = fmt->i_sar_den = 1;
++ }
++
++ if (dec->fmt_in.video.i_frame_rate > 0
++ && dec->fmt_in.video.i_frame_rate_base > 0)
++ {
++ fmt->i_frame_rate = dec->fmt_in.video.i_frame_rate;
++ fmt->i_frame_rate_base = dec->fmt_in.video.i_frame_rate_base;
++ }
++ else if (ctx->framerate.num > 0 && ctx->framerate.den > 0)
++ {
++ fmt->i_frame_rate = ctx->framerate.num;
++ fmt->i_frame_rate_base = ctx->framerate.den;
++# if LIBAVCODEC_VERSION_MICRO < 100
++ // for some reason libav don't thinkg framerate presents actually same thing as in ffmpeg
++ fmt->i_frame_rate_base *= __MAX(ctx->ticks_per_frame, 1);
++# endif
++ }
++ else if (ctx->time_base.num > 0 && ctx->time_base.den > 0)
++ {
++ fmt->i_frame_rate = ctx->time_base.den;
++ fmt->i_frame_rate_base = ctx->time_base.num
++ * __MAX(ctx->ticks_per_frame, 1);
++ }
++
++ if( ctx->color_range == AVCOL_RANGE_JPEG )
++ fmt->b_color_range_full = true;
++
++ switch( ctx->colorspace )
++ {
++ case AVCOL_SPC_BT709:
++ fmt->space = COLOR_SPACE_BT709;
++ break;
++ case AVCOL_SPC_SMPTE170M:
++ case AVCOL_SPC_BT470BG:
++ fmt->space = COLOR_SPACE_BT601;
++ break;
++ case AVCOL_SPC_BT2020_NCL:
++ case AVCOL_SPC_BT2020_CL:
++ fmt->space = COLOR_SPACE_BT2020;
++ break;
++ default:
++ break;
++ }
++
++ switch( ctx->color_trc )
++ {
++ case AVCOL_TRC_LINEAR:
++ fmt->transfer = TRANSFER_FUNC_LINEAR;
++ break;
++ case AVCOL_TRC_GAMMA22:
++ fmt->transfer = TRANSFER_FUNC_SRGB;
++ break;
++ case AVCOL_TRC_BT709:
++ fmt->transfer = TRANSFER_FUNC_BT709;
++ break;
++ case AVCOL_TRC_SMPTE170M:
++ case AVCOL_TRC_BT2020_10:
++ case AVCOL_TRC_BT2020_12:
++ fmt->transfer = TRANSFER_FUNC_BT2020;
++ break;
++#if LIBAVUTIL_VERSION_CHECK( 55, 14, 0, 31, 100)
++ case AVCOL_TRC_ARIB_STD_B67:
++ fmt->transfer = TRANSFER_FUNC_ARIB_B67;
++ break;
++#endif
++#if LIBAVUTIL_VERSION_CHECK( 55, 17, 0, 37, 100)
++ case AVCOL_TRC_SMPTE2084:
++ fmt->transfer = TRANSFER_FUNC_SMPTE_ST2084;
++ break;
++ case AVCOL_TRC_SMPTE240M:
++ fmt->transfer = TRANSFER_FUNC_SMPTE_240;
++ break;
++ case AVCOL_TRC_GAMMA28:
++ fmt->transfer = TRANSFER_FUNC_BT470_BG;
++ break;
++#endif
++ default:
++ break;
++ }
++
++ switch( ctx->color_primaries )
++ {
++ case AVCOL_PRI_BT709:
++ fmt->primaries = COLOR_PRIMARIES_BT709;
++ break;
++ case AVCOL_PRI_BT470BG:
++ fmt->primaries = COLOR_PRIMARIES_BT601_625;
++ break;
++ case AVCOL_PRI_SMPTE170M:
++ case AVCOL_PRI_SMPTE240M:
++ fmt->primaries = COLOR_PRIMARIES_BT601_525;
++ break;
++ case AVCOL_PRI_BT2020:
++ fmt->primaries = COLOR_PRIMARIES_BT2020;
++ break;
++ default:
++ break;
++ }
++
++ switch( ctx->chroma_sample_location )
++ {
++ case AVCHROMA_LOC_LEFT:
++ fmt->chroma_location = CHROMA_LOCATION_LEFT;
++ break;
++ case AVCHROMA_LOC_CENTER:
++ fmt->chroma_location = CHROMA_LOCATION_CENTER;
++ break;
++ case AVCHROMA_LOC_TOPLEFT:
++ fmt->chroma_location = CHROMA_LOCATION_TOP_LEFT;
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++static int lavc_UpdateVideoFormat(decoder_t *dec, AVCodecContext *ctx,
++ enum AVPixelFormat fmt,
++ enum AVPixelFormat swfmt)
++{
++ video_format_t fmt_out;
++ int val;
++
++ val = lavc_GetVideoFormat(dec, &fmt_out, ctx, fmt, swfmt);
++ if (val)
++ return val;
++
++ /* always have date in fields/ticks units */
++ if(dec->p_sys->pts.i_divider_num)
++ date_Change(&dec->p_sys->pts, fmt_out.i_frame_rate *
++ __MAX(ctx->ticks_per_frame, 1),
++ fmt_out.i_frame_rate_base);
++ else
++ date_Init(&dec->p_sys->pts, fmt_out.i_frame_rate *
++ __MAX(ctx->ticks_per_frame, 1),
++ fmt_out.i_frame_rate_base);
++
++ fmt_out.p_palette = dec->fmt_out.video.p_palette;
++ dec->fmt_out.video.p_palette = NULL;
++
++ es_format_Change(&dec->fmt_out, VIDEO_ES, fmt_out.i_chroma);
++ dec->fmt_out.video = fmt_out;
++ dec->fmt_out.video.orientation = dec->fmt_in.video.orientation;
++ dec->fmt_out.video.projection_mode = dec->fmt_in.video.projection_mode;
++ dec->fmt_out.video.multiview_mode = dec->fmt_in.video.multiview_mode;
++ dec->fmt_out.video.pose = dec->fmt_in.video.pose;
++ if ( dec->fmt_in.video.mastering.max_luminance )
++ dec->fmt_out.video.mastering = dec->fmt_in.video.mastering;
++ dec->fmt_out.video.lighting = dec->fmt_in.video.lighting;
++
++ return decoder_UpdateVideoFormat(dec);
++}
++
++/*****************************************************************************
++ * Flush:
++ *****************************************************************************/
++static void Flush( decoder_t *p_dec )
++{
++ decoder_sys_t *p_sys = p_dec->p_sys;
++ AVCodecContext *p_context = p_sys->p_context;
++
++ date_Set(&p_sys->pts, VLC_TS_INVALID); /* To make sure we recover properly */
++ p_sys->i_late_frames = 0;
++// cc_Flush( &p_sys->cc );
++
++ /* Abort pictures in order to unblock all avcodec workers threads waiting
++ * for a picture. This will avoid a deadlock between avcodec_flush_buffers
++ * and workers threads */
++ decoder_AbortPictures( p_dec, true );
++
++ /* do not flush buffers if codec hasn't been opened (theora/vorbis/VC1) */
++ if( avcodec_is_open( p_context ) )
++ avcodec_flush_buffers( p_context );
++
++ /* Reset cancel state to false */
++ decoder_AbortPictures( p_dec, false );
++}
++
++static bool check_block_validity( decoder_sys_t *p_sys, block_t *block )
++{
++ if( !block)
++ return true;
++
++ if( block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
++ {
++ date_Set( &p_sys->pts, VLC_TS_INVALID ); /* To make sure we recover properly */
++// cc_Flush( &p_sys->cc );
++
++ p_sys->i_late_frames = 0;
++ if( block->i_flags & BLOCK_FLAG_CORRUPTED )
++ {
++ block_Release( block );
++ return false;
++ }
++ }
++ return true;
++}
++
++static bool check_block_being_late( decoder_sys_t *p_sys, block_t *block, mtime_t current_time)
++{
++ if( !block )
++ return false;
++ if( block->i_flags & BLOCK_FLAG_PREROLL )
++ {
++ /* Do not care about late frames when prerolling
++ * TODO avoid decoding of non reference frame
++ * (ie all B except for H264 where it depends only on nal_ref_idc) */
++ p_sys->i_late_frames = 0;
++ p_sys->b_from_preroll = true;
++ p_sys->i_last_late_delay = INT64_MAX;
++ }
++
++ if( p_sys->i_late_frames <= 0 )
++ return false;
++
++ if( current_time - p_sys->i_late_frames_start > (5*CLOCK_FREQ))
++ {
++ date_Set( &p_sys->pts, VLC_TS_INVALID ); /* To make sure we recover properly */
++ block_Release( block );
++ p_sys->i_late_frames--;
++ return true;
++ }
++ return false;
++}
++
++static bool check_frame_should_be_dropped( decoder_sys_t *p_sys, AVCodecContext *p_context, bool *b_need_output_picture )
++{
++ if( p_sys->i_late_frames <= 4)
++ return false;
++
++ *b_need_output_picture = false;
++ if( p_sys->i_late_frames < 12 )
++ {
++ p_context->skip_frame =
++ (p_sys->i_skip_frame <= AVDISCARD_NONREF) ?
++ AVDISCARD_NONREF : p_sys->i_skip_frame;
++ }
++ else
++ {
++ /* picture too late, won't decode
++ * but break picture until a new I, and for mpeg4 ...*/
++ p_sys->i_late_frames--; /* needed else it will never be decrease */
++ return true;
++ }
++ return false;
++}
++
++static void interpolate_next_pts( decoder_t *p_dec, AVFrame *frame )
++{
++ decoder_sys_t *p_sys = p_dec->p_sys;
++ AVCodecContext *p_context = p_sys->p_context;
++
++ if( date_Get( &p_sys->pts ) == VLC_TS_INVALID ||
++ p_sys->pts.i_divider_num == 0 )
++ return;
++
++ int i_tick = p_context->ticks_per_frame;
++ if( i_tick <= 0 )
++ i_tick = 1;
++
++ /* interpolate the next PTS */
++ date_Increment( &p_sys->pts, i_tick + frame->repeat_pict );
++}
++
++static void update_late_frame_count( decoder_t *p_dec, block_t *p_block, mtime_t current_time, mtime_t i_pts )
++{
++ decoder_sys_t *p_sys = p_dec->p_sys;
++ /* Update frame late count (except when doing preroll) */
++ mtime_t i_display_date = VLC_TS_INVALID;
++ if( !p_block || !(p_block->i_flags & BLOCK_FLAG_PREROLL) )
++ i_display_date = decoder_GetDisplayDate( p_dec, i_pts );
++
++ if( i_display_date > VLC_TS_INVALID && i_display_date <= current_time )
++ {
++ /* Out of preroll, consider only late frames on rising delay */
++ if( p_sys->b_from_preroll )
++ {
++ if( p_sys->i_last_late_delay > current_time - i_display_date )
++ {
++ p_sys->i_last_late_delay = current_time - i_display_date;
++ return;
++ }
++ p_sys->b_from_preroll = false;
++ }
++
++ p_sys->i_late_frames++;
++ if( p_sys->i_late_frames == 1 )
++ p_sys->i_late_frames_start = current_time;
++
++ }
++ else
++ {
++ p_sys->i_late_frames = 0;
++ }
++}
++
++
++static int DecodeSidedata( decoder_t *p_dec, const AVFrame *frame, picture_t *p_pic )
++{
++// decoder_sys_t *p_sys = p_dec->p_sys;
++ bool format_changed = false;
++
++#if (LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT( 55, 16, 101 ) )
++#define FROM_AVRAT(default_factor, avrat) \
++(uint64_t)(default_factor) * (avrat).num / (avrat).den
++ const AVFrameSideData *metadata =
++ av_frame_get_side_data( frame,
++ AV_FRAME_DATA_MASTERING_DISPLAY_METADATA );
++ if ( metadata )
++ {
++ const AVMasteringDisplayMetadata *hdr_meta =
++ (const AVMasteringDisplayMetadata *) metadata->data;
++ if ( hdr_meta->has_luminance )
++ {
++#define ST2086_LUMA_FACTOR 10000
++ p_pic->format.mastering.max_luminance =
++ FROM_AVRAT(ST2086_LUMA_FACTOR, hdr_meta->max_luminance);
++ p_pic->format.mastering.min_luminance =
++ FROM_AVRAT(ST2086_LUMA_FACTOR, hdr_meta->min_luminance);
++ }
++ if ( hdr_meta->has_primaries )
++ {
++#define ST2086_RED 2
++#define ST2086_GREEN 0
++#define ST2086_BLUE 1
++#define LAV_RED 0
++#define LAV_GREEN 1
++#define LAV_BLUE 2
++#define ST2086_PRIM_FACTOR 50000
++ p_pic->format.mastering.primaries[ST2086_RED*2 + 0] =
++ FROM_AVRAT(ST2086_PRIM_FACTOR, hdr_meta->display_primaries[LAV_RED][0]);
++ p_pic->format.mastering.primaries[ST2086_RED*2 + 1] =
++ FROM_AVRAT(ST2086_PRIM_FACTOR, hdr_meta->display_primaries[LAV_RED][1]);
++ p_pic->format.mastering.primaries[ST2086_GREEN*2 + 0] =
++ FROM_AVRAT(ST2086_PRIM_FACTOR, hdr_meta->display_primaries[LAV_GREEN][0]);
++ p_pic->format.mastering.primaries[ST2086_GREEN*2 + 1] =
++ FROM_AVRAT(ST2086_PRIM_FACTOR, hdr_meta->display_primaries[LAV_GREEN][1]);
++ p_pic->format.mastering.primaries[ST2086_BLUE*2 + 0] =
++ FROM_AVRAT(ST2086_PRIM_FACTOR, hdr_meta->display_primaries[LAV_BLUE][0]);
++ p_pic->format.mastering.primaries[ST2086_BLUE*2 + 1] =
++ FROM_AVRAT(ST2086_PRIM_FACTOR, hdr_meta->display_primaries[LAV_BLUE][1]);
++ p_pic->format.mastering.white_point[0] =
++ FROM_AVRAT(ST2086_PRIM_FACTOR, hdr_meta->white_point[0]);
++ p_pic->format.mastering.white_point[1] =
++ FROM_AVRAT(ST2086_PRIM_FACTOR, hdr_meta->white_point[1]);
++ }
++
++ if ( memcmp( &p_dec->fmt_out.video.mastering,
++ &p_pic->format.mastering,
++ sizeof(p_pic->format.mastering) ) )
++ {
++ p_dec->fmt_out.video.mastering = p_pic->format.mastering;
++ format_changed = true;
++ }
++#undef FROM_AVRAT
++ }
++#endif
++#if (LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT( 55, 60, 100 ) )
++ const AVFrameSideData *metadata_lt =
++ av_frame_get_side_data( frame,
++ AV_FRAME_DATA_CONTENT_LIGHT_LEVEL );
++ if ( metadata_lt )
++ {
++ const AVContentLightMetadata *light_meta =
++ (const AVContentLightMetadata *) metadata_lt->data;
++ p_pic->format.lighting.MaxCLL = light_meta->MaxCLL;
++ p_pic->format.lighting.MaxFALL = light_meta->MaxFALL;
++ if ( memcmp( &p_dec->fmt_out.video.lighting,
++ &p_pic->format.lighting,
++ sizeof(p_pic->format.lighting) ) )
++ {
++ p_dec->fmt_out.video.lighting = p_pic->format.lighting;
++ format_changed = true;
++ }
++ }
++#endif
++
++ if (format_changed && decoder_UpdateVideoFormat( p_dec ))
++ return -1;
++#if 0
++ const AVFrameSideData *p_avcc = av_frame_get_side_data( frame, AV_FRAME_DATA_A53_CC );
++ if( p_avcc )
++ {
++ cc_Extract( &p_sys->cc, CC_PAYLOAD_RAW, true, p_avcc->data, p_avcc->size );
++ if( p_sys->cc.b_reorder || p_sys->cc.i_data )
++ {
++ block_t *p_cc = block_Alloc( p_sys->cc.i_data );
++ if( p_cc )
++ {
++ memcpy( p_cc->p_buffer, p_sys->cc.p_data, p_sys->cc.i_data );
++ if( p_sys->cc.b_reorder )
++ p_cc->i_dts = p_cc->i_pts = p_pic->date;
++ else
++ p_cc->i_pts = p_cc->i_dts;
++ decoder_cc_desc_t desc;
++ desc.i_608_channels = p_sys->cc.i_608channels;
++ desc.i_708_channels = p_sys->cc.i_708channels;
++ desc.i_reorder_depth = 4;
++ decoder_QueueCc( p_dec, p_cc, &desc );
++ }
++ cc_Flush( &p_sys->cc );
++ }
++ }
++#endif
++ return 0;
++}
++
++
++
++static int OpenVideoCodec( decoder_t *p_dec )
++{
++ decoder_sys_t *p_sys = p_dec->p_sys;
++ AVCodecContext *ctx = p_sys->p_context;
++ const AVCodec *codec = p_sys->p_codec;
++ int ret;
++
++#if TRACE_ALL
++ msg_Dbg(p_dec, "<<< %s", __func__);
++#endif
++
++ if( ctx->extradata_size <= 0 )
++ {
++ if( codec->id == AV_CODEC_ID_VC1 ||
++ codec->id == AV_CODEC_ID_THEORA )
++ {
++ msg_Warn( p_dec, "waiting for extra data for codec %s",
++ codec->name );
++ return 1;
++ }
++ }
++
++ ctx->width = p_dec->fmt_in.video.i_visible_width;
++ ctx->height = p_dec->fmt_in.video.i_visible_height;
++
++ ctx->coded_width = p_dec->fmt_in.video.i_width;
++ ctx->coded_height = p_dec->fmt_in.video.i_height;
++
++ ctx->bits_per_coded_sample = p_dec->fmt_in.video.i_bits_per_pixel;
++ p_sys->pix_fmt = AV_PIX_FMT_NONE;
++ p_sys->profile = -1;
++ p_sys->level = -1;
++// cc_Init( &p_sys->cc );
++
++ set_video_color_settings( &p_dec->fmt_in.video, ctx );
++
++ ret = ffmpeg_OpenCodec( p_dec, ctx, codec );
++ if( ret < 0 )
++ return ret;
++
++ switch( ctx->active_thread_type )
++ {
++ case FF_THREAD_FRAME:
++ msg_Dbg( p_dec, "using frame thread mode with %d threads",
++ ctx->thread_count );
++ break;
++ case FF_THREAD_SLICE:
++ msg_Dbg( p_dec, "using slice thread mode with %d threads",
++ ctx->thread_count );
++ break;
++ case 0:
++ if( ctx->thread_count > 1 )
++ msg_Warn( p_dec, "failed to enable threaded decoding" );
++ break;
++ default:
++ msg_Warn( p_dec, "using unknown thread mode with %d threads",
++ ctx->thread_count );
++ break;
++ }
++ return 0;
++}
++
++static MMAL_BOOL_T
++zc_buf_pre_release_cb(MMAL_BUFFER_HEADER_T * buf, void *userdata)
++{
++ const AVRpiZcRefPtr fr_ref = userdata;
++ VLC_UNUSED(buf);
++
++ av_rpi_zc_unref(fr_ref);
++
++ return MMAL_FALSE;
++}
++
++static MMAL_FOURCC_T
++avfmt_to_mmal(const int avfmt)
++{
++ switch( avfmt )
++ {
++ case AV_PIX_FMT_SAND128:
++ return MMAL_ENCODING_YUVUV128;
++ case AV_PIX_FMT_SAND64_10:
++ return MMAL_ENCODING_YUVUV64_10;
++ default:
++ break;
++ }
++ return MMAL_ENCODING_UNKNOWN;
++}
++
++/*****************************************************************************
++ * DecodeBlock: Called to decode one or more frames
++ *****************************************************************************/
++
++
++// Returns
++// -ve error
++// 0 Need more input (EAGAIN)
++// 1 Frame decoded (dropped or Qed)
++// 2 Decode err
++// 3 EOF
++
++static int rx_frame(decoder_t * const p_dec, decoder_sys_t * const p_sys, AVCodecContext * const p_context)
++{
++ AVFrame * frame = av_frame_alloc();
++ picture_t * p_pic = NULL;
++ int ret;
++
++ if (frame == NULL)
++ return VLC_ENOMEM;
++
++ ret = avcodec_receive_frame(p_context, frame);
++
++ if (ret != 0)
++ {
++ av_frame_free(&frame);
++ switch (ret)
++ {
++ case AVERROR(EAGAIN):
++ return 0;
++
++ case AVERROR(ENOMEM):
++ case AVERROR(EINVAL):
++ msg_Err(p_dec, "avcodec_receive_frame critical error");
++ return VLC_EGENERIC;
++
++ case AVERROR_EOF:
++ msg_Dbg(p_dec, "Rx EOF");
++ avcodec_flush_buffers(p_context);
++ return 2;
++
++ default:
++ msg_Warn(p_dec, "Decode error: %d", ret);
++ return 1;
++ }
++ }
++
++ /* Compute the PTS */
++#ifdef FF_API_PKT_PTS
++ mtime_t i_pts = frame->pts;
++#else
++ mtime_t i_pts = frame->pkt_pts;
++#endif
++ if (i_pts == AV_NOPTS_VALUE )
++ i_pts = frame->pkt_dts;
++
++ if( i_pts == AV_NOPTS_VALUE )
++ i_pts = date_Get( &p_sys->pts );
++
++ /* Interpolate the next PTS */
++ if( i_pts > VLC_TS_INVALID )
++ date_Set( &p_sys->pts, i_pts );
++
++ interpolate_next_pts( p_dec, frame );
++
++// update_late_frame_count( p_dec, p_block, current_time, i_pts); //*********************
++
++ if( ( /* !p_sys->p_va && */ !frame->linesize[0] ) ||
++ ( p_dec->b_frame_drop_allowed && (frame->flags & AV_FRAME_FLAG_CORRUPT) &&
++ !p_sys->b_show_corrupted ) )
++ {
++ msg_Dbg(p_dec, "Frame drop");
++ av_frame_free(&frame);
++ return 1;
++ }
++
++ lavc_UpdateVideoFormat(p_dec, p_context, p_context->pix_fmt,
++ p_context->pix_fmt);
++
++ {
++ MMAL_BUFFER_HEADER_T * const buf = mmal_queue_wait(p_sys->out_pool->queue);
++// MMAL_BUFFER_HEADER_T * const buf = mmal_queue_get(p_sys->out_pool->queue);
++ if (buf == NULL) {
++ msg_Err(p_dec, "MMAL buffer alloc failure");
++ av_frame_free(&frame);
++ return 1;
++ }
++
++ mmal_buffer_header_reset(buf); // length, offset, flags, pts, dts
++ buf->cmd = 0;
++ buf->user_data = NULL;
++
++ {
++ const AVRpiZcRefPtr fr_buf = av_rpi_zc_ref(p_context, frame, frame->format, 0);
++
++ if (fr_buf == NULL) {
++ mmal_buffer_header_release(buf);
++ av_frame_free(&frame);
++ return VLC_ENOMEM;
++ }
++
++ const intptr_t vc_handle = (intptr_t)av_rpi_zc_vc_handle(fr_buf);
++
++ buf->data = (uint8_t *)vc_handle; // Cast our handle to a pointer for mmal - 2 steps to avoid gcc warnings
++ buf->offset = av_rpi_zc_offset(fr_buf);
++ buf->length = av_rpi_zc_length(fr_buf);
++ buf->alloc_size = av_rpi_zc_numbytes(fr_buf);
++ buf->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;
++
++ mmal_buffer_header_pre_release_cb_set(buf, zc_buf_pre_release_cb, fr_buf);
++ }
++
++ p_pic = decoder_NewPicture(p_dec); // *** Really want an empy pic
++ if (p_pic == NULL)
++ {
++ msg_Err(p_dec, "Picture alloc failure");
++ mmal_buffer_header_release(buf);
++ av_frame_free(&frame);
++ return VLC_ENOMEM;
++ }
++
++ p_pic->context = hw_mmal_gen_context(avfmt_to_mmal(frame->format), buf, NULL);
++ }
++
++
++ if( !p_dec->fmt_in.video.i_sar_num || !p_dec->fmt_in.video.i_sar_den )
++ {
++ /* Fetch again the aspect ratio in case it changed */
++ p_dec->fmt_out.video.i_sar_num
++ = p_context->sample_aspect_ratio.num;
++ p_dec->fmt_out.video.i_sar_den
++ = p_context->sample_aspect_ratio.den;
++
++ if( !p_dec->fmt_out.video.i_sar_num || !p_dec->fmt_out.video.i_sar_den )
++ {
++ p_dec->fmt_out.video.i_sar_num = 1;
++ p_dec->fmt_out.video.i_sar_den = 1;
++ }
++ }
++
++ p_pic->date = i_pts;
++ /* Hack to force display of still pictures */
++ p_pic->b_force = p_sys->b_first_frame;
++ p_pic->i_nb_fields = 2 + frame->repeat_pict;
++ p_pic->b_progressive = !frame->interlaced_frame;
++ p_pic->b_top_field_first = frame->top_field_first;
++
++ if (DecodeSidedata(p_dec, frame, p_pic))
++ i_pts = VLC_TS_INVALID;
++
++ av_frame_free(&frame);
++
++ p_sys->b_first_frame = false;
++ decoder_QueueVideo(p_dec, p_pic);
++
++ return 1;
++}
++
++
++
++
++
++static int DecodeVideo( decoder_t *p_dec, block_t * p_block)
++{
++ decoder_sys_t *p_sys = p_dec->p_sys;
++ AVCodecContext *p_context = p_sys->p_context;
++ /* Boolean if we assume that we should get valid pic as result */
++ bool b_need_output_picture = true;
++
++ /* Boolean for END_OF_SEQUENCE */
++ bool eos_spotted = false;
++ mtime_t current_time;
++ int rv = VLCDEC_SUCCESS;
++
++ if( !p_context->extradata_size && p_dec->fmt_in.i_extra )
++ {
++ ffmpeg_InitCodec( p_dec );
++ if( !avcodec_is_open( p_context ) )
++ OpenVideoCodec( p_dec );
++ }
++
++ if(!p_block && !(p_sys->p_codec->capabilities & AV_CODEC_CAP_DELAY) )
++ return VLCDEC_SUCCESS;
++
++ if( !avcodec_is_open( p_context ) )
++ {
++ if( p_block )
++ block_Release( p_block );
++ return VLCDEC_ECRITICAL;
++ }
++
++ if( !check_block_validity( p_sys, p_block ) )
++ return VLCDEC_SUCCESS;
++
++ current_time = mdate();
++ if( p_dec->b_frame_drop_allowed && check_block_being_late( p_sys, p_block, current_time) )
++ {
++ msg_Err( p_dec, "more than 5 seconds of late video -> "
++ "dropping frame (computer too slow ?)" );
++ return VLCDEC_SUCCESS;
++ }
++
++
++ /* A good idea could be to decode all I pictures and see for the other */
++ b_need_output_picture = true;
++
++ /* Defaults that if we aren't in prerolling, we want output picture
++ same for if we are flushing (p_block==NULL) */
++ if( !p_block || !(p_block->i_flags & BLOCK_FLAG_PREROLL) )
++ b_need_output_picture = true;
++ else
++ b_need_output_picture = false;
++
++ /* Change skip_frame config only if hurry_up is enabled */
++ if( p_sys->b_hurry_up )
++ {
++ p_context->skip_frame = p_sys->i_skip_frame;
++
++ /* Check also if we should/can drop the block and move to next block
++ as trying to catchup the speed*/
++ if( p_dec->b_frame_drop_allowed &&
++ check_frame_should_be_dropped( p_sys, p_context, &b_need_output_picture ) )
++ {
++ if( p_block )
++ block_Release( p_block );
++ msg_Warn( p_dec, "More than 11 late frames, dropping frame" );
++ return VLCDEC_SUCCESS;
++ }
++ }
++ if( !b_need_output_picture )
++ {
++ p_context->skip_frame = __MAX( p_context->skip_frame,
++ AVDISCARD_NONREF );
++ }
++
++ /*
++ * Do the actual decoding now */
++
++ /* Don't forget that libavcodec requires a little more bytes
++ * that the real frame size */
++ if( p_block && p_block->i_buffer > 0 )
++ {
++ eos_spotted = ( p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE ) != 0;
++
++ p_block = block_Realloc( p_block, 0,
++ p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE );
++ if( !p_block )
++ return VLCDEC_ECRITICAL;
++
++ p_block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE;
++ memset( p_block->p_buffer + p_block->i_buffer, 0,
++ FF_INPUT_BUFFER_PADDING_SIZE );
++ }
++
++ AVPacket pkt = {.data = NULL, .size = 0};
++
++ av_init_packet( &pkt );
++ if( p_block && p_block->i_buffer > 0 )
++ {
++ pkt.data = p_block->p_buffer;
++ pkt.size = p_block->i_buffer;
++ pkt.pts = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : AV_NOPTS_VALUE;
++ pkt.dts = p_block->i_dts > VLC_TS_INVALID ? p_block->i_dts : AV_NOPTS_VALUE;
++ }
++
++ if( !p_sys->palette_sent )
++ {
++ uint8_t *pal = av_packet_new_side_data(&pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
++ if (pal) {
++ memcpy(pal, p_dec->fmt_in.video.p_palette->palette, AVPALETTE_SIZE);
++ p_sys->palette_sent = true;
++ }
++ }
++
++#if LIBAVCODEC_VERSION_CHECK( 57, 0, 0xFFFFFFFFU, 64, 101 )
++ if( !b_need_output_picture )
++ pkt.flags |= AV_PKT_FLAG_DISCARD;
++#endif
++
++ int ret = avcodec_send_packet(p_context, &pkt);
++
++ if (ret == AVERROR(EAGAIN))
++ {
++ // Cannot send more data until output drained - so do drain
++ while (rx_frame(p_dec, p_sys, p_context) == 1)
++ /* Loop */;
++
++ // And try again - should not fail the same way
++ ret = avcodec_send_packet(p_context, &pkt);
++ }
++
++ // Now done with pkt & block
++ av_packet_unref(&pkt);
++ if (p_block != NULL)
++ {
++ block_Release( p_block );
++ p_block = NULL;
++ }
++
++ if (ret != 0)
++ {
++ if (ret == AVERROR(ENOMEM) || ret == AVERROR(EINVAL))
++ {
++ msg_Err(p_dec, "avcodec_send_packet critical error");
++ rv = VLCDEC_ECRITICAL;
++ }
++ }
++
++ while (rx_frame(p_dec, p_sys, p_context) == 1)
++ /* Loop */;
++
++ if (eos_spotted)
++ p_sys->b_first_frame = true;
++
++ return rv;
++}
++
++/*****************************************************************************
++ * EndVideo: decoder destruction
++ *****************************************************************************
++ * This function is called when the thread ends after a successful
++ * initialization.
++ *****************************************************************************/
++static void MmalAvcodecCloseDecoder(vlc_object_t *obj)
++{
++ decoder_t *p_dec = (decoder_t *)obj;
++ decoder_sys_t *p_sys = p_dec->p_sys;
++ AVCodecContext *ctx = p_sys->p_context;
++// void *hwaccel_context;
++
++ /* do not flush buffers if codec hasn't been opened (theora/vorbis/VC1) */
++ if( avcodec_is_open( ctx ) )
++ avcodec_flush_buffers( ctx );
++
++// cc_Flush( &p_sys->cc );
++
++ avcodec_close(ctx);
++ av_rpi_zc_uninit(ctx);
++
++// hwaccel_context = ctx->hwaccel_context;
++ avcodec_free_context( &ctx );
++
++ if( p_sys->out_pool != NULL )
++ mmal_pool_destroy(p_sys->out_pool);
++
++// if( p_sys->p_va )
++// vlc_va_Delete( p_sys->p_va, &hwaccel_context );
++
++ free( p_sys );
++}
++
++/*****************************************************************************
++ * ffmpeg_InitCodec: setup codec extra initialization data for ffmpeg
++ *****************************************************************************/
++static void ffmpeg_InitCodec( decoder_t *p_dec )
++{
++ decoder_sys_t *p_sys = p_dec->p_sys;
++ size_t i_size = p_dec->fmt_in.i_extra;
++
++ if( !i_size ) return;
++
++ if( p_sys->p_codec->id == AV_CODEC_ID_SVQ3 )
++ {
++ uint8_t *p;
++
++ p_sys->p_context->extradata_size = i_size + 12;
++ p = p_sys->p_context->extradata =
++ av_malloc( p_sys->p_context->extradata_size +
++ FF_INPUT_BUFFER_PADDING_SIZE );
++ if( !p )
++ return;
++
++ memcpy( &p[0], "SVQ3", 4 );
++ memset( &p[4], 0, 8 );
++ memcpy( &p[12], p_dec->fmt_in.p_extra, i_size );
++
++ /* Now remove all atoms before the SMI one */
++ if( p_sys->p_context->extradata_size > 0x5a &&
++ strncmp( (char*)&p[0x56], "SMI ", 4 ) )
++ {
++ uint8_t *psz = &p[0x52];
++
++ while( psz < &p[p_sys->p_context->extradata_size - 8] )
++ {
++ uint_fast32_t atom_size = GetDWBE( psz );
++ if( atom_size <= 1 )
++ {
++ /* FIXME handle 1 as long size */
++ break;
++ }
++ if( !strncmp( (char*)&psz[4], "SMI ", 4 ) )
++ {
++ memmove( &p[0x52], psz,
++ &p[p_sys->p_context->extradata_size] - psz );
++ break;
++ }
++
++ psz += atom_size;
++ }
++ }
++ }
++ else
++ {
++ p_sys->p_context->extradata_size = i_size;
++ p_sys->p_context->extradata =
++ av_malloc( i_size + FF_INPUT_BUFFER_PADDING_SIZE );
++ if( p_sys->p_context->extradata )
++ {
++ memcpy( p_sys->p_context->extradata,
++ p_dec->fmt_in.p_extra, i_size );
++ memset( p_sys->p_context->extradata + i_size,
++ 0, FF_INPUT_BUFFER_PADDING_SIZE );
++ }
++ }
++}
++
++
++static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_context,
++ const enum PixelFormat *pi_fmt )
++{
++ decoder_t *p_dec = p_context->opaque;
++ decoder_sys_t *p_sys = p_dec->p_sys;
++ video_format_t fmt;
++
++ /* Enumerate available formats */
++ enum PixelFormat swfmt = avcodec_default_get_format(p_context, pi_fmt);
++// bool can_hwaccel = false;
++
++ for (size_t i = 0; pi_fmt[i] != AV_PIX_FMT_NONE; i++)
++ {
++ const AVPixFmtDescriptor *dsc = av_pix_fmt_desc_get(pi_fmt[i]);
++ if (dsc == NULL)
++ continue;
++ bool hwaccel = (dsc->flags & AV_PIX_FMT_FLAG_HWACCEL) != 0;
++
++ msg_Dbg( p_dec, "available %sware decoder output format %d (%s)",
++ hwaccel ? "hard" : "soft", pi_fmt[i], dsc->name );
++// if (hwaccel)
++// can_hwaccel = true;
++ }
++
++ /* If the format did not actually change (e.g. seeking), try to reuse the
++ * existing output format, and if present, hardware acceleration back-end.
++ * This avoids resetting the pipeline downstream. This also avoids
++ * needlessly probing for hardware acceleration support. */
++ if (p_sys->pix_fmt != AV_PIX_FMT_NONE
++ && lavc_GetVideoFormat(p_dec, &fmt, p_context, p_sys->pix_fmt, swfmt) == 0
++ && fmt.i_width == p_dec->fmt_out.video.i_width
++ && fmt.i_height == p_dec->fmt_out.video.i_height
++ && p_context->profile == p_sys->profile
++ && p_context->level <= p_sys->level)
++ {
++ for (size_t i = 0; pi_fmt[i] != AV_PIX_FMT_NONE; i++)
++ if (pi_fmt[i] == p_sys->pix_fmt)
++ {
++ msg_Dbg(p_dec, "reusing decoder output format %d", pi_fmt[i]);
++ return p_sys->pix_fmt;
++ }
++ }
++
++// if (p_sys->p_va != NULL)
++// {
++// msg_Err(p_dec, "existing hardware acceleration cannot be reused");
++// vlc_va_Delete(p_sys->p_va, &p_context->hwaccel_context);
++// p_sys->p_va = NULL;
++// }
++
++ p_sys->profile = p_context->profile;
++ p_sys->level = p_context->level;
++
++#if 1
++ return swfmt;
++#else
++ if (!can_hwaccel)
++ return swfmt;
++
++#if (LIBAVCODEC_VERSION_MICRO >= 100) \
++ && (LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 83, 101))
++ if (p_context->active_thread_type)
++ {
++ msg_Warn(p_dec, "thread type %d: disabling hardware acceleration",
++ p_context->active_thread_type);
++ return swfmt;
++ }
++#endif
++
++ wait_mt(p_sys);
++
++ static const enum PixelFormat hwfmts[] =
++ {
++#ifdef _WIN32
++#if LIBAVUTIL_VERSION_CHECK(54, 13, 1, 24, 100)
++ AV_PIX_FMT_D3D11VA_VLD,
++#endif
++ AV_PIX_FMT_DXVA2_VLD,
++#endif
++ AV_PIX_FMT_VAAPI_VLD,
++#if (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 4, 0))
++ AV_PIX_FMT_VDPAU,
++#endif
++ AV_PIX_FMT_NONE,
++ };
++
++ for( size_t i = 0; hwfmts[i] != AV_PIX_FMT_NONE; i++ )
++ {
++ enum PixelFormat hwfmt = AV_PIX_FMT_NONE;
++ for( size_t j = 0; hwfmt == AV_PIX_FMT_NONE && pi_fmt[j] != AV_PIX_FMT_NONE; j++ )
++ if( hwfmts[i] == pi_fmt[j] )
++ hwfmt = hwfmts[i];
++
++ if( hwfmt == AV_PIX_FMT_NONE )
++ continue;
++
++ p_dec->fmt_out.video.i_chroma = vlc_va_GetChroma(hwfmt, swfmt);
++ if (p_dec->fmt_out.video.i_chroma == 0)
++ continue; /* Unknown brand of hardware acceleration */
++ if (p_context->width == 0 || p_context->height == 0)
++ { /* should never happen */
++ msg_Err(p_dec, "unspecified video dimensions");
++ continue;
++ }
++ const AVPixFmtDescriptor *dsc = av_pix_fmt_desc_get(hwfmt);
++ msg_Dbg(p_dec, "trying format %s", dsc ? dsc->name : "unknown");
++ if (lavc_UpdateVideoFormat(p_dec, p_context, hwfmt, swfmt))
++ continue; /* Unsupported brand of hardware acceleration */
++ post_mt(p_sys);
++
++ picture_t *test_pic = decoder_NewPicture(p_dec);
++ assert(!test_pic || test_pic->format.i_chroma == p_dec->fmt_out.video.i_chroma);
++ vlc_va_t *va = vlc_va_New(VLC_OBJECT(p_dec), p_context, hwfmt,
++ &p_dec->fmt_in,
++ test_pic ? test_pic->p_sys : NULL);
++ if (test_pic)
++ picture_Release(test_pic);
++ if (va == NULL)
++ {
++ wait_mt(p_sys);
++ continue; /* Unsupported codec profile or such */
++ }
++
++ if (va->description != NULL)
++ msg_Info(p_dec, "Using %s for hardware decoding", va->description);
++
++ p_sys->p_va = va;
++ p_sys->pix_fmt = hwfmt;
++ p_context->draw_horiz_band = NULL;
++ return hwfmt;
++ }
++
++ post_mt(p_sys);
++ /* Fallback to default behaviour */
++ p_sys->pix_fmt = swfmt;
++ return swfmt;
++#endif
++}
++
++/*****************************************************************************
++ * InitVideo: initialize the video decoder
++ *****************************************************************************
++ * the ffmpeg codec will be opened, some memory allocated. The vout is not yet
++ * opened (done after the first decoded frame).
++ *****************************************************************************/
++
++/*****************************************************************************
++ * ffmpeg_OpenCodec:
++ *****************************************************************************/
++
++static int MmalAvcodecOpenDecoder( vlc_object_t *obj )
++{
++ decoder_t *p_dec = (decoder_t *)obj;
++ const AVCodec *p_codec;
++
++ if (p_dec->fmt_in.i_codec != VLC_CODEC_HEVC)
++ return VLC_EGENERIC;
++
++ AVCodecContext *p_context = ffmpeg_AllocContext( p_dec, &p_codec );
++ if( p_context == NULL )
++ return VLC_EGENERIC;
++
++ int i_val;
++
++ /* Allocate the memory needed to store the decoder's structure */
++ decoder_sys_t *p_sys = calloc( 1, sizeof(*p_sys) );
++ if( unlikely(p_sys == NULL) )
++ {
++ avcodec_free_context( &p_context );
++ return VLC_ENOMEM;
++ }
++
++ p_dec->p_sys = p_sys;
++ p_sys->p_context = p_context;
++ p_sys->p_codec = p_codec;
++// p_sys->p_va = NULL;
++
++ /* ***** Fill p_context with init values ***** */
++ p_context->codec_tag = ffmpeg_CodecTag( p_dec->fmt_in.i_original_fourcc ?
++ p_dec->fmt_in.i_original_fourcc : p_dec->fmt_in.i_codec );
++
++ /* ***** Get configuration of ffmpeg plugin ***** */
++ p_context->workaround_bugs =
++ var_InheritInteger( p_dec, "avcodec-workaround-bugs" );
++ p_context->err_recognition =
++ var_InheritInteger( p_dec, "avcodec-error-resilience" );
++
++ if( var_CreateGetBool( p_dec, "grayscale" ) )
++ p_context->flags |= AV_CODEC_FLAG_GRAY;
++
++ /* ***** Output always the frames ***** */
++ p_context->flags |= AV_CODEC_FLAG_OUTPUT_CORRUPT;
++
++ i_val = var_CreateGetInteger( p_dec, "avcodec-skiploopfilter" );
++ if( i_val >= 4 ) p_context->skip_loop_filter = AVDISCARD_ALL;
++ else if( i_val == 3 ) p_context->skip_loop_filter = AVDISCARD_NONKEY;
++ else if( i_val == 2 ) p_context->skip_loop_filter = AVDISCARD_BIDIR;
++ else if( i_val == 1 ) p_context->skip_loop_filter = AVDISCARD_NONREF;
++ else p_context->skip_loop_filter = AVDISCARD_DEFAULT;
++
++ if( var_CreateGetBool( p_dec, "avcodec-fast" ) )
++ p_context->flags2 |= AV_CODEC_FLAG2_FAST;
++
++ /* ***** libavcodec frame skipping ***** */
++ p_sys->b_hurry_up = var_CreateGetBool( p_dec, "avcodec-hurry-up" );
++ p_sys->b_show_corrupted = var_CreateGetBool( p_dec, "avcodec-corrupted" );
++
++ i_val = var_CreateGetInteger( p_dec, "avcodec-skip-frame" );
++ if( i_val >= 4 ) p_sys->i_skip_frame = AVDISCARD_ALL;
++ else if( i_val == 3 ) p_sys->i_skip_frame = AVDISCARD_NONKEY;
++ else if( i_val == 2 ) p_sys->i_skip_frame = AVDISCARD_BIDIR;
++ else if( i_val == 1 ) p_sys->i_skip_frame = AVDISCARD_NONREF;
++ else if( i_val == -1 ) p_sys->i_skip_frame = AVDISCARD_NONE;
++ else p_sys->i_skip_frame = AVDISCARD_DEFAULT;
++ p_context->skip_frame = p_sys->i_skip_frame;
++
++ i_val = var_CreateGetInteger( p_dec, "avcodec-skip-idct" );
++ if( i_val >= 4 ) p_context->skip_idct = AVDISCARD_ALL;
++ else if( i_val == 3 ) p_context->skip_idct = AVDISCARD_NONKEY;
++ else if( i_val == 2 ) p_context->skip_idct = AVDISCARD_BIDIR;
++ else if( i_val == 1 ) p_context->skip_idct = AVDISCARD_NONREF;
++ else if( i_val == -1 ) p_context->skip_idct = AVDISCARD_NONE;
++ else p_context->skip_idct = AVDISCARD_DEFAULT;
++
++ /* ***** libavcodec direct rendering ***** */
++ p_sys->b_direct_rendering = false;
++ atomic_init(&p_sys->b_dr_failure, false);
++ if( var_CreateGetBool( p_dec, "avcodec-dr" ) &&
++ (p_codec->capabilities & AV_CODEC_CAP_DR1) &&
++ /* No idea why ... but this fixes flickering on some TSCC streams */
++ p_sys->p_codec->id != AV_CODEC_ID_TSCC &&
++ p_sys->p_codec->id != AV_CODEC_ID_CSCD &&
++ p_sys->p_codec->id != AV_CODEC_ID_CINEPAK )
++ {
++ /* Some codecs set pix_fmt only after the 1st frame has been decoded,
++ * so we need to do another check in ffmpeg_GetFrameBuf() */
++ p_sys->b_direct_rendering = true;
++ }
++
++ p_context->get_format = ffmpeg_GetFormat;
++ /* Always use our get_buffer wrapper so we can calculate the
++ * PTS correctly */
++// p_context->get_buffer2 = lavc_GetFrame;
++// p_context->opaque = p_dec;
++
++ int i_thread_count = var_InheritInteger( p_dec, "avcodec-threads" );
++ if( i_thread_count <= 0 )
++ i_thread_count = 6;
++#if 0
++ if( i_thread_count <= 0 )
++ {
++ i_thread_count = vlc_GetCPUCount();
++ if( i_thread_count > 1 )
++ i_thread_count++;
++
++ //FIXME: take in count the decoding time
++#if VLC_WINSTORE_APP
++ i_thread_count = __MIN( i_thread_count, 6 );
++#else
++ i_thread_count = __MIN( i_thread_count, p_codec->id == AV_CODEC_ID_HEVC ? 10 : 6 );
++#endif
++ }
++ i_thread_count = __MIN( i_thread_count, p_codec->id == AV_CODEC_ID_HEVC ? 32 : 16 );
++#endif
++ msg_Dbg( p_dec, "allowing %d thread(s) for decoding", i_thread_count );
++ p_context->thread_count = i_thread_count;
++ p_context->thread_safe_callbacks = true;
++
++ p_context->thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME;
++
++ if( p_context->thread_type & FF_THREAD_FRAME )
++ p_dec->i_extra_picture_buffers = 2 * p_context->thread_count;
++
++ /* ***** misc init ***** */
++ date_Init(&p_sys->pts, 1, 30001);
++ date_Set(&p_sys->pts, VLC_TS_INVALID);
++ p_sys->b_first_frame = true;
++ p_sys->i_late_frames = 0;
++ p_sys->b_from_preroll = false;
++
++ /* Set output properties */
++ if( GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) != VLC_SUCCESS )
++ {
++ /* we are doomed. but not really, because most codecs set their pix_fmt later on */
++ p_dec->fmt_out.i_codec = VLC_CODEC_I420;
++ }
++ p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma;
++
++ p_dec->fmt_out.video.orientation = p_dec->fmt_in.video.orientation;
++
++ if( p_dec->fmt_in.video.p_palette ) {
++ p_sys->palette_sent = false;
++ p_dec->fmt_out.video.p_palette = malloc( sizeof(video_palette_t) );
++ if( p_dec->fmt_out.video.p_palette )
++ *p_dec->fmt_out.video.p_palette = *p_dec->fmt_in.video.p_palette;
++ } else
++ p_sys->palette_sent = true;
++
++ /* ***** init this codec with special data ***** */
++ ffmpeg_InitCodec( p_dec );
++
++ /* ***** Open the codec ***** */
++ if( OpenVideoCodec( p_dec ) < 0 )
++ {
++ free( p_sys );
++ avcodec_free_context( &p_context );
++ return VLC_EGENERIC;
++ }
++
++ if ((p_sys->out_pool = mmal_pool_create(5, 0)) == NULL)
++ {
++ msg_Err(p_dec, "Failed to create mmal buffer pool");
++ goto fail;
++ }
++
++ p_dec->pf_decode = DecodeVideo;
++ p_dec->pf_flush = Flush;
++
++ /* XXX: Writing input format makes little sense. */
++ if( p_context->profile != FF_PROFILE_UNKNOWN )
++ p_dec->fmt_in.i_profile = p_context->profile;
++ if( p_context->level != FF_LEVEL_UNKNOWN )
++ p_dec->fmt_in.i_level = p_context->level;
++ return VLC_SUCCESS;
++
++fail:
++ MmalAvcodecCloseDecoder(VLC_OBJECT(p_dec));
++ return VLC_EGENERIC;
++}
++
++
++
++vlc_module_begin()
++ set_category( CAT_INPUT )
++ set_subcategory( SUBCAT_INPUT_VCODEC )
++ set_shortname(N_("MMAL avcodec"))
++ set_description(N_("MMAL buffered avcodec "))
++ set_capability("video decoder", 800)
++ add_shortcut("mmal_avcodec")
++ set_callbacks(MmalAvcodecOpenDecoder, MmalAvcodecCloseDecoder)
++vlc_module_end()
++
--- a/modules/hw/mmal/mmal_picture.c
+++ b/modules/hw/mmal/mmal_picture.c
-@@ -21,25 +21,847 @@
+@@ -21,25 +21,961 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
@@ -3681,12 +6204,51 @@
+ return MMAL_COLOR_SPACE_UNKNOWN;
+}
+
++MMAL_FOURCC_T vlc_to_mmal_video_fourcc(const video_frame_format_t * const vf_vlc)
++{
++ switch (vf_vlc->i_chroma) {
++ case VLC_CODEC_RGB32:
++ {
++ // VLC RGB32 aka RV32 means we have to look at the mask values
++ const uint32_t r = vf_vlc->i_rmask;
++ const uint32_t g = vf_vlc->i_gmask;
++ const uint32_t b = vf_vlc->i_bmask;
++ if (r == 0xff0000 && g == 0xff00 && b == 0xff)
++ return MMAL_ENCODING_BGRA;
++ if (r == 0xff && g == 0xff00 && b == 0xff0000)
++ return MMAL_ENCODING_RGBA;
++ if (r == 0xff000000 && g == 0xff0000 && b == 0xff00)
++ return MMAL_ENCODING_ABGR;
++ if (r == 0xff00 && g == 0xff0000 && b == 0xff000000)
++ return MMAL_ENCODING_ARGB;
++ break;
++ }
++ case VLC_CODEC_RGBA:
++ return MMAL_ENCODING_RGBA;
++ case VLC_CODEC_BGRA:
++ return MMAL_ENCODING_BGRA;
++ case VLC_CODEC_ARGB:
++ return MMAL_ENCODING_ARGB;
++ // VLC_CODEC_ABGR does not exist in VLC
++ case VLC_CODEC_MMAL_OPAQUE:
++ return MMAL_ENCODING_OPAQUE;
++ case VLC_CODEC_MMAL_ZC_SAND8:
++ return MMAL_ENCODING_YUVUV128;
++ case VLC_CODEC_MMAL_ZC_SAND10:
++ return MMAL_ENCODING_YUVUV64_10;
++ default:
++ break;
++ }
++ return 0;
++}
++
++
+void vlc_to_mmal_video_fmt(MMAL_ES_FORMAT_T *const es_fmt, const video_frame_format_t * const vf_vlc)
+{
+ MMAL_VIDEO_FORMAT_T * const vf_mmal = &es_fmt->es->video;
+
+ vf_mmal->width = (vf_vlc->i_width + 31) & ~31;
-+ vf_mmal->height = (vf_vlc->i_height + 15) & ~15;;
++ vf_mmal->height = (vf_vlc->i_height + 15) & ~15;
+ vf_mmal->crop.x = vf_vlc->i_x_offset;
+ vf_mmal->crop.y = vf_vlc->i_y_offset;
+ vf_mmal->crop.width = vf_vlc->i_visible_width;
@@ -3754,7 +6316,7 @@
+
+// Put buffer in port if possible - if not then release to pool
+// Returns true if sent, false if recycled
-+static bool hw_mmal_port_pool_ref_recycle(hw_mmal_port_pool_ref_t * const ppr, MMAL_BUFFER_HEADER_T * const buf)
++bool hw_mmal_port_pool_ref_recycle(hw_mmal_port_pool_ref_t * const ppr, MMAL_BUFFER_HEADER_T * const buf)
+{
+ mmal_buffer_header_reset(buf);
+ buf->user_data = NULL;
@@ -3780,6 +6342,58 @@
+ return err;
+}
+
++
++MMAL_STATUS_T hw_mmal_opaque_output(vlc_object_t * const obj,
++ hw_mmal_port_pool_ref_t ** pppr,
++ MMAL_PORT_T * const port,
++ const unsigned int extra_buffers, MMAL_PORT_BH_CB_T callback)
++{
++ MMAL_STATUS_T status;
++
++ port->userdata = (struct MMAL_PORT_USERDATA_T *)obj;
++
++ status = port_parameter_set_uint32(port, MMAL_PARAMETER_EXTRA_BUFFERS, extra_buffers);
++ if (status != MMAL_SUCCESS) {
++ msg_Err(obj, "Failed to set MMAL_PARAMETER_EXTRA_BUFFERS on output port (status=%"PRIx32" %s)",
++ status, mmal_status_to_string(status));
++ return status;
++ }
++
++ status = port_parameter_set_bool(port, MMAL_PARAMETER_ZERO_COPY, 1);
++ if (status != MMAL_SUCCESS) {
++ msg_Err(obj, "Failed to set zero copy on port %s (status=%"PRIx32" %s)",
++ port->name, status, mmal_status_to_string(status));
++ return status;
++ }
++
++ port->format->encoding = MMAL_ENCODING_OPAQUE;
++ port->format->encoding_variant = 0;
++ if ((status = mmal_port_format_commit(port)) != MMAL_SUCCESS)
++ {
++ msg_Err(obj, "Failed to commit format on port %s (status=%"PRIx32" %s)",
++ port->name, status, mmal_status_to_string(status));
++ return status;
++ }
++
++ port->buffer_num = 30;
++ port->buffer_size = port->buffer_size_recommended;
++
++ if ((*pppr = hw_mmal_port_pool_ref_create(port, port->buffer_num, port->buffer_size)) == NULL) {
++ msg_Err(obj, "Failed to create output pool");
++ return status;
++ }
++
++ 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;
++ }
++
++ return MMAL_SUCCESS;
++}
++
++
+void hw_mmal_pic_ctx_destroy(picture_context_t * pic_ctx_cmn)
+{
+ pic_ctx_mmal_t * const ctx = (pic_ctx_mmal_t *)pic_ctx_cmn;
@@ -3833,23 +6447,27 @@
+// Buffer belongs to context on successful return from this fn
+// is still valid on failure
+picture_context_t *
-+hw_mmal_gen_context(MMAL_BUFFER_HEADER_T * buf, hw_mmal_port_pool_ref_t * const ppr)
++hw_mmal_gen_context(const MMAL_FOURCC_T fmt, MMAL_BUFFER_HEADER_T * buf, hw_mmal_port_pool_ref_t * const ppr)
+{
+ pic_ctx_mmal_t * const ctx = calloc(1, sizeof(pic_ctx_mmal_t));
+
+ if (ctx == NULL)
+ return NULL;
+
-+ hw_mmal_port_pool_ref_acquire(ppr);
-+ mmal_buffer_header_pre_release_cb_set(buf, buf_pre_release_cb, ppr);
++ // If we have an associated ppr then ref & set appropriate callbacks
++ if (ppr != NULL) {
++ hw_mmal_port_pool_ref_acquire(ppr);
++ mmal_buffer_header_pre_release_cb_set(buf, buf_pre_release_cb, ppr);
++ buf->user_data = NULL;
++ }
+
+ ctx->cmn.copy = hw_mmal_pic_ctx_copy;
+ ctx->cmn.destroy = hw_mmal_pic_ctx_destroy;
+
-+ ctx->bufs[0] = buf;
++ ctx->fmt = fmt;
+ ctx->buf_count = 1;
++ ctx->bufs[0] = buf;
+
-+ buf->user_data = NULL;
+ return &ctx->cmn;
+}
+
@@ -3922,6 +6540,7 @@
+
+ unsigned int width;
+ unsigned int height;
++ MMAL_FOURCC_T enc_type;
+
+ picture_t * pic;
+} pool_ent_t;
@@ -4069,9 +6688,7 @@
+#define POOL_ENT_ALLOC_BLOCK 0x10000
+
+static pool_ent_t * pool_ent_alloc_new(size_t req_size)
- {
-- picture_sys_t *pic_sys = picture->p_sys;
-- MMAL_BUFFER_HEADER_T *buffer = pic_sys->buffer;
++{
+ pool_ent_t * ent = calloc(1, sizeof(*ent));
+ const size_t alloc_size = (req_size + POOL_ENT_ALLOC_BLOCK - 1) & ~(POOL_ENT_ALLOC_BLOCK - 1);
+
@@ -4120,21 +6737,14 @@
+
+ if (n != 0)
+ return;
-
-- 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;
++
+ if (ent->pic != NULL) {
+ picture_Release(ent->pic);
+ ent->pic = NULL;
- }
-
-- pic_sys->displayed = false;
++ }
++
+ vlc_mutex_lock(&pc->lock);
-
-- return VLC_SUCCESS;
++
+ // If we have a full pool then extract the LRU and free it
+ // Free done outside mutex
+ if (pc->ent_pool.n >= pc->max_n)
@@ -4145,7 +6755,7 @@
+ vlc_mutex_unlock(&pc->lock);
+
+ ent_free(xs);
- }
++}
+
+// * This could be made more efficient, but this is easy
+static void pool_recycle_list(vzc_pool_ctl_t * const pc, ent_list_hdr_t * const elh)
@@ -4189,14 +6799,22 @@
+ return best;
+}
+
++
++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;
++ *pW = ent->width;
++ *pH = ent->height;
++}
++
+bool hw_mmal_vzc_buf_set_format(MMAL_BUFFER_HEADER_T * const buf, MMAL_ES_FORMAT_T * const es_fmt)
+{
+ const pool_ent_t *const ent = ((vzc_subbuf_ent_t *)buf->user_data)->ent;
+ MMAL_VIDEO_FORMAT_T * const v_fmt = &es_fmt->es->video;
+
+ es_fmt->type = MMAL_ES_TYPE_VIDEO;
-+ es_fmt->encoding = MMAL_ENCODING_BGRA;
-+ es_fmt->encoding_variant = MMAL_ENCODING_BGRA;
++ es_fmt->encoding = ent->enc_type;
++ es_fmt->encoding_variant = 0;
+
+ v_fmt->width = ent->width;
+ v_fmt->height = ent->height;
@@ -4246,7 +6864,9 @@
+}
+
+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;
@@ -4306,6 +6926,7 @@
+ const size_t dst_size = dst_stride * dst_lines;
+
+ pool_ent_t * ent = ent_list_extract_pic_ent(&pc->ents_prev, pic);
++ bool needs_copy = false;
+
+ // If we didn't find ent in last then look in cur in case is_first
+ // isn't working
@@ -4316,8 +6937,14 @@
+
+ if (ent == NULL)
+ {
++ // Need a new ent
++ needs_copy = true;
++
+ if ((ent = pool_best_fit(pc, dst_size)) == NULL)
+ goto fail2;
++ if ((ent->enc_type = vlc_to_mmal_video_fourcc(&pic->format)) == 0)
++ goto fail2;
++
+ ent->pic = picture_Hold(pic);
+ }
+
@@ -4358,22 +6985,25 @@
+ .height = dst_pic->format.i_visible_height
+ };
+
-+ ent->width = dst_stride / bpp;
-+ ent->height = dst_lines;
-+
-+ // 2D copy
++ if (needs_copy)
+ {
-+ unsigned int i;
-+ uint8_t *d = ent->buf;
-+ const uint8_t *s = pic->p[0].p_pixels + xl * bpp + fmt->i_y_offset * pic->p[0].i_pitch;
-+ for (i = 0; i != fmt->i_visible_height; ++i) {
-+ memcpy(d, s, dst_stride);
-+ d += dst_stride;
-+ s += pic->p[0].i_pitch;
-+ }
++ ent->width = dst_stride / bpp;
++ ent->height = dst_lines;
+
-+ // And make sure it is actually in memory
-+ flush_range(ent->buf, d - (uint8_t *)ent->buf);
++ // 2D copy
++ {
++ unsigned int i;
++ uint8_t *d = ent->buf;
++ const uint8_t *s = pic->p[0].p_pixels + xl * bpp + fmt->i_y_offset * pic->p[0].i_pitch;
++ for (i = 0; i != fmt->i_visible_height; ++i) {
++ memcpy(d, s, dst_stride);
++ d += dst_stride;
++ s += pic->p[0].i_pitch;
++ }
++
++ // And make sure it is actually in memory
++ flush_range(ent->buf, d - (uint8_t *)ent->buf);
++ }
+ }
+ }
+
@@ -4391,7 +7021,12 @@
+ 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)
+{
+
@@ -4472,20 +7107,22 @@
+ {
+ 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;
-+}
+ }
+
+
+
--- a/modules/hw/mmal/mmal_picture.h
+++ b/modules/hw/mmal/mmal_picture.h
-@@ -24,19 +24,209 @@
+@@ -24,19 +24,243 @@
#ifndef VLC_MMAL_MMAL_PICTURE_H_
#define VLC_MMAL_MMAL_PICTURE_H_
@@ -4521,10 +7158,15 @@
+
+
+#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
+
++ MMAL_FOURCC_T fmt;
++
+ unsigned int buf_count;
+ MMAL_BUFFER_HEADER_T * bufs[CTX_BUFS_MAX];
+
@@ -4538,23 +7180,25 @@
+ vlc_object_t * obj;
+#endif
+} pic_ctx_mmal_t;
-+
-+
+
+-int mmal_picture_lock(picture_t *picture);
++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);
-
-- MMAL_BUFFER_HEADER_T *buffer;
-- bool displayed;
--};
++
+hw_mmal_port_pool_ref_t * hw_mmal_port_pool_ref_create(MMAL_PORT_T * const port,
+ const unsigned int headers, const uint32_t payload_size);
+void hw_mmal_port_pool_ref_release(hw_mmal_port_pool_ref_t * const ppr, const bool in_cb);
-+//bool hw_mmal_port_pool_ref_recycle(hw_mmal_port_pool_ref_t * const ppr, MMAL_BUFFER_HEADER_T * const buf);
++bool hw_mmal_port_pool_ref_recycle(hw_mmal_port_pool_ref_t * const ppr, MMAL_BUFFER_HEADER_T * const buf);
+MMAL_STATUS_T hw_mmal_port_pool_ref_fill(hw_mmal_port_pool_ref_t * const ppr);
+static inline void hw_mmal_port_pool_ref_acquire(hw_mmal_port_pool_ref_t * const ppr)
+{
+ atomic_fetch_add(&ppr->refs, 1);
+}
++MMAL_STATUS_T hw_mmal_opaque_output(vlc_object_t * const obj,
++ hw_mmal_port_pool_ref_t ** pppr,
++ MMAL_PORT_T * const port,
++ const unsigned int extra_buffers, MMAL_PORT_BH_CB_T callback);
+
+static inline int hw_mmal_pic_has_sub_bufs(picture_t * const pic)
+{
@@ -4581,10 +7225,24 @@
+ return n + 1 > ctx->buf_count ? NULL : ctx->bufs[n + 1];
+}
+
++static inline bool hw_mmal_pic_is_mmal(const picture_t * const pic)
++{
++ 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;
++}
++
++static inline MMAL_FOURCC_T hw_mmal_pic_format(const picture_t *const pic)
++{
++ const pic_ctx_mmal_t * const ctx = (pic_ctx_mmal_t *)pic->context;
++ return ctx->fmt;
++}
++
+picture_context_t * hw_mmal_pic_ctx_copy(picture_context_t * pic_ctx_cmn);
+void hw_mmal_pic_ctx_destroy(picture_context_t * pic_ctx_cmn);
-+picture_context_t * hw_mmal_gen_context(MMAL_BUFFER_HEADER_T * buf,
-+ hw_mmal_port_pool_ref_t * const ppr);
++picture_context_t * hw_mmal_gen_context(const MMAL_FOURCC_T fmt,
++ MMAL_BUFFER_HEADER_T * buf, hw_mmal_port_pool_ref_t * const ppr);
+
+int hw_mmal_get_gpu_mem(void);
+
@@ -4598,7 +7256,7 @@
+ return mmal_port_parameter_set(port, ¶m.hdr);
+}
+
-+static inline MMAL_STATUS_T port_parameter_set_bool(MMAL_PORT_T * port, uint32_t id, int val)
++static inline MMAL_STATUS_T port_parameter_set_bool(MMAL_PORT_T * const port, const uint32_t id, const bool val)
+{
+ const MMAL_PARAMETER_BOOLEAN_T param = {
+ .hdr = {.id = id, .size = sizeof(MMAL_PARAMETER_BOOLEAN_T)},
@@ -4670,6 +7328,7 @@
+}
+
+// Retrieve buf from pic & update with pic props
++// Note that this is a weak pointer - replicate before putting in a Q
+static inline MMAL_BUFFER_HEADER_T * pic_mmal_buffer(const picture_t *const pic)
+{
+ MMAL_BUFFER_HEADER_T * const buf = ((pic_ctx_mmal_t *)pic->context)->bufs[0];
@@ -4682,10 +7341,19 @@
+struct vzc_pool_ctl_s;
+typedef struct vzc_pool_ctl_s vzc_pool_ctl_t;
+
++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;
++}
++
+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);
+void hw_mmal_vzc_buf_frame_size(MMAL_BUFFER_HEADER_T * const buf,
@@ -4695,13 +7363,129 @@
+void hw_mmal_vzc_pool_release(vzc_pool_ctl_t * const pc);
+void hw_mmal_vzc_pool_ref(vzc_pool_ctl_t * const pc);
+vzc_pool_ctl_t * hw_mmal_vzc_pool_new(void);
-
--int mmal_picture_lock(picture_t *picture);
++
+#define VOUT_DISPLAY_CHANGE_MMAL_BASE 1024
+#define VOUT_DISPLAY_CHANGE_MMAL_HIDE (VOUT_DISPLAY_CHANGE_MMAL_BASE + 0)
++
++#define MMAL_COMPONENT_DEFAULT_RESIZER "vc.ril.resize"
++#define MMAL_COMPONENT_ISP_RESIZER "vc.ril.isp"
++#define MMAL_COMPONENT_HVS "vc.ril.hvs"
#endif
--- /dev/null
++++ b/modules/hw/mmal/rpi_prof.h
+@@ -0,0 +1,110 @@
++#ifndef RPI_PROFILE_H
++#define RPI_PROFILE_H
++
++#include <stdint.h>
++#include <inttypes.h>
++
++#ifndef RPI_PROFILE
++#define RPI_PROFILE 0
++#endif
++
++#if RPI_PROFILE
++
++#include "v7_pmu.h"
++
++#ifdef RPI_PROC_ALLOC
++#define X volatile
++#define Z =0
++#else
++#define X extern volatile
++#define Z
++#endif
++
++X uint64_t av_rpi_prof0_cycles Z;
++X unsigned int av_rpi_prof0_cnt Z;
++#define RPI_prof0_MAX_DURATION 100000
++
++X uint64_t av_rpi_prof1_cycles Z;
++X unsigned int av_rpi_prof1_cnt Z;
++#define RPI_prof1_MAX_DURATION 100000
++
++X uint64_t av_rpi_prof2_cycles Z;
++X unsigned int av_rpi_prof2_cnt Z;
++#define RPI_prof2_MAX_DURATION 10000
++
++X uint64_t av_rpi_prof_n_cycles[128];
++X unsigned int av_rpi_prof_n_cnt[128];
++#define RPI_prof_n_MAX_DURATION 10000
++
++
++#undef X
++#undef Z
++
++#define PROFILE_INIT()\
++do {\
++ enable_pmu();\
++ enable_ccnt();\
++} while (0)
++
++#define PROFILE_START()\
++do {\
++ volatile uint32_t perf_1 = read_ccnt();\
++ volatile uint32_t perf_2
++
++
++#define PROFILE_ACC(x)\
++ perf_2 = read_ccnt();\
++ {\
++ const uint32_t duration = perf_2 - perf_1;\
++ if (duration < RPI_##x##_MAX_DURATION)\
++ {\
++ av_rpi_##x##_cycles += duration;\
++ av_rpi_##x##_cnt += 1;\
++ }\
++ }\
++} while(0)
++
++
++#define PROFILE_ACC_N(n)\
++ if ((n) >= 0) {\
++ perf_2 = read_ccnt();\
++ {\
++ const uint32_t duration = perf_2 - perf_1;\
++ if (duration < RPI_prof_n_MAX_DURATION)\
++ {\
++ av_rpi_prof_n_cycles[n] += duration;\
++ av_rpi_prof_n_cnt[n] += 1;\
++ }\
++ }\
++ }\
++} while(0)
++
++#define PROFILE_PRINTF(x)\
++ printf("%-20s cycles=%14" PRIu64 "; cnt=%8u; avg=%5" PRIu64 "\n", #x, av_rpi_##x##_cycles, av_rpi_##x##_cnt,\
++ av_rpi_##x##_cnt == 0 ? (uint64_t)0 : av_rpi_##x##_cycles / (uint64_t)av_rpi_##x##_cnt)
++
++#define PROFILE_PRINTF_N(n)\
++ printf("prof[%d] cycles=%14" PRIu64 "; cnt=%8u; avg=%5" PRIu64 "\n", (n), av_rpi_prof_n_cycles[n], av_rpi_prof_n_cnt[n],\
++ av_rpi_prof_n_cnt[n] == 0 ? (uint64_t)0 : av_rpi_prof_n_cycles[n] / (uint64_t)av_rpi_prof_n_cnt[n])
++
++#define PROFILE_CLEAR_N(n) \
++do {\
++ av_rpi_prof_n_cycles[n] = 0;\
++ av_rpi_prof_n_cnt[n] = 0;\
++} while(0)
++
++#else
++
++// No profile
++#define PROFILE_INIT()
++#define PROFILE_START()
++#define PROFILE_ACC(x)
++#define PROFILE_ACC_N(x)
++#define PROFILE_PRINTF(x)
++#define PROFILE_PRINTF_N(x)
++#define PROFILE_CLEAR_N(n)
++
++#endif
++
++#endif
++
+--- /dev/null
+++ b/modules/hw/mmal/subpic.c
@@ -0,0 +1,222 @@
+/*****************************************************************************
@@ -4927,35 +7711,417 @@
+
+
--- /dev/null
-+++ b/modules/hw/mmal/subpic.h
-@@ -0,0 +1,28 @@
-+#ifndef VLC_HW_MMAL_SUBPIC_H_
-+#define VLC_HW_MMAL_SUBPIC_H_
-+
-+typedef struct subpic_reg_stash_s
-+{
-+ MMAL_PORT_T * port;
-+ MMAL_POOL_T * pool;
-+ unsigned int layer;
-+ // Shadow vars so we can tell if stuff has changed
-+ MMAL_RECT_T dest_rect;
-+ unsigned int alpha;
-+ unsigned int seq;
-+} 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);
-+
-+void hw_mmal_subpic_flush(vlc_object_t * const p_filter, subpic_reg_stash_t * const spe);
-+
-+void hw_mmal_subpic_close(vlc_object_t * const p_filter, subpic_reg_stash_t * const spe);
-+
-+MMAL_STATUS_T hw_mmal_subpic_open(vlc_object_t * const p_filter, subpic_reg_stash_t * const spe, MMAL_PORT_T * const port, const unsigned int layer);
-+
-+#endif
++++ b/modules/hw/mmal/subpic.h
+@@ -0,0 +1,28 @@
++#ifndef VLC_HW_MMAL_SUBPIC_H_
++#define VLC_HW_MMAL_SUBPIC_H_
++
++typedef struct subpic_reg_stash_s
++{
++ MMAL_PORT_T * port;
++ MMAL_POOL_T * pool;
++ unsigned int layer;
++ // Shadow vars so we can tell if stuff has changed
++ MMAL_RECT_T dest_rect;
++ unsigned int alpha;
++ unsigned int seq;
++} 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);
++
++void hw_mmal_subpic_flush(vlc_object_t * const p_filter, subpic_reg_stash_t * const spe);
++
++void hw_mmal_subpic_close(vlc_object_t * const p_filter, subpic_reg_stash_t * const spe);
++
++MMAL_STATUS_T hw_mmal_subpic_open(vlc_object_t * const p_filter, subpic_reg_stash_t * const spe, MMAL_PORT_T * const port, const unsigned int layer);
++
++#endif
++
+--- /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 */
++/* ------------------------------------------------------------ */
++
++
+--- /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
++// ------------------------------------------------------------
+
--- a/modules/hw/mmal/vout.c
+++ b/modules/hw/mmal/vout.c
@@ -5070,7 +8236,7 @@
int next_phase_check; /* lowpass for phase check frequency */
int phase_offset; /* currently applied offset to presentation time in ns */
-@@ -136,32 +100,18 @@
+@@ -136,264 +100,415 @@
bool native_interlaced;
bool b_top_field_first; /* cached interlaced settings to detect changes for native mode */
bool b_progressive;
@@ -5084,13 +8250,22 @@
+ vout_subpic_t subs[SUBS_MAX];
+
+ picture_pool_t * pic_pool;
++
++ struct vout_isp_conf_s {
++ MMAL_COMPONENT_T *component;
++ MMAL_PORT_T * input;
++ MMAL_PORT_T * output;
++ MMAL_QUEUE_T * out_q;
++ MMAL_POOL_T * in_pool;
++ MMAL_POOL_T * out_pool;
++ bool pending;
++ } isp;
};
-+
- /* Utility functions */
+-/* 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);
+-static int configure_display(vout_display_t *vd, const vout_display_cfg_t *cfg,
+- const video_format_t *fmt);
-/* VLC vout display callbacks */
-static picture_pool_t *vd_pool(vout_display_t *vd, unsigned count);
@@ -5104,13 +8279,18 @@
-/* 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);
--
- /* TV service */
- static int query_resolution(vout_display_t *vd, unsigned *width, unsigned *height);
- static void tvservice_cb(void *callback_data, uint32_t reason, uint32_t param1,
-@@ -169,221 +119,52 @@
- 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);
++// ISP setup
+
+-/* TV service */
+-static int query_resolution(vout_display_t *vd, unsigned *width, unsigned *height);
+-static void tvservice_cb(void *callback_data, uint32_t reason, uint32_t param1,
+- 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);
@@ -5122,11 +8302,25 @@
-static void dmx_region_delete(struct dmx_region_t *dmx_region,
- DISPMANX_UPDATE_HANDLE_T update);
-static void show_background(vout_display_t *vd, bool enable);
-+// Mmal
- static void maintain_phase_sync(vout_display_t *vd);
+-static void maintain_phase_sync(vout_display_t *vd);
++static MMAL_FOURCC_T vout_vlc_to_mmal_pic_fourcc(const unsigned int fcc)
++{
++ switch (fcc){
++ case VLC_CODEC_MMAL_OPAQUE:
++ return MMAL_ENCODING_OPAQUE;
++ case VLC_CODEC_MMAL_ZC_SAND8:
++ return MMAL_ENCODING_YUVUV128;
++ case VLC_CODEC_MMAL_ZC_SAND10:
++ return MMAL_ENCODING_YUVUV64_10; // It will be after we've converted it...
++ default:
++ break;
++ }
++ return 0;
++}
-static int Open(vlc_object_t *object)
--{
++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;
@@ -5135,20 +8329,68 @@
- 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;
++
++ es_fmt->type = MMAL_ES_TYPE_VIDEO;
++ es_fmt->encoding = is_intermediate ? MMAL_ENCODING_I420 : vout_vlc_to_mmal_pic_fourcc(vd->fmt.i_chroma);;
++ es_fmt->encoding_variant = 0;
++
++ v_fmt->width = (w + 31) & ~31;
++ v_fmt->height = (h + 15) & ~15;
++ v_fmt->crop.x = 0;
++ v_fmt->crop.y = 0;
++ v_fmt->crop.width = w;
++ v_fmt->crop.height = h;
++ if (vd->fmt.i_sar_num == 0 || vd->fmt.i_sar_den == 0) {
++ v_fmt->par.num = 1;
++ v_fmt->par.den = 1;
++ } 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;
--
++static void display_src_rect(const vout_display_t * const vd, MMAL_RECT_T *const rect)
++{
++ const bool wants_isp = want_isp(vd);
++ rect->x = wants_isp ? 0 : vd->fmt.i_x_offset;
++ rect->y = wants_isp ? 0 : vd->fmt.i_y_offset;
++ 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
++ vout_display_t * const vd = (vout_display_t *)port->userdata;
++ pic_ctx_mmal_t * ctx = buf->user_data;
++ msg_Dbg(vd, "<<< %s: cmd=%d, ctx=%p, buf=%p, flags=%#x, pts=%lld", __func__, buf->cmd, ctx, buf,
++ buf->flags, (long long)buf->pts);
++#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)",
@@ -5156,7 +8398,11 @@
- 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) {
@@ -5164,11 +8410,16 @@
- 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));
+ }
+
- sys->input = sys->component->input[0];
- sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)vd;
--
++ mmal_buffer_header_release(buffer);
++}
+
- if (sys->opaque) {
- sys->input->format->encoding = MMAL_ENCODING_OPAQUE;
- sys->i_planes = 1;
@@ -5190,16 +8441,14 @@
- sys->input->format->es->video.crop.height = vd->fmt.i_height;
- sys->input->format->es->video.par.num = vd->source.i_sar_num;
- sys->input->format->es->video.par.den = vd->source.i_sar_den;
-+static void vd_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
++static void isp_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
+{
-+#if TRACE_ALL
-+ vout_display_t * const vd = (vout_display_t *)port->userdata;
-+ pic_ctx_mmal_t * ctx = buf->user_data;
-+ msg_Dbg(vd, "<<< %s[%d] cmd=%d, ctx=%p, buf=%p, flags=%#x, pts=%lld", __func__, buf->cmd, ctx, buf,
-+ buf->flags, (long long)buf->pts);
-+#else
-+ VLC_UNUSED(port);
-+#endif
++ if (buf->cmd == 0 && buf->length != 0)
++ {
++ // The filter structure etc. should always exist if we have contents
++ // but might not on later flushes as we shut down
++ vout_display_t * const vd = (vout_display_t *)port->userdata;
++ struct vout_isp_conf_s *const isp = &vd->sys->isp;
- status = mmal_port_format_commit(sys->input);
- if (status != MMAL_SUCCESS) {
@@ -5207,9 +8456,21 @@
- sys->input->name, status, mmal_status_to_string(status));
- ret = VLC_EGENERIC;
- goto out;
-- }
++#if TRACE_ALL
++ msg_Dbg(vd, "<<< %s: cmd=%d; flags=%#x, pts=%lld", __func__, buf->cmd, buf->flags, (long long) buf->pts);
++#endif
++ mmal_queue_put(isp->out_q, buf);
++#if TRACE_ALL
++ msg_Dbg(vd, ">>> %s: out Q len=%d", __func__, mmal_queue_length(isp->out_q));
++#endif
+ }
- sys->input->buffer_size = sys->input->buffer_size_recommended;
-+ mmal_buffer_header_release(buf);
++ else
++ {
++ mmal_buffer_header_reset(buf);
++ mmal_buffer_header_release(buf);
++ }
++}
- vout_display_PlacePicture(&place, &vd->source, vd->cfg, false);
- display_region.hdr.id = MMAL_PARAMETER_DISPLAYREGION;
@@ -5232,100 +8493,189 @@
- status, mmal_status_to_string(status));
- ret = VLC_EGENERIC;
- goto out;
-- }
-+#if TRACE_ALL
-+ msg_Dbg(vd, ">>> %s", __func__);
-+#endif
++static void isp_empty_out_q(struct vout_isp_conf_s * const isp)
++{
++ MMAL_BUFFER_HEADER_T * buf;
++ // We can be called as part of error recovery so allow for missing Q
++ if (isp->out_q == NULL)
++ return;
++
++ while ((buf = mmal_queue_get(isp->out_q)) != NULL)
++ mmal_buffer_header_release(buf);
++}
++
++static void isp_flush(struct vout_isp_conf_s * const isp)
++{
++ if (!isp->input->is_enabled)
++ mmal_port_disable(isp->input);
++
++ if (isp->output->is_enabled)
++ mmal_port_disable(isp->output);
++
++ isp_empty_out_q(isp);
++ isp->pending = false;
+}
++
++static MMAL_STATUS_T isp_prepare(vout_display_t * const vd, struct vout_isp_conf_s * const isp)
++{
++ MMAL_STATUS_T err;
++ MMAL_BUFFER_HEADER_T * buf;
++
++ if (!isp->output->is_enabled) {
++ if ((err = mmal_port_enable(isp->output, isp_output_cb)) != MMAL_SUCCESS)
++ {
++ msg_Err(vd, "ISP output port enable failed");
++ return err;
++ }
+ }
- for (i = 0; i < sys->i_planes; ++i) {
- sys->planes[i].i_lines = buffer_height;
- sys->planes[i].i_pitch = buffer_pitch;
- sys->planes[i].i_visible_lines = vd->fmt.i_visible_height;
- sys->planes[i].i_visible_pitch = vd->fmt.i_visible_width;
-+static int query_resolution(vout_display_t *vd, unsigned *width, unsigned *height)
-+{
-+ TV_DISPLAY_STATE_T display_state;
-+ int ret = 0;
++ while ((buf = mmal_queue_get(isp->out_pool->queue)) != NULL) {
++ if ((err = mmal_port_send_buffer(isp->output, buf)) != MMAL_SUCCESS)
++ {
++ msg_Err(vd, "ISP output port stuff failed");
++ return err;
++ }
++ }
- if (i > 0) {
- sys->planes[i].i_lines /= 2;
- sys->planes[i].i_pitch /= 2;
- sys->planes[i].i_visible_lines /= 2;
- sys->planes[i].i_visible_pitch /= 2;
-+ if (vc_tv_get_display_state(&display_state) == 0) {
-+ if (display_state.state & 0xFF) {
-+ *width = display_state.display.hdmi.width;
-+ *height = display_state.display.hdmi.height;
-+ } else if (display_state.state & 0xFF00) {
-+ *width = display_state.display.sdtv.width;
-+ *height = display_state.display.sdtv.height;
-+ } else {
-+ msg_Warn(vd, "Invalid display state %"PRIx32, display_state.state);
-+ ret = -1;
++ if (!isp->input->is_enabled) {
++ if ((err = mmal_port_enable(isp->input, isp_input_cb)) != MMAL_SUCCESS)
++ {
++ msg_Err(vd, "ISP input port enable failed");
++ return err;
}
-- }
--
+ }
++ return MMAL_SUCCESS;
++}
+
- vlc_mutex_init(&sys->buffer_mutex);
- vlc_cond_init(&sys->buffer_cond);
- vlc_mutex_init(&sys->manage_mutex);
--
++static void isp_close(vout_display_t * const vd, vout_display_sys_t * const vd_sys)
++{
++ struct vout_isp_conf_s * const isp = &vd_sys->isp;
++ VLC_UNUSED(vd);
+
- vd->pool = vd_pool;
- vd->prepare = vd_prepare;
- vd->display = vd_display;
- vd->control = vd_control;
- vd->manage = vd_manage;
--
++ if (isp->component == NULL)
++ return;
+
- vc_tv_register_callback(tvservice_cb, vd);
--
++ isp_flush(isp);
+
- if (query_resolution(vd, &sys->display_width, &sys->display_height) >= 0) {
- vout_display_SendEventDisplaySize(vd, sys->display_width, sys->display_height);
- } else {
+- } else {
- sys->display_width = vd->cfg->display.width;
- sys->display_height = vd->cfg->display.height;
-+ msg_Warn(vd, "Failed to query display resolution");
-+ ret = -1;
++ if (isp->component->control->is_enabled)
++ mmal_port_disable(isp->component->control);
++
++ if (isp->out_q != NULL) {
++ // 1st junk anything lying around
++ isp_empty_out_q(isp);
++
++ mmal_queue_destroy(isp->out_q);
++ isp->out_q = NULL;
}
- sys->dmx_handle = vc_dispmanx_display_open(0);
- vd->info.subpicture_chromas = subpicture_chromas;
--
++ if (isp->out_pool != NULL) {
++ mmal_port_pool_destroy(isp->output, isp->out_pool);
++ isp->out_pool = NULL;
++ }
+
- vout_display_DeleteWindow(vd, NULL);
--
++ isp->input = NULL;
++ isp->output = NULL;
+
-out:
- if (ret != VLC_SUCCESS)
- Close(object);
--
- return ret;
++ mmal_component_release(isp->component);
++ isp->component = NULL;
+
+- return ret;
++ return;
}
-static void Close(vlc_object_t *object)
--{
++// Restuff into output rather than return to pool is we can
++static MMAL_BOOL_T isp_out_pool_cb(MMAL_POOL_T *pool, MMAL_BUFFER_HEADER_T *buffer, void *userdata)
+ {
- vout_display_t *vd = (vout_display_t *)object;
- vout_display_sys_t *sys = vd->sys;
- char response[20]; /* answer is hvs_update_fields=%1d */
- unsigned i;
--
++ struct vout_isp_conf_s * const isp = userdata;
++ VLC_UNUSED(pool);
++ if (isp->output->is_enabled) {
++ mmal_buffer_header_reset(buffer);
++ if (mmal_port_send_buffer(isp->output, buffer) == MMAL_SUCCESS)
++ return MMAL_FALSE;
++ }
++ return MMAL_TRUE;
++}
+
- vc_tv_unregister_callback_full(tvservice_cb, vd);
--
++static MMAL_STATUS_T isp_setup(vout_display_t * const vd, vout_display_sys_t * const vd_sys)
++{
++ struct vout_isp_conf_s * const isp = &vd_sys->isp;
++ MMAL_STATUS_T err;
+
- if (sys->dmx_handle)
- close_dmx(vd);
--
++ if ((err = mmal_component_create(MMAL_COMPONENT_ISP_RESIZER, &isp->component)) != MMAL_SUCCESS) {
++ msg_Err(vd, "Cannot create ISP component");
++ return err;
++ }
++ isp->input = isp->component->input[0];
++ isp->output = isp->component->output[0];
+
- if (sys->component && sys->component->control->is_enabled)
- mmal_port_disable(sys->component->control);
--
++ isp->component->control->userdata = (void *)vd;
++ if ((err = mmal_port_enable(isp->component->control, isp_control_port_cb)) != MMAL_SUCCESS) {
++ msg_Err(vd, "Failed to enable ISP control port");
++ goto fail;
++ }
+
- if (sys->input && sys->input->is_enabled)
- mmal_port_disable(sys->input);
--
++ isp->input->userdata = (void *)vd;
++ display_set_format(vd, isp->input->format, false);
+
- if (sys->component && sys->component->is_enabled)
- mmal_component_disable(sys->component);
--
++ if ((err = port_parameter_set_bool(isp->input, MMAL_PARAMETER_ZERO_COPY, true)) != MMAL_SUCCESS)
++ goto fail;
+
- if (sys->pool)
- mmal_port_pool_destroy(sys->input, sys->pool);
--
++ if ((err = mmal_port_format_commit(isp->input)) != MMAL_SUCCESS) {
++ msg_Err(vd, "Failed to set ISP input format");
++ goto fail;
++ }
+
- if (sys->component)
- mmal_component_release(sys->component);
--
++ isp->input->buffer_size = isp->input->buffer_size_recommended;
++ isp->input->buffer_num = 30;
+
- if (sys->picture_pool)
- picture_pool_Release(sys->picture_pool);
- else
@@ -5334,35 +8684,194 @@
- mmal_buffer_header_release(sys->pictures[i]->p_sys->buffer);
- picture_Release(sys->pictures[i]);
- }
--
++ if ((isp->in_pool = mmal_pool_create(isp->input->buffer_num, 0)) == NULL)
++ {
++ msg_Err(vd, "Failed to create input pool");
++ goto fail;
++ }
+
- vlc_mutex_destroy(&sys->buffer_mutex);
- vlc_cond_destroy(&sys->buffer_cond);
- vlc_mutex_destroy(&sys->manage_mutex);
--
++ if ((isp->out_q = mmal_queue_create()) == NULL)
++ {
++ err = MMAL_ENOMEM;
++ goto fail;
++ }
+
- if (sys->native_interlaced) {
- if (vc_gencmd(response, sizeof(response), "hvs_update_fields 0") < 0 ||
- response[18] != '0')
- msg_Warn(vd, "Could not reset hvs field mode");
-- }
--
++ display_set_format(vd, isp->output->format, true);
++
++ if ((err = port_parameter_set_bool(isp->output, MMAL_PARAMETER_ZERO_COPY, true)) != MMAL_SUCCESS)
++ goto fail;
++
++ if ((err = mmal_port_format_commit(isp->output)) != MMAL_SUCCESS) {
++ msg_Err(vd, "Failed to set ISP input format");
++ goto fail;
+ }
+
- free(sys->pictures);
- free(sys);
--
++ isp->output->buffer_size = isp->output->buffer_size_recommended;
++ isp->output->buffer_num = 2;
++ isp->output->userdata = (void *)vd;
+
- bcm_host_deinit();
--}
--
++ if ((isp->out_pool = mmal_port_pool_create(isp->output, isp->output->buffer_num, isp->output->buffer_size)) == NULL)
++ {
++ msg_Err(vd, "Failed to make ISP port pool");
++ goto fail;
++ }
++
++ mmal_pool_callback_set(isp->out_pool, isp_out_pool_cb, isp);
++
++ if ((err = isp_prepare(vd, isp)) != MMAL_SUCCESS)
++ goto fail;
++
++ return MMAL_SUCCESS;
++
++fail:
++ isp_close(vd, vd_sys);
++ return err;
+ }
+
-static inline uint32_t align(uint32_t x, uint32_t y) {
- uint32_t mod = x % y;
- if (mod == 0)
- return x;
-- else
++static MMAL_STATUS_T isp_check(vout_display_t * const vd, vout_display_sys_t * const vd_sys)
++{
++ struct vout_isp_conf_s *const isp = &vd_sys->isp;
++ const bool has_isp = (isp->component != NULL);
++ const bool wants_isp = want_isp(vd);
++
++ if (has_isp == wants_isp)
++ {
++ // All OK - do nothing
++ }
++ else if (has_isp)
++ {
++ // ISP active but we don't want it
++ isp_flush(isp);
++
++ // Check we have everything back and then kill it
++ if (mmal_queue_length(isp->out_pool->queue) == isp->output->buffer_num)
++ isp_close(vd, vd_sys);
++ }
+ else
- return x + y - mod;
--}
--
++ {
++ // ISP closed but we want it
++ return isp_setup(vd, vd_sys);
++ }
++
++ return MMAL_SUCCESS;
++}
++
++/* TV service */
++static void tvservice_cb(void *callback_data, uint32_t reason, uint32_t param1,
++ 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);
++
++// Mmal
++static void maintain_phase_sync(vout_display_t *vd);
++
++
++
++static void vd_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
++{
++#if TRACE_ALL
++ vout_display_t * const vd = (vout_display_t *)port->userdata;
++ pic_ctx_mmal_t * ctx = buf->user_data;
++ msg_Dbg(vd, "<<< %s: cmd=%d, ctx=%p, buf=%p, flags=%#x, pts=%lld", __func__, buf->cmd, ctx, buf,
++ buf->flags, (long long)buf->pts);
++#else
++ VLC_UNUSED(port);
++#endif
++
++ mmal_buffer_header_release(buf);
++
++#if TRACE_ALL
++ msg_Dbg(vd, ">>> %s", __func__);
++#endif
++}
++
++static int query_resolution(vout_display_t *vd, unsigned *width, unsigned *height)
++{
++ TV_DISPLAY_STATE_T display_state;
++ int ret = 0;
++
++ if (vc_tv_get_display_state(&display_state) == 0) {
++ msg_Dbg(vd, "State=%#x", display_state.state);
++ if (display_state.state & 0xFF) {
++ msg_Dbg(vd, "HDMI: %dx%d", display_state.display.hdmi.width, display_state.display.hdmi.height);
++ *width = display_state.display.hdmi.width;
++ *height = display_state.display.hdmi.height;
++ } else if (display_state.state & 0xFF00) {
++ msg_Dbg(vd, "SDTV: %dx%d", display_state.display.sdtv.width, display_state.display.sdtv.height);
++ *width = display_state.display.sdtv.width;
++ *height = display_state.display.sdtv.height;
++ } else {
++ msg_Warn(vd, "Invalid display state %"PRIx32, display_state.state);
++ ret = -1;
++ }
++ } else {
++ msg_Warn(vd, "Failed to query display resolution");
++ ret = -1;
++ }
++
++ return ret;
+ }
+
static int configure_display(vout_display_t *vd, const vout_display_cfg_t *cfg,
const video_format_t *fmt)
{
-@@ -426,8 +207,9 @@
+- vout_display_sys_t *sys = vd->sys;
++ vout_display_sys_t * const sys = vd->sys;
+ vout_display_place_t place;
+ MMAL_DISPLAYREGION_T display_region;
+ MMAL_STATUS_T status;
+
+ if (!cfg && !fmt)
++ {
++ msg_Err(vd, "%s: Missing cfg & fmt", __func__);
+ return -EINVAL;
++ }
++
++ isp_check(vd, sys);
+
+ if (fmt) {
+ sys->input->format->es->video.par.num = fmt->i_sar_num;
+@@ -412,22 +527,29 @@
+ if (!cfg)
+ cfg = vd->cfg;
+
+- vout_display_PlacePicture(&place, fmt, cfg, false);
++ {
++ // Ignore what VLC thinks might be going on with display size
++ vout_display_cfg_t tcfg = *cfg;
++ tcfg.display.width = sys->display_width;
++ tcfg.display.height = sys->display_height;
++ tcfg.is_display_filled = true;
++ vout_display_PlacePicture(&place, fmt, &tcfg, false);
++
++ msg_Dbg(vd, "%dx%d -> %dx%d @ %d,%d", tcfg.display.width, tcfg.display.height, place.width, place.height, place.x, place.y);
++ }
+
+ display_region.hdr.id = MMAL_PARAMETER_DISPLAYREGION;
+ display_region.hdr.size = sizeof(MMAL_DISPLAYREGION_T);
+ display_region.fullscreen = MMAL_FALSE;
+- display_region.src_rect.x = fmt->i_x_offset;
+- display_region.src_rect.y = fmt->i_y_offset;
+- display_region.src_rect.width = fmt->i_visible_width;
+- display_region.src_rect.height = fmt->i_visible_height;
++ display_src_rect(vd, &display_region.src_rect);
+ display_region.dest_rect.x = place.x;
+ display_region.dest_rect.y = place.y;
display_region.dest_rect.width = place.width;
display_region.dest_rect.height = place.height;
display_region.layer = sys->layer;
@@ -5373,7 +8882,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 +217,6 @@
+@@ -435,7 +557,6 @@
return -EINVAL;
}
@@ -5381,7 +8890,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,171 +227,103 @@
+@@ -446,191 +567,130 @@
return 0;
}
@@ -5486,31 +8995,48 @@
+ sys->i_frame_rate = p_pic->format.i_frame_rate;
+ sys->i_frame_rate_base = p_pic->format.i_frame_rate_base;
+ configure_display(vd, NULL, &p_pic->format);
++ }
++
++ if (!sys->input->is_enabled &&
++ (err = mmal_port_enable(sys->input, vd_input_port_cb)) != MMAL_SUCCESS)
++ {
++ msg_Err(vd, "Input port enable failed");
++ goto fail;
++ }
++ // 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 TRACE_ALL
++ msg_Dbg(vd, "--- %s: ISP 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");
++ goto fail;
++ }
}
-
+-
- memset(&picture_res, 0, sizeof(picture_resource_t));
- sys->pictures = calloc(sys->num_buffers, sizeof(picture_t *));
- for (i = 0; i < sys->num_buffers; ++i) {
- picture_res.p_sys = calloc(1, sizeof(picture_sys_t));
- picture_res.p_sys->owner = (vlc_object_t *)vd;
- picture_res.p_sys->buffer = mmal_queue_get(sys->pool->queue);
-
+-
- sys->pictures[i] = picture_NewFromResource(&fmt, &picture_res);
- if (!sys->pictures[i]) {
- msg_Err(vd, "Failed to create picture");
- free(picture_res.p_sys);
- goto out;
-+ if (!sys->input->is_enabled &&
-+ (err = mmal_port_enable(sys->input, vd_input_port_cb)) != MMAL_SUCCESS)
-+ {
-+ msg_Err(vd, "Input port enable failed");
-+ goto fail;
-+ }
-+
-+ // Stuff into input
-+ // We assume the BH is already set up with values reflecting pic date etc.
++ else
+ {
+ 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");
@@ -5622,7 +9148,31 @@
}
static int vd_control(vout_display_t *vd, int query, va_list args)
-@@ -640,11 +353,39 @@
+ {
+- vout_display_sys_t *sys = vd->sys;
+- vout_display_cfg_t cfg;
+- const vout_display_cfg_t *tmp_cfg;
++ vout_display_sys_t * const sys = vd->sys;
+ int ret = VLC_EGENERIC;
++ VLC_UNUSED(args);
+
+ switch (query) {
+ case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
+- tmp_cfg = va_arg(args, const vout_display_cfg_t *);
+- if (tmp_cfg->display.width == sys->display_width &&
+- tmp_cfg->display.height == sys->display_height) {
+- cfg = *vd->cfg;
+- cfg.display.width = sys->display_width;
+- cfg.display.height = sys->display_height;
+- 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 @@
break;
case VOUT_DISPLAY_RESET_PICTURES:
@@ -5635,8 +9185,9 @@
+
case VOUT_DISPLAY_CHANGE_ZOOM:
msg_Warn(vd, "Unsupported control query %d", query);
- break;
-
++ ret = VLC_SUCCESS;
++ break;
++
+ case VOUT_DISPLAY_CHANGE_MMAL_HIDE:
+ {
+ MMAL_STATUS_T err;
@@ -5651,19 +9202,16 @@
+ (err = mmal_port_disable(sys->input)) != MMAL_SUCCESS)
+ {
+ msg_Err(vd, "Unable to disable port: err=%d", err);
-+ ret = VLC_EGENERIC;
+ break;
+ }
+ sys->force_config = true;
-+
+ ret = VLC_SUCCESS;
-+ break;
+ break;
+ }
-+
+
default:
msg_Warn(vd, "Unknown control query %d", query);
- break;
-@@ -661,13 +402,11 @@
+@@ -661,13 +748,11 @@
vlc_mutex_lock(&sys->manage_mutex);
if (sys->need_configure_display) {
@@ -5679,25 +9227,12 @@
}
sys->need_configure_display = false;
-@@ -676,56 +415,45 @@
+@@ -676,56 +761,76 @@
vlc_mutex_unlock(&sys->manage_mutex);
}
-static void 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;
--
-- if (buffer->cmd == MMAL_EVENT_ERROR) {
-- status = *(uint32_t *)buffer->data;
-- msg_Err(vd, "MMAL error %"PRIx32" \"%s\"", status, mmal_status_to_string(status));
-- }
--
-- mmal_buffer_header_release(buffer);
--}
--
--static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
-+static void vd_prepare(vout_display_t *vd, picture_t *picture,
++static void vd_prepare(vout_display_t *vd, picture_t *p_pic,
+#if VLC_VER_3
+ subpicture_t *subpicture
+#else
@@ -5706,11 +9241,51 @@
+ )
{
- vout_display_t *vd = (vout_display_t *)port->userdata;
-+ VLC_UNUSED(picture);
+- 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);
++
++ 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;
++ MMAL_BUFFER_HEADER_T * buf;
++
++ // 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;
++
++ buf = pic_mmal_buffer(p_pic);
++ if ((err = port_send_replicated(isp->input, isp->in_pool,
++ buf, buf->pts)) != MMAL_SUCCESS)
++ {
++ msg_Err(vd, "Send buffer to input failed");
++ return;
++ }
++
++ isp->pending = true;
++ }
++
+#if 0
+ VLC_UNUSED(date);
vout_display_sys_t *sys = vd->sys;
@@ -5765,7 +9340,7 @@
}
static void tvservice_cb(void *callback_data, uint32_t reason, uint32_t param1, uint32_t param2)
-@@ -828,148 +556,12 @@
+@@ -828,148 +933,12 @@
}
}
@@ -5915,7 +9490,7 @@
((double)vd->sys->i_frame_rate /
vd->sys->i_frame_rate_base);
vout_display_sys_t *sys = vd->sys;
-@@ -1012,32 +604,258 @@
+@@ -1012,32 +981,260 @@
}
}
@@ -5990,6 +9565,8 @@
+ if (sys->component)
+ mmal_component_release(sys->component);
+
++ isp_close(vd, sys);
++
+ vlc_mutex_destroy(&sys->manage_mutex);
+
+ if (sys->native_interlaced) {
@@ -6015,11 +9592,12 @@
+ MMAL_DISPLAYREGION_T display_region;
+ MMAL_STATUS_T status;
+ int ret = VLC_EGENERIC;
++ const MMAL_FOURCC_T enc_in = vout_vlc_to_mmal_pic_fourcc(vd->fmt.i_chroma);
+
+#if TRACE_ALL
+ msg_Dbg(vd, "<<< %s", __func__);
+#endif
-+ if (vd->fmt.i_chroma != VLC_CODEC_MMAL_OPAQUE)
++ if (enc_in == 0)
+ {
+#if TRACE_ALL
+ msg_Dbg(vd, ">>> %s: Format not MMAL", __func__);
@@ -6032,6 +9610,8 @@
+ return VLC_ENOMEM;
+ vd->sys = sys;
+
++ bcm_host_init();
++
+ sys->layer = var_InheritInteger(vd, MMAL_LAYER_NAME);
+
+ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &sys->component);
@@ -6052,18 +9632,12 @@
+ sys->input = sys->component->input[0];
+ sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)vd;
+
-+ sys->input->format->encoding = MMAL_ENCODING_OPAQUE;
++ sys->input->format->encoding = enc_in;
++ sys->input->format->encoding_variant = 0;
+ sys->i_planes = 1;
+ sys->buffer_size = sys->input->buffer_size_recommended;
+
-+ sys->input->format->es->video.width = vd->fmt.i_width;
-+ sys->input->format->es->video.height = vd->fmt.i_height;
-+ sys->input->format->es->video.crop.x = 0;
-+ sys->input->format->es->video.crop.y = 0;
-+ sys->input->format->es->video.crop.width = vd->fmt.i_width;
-+ sys->input->format->es->video.crop.height = vd->fmt.i_height;
-+ sys->input->format->es->video.par.num = vd->source.i_sar_num;
-+ sys->input->format->es->video.par.den = vd->source.i_sar_den;
++ display_set_format(vd, sys->input->format, want_isp(vd));
+
+ status = port_parameter_set_bool(sys->input, MMAL_PARAMETER_ZERO_COPY, true);
+ if (status != MMAL_SUCCESS) {
@@ -6085,10 +9659,7 @@
+ display_region.hdr.id = MMAL_PARAMETER_DISPLAYREGION;
+ display_region.hdr.size = sizeof(MMAL_DISPLAYREGION_T);
+ display_region.fullscreen = MMAL_FALSE;
-+ display_region.src_rect.x = vd->fmt.i_x_offset;
-+ display_region.src_rect.y = vd->fmt.i_y_offset;
-+ display_region.src_rect.width = vd->fmt.i_visible_width;
-+ display_region.src_rect.height = vd->fmt.i_visible_height;
++ display_src_rect(vd, &display_region.src_rect);
+ display_region.dest_rect.x = place.x;
+ display_region.dest_rect.y = place.y;
+ display_region.dest_rect.width = place.width;
@@ -6153,6 +9724,14 @@
+
+ vlc_mutex_init(&sys->manage_mutex);
+
++ vd->info = (vout_display_info_t){
++ .is_slow = false,
++ .has_double_click = false,
++ .needs_hide_mouse = false,
++ .has_pictures_invalid = true,
++ .subpicture_chromas = NULL
++ };
++
+ vd->pool = vd_pool;
+ vd->prepare = vd_prepare;
+ vd->display = vd_display;
@@ -6160,10 +9739,8 @@
+
+ vc_tv_register_callback(tvservice_cb, vd);
+
-+ if (query_resolution(vd, &sys->display_width, &sys->display_height) >= 0) {
-+// vout_window_ReportSize(vd->cfg->window,
-+// sys->display_width, sys->display_height);
-+ } else {
++ if (query_resolution(vd, &sys->display_width, &sys->display_height) < 0)
++ {
+ sys->display_width = vd->cfg->display.width;
+ sys->display_height = vd->cfg->display.height;
+ }
@@ -6202,7 +9779,7 @@
+
--- /dev/null
+++ b/modules/hw/mmal/xsplitter.c
-@@ -0,0 +1,365 @@
+@@ -0,0 +1,403 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
@@ -6233,6 +9810,19 @@
+ uint32_t changed;
+} 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) {
@@ -6311,10 +9901,12 @@
+
+ if ((x_vout->module = module_need(x_vout, cap, module_name, true)) == NULL)
+ {
-+ msg_Err(vd, "Failed to find X11 module");
++ msg_Err(vd, "Failed to open Xsplitter:%s module", module_name);
+ goto fail;
+ }
+
++ msg_Dbg(vd, "R/G/B: %08x/%08x/%08x", x_vout->fmt.i_rmask, x_vout->fmt.i_gmask, x_vout->fmt.i_bmask);
++
+ return x_vout;
+
+fail:
@@ -6337,9 +9929,18 @@
+ mmal_x11_sys_t * const sys = (mmal_x11_sys_t *)vd->sys;
+ vout_display_t * const x_vd = sys->cur_vout;
+#if TRACE_ALL
-+ msg_Dbg(vd, "<<< %s (count=%d) %dx%d", __func__, count, x_vd->fmt.i_width, x_vd->fmt.i_height);
++ char buf0[5];
++ msg_Dbg(vd, "<<< %s (count=%d) %s:%dx%d->%s:%dx%d", __func__, count,
++ str_fourcc(buf0, vd->fmt.i_chroma),
++ vd->fmt.i_width, vd->fmt.i_height,
++ str_fourcc(buf0, x_vd->fmt.i_chroma),
++ x_vd->fmt.i_width, x_vd->fmt.i_height);
++#endif
++ picture_pool_t * pool = x_vd->pool(x_vd, count);
++#if TRACE_ALL
++ msg_Dbg(vd, ">>> %s: %p", __func__, pool);
+#endif
-+ return x_vd->pool(x_vd, count);
++ return pool;
+}
+
+/* Prepare a picture and an optional subpicture for display (optional).
@@ -6377,10 +9978,11 @@
+{
+ mmal_x11_sys_t * const sys = (mmal_x11_sys_t *)vd->sys;
+ vout_display_t * const x_vd = sys->cur_vout;
-+ const bool is_mmal_pic = (pic->format.i_chroma == VLC_CODEC_MMAL_OPAQUE);
++ const bool is_mmal_pic = hw_mmal_pic_is_mmal(pic);
+
+#if TRACE_ALL
-+ msg_Dbg(vd, "<<< %s: fmt: %dx%d/%dx%d, pic:%dx%d", __func__, vd->fmt.i_width, vd->fmt.i_height, x_vd->fmt.i_width, x_vd->fmt.i_height, pic->format.i_width, pic->format.i_height);
++ msg_Dbg(vd, "<<< %s: fmt: %dx%d/%dx%d, pic:%dx%d, pts=%lld, mmal=%d/%d", __func__, vd->fmt.i_width, vd->fmt.i_height, x_vd->fmt.i_width, x_vd->fmt.i_height, pic->format.i_width, pic->format.i_height, (long long)pic->date,
++ is_mmal_pic, sys->use_mmal);
+#endif
+
+ if (sys->use_mmal != is_mmal_pic) {
@@ -6407,6 +10009,11 @@
+ return result;
+}
+
++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");
++}
++
+/* Control on the module (mandatory) */
+static int mmal_x11_control(vout_display_t * vd, int ctl, va_list va)
+{
@@ -6424,10 +10031,12 @@
+ case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
+ {
+ const vout_display_cfg_t * cfg = va_arg(va, const vout_display_cfg_t *);
-+ const bool want_mmal = sys->mmal_vout != NULL && var_InheritBool(vd, "fullscreen");
++ const bool want_mmal = want_mmal_vout(vd, sys);
+ vout_display_t *new_vd = want_mmal ? sys->mmal_vout : sys->x_vout;
+
-+ msg_Dbg(vd, "Change size: %d, %d", cfg->display.width, cfg->display.height);
++ 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 (sys->use_mmal) {
@@ -6466,7 +10075,10 @@
+
+ case VOUT_DISPLAY_RESET_PICTURES:
+ msg_Dbg(vd, "Reset pictures");
-+ rv = x_vd->control(x_vd, ctl, va);
++// 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);
@@ -6502,19 +10114,6 @@
+}
+#endif
+
-+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 int OpenMmalX11(vlc_object_t *object)
+{
+ vout_display_t * const vd = (vout_display_t *)object;
@@ -6526,6 +10125,14 @@
+ }
+ vd->sys = (vout_display_sys_t *)sys;
+
++ vd->info = (vout_display_info_t){
++ .is_slow = false,
++ .has_double_click = false,
++ .needs_hide_mouse = false,
++ .has_pictures_invalid = true,
++ .subpicture_chromas = NULL
++ };
++
+ if ((sys->x_vout = load_display_module(vd, "vout display", "xcb_x11")) == NULL)
+ goto fail;
+
@@ -6536,10 +10143,6 @@
+ 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));
+ }
+
-+ sys->cur_vout = sys->x_vout;
-+ vd->info = sys->cur_vout->info;
-+ vd->fmt = sys->cur_vout->fmt;
-+
+ vd->pool = mmal_x11_pool;
+ vd->prepare = mmal_x11_prepare;
+ vd->display = mmal_x11_display;
@@ -6548,6 +10151,18 @@
+ vd->manage = mmal_x11_manage;
+#endif
+
++ if (want_mmal_vout(vd, sys)) {
++ sys->cur_vout = sys->mmal_vout;
++ sys->use_mmal = true;
++ }
++ else {
++ sys->cur_vout = sys->x_vout;
++ sys->use_mmal = false;
++ }
++
++ vd->info = sys->cur_vout->info;
++ vd->fmt = sys->cur_vout->fmt;
++
+ return VLC_SUCCESS;
+
+fail:
@@ -6568,3 +10183,14 @@
+ set_callbacks(OpenMmalX11, CloseMmalX11)
+vlc_module_end()
+
+--- a/src/misc/fourcc.c
++++ b/src/misc/fourcc.c
+@@ -756,6 +756,8 @@
+ 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 },
+ FAKE_FMT() },
+ { { VLC_CODEC_D3D11_OPAQUE_10B, VLC_CODEC_D3D9_OPAQUE_10B },
5 years, 7 months
[wireguard-kmod/el7] Fix date for EPEL old rpm
by Robert-André Mauchin
commit fab7a7ce0c8f08fb552ce366c773e513982c6fa4
Author: Robert-André Mauchin <zebob.m(a)gmail.com>
Date: Sat Apr 6 14:26:26 2019 +0200
Fix date for EPEL old rpm
wireguard-kmod.spec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
---
diff --git a/wireguard-kmod.spec b/wireguard-kmod.spec
index 877ef5a..c5ae190 100644
--- a/wireguard-kmod.spec
+++ b/wireguard-kmod.spec
@@ -58,7 +58,7 @@ done
%changelog
-* Sat Apr 06 13:32:03 CET 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190406-1
+* Sat Apr 06 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190406-1
- Release 0.0.20190406
* Thu Feb 28 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190227-1
5 years, 7 months
[wireguard/el7] Fix date for EPEL old rpm
by Robert-André Mauchin
commit 3f996d65a1e404ab6807b7da60ca0cc88cb3248d
Author: Robert-André Mauchin <zebob.m(a)gmail.com>
Date: Sat Apr 6 14:25:29 2019 +0200
Fix date for EPEL old rpm
wireguard.spec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
---
diff --git a/wireguard.spec b/wireguard.spec
index 836e69a..0c2408a 100644
--- a/wireguard.spec
+++ b/wireguard.spec
@@ -74,7 +74,7 @@ sed -i '1s@/usr/bin/env bash@/bin/bash@' contrib/examples/ncat-client-server/cli
%changelog
-* Sat Apr 06 13:29:56 CET 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190406-1
+* Sat Apr 06 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190406-1
- Release 0.0.20190406
* Thu Mar 07 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190227-2
5 years, 7 months
[ffmpeg/f29] Bump to latest cuda
by Nicolas Chauvet
commit bd2e9e157fc170f6fbc1596db4e5f5081b78a126
Author: Nicolas Chauvet <kwizart(a)gmail.com>
Date: Sat Apr 6 14:21:32 2019 +0200
Bump to latest cuda
ffmpeg.spec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
---
diff --git a/ffmpeg.spec b/ffmpeg.spec
index d09e407..cf678ea 100644
--- a/ffmpeg.spec
+++ b/ffmpeg.spec
@@ -55,7 +55,7 @@
# extras flags
%if 0%{!?_cuda_version:1}
-%global _cuda_version 10.0
+%global _cuda_version 10.1
%endif
%global _cuda_version_rpm %(echo %{_cuda_version} | sed -e 's/\\./-/')
%global _cuda_bindir %{_cuda_prefix}/bin
5 years, 7 months
[ffmpeg/f30] Bump to latest cuda
by Nicolas Chauvet
commit 13b691b61080a610d21c34dc2f75db4e0cd786d8
Author: Nicolas Chauvet <kwizart(a)gmail.com>
Date: Sat Apr 6 14:21:32 2019 +0200
Bump to latest cuda
ffmpeg.spec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
---
diff --git a/ffmpeg.spec b/ffmpeg.spec
index 1efc017..eb56ca8 100644
--- a/ffmpeg.spec
+++ b/ffmpeg.spec
@@ -48,7 +48,7 @@
# extras flags
%if 0%{!?_cuda_version:1}
-%global _cuda_version 10.0
+%global _cuda_version 10.1
%endif
%global _cuda_version_rpm %(echo %{_cuda_version} | sed -e 's/\\./-/')
%global _cuda_bindir %{_cuda_prefix}/bin
5 years, 7 months
[ffmpeg] Bump to latest cuda
by Nicolas Chauvet
commit 1670f1d570f7307a6cbfc5fa53d979b4957b5caf
Author: Nicolas Chauvet <kwizart(a)gmail.com>
Date: Sat Apr 6 14:21:32 2019 +0200
Bump to latest cuda
ffmpeg.spec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
---
diff --git a/ffmpeg.spec b/ffmpeg.spec
index 1efc017..eb56ca8 100644
--- a/ffmpeg.spec
+++ b/ffmpeg.spec
@@ -48,7 +48,7 @@
# extras flags
%if 0%{!?_cuda_version:1}
-%global _cuda_version 10.0
+%global _cuda_version 10.1
%endif
%global _cuda_version_rpm %(echo %{_cuda_version} | sed -e 's/\\./-/')
%global _cuda_bindir %{_cuda_prefix}/bin
5 years, 7 months
[wireguard-kmod/el7] Release 0.0.20190406
by Robert-André Mauchin
commit 9371beb6d36a8e602aca94cce35e4a9369776f68
Author: Robert-André Mauchin <zebob.m(a)gmail.com>
Date: Sat Apr 6 13:32:55 2019 +0200
Release 0.0.20190406
Signed-off-by: Robert-André Mauchin <zebob.m(a)gmail.com>
.gitignore | 1 +
sources | 2 +-
wireguard-kmod.spec | 15 +++++++++------
3 files changed, 11 insertions(+), 7 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index a9d4a70..c409cd6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@
/WireGuard-0.0.20181218.tar.xz
/WireGuard-0.0.20190123.tar.xz
/WireGuard-0.0.20190227.tar.xz
+/WireGuard-0.0.20190406.tar.xz
diff --git a/sources b/sources
index 9217180..76f26e0 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-148748a50ed153cbc2f21c086e5623f9 WireGuard-0.0.20190227.tar.xz
+c11254fe48695e61c145a7e82756ecba WireGuard-0.0.20190406.tar.xz
diff --git a/wireguard-kmod.spec b/wireguard-kmod.spec
index d1a7244..877ef5a 100644
--- a/wireguard-kmod.spec
+++ b/wireguard-kmod.spec
@@ -3,7 +3,7 @@
Name: wireguard-kmod
Summary: Kernel module (kmod) for Wireguard
-Version: 0.0.20190227
+Version: 0.0.20190406
Release: 1%{?dist}
License: GPLv2
@@ -18,11 +18,11 @@ BuildRequires: elfutils-libelf-devel
%{expand:%(kmodtool --target %{_target_cpu} --repo rpmfusion --kmodname %{name} %{?buildforkernels:--%{buildforkernels}} %{?kernels:--for-kernels "%{?kernels}"} 2>/dev/null) }
%description
-WireGuard is a novel VPN that runs inside the Linux Kernel and utilizes
-state-of-the-art cryptography. It aims to be faster, simpler, leaner,
-and more useful than IPSec, while avoiding the massive headache. It intends
-to be considerably more performant than OpenVPN. WireGuard is designed as a
-general purpose VPN for running on embedded interfaces and super computers
+WireGuard is a novel VPN that runs inside the Linux Kernel and utilizes
+state-of-the-art cryptography. It aims to be faster, simpler, leaner,
+and more useful than IPSec, while avoiding the massive headache. It intends
+to be considerably more performant than OpenVPN. WireGuard is designed as a
+general purpose VPN for running on embedded interfaces and super computers
alike, fit for many different circumstances. It runs over UDP.
This package contains the kmod module for WireGuard.
@@ -58,6 +58,9 @@ done
%changelog
+* Sat Apr 06 13:32:03 CET 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190406-1
+- Release 0.0.20190406
+
* Thu Feb 28 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190227-1
- Release 0.0.20190227
5 years, 7 months
[wireguard/el7] - Release 0.0.20190406
by Robert-André Mauchin
commit 47f6c9592effbd51835db15184078956e6ff21bb
Author: Robert-André Mauchin <zebob.m(a)gmail.com>
Date: Sat Apr 6 13:31:20 2019 +0200
- Release 0.0.20190406
Signed-off-by: Robert-André Mauchin <zebob.m(a)gmail.com>
.gitignore | 1 +
sources | 2 +-
wireguard.spec | 7 +++++--
3 files changed, 7 insertions(+), 3 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index a9d4a70..c409cd6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@
/WireGuard-0.0.20181218.tar.xz
/WireGuard-0.0.20190123.tar.xz
/WireGuard-0.0.20190227.tar.xz
+/WireGuard-0.0.20190406.tar.xz
diff --git a/sources b/sources
index 9217180..76f26e0 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-148748a50ed153cbc2f21c086e5623f9 WireGuard-0.0.20190227.tar.xz
+c11254fe48695e61c145a7e82756ecba WireGuard-0.0.20190406.tar.xz
diff --git a/wireguard.spec b/wireguard.spec
index a1998e6..836e69a 100644
--- a/wireguard.spec
+++ b/wireguard.spec
@@ -1,7 +1,7 @@
Name: wireguard
Summary: Fast, modern, secure VPN tunnel
-Version: 0.0.20190227
-Release: 2%{?dist}
+Version: 0.0.20190406
+Release: 1%{?dist}
License: GPLv2
URL: https://www.wireguard.com/
@@ -74,6 +74,9 @@ sed -i '1s@/usr/bin/env bash@/bin/bash@' contrib/examples/ncat-client-server/cli
%changelog
+* Sat Apr 06 13:29:56 CET 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190406-1
+- Release 0.0.20190406
+
* Thu Mar 07 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190227-2
- Unifying spec with Lubomir Rintel's one
- Rebuilt for akmods-ostree-post scriptlet
5 years, 7 months
[wireguard/el7] Unifying spec with Lubomir Rintel's one Rebuilt for akmods-ostree-post scriptlet
by Robert-André Mauchin
commit e26da43891e1acfb0c1e8a268ab646339f84f356
Author: Robert-André Mauchin <zebob.m(a)gmail.com>
Date: Thu Apr 4 19:35:32 2019 +0200
Unifying spec with Lubomir Rintel's one
Rebuilt for akmods-ostree-post scriptlet
Signed-off-by: Robert-André Mauchin <zebob.m(a)gmail.com>
WireGuard-0.0.20190406.tar.xz | Bin 0 -> 324112 bytes
wireguard.spec | 42 +++++++++++++++++++-----------------------
2 files changed, 19 insertions(+), 23 deletions(-)
---
diff --git a/WireGuard-0.0.20190406.tar.xz b/WireGuard-0.0.20190406.tar.xz
new file mode 100644
index 0000000..d262ecc
Binary files /dev/null and b/WireGuard-0.0.20190406.tar.xz differ
diff --git a/wireguard.spec b/wireguard.spec
index ff393f2..a1998e6 100644
--- a/wireguard.spec
+++ b/wireguard.spec
@@ -1,7 +1,7 @@
Name: wireguard
Summary: Fast, modern, secure VPN tunnel
Version: 0.0.20190227
-Release: 1%{?dist}
+Release: 2%{?dist}
License: GPLv2
URL: https://www.wireguard.com/
@@ -17,41 +17,33 @@ Provides: %{name}-kmod-common = %{version}
Requires: %{name}-kmod >= %{version}
%description
-WireGuard is a novel VPN that runs inside the Linux Kernel and utilizes
-state-of-the-art cryptography. It aims to be faster, simpler, leaner,
-and more useful than IPSec, while avoiding the massive headache. It intends
-to be considerably more performant than OpenVPN. WireGuard is designed as a
-general purpose VPN for running on embedded interfaces and super computers
+WireGuard is a novel VPN that runs inside the Linux Kernel and utilizes
+state-of-the-art cryptography. It aims to be faster, simpler, leaner,
+and more useful than IPSec, while avoiding the massive headache. It intends
+to be considerably more performant than OpenVPN. WireGuard is designed as a
+general purpose VPN for running on embedded interfaces and super computers
alike, fit for many different circumstances. It runs over UDP.
%prep
-%autosetup -n WireGuard-%{version} different circumstances. It runs over UDP.
+%autosetup -n WireGuard-%{version}
# Remove .gitignore files in examples
find contrib/ -type f -name ".gitignore" -exec rm "{}" \;
# Do not use /usr/bin/env
sed -i '1s@/usr/bin/env bash@/bin/bash@' contrib/examples/ncat-client-server/client-quick.sh
-# Use standard perms for /etc/wireguard
-sed -i 's|install -v -m 0700|install -v -m 0755|' src/tools/Makefile
%build
%set_build_flags
-
-pushd contrib/examples/dns-hatchet
-sh apply.sh
-popd
-
-pushd src/tools
-%make_build V=1
-popd
+%make_build V=1 -C src/tools
%install
-pushd src/tools
-%make_install
-popd
+%make_install -C src/tools \
+ WITH_BASHCOMPLETION=yes \
+ WITH_WGQUICK=yes \
+ WITH_SYSTEMDUNITS=yes
%post
@@ -71,17 +63,21 @@ popd
%license COPYING
%{_bindir}/wg
%{_bindir}/wg-quick
+%{_unitdir}/wg-quick@.service
%{_sysconfdir}/wireguard
+%{_mandir}/man8/wg.8*
+%{_mandir}/man8/wg-quick.8*
%dir %{_datadir}/bash-completion
%dir %{_datadir}/bash-completion/completions
%{_datadir}/bash-completion/completions/wg
%{_datadir}/bash-completion/completions/wg-quick
-%{_unitdir}/wg-quick@.service
-%{_mandir}/man8/wg.8*
-%{_mandir}/man8/wg-quick.8*
%changelog
+* Thu Mar 07 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190227-2
+- Unifying spec with Lubomir Rintel's one
+- Rebuilt for akmods-ostree-post scriptlet
+
* Thu Feb 28 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190227-1
- Release 0.0.20190227
5 years, 7 months
[wireguard-kmod/f29] Release 0.0.20190406
by Robert-André Mauchin
commit bafebf0daf17c5e78af1fe81268b87faec11b224
Author: Robert-André Mauchin <zebob.m(a)gmail.com>
Date: Sat Apr 6 13:32:55 2019 +0200
Release 0.0.20190406
Signed-off-by: Robert-André Mauchin <zebob.m(a)gmail.com>
.gitignore | 1 +
sources | 2 +-
wireguard-kmod.spec | 7 +++++--
3 files changed, 7 insertions(+), 3 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index a9d4a70..c409cd6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@
/WireGuard-0.0.20181218.tar.xz
/WireGuard-0.0.20190123.tar.xz
/WireGuard-0.0.20190227.tar.xz
+/WireGuard-0.0.20190406.tar.xz
diff --git a/sources b/sources
index 9217180..76f26e0 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-148748a50ed153cbc2f21c086e5623f9 WireGuard-0.0.20190227.tar.xz
+c11254fe48695e61c145a7e82756ecba WireGuard-0.0.20190406.tar.xz
diff --git a/wireguard-kmod.spec b/wireguard-kmod.spec
index a5ff8c1..cccdf27 100644
--- a/wireguard-kmod.spec
+++ b/wireguard-kmod.spec
@@ -3,8 +3,8 @@
Name: wireguard-kmod
Summary: Kernel module (kmod) for Wireguard
-Version: 0.0.20190227
-Release: 2%{?dist}
+Version: 0.0.20190406
+Release: 1%{?dist}
License: GPLv2
URL: https://www.wireguard.com/
@@ -58,6 +58,9 @@ done
%changelog
+* Sat Apr 06 13:32:03 CET 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190406-1
+- Release 0.0.20190406
+
* Thu Apr 04 19:27:39 CET 2019 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.0.20190227-2
- Rebuilt for akmods-ostree-post scriptlet
5 years, 7 months