ffmpeg-devel
Threads by month
- ----- 2026 -----
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
August 2021
- 101 participants
- 452 discussions
[PATCH] avcodec/ffv1enc: Use version 3 by default (CRCs by default)
by Michael Niedermayer 12 Apr '25
by Michael Niedermayer 12 Apr '25
12 Apr '25
Version 3 is since 2013 (FFmpeg 2.1) non experimental so should be widely supported
Signed-off-by: Michael Niedermayer <michael(a)niedermayer.cc>
---
libavcodec/ffv1enc.c | 3 ++-
tests/fate/vcodec.mak | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index c521b7d445..ce66d0e4d6 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -542,7 +542,8 @@ static av_cold int encode_init(AVCodecContext *avctx)
return AVERROR(EINVAL);
}
s->version = avctx->level;
- }
+ } else if (s->version < 3)
+ s->version = 3;
if (s->ec < 0) {
s->ec = (s->version >= 3);
diff --git a/tests/fate/vcodec.mak b/tests/fate/vcodec.mak
index 452246689e..91b46034c8 100644
--- a/tests/fate/vcodec.mak
+++ b/tests/fate/vcodec.mak
@@ -168,7 +168,7 @@ FATE_VCODEC-$(call ENCDEC, FFV1, AVI) += ffv1 ffv1-v0 \
ffv1-v3-yuv420p ffv1-v3-yuv422p10 ffv1-v3-yuv444p16 \
ffv1-v3-bgr0 ffv1-v3-rgb48
fate-vsynth%-ffv1: ENCOPTS = -slices 4
-fate-vsynth%-ffv1-v0: CODEC = ffv1
+fate-vsynth%-ffv1-v0: ENCOPTS = -level 0
fate-vsynth%-ffv1-v3-yuv420p: ENCOPTS = -level 3 -pix_fmt yuv420p
fate-vsynth%-ffv1-v3-yuv422p10: ENCOPTS = -level 3 -pix_fmt yuv422p10 \
-sws_flags neighbor+bitexact
--
2.23.0
3
4
Signed-off-by: Paul B Mahol <onemda(a)gmail.com>
---
Please test it and reports benchmark results on non toyish GPUs.
---
configure | 1 +
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 1 +
libavfilter/vf_v360_vulkan.c | 668 +++++++++++++++++++++++++++++++++++
4 files changed, 671 insertions(+)
create mode 100644 libavfilter/vf_v360_vulkan.c
diff --git a/configure b/configure
index 7495f35faa..2a3ac563db 100755
--- a/configure
+++ b/configure
@@ -3622,6 +3622,7 @@ transpose_opencl_filter_deps="opencl"
transpose_vaapi_filter_deps="vaapi VAProcPipelineCaps_rotation_flags"
unsharp_opencl_filter_deps="opencl"
uspp_filter_deps="gpl avcodec"
+v360_vulkan_filter_deps="vulkan libglslang"
vaguedenoiser_filter_deps="gpl"
vidstabdetect_filter_deps="libvidstab"
vidstabtransform_filter_deps="libvidstab"
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 191826a622..6440794bcf 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -441,6 +441,7 @@ OBJS-$(CONFIG_UNSHARP_OPENCL_FILTER) += vf_unsharp_opencl.o opencl.o \
OBJS-$(CONFIG_UNTILE_FILTER) += vf_untile.o
OBJS-$(CONFIG_USPP_FILTER) += vf_uspp.o
OBJS-$(CONFIG_V360_FILTER) += vf_v360.o
+OBJS-$(CONFIG_V360_VULKAN_FILTER) += vf_v360_vulkan.o vulkan.o
OBJS-$(CONFIG_VAGUEDENOISER_FILTER) += vf_vaguedenoiser.o
OBJS-$(CONFIG_VECTORSCOPE_FILTER) += vf_vectorscope.o
OBJS-$(CONFIG_VFLIP_FILTER) += vf_vflip.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index de5884529c..65669c4422 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -420,6 +420,7 @@ extern AVFilter ff_vf_unsharp_opencl;
extern AVFilter ff_vf_untile;
extern AVFilter ff_vf_uspp;
extern AVFilter ff_vf_v360;
+extern AVFilter ff_vf_v360_vulkan;
extern AVFilter ff_vf_vaguedenoiser;
extern AVFilter ff_vf_vectorscope;
extern AVFilter ff_vf_vflip;
diff --git a/libavfilter/vf_v360_vulkan.c b/libavfilter/vf_v360_vulkan.c
new file mode 100644
index 0000000000..7db200f1c6
--- /dev/null
+++ b/libavfilter/vf_v360_vulkan.c
@@ -0,0 +1,668 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/random_seed.h"
+#include "libavutil/opt.h"
+#include "vulkan.h"
+#include "internal.h"
+
+enum RotationOrder {
+ YAW,
+ PITCH,
+ ROLL,
+ NB_RORDERS,
+};
+
+enum Projections {
+ EQUIRECTANGULAR,
+ CUBEMAP_3_2,
+ CUBEMAP_6_1,
+ EQUIANGULAR,
+ FLAT,
+ DUAL_FISHEYE,
+ BARREL,
+ CUBEMAP_1_6,
+ STEREOGRAPHIC,
+ MERCATOR,
+ BALL,
+ HAMMER,
+ SINUSOIDAL,
+ FISHEYE,
+ PANNINI,
+ CYLINDRICAL,
+ PERSPECTIVE,
+ TETRAHEDRON,
+ BARREL_SPLIT,
+ TSPYRAMID,
+ HEQUIRECTANGULAR,
+ NB_PROJECTIONS,
+};
+
+#define CGROUPS (int [3]){ 32, 32, 1 }
+
+typedef struct V360VulkanContext {
+ VulkanFilterContext vkctx;
+
+ int initialized;
+ FFVkExecContext *exec;
+ VulkanPipeline *pl;
+
+ /* Shader updators, must be in the main filter struct */
+ VkDescriptorImageInfo input_images[3];
+ VkDescriptorImageInfo output_images[3];
+
+ int planewidth[4], planeheight[4];
+ int inplanewidth[4], inplaneheight[4];
+ int in, out;
+ int width, height;
+ float h_fov, v_fov;
+ float ih_fov, iv_fov;
+ float yaw, pitch, roll;
+ char *rorder;
+ int rotation_order[3];
+
+ /* Push constants / options */
+ struct {
+ float flat_range[2];
+ float iflat_range[2];
+ float rot_mat[4][4];
+ } opts;
+} V360VulkanContext;
+
+static const char flat_to_xyz[] = {
+ C(0, void out_transform(out vec3 v, in ivec2 out_size, in ivec2 pos) )
+ C(0, { )
+ C(1, vec2 fpos = vec2(pos) + vec2(0.5f, 0.5f); )
+ C(1, vec2 p = ((fpos / vec2(out_size)) - 0.5f)*2.0f; )
+ C(1, v = vec3(p[0], p[1], 1.f) * vec3(flat_range, 1.f); )
+ C(1, v = normalize(v); )
+ C(0, } )
+};
+
+static const char xyz_to_flat[] = {
+ C(0, void in_transform(int idx, in vec3 v, in ivec2 pos, in ivec2 in_size) )
+ C(0, { )
+ C(1, const float r = tan(acos(v[2])); )
+ C(1, const float rr = abs(r) < 1e+6f ? r : length(in_size); )
+ C(1, const float h = length(vec2(v[0], v[1])); )
+ C(1, const float c = h <= 1e-6f ? 1.f : rr / h; )
+ C(1, vec2 p = vec2(v[0], v[1]) / iflat_range * c; )
+ C(1, p = IS_WITHIN(abs(p), vec2(1.f)) ? (p/2.0f)+0.5f:vec2(0.f); )
+ C(1, p = v[2] >= 0.f ? p : vec2(0.f); )
+ C(1, vec4 res = texture(input_img[idx], p); )
+ C(1, imageStore(output_img[idx], pos, res); )
+ C(0, } )
+};
+
+static const char equirect_to_xyz[] = {
+ C(0, void out_transform(out vec3 v, in ivec2 out_size, in ivec2 pos) )
+ C(0, { )
+ C(1, vec2 fpos = 2.f * vec2(pos) + 0.5f; )
+ C(1, vec2 p = fpos / vec2(out_size) - 1.f; )
+ C(1, p = vec2(p[0] * PI, p[1] * PI_2); )
+ C(1, v = vec3(cos(p[1]) * sin(p[0]), sin(p[1]), cos(p[1])*cos(p[0])); )
+ C(0, } )
+};
+
+static const char xyz_to_equirect[] = {
+ C(0, void in_transform(int idx, in vec3 v, in ivec2 pos, in ivec2 in_size) )
+ C(0, { )
+ C(1, vec2 p = vec2(atan(v[0], v[2]) / PI, asin(v[1]) / PI_2); )
+ C(1, vec4 res = texture(input_img[idx], (p/2.0f) + 0.5f); )
+ C(1, imageStore(output_img[idx], pos, res); )
+ C(0, } )
+};
+
+static const char stereographic_to_xyz[] = {
+ C(0, void out_transform(out vec3 v, in ivec2 out_size, in ivec2 pos) )
+ C(0, { )
+ C(1, vec2 fpos = vec2(pos) + vec2(0.5f, 0.5f); )
+ C(1, vec2 p = (fpos / vec2(out_size) - 0.5f) * 2.0f * flat_range; )
+ C(1, const float r = length(p); )
+ C(1, const float theta = atan(r) * 2.0f; )
+ C(1, v = vec3(p[0] / r*sin(theta), p[1] / r*sin(theta), cos(theta)); )
+ C(1, v = normalize(v); )
+ C(0, } )
+};
+
+static const char xyz_to_stereographic[] = {
+ C(0, void in_transform(int idx, in vec3 v, in ivec2 pos, in ivec2 in_size) )
+ C(0, { )
+ C(1, const float theta = acos(v[2]); )
+ C(1, const float r = tan(theta * 0.5f); )
+ C(1, const vec2 c = (r / length(vec2(v[0], v[1]))) / iflat_range; )
+ C(1, vec2 p = vec2(v[0], v[1]) * c; )
+ C(1, p = IS_WITHIN(abs(p), vec2(1.f)) ? (p/2.0f)+0.5f:vec2(0.f); )
+ C(1, vec4 res = texture(input_img[idx], p); )
+ C(1, imageStore(output_img[idx], pos, res); )
+ C(0, } )
+};
+
+static const char fisheye_to_xyz[] = {
+ C(0, void out_transform(out vec3 v, in ivec2 out_size, in ivec2 pos) )
+ C(0, { )
+ C(1, vec2 fpos = vec2(pos) + vec2(0.5f, 0.5f); )
+ C(1, vec2 p = (fpos / vec2(out_size) - 0.5f) * 2.0f * flat_range; )
+ C(1, const float r = length(p); )
+ C(1, const float phi = atan(p[1], p[0]); )
+ C(1, const float theta = (1.f - r) * PI_2; )
+ C(1, v = vec3(cos(theta)*cos(phi), cos(theta)*sin(phi), sin(theta)); )
+ C(1, v = normalize(v); )
+ C(0, } )
+};
+
+static const char xyz_to_fisheye[] = {
+ C(0, void in_transform(int idx, in vec3 v, in ivec2 pos, in ivec2 in_size) )
+ C(0, { )
+ C(1, const float h = length(vec2(v[0], v[1])); )
+ C(1, const float lh = h > 0.f ? h / 2.f : 1.f; )
+ C(1, const float phi = atan(h, v[2]) / PI; )
+ C(1, vec2 p = vec2(v[0], v[1]) * phi / lh / iflat_range; )
+ C(1, p = (length(p) <= 1.f) ? (p/2.0f)+0.5f:vec2(0.f); )
+ C(1, vec4 res = texture(input_img[idx], p); )
+ C(1, imageStore(output_img[idx], pos, res); )
+ C(0, } )
+};
+
+static const char dfisheye_to_xyz[] = {
+ C(0, void out_transform(out vec3 v, in ivec2 out_size, in ivec2 pos) )
+ C(0, { )
+ C(1, const float m = pos[0] >= out_size[0] / 2 ? 1.f : -1.f; )
+ C(1, vec2 npos = m == 1.f ? vec2(out_size[0] / 2, 0.f) : vec2(0.f); )
+ C(1, vec2 fpos = vec2(pos) - npos + vec2(0.5f, 0.5f); )
+ C(1, vec2 osize = vec2(out_size) * vec2(0.5f, 1.f); )
+ C(1, vec2 p = (fpos / osize - 0.5f) * 2.0f * flat_range; )
+ C(1, const float h = length(p); )
+ C(1, const float lh = h > 0.f ? h : 1.f; )
+ C(1, const float theta = m * PI_2 * (1.f - h); )
+ C(1, p = p / lh; )
+ C(1, v = vec3(cos(theta)*m*p[0], cos(theta)*p[1], sin(theta)); )
+ C(1, v = normalize(v); )
+ C(0, } )
+};
+
+static const char xyz_to_dfisheye[] = {
+ C(0, void in_transform(int idx, in vec3 v, in ivec2 pos, in ivec2 in_size) )
+ C(0, { )
+ C(1, const float h = length(vec2(v[0], v[1])); )
+ C(1, const float lh = h > 0.f ? h : 1.f; )
+ C(1, const float theta = acos(abs(v[2])) / PI; )
+ C(1, vec2 p = (vec2(v[0], v[1]) * theta)/lh/iflat_range + 0.5f; )
+ C(1, p = p * vec2(0.5f, 1.f); )
+ C(1, p = v[2] >= 0.f ? vec2(p[0]+0.5f, p[1]) : vec2(0.5f-p[0], p[1]); )
+ C(1, vec4 res = texture(input_img[idx], p); )
+ C(1, imageStore(output_img[idx], pos, res); )
+ C(0, } )
+};
+
+static void multiply_matrix(float c[4][4], const float a[4][4], const float b[4][4])
+{
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ float sum = 0.f;
+
+ for (int k = 0; k < 3; k++)
+ sum += a[i][k] * b[k][j];
+
+ c[i][j] = sum;
+ }
+ }
+}
+
+static inline void calculate_rotation_matrix(float yaw, float pitch, float roll,
+ float rot_mat[4][4],
+ const int rotation_order[3])
+{
+ const float yaw_rad = yaw * M_PI / 180.f;
+ const float pitch_rad = pitch * M_PI / 180.f;
+ const float roll_rad = roll * M_PI / 180.f;
+
+ const float sin_yaw = sinf(yaw_rad);
+ const float cos_yaw = cosf(yaw_rad);
+ const float sin_pitch = sinf(pitch_rad);
+ const float cos_pitch = cosf(pitch_rad);
+ const float sin_roll = sinf(roll_rad);
+ const float cos_roll = cosf(roll_rad);
+
+ float m[3][4][4];
+ float temp[4][4];
+
+ m[0][0][0] = cos_yaw; m[0][0][1] = 0; m[0][0][2] = sin_yaw;
+ m[0][1][0] = 0; m[0][1][1] = 1; m[0][1][2] = 0;
+ m[0][2][0] = -sin_yaw; m[0][2][1] = 0; m[0][2][2] = cos_yaw;
+
+ m[1][0][0] = 1; m[1][0][1] = 0; m[1][0][2] = 0;
+ m[1][1][0] = 0; m[1][1][1] = cos_pitch; m[1][1][2] = -sin_pitch;
+ m[1][2][0] = 0; m[1][2][1] = sin_pitch; m[1][2][2] = cos_pitch;
+
+ m[2][0][0] = cos_roll; m[2][0][1] = -sin_roll; m[2][0][2] = 0;
+ m[2][1][0] = sin_roll; m[2][1][1] = cos_roll; m[2][1][2] = 0;
+ m[2][2][0] = 0; m[2][2][1] = 0; m[2][2][2] = 1;
+
+ multiply_matrix(temp, m[rotation_order[0]], m[rotation_order[1]]);
+ multiply_matrix(rot_mat, temp, m[rotation_order[2]]);
+}
+
+static void set_dimensions(int *outw, int *outh, int w, int h, const AVPixFmtDescriptor *desc)
+{
+ outw[1] = outw[2] = FF_CEIL_RSHIFT(w, desc->log2_chroma_w);
+ outw[0] = outw[3] = w;
+ outh[1] = outh[2] = FF_CEIL_RSHIFT(h, desc->log2_chroma_h);
+ outh[0] = outh[3] = h;
+}
+
+static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
+{
+ AVFilterLink *outlink = ctx->outputs[0];
+ V360VulkanContext *s = ctx->priv;
+ int err;
+
+ /* Create a sampler */
+ VkSampler *sampler = ff_vk_init_sampler(ctx, 0, VK_FILTER_LINEAR);
+ if (!sampler)
+ return AVERROR_EXTERNAL;
+
+ s->vkctx.queue_family_idx = s->vkctx.hwctx->queue_family_comp_index;
+ s->vkctx.queue_count = GET_QUEUE_COUNT(s->vkctx.hwctx, 0, 1, 0);
+ s->vkctx.cur_queue_idx = av_get_random_seed() % s->vkctx.queue_count;
+
+ s->pl = ff_vk_create_pipeline(ctx);
+ if (!s->pl)
+ return AVERROR(ENOMEM);
+
+ switch (s->out) {
+ case FLAT:
+ s->opts.flat_range[0] = tanf(0.5f * s->h_fov * M_PI / 180.f);
+ s->opts.flat_range[1] = tanf(0.5f * s->v_fov * M_PI / 180.f);
+ break;
+ case STEREOGRAPHIC:
+ s->opts.flat_range[0] = tanf(FFMIN(s->h_fov, 359.f) * M_PI / 720.f);
+ s->opts.flat_range[1] = tanf(FFMIN(s->v_fov, 359.f) * M_PI / 720.f);
+ break;
+ case DUAL_FISHEYE:
+ case FISHEYE:
+ s->opts.flat_range[0] = s->h_fov / 180.f;
+ s->opts.flat_range[1] = s->v_fov / 180.f;
+ break;
+ }
+
+ switch (s->in) {
+ case FLAT:
+ s->opts.iflat_range[0] = tanf(0.5f * s->ih_fov * M_PI / 180.f);
+ s->opts.iflat_range[1] = tanf(0.5f * s->iv_fov * M_PI / 180.f);
+ break;
+ case STEREOGRAPHIC:
+ s->opts.iflat_range[0] = tanf(FFMIN(s->ih_fov, 359.f) * M_PI / 720.f);
+ s->opts.iflat_range[1] = tanf(FFMIN(s->iv_fov, 359.f) * M_PI / 720.f);
+ break;
+ case DUAL_FISHEYE:
+ case FISHEYE:
+ s->opts.iflat_range[0] = s->ih_fov / 180.f;
+ s->opts.iflat_range[1] = s->iv_fov / 180.f;
+ break;
+ }
+
+ s->rotation_order[0] = YAW;
+ s->rotation_order[1] = PITCH;
+ s->rotation_order[2] = ROLL;
+
+ { /* Create the shader */
+ const int planes = av_pix_fmt_count_planes(s->vkctx.output_format);
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->vkctx.output_format);
+
+ set_dimensions(s->inplanewidth, s->inplaneheight, in->width, in->height, desc);
+ set_dimensions(s->planewidth, s->planeheight, outlink->w, outlink->h, desc);
+ calculate_rotation_matrix(s->yaw, s->pitch, s->roll, s->opts.rot_mat, s->rotation_order);
+
+ VulkanDescriptorSetBinding desc_i[2] = {
+ {
+ .name = "input_img",
+ .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ .dimensions = 2,
+ .elems = planes,
+ .stages = VK_SHADER_STAGE_COMPUTE_BIT,
+ .updater = s->input_images,
+ .samplers = DUP_SAMPLER_ARRAY4(*sampler),
+ },
+ {
+ .name = "output_img",
+ .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ .mem_layout = ff_vk_shader_rep_fmt(s->vkctx.output_format),
+ .mem_quali = "writeonly",
+ .dimensions = 2,
+ .elems = planes,
+ .stages = VK_SHADER_STAGE_COMPUTE_BIT,
+ .updater = s->output_images,
+ },
+ };
+
+ SPIRVShader *shd = ff_vk_init_shader(ctx, s->pl, "v360_compute",
+ VK_SHADER_STAGE_COMPUTE_BIT);
+ if (!shd)
+ return AVERROR(ENOMEM);
+
+ ff_vk_set_compute_shader_sizes(ctx, shd, CGROUPS);
+
+ GLSLC(0, layout(push_constant, std430) uniform pushConstants { );
+ GLSLC(1, vec2 flat_range; );
+ GLSLC(1, vec2 iflat_range; );
+ GLSLC(1, mat4 rot_mat; );
+ GLSLC(0, }; );
+ GLSLC(0, );
+
+ ff_vk_add_push_constant(ctx, s->pl, 0, sizeof(s->opts),
+ VK_SHADER_STAGE_COMPUTE_BIT);
+
+ RET(ff_vk_add_descriptor_set(ctx, s->pl, shd, desc_i, 2, 0)); /* set 0 */
+
+ GLSLF(0, #define PI (%f) ,M_PI);
+ GLSLF(0, #define PI_2 (%f) ,M_PI_2);
+ GLSLF(0, #define SQRT2 (%f) ,M_SQRT2);
+ GLSLF(0, #define inplanewidth ivec4(%i, %i, %i, %i), s->inplanewidth[0],
+ s->inplanewidth[1],
+ s->inplanewidth[2],
+ s->inplanewidth[3]);
+ GLSLF(0, #define inplaneheight ivec4(%i, %i, %i, %i), s->inplaneheight[0],
+ s->inplaneheight[1],
+ s->inplaneheight[2],
+ s->inplaneheight[3]);
+
+ switch (s->out) {
+ case FLAT:
+ GLSLD(flat_to_xyz);
+ break;
+ case EQUIRECTANGULAR:
+ GLSLD(equirect_to_xyz);
+ break;
+ case STEREOGRAPHIC:
+ GLSLD(stereographic_to_xyz);
+ break;
+ case FISHEYE:
+ GLSLD(fisheye_to_xyz);
+ break;
+ case DUAL_FISHEYE:
+ GLSLD(dfisheye_to_xyz);
+ break;
+ }
+
+ switch (s->in) {
+ case FLAT:
+ GLSLD(xyz_to_flat);
+ break;
+ case EQUIRECTANGULAR:
+ GLSLD(xyz_to_equirect);
+ break;
+ case STEREOGRAPHIC:
+ GLSLD(xyz_to_stereographic);
+ break;
+ case FISHEYE:
+ GLSLD(xyz_to_fisheye);
+ break;
+ case DUAL_FISHEYE:
+ GLSLD(xyz_to_dfisheye);
+ break;
+ }
+
+ GLSLC(0, void main() );
+ GLSLC(0, { );
+ GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
+ GLSLC(1, vec3 vector; );
+ GLSLF(1, int planes = %i; ,planes);
+ GLSLC(1, for (int i = 0; i < planes; i++) { );
+ GLSLC(2, ivec2 out_size = imageSize(output_img[i]); );
+ GLSLC(2, ivec2 in_size = ivec2(inplanewidth[i],inplaneheight[i]););
+ GLSLC(2, out_transform(vector, out_size, pos); );
+ GLSLC(2, vector = normalize((rot_mat * vec4(vector, 1.f)).xyz); );
+ GLSLC(2, in_transform(i, vector, pos, in_size); );
+ GLSLC(1, } );
+ GLSLC(0, } );
+
+ RET(ff_vk_compile_shader(ctx, shd, "main"));
+ }
+
+ RET(ff_vk_init_pipeline_layout(ctx, s->pl));
+ RET(ff_vk_init_compute_pipeline(ctx, s->pl));
+
+ /* Execution context */
+ RET(ff_vk_create_exec_ctx(ctx, &s->exec));
+
+ s->initialized = 1;
+
+ return 0;
+
+fail:
+ return err;
+}
+
+static int process_frames(AVFilterContext *avctx, AVFrame *out_f, AVFrame *in_f)
+{
+ int err = 0;
+ VkCommandBuffer cmd_buf;
+ V360VulkanContext *s = avctx->priv;
+ AVVkFrame *in = (AVVkFrame *)in_f->data[0];
+ AVVkFrame *out = (AVVkFrame *)out_f->data[0];
+ int planes = av_pix_fmt_count_planes(s->vkctx.output_format);
+
+ /* Update descriptors and init the exec context */
+ ff_vk_start_exec_recording(avctx, s->exec);
+ cmd_buf = ff_vk_get_exec_buf(avctx, s->exec);
+
+ for (int i = 0; i < planes; i++) {
+ RET(ff_vk_create_imageview(avctx, s->exec, &s->input_images[i].imageView, in->img[i],
+ av_vkfmt_from_pixfmt(s->vkctx.input_format)[i],
+ ff_comp_identity_map));
+
+ RET(ff_vk_create_imageview(avctx, s->exec, &s->output_images[i].imageView, out->img[i],
+ av_vkfmt_from_pixfmt(s->vkctx.output_format)[i],
+ ff_comp_identity_map));
+
+ s->input_images[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ s->output_images[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
+ }
+
+ ff_vk_update_descriptor_set(avctx, s->pl, 0);
+
+ for (int i = 0; i < planes; i++) {
+ VkImageMemoryBarrier bar[2] = {
+ {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .srcAccessMask = 0,
+ .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
+ .oldLayout = in->layout[i],
+ .newLayout = s->input_images[i].imageLayout,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = in->img[i],
+ .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .subresourceRange.levelCount = 1,
+ .subresourceRange.layerCount = 1,
+ },
+ {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .srcAccessMask = 0,
+ .dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
+ .oldLayout = out->layout[i],
+ .newLayout = s->output_images[i].imageLayout,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = out->img[i],
+ .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .subresourceRange.levelCount = 1,
+ .subresourceRange.layerCount = 1,
+ },
+ };
+
+ vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
+ 0, NULL, 0, NULL, FF_ARRAY_ELEMS(bar), bar);
+
+ in->layout[i] = bar[0].newLayout;
+ in->access[i] = bar[0].dstAccessMask;
+
+ out->layout[i] = bar[1].newLayout;
+ out->access[i] = bar[1].dstAccessMask;
+ }
+
+ ff_vk_bind_pipeline_exec(avctx, s->exec, s->pl);
+
+ ff_vk_update_push_exec(avctx, s->exec, VK_SHADER_STAGE_COMPUTE_BIT,
+ 0, sizeof(s->opts), &s->opts);
+
+ vkCmdDispatch(cmd_buf,
+ FFALIGN(s->vkctx.output_width, CGROUPS[0])/CGROUPS[0],
+ FFALIGN(s->vkctx.output_height, CGROUPS[1])/CGROUPS[1], 1);
+
+ ff_vk_add_exec_dep(avctx, s->exec, in_f, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
+ ff_vk_add_exec_dep(avctx, s->exec, out_f, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
+
+ err = ff_vk_submit_exec_queue(avctx, s->exec);
+ if (err)
+ return err;
+
+fail:
+ ff_vk_discard_exec_deps(avctx, s->exec);
+ return err;
+}
+
+static int v360_vulkan_filter_frame(AVFilterLink *link, AVFrame *in)
+{
+ int err;
+ AVFilterContext *ctx = link->dst;
+ V360VulkanContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+
+ AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if (!s->initialized)
+ RET(init_filter(ctx, in));
+
+ RET(process_frames(ctx, out, in));
+
+ err = av_frame_copy_props(out, in);
+ if (err < 0)
+ goto fail;
+
+ av_frame_free(&in);
+
+ return ff_filter_frame(outlink, out);
+
+fail:
+ av_frame_free(&in);
+ av_frame_free(&out);
+ return err;
+}
+
+static int v360_vulkan_config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *avctx = outlink->src;
+ V360VulkanContext *s = avctx->priv;
+ AVFilterLink *inlink = avctx->inputs[0];
+ int err;
+
+ if (s->width > 0 && s->height > 0) {
+ s->vkctx.output_width = s->width;
+ s->vkctx.output_height = s->height;
+ }
+
+ s->vkctx.output_format = s->vkctx.input_format;
+
+ err = ff_vk_filter_config_output(outlink);
+ if (err < 0)
+ return err;
+
+ outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
+
+ return 0;
+}
+
+static void v360_vulkan_uninit(AVFilterContext *avctx)
+{
+ V360VulkanContext *s = avctx->priv;
+
+ ff_vk_filter_uninit(avctx);
+
+ s->initialized = 0;
+}
+
+#define OFFSET(x) offsetof(V360VulkanContext, x)
+#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
+static const AVOption v360_vulkan_options[] = {
+ { "input", "set input projection", OFFSET(in), AV_OPT_TYPE_INT, {.i64=EQUIRECTANGULAR}, 0, NB_PROJECTIONS-1, FLAGS, "in" },
+ { "e", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, "in" },
+ { "equirect", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, "in" },
+ { "flat", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, "in" },
+ { "dfisheye", "dual fisheye", 0, AV_OPT_TYPE_CONST, {.i64=DUAL_FISHEYE}, 0, 0, FLAGS, "in" },
+ { "sg", "stereographic", 0, AV_OPT_TYPE_CONST, {.i64=STEREOGRAPHIC}, 0, 0, FLAGS, "in" },
+ { "fisheye", "fisheye", 0, AV_OPT_TYPE_CONST, {.i64=FISHEYE} , 0, 0, FLAGS, "in" },
+ { "output", "set output projection", OFFSET(out), AV_OPT_TYPE_INT, {.i64=FLAT}, 0, NB_PROJECTIONS-1, FLAGS, "out" },
+ { "e", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, "out" },
+ { "equirect", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, "out" },
+ { "flat", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, "out" },
+ { "dfisheye", "dual fisheye", 0, AV_OPT_TYPE_CONST, {.i64=DUAL_FISHEYE}, 0, 0, FLAGS, "out" },
+ { "sg", "stereographic", 0, AV_OPT_TYPE_CONST, {.i64=STEREOGRAPHIC}, 0, 0, FLAGS, "out" },
+ { "fisheye", "fisheye", 0, AV_OPT_TYPE_CONST, {.i64=FISHEYE} , 0, 0, FLAGS, "out" },
+ { "w", "output width", OFFSET(width), AV_OPT_TYPE_INT, {.i64=0}, 0, INT16_MAX, FLAGS, "w"},
+ { "h", "output height", OFFSET(height), AV_OPT_TYPE_INT, {.i64=0}, 0, INT16_MAX, FLAGS, "h"},
+ { "yaw", "yaw rotation", OFFSET(yaw), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, -180.f, 180.f, FLAGS, "yaw"},
+ { "pitch", "pitch rotation", OFFSET(pitch), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, -180.f, 180.f, FLAGS, "pitch"},
+ { "roll", "roll rotation", OFFSET(roll), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, -180.f, 180.f, FLAGS, "roll"},
+ { "rorder", "rotation order", OFFSET(rorder), AV_OPT_TYPE_STRING, {.str="ypr"}, 0, 0, FLAGS, "rorder"},
+ { "h_fov", "set output horizontal FOV angle", OFFSET(h_fov), AV_OPT_TYPE_FLOAT, {.dbl = 90.0f}, 0.00001f, 360.0f, .flags = FLAGS },
+ { "v_fov", "set output vertical FOV angle", OFFSET(v_fov), AV_OPT_TYPE_FLOAT, {.dbl = 45.0f}, 0.00001f, 360.0f, .flags = FLAGS },
+ { "ih_fov", "set input horizontal FOV angle", OFFSET(ih_fov), AV_OPT_TYPE_FLOAT, {.dbl = 90.0f}, 0.00001f, 360.0f, .flags = FLAGS },
+ { "iv_fov", "set input vertical FOV angle", OFFSET(iv_fov), AV_OPT_TYPE_FLOAT, {.dbl = 45.0f}, 0.00001f, 360.0f, .flags = FLAGS },
+ { NULL },
+};
+
+AVFILTER_DEFINE_CLASS(v360_vulkan);
+
+static const AVFilterPad v360_vulkan_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = &v360_vulkan_filter_frame,
+ .config_props = &ff_vk_filter_config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad v360_vulkan_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = &v360_vulkan_config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_v360_vulkan = {
+ .name = "v360_vulkan",
+ .description = NULL_IF_CONFIG_SMALL("Convert 360 projection of video."),
+ .priv_size = sizeof(V360VulkanContext),
+ .init = &ff_vk_filter_init,
+ .uninit = &v360_vulkan_uninit,
+ .query_formats = &ff_vk_filter_query_formats,
+ .inputs = v360_vulkan_inputs,
+ .outputs = v360_vulkan_outputs,
+ .priv_class = &v360_vulkan_class,
+ .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
+};
--
2.17.1
5
18
Signed-off-by: Paul B Mahol <onemda(a)gmail.com>
---
doc/filters.texi | 27 +++++
libavfilter/Makefile | 1 +
libavfilter/af_asoftclip.c | 217 +++++++++++++++++++++++++++++++++++++
libavfilter/allfilters.c | 1 +
4 files changed, 246 insertions(+)
create mode 100644 libavfilter/af_asoftclip.c
diff --git a/doc/filters.texi b/doc/filters.texi
index 4dd1a5de85..465eeb4732 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -2104,6 +2104,33 @@ audio, the data is treated as if all the planes were concatenated.
A list of Adler-32 checksums for each data plane.
@end table
+@section asoftclip
+Apply audio soft clipping.
+
+Soft clipping is a type of distortion effect where the amplitude of a signal is saturated
+along a smooth curve, rather than the abrupt shape of hard-clipping.
+
+This filter accepts the following options:
+
+@table @option
+@item type
+Set type of soft-clipping.
+
+It accepts the following values:
+@table @option
+@item tanh
+@item atan
+@item cubic
+@item exp
+@item alg
+@item quintic
+@item sin
+@end table
+
+@item param
+Set additional parameter which controls sigmoid function.
+@end table
+
@anchor{astats}
@section astats
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index fef6ec5c55..682df45ef5 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -80,6 +80,7 @@ OBJS-$(CONFIG_ASETRATE_FILTER) += af_asetrate.o
OBJS-$(CONFIG_ASETTB_FILTER) += settb.o
OBJS-$(CONFIG_ASHOWINFO_FILTER) += af_ashowinfo.o
OBJS-$(CONFIG_ASIDEDATA_FILTER) += f_sidedata.o
+OBJS-$(CONFIG_ASOFTCLIP_FILTER) += af_asoftclip.o
OBJS-$(CONFIG_ASPLIT_FILTER) += split.o
OBJS-$(CONFIG_ASTATS_FILTER) += af_astats.o
OBJS-$(CONFIG_ASTREAMSELECT_FILTER) += f_streamselect.o framesync.o
diff --git a/libavfilter/af_asoftclip.c b/libavfilter/af_asoftclip.c
new file mode 100644
index 0000000000..239b1d6a6b
--- /dev/null
+++ b/libavfilter/af_asoftclip.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2019 The FFmpeg Project
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "formats.h"
+
+enum ASoftClipTypes {
+ ASC_TANH,
+ ASC_ATAN,
+ ASC_CUBIC,
+ ASC_EXP,
+ ASC_ALG,
+ ASC_QUINTIC,
+ ASC_SIN,
+ NB_TYPES,
+};
+
+typedef struct ASoftClipContext {
+ const AVClass *class;
+
+ int type;
+ double param;
+
+ void (*filter)(struct ASoftClipContext *s, void **dst, const void **src,
+ int nb_samples, int channels);
+} ASoftClipContext;
+
+#define OFFSET(x) offsetof(ASoftClipContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption asoftclip_options[] = {
+ { "type", "set softclip type", OFFSET(type), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_TYPES-1, A, "types" },
+ { "tanh", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_TANH}, 0, 0, A, "types" },
+ { "atan", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_ATAN}, 0, 0, A, "types" },
+ { "cubic", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_CUBIC}, 0, 0, A, "types" },
+ { "exp", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_EXP}, 0, 0, A, "types" },
+ { "alg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_ALG}, 0, 0, A, "types" },
+ { "quintic", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_QUINTIC},0, 0, A, "types" },
+ { "sin", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_SIN}, 0, 0, A, "types" },
+ { "param", "set softclip parameter", OFFSET(param), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 3, A },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(asoftclip);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layouts = NULL;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_DBLP,
+ AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ layouts = ff_all_channel_counts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+#define SQR(x) ((x) * (x))
+
+static void filter_dblp(ASoftClipContext *s,
+ void **dptr, const void **sptr,
+ int nb_samples, int channels)
+{
+ double param = s->param;
+ int n, c;
+
+ for (c = 0; c < channels; c++) {
+ const double *src = sptr[c];
+ double *dst = dptr[c];
+
+ switch (s->type) {
+ case ASC_TANH:
+ for (n = 0; n < nb_samples; n++) {
+ dst[n] = tanh(src[n] * param);
+ }
+ break;
+ case ASC_ATAN:
+ for (n = 0; n < nb_samples; n++)
+ dst[n] = 2. / M_PI * atan(src[n] * param);
+ break;
+ case ASC_CUBIC:
+ for (n = 0; n < nb_samples; n++) {
+ if (FFABS(src[n]) >= 1.5)
+ dst[n] = FFSIGN(src[n]);
+ else
+ dst[n] = src[n] - 0.1481 * pow(src[n], 3.0f);
+ }
+ break;
+ case ASC_EXP:
+ for (n = 0; n < nb_samples; n++)
+ dst[n] = 2. / (1. + exp(-2. * src[n])) - 1.;
+ break;
+ case ASC_ALG:
+ for (n = 0; n < nb_samples; n++)
+ dst[n] = src[n] / (sqrt(param + src[n] * src[n]));
+ break;
+ case ASC_QUINTIC:
+ for (n = 0; n < nb_samples; n++) {
+ if (FFABS(src[n]) >= 1.25)
+ dst[n] = FFSIGN(src[n]);
+ else
+ dst[n] = src[n] - 0.08192 * pow(src[n], 5.);
+ }
+ break;
+ case ASC_SIN:
+ for (n = 0; n < nb_samples; n++) {
+ if (FFABS(src[n]) >= M_PI_2)
+ dst[n] = FFSIGN(src[n]);
+ else
+ dst[n] = sin(src[n]);
+ }
+ break;
+ }
+ }
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ASoftClipContext *s = ctx->priv;
+
+ s->filter = filter_dblp;
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ ASoftClipContext *s = ctx->priv;
+ AVFrame *out;
+
+ if (av_frame_is_writable(in)) {
+ out = in;
+ } else {
+ out = ff_get_audio_buffer(outlink, in->nb_samples);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ s->filter(s, (void **)out->extended_data, (const void **)in->extended_data,
+ in->nb_samples, in->channels);
+
+ if (out != in)
+ av_frame_free(&in);
+
+ return ff_filter_frame(outlink, out);
+}
+
+static const AVFilterPad inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_asoftclip = {
+ .name = "asoftclip",
+ .description = NULL_IF_CONFIG_SMALL("Audio Soft Clipper."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(ASoftClipContext),
+ .priv_class = &asoftclip_class,
+ .inputs = inputs,
+ .outputs = outputs,
+};
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index c51ae0f3c7..4d3039d6ba 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -72,6 +72,7 @@ extern AVFilter ff_af_asetrate;
extern AVFilter ff_af_asettb;
extern AVFilter ff_af_ashowinfo;
extern AVFilter ff_af_asidedata;
+extern AVFilter ff_af_asoftclip;
extern AVFilter ff_af_asplit;
extern AVFilter ff_af_astats;
extern AVFilter ff_af_astreamselect;
--
2.17.1
6
47
[PATCH 1/3] closed caption decoder: accept and decode a new codec type of 'raw 608 byte pairs'
by Roger Pack 20 Jun '23
by Roger Pack 20 Jun '23
20 Jun '23
I needed this in order to be able to parse raw analog TV closed
caption byte pairs (analog line 21 CC's).
6
12
single: Single-track
track{0,1}: Dual-track
trunc-t1: Truncated track 1
trunc-t2-track{0,1}: Fully-truncated track 2
trunc-t2a-track{0,1}: Partially-truncated track 2
trunc-h2: Truncated track 2 header
Signed-off-by: Zane van Iperen <zane(a)zanevaniperen.com>
---
tests/fate/adpcm.mak | 27 +++++++++++++++++++
tests/ref/fate/adpcm-ima-cunning-single | 1 +
tests/ref/fate/adpcm-ima-cunning-track0 | 1 +
tests/ref/fate/adpcm-ima-cunning-track1 | 1 +
tests/ref/fate/adpcm-ima-cunning-trunc-h2 | 1 +
tests/ref/fate/adpcm-ima-cunning-trunc-t1 | 1 +
.../fate/adpcm-ima-cunning-trunc-t2-track0 | 1 +
.../fate/adpcm-ima-cunning-trunc-t2-track1 | 1 +
.../fate/adpcm-ima-cunning-trunc-t2a-track0 | 1 +
.../fate/adpcm-ima-cunning-trunc-t2a-track1 | 1 +
10 files changed, 36 insertions(+)
create mode 100644 tests/ref/fate/adpcm-ima-cunning-single
create mode 100644 tests/ref/fate/adpcm-ima-cunning-track0
create mode 100644 tests/ref/fate/adpcm-ima-cunning-track1
create mode 100644 tests/ref/fate/adpcm-ima-cunning-trunc-h2
create mode 100644 tests/ref/fate/adpcm-ima-cunning-trunc-t1
create mode 100644 tests/ref/fate/adpcm-ima-cunning-trunc-t2-track0
create mode 100644 tests/ref/fate/adpcm-ima-cunning-trunc-t2-track1
create mode 100644 tests/ref/fate/adpcm-ima-cunning-trunc-t2a-track0
create mode 100644 tests/ref/fate/adpcm-ima-cunning-trunc-t2a-track1
diff --git a/tests/fate/adpcm.mak b/tests/fate/adpcm.mak
index 3e6d4ecdd1..bc2804477f 100644
--- a/tests/fate/adpcm.mak
+++ b/tests/fate/adpcm.mak
@@ -112,5 +112,32 @@ fate-adpcm-ima-alp-mono: CMD = md5 -i $(TARGET_SAMPLES)/alp/AD_P11.PCM -f s16le
FATE_ADPCM-$(call DEMDEC, ALP, ADPCM_IMA_ALP) += fate-adpcm-ima-alp-stereo
fate-adpcm-ima-alp-stereo: CMD = md5 -i $(TARGET_SAMPLES)/alp/theme-cut.tun -f s16le
+FATE_ADPCM-$(call DEMDEC, PP_BNK, ADPCM_IMA_CUNNING) += fate-adpcm-ima-cunning-single
+fate-adpcm-ima-cunning-single: CMD = md5 -y -i $(TARGET_SAMPLES)/pp_bnk/GD-cut.5c -f s16le
+
+FATE_ADPCM-$(call DEMDEC, PP_BNK, ADPCM_IMA_CUNNING) += fate-adpcm-ima-cunning-track0
+fate-adpcm-ima-cunning-track0: CMD = md5 -y -i $(TARGET_SAMPLES)/pp_bnk/VIDEOMOD-cut.11c -map 0:a:0 -f s16le
+
+FATE_ADPCM-$(call DEMDEC, PP_BNK, ADPCM_IMA_CUNNING) += fate-adpcm-ima-cunning-track1
+fate-adpcm-ima-cunning-track1: CMD = md5 -y -i $(TARGET_SAMPLES)/pp_bnk/VIDEOMOD-cut.11c -map 0:a:1 -f s16le
+
+FATE_ADPCM-$(call DEMDEC, PP_BNK, ADPCM_IMA_CUNNING) += fate-adpcm-ima-cunning-trunc-t1
+fate-adpcm-ima-cunning-trunc-t1: CMD = md5 -y -i $(TARGET_SAMPLES)/pp_bnk/VIDEOMOD-trunc-t1.11c -map 0:a:0 -f s16le
+
+FATE_ADPCM-$(call DEMDEC, PP_BNK, ADPCM_IMA_CUNNING) += fate-adpcm-ima-cunning-trunc-t2-track0
+fate-adpcm-ima-cunning-trunc-t2-track0: CMD = md5 -y -i $(TARGET_SAMPLES)/pp_bnk/VIDEOMOD-trunc-t2.11c -map 0:a:0 -f s16le
+
+FATE_ADPCM-$(call DEMDEC, PP_BNK, ADPCM_IMA_CUNNING) += fate-adpcm-ima-cunning-trunc-t2-track1
+fate-adpcm-ima-cunning-trunc-t2-track1: CMD = md5 -y -i $(TARGET_SAMPLES)/pp_bnk/VIDEOMOD-trunc-t2.11c -map 0:a:1 -f s16le
+
+FATE_ADPCM-$(call DEMDEC, PP_BNK, ADPCM_IMA_CUNNING) += fate-adpcm-ima-cunning-trunc-t2a-track0
+fate-adpcm-ima-cunning-trunc-t2a-track0: CMD = md5 -y -i $(TARGET_SAMPLES)/pp_bnk/VIDEOMOD-trunc-t2a.11c -map 0:a:0 -f s16le
+
+FATE_ADPCM-$(call DEMDEC, PP_BNK, ADPCM_IMA_CUNNING) += fate-adpcm-ima-cunning-trunc-t2a-track1
+fate-adpcm-ima-cunning-trunc-t2a-track1: CMD = md5 -y -i $(TARGET_SAMPLES)/pp_bnk/VIDEOMOD-trunc-t2a.11c -map 0:a:1 -f s16le
+
+FATE_ADPCM-$(call DEMDEC, PP_BNK, ADPCM_IMA_CUNNING) += fate-adpcm-ima-cunning-trunc-h2
+fate-adpcm-ima-cunning-trunc-h2: CMD = md5 -y -i $(TARGET_SAMPLES)/pp_bnk/VIDEOMOD-trunc-h2.11c -map 0:a:0 -f s16le
+
FATE_SAMPLES_AVCONV += $(FATE_ADPCM-yes)
fate-adpcm: $(FATE_ADPCM-yes)
diff --git a/tests/ref/fate/adpcm-ima-cunning-single b/tests/ref/fate/adpcm-ima-cunning-single
new file mode 100644
index 0000000000..49a8308093
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-cunning-single
@@ -0,0 +1 @@
+dd6ba6151c3e74d09be3c54005465aab
diff --git a/tests/ref/fate/adpcm-ima-cunning-track0 b/tests/ref/fate/adpcm-ima-cunning-track0
new file mode 100644
index 0000000000..bd489cfb45
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-cunning-track0
@@ -0,0 +1 @@
+fb8db1eef33860c1adde4932e7a250ac
diff --git a/tests/ref/fate/adpcm-ima-cunning-track1 b/tests/ref/fate/adpcm-ima-cunning-track1
new file mode 100644
index 0000000000..f79013c9de
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-cunning-track1
@@ -0,0 +1 @@
+4b2f9c416ae676526754c82f2a669c91
diff --git a/tests/ref/fate/adpcm-ima-cunning-trunc-h2 b/tests/ref/fate/adpcm-ima-cunning-trunc-h2
new file mode 100644
index 0000000000..bd489cfb45
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-cunning-trunc-h2
@@ -0,0 +1 @@
+fb8db1eef33860c1adde4932e7a250ac
diff --git a/tests/ref/fate/adpcm-ima-cunning-trunc-t1 b/tests/ref/fate/adpcm-ima-cunning-trunc-t1
new file mode 100644
index 0000000000..4669e38855
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-cunning-trunc-t1
@@ -0,0 +1 @@
+a0eaad31febdcf1cfb94a4d418e1e140
diff --git a/tests/ref/fate/adpcm-ima-cunning-trunc-t2-track0 b/tests/ref/fate/adpcm-ima-cunning-trunc-t2-track0
new file mode 100644
index 0000000000..bd489cfb45
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-cunning-trunc-t2-track0
@@ -0,0 +1 @@
+fb8db1eef33860c1adde4932e7a250ac
diff --git a/tests/ref/fate/adpcm-ima-cunning-trunc-t2-track1 b/tests/ref/fate/adpcm-ima-cunning-trunc-t2-track1
new file mode 100644
index 0000000000..df9edc403d
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-cunning-trunc-t2-track1
@@ -0,0 +1 @@
+d41d8cd98f00b204e9800998ecf8427e
diff --git a/tests/ref/fate/adpcm-ima-cunning-trunc-t2a-track0 b/tests/ref/fate/adpcm-ima-cunning-trunc-t2a-track0
new file mode 100644
index 0000000000..bd489cfb45
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-cunning-trunc-t2a-track0
@@ -0,0 +1 @@
+fb8db1eef33860c1adde4932e7a250ac
diff --git a/tests/ref/fate/adpcm-ima-cunning-trunc-t2a-track1 b/tests/ref/fate/adpcm-ima-cunning-trunc-t2a-track1
new file mode 100644
index 0000000000..77d4b09e62
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-cunning-trunc-t2a-track1
@@ -0,0 +1 @@
+af0d42f01108333ab356061f9cab9403
--
2.25.1
3
5
This video format is mainly used in older Nintendo DS games in a .vx container. It is the predecessor of the Mobiclip format.
Signed-off-by: Florian Nouwt <fnouwt2(a)gmail.com>
---
Changelog | 1 +
configure | 1 +
doc/general_contents.texi | 2 +
libavcodec/Makefile | 1 +
libavcodec/actimagine.c | 1644 +++++++++++++++++++++++++++++++++++++
libavcodec/allcodecs.c | 1 +
libavcodec/codec_desc.c | 7 +
libavcodec/codec_id.h | 1 +
libavcodec/version.h | 2 +-
libavformat/riff.c | 2 +
10 files changed, 1661 insertions(+), 1 deletion(-)
create mode 100644 libavcodec/actimagine.c
diff --git a/Changelog b/Changelog
index a96e350e09..8807f3dcb3 100644
--- a/Changelog
+++ b/Changelog
@@ -83,6 +83,7 @@ version <next>:
- msad video filter
- gophers protocol
- RIST protocol via librist
+- Actimagine VX video decoder
version 4.3:
diff --git a/configure b/configure
index f0ac719d2d..10a07da95f 100755
--- a/configure
+++ b/configure
@@ -2662,6 +2662,7 @@ ac3_fixed_decoder_select="ac3_parser ac3dsp bswapdsp mdct"
ac3_encoder_select="ac3dsp audiodsp mdct me_cmp"
ac3_fixed_encoder_select="ac3dsp audiodsp mdct me_cmp"
acelp_kelvin_decoder_select="audiodsp"
+actimagine_decoder_select="bswapdsp golomb"
adpcm_g722_decoder_select="g722dsp"
adpcm_g722_encoder_select="g722dsp"
aic_decoder_select="golomb idctdsp"
diff --git a/doc/general_contents.texi b/doc/general_contents.texi
index 33ece6e884..d4261386fc 100644
--- a/doc/general_contents.texi
+++ b/doc/general_contents.texi
@@ -807,6 +807,8 @@ following image formats are supported:
@item 8088flex TMV @tab @tab X
@item A64 multicolor @tab X @tab
@tab Creates video suitable to be played on a commodore 64 (multicolor mode).
+@item Actimagine VX Video @tab @tab X
+ @tab fourcc: vxs1, VXS1
@item Amazing Studio PAF Video @tab @tab X
@item American Laser Games MM @tab @tab X
@tab Used in games like Mad Dog McCree.
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 81cc16471b..39b3bc968d 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -182,6 +182,7 @@ OBJS-$(CONFIG_AC3_ENCODER) += ac3enc_float.o ac3enc.o ac3tab.o \
OBJS-$(CONFIG_AC3_FIXED_ENCODER) += ac3enc_fixed.o ac3enc.o ac3tab.o ac3.o kbdwin.o
OBJS-$(CONFIG_AC3_MF_ENCODER) += mfenc.o mf_utils.o
OBJS-$(CONFIG_ACELP_KELVIN_DECODER) += g729dec.o lsp.o celp_math.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o
+OBJS-$(CONFIG_ACTIMAGINE_DECODER) += actimagine.o
OBJS-$(CONFIG_AGM_DECODER) += agm.o
OBJS-$(CONFIG_AIC_DECODER) += aic.o
OBJS-$(CONFIG_ALAC_DECODER) += alac.o alac_data.o alacdsp.o
diff --git a/libavcodec/actimagine.c b/libavcodec/actimagine.c
new file mode 100644
index 0000000000..6bb5126b05
--- /dev/null
+++ b/libavcodec/actimagine.c
@@ -0,0 +1,1644 @@
+/*
+ * Actimagine VX Video decoder
+ * Copyright (c) 2021 Florian Nouwt
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <inttypes.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/thread.h"
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "bswapdsp.h"
+#include "get_bits.h"
+#include "golomb.h"
+#include "internal.h"
+
+static const uint8_t predict_dc_shift_tab[] = {1, 2, 3, 0, 4};
+
+static const uint8_t zigzag4x4_tab[] =
+{
+ 0x00, 0x04, 0x01, 0x02, 0x05, 0x08, 0x0C, 0x09,
+ 0x06, 0x03, 0x07, 0x0A, 0x0D, 0x0E, 0x0B, 0x0F
+};
+
+static const uint8_t quant4x4_tab[][8] =
+{
+ { 0x0A, 0x0D, 0x0A, 0x0D, 0x0D, 0x10, 0x0D, 0x10 },
+ { 0x0B, 0x0E, 0x0B, 0x0E, 0x0E, 0x12, 0x0E, 0x12 },
+ { 0x0D, 0x10, 0x0D, 0x10, 0x10, 0x14, 0x10, 0x14 },
+ { 0x0E, 0x12, 0x0E, 0x12, 0x12, 0x17, 0x12, 0x17 },
+ { 0x10, 0x14, 0x10, 0x14, 0x14, 0x19, 0x14, 0x19 },
+ { 0x12, 0x17, 0x12, 0x17, 0x17, 0x1D, 0x17, 0x1D }
+};
+
+static const uint8_t old_mb_mode_remap_tab[] =
+{
+ 1, 2, 0, 4, 7, 3, 11, 15, 9, 5, 14, 6,
+ 12, 13, 8, 16, 23, 10, 22, 19, 20, 17, 21, 18
+};
+
+static const uint8_t residu_mask_old_tab[] =
+{
+ 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x03, 0x05,
+ 0x0A, 0x0C, 0x0F, 0x1F, 0x07, 0x0B, 0x0D, 0x0E,
+ 0x06, 0x09, 0x13, 0x15, 0x1A, 0x1C, 0x11, 0x12,
+ 0x14, 0x18, 0x17, 0x1B, 0x1D, 0x1E, 0x16, 0x19
+};
+
+static const uint8_t residu_mask_new_tab[] =
+{
+ 0x00, 0x08, 0x04, 0x02, 0x01, 0x1F, 0x0F, 0x0A,
+ 0x05, 0x0C, 0x03, 0x10, 0x0E, 0x0D, 0x0B, 0x07,
+ 0x09, 0x06, 0x1E, 0x1B, 0x1A, 0x1D, 0x17, 0x15,
+ 0x18, 0x12, 0x11, 0x1C, 0x14, 0x13, 0x16, 0x19
+};
+
+static const int cavlc_suffix_len_update_tab[] =
+{
+ 2, 5, 11, 23, 47, 32768
+};
+
+// same tables as h264 cavlc
+static const uint8_t coeff_token_table_index[17] =
+{
+ 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3
+};
+
+static const uint8_t coeff_token_len[4][4 * 17] = {
+{
+ 1, 0, 0, 0,
+ 6, 2, 0, 0, 8, 6, 3, 0, 9, 8, 7, 5, 10, 9, 8, 6,
+ 11,10, 9, 7, 13,11,10, 8, 13,13,11, 9, 13,13,13,10,
+ 14,14,13,11, 14,14,14,13, 15,15,14,14, 15,15,15,14,
+ 16,15,15,15, 16,16,16,15, 16,16,16,16, 16,16,16,16,
+},
+{
+ 2, 0, 0, 0,
+ 6, 2, 0, 0, 6, 5, 3, 0, 7, 6, 6, 4, 8, 6, 6, 4,
+ 8, 7, 7, 5, 9, 8, 8, 6, 11, 9, 9, 6, 11,11,11, 7,
+ 12,11,11, 9, 12,12,12,11, 12,12,12,11, 13,13,13,12,
+ 13,13,13,13, 13,14,13,13, 14,14,14,13, 14,14,14,14,
+},
+{
+ 4, 0, 0, 0,
+ 6, 4, 0, 0, 6, 5, 4, 0, 6, 5, 5, 4, 7, 5, 5, 4,
+ 7, 5, 5, 4, 7, 6, 6, 4, 7, 6, 6, 4, 8, 7, 7, 5,
+ 8, 8, 7, 6, 9, 8, 8, 7, 9, 9, 8, 8, 9, 9, 9, 8,
+ 10, 9, 9, 9, 10,10,10,10, 10,10,10,10, 10,10,10,10,
+},
+{
+ 6, 0, 0, 0,
+ 6, 6, 0, 0, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+}
+};
+
+static const uint8_t coeff_token_bits[4][4 * 17] = {
+{
+ 1, 0, 0, 0,
+ 5, 1, 0, 0, 7, 4, 1, 0, 7, 6, 5, 3, 7, 6, 5, 3,
+ 7, 6, 5, 4, 15, 6, 5, 4, 11,14, 5, 4, 8,10,13, 4,
+ 15,14, 9, 4, 11,10,13,12, 15,14, 9,12, 11,10,13, 8,
+ 15, 1, 9,12, 11,14,13, 8, 7,10, 9,12, 4, 6, 5, 8,
+},
+{
+ 3, 0, 0, 0,
+ 11, 2, 0, 0, 7, 7, 3, 0, 7,10, 9, 5, 7, 6, 5, 4,
+ 4, 6, 5, 6, 7, 6, 5, 8, 15, 6, 5, 4, 11,14,13, 4,
+ 15,10, 9, 4, 11,14,13,12, 8,10, 9, 8, 15,14,13,12,
+ 11,10, 9,12, 7,11, 6, 8, 9, 8,10, 1, 7, 6, 5, 4,
+},
+{
+ 15, 0, 0, 0,
+ 15,14, 0, 0, 11,15,13, 0, 8,12,14,12, 15,10,11,11,
+ 11, 8, 9,10, 9,14,13, 9, 8,10, 9, 8, 15,14,13,13,
+ 11,14,10,12, 15,10,13,12, 11,14, 9,12, 8,10,13, 8,
+ 13, 7, 9,12, 9,12,11,10, 5, 8, 7, 6, 1, 4, 3, 2,
+},
+{
+ 3, 0, 0, 0,
+ 0, 1, 0, 0, 4, 5, 6, 0, 8, 9,10,11, 12,13,14,15,
+ 16,17,18,19, 20,21,22,23, 24,25,26,27, 28,29,30,31,
+ 32,33,34,35, 36,37,38,39, 40,41,42,43, 44,45,46,47,
+ 48,49,50,51, 52,53,54,55, 56,57,58,59, 60,61,62,63,
+}
+};
+
+static const uint8_t total_zeros_len[16][16] = {
+ {1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9},
+ {3,3,3,3,3,4,4,4,4,5,5,6,6,6,6},
+ {4,3,3,3,4,4,3,3,4,5,5,6,5,6},
+ {5,3,4,4,3,3,3,4,3,4,5,5,5},
+ {4,4,4,3,3,3,3,3,4,5,4,5},
+ {6,5,3,3,3,3,3,3,4,3,6},
+ {6,5,3,3,3,2,3,4,3,6},
+ {6,4,5,3,2,2,3,3,6},
+ {6,6,4,2,2,3,2,5},
+ {5,5,3,2,2,2,4},
+ {4,4,3,3,1,3},
+ {4,4,2,1,3},
+ {3,3,1,2},
+ {2,2,1},
+ {1,1},
+};
+
+static const uint8_t total_zeros_bits[16][16] = {
+ {1,3,2,3,2,3,2,3,2,3,2,3,2,3,2,1},
+ {7,6,5,4,3,5,4,3,2,3,2,3,2,1,0},
+ {5,7,6,5,4,3,4,3,2,3,2,1,1,0},
+ {3,7,5,4,6,5,4,3,3,2,2,1,0},
+ {5,4,3,7,6,5,4,3,2,1,1,0},
+ {1,1,7,6,5,4,3,2,1,1,0},
+ {1,1,5,4,3,3,2,1,1,0},
+ {1,1,1,3,3,2,2,1,0},
+ {1,0,1,3,2,1,1,1},
+ {1,0,1,3,2,1,1},
+ {0,1,1,2,1,3},
+ {0,1,1,1,1},
+ {0,1,1,1},
+ {0,1,1},
+ {0,1},
+};
+
+static const uint8_t run_len[7][16] = {
+ {1,1},
+ {1,2,2},
+ {2,2,2,2},
+ {2,2,2,3,3},
+ {2,2,3,3,3,3},
+ {2,3,3,3,3,3,3},
+ {3,3,3,3,3,3,3,4,5,6,7,8,9,10,11},
+};
+
+static const uint8_t run_bits[7][16] = {
+ {1,0},
+ {1,1,0},
+ {3,2,1,0},
+ {3,2,1,1,0},
+ {3,2,3,2,1,0},
+ {3,0,1,3,2,5,4},
+ {7,6,5,4,3,2,1,1,1,1,1,1,1,1,1},
+};
+
+typedef struct MVec {
+ int x, y;
+} MVec;
+
+typedef struct ActimagineContext {
+ AVFrame *cur_frame;
+ AVFrame *ref_frames[3];
+ int ref_frame_count;
+
+ int version;
+ int quantizer;
+ int avi;
+
+ GetBitContext gb;
+
+ uint8_t *bitstream;
+ int bitstream_size;
+
+ int qtab[2][4];
+
+ uint8_t pred4_cache[5][5];
+
+ MVec *vectors;
+ int vectors_stride;
+
+ uint8_t *total_coeff_y;
+ int total_coeff_y_stride;
+
+ uint8_t *total_coeff_uv;
+ int total_coeff_uv_stride;
+
+ BswapDSPContext bdsp;
+} ActimagineContext;
+
+static VLC coeff_token_vlc[4];
+static VLC_TYPE coeff_token_vlc_tables[520+332+280+256][2];
+static const int coeff_token_vlc_tables_size[4]={520,332,280,256};
+
+static VLC total_zeros_vlc[15+1];
+static VLC_TYPE total_zeros_vlc_tables[15][512][2];
+static const int total_zeros_vlc_tables_size = 512;
+
+static VLC run_vlc[6+1];
+static VLC_TYPE run_vlc_tables[6][8][2];
+static const int run_vlc_tables_size = 8;
+
+static VLC run7_vlc;
+static VLC_TYPE run7_vlc_table[96][2];
+static const int run7_vlc_table_size = 96;
+
+#define COEFF_TOKEN_VLC_BITS 8
+#define TOTAL_ZEROS_VLC_BITS 9
+#define RUN_VLC_BITS 3
+#define RUN7_VLC_BITS 6
+
+#define PIXEL_REF(s, ref, plane, x, y)\
+ ((s)->ref_frames[(ref)]->data[(plane)]\
+ [(y) * (s)->ref_frames[(ref)]->linesize[(plane)] + (x)])
+
+#define PIXEL_CUR(s, plane, x, y)\
+ ((s)->cur_frame->data[(plane)]\
+ [(y) * (s)->cur_frame->linesize[(plane)] + (x)])
+
+#define PREDICT2(a,b) (((a) + (b) + 1) >> 1)
+#define PREDICT3(a,b,c) (((a) + 2 * (b) + (c) + 2) >> 2)
+
+#define VX_VERSION_INVALID -1
+#define VX_VERSION_OLD 0
+#define VX_VERSION_NEW 1
+
+static av_cold void actimagine_init_static(void)
+{
+ // all these tables are equal to the ones used for h264 cavlc
+ int offset = 0;
+ for (int i = 0; i < 4; i++) {
+ coeff_token_vlc[i].table = coeff_token_vlc_tables + offset;
+ coeff_token_vlc[i].table_allocated = coeff_token_vlc_tables_size[i];
+ init_vlc(&coeff_token_vlc[i], COEFF_TOKEN_VLC_BITS, 4 * 17,
+ &coeff_token_len [i][0], 1, 1,
+ &coeff_token_bits[i][0], 1, 1,
+ INIT_VLC_USE_NEW_STATIC);
+ offset += coeff_token_vlc_tables_size[i];
+ }
+ /*
+ * This is a one time safety check to make sure that
+ * the packed static coeff_token_vlc table sizes
+ * were initialized correctly.
+ */
+ av_assert0(offset == FF_ARRAY_ELEMS(coeff_token_vlc_tables));
+
+ for (int i = 0; i < 15; i++) {
+ total_zeros_vlc[i + 1].table = total_zeros_vlc_tables[i];
+ total_zeros_vlc[i + 1].table_allocated = total_zeros_vlc_tables_size;
+ init_vlc(&total_zeros_vlc[i + 1],
+ TOTAL_ZEROS_VLC_BITS, 16,
+ &total_zeros_len [i][0], 1, 1,
+ &total_zeros_bits[i][0], 1, 1,
+ INIT_VLC_USE_NEW_STATIC);
+ }
+
+ for (int i = 0; i < 6; i++) {
+ run_vlc[i + 1].table = run_vlc_tables[i];
+ run_vlc[i + 1].table_allocated = run_vlc_tables_size;
+ init_vlc(&run_vlc[i + 1],
+ RUN_VLC_BITS, 7,
+ &run_len [i][0], 1, 1,
+ &run_bits[i][0], 1, 1,
+ INIT_VLC_USE_NEW_STATIC);
+ }
+
+ run7_vlc.table = run7_vlc_table,
+ run7_vlc.table_allocated = run7_vlc_table_size;
+ init_vlc(&run7_vlc, RUN7_VLC_BITS, 16,
+ &run_len [6][0], 1, 1,
+ &run_bits[6][0], 1, 1,
+ INIT_VLC_USE_NEW_STATIC);
+}
+
+static int setup_qtables(AVCodecContext *avctx, int quantizer)
+{
+ int qx, qy;
+ ActimagineContext *s = avctx->priv_data;
+
+ if (quantizer < 12 || quantizer > 161)
+ return AVERROR_INVALIDDATA;
+
+ s->quantizer = quantizer;
+
+ qx = quantizer % 6;
+ qy = quantizer / 6;
+
+ for (int i = 0; i < 2; i++)
+ for (int j = 0; j < 4; j++)
+ s->qtab[i][j] = quant4x4_tab[qx][4 * i + j] << qy;
+
+ return 0;
+}
+
+static av_cold int actimagine_init(AVCodecContext *avctx)
+{
+ int vectors_size;
+ int total_coeff_y_size;
+ int total_coeff_uv_size;
+ static AVOnce init_static_once = AV_ONCE_INIT;
+ ActimagineContext *s = avctx->priv_data;
+
+ if (avctx->width & 15 || avctx->height & 15) {
+ av_log(avctx, AV_LOG_ERROR, "width/height not multiple of 16\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ff_bswapdsp_init(&s->bdsp);
+
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ avctx->color_range = AVCOL_RANGE_JPEG;
+ avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
+ // the color space of this video format is not supported currently
+ // it is a yuv approximation that can be converted back to rgb using bitshifts
+ // r = y + (v << 1)
+ // g = y - (u >> 1) - v
+ // b = y + (u << 1)
+ avctx->colorspace = AVCOL_SPC_NB;
+
+ // predict4 cache
+ for (int i = 0; i < 5; i++)
+ for (int j = 0; j < 5; j++)
+ s->pred4_cache[i][j] = 9;
+
+ // motion vector cache
+ s->vectors_stride = (avctx->width >> 4) + 2;
+ vectors_size = ((avctx->height >> 4) + 1) * s->vectors_stride;
+ s->vectors = av_calloc(vectors_size, sizeof(MVec));
+ if (!s->vectors)
+ return AVERROR(ENOMEM);
+ memset(s->vectors, 0, vectors_size * sizeof(MVec));
+
+ // total dct coefficient cache for luma
+ s->total_coeff_y_stride = (avctx->width >> 2) + 1;
+ total_coeff_y_size = ((avctx->height >> 2) + 1) * s->total_coeff_y_stride;
+ s->total_coeff_y = av_malloc(total_coeff_y_size);
+ if (!s->total_coeff_y)
+ return AVERROR(ENOMEM);
+ memset(s->total_coeff_y, 0, total_coeff_y_size);
+
+ // total dct coefficient cache for chroma
+ s->total_coeff_uv_stride = (avctx->width >> 3) + 1;
+ total_coeff_uv_size = ((avctx->height >> 3) + 1) * s->total_coeff_uv_stride;
+ s->total_coeff_uv = av_malloc(total_coeff_uv_size);
+ if (!s->total_coeff_uv)
+ return AVERROR(ENOMEM);
+ memset(s->total_coeff_uv, 0, total_coeff_uv_size);
+
+ s->ref_frame_count = 0;
+ for (int i = 0; i < 3; i++) {
+ s->ref_frames[i] = av_frame_alloc();
+ if (!s->ref_frames[i])
+ return AVERROR(ENOMEM);
+ }
+ s->cur_frame = av_frame_alloc();
+ if (!s->cur_frame)
+ return AVERROR(ENOMEM);
+
+ s->version = VX_VERSION_INVALID;
+ s->quantizer = -1;
+ s->avi = 0;
+
+ // when the source is an avi file, the quantizer is stored in the extradata
+ if (avctx->extradata_size == 4)
+ if (!setup_qtables(avctx, AV_RL32(avctx->extradata)))
+ s->avi = 1;
+
+ ff_thread_once(&init_static_once, actimagine_init_static);
+
+ return 0;
+}
+
+static void clear_total_coeff(AVCodecContext *avctx, int x, int y, int w, int h)
+{
+ ActimagineContext *s = avctx->priv_data;
+
+ // luma
+ uint8_t *total_coeff = &s->total_coeff_y[
+ ((y >> 2) + 1) * s->total_coeff_y_stride + (x >> 2) + 1];
+
+ for (int y2 = 0; y2 < (h >> 2); y2++)
+ for (int x2 = 0; x2 < (w >> 2); x2++)
+ total_coeff[y2 * s->total_coeff_y_stride + x2] = 0;
+
+ // chroma
+ total_coeff = &s->total_coeff_uv[
+ ((y >> 3) + 1) * s->total_coeff_uv_stride + (x >> 3) + 1];
+
+ for (int y2 = 0; y2 < (h >> 3); y2++)
+ for (int x2 = 0; x2 < (w >> 3); x2++)
+ total_coeff[y2 * s->total_coeff_uv_stride + x2] = 0;
+}
+
+static void predict_plane_intern(AVCodecContext *avctx, int x, int y,
+ int w, int h, int plane)
+{
+ ActimagineContext *s = avctx->priv_data;
+ if (w == 1 && h == 1)
+ return;
+ if (w == 1 && h != 1) {
+ uint8_t top = PIXEL_CUR(s, plane, x, y - 1);
+ uint8_t bottom = PIXEL_CUR(s, plane, x, y + h - 1);
+ PIXEL_CUR(s, plane, x, y + (h >> 1) - 1) = (top + bottom) >> 1;
+ predict_plane_intern(avctx, x, y, 1, h >> 1, plane);
+ predict_plane_intern(avctx, x, y + (h >> 1), 1, h >> 1, plane);
+ } else if (w != 1 && h == 1) {
+ uint8_t left = PIXEL_CUR(s, plane, x - 1, y);
+ uint8_t right = PIXEL_CUR(s, plane, x + w - 1, y);
+ PIXEL_CUR(s, plane, x + (w >> 1) - 1, y) = (left + right) >> 1;
+ predict_plane_intern(avctx, x, y, w >> 1, 1, plane);
+ predict_plane_intern(avctx, x + (w >> 1), y, w >> 1, 1, plane);
+ } else {
+ uint8_t bottom_left = PIXEL_CUR(s, plane, x - 1, y + h - 1);
+ uint8_t top_right = PIXEL_CUR(s, plane, x + w - 1, y - 1);
+ uint8_t bottom_right = PIXEL_CUR(s, plane, x + w - 1, y + h - 1);
+ uint8_t bottom_center = (bottom_left + bottom_right) >> 1;
+ uint8_t center_right = (top_right + bottom_right) >> 1;
+ PIXEL_CUR(s, plane, x + (w >> 1) - 1, y + h - 1) = bottom_center;
+ PIXEL_CUR(s, plane, x + w - 1, y + (h >> 1) - 1) = center_right;
+ if ((w == 4 || w == 16) ^ (h == 4 || h == 16)) {
+ uint8_t center_left = PIXEL_CUR(s, plane, x - 1, y + (h >> 1) - 1);
+ PIXEL_CUR(s, plane, x + (w >> 1) - 1, y + (h >> 1) - 1)
+ = (center_left + center_right) >> 1;
+ } else {
+ uint8_t top_center = PIXEL_CUR(s, plane, x + (w >> 1) - 1, y - 1);
+ PIXEL_CUR(s, plane, x + (w >> 1) - 1, y + (h >> 1) - 1)
+ = (top_center + bottom_center) >> 1;
+ }
+ predict_plane_intern(avctx, x, y, w >> 1, h >> 1, plane);
+ predict_plane_intern(avctx, x + (w >> 1), y, w >> 1, h >> 1, plane);
+ predict_plane_intern(avctx, x, y + (h >> 1), w >> 1, h >> 1, plane);
+ predict_plane_intern(avctx, x + (w >> 1), y + (h >> 1), w >> 1, h >> 1,
+ plane);
+ }
+}
+
+static void predict_plane(AVCodecContext *avctx, int x, int y, int w, int h,
+ int plane, int param)
+{
+ ActimagineContext *s = avctx->priv_data;
+ uint8_t bottom_left = PIXEL_CUR(s, plane, x - 1, y + h - 1);
+ uint8_t top_right = PIXEL_CUR(s, plane, x + w - 1, y - 1);
+ PIXEL_CUR(s, plane, x + w - 1, y + h - 1)
+ = ((bottom_left + top_right + 1) >> 1) + param;
+ predict_plane_intern(avctx, x, y, w, h, plane);
+}
+
+static int predict_mb_plane(AVCodecContext *avctx, int x, int y, int w, int h)
+{
+ ActimagineContext *s = avctx->priv_data;
+ GetBitContext *gb = &s->gb;
+ // y
+ int param = get_se_golomb(gb);
+ if (param < -(1 << 16) || param >= (1 << 16)) {
+ av_log(avctx, AV_LOG_ERROR, "invalid plane param\n");
+ return AVERROR_INVALIDDATA;
+ }
+ predict_plane(avctx, x, y, w, h, 0, param << 1);
+
+ // u
+ param = get_se_golomb(gb);
+ if (param < -(1 << 16) || param >= (1 << 16)) {
+ av_log(avctx, AV_LOG_ERROR, "invalid plane param\n");
+ return AVERROR_INVALIDDATA;
+ }
+ predict_plane(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 1, param << 1);
+
+ // v
+ param = get_se_golomb(gb);
+ if (param < -(1 << 16) || param >= (1 << 16)) {
+ av_log(avctx, AV_LOG_ERROR, "invalid plane param\n");
+ return AVERROR_INVALIDDATA;
+ }
+ predict_plane(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 2, param << 1);
+
+ return 0;
+}
+
+static void predict_horizontal(AVCodecContext *avctx, int x, int y,
+ int w, int h, int plane)
+{
+ ActimagineContext *s = avctx->priv_data;
+ for (int y2 = 0; y2 < h; y2++) {
+ uint8_t pixel = PIXEL_CUR(s, plane, x - 1, y + y2);
+ for (int x2 = 0; x2 < w; x2++)
+ PIXEL_CUR(s, plane, x + x2, y + y2) = pixel;
+ }
+}
+
+static void predict_vertical(AVCodecContext *avctx, int x, int y,
+ int w, int h, int plane)
+{
+ ActimagineContext *s = avctx->priv_data;
+ for (int y2 = 0; y2 < h; y2++)
+ for (int x2 = 0; x2 < w; x2++)
+ PIXEL_CUR(s, plane, x + x2, y + y2)
+ = PIXEL_CUR(s, plane, x + x2, y - 1);
+}
+
+static void predict_dc(AVCodecContext *avctx, int x, int y, int w, int h,
+ int plane)
+{
+ uint8_t dc;
+ ActimagineContext *s = avctx->priv_data;
+ if (x != 0 && y != 0) {
+ int sum_h, sum_v;
+ sum_h = w >> 1;
+ for (int x2 = 0; x2 < w; x2++)
+ sum_h += PIXEL_CUR(s, plane, x + x2, y - 1);
+ sum_h >>= predict_dc_shift_tab[w >> 2];
+
+ sum_v = h >> 1;
+ for (int y2 = 0; y2 < h; y2++)
+ sum_v += PIXEL_CUR(s, plane, x - 1, y + y2);
+ sum_v >>= predict_dc_shift_tab[h >> 2];
+
+ dc = (sum_h + sum_v + 1) >> 1;
+ } else if (x == 0 && y != 0) {
+ int sum = w >> 1;
+ for (int x2 = 0; x2 < w; x2++)
+ sum += PIXEL_CUR(s, plane, x + x2, y - 1);
+ dc = sum >> predict_dc_shift_tab[w >> 2];
+ } else if (x != 0 && y == 0) {
+ int sum = h >> 1;
+ for (int y2 = 0; y2 < h; y2++)
+ sum += PIXEL_CUR(s, plane, x - 1, y + y2);
+ dc = sum >> predict_dc_shift_tab[h >> 2];
+ } else
+ dc = 128;
+
+ for (int y2 = 0; y2 < h; y2++)
+ for (int x2 = 0; x2 < w; x2++)
+ PIXEL_CUR(s, plane, x + x2, y + y2) = dc;
+}
+
+static int predict_notile_uv(AVCodecContext *avctx, int x, int y, int w, int h)
+{
+ ActimagineContext *s = avctx->priv_data;
+ GetBitContext *gb = &s->gb;
+ int mode_uv = get_ue_golomb_31(gb);
+ switch (mode_uv) {
+ case 0:// dc
+ predict_dc(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 1);
+ predict_dc(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 2);
+ break;
+ case 1:// horizontal
+ predict_horizontal(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 1);
+ predict_horizontal(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 2);
+ break;
+ case 2:// vertical
+ predict_vertical(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 1);
+ predict_vertical(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 2);
+ break;
+ case 3:// plane
+ predict_plane(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 1, 0);
+ predict_plane(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 2, 0);
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "invalid predict notile uv mode\n");
+ return AVERROR_INVALIDDATA;
+ }
+ return 0;
+}
+
+static int predict_notile(AVCodecContext *avctx, int x, int y, int w, int h)
+{
+ ActimagineContext *s = avctx->priv_data;
+ GetBitContext *gb = &s->gb;
+ int mode_y = get_ue_golomb_31(gb);
+ switch (mode_y) {
+ case 0:// vertical
+ predict_vertical(avctx, x, y, w, h, 0);
+ break;
+ case 1:// horizontal
+ predict_horizontal(avctx, x, y, w, h, 0);
+ break;
+ case 2:// dc
+ predict_dc(avctx, x, y, w, h, 0);
+ break;
+ case 3:// plane
+ predict_plane(avctx, x, y, w, h, 0, 0);
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "invalid predict notile y mode\n");
+ return AVERROR_INVALIDDATA;
+ }
+ return predict_notile_uv(avctx, x, y, w, h);
+}
+
+// slightly different from the common dc prediction method
+static void predict4_dc(AVCodecContext *avctx, int x, int y)
+{
+ uint8_t dc;
+ ActimagineContext *s = avctx->priv_data;
+ if (x == 0 && y == 0)
+ dc = 128;
+ else {
+ int sum = 0;
+ int shift = 1;
+
+ if (x != 0) {
+ shift++;
+ for (int y2 = 0; y2 < 4; y2++)
+ sum += PIXEL_CUR(s, 0, x - 1, y + y2);
+ sum += 2;
+ }
+
+ if (y != 0) {
+ shift++;
+ for (int x2 = 0; x2 < 4; x2++)
+ sum += PIXEL_CUR(s, 0, x + x2, y - 1);
+ sum += 2;
+ }
+
+ dc = sum >> shift;
+ }
+
+ for (int y2 = 0; y2 < 4; y2++)
+ for (int x2 = 0; x2 < 4; x2++)
+ PIXEL_CUR(s, 0, x + x2, y + y2) = dc;
+}
+
+static void predict4_diagonal_down_left(AVCodecContext *avctx, int x, int y)
+{
+ uint8_t val;
+ ActimagineContext *s = avctx->priv_data;
+
+ uint8_t a = PIXEL_CUR(s, 0, x + 0, y - 1);
+ uint8_t b = PIXEL_CUR(s, 0, x + 1, y - 1);
+ uint8_t c = PIXEL_CUR(s, 0, x + 2, y - 1);
+ uint8_t d = PIXEL_CUR(s, 0, x + 3, y - 1);
+ uint8_t e = PIXEL_CUR(s, 0, x + 4, y - 1);
+ uint8_t f = PIXEL_CUR(s, 0, x + 5, y - 1);
+ uint8_t g = PIXEL_CUR(s, 0, x + 6, y - 1);
+ uint8_t h = PIXEL_CUR(s, 0, x + 7, y - 1);
+
+ PIXEL_CUR(s, 0, x, y) = PREDICT3(a, b, c);
+
+ val = PREDICT3(b, c, d);
+ PIXEL_CUR(s, 0, x + 1, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 0, y + 1) = val;
+
+ val = PREDICT3(c, d, e);
+ PIXEL_CUR(s, 0, x + 2, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 1, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 0, y + 2) = val;
+
+ val = PREDICT3(d, e, f);
+ PIXEL_CUR(s, 0, x + 3, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 1, y + 2) = val;
+ PIXEL_CUR(s, 0, x + 0, y + 3) = val;
+
+ val = PREDICT3(e, f, g);
+ PIXEL_CUR(s, 0, x + 3, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 2) = val;
+ PIXEL_CUR(s, 0, x + 1, y + 3) = val;
+
+ val = PREDICT3(f, g, h);
+ PIXEL_CUR(s, 0, x + 3, y + 2) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 3) = val;
+
+ PIXEL_CUR(s, 0, x + 3, y + 3) = PREDICT3(g, h, h);
+}
+
+static void predict4_diagonal_down_right(AVCodecContext *avctx, int x, int y)
+{
+ uint8_t val;
+ ActimagineContext *s = avctx->priv_data;
+
+ uint8_t a = PIXEL_CUR(s, 0, x + 0, y - 1);
+ uint8_t b = PIXEL_CUR(s, 0, x + 1, y - 1);
+ uint8_t c = PIXEL_CUR(s, 0, x + 2, y - 1);
+ uint8_t d = PIXEL_CUR(s, 0, x + 3, y - 1);
+
+ uint8_t i = PIXEL_CUR(s, 0, x - 1, y + 0);
+ uint8_t j = PIXEL_CUR(s, 0, x - 1, y + 1);
+ uint8_t k = PIXEL_CUR(s, 0, x - 1, y + 2);
+ uint8_t l = PIXEL_CUR(s, 0, x - 1, y + 3);
+
+ uint8_t m = PIXEL_CUR(s, 0, x - 1, y - 1);
+
+ PIXEL_CUR(s, 0, x + 0, y + 3) = PREDICT3(j, k, l);
+
+ val = PREDICT3(i, j, k);
+ PIXEL_CUR(s, 0, x + 0, y + 2) = val;
+ PIXEL_CUR(s, 0, x + 1, y + 3) = val;
+
+ val = PREDICT3(m, i, j);
+ PIXEL_CUR(s, 0, x + 0, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 1, y + 2) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 3) = val;
+
+ val = PREDICT3(i, m, a);
+ PIXEL_CUR(s, 0, x + 0, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 1, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 2) = val;
+ PIXEL_CUR(s, 0, x + 3, y + 3) = val;
+
+ val = PREDICT3(m, a, b);
+ PIXEL_CUR(s, 0, x + 1, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 3, y + 2) = val;
+
+ val = PREDICT3(a, b, c);
+ PIXEL_CUR(s, 0, x + 2, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 3, y + 1) = val;
+
+ PIXEL_CUR(s, 0, x + 3, y + 0) = PREDICT3(b, c, d);
+}
+
+static void predict4_vertical_right(AVCodecContext *avctx, int x, int y)
+{
+ uint8_t val;
+ ActimagineContext *s = avctx->priv_data;
+
+ uint8_t a = PIXEL_CUR(s, 0, x + 0, y - 1);
+ uint8_t b = PIXEL_CUR(s, 0, x + 1, y - 1);
+ uint8_t c = PIXEL_CUR(s, 0, x + 2, y - 1);
+ uint8_t d = PIXEL_CUR(s, 0, x + 3, y - 1);
+
+ uint8_t i = PIXEL_CUR(s, 0, x - 1, y + 0);
+ uint8_t j = PIXEL_CUR(s, 0, x - 1, y + 1);
+ uint8_t k = PIXEL_CUR(s, 0, x - 1, y + 2);
+
+ uint8_t m = PIXEL_CUR(s, 0, x - 1, y - 1);
+
+ PIXEL_CUR(s, 0, x + 0, y + 3) = PREDICT3(i, j, k);
+ PIXEL_CUR(s, 0, x + 0, y + 2) = PREDICT3(m, i, j);
+
+ val = PREDICT3(a, m, i);
+ PIXEL_CUR(s, 0, x + 0, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 1, y + 3) = val;
+
+ val = PREDICT2(a, m);
+ PIXEL_CUR(s, 0, x + 0, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 1, y + 2) = val;
+
+ val = PREDICT3(b, a, m);
+ PIXEL_CUR(s, 0, x + 1, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 3) = val;
+
+ val = PREDICT2(b, a);
+ PIXEL_CUR(s, 0, x + 1, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 2) = val;
+
+ val = PREDICT3(c, b, a);
+ PIXEL_CUR(s, 0, x + 2, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 3, y + 3) = val;
+
+ val = PREDICT2(c, b);
+ PIXEL_CUR(s, 0, x + 2, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 3, y + 2) = val;
+
+ PIXEL_CUR(s, 0, x + 3, y + 1) = PREDICT3(d, c, b);
+ PIXEL_CUR(s, 0, x + 3, y + 0) = PREDICT2(d, c);
+}
+
+static void predict4_horizontal_down(AVCodecContext *avctx, int x, int y)
+{
+ uint8_t val;
+ ActimagineContext *s = avctx->priv_data;
+
+ uint8_t a = PIXEL_CUR(s, 0, x + 0, y - 1);
+ uint8_t b = PIXEL_CUR(s, 0, x + 1, y - 1);
+ uint8_t c = PIXEL_CUR(s, 0, x + 2, y - 1);
+
+ uint8_t i = PIXEL_CUR(s, 0, x - 1, y + 0);
+ uint8_t j = PIXEL_CUR(s, 0, x - 1, y + 1);
+ uint8_t k = PIXEL_CUR(s, 0, x - 1, y + 2);
+ uint8_t l = PIXEL_CUR(s, 0, x - 1, y + 3);
+
+ uint8_t m = PIXEL_CUR(s, 0, x - 1, y - 1);
+
+ PIXEL_CUR(s, 0, x + 0, y + 3) = PREDICT2(k, l);
+ PIXEL_CUR(s, 0, x + 1, y + 3) = PREDICT3(j, k, l);
+
+ val = PREDICT2(j, k);
+ PIXEL_CUR(s, 0, x + 0, y + 2) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 3) = val;
+
+ val = PREDICT3(i, j, k);
+ PIXEL_CUR(s, 0, x + 1, y + 2) = val;
+ PIXEL_CUR(s, 0, x + 3, y + 3) = val;
+
+ val = PREDICT2(i, j);
+ PIXEL_CUR(s, 0, x + 0, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 2) = val;
+
+ val = PREDICT3(m, i, j);
+ PIXEL_CUR(s, 0, x + 1, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 3, y + 2) = val;
+
+ val = PREDICT2(i, m);
+ PIXEL_CUR(s, 0, x + 0, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 1) = val;
+
+ val = PREDICT3(i, m, a);
+ PIXEL_CUR(s, 0, x + 1, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 3, y + 1) = val;
+
+ PIXEL_CUR(s, 0, x + 2, y + 0) = PREDICT3(m, a, b);
+ PIXEL_CUR(s, 0, x + 3, y + 0) = PREDICT3(a, b, c);
+}
+
+static void predict4_vertical_left(AVCodecContext *avctx, int x, int y)
+{
+ uint8_t val;
+ ActimagineContext *s = avctx->priv_data;
+
+ uint8_t a = PIXEL_CUR(s, 0, x + 0, y - 1);
+ uint8_t b = PIXEL_CUR(s, 0, x + 1, y - 1);
+ uint8_t c = PIXEL_CUR(s, 0, x + 2, y - 1);
+ uint8_t d = PIXEL_CUR(s, 0, x + 3, y - 1);
+ uint8_t e = PIXEL_CUR(s, 0, x + 4, y - 1);
+ uint8_t f = PIXEL_CUR(s, 0, x + 5, y - 1);
+ uint8_t g = PIXEL_CUR(s, 0, x + 6, y - 1);
+
+ PIXEL_CUR(s, 0, x + 3, y + 3) = PREDICT3(e, f, g);
+ PIXEL_CUR(s, 0, x + 3, y + 2) = PREDICT2(e, f);
+
+ val = PREDICT3(d, e, f);
+ PIXEL_CUR(s, 0, x + 3, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 3) = val;
+
+ val = PREDICT2(d, e);
+ PIXEL_CUR(s, 0, x + 3, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 2, y + 2) = val;
+
+ val = PREDICT3(c, d, e);
+ PIXEL_CUR(s, 0, x + 2, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 1, y + 3) = val;
+
+ val = PREDICT2(c, d);
+ PIXEL_CUR(s, 0, x + 2, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 1, y + 2) = val;
+
+ val = PREDICT3(b, c, d);
+ PIXEL_CUR(s, 0, x + 1, y + 1) = val;
+ PIXEL_CUR(s, 0, x + 0, y + 3) = val;
+
+ val = PREDICT2(b, c);
+ PIXEL_CUR(s, 0, x + 1, y + 0) = val;
+ PIXEL_CUR(s, 0, x + 0, y + 2) = val;
+
+ PIXEL_CUR(s, 0, x + 0, y + 1) = PREDICT3(a, b, c);
+ PIXEL_CUR(s, 0, x + 0, y + 0) = PREDICT2(a, b);
+}
+
+static void predict4_horizontal_up(AVCodecContext *avctx, int x, int y)
+{
+ ActimagineContext *s = avctx->priv_data;
+
+ uint8_t i = PIXEL_CUR(s, 0, x - 1, y + 0);
+ uint8_t j = PIXEL_CUR(s, 0, x - 1, y + 1);
+ uint8_t k = PIXEL_CUR(s, 0, x - 1, y + 2);
+ uint8_t l = PIXEL_CUR(s, 0, x - 1, y + 3);
+
+ PIXEL_CUR(s, 0, x + 0, y + 0) = PREDICT2(i, j);
+ PIXEL_CUR(s, 0, x + 1, y + 0) = PREDICT3(i, j, k);
+ PIXEL_CUR(s, 0, x + 2, y + 0) = PREDICT2(j, k);
+ PIXEL_CUR(s, 0, x + 3, y + 0) = PREDICT3(j, k, l);
+
+ PIXEL_CUR(s, 0, x + 0, y + 1) = PREDICT2(j, k);
+ PIXEL_CUR(s, 0, x + 1, y + 1) = PREDICT3(j, k, l);
+ PIXEL_CUR(s, 0, x + 2, y + 1) = PREDICT2(k, l);
+ PIXEL_CUR(s, 0, x + 3, y + 1) = PREDICT3(k, l, l);
+
+ PIXEL_CUR(s, 0, x + 0, y + 2) = PREDICT2(k, l);
+ PIXEL_CUR(s, 0, x + 1, y + 2) = PREDICT3(k, l, l);
+ PIXEL_CUR(s, 0, x + 2, y + 2) = l;
+ PIXEL_CUR(s, 0, x + 3, y + 2) = l;
+
+ PIXEL_CUR(s, 0, x + 0, y + 3) = l;
+ PIXEL_CUR(s, 0, x + 1, y + 3) = l;
+ PIXEL_CUR(s, 0, x + 2, y + 3) = l;
+ PIXEL_CUR(s, 0, x + 3, y + 3) = l;
+}
+
+static int predict4(AVCodecContext *avctx, int x, int y, int w, int h)
+{
+ ActimagineContext *s = avctx->priv_data;
+ GetBitContext *gb = &s->gb;
+ for (int y2 = 0; y2 < h >> 2; y2++) {
+ for (int x2 = 0; x2 < w >> 2; x2++) {
+ uint8_t mode = FFMIN(s->pred4_cache[1 + y2 - 1][1 + x2],
+ s->pred4_cache[1 + y2][1 + x2 - 1]);
+ if (mode == 9)// if invalid predict dc
+ mode = 2;
+
+ if (!get_bits1(gb)) {
+ uint8_t val = get_bits(gb, 3);
+ if (val >= mode)
+ val++;
+ mode = val;
+ }
+
+ s->pred4_cache[1 + y2][1 + x2] = mode;
+
+ switch (mode) {
+ case 0:// vertical
+ predict_vertical(avctx, x + x2 * 4, y + y2 * 4, 4, 4, 0);
+ break;
+ case 1:// horizontal
+ predict_horizontal(avctx, x + x2 * 4, y + y2 * 4, 4, 4, 0);
+ break;
+ case 2:// dc
+ predict4_dc(avctx, x + x2 * 4, y + y2 * 4);
+ break;
+ case 3:// diagonal-down-left
+ predict4_diagonal_down_left(avctx, x + x2 * 4, y + y2 * 4);
+ break;
+ case 4:// diagonal-down-right
+ predict4_diagonal_down_right(avctx, x + x2 * 4, y + y2 * 4);
+ break;
+ case 5:// vertical-right
+ predict4_vertical_right(avctx, x + x2 * 4, y + y2 * 4);
+ break;
+ case 6:// horizontal-down
+ predict4_horizontal_down(avctx, x + x2 * 4, y + y2 * 4);
+ break;
+ case 7:// vertical-left
+ predict4_vertical_left(avctx, x + x2 * 4, y + y2 * 4);
+ break;
+ case 8:// horizontal-up
+ predict4_horizontal_up(avctx, x + x2 * 4, y + y2 * 4);
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "invalid predict4 mode\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ }
+ return predict_notile_uv(avctx, x, y, w, h);
+}
+
+static void decode_dct(AVCodecContext *avctx, int x, int y, int plane,
+ const int* level)
+{
+ int a, b, c, d, e, f;
+ int dct[16];
+ int tmp[16];
+ ActimagineContext *s = avctx->priv_data;
+
+ // dezigzag
+ for (int i = 0; i < 16; i++)
+ dct[zigzag4x4_tab[i]] = level[i];
+
+ // dequantize
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 4; j++) {
+ dct[4 * j + i] *= s->qtab[i][j];
+ dct[4 * j + i + 2] *= s->qtab[i][j];
+ }
+ }
+
+ dct[0] += 32;// rounding
+
+ for (int i = 0; i < 4; i++) {
+ a = dct[i * 4 + 0];
+ b = dct[i * 4 + 1];
+ c = dct[i * 4 + 2];
+ d = dct[i * 4 + 3];
+ a += c;
+ c = a - c * 2;
+ e = (b >> 1) - d;
+ f = b + (d >> 1);
+ tmp[ 0 + i] = a + f;
+ tmp[ 4 + i] = c + e;
+ tmp[ 8 + i] = c - e;
+ tmp[12 + i] = a - f;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ a = tmp[i * 4 + 0];
+ b = tmp[i * 4 + 1];
+ c = tmp[i * 4 + 2];
+ d = tmp[i * 4 + 3];
+ a += c;
+ c = a - c * 2;
+ e = (b >> 1) - d;
+ f = b + (d >> 1);
+ PIXEL_CUR(s, plane, x + 0, y + i)
+ = av_clip_uint8(PIXEL_CUR(s, plane, x + 0, y + i) + ((a + f) >> 6));
+ PIXEL_CUR(s, plane, x + 1, y + i)
+ = av_clip_uint8(PIXEL_CUR(s, plane, x + 1, y + i) + ((c + e) >> 6));
+ PIXEL_CUR(s, plane, x + 2, y + i)
+ = av_clip_uint8(PIXEL_CUR(s, plane, x + 2, y + i) + ((c - e) >> 6));
+ PIXEL_CUR(s, plane, x + 3, y + i)
+ = av_clip_uint8(PIXEL_CUR(s, plane, x + 3, y + i) + ((a - f) >> 6));
+ }
+}
+
+static void decode_residu_cavlc(AVCodecContext *avctx, int x, int y, int plane,
+ int nc, uint8_t *out_total_coeff)
+{
+ int level[16];
+ int coeff_token, total_coeff, trailing_ones, i, zeros_left, suffix_length;
+ ActimagineContext *s = avctx->priv_data;
+ GetBitContext *gb = &s->gb;
+
+ coeff_token = get_vlc2(gb, coeff_token_vlc[coeff_token_table_index[nc]].table,
+ COEFF_TOKEN_VLC_BITS, 2);
+ trailing_ones = coeff_token & 3;
+ total_coeff = coeff_token >> 2;
+
+ *out_total_coeff = total_coeff;
+ if (total_coeff == 0)
+ return;
+
+ av_assert2(total_coeff <= 16);
+
+ i = 15;
+ if (total_coeff != 16) {
+ int trailing_zeros;
+ zeros_left = get_vlc2(gb, total_zeros_vlc[total_coeff].table,
+ TOTAL_ZEROS_VLC_BITS, 1);
+ trailing_zeros = 16 - (total_coeff + zeros_left);
+ while(trailing_zeros-- > 0)
+ level[i--] = 0;
+ } else
+ zeros_left = 0;
+
+ suffix_length = 0;
+ while (1) {
+ int level_suffix, level_code, run_before;
+ if (trailing_ones > 0) {
+ trailing_ones--;
+ level[i--] = get_bits1(gb) ? -1 : 1;
+ } else {
+ int level_prefix = 0;
+ while (!get_bits1(gb))
+ level_prefix++;
+
+ if (level_prefix == 15)
+ level_suffix = get_bits(gb, 11);
+ else
+ level_suffix = suffix_length == 0 ? 0 : get_bits(gb, suffix_length);
+
+ level_code = level_suffix + (level_prefix << suffix_length);
+
+ if (level_code > cavlc_suffix_len_update_tab[suffix_length])
+ suffix_length++;
+
+ level_code++;
+ if (get_bits1(gb))
+ level_code = -level_code;
+ level[i--] = level_code;
+ }
+
+ if (--total_coeff == 0)
+ break;
+
+ if (zeros_left == 0)
+ continue;
+
+ if(zeros_left < 7)
+ run_before = get_vlc2(gb, run_vlc[zeros_left].table, RUN_VLC_BITS, 1);
+ else
+ run_before = get_vlc2(gb, run7_vlc.table, RUN7_VLC_BITS, 2);
+ zeros_left -= run_before;
+ while(run_before-- > 0)
+ level[i--] = 0;
+ }
+
+ while(zeros_left-- > 0)
+ level[i--] = 0;
+
+ decode_dct(avctx, x, y, plane, level);
+}
+
+static int decode_residu_blocks(AVCodecContext *avctx, int x, int y,
+ int w, int h)
+{
+ ActimagineContext *s = avctx->priv_data;
+ GetBitContext *gb = &s->gb;
+ uint8_t *total_coeff_y = &s->total_coeff_y[
+ ((y >> 2) + 1) * s->total_coeff_y_stride + (x >> 2) + 1];
+ uint8_t *total_coeff_uv = &s->total_coeff_uv[
+ ((y >> 3) + 1) * s->total_coeff_uv_stride + (x >> 3) + 1];
+ for (int y2 = 0; y2 < h >> 3; y2++) {
+ for (int x2 = 0; x2 < w >> 3; x2++) {
+ uint8_t residu_mask;
+ int code = get_ue_golomb_31(gb);
+ if (code > 0x1F) {
+ av_log(avctx, AV_LOG_ERROR, "invalid residu mask code\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (s->version == VX_VERSION_OLD)
+ residu_mask = residu_mask_old_tab[code];
+ else
+ residu_mask = residu_mask_new_tab[code];
+
+ if (residu_mask & 1) {
+ int nc = (total_coeff_y[-1] +
+ total_coeff_y[-s->total_coeff_y_stride] + 1) >> 1;
+ decode_residu_cavlc(avctx, x + x2 * 8, y + y2 * 8, 0, nc,
+ &total_coeff_y[0]);
+ } else
+ total_coeff_y[0] = 0;
+
+ if (residu_mask & 2) {
+ int nc = (total_coeff_y[0] +
+ total_coeff_y[-s->total_coeff_y_stride + 1] + 1) >> 1;
+ decode_residu_cavlc(avctx, x + x2 * 8 + 4, y + y2 * 8, 0, nc,
+ &total_coeff_y[1]);
+ } else
+ total_coeff_y[1] = 0;
+
+ if (residu_mask & 4) {
+ int nc = (total_coeff_y[s->total_coeff_y_stride - 1] +
+ total_coeff_y[0] + 1) >> 1;
+ decode_residu_cavlc(avctx, x + x2 * 8, y + y2 * 8 + 4, 0, nc,
+ &total_coeff_y[s->total_coeff_y_stride]);
+ } else
+ total_coeff_y[s->total_coeff_y_stride] = 0;
+
+ if (residu_mask & 8) {
+ int nc = (total_coeff_y[s->total_coeff_y_stride] +
+ total_coeff_y[1] + 1) >> 1;
+ decode_residu_cavlc(
+ avctx, x + x2 * 8 + 4, y + y2 * 8 + 4, 0, nc,
+ &total_coeff_y[s->total_coeff_y_stride + 1]);
+ } else
+ total_coeff_y[s->total_coeff_y_stride + 1] = 0;
+
+ if (residu_mask & 16) {
+ uint8_t total_coeff_u, total_coeff_v;
+ int nc = (total_coeff_uv[-1] +
+ total_coeff_uv[-s->total_coeff_uv_stride] + 1) >> 1;
+ decode_residu_cavlc(avctx, (x + x2 * 8) >> 1, (y + y2 * 8) >> 1,
+ 1, nc, &total_coeff_u);
+ decode_residu_cavlc(avctx, (x + x2 * 8) >> 1, (y + y2 * 8) >> 1,
+ 2, nc, &total_coeff_v);
+ total_coeff_uv[0] = (total_coeff_u + total_coeff_v + 1) >> 1;
+ } else
+ total_coeff_uv[0] = 0;
+
+ total_coeff_y += 2;
+ total_coeff_uv++;
+ }
+ total_coeff_y += (s->total_coeff_y_stride << 1) - (w >> 2);
+ total_coeff_uv += s->total_coeff_uv_stride - (w >> 3);
+ }
+ return 0;
+}
+
+static int predict_inter(AVCodecContext *avctx, int x, int y, int w, int h,
+ const MVec *predVec, int has_delta, int ref_frame)
+{
+ ActimagineContext *s = avctx->priv_data;
+ GetBitContext *gb = &s->gb;
+ MVec vec = *predVec;
+
+ if (ref_frame >= s->ref_frame_count) {
+ av_log(avctx, AV_LOG_ERROR, "reference to unavailable frame\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ s->cur_frame->pict_type = AV_PICTURE_TYPE_P;
+ s->cur_frame->key_frame = 0;
+
+ if (has_delta) {
+ vec.x += (unsigned)get_se_golomb(gb);
+ vec.y += (unsigned)get_se_golomb(gb);
+ }
+
+ if (vec.x >= INT_MAX || vec.y >= INT_MAX)
+ return AVERROR_INVALIDDATA;
+
+ s->vectors[(1 + (y >> 4)) * s->vectors_stride + 1 + (x >> 4)] = vec;
+
+ if (x + vec.x < 0 || x + vec.x + w > avctx->width ||
+ y + vec.y < 0 || y + vec.y + h > avctx->height) {
+ av_log(avctx, AV_LOG_ERROR, "motion vector out of bounds\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ // luma
+ for (int y2 = 0; y2 < h; y2++)
+ for (int x2 = 0; x2 < w; x2++)
+ PIXEL_CUR(s, 0, x + x2, y + y2)
+ = PIXEL_REF(s, ref_frame, 0, x + x2 + vec.x, y + y2 + vec.y);
+
+ // chroma
+ for (int y2 = 0; y2 < (h >> 1); y2++) {
+ for (int x2 = 0; x2 < (w >> 1); x2++) {
+ // u
+ PIXEL_CUR(s, 1, (x >> 1) + x2, (y >> 1) + y2)
+ = PIXEL_REF(s, ref_frame, 1, (x >> 1) + x2 + (vec.x >> 1),
+ (y >> 1) + y2 + (vec.y >> 1));
+ // v
+ PIXEL_CUR(s, 2, (x >> 1) + x2, (y >> 1) + y2)
+ = PIXEL_REF(s, ref_frame, 2, (x >> 1) + x2 + (vec.x >> 1),
+ (y >> 1) + y2 + (vec.y >> 1));
+ }
+ }
+
+ return 0;
+}
+
+static int predict_inter_dc(AVCodecContext *avctx, int x, int y, int w, int h)
+{
+ int dx, dy, dc_y, dc_u, dc_v;
+ ActimagineContext *s = avctx->priv_data;
+ GetBitContext *gb = &s->gb;
+
+ if (s->ref_frame_count == 0) {
+ av_log(avctx, AV_LOG_ERROR, "reference to unavailable frame\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ dx = get_se_golomb(gb);
+ dy = get_se_golomb(gb);
+
+ if (x + dx < 0 || x + dx + w > avctx->width ||
+ y + dy < 0 || y + dy + h > avctx->height) {
+ av_log(avctx, AV_LOG_ERROR, "motion vector out of bounds\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ dc_y = get_se_golomb(gb);
+ if (dc_y < -(1<<16) || dc_y >= (1 << 16)) {
+ av_log(avctx, AV_LOG_ERROR, "invalid dc offset\n");
+ return AVERROR_INVALIDDATA;
+ }
+ dc_y <<= 1;
+
+ dc_u = get_se_golomb(gb);
+ if (dc_u < -(1<<16) || dc_u >= (1 << 16)) {
+ av_log(avctx, AV_LOG_ERROR, "invalid dc offset\n");
+ return AVERROR_INVALIDDATA;
+ }
+ dc_u <<= 1;
+
+ dc_v = get_se_golomb(gb);
+ if (dc_v < -(1<<16) || dc_v >= (1 << 16)) {
+ av_log(avctx, AV_LOG_ERROR, "invalid dc offset\n");
+ return AVERROR_INVALIDDATA;
+ }
+ dc_v <<= 1;
+
+ s->cur_frame->pict_type = AV_PICTURE_TYPE_P;
+ s->cur_frame->key_frame = 0;
+
+ // luma
+ for (int y2 = 0; y2 < h; y2++)
+ for (int x2 = 0; x2 < w; x2++)
+ PIXEL_CUR(s, 0, x + x2, y + y2) = av_clip_uint8(
+ PIXEL_REF(s, 0, 0, x + x2 + dx, y + y2 + dy) + dc_y);
+
+ // chroma
+ for (int y2 = 0; y2 < (h >> 1); y2++) {
+ for (int x2 = 0; x2 < (w >> 1); x2++) {
+ PIXEL_CUR(s, 1, (x >> 1) + x2, (y >> 1) + y2) = av_clip_uint8(
+ PIXEL_REF(s, 0, 1, (x >> 1) + x2 + (dx >> 1),
+ (y >> 1) + y2 + (dy >> 1)) + dc_u);
+ PIXEL_CUR(s, 2, (x >> 1) + x2, (y >> 1) + y2) = av_clip_uint8(
+ PIXEL_REF(s, 0, 2, (x >> 1) + x2 + (dx >> 1),
+ (y >> 1) + y2 + (dy >> 1)) + dc_v);
+ }
+ }
+
+ return 0;
+}
+
+static int decode_mb(AVCodecContext *avctx, int x, int y, int w, int h,
+ const MVec *predVec)
+{
+ ActimagineContext *s = avctx->priv_data;
+ GetBitContext *gb = &s->gb;
+ int ret = 0;
+
+ int mode = get_ue_golomb_31(gb);
+ if (s->version == VX_VERSION_OLD)
+ mode = old_mb_mode_remap_tab[mode];
+
+ switch (mode) {
+ case 0:// v-split, no residu
+ if (w == 2) {
+ av_log(avctx, AV_LOG_ERROR, "invalid macroblock mode\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if ((ret = decode_mb(avctx, x, y, w >> 1, h, predVec)) < 0)
+ return ret;
+ if ((ret = decode_mb(avctx, x + (w >> 1), y, w >> 1, h, predVec)) < 0)
+ return ret;
+ if (w == 8 && (h == 8 || h == 16))
+ clear_total_coeff(avctx, x, y, w, h);
+ break;
+ case 1:// no delta, no residu, ref 0
+ if ((ret = predict_inter(avctx, x, y, w, h, predVec, 0, 0)) < 0)
+ return ret;
+ if ((w == 8 || w == 16) && (h == 8 || h == 16))
+ clear_total_coeff(avctx, x, y, w, h);
+ break;
+ case 2:// h-split, no residu
+ if (h == 2) {
+ av_log(avctx, AV_LOG_ERROR, "invalid macroblock mode\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if ((ret = decode_mb(avctx, x, y, w, h >> 1, predVec)) < 0)
+ return ret;
+ if ((ret = decode_mb(avctx, x, y + (h >> 1), w, h >> 1, predVec)) < 0)
+ return ret;
+ if ((w == 8 || w == 16) && h == 8)
+ clear_total_coeff(avctx, x, y, w, h);
+ break;
+ case 3:// unpredicted delta ref0 + dc offset, no residu
+ if ((ret = predict_inter_dc(avctx, x, y, w, h)) < 0)
+ return ret;
+ if ((w == 8 || w == 16) && (h == 8 || h == 16))
+ clear_total_coeff(avctx, x, y, w, h);
+ break;
+ case 4:// delta, no residu, ref 0
+ case 5:// delta, no residu, ref 1
+ case 6:// delta, no residu, ref 2
+ if ((ret = predict_inter(avctx, x, y, w, h, predVec, 1, mode - 4)) < 0)
+ return ret;
+ if ((w == 8 || w == 16) && (h == 8 || h == 16))
+ clear_total_coeff(avctx, x, y, w, h);
+ break;
+ case 7:// plane, no residu
+ if ((ret = predict_mb_plane(avctx, x, y, w, h)) < 0)
+ return ret;
+ if ((w == 8 || w == 16) && (h == 8 || h == 16))
+ clear_total_coeff(avctx, x, y, w, h);
+ break;
+ case 8:// v-split, residu
+ if (w == 2) {
+ av_log(avctx, AV_LOG_ERROR, "invalid macroblock mode\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if ((ret = decode_mb(avctx, x, y, w >> 1, h, predVec)) < 0)
+ return ret;
+ if ((ret = decode_mb(avctx, x + (w >> 1), y, w >> 1, h, predVec)) < 0)
+ return ret;
+ if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
+ return ret;
+ break;
+ case 9:// no delta, no residu, ref 1
+ if ((ret = predict_inter(avctx, x, y, w, h, predVec, 0, 1)) < 0)
+ return ret;
+ if ((w == 8 || w == 16) && (h == 8 || h == 16))
+ clear_total_coeff(avctx, x, y, w, h);
+ break;
+ case 10:// unpredicted delta ref0 + dc offset, residu
+ if ((ret = predict_inter_dc(avctx, x, y, w, h)) < 0)
+ return ret;
+ if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
+ return ret;
+ break;
+ case 11:// predict notile, no residu
+ if ((ret = predict_notile(avctx, x, y, w, h)) < 0)
+ return ret;
+ if ((w == 8 || w == 16) && (h == 8 || h == 16))
+ clear_total_coeff(avctx, x, y, w, h);
+ break;
+ case 12:// no delta, residu, ref 0
+ if ((ret = predict_inter(avctx, x, y, w, h, predVec, 0, 0)) < 0)
+ return ret;
+ if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
+ return ret;
+ break;
+ case 13:// h-split, residu
+ if (h == 2) {
+ av_log(avctx, AV_LOG_ERROR, "invalid macroblock mode\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if ((ret = decode_mb(avctx, x, y, w, h >> 1, predVec)) < 0)
+ return ret;
+ if ((ret = decode_mb(avctx, x, y + (h >> 1), w, h >> 1, predVec)) < 0)
+ return ret;
+ if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
+ return ret;
+ break;
+ case 14:// no delta, no residu, ref 2
+ if ((ret = predict_inter(avctx, x, y, w, h, predVec, 0, 2)) < 0)
+ return ret;
+ if ((w == 8 || w == 16) && (h == 8 || h == 16))
+ clear_total_coeff(avctx, x, y, w, h);
+ break;
+ case 15:// predict4, no residu
+ if ((ret = predict4(avctx, x, y, w, h)) < 0)
+ return ret;
+ if ((w == 8 || w == 16) && (h == 8 || h == 16))
+ clear_total_coeff(avctx, x, y, w, h);
+ break;
+ case 16:// delta, residu, ref 0
+ case 17:// delta, residu, ref 1
+ case 18:// delta, residu, ref 2
+ if ((ret = predict_inter(avctx, x, y, w, h, predVec, 1, mode - 16)) < 0)
+ return ret;
+ if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
+ return ret;
+ break;
+ case 19:// predict4, residu
+ if ((ret = predict4(avctx, x, y, w, h)) < 0)
+ return ret;
+ if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
+ return ret;
+ break;
+ case 20:// no delta, residu, ref 1
+ case 21:// no delta, residu, ref 2
+ if ((ret = predict_inter(avctx, x, y, w, h, predVec, 0, mode - 20 + 1)) < 0)
+ return ret;
+ if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
+ return ret;
+ break;
+ case 22:// predict notile, residu
+ if ((ret = predict_notile(avctx, x, y, w, h)) < 0)
+ return ret;
+ if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
+ return ret;
+ break;
+ case 23:// plane, residu
+ if ((ret = predict_mb_plane(avctx, x, y, w, h)) < 0)
+ return ret;
+ if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
+ return ret;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "invalid macroblock mode\n");
+ return AVERROR_INVALIDDATA;
+ }
+ return 0;
+}
+
+static int detect_format(AVCodecContext *avctx)
+{
+ // assume the new format, if any incorrect decisions are made for the
+ // first macroblock of a keyframe (ref, non-dc prediction) then it must be
+ // the old format
+ ActimagineContext *s = avctx->priv_data;
+ GetBitContext *gb = &s->gb;
+ int w = 16;
+ int h = 16;
+ while (1) {
+ int mode = get_ue_golomb_31(gb);
+ if (mode == 0 || mode == 8) { // v-split
+ if (w == 2) // too many splits
+ return VX_VERSION_OLD;
+ w >>= 1;
+ continue;
+ } else if (mode == 2 || mode == 13) { // h-split
+ if (h == 2) // too many splits
+ return VX_VERSION_OLD;
+ h >>= 1;
+ continue;
+ } else if (mode == 11 || mode == 22) { // predict notile
+ if (get_ue_golomb_31(gb) != 2) // mode_y != dc
+ return VX_VERSION_OLD;
+ if (get_ue_golomb_31(gb) != 0) // mode_uv != dc
+ return VX_VERSION_OLD;
+ break; //we should have enough evidence now
+ } else if (mode == 15 || mode == 19) { // predict4
+ // initial prediction is always dc
+ // we don't expect that prediction to be wrong
+ if (!get_bits1(gb))
+ return VX_VERSION_OLD;
+ break; //we should have enough evidence now
+ } else // inter prediction, plane or any other value
+ return VX_VERSION_OLD;
+ }
+ return VX_VERSION_NEW;
+}
+
+static int actimagine_decode(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *pkt)
+{
+ MVec *vectors;
+ int ret;
+ ActimagineContext *s = avctx->priv_data;
+ GetBitContext *gb = &s->gb;
+ AVFrame *frame = s->cur_frame;
+
+ // in avi files the frames start with a 32 bit number that seems to
+ // indicate the total number of bits
+ int offset = s->avi ? 4 : 0;
+
+ av_fast_padded_malloc(&s->bitstream, &s->bitstream_size,
+ pkt->size);
+
+ if ((ret = ff_reget_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
+ s->bdsp.bswap16_buf((uint16_t *)s->bitstream, (uint16_t *)pkt->data,
+ (pkt->size + 1) >> 1);
+
+ ret = init_get_bits8(gb, s->bitstream + offset,
+ FFALIGN(pkt->size - offset, 2));
+ if (ret < 0)
+ return ret;
+
+ // determine the bitstream version if this was not done yet
+ if (s->version == VX_VERSION_INVALID) {
+ if (s->ref_frame_count != 0) {
+ av_log(avctx, AV_LOG_ERROR, "can't determine version on p frame\n");
+ return AVERROR_INVALIDDATA;
+ }
+ s->version = detect_format(avctx);
+
+ // reinit bitreader
+ ret = init_get_bits8(gb, s->bitstream + offset,
+ FFALIGN(pkt->size - offset, 2));
+ if (ret < 0)
+ return ret;
+ }
+
+ vectors = s->vectors + s->vectors_stride + 1;
+
+ frame->pict_type = AV_PICTURE_TYPE_I;
+ frame->key_frame = 1;
+
+ if (s->quantizer == -1) {
+ av_log(avctx, AV_LOG_ERROR, "no quantizer setup\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (int y = 0; y < avctx->height; y += 16) {
+ MVec *vec_cur = vectors;
+ for (int x = 0; x < avctx->width; x += 16) {
+ MVec predVec;
+ vec_cur[0].x = 0;
+ vec_cur[0].y = 0;
+ predVec.x = mid_pred(vec_cur[-1].x, vec_cur[-s->vectors_stride].x,
+ vec_cur[-s->vectors_stride + 1].x);
+ predVec.y = mid_pred(vec_cur[-1].y, vec_cur[-s->vectors_stride].y,
+ vec_cur[-s->vectors_stride + 1].y);
+ if ((ret = decode_mb(avctx, x, y, 16, 16, &predVec)) < 0)
+ return ret;
+ vec_cur++;
+ }
+ vectors += s->vectors_stride;
+ }
+
+ if (s->ref_frame_count == 3)
+ av_frame_unref(s->ref_frames[2]);
+
+ s->cur_frame = s->ref_frames[2];
+ s->ref_frames[2] = s->ref_frames[1];
+ s->ref_frames[1] = s->ref_frames[0];
+ s->ref_frames[0] = frame;
+
+ if (s->ref_frame_count < 3)
+ s->ref_frame_count++;
+
+ if ((ret = av_frame_ref(data, frame)) < 0)
+ return ret;
+ *got_frame = 1;
+
+ return 0;
+}
+
+static void actimagine_flush(AVCodecContext *avctx)
+{
+ ActimagineContext *s = avctx->priv_data;
+
+ for (int i = 0; i < 3; i++)
+ av_frame_unref(s->ref_frames[i]);
+
+ s->ref_frame_count = 0;
+}
+
+static av_cold int actimagine_close(AVCodecContext *avctx)
+{
+ ActimagineContext *s = avctx->priv_data;
+
+ av_freep(&s->vectors);
+ s->vectors_stride = 0;
+ av_freep(&s->total_coeff_y);
+ s->total_coeff_y_stride = 0;
+ av_freep(&s->total_coeff_uv);
+ s->total_coeff_uv_stride = 0;
+
+ av_freep(&s->bitstream);
+ s->bitstream_size = 0;
+
+ for (int i = 0; i < 3; i++)
+ av_frame_free(&s->ref_frames[i]);
+ av_frame_free(&s->cur_frame);
+
+ return 0;
+}
+
+AVCodec ff_actimagine_decoder = {
+ .name = "actimagine",
+ .long_name = NULL_IF_CONFIG_SMALL("Actimagine VX Video"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_ACTIMAGINE,
+ .priv_data_size = sizeof(ActimagineContext),
+ .init = actimagine_init,
+ .decode = actimagine_decode,
+ .flush = actimagine_flush,
+ .close = actimagine_close,
+ .capabilities = AV_CODEC_CAP_DR1,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
+};
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 2e9a3581de..10809f3492 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -32,6 +32,7 @@
extern AVCodec ff_a64multi_encoder;
extern AVCodec ff_a64multi5_encoder;
extern AVCodec ff_aasc_decoder;
+extern AVCodec ff_actimagine_decoder;
extern AVCodec ff_aic_decoder;
extern AVCodec ff_alias_pix_encoder;
extern AVCodec ff_alias_pix_decoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 17f8a14044..65d96c21af 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1856,6 +1856,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("Digital Pictures SGA Video"),
.props = AV_CODEC_PROP_LOSSY,
},
+ {
+ .id = AV_CODEC_ID_ACTIMAGINE,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "actimagine",
+ .long_name = NULL_IF_CONFIG_SMALL("Actimagine VX Video"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
/* various PCM "codecs" */
{
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index ab7bc68ee2..a4b3f3955d 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -307,6 +307,7 @@ enum AVCodecID {
AV_CODEC_ID_CRI,
AV_CODEC_ID_SIMBIOSIS_IMX,
AV_CODEC_ID_SGA_VIDEO,
+ AV_CODEC_ID_ACTIMAGINE,
/* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 4299ad4239..f992e1b36e 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,7 +28,7 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 58
-#define LIBAVCODEC_VERSION_MINOR 131
+#define LIBAVCODEC_VERSION_MINOR 132
#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
diff --git a/libavformat/riff.c b/libavformat/riff.c
index 270ff7c024..5d5cfe16b0 100644
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -496,6 +496,8 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_MVHA, MKTAG('M', 'V', 'H', 'A') },
{ AV_CODEC_ID_MV30, MKTAG('M', 'V', '3', '0') },
{ AV_CODEC_ID_NOTCHLC, MKTAG('n', 'l', 'c', '1') },
+ { AV_CODEC_ID_ACTIMAGINE, MKTAG('V', 'X', 'S', '1') },
+ { AV_CODEC_ID_ACTIMAGINE, MKTAG('v', 'x', 's', '1') },
{ AV_CODEC_ID_NONE, 0 }
};
--
2.18.0.windows.1
4
12
There is no reason to enforce a high minimum. In the context
of streaming only a few output buffers and capture buffers
are even needed for continuous playback. This also helps
alleviate memory pressure when decoding 4K media.
---
libavcodec/v4l2_m2m.h | 2 +-
libavcodec/v4l2_m2m_dec.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
index 61cb919771..feeb162812 100644
--- a/libavcodec/v4l2_m2m.h
+++ b/libavcodec/v4l2_m2m.h
@@ -38,7 +38,7 @@
#define V4L_M2M_DEFAULT_OPTS \
{ "num_output_buffers", "Number of buffers in the output context",\
- OFFSET(num_output_buffers), AV_OPT_TYPE_INT, { .i64 = 16 }, 6, INT_MAX, FLAGS }
+ OFFSET(num_output_buffers), AV_OPT_TYPE_INT, { .i64 = 16 }, 2, INT_MAX, FLAGS }
typedef struct V4L2m2mContext {
char devname[PATH_MAX];
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
index c6b865fde8..b9725be377 100644
--- a/libavcodec/v4l2_m2m_dec.c
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -262,7 +262,7 @@ static av_cold int v4l2_decode_close(AVCodecContext *avctx)
static const AVOption options[] = {
V4L_M2M_DEFAULT_OPTS,
{ "num_capture_buffers", "Number of buffers in the capture context",
- OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 20}, 20, INT_MAX, FLAGS },
+ OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 20}, 2, INT_MAX, FLAGS },
{ NULL},
};
--
2.24.1
3
2
[V2 01/10] libavfilter/vulkan: Fix problem when device have queue_count greater than 1
by Wenbin Chen 19 Nov '22
by Wenbin Chen 19 Nov '22
19 Nov '22
If the descriptorSetCount is greater than the number of setLayouts,
vkAllocateDescriptorSets will report error. Now fix it.
Now the following command can run on the device that has queue_count greater
than one:
ffmpeg -v verbose -init_hw_device vulkan=vul:0 -filter_hw_device vul
-i input1080p.264 -vf "hwupload=extra_hw_frames=16,scale_vulkan=1920:1080,
hwdownload,format=yuv420p" -f rawvideo output.yuv
Signed-off-by: Wenbin Chen <wenbin.chen(a)intel.com>
---
libavfilter/vulkan.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libavfilter/vulkan.c b/libavfilter/vulkan.c
index 337c8d7d5a..e5b070b3e6 100644
--- a/libavfilter/vulkan.c
+++ b/libavfilter/vulkan.c
@@ -1160,7 +1160,7 @@ void ff_vk_update_descriptor_set(AVFilterContext *avctx, VulkanPipeline *pl,
VulkanFilterContext *s = avctx->priv;
vkUpdateDescriptorSetWithTemplate(s->hwctx->act_dev,
- pl->desc_set[s->cur_queue_idx * pl->desc_layout_num + set_id],
+ pl->desc_set[set_id],
pl->desc_template[set_id],
s);
}
@@ -1179,7 +1179,7 @@ int ff_vk_init_pipeline_layout(AVFilterContext *avctx, VulkanPipeline *pl)
VkResult ret;
VulkanFilterContext *s = avctx->priv;
- pl->descriptor_sets_num = pl->desc_layout_num * s->queue_count;
+ pl->descriptor_sets_num = pl->desc_layout_num;
{ /* Init descriptor set pool */
VkDescriptorPoolCreateInfo pool_create_info = {
--
2.25.1
4
16
12 Sep '22
When compiling FFmpeg with GCC-9, some very random segfaults were
observed in code which had previously called down into the SBC encoder
NEON assembly routines. This was caused by these functions clobbering
some of the vfp callee saved registers (d8 - d15 aka q4 - q7). GCC was
using these registers to save local variables, but after these
functions returned, they would contain garbage.
Fix by saving the relevant registers on the stack in the affected
functions.
Signed-off-by: James Cowgill <jcowgill(a)debian.org>
---
libavcodec/arm/sbcdsp_neon.S | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/libavcodec/arm/sbcdsp_neon.S b/libavcodec/arm/sbcdsp_neon.S
index d83d21d202..aa03800096 100644
--- a/libavcodec/arm/sbcdsp_neon.S
+++ b/libavcodec/arm/sbcdsp_neon.S
@@ -38,6 +38,8 @@ function ff_sbc_analyze_4_neon, export=1
/* TODO: merge even and odd cases (or even merge all four calls to this
* function) in order to have only aligned reads from 'in' array
* and reduce number of load instructions */
+ vpush {d8-d11}
+
vld1.16 {d4, d5}, [r0, :64]!
vld1.16 {d8, d9}, [r2, :128]!
@@ -84,6 +86,7 @@ function ff_sbc_analyze_4_neon, export=1
vst1.32 {d0, d1}, [r1, :128]
+ vpop {d8-d11}
bx lr
endfunc
@@ -91,6 +94,8 @@ function ff_sbc_analyze_8_neon, export=1
/* TODO: merge even and odd cases (or even merge all four calls to this
* function) in order to have only aligned reads from 'in' array
* and reduce number of load instructions */
+ vpush {d8-d15}
+
vld1.16 {d4, d5}, [r0, :64]!
vld1.16 {d8, d9}, [r2, :128]!
@@ -188,6 +193,7 @@ function ff_sbc_analyze_8_neon, export=1
vst1.32 {d0, d1, d2, d3}, [r1, :128]
+ vpop {d8-d15}
bx lr
endfunc
--
2.22.0
3
3
06 Jul '22
Hello,
As part of GNU Jami development, I've picked up this patch and worked
to complete and validate it.
The few changes I've made are mostly to add checks to manage errors
and different cases, notably video vs audio containers. I have tested
the feature with opus stream encapsulated in mkv, opus, and RTP stream.
In the last case, packets can be dropped with the tc command.
Thanks a lot Steiner for your original work, it helped a lot.
Thanks for your time.
Philip-Dylan Gleonec (1):
avcodec/libopusdec: Enable FEC/PLC
libavcodec/libopusdec.c | 105 +++++++++++++++++++++++++++++++++++-----
1 file changed, 94 insertions(+), 11 deletions(-)
--
2.25.1
6
22