ffmpeg-devel
Threads by month
- ----- 2026 -----
- 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
May 2022
- 94 participants
- 282 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
[PATCH 1/2] avcodec/vc1_loopfilter: Factor duplicate code in vc1_b_h_intfi_loop_filter()
by Michael Niedermayer 18 May '24
by Michael Niedermayer 18 May '24
18 May '24
Fixes: CID1435168
Signed-off-by: Michael Niedermayer <michael(a)niedermayer.cc>
---
libavcodec/vc1_loopfilter.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/libavcodec/vc1_loopfilter.c b/libavcodec/vc1_loopfilter.c
index 0f990cccef..ee694ede28 100644
--- a/libavcodec/vc1_loopfilter.c
+++ b/libavcodec/vc1_loopfilter.c
@@ -1125,10 +1125,7 @@ static av_always_inline void vc1_b_h_intfi_loop_filter(VC1Context *v, uint8_t *d
dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8;
if (!(flags & RIGHT_EDGE) || !(block_num & 5)) {
- if (block_num > 3)
- v->vc1dsp.vc1_h_loop_filter8(dst + 8, linesize, pq);
- else
- v->vc1dsp.vc1_h_loop_filter8(dst + 8, linesize, pq);
+ v->vc1dsp.vc1_h_loop_filter8(dst + 8, linesize, pq);
}
tt = ttblk[0] >> (block_num * 4) & 0xf;
--
2.17.1
2
4
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
Signed-off-by: Paul B Mahol <onemda(a)gmail.com>
---
libavfilter/src_movie.c | 90 +++++++++++++++++++++++++----------------
1 file changed, 56 insertions(+), 34 deletions(-)
diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c
index 711854c23c..bc7b0d37af 100644
--- a/libavfilter/src_movie.c
+++ b/libavfilter/src_movie.c
@@ -46,6 +46,7 @@
#include "audio.h"
#include "avfilter.h"
+#include "filters.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
@@ -55,6 +56,7 @@ typedef struct MovieStream {
AVCodecContext *codec_ctx;
int64_t discontinuity_threshold;
int64_t last_pts;
+ int got_eof;
} MovieStream;
typedef struct MovieContext {
@@ -70,6 +72,8 @@ typedef struct MovieContext {
int64_t discontinuity_threshold;
int64_t ts_offset;
int dec_threads;
+ int got_eagain;
+ int got_wanted;
AVFormatContext *format_ctx;
@@ -100,7 +104,6 @@ static const AVOption movie_options[]= {
};
static int movie_config_output_props(AVFilterLink *outlink);
-static int movie_request_frame(AVFilterLink *outlink);
static AVStream *find_stream(void *log, AVFormatContext *avf, const char *spec)
{
@@ -314,7 +317,6 @@ static av_cold int movie_common_init(AVFilterContext *ctx)
if (!pad.name)
return AVERROR(ENOMEM);
pad.config_props = movie_config_output_props;
- pad.request_frame = movie_request_frame;
if ((ret = ff_append_outpad_free_name(ctx, &pad)) < 0)
return ret;
if ( movie->st[i].st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
@@ -554,47 +556,67 @@ static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
return 0;
}
-static int movie_request_frame(AVFilterLink *outlink)
+static int activate(AVFilterContext *ctx)
{
- AVFilterContext *ctx = outlink->src;
MovieContext *movie = ctx->priv;
- unsigned out_id = FF_OUTLINK_IDX(outlink);
+ int ret = 0;
+
+ /* check all decoders for available output */
+ for (int i = 0; i < ctx->nb_outputs; i++) {
+ if (movie->st[i].got_eof)
+ continue;
+
+ if (ff_outlink_frame_wanted(ctx->outputs[i]))
+ movie->got_wanted++;
- while (1) {
- int got_eagain = 0, got_eof = 0;
- int ret = 0;
+ ret = movie_push_frame(ctx, i);
+ if (ret == AVERROR(EAGAIN))
+ movie->got_eagain++;
+ else if (ret == AVERROR_EOF)
+ movie->st[i].got_eof = 1;
+ else if (ret < 0)
+ return ret;
+ }
+
+ if (movie->got_eagain || movie->got_wanted) {
+ /* all decoders require more input -> read a new packet */
+ movie->got_eagain = 0;
+ movie->got_wanted = 0;
+ ret = movie_decode_packet(ctx);
+ if (ret < 0 && ret != AVERROR(EAGAIN))
+ return ret;
+ ff_filter_set_ready(ctx, 100);
+ return 0;
+ } else {
+ int nb_eofs = 0;
- /* check all decoders for available output */
for (int i = 0; i < ctx->nb_outputs; i++) {
- ret = movie_push_frame(ctx, i);
- if (ret == AVERROR(EAGAIN))
- got_eagain++;
- else if (ret == AVERROR_EOF)
- got_eof++;
- else if (ret < 0)
- return ret;
- else if (i == out_id)
- return 0;
+ if (movie->st[i].got_eof) {
+ if (movie->loop_count == 1)
+ ff_outlink_set_status(ctx->outputs[i], AVERROR_EOF, movie->st[i].last_pts);
+ nb_eofs++;
+ }
+ }
+
+ if (nb_eofs != ctx->nb_outputs) {
+ ff_filter_set_ready(ctx, 100);
+ return 0;
}
- if (got_eagain) {
- /* all decoders require more input -> read a new packet */
- ret = movie_decode_packet(ctx);
+ if (movie->loop_count != 1) {
+ ret = rewind_file(ctx);
if (ret < 0)
return ret;
- } else if (got_eof) {
- /* all decoders flushed */
- if (movie->loop_count != 1) {
- ret = rewind_file(ctx);
- if (ret < 0)
- return ret;
- movie->loop_count -= movie->loop_count > 1;
- av_log(ctx, AV_LOG_VERBOSE, "Stream finished, looping.\n");
- continue;
- }
- return AVERROR_EOF;
+ movie->loop_count -= movie->loop_count > 1;
+ av_log(ctx, AV_LOG_VERBOSE, "Stream finished, looping.\n");
+ for (int i = 0; i < ctx->nb_outputs; i++)
+ movie->st[i].got_eof = 0;
+ ff_filter_set_ready(ctx, 100);
}
+ return 0;
}
+
+ return FFERROR_NOT_READY;
}
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
@@ -651,7 +673,7 @@ const AVFilter ff_avsrc_movie = {
.init = movie_common_init,
.uninit = movie_uninit,
FILTER_QUERY_FUNC(movie_query_formats),
-
+ .activate = activate,
.inputs = NULL,
.outputs = NULL,
.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
@@ -670,7 +692,7 @@ const AVFilter ff_avsrc_amovie = {
.init = movie_common_init,
.uninit = movie_uninit,
FILTER_QUERY_FUNC(movie_query_formats),
-
+ .activate = activate,
.inputs = NULL,
.outputs = NULL,
.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
--
2.35.1
2
6
This script generates the current general assembly voters according to
the criteria of '20 commits in the last 36 months'.
Signed-off-by: J. Dekker <jdek(a)itanimul.li>
---
doc/dev_community/community.md | 3 +++
tools/general_assembly.pl | 40 ++++++++++++++++++++++++++++++++++
2 files changed, 43 insertions(+)
create mode 100644 tools/general_assembly.pl
diff --git a/doc/dev_community/community.md b/doc/dev_community/community.md
index 21e08e20e3..516ca5c05e 100644
--- a/doc/dev_community/community.md
+++ b/doc/dev_community/community.md
@@ -25,6 +25,9 @@ proposal by a member of the General Assembly.
They are part of the GA for two years, after which they need a confirmation by
the GA.
+A script to generate the current members of the general assembly (minus members
+voted in) can be found in `tools/general_assembly.pl`.
+
## Voting
Voting is done using a ranked voting system, currently running on https://vote.ffmpeg.org/ .
diff --git a/tools/general_assembly.pl b/tools/general_assembly.pl
new file mode 100644
index 0000000000..898a6262ef
--- /dev/null
+++ b/tools/general_assembly.pl
@@ -0,0 +1,40 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use POSIX qw(strftime);
+use Encode qw(decode);
+use Data::Dumper;
+
+sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s };
+
+my @shortlog = split /\n/, decode('UTF-8', `git log --pretty=format:"%aN <%aE>" --since="last 36 months" | sort | uniq -c | sort -r`, Encode::FB_CROAK);
+my %assembly = ();
+
+foreach my $line (@shortlog) {
+ my ($count, $name, $email) = $line =~ m/^ *(\d+) *(.*?) <(.*?)>/;
+ if ($count < 20) {
+ next;
+ }
+
+ $name = trim $name;
+ if ($count < 50) {
+ my $true = 0;
+ my @commits = split /(^|\n)commit [a-z0-9]{40}(\n|$)/, decode('UTF-8', `git log --name-only --use-mailmap --author="$email" --since="last 36 months"`, Encode::FB_CROAK);
+ foreach my $commit (@commits) {
+ $true++; # if ($commit =~ /\n[\w\/]+\.(c|h|S|asm|texi)/);
+ }
+
+ if ($true < 20) {
+ next;
+ }
+ }
+
+ $assembly{$name} = $email;
+}
+
+printf("# %s %s", strftime("%Y-%m-%d", localtime), decode('UTF-8', `git rev-parse HEAD`, Encode::FB_CROAK));
+foreach my $email (sort values %assembly) {
+ printf("%s\n", $email);
+}
--
2.32.0 (Apple Git-132)
4
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