2012-10-21 14:05:46 +02:00
|
|
|
/*
|
|
|
|
|
* FFV1 decoder
|
|
|
|
|
*
|
2013-08-17 01:41:31 +02:00
|
|
|
* Copyright (c) 2003-2013 Michael Niedermayer <michaelni@gmx.at>
|
2012-10-21 14:05:46 +02:00
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @file
|
|
|
|
|
* FF Video Codec 1 (a lossless codec) decoder
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "libavutil/avassert.h"
|
|
|
|
|
#include "libavutil/crc.h"
|
2024-03-25 01:30:37 +01:00
|
|
|
#include "libavutil/mem.h"
|
2012-10-21 14:05:46 +02:00
|
|
|
#include "libavutil/imgutils.h"
|
|
|
|
|
#include "libavutil/pixdesc.h"
|
|
|
|
|
#include "avcodec.h"
|
2022-03-16 18:18:28 +01:00
|
|
|
#include "codec_internal.h"
|
2012-10-21 14:05:46 +02:00
|
|
|
#include "get_bits.h"
|
|
|
|
|
#include "rangecoder.h"
|
|
|
|
|
#include "golomb.h"
|
|
|
|
|
#include "mathops.h"
|
|
|
|
|
#include "ffv1.h"
|
2022-09-02 21:51:35 +02:00
|
|
|
#include "progressframe.h"
|
2024-10-15 22:37:56 +02:00
|
|
|
#include "libavutil/refstruct.h"
|
2022-02-06 14:49:23 +01:00
|
|
|
#include "thread.h"
|
2025-01-05 13:42:47 +09:00
|
|
|
#include "decode.h"
|
2025-01-05 15:27:30 +09:00
|
|
|
#include "hwconfig.h"
|
|
|
|
|
#include "hwaccel_internal.h"
|
|
|
|
|
#include "config_components.h"
|
2012-10-21 14:05:46 +02:00
|
|
|
|
|
|
|
|
static inline int get_vlc_symbol(GetBitContext *gb, VlcState *const state,
|
|
|
|
|
int bits)
|
|
|
|
|
{
|
|
|
|
|
int k, i, v, ret;
|
|
|
|
|
|
|
|
|
|
i = state->count;
|
|
|
|
|
k = 0;
|
|
|
|
|
while (i < state->error_sum) { // FIXME: optimize
|
|
|
|
|
k++;
|
|
|
|
|
i += i;
|
|
|
|
|
}
|
2025-07-16 00:01:07 +02:00
|
|
|
if (k > bits) {
|
|
|
|
|
ff_dlog(NULL, "k-overflow bias:%d error:%d drift:%d count:%d k:%d",
|
|
|
|
|
state->bias, state->error_sum, state->drift, state->count, k);
|
|
|
|
|
k = bits;
|
|
|
|
|
}
|
2012-10-21 14:05:46 +02:00
|
|
|
|
|
|
|
|
v = get_sr_golomb(gb, k, 12, bits);
|
2015-03-16 08:57:36 +00:00
|
|
|
ff_dlog(NULL, "v:%d bias:%d error:%d drift:%d count:%d k:%d",
|
2012-10-21 14:05:46 +02:00
|
|
|
v, state->bias, state->error_sum, state->drift, state->count, k);
|
|
|
|
|
|
|
|
|
|
v ^= ((2 * state->drift + state->count) >> 31);
|
|
|
|
|
|
|
|
|
|
ret = fold(v + state->bias, bits);
|
|
|
|
|
|
|
|
|
|
update_vlc_state(state, v);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-08 13:11:52 +02:00
|
|
|
static int is_input_end(RangeCoder *c, GetBitContext *gb, int ac)
|
2017-08-14 00:15:55 +02:00
|
|
|
{
|
2024-07-08 13:11:52 +02:00
|
|
|
if (ac != AC_GOLOMB_RICE) {
|
2017-08-14 00:15:55 +02:00
|
|
|
if (c->overread > MAX_OVERREAD)
|
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
} else {
|
2024-07-08 10:09:22 +02:00
|
|
|
if (get_bits_left(gb) < 1)
|
2017-08-14 00:15:55 +02:00
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-07 23:37:17 +02:00
|
|
|
#define TYPE int16_t
|
|
|
|
|
#define RENAME(name) name
|
|
|
|
|
#include "ffv1dec_template.c"
|
|
|
|
|
#undef TYPE
|
|
|
|
|
#undef RENAME
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2016-08-08 00:00:46 +02:00
|
|
|
#define TYPE int32_t
|
|
|
|
|
#define RENAME(name) name ## 32
|
|
|
|
|
#include "ffv1dec_template.c"
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2024-07-10 17:25:54 +02:00
|
|
|
static int decode_plane(FFV1Context *f, FFV1SliceContext *sc,
|
2024-07-08 10:09:22 +02:00
|
|
|
GetBitContext *gb,
|
2024-07-07 19:46:20 +02:00
|
|
|
uint8_t *src, int w, int h, int stride, int plane_index,
|
2025-03-10 00:18:41 +01:00
|
|
|
int remap_index, int pixel_stride, int ac)
|
2012-10-21 14:05:46 +02:00
|
|
|
{
|
|
|
|
|
int x, y;
|
|
|
|
|
int16_t *sample[2];
|
2025-04-02 19:39:10 +02:00
|
|
|
int bits;
|
|
|
|
|
unsigned mask;
|
|
|
|
|
|
|
|
|
|
if (sc->remap) {
|
|
|
|
|
bits = av_ceil_log2(sc->remap_count[remap_index]);
|
|
|
|
|
mask = (1<<bits)-1;
|
|
|
|
|
} else {
|
|
|
|
|
bits = f->avctx->bits_per_raw_sample;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-07 19:46:20 +02:00
|
|
|
sample[0] = sc->sample_buffer + 3;
|
|
|
|
|
sample[1] = sc->sample_buffer + w + 6 + 3;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2024-07-07 19:46:20 +02:00
|
|
|
sc->run_index = 0;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2024-07-07 19:46:20 +02:00
|
|
|
memset(sc->sample_buffer, 0, 2 * (w + 6) * sizeof(*sc->sample_buffer));
|
2012-10-21 14:05:46 +02:00
|
|
|
|
|
|
|
|
for (y = 0; y < h; y++) {
|
|
|
|
|
int16_t *temp = sample[0]; // FIXME: try a normal buffer
|
|
|
|
|
|
|
|
|
|
sample[0] = sample[1];
|
|
|
|
|
sample[1] = temp;
|
|
|
|
|
|
|
|
|
|
sample[1][-1] = sample[0][0];
|
|
|
|
|
sample[0][w] = sample[0][w - 1];
|
|
|
|
|
|
2024-07-10 17:25:54 +02:00
|
|
|
if (f->avctx->bits_per_raw_sample <= 8) {
|
|
|
|
|
int ret = decode_line(f, sc, gb, w, sample, plane_index, 8, ac);
|
2017-08-14 00:15:55 +02:00
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
2025-03-10 00:18:41 +01:00
|
|
|
if (sc->remap)
|
|
|
|
|
for (x = 0; x < w; x++)
|
|
|
|
|
sample[1][x] = sc->fltmap[remap_index][sample[1][x]];
|
2012-10-21 14:05:46 +02:00
|
|
|
for (x = 0; x < w; x++)
|
2016-01-01 01:16:34 +01:00
|
|
|
src[x*pixel_stride + stride * y] = sample[1][x];
|
2012-10-21 14:05:46 +02:00
|
|
|
} else {
|
2025-04-02 19:39:10 +02:00
|
|
|
int ret = decode_line(f, sc, gb, w, sample, plane_index, bits, ac);
|
2017-08-14 00:15:55 +02:00
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
2025-03-15 00:49:30 +01:00
|
|
|
|
|
|
|
|
if (sc->remap) {
|
|
|
|
|
if (f->packed_at_lsb || f->avctx->bits_per_raw_sample == 16) {
|
|
|
|
|
for (x = 0; x < w; x++) {
|
2025-04-02 19:39:10 +02:00
|
|
|
((uint16_t*)(src + stride*y))[x*pixel_stride] = sc->fltmap[remap_index][sample[1][x] & mask];
|
2025-03-15 00:49:30 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for (x = 0; x < w; x++) {
|
2025-04-02 19:39:10 +02:00
|
|
|
int v = sc->fltmap[remap_index][sample[1][x] & mask];
|
2025-03-15 00:49:30 +01:00
|
|
|
((uint16_t*)(src + stride*y))[x*pixel_stride] = v << (16 - f->avctx->bits_per_raw_sample) | v >> (2 * f->avctx->bits_per_raw_sample - 16);
|
|
|
|
|
}
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2025-03-15 00:49:30 +01:00
|
|
|
if (f->packed_at_lsb || f->avctx->bits_per_raw_sample == 16) {
|
|
|
|
|
for (x = 0; x < w; x++) {
|
|
|
|
|
((uint16_t*)(src + stride*y))[x*pixel_stride] = sample[1][x];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for (x = 0; x < w; x++) {
|
|
|
|
|
((uint16_t*)(src + stride*y))[x*pixel_stride] = sample[1][x] << (16 - f->avctx->bits_per_raw_sample) | ((uint16_t **)sample)[1][x] >> (2 * f->avctx->bits_per_raw_sample - 16);
|
|
|
|
|
}
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-14 00:15:55 +02:00
|
|
|
return 0;
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-10 17:25:54 +02:00
|
|
|
static int decode_slice_header(const FFV1Context *f,
|
2024-07-04 10:22:53 +02:00
|
|
|
FFV1SliceContext *sc, AVFrame *frame)
|
2012-10-21 14:05:46 +02:00
|
|
|
{
|
2024-07-09 08:45:16 +02:00
|
|
|
RangeCoder *c = &sc->c;
|
2012-10-21 14:05:46 +02:00
|
|
|
uint8_t state[CONTEXT_SIZE];
|
2024-07-03 13:24:23 +02:00
|
|
|
unsigned ps, context_count;
|
2022-11-22 23:34:22 +01:00
|
|
|
int sx, sy, sw, sh;
|
|
|
|
|
|
2012-10-21 14:05:46 +02:00
|
|
|
memset(state, 128, sizeof(state));
|
2025-02-02 22:55:45 -03:00
|
|
|
sx = ff_ffv1_get_symbol(c, state, 0);
|
|
|
|
|
sy = ff_ffv1_get_symbol(c, state, 0);
|
|
|
|
|
sw = ff_ffv1_get_symbol(c, state, 0) + 1U;
|
|
|
|
|
sh = ff_ffv1_get_symbol(c, state, 0) + 1U;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
|
|
|
|
av_assert0(f->version > 2);
|
|
|
|
|
|
2022-11-22 23:34:22 +01:00
|
|
|
|
|
|
|
|
if (sx < 0 || sy < 0 || sw <= 0 || sh <= 0)
|
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
if (sx > f->num_h_slices - sw || sy > f->num_v_slices - sh)
|
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
|
2024-10-01 22:08:08 +02:00
|
|
|
sc->slice_x = ff_slice_coord(f, f->width , sx , f->num_h_slices, f->chroma_h_shift);
|
|
|
|
|
sc->slice_y = ff_slice_coord(f, f->height, sy , f->num_v_slices, f->chroma_v_shift);
|
|
|
|
|
sc->slice_width = ff_slice_coord(f, f->width , sx + sw, f->num_h_slices, f->chroma_h_shift) - sc->slice_x;
|
|
|
|
|
sc->slice_height = ff_slice_coord(f, f->height, sy + sh, f->num_v_slices, f->chroma_v_shift) - sc->slice_y;
|
2022-11-22 23:34:22 +01:00
|
|
|
|
2024-07-04 10:22:53 +02:00
|
|
|
av_assert0((unsigned)sc->slice_width <= f->width &&
|
|
|
|
|
(unsigned)sc->slice_height <= f->height);
|
|
|
|
|
av_assert0 ( (unsigned)sc->slice_x + (uint64_t)sc->slice_width <= f->width
|
|
|
|
|
&& (unsigned)sc->slice_y + (uint64_t)sc->slice_height <= f->height);
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2024-07-08 13:11:52 +02:00
|
|
|
if (f->ac == AC_GOLOMB_RICE && sc->slice_width >= (1<<23))
|
2022-07-03 13:31:19 +02:00
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
|
2024-07-03 13:24:23 +02:00
|
|
|
for (unsigned i = 0; i < f->plane_count; i++) {
|
2024-07-08 18:01:13 +02:00
|
|
|
PlaneContext * const p = &sc->plane[i];
|
2025-02-02 22:55:45 -03:00
|
|
|
int idx = ff_ffv1_get_symbol(c, state, 0);
|
2015-09-26 13:20:59 +02:00
|
|
|
if (idx >= (unsigned)f->quant_table_count) {
|
2012-10-21 14:05:46 +02:00
|
|
|
av_log(f->avctx, AV_LOG_ERROR, "quant_table_index out of range\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
p->quant_table_index = idx;
|
|
|
|
|
context_count = f->context_count[idx];
|
|
|
|
|
|
|
|
|
|
if (p->context_count < context_count) {
|
|
|
|
|
av_freep(&p->state);
|
|
|
|
|
av_freep(&p->vlc_state);
|
|
|
|
|
}
|
|
|
|
|
p->context_count = context_count;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-02 22:55:45 -03:00
|
|
|
ps = ff_ffv1_get_symbol(c, state, 0);
|
2012-10-21 14:05:46 +02:00
|
|
|
if (ps == 1) {
|
2024-07-03 14:36:02 +02:00
|
|
|
frame->flags |= AV_FRAME_FLAG_INTERLACED;
|
|
|
|
|
frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
|
2012-10-21 14:05:46 +02:00
|
|
|
} else if (ps == 2) {
|
2024-07-03 14:36:02 +02:00
|
|
|
frame->flags |= AV_FRAME_FLAG_INTERLACED;
|
|
|
|
|
frame->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST;
|
2012-10-21 14:05:46 +02:00
|
|
|
} else if (ps == 3) {
|
2024-07-03 14:36:02 +02:00
|
|
|
frame->flags &= ~AV_FRAME_FLAG_INTERLACED;
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
2025-02-02 22:55:45 -03:00
|
|
|
frame->sample_aspect_ratio.num = ff_ffv1_get_symbol(c, state, 0);
|
|
|
|
|
frame->sample_aspect_ratio.den = ff_ffv1_get_symbol(c, state, 0);
|
2012-10-19 12:14:22 +02:00
|
|
|
|
2014-04-28 16:08:33 -04:00
|
|
|
if (av_image_check_sar(f->width, f->height,
|
2024-07-03 14:36:02 +02:00
|
|
|
frame->sample_aspect_ratio) < 0) {
|
2014-04-28 16:08:33 -04:00
|
|
|
av_log(f->avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n",
|
2024-07-03 14:36:02 +02:00
|
|
|
frame->sample_aspect_ratio.num,
|
|
|
|
|
frame->sample_aspect_ratio.den);
|
|
|
|
|
frame->sample_aspect_ratio = (AVRational){ 0, 1 };
|
2014-04-28 16:08:33 -04:00
|
|
|
}
|
|
|
|
|
|
2024-07-10 17:25:54 +02:00
|
|
|
if (f->version > 3) {
|
2024-07-10 17:38:24 +02:00
|
|
|
sc->slice_reset_contexts = get_rac(c, state);
|
2025-02-02 22:55:45 -03:00
|
|
|
sc->slice_coding_mode = ff_ffv1_get_symbol(c, state, 0);
|
2024-10-03 01:49:09 +02:00
|
|
|
if (sc->slice_coding_mode != 1 && f->colorspace == 1) {
|
2025-02-02 22:55:45 -03:00
|
|
|
sc->slice_rct_by_coef = ff_ffv1_get_symbol(c, state, 0);
|
|
|
|
|
sc->slice_rct_ry_coef = ff_ffv1_get_symbol(c, state, 0);
|
2024-07-08 16:11:25 +02:00
|
|
|
if ((uint64_t)sc->slice_rct_by_coef + (uint64_t)sc->slice_rct_ry_coef > 4) {
|
2013-12-08 22:09:50 +01:00
|
|
|
av_log(f->avctx, AV_LOG_ERROR, "slice_rct_y_coef out of range\n");
|
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-18 21:51:27 +01:00
|
|
|
if (f->combined_version >= 0x40004) {
|
|
|
|
|
sc->remap = ff_ffv1_get_symbol(c, state, 0);
|
2025-03-11 15:00:01 +01:00
|
|
|
if (sc->remap > 2U ||
|
|
|
|
|
sc->remap && !f->flt) {
|
2025-01-18 21:51:27 +01:00
|
|
|
av_log(f->avctx, AV_LOG_ERROR, "unsupported remap %d\n", sc->remap);
|
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-09-09 19:56:44 +02:00
|
|
|
}
|
2025-03-19 01:30:47 +01:00
|
|
|
if (f->avctx->bits_per_raw_sample == 32) {
|
|
|
|
|
if (!sc->remap) {
|
|
|
|
|
av_log(f->avctx, AV_LOG_ERROR, "unsupported remap\n");
|
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-06-20 22:20:28 +02:00
|
|
|
|
2012-10-21 14:05:46 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-16 18:21:29 +02:00
|
|
|
static void slice_set_damaged(FFV1Context *f, FFV1SliceContext *sc)
|
|
|
|
|
{
|
|
|
|
|
sc->slice_damaged = 1;
|
|
|
|
|
|
|
|
|
|
// only set this for frame threading, as for slice threading its value is
|
|
|
|
|
// not used and setting it would be a race
|
|
|
|
|
if (f->avctx->active_thread_type & FF_THREAD_FRAME)
|
|
|
|
|
f->frame_damaged = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-20 22:51:01 +01:00
|
|
|
static int decode_current_mul(RangeCoder *rc, uint8_t state[32], int *mul, int mul_count, int64_t i)
|
|
|
|
|
{
|
|
|
|
|
int ndx = (i * mul_count) >> 32;
|
|
|
|
|
av_assert2(ndx <= 4096U);
|
|
|
|
|
|
|
|
|
|
if (mul[ndx] < 0)
|
|
|
|
|
mul[ndx] = ff_ffv1_get_symbol(rc, state, 0) & 0x3FFFFFFF;
|
|
|
|
|
|
|
|
|
|
return mul[ndx];
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 23:35:44 +01:00
|
|
|
static int decode_remap(FFV1Context *f, FFV1SliceContext *sc)
|
|
|
|
|
{
|
2025-03-24 16:00:02 +01:00
|
|
|
unsigned int end = (1LL<<f->avctx->bits_per_raw_sample) - 1;
|
2025-03-19 01:30:47 +01:00
|
|
|
int flip = sc->remap == 2 ? (end>>1) : 0;
|
2025-04-03 10:58:10 +02:00
|
|
|
const int pixel_num = sc->slice_width * sc->slice_height;
|
2025-03-09 23:35:44 +01:00
|
|
|
|
2025-03-14 22:33:46 +01:00
|
|
|
for (int p= 0; p < 1 + 2*f->chroma_planes + f->transparency; p++) {
|
2025-03-09 23:35:44 +01:00
|
|
|
int j = 0;
|
|
|
|
|
int lu = 0;
|
2025-03-20 22:51:01 +01:00
|
|
|
uint8_t state[2][3][32];
|
2025-03-19 01:30:47 +01:00
|
|
|
int64_t i;
|
2025-03-20 22:51:01 +01:00
|
|
|
int mul[4096+1];
|
|
|
|
|
int mul_count;
|
|
|
|
|
|
2025-03-09 23:35:44 +01:00
|
|
|
memset(state, 128, sizeof(state));
|
2025-03-20 22:51:01 +01:00
|
|
|
mul_count = ff_ffv1_get_symbol(&sc->c, state[0][0], 0);
|
|
|
|
|
|
|
|
|
|
if (mul_count > 4096U)
|
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
for (int i = 0; i<mul_count; i++) {
|
|
|
|
|
mul[i] = -1;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
mul[mul_count] = 1;
|
|
|
|
|
|
|
|
|
|
memset(state, 128, sizeof(state));
|
|
|
|
|
int current_mul = 1;
|
|
|
|
|
for (i=0; i <= end ;) {
|
|
|
|
|
unsigned run = get_symbol_inline(&sc->c, state[lu][0], 0);
|
|
|
|
|
unsigned run0 = lu ? 0 : run;
|
|
|
|
|
unsigned run1 = lu ? run : 1;
|
|
|
|
|
|
|
|
|
|
i += run0 * current_mul;
|
|
|
|
|
|
|
|
|
|
while (run1--) {
|
|
|
|
|
if (current_mul > 1) {
|
|
|
|
|
int delta = get_symbol_inline(&sc->c, state[lu][1], 1);
|
|
|
|
|
if (delta <= -current_mul || delta > current_mul/2)
|
|
|
|
|
return AVERROR_INVALIDDATA; //not sure we should check this
|
|
|
|
|
i += current_mul - 1 + delta;
|
2025-03-19 01:30:47 +01:00
|
|
|
}
|
2025-03-25 12:30:16 +01:00
|
|
|
if (i - 1 >= end)
|
2025-03-20 22:51:01 +01:00
|
|
|
break;
|
2025-04-03 10:58:10 +02:00
|
|
|
if (j >= pixel_num)
|
2025-03-20 22:51:01 +01:00
|
|
|
return AVERROR_INVALIDDATA;
|
2025-03-24 16:00:02 +01:00
|
|
|
if (end <= 0xFFFF) {
|
2025-03-20 22:51:01 +01:00
|
|
|
sc->fltmap [p][j++] = i ^ ((i& 0x8000) ? 0 : flip);
|
|
|
|
|
} else
|
|
|
|
|
sc->fltmap32[p][j++] = i ^ ((i&0x80000000) ? 0 : flip);
|
|
|
|
|
i++;
|
|
|
|
|
current_mul = decode_current_mul(&sc->c, state[0][2], mul, mul_count, i);
|
|
|
|
|
}
|
|
|
|
|
if (lu) {
|
|
|
|
|
i += current_mul;
|
2025-03-09 23:35:44 +01:00
|
|
|
}
|
2025-03-20 22:51:01 +01:00
|
|
|
lu ^= !run;
|
2025-03-09 23:35:44 +01:00
|
|
|
}
|
2025-04-02 19:39:10 +02:00
|
|
|
sc->remap_count[p] = j;
|
2025-03-09 23:35:44 +01:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-21 14:05:46 +02:00
|
|
|
static int decode_slice(AVCodecContext *c, void *arg)
|
|
|
|
|
{
|
2024-07-10 17:25:54 +02:00
|
|
|
FFV1Context *f = c->priv_data;
|
|
|
|
|
FFV1SliceContext *sc = arg;
|
2012-10-19 12:14:22 +02:00
|
|
|
int width, height, x, y, ret;
|
2025-01-05 13:42:47 +09:00
|
|
|
const int ps = av_pix_fmt_desc_get(f->pix_fmt)->comp[0].step;
|
2024-07-03 14:36:02 +02:00
|
|
|
AVFrame * const p = f->picture.f;
|
2024-07-10 17:25:54 +02:00
|
|
|
const int si = sc - f->slices;
|
2024-07-08 10:09:22 +02:00
|
|
|
GetBitContext gb;
|
2024-10-25 01:45:56 +02:00
|
|
|
int ac = f->ac || sc->slice_coding_mode == 1;
|
2013-04-27 22:24:14 +02:00
|
|
|
|
2024-07-16 18:21:29 +02:00
|
|
|
if (!(p->flags & AV_FRAME_FLAG_KEY) && f->last_picture.f)
|
2022-09-02 21:51:35 +02:00
|
|
|
ff_progress_frame_await(&f->last_picture, si);
|
2013-04-27 22:24:14 +02:00
|
|
|
|
2024-07-16 18:21:29 +02:00
|
|
|
if (f->slice_damaged[si])
|
|
|
|
|
slice_set_damaged(f, sc);
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2024-07-08 16:11:25 +02:00
|
|
|
sc->slice_rct_by_coef = 1;
|
|
|
|
|
sc->slice_rct_ry_coef = 1;
|
2013-12-08 22:09:50 +01:00
|
|
|
|
2012-10-21 14:05:46 +02:00
|
|
|
if (f->version > 2) {
|
2024-07-09 08:45:16 +02:00
|
|
|
if (ff_ffv1_init_slice_state(f, sc) < 0)
|
2012-10-21 14:05:46 +02:00
|
|
|
return AVERROR(ENOMEM);
|
2024-07-10 17:25:54 +02:00
|
|
|
if (decode_slice_header(f, sc, p) < 0) {
|
2024-07-04 10:22:53 +02:00
|
|
|
sc->slice_x = sc->slice_y = sc->slice_height = sc->slice_width = 0;
|
2024-07-16 18:21:29 +02:00
|
|
|
slice_set_damaged(f, sc);
|
2012-10-21 14:05:46 +02:00
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-09 08:45:16 +02:00
|
|
|
if ((ret = ff_ffv1_init_slice_state(f, sc)) < 0)
|
2012-10-19 12:14:22 +02:00
|
|
|
return ret;
|
2024-07-10 17:38:24 +02:00
|
|
|
if ((p->flags & AV_FRAME_FLAG_KEY) || sc->slice_reset_contexts) {
|
2024-07-08 18:01:13 +02:00
|
|
|
ff_ffv1_clear_slice_state(f, sc);
|
2024-07-10 17:38:24 +02:00
|
|
|
} else if (sc->slice_damaged) {
|
2022-10-06 22:04:48 +02:00
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
}
|
2012-10-21 16:03:31 +02:00
|
|
|
|
2024-07-04 10:22:53 +02:00
|
|
|
width = sc->slice_width;
|
|
|
|
|
height = sc->slice_height;
|
|
|
|
|
x = sc->slice_x;
|
|
|
|
|
y = sc->slice_y;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2025-03-09 23:35:44 +01:00
|
|
|
if (sc->remap) {
|
2025-04-03 10:58:10 +02:00
|
|
|
const int pixel_num = sc->slice_width * sc->slice_height;
|
|
|
|
|
|
2025-04-02 16:30:28 +02:00
|
|
|
for(int p = 0; p < 1 + 2*f->chroma_planes + f->transparency ; p++) {
|
|
|
|
|
if (f->avctx->bits_per_raw_sample == 32) {
|
2025-04-03 10:58:10 +02:00
|
|
|
av_fast_malloc(&sc->fltmap32[p], &sc->fltmap32_size[p], pixel_num * sizeof(*sc->fltmap32[p]));
|
|
|
|
|
if (!sc->fltmap32[p])
|
|
|
|
|
return AVERROR(ENOMEM);
|
2025-04-02 16:30:28 +02:00
|
|
|
} else {
|
2025-04-03 10:58:10 +02:00
|
|
|
av_fast_malloc(&sc->fltmap[p], &sc->fltmap_size[p], pixel_num * sizeof(*sc->fltmap[p]));
|
|
|
|
|
if (!sc->fltmap[p])
|
|
|
|
|
return AVERROR(ENOMEM);
|
2025-04-02 16:30:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 23:35:44 +01:00
|
|
|
ret = decode_remap(f, sc);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-25 01:45:56 +02:00
|
|
|
if (ac == AC_GOLOMB_RICE) {
|
2025-01-18 01:49:38 +01:00
|
|
|
if (f->combined_version >= 0x30002)
|
2024-07-09 08:45:16 +02:00
|
|
|
get_rac(&sc->c, (uint8_t[]) { 129 });
|
2024-07-10 17:20:07 +02:00
|
|
|
sc->ac_byte_count = f->version > 2 || (!x && !y) ? sc->c.bytestream - sc->c.bytestream_start - 1 : 0;
|
2024-07-08 10:09:22 +02:00
|
|
|
init_get_bits(&gb,
|
2024-07-10 17:20:07 +02:00
|
|
|
sc->c.bytestream_start + sc->ac_byte_count,
|
|
|
|
|
(sc->c.bytestream_end - sc->c.bytestream_start - sc->ac_byte_count) * 8);
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
av_assert1(width && height);
|
2024-07-08 13:11:52 +02:00
|
|
|
if (f->colorspace == 0 && (f->chroma_planes || !f->transparency)) {
|
2016-01-27 15:19:38 +00:00
|
|
|
const int chroma_width = AV_CEIL_RSHIFT(width, f->chroma_h_shift);
|
|
|
|
|
const int chroma_height = AV_CEIL_RSHIFT(height, f->chroma_v_shift);
|
2012-10-21 14:05:46 +02:00
|
|
|
const int cx = x >> f->chroma_h_shift;
|
|
|
|
|
const int cy = y >> f->chroma_v_shift;
|
2025-03-10 00:18:41 +01:00
|
|
|
decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 0, 1, ac);
|
2012-10-21 14:05:46 +02:00
|
|
|
|
|
|
|
|
if (f->chroma_planes) {
|
2025-03-10 00:18:41 +01:00
|
|
|
decode_plane(f, sc, &gb, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1, 1, ac);
|
|
|
|
|
decode_plane(f, sc, &gb, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 2, 1, ac);
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
2024-07-08 13:11:52 +02:00
|
|
|
if (f->transparency)
|
2025-03-15 00:52:30 +01:00
|
|
|
decode_plane(f, sc, &gb, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], (f->version >= 4 && !f->chroma_planes) ? 1 : 2,
|
|
|
|
|
(f->version >= 4 && !f->chroma_planes) ? 1 : 3, 1, ac);
|
2016-01-01 01:16:34 +01:00
|
|
|
} else if (f->colorspace == 0) {
|
2025-03-14 22:40:39 +01:00
|
|
|
decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] , width, height, p->linesize[0], 0, 0, 2, ac);
|
|
|
|
|
decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] + (ps>>1), width, height, p->linesize[0], 1, 1, 2, ac);
|
2016-08-08 00:00:46 +02:00
|
|
|
} else if (f->use32bit) {
|
2025-07-22 11:57:13 -03:00
|
|
|
uint8_t *planes[4] = { p->data[0] + ps * x + y * p->linesize[0],
|
|
|
|
|
p->data[1] + ps * x + y * p->linesize[1],
|
|
|
|
|
p->data[2] + ps * x + y * p->linesize[2] };
|
2025-07-13 19:56:13 -03:00
|
|
|
if (f->transparency)
|
|
|
|
|
planes[3] = p->data[3] + ps * x + y * p->linesize[3];
|
2024-07-10 17:25:54 +02:00
|
|
|
decode_rgb_frame32(f, sc, &gb, planes, width, height, p->linesize);
|
2012-10-21 14:05:46 +02:00
|
|
|
} else {
|
2025-07-18 21:42:35 -03:00
|
|
|
uint8_t *planes[4] = { p->data[0] + ps * x + y * p->linesize[0] };
|
2025-07-22 11:57:13 -03:00
|
|
|
if (f->avctx->bits_per_raw_sample > 8) {
|
2025-07-18 21:42:35 -03:00
|
|
|
planes[1] = p->data[1] + ps * x + y * p->linesize[1];
|
|
|
|
|
planes[2] = p->data[2] + ps * x + y * p->linesize[2];
|
2025-07-22 11:57:13 -03:00
|
|
|
if (f->transparency)
|
|
|
|
|
planes[3] = p->data[3] + ps * x + y * p->linesize[3];
|
2025-07-18 21:42:35 -03:00
|
|
|
}
|
2024-07-10 17:25:54 +02:00
|
|
|
decode_rgb_frame(f, sc, &gb, planes, width, height, p->linesize);
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
2024-10-25 01:45:56 +02:00
|
|
|
if (ac != AC_GOLOMB_RICE && f->version > 2) {
|
2012-10-21 14:05:46 +02:00
|
|
|
int v;
|
2024-07-09 08:45:16 +02:00
|
|
|
get_rac(&sc->c, (uint8_t[]) { 129 });
|
2024-10-10 20:39:23 +02:00
|
|
|
v = sc->c.bytestream_end - sc->c.bytestream - 2 - 5*!!f->ec;
|
2012-10-21 14:05:46 +02:00
|
|
|
if (v) {
|
|
|
|
|
av_log(f->avctx, AV_LOG_ERROR, "bytestream end mismatching by %d\n", v);
|
2024-07-16 18:21:29 +02:00
|
|
|
slice_set_damaged(f, sc);
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-24 22:19:31 +02:00
|
|
|
if (sc->slice_damaged && (f->avctx->err_recognition & AV_EF_EXPLODE))
|
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
|
2024-07-16 18:21:29 +02:00
|
|
|
if ((c->active_thread_type & FF_THREAD_FRAME) && !f->frame_damaged)
|
|
|
|
|
ff_progress_frame_report(&f->picture, si);
|
2013-04-27 22:24:14 +02:00
|
|
|
|
2012-10-21 14:05:46 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 13:42:47 +09:00
|
|
|
static enum AVPixelFormat get_pixel_format(FFV1Context *f)
|
|
|
|
|
{
|
|
|
|
|
enum AVPixelFormat pix_fmts[] = {
|
2025-03-10 03:04:39 +00:00
|
|
|
#if CONFIG_FFV1_VULKAN_HWACCEL
|
|
|
|
|
AV_PIX_FMT_VULKAN,
|
|
|
|
|
#endif
|
2025-01-05 13:42:47 +09:00
|
|
|
f->pix_fmt,
|
|
|
|
|
AV_PIX_FMT_NONE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return ff_get_format(f->avctx, pix_fmts);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 14:46:56 +09:00
|
|
|
static int read_header(FFV1Context *f, RangeCoder *c)
|
2012-10-21 14:05:46 +02:00
|
|
|
{
|
|
|
|
|
uint8_t state[CONTEXT_SIZE];
|
2024-07-03 13:24:23 +02:00
|
|
|
int context_count = -1; //-1 to avoid warning
|
2025-02-02 22:55:45 -03:00
|
|
|
int ret;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
|
|
|
|
memset(state, 128, sizeof(state));
|
|
|
|
|
|
2025-02-02 22:55:45 -03:00
|
|
|
ret = ff_ffv1_parse_header(f, c, state);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2025-01-05 15:27:30 +09:00
|
|
|
if (f->configured_pix_fmt != f->pix_fmt) {
|
|
|
|
|
f->avctx->pix_fmt = get_pixel_format(f);
|
|
|
|
|
if (f->avctx->pix_fmt < 0)
|
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
|
f->configured_pix_fmt = f->pix_fmt;
|
|
|
|
|
}
|
2025-01-05 13:42:47 +09:00
|
|
|
|
2015-03-16 08:57:36 +00:00
|
|
|
ff_dlog(f->avctx, "%d %d %d\n",
|
2025-01-05 13:42:47 +09:00
|
|
|
f->chroma_h_shift, f->chroma_v_shift, f->pix_fmt);
|
2012-10-21 14:05:46 +02:00
|
|
|
if (f->version < 2) {
|
2025-02-02 22:55:45 -03:00
|
|
|
context_count = ff_ffv1_read_quant_tables(c, f->quant_tables[0]);
|
2012-10-21 14:05:46 +02:00
|
|
|
if (context_count < 0) {
|
|
|
|
|
av_log(f->avctx, AV_LOG_ERROR, "read_quant_table error\n");
|
2012-10-19 12:14:22 +02:00
|
|
|
return AVERROR_INVALIDDATA;
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
2015-09-24 23:49:30 +02:00
|
|
|
f->slice_count = f->max_slice_count;
|
2012-10-21 14:05:46 +02:00
|
|
|
} else if (f->version < 3) {
|
2025-02-02 22:55:45 -03:00
|
|
|
f->slice_count = ff_ffv1_get_symbol(c, state, 0);
|
2012-10-21 14:05:46 +02:00
|
|
|
} else {
|
|
|
|
|
const uint8_t *p = c->bytestream_end;
|
2012-10-19 12:14:22 +02:00
|
|
|
for (f->slice_count = 0;
|
2017-10-09 11:49:28 +02:00
|
|
|
f->slice_count < MAX_SLICES && 3 + 5*!!f->ec < p - c->bytestream_start;
|
2012-10-19 12:14:22 +02:00
|
|
|
f->slice_count++) {
|
2012-10-21 14:05:46 +02:00
|
|
|
int trailer = 3 + 5*!!f->ec;
|
|
|
|
|
int size = AV_RB24(p-trailer);
|
|
|
|
|
if (size + trailer > p - c->bytestream_start)
|
|
|
|
|
break;
|
|
|
|
|
p -= size + trailer;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-24 23:49:30 +02:00
|
|
|
if (f->slice_count > (unsigned)MAX_SLICES || f->slice_count <= 0 || f->slice_count > f->max_slice_count) {
|
|
|
|
|
av_log(f->avctx, AV_LOG_ERROR, "slice count %d is invalid (max=%d)\n", f->slice_count, f->max_slice_count);
|
2012-10-21 14:54:16 +02:00
|
|
|
return AVERROR_INVALIDDATA;
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-15 22:37:56 +02:00
|
|
|
av_refstruct_unref(&f->slice_damaged);
|
|
|
|
|
f->slice_damaged = av_refstruct_allocz(f->slice_count * sizeof(*f->slice_damaged));
|
2024-07-16 18:21:29 +02:00
|
|
|
if (!f->slice_damaged)
|
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
2024-07-03 13:24:23 +02:00
|
|
|
for (int j = 0; j < f->slice_count; j++) {
|
2024-07-04 10:22:53 +02:00
|
|
|
FFV1SliceContext *sc = &f->slices[j];
|
2012-10-21 14:05:46 +02:00
|
|
|
|
|
|
|
|
if (f->version == 2) {
|
2025-02-02 22:55:45 -03:00
|
|
|
int sx = ff_ffv1_get_symbol(c, state, 0);
|
|
|
|
|
int sy = ff_ffv1_get_symbol(c, state, 0);
|
|
|
|
|
int sw = ff_ffv1_get_symbol(c, state, 0) + 1U;
|
|
|
|
|
int sh = ff_ffv1_get_symbol(c, state, 0) + 1U;
|
2022-11-22 23:34:22 +01:00
|
|
|
|
|
|
|
|
if (sx < 0 || sy < 0 || sw <= 0 || sh <= 0)
|
2012-10-19 10:33:43 +02:00
|
|
|
return AVERROR_INVALIDDATA;
|
2022-11-22 23:34:22 +01:00
|
|
|
if (sx > f->num_h_slices - sw || sy > f->num_v_slices - sh)
|
2012-10-19 10:33:43 +02:00
|
|
|
return AVERROR_INVALIDDATA;
|
2022-11-22 23:34:22 +01:00
|
|
|
|
2024-07-04 10:22:53 +02:00
|
|
|
sc->slice_x = sx * (int64_t)f->width / f->num_h_slices;
|
|
|
|
|
sc->slice_y = sy * (int64_t)f->height / f->num_v_slices;
|
|
|
|
|
sc->slice_width = (sx + sw) * (int64_t)f->width / f->num_h_slices - sc->slice_x;
|
|
|
|
|
sc->slice_height = (sy + sh) * (int64_t)f->height / f->num_v_slices - sc->slice_y;
|
2022-11-22 23:34:22 +01:00
|
|
|
|
2024-07-04 10:22:53 +02:00
|
|
|
av_assert0((unsigned)sc->slice_width <= f->width &&
|
|
|
|
|
(unsigned)sc->slice_height <= f->height);
|
|
|
|
|
av_assert0 ( (unsigned)sc->slice_x + (uint64_t)sc->slice_width <= f->width
|
|
|
|
|
&& (unsigned)sc->slice_y + (uint64_t)sc->slice_height <= f->height);
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-15 22:37:56 +02:00
|
|
|
av_refstruct_unref(&sc->plane);
|
lavc/ffv1: change FFV1SliceContext.plane into a RefStruct object
Frame threading in the FFV1 decoder works in a very unusual way - the
state that needs to be propagated from the previous frame is not decoded
pixels(¹), but each slice's entropy coder state after decoding the slice.
For that purpose, the decoder's update_thread_context() callback stores
a pointer to the previous frame thread's private data. Then, when
decoding each slice, the frame thread uses the standard progress
mechanism to wait for the corresponding slice in the previous frame to
be completed, then copies the entropy coder state from the
previously-stored pointer.
This approach is highly dubious, as update_thread_context() should be
the only point where frame-thread contexts come into direct contact.
There are no guarantees that the stored pointer will be valid at all, or
will contain any particular data after update_thread_context() finishes.
More specifically, this code can break due to the fact that keyframes
reset entropy coder state and thus do not need to wait for the previous
frame. As an example, consider a decoder process with 2 frame threads -
thread 0 with its context 0, and thread 1 with context 1 - decoding a
previous frame P, current frame F, followed by a keyframe K. Then
consider concurrent execution consistent with the following sequence of
events:
* thread 0 starts decoding P
* thread 0 reads P's slice header, then calls
ff_thread_finish_setup() allowing next frame thread to start
* main thread calls update_thread_context() to transfer state from
context 0 to context 1; context 1 stores a pointer to context 0's private
data
* thread 1 starts decoding F
* thread 1 reads F's slice header, then calls
ff_thread_finish_setup() allowing the next frame thread to start
decoding
* thread 0 finishes decoding P
* thread 0 starts decoding K; since K is a keyframe, it does not
wait for F and reallocates the arrays holding entropy coder state
* thread 0 finishes decoding K
* thread 1 reads entropy coder state from its stored pointer to context
0, however it finds state from K rather than from P
This execution is currently prevented by special-casing FFV1 in the
generic frame threading code, however that is supremely ugly. It also
involves unnecessary copies of the state arrays, when in fact they can
only be used by one thread at a time.
This commit addresses these deficiencies by changing the array of
PlaneContext (each of which contains the allocated state arrays)
embedded in FFV1SliceContext into a RefStruct object. This object can
then be propagated across frame threads in standard manner. Since the
code structure guarantees only one thread accesses it at a time, no
copies are necessary. It is also re-created for keyframes, solving the
above issue cleanly.
Special-casing of FFV1 in the generic frame threading code will be
removed in a later commit.
(¹) except in the case of a damaged slice, when previous frame's pixels
are used directly
2024-07-11 11:08:55 +02:00
|
|
|
sc->plane = ff_ffv1_planes_alloc();
|
|
|
|
|
if (!sc->plane)
|
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
2024-07-03 13:24:23 +02:00
|
|
|
for (int i = 0; i < f->plane_count; i++) {
|
2024-07-08 18:01:13 +02:00
|
|
|
PlaneContext *const p = &sc->plane[i];
|
2012-10-21 14:05:46 +02:00
|
|
|
|
|
|
|
|
if (f->version == 2) {
|
2025-02-02 22:55:45 -03:00
|
|
|
int idx = ff_ffv1_get_symbol(c, state, 0);
|
2020-12-19 00:22:04 +01:00
|
|
|
if (idx >= (unsigned)f->quant_table_count) {
|
2012-10-21 14:05:46 +02:00
|
|
|
av_log(f->avctx, AV_LOG_ERROR,
|
|
|
|
|
"quant_table_index out of range\n");
|
2012-10-19 10:33:43 +02:00
|
|
|
return AVERROR_INVALIDDATA;
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
p->quant_table_index = idx;
|
|
|
|
|
context_count = f->context_count[idx];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (f->version <= 2) {
|
|
|
|
|
av_assert0(context_count >= 0);
|
|
|
|
|
p->context_count = context_count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static av_cold int decode_init(AVCodecContext *avctx)
|
|
|
|
|
{
|
|
|
|
|
FFV1Context *f = avctx->priv_data;
|
2012-10-19 10:33:43 +02:00
|
|
|
int ret;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2025-01-05 15:27:30 +09:00
|
|
|
f->pix_fmt = AV_PIX_FMT_NONE;
|
|
|
|
|
f->configured_pix_fmt = AV_PIX_FMT_NONE;
|
|
|
|
|
|
2025-02-02 22:55:45 -03:00
|
|
|
if ((ret = ff_ffv1_common_init(avctx, f)) < 0)
|
2012-11-07 13:27:01 +01:00
|
|
|
return ret;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2025-02-02 22:55:45 -03:00
|
|
|
if (avctx->extradata_size > 0 && (ret = ff_ffv1_read_extra_header(f)) < 0)
|
2012-10-19 10:33:43 +02:00
|
|
|
return ret;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2015-08-21 18:14:12 -07:00
|
|
|
if ((ret = ff_ffv1_init_slice_contexts(f)) < 0)
|
2012-10-19 10:33:43 +02:00
|
|
|
return ret;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 13:51:52 +09:00
|
|
|
static int find_next_slice(AVCodecContext *avctx,
|
|
|
|
|
uint8_t *buf, uint8_t *buf_end, int idx,
|
|
|
|
|
uint8_t **pos, uint32_t *len)
|
|
|
|
|
{
|
|
|
|
|
FFV1Context *f = avctx->priv_data;
|
|
|
|
|
|
|
|
|
|
/* Length field */
|
|
|
|
|
uint32_t v = buf_end - buf;
|
|
|
|
|
if (idx || f->version > 2) {
|
|
|
|
|
/* Three bytes of length, plus flush bit + CRC */
|
|
|
|
|
uint32_t trailer = 3 + 5*!!f->ec;
|
|
|
|
|
if (trailer > buf_end - buf)
|
|
|
|
|
v = INT_MAX;
|
|
|
|
|
else
|
|
|
|
|
v = AV_RB24(buf_end - trailer) + trailer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (buf_end - buf < v) {
|
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Slice pointer chain broken\n");
|
|
|
|
|
ff_progress_frame_report(&f->picture, INT_MAX);
|
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*len = v;
|
|
|
|
|
if (idx)
|
|
|
|
|
*pos = buf_end - v;
|
|
|
|
|
else
|
|
|
|
|
*pos = buf;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 14:46:56 +09:00
|
|
|
static int decode_header(AVCodecContext *avctx, RangeCoder *c,
|
|
|
|
|
uint8_t *buf, size_t buf_size)
|
2012-10-21 14:05:46 +02:00
|
|
|
{
|
2025-01-05 14:46:56 +09:00
|
|
|
int ret;
|
|
|
|
|
FFV1Context *f = avctx->priv_data;
|
2013-08-02 23:31:40 +02:00
|
|
|
|
2025-01-05 14:46:56 +09:00
|
|
|
uint8_t keystate = 128;
|
2012-10-21 14:05:46 +02:00
|
|
|
ff_init_range_decoder(c, buf, buf_size);
|
|
|
|
|
ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8);
|
|
|
|
|
|
|
|
|
|
if (get_rac(c, &keystate)) {
|
2025-01-05 14:46:56 +09:00
|
|
|
f->key_frame = AV_FRAME_FLAG_KEY;
|
2012-10-21 14:05:46 +02:00
|
|
|
f->key_frame_ok = 0;
|
2025-01-05 14:46:56 +09:00
|
|
|
if ((ret = read_header(f, c)) < 0)
|
2012-10-19 10:33:43 +02:00
|
|
|
return ret;
|
2012-10-21 14:05:46 +02:00
|
|
|
f->key_frame_ok = 1;
|
|
|
|
|
} else {
|
|
|
|
|
if (!f->key_frame_ok) {
|
2012-10-19 12:14:22 +02:00
|
|
|
av_log(avctx, AV_LOG_ERROR,
|
2012-12-19 18:48:21 +01:00
|
|
|
"Cannot decode non-keyframe without valid keyframe\n");
|
2012-10-21 14:05:46 +02:00
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
}
|
2025-01-05 14:46:56 +09:00
|
|
|
f->key_frame = 0;
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
|
2022-07-03 14:19:54 +02:00
|
|
|
if (f->ac != AC_GOLOMB_RICE) {
|
|
|
|
|
if (buf_size < avctx->width * avctx->height / (128*8))
|
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
} else {
|
2022-07-19 01:25:01 +02:00
|
|
|
int w = avctx->width;
|
2022-07-21 00:20:41 +02:00
|
|
|
int s = 1 + w / (1<<23);
|
2024-07-03 13:24:23 +02:00
|
|
|
int i;
|
2022-07-21 00:20:41 +02:00
|
|
|
|
|
|
|
|
w /= s;
|
|
|
|
|
|
|
|
|
|
for (i = 0; w > (1<<ff_log2_run[i]); i++)
|
2022-07-19 01:25:01 +02:00
|
|
|
w -= ff_log2_run[i];
|
2022-07-21 00:20:41 +02:00
|
|
|
if (buf_size < (avctx->height + i + 6) / 8 * s)
|
2022-07-03 14:19:54 +02:00
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 14:46:56 +09:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 15:20:02 +09:00
|
|
|
static int decode_slices(AVCodecContext *avctx, RangeCoder c,
|
|
|
|
|
AVPacket *avpkt)
|
2025-01-05 14:46:56 +09:00
|
|
|
{
|
2025-01-05 15:20:02 +09:00
|
|
|
FFV1Context *f = avctx->priv_data;
|
|
|
|
|
AVFrame *p = f->picture.f;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2025-01-05 15:20:02 +09:00
|
|
|
uint8_t *buf = avpkt->data;
|
|
|
|
|
size_t buf_size = avpkt->size;
|
|
|
|
|
uint8_t *buf_end = buf + buf_size;
|
2013-04-27 22:24:14 +02:00
|
|
|
|
2024-07-03 13:24:23 +02:00
|
|
|
for (int i = f->slice_count - 1; i >= 0; i--) {
|
2024-07-09 08:45:16 +02:00
|
|
|
FFV1SliceContext *sc = &f->slices[i];
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2025-01-05 13:51:52 +09:00
|
|
|
uint8_t *pos;
|
|
|
|
|
uint32_t len;
|
|
|
|
|
int err = find_next_slice(avctx, buf, buf_end, i,
|
|
|
|
|
&pos, &len);
|
|
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
2024-07-16 18:21:29 +02:00
|
|
|
|
2025-01-05 13:51:52 +09:00
|
|
|
buf_end -= len;
|
|
|
|
|
|
|
|
|
|
sc->slice_damaged = 0;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
|
|
|
|
if (f->ec) {
|
2025-01-05 13:51:52 +09:00
|
|
|
unsigned crc = av_crc(av_crc_get_table(AV_CRC_32_IEEE), f->crcref, pos, len);
|
2024-09-25 09:46:17 +02:00
|
|
|
if (crc != f->crcref) {
|
2012-10-21 14:05:46 +02:00
|
|
|
int64_t ts = avpkt->pts != AV_NOPTS_VALUE ? avpkt->pts : avpkt->dts;
|
2019-10-17 23:22:22 +02:00
|
|
|
av_log(f->avctx, AV_LOG_ERROR, "slice CRC mismatch %X!", crc);
|
2012-10-21 14:05:46 +02:00
|
|
|
if (ts != AV_NOPTS_VALUE && avctx->pkt_timebase.num) {
|
|
|
|
|
av_log(f->avctx, AV_LOG_ERROR, "at %f seconds\n", ts*av_q2d(avctx->pkt_timebase));
|
|
|
|
|
} else if (ts != AV_NOPTS_VALUE) {
|
|
|
|
|
av_log(f->avctx, AV_LOG_ERROR, "at %"PRId64"\n", ts);
|
|
|
|
|
} else {
|
|
|
|
|
av_log(f->avctx, AV_LOG_ERROR, "\n");
|
|
|
|
|
}
|
2024-07-16 18:21:29 +02:00
|
|
|
slice_set_damaged(f, sc);
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
2015-09-02 02:11:43 +02:00
|
|
|
if (avctx->debug & FF_DEBUG_PICT_INFO) {
|
2025-01-05 13:51:52 +09:00
|
|
|
av_log(avctx, AV_LOG_DEBUG, "slice %d, CRC: 0x%08"PRIX32"\n", i, AV_RB32(pos + len - 4));
|
2015-09-02 02:11:43 +02:00
|
|
|
}
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i) {
|
2025-01-05 13:51:52 +09:00
|
|
|
ff_init_range_decoder(&sc->c, pos, len);
|
2024-07-09 08:45:16 +02:00
|
|
|
ff_build_rac_states(&sc->c, 0.05 * (1LL << 32), 256 - 8);
|
2025-01-05 14:46:56 +09:00
|
|
|
} else {
|
|
|
|
|
sc->c = c;
|
2025-01-05 13:51:52 +09:00
|
|
|
sc->c.bytestream_end = pos + len;
|
2025-01-05 14:46:56 +09:00
|
|
|
}
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-21 16:03:31 +02:00
|
|
|
avctx->execute(avctx,
|
|
|
|
|
decode_slice,
|
2024-07-10 17:25:54 +02:00
|
|
|
f->slices,
|
2012-10-21 16:03:31 +02:00
|
|
|
NULL,
|
2012-10-19 12:14:22 +02:00
|
|
|
f->slice_count,
|
2024-07-10 17:25:54 +02:00
|
|
|
sizeof(*f->slices));
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2024-07-03 13:24:23 +02:00
|
|
|
for (int i = f->slice_count - 1; i >= 0; i--) {
|
2024-07-04 10:22:53 +02:00
|
|
|
FFV1SliceContext *sc = &f->slices[i];
|
2024-07-10 17:38:24 +02:00
|
|
|
if (sc->slice_damaged && f->last_picture.f) {
|
2025-01-05 13:42:47 +09:00
|
|
|
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(f->pix_fmt);
|
2012-10-19 12:14:22 +02:00
|
|
|
const uint8_t *src[4];
|
|
|
|
|
uint8_t *dst[4];
|
2022-09-02 21:51:35 +02:00
|
|
|
ff_progress_frame_await(&f->last_picture, INT_MAX);
|
2024-07-03 13:24:23 +02:00
|
|
|
for (int j = 0; j < desc->nb_components; j++) {
|
2015-09-25 16:44:46 +02:00
|
|
|
int pixshift = desc->comp[j].depth > 8;
|
2012-10-19 12:14:22 +02:00
|
|
|
int sh = (j == 1 || j == 2) ? f->chroma_h_shift : 0;
|
|
|
|
|
int sv = (j == 1 || j == 2) ? f->chroma_v_shift : 0;
|
2012-11-21 21:34:46 +01:00
|
|
|
dst[j] = p->data[j] + p->linesize[j] *
|
2024-07-04 10:22:53 +02:00
|
|
|
(sc->slice_y >> sv) + ((sc->slice_x >> sh) << pixshift);
|
2013-11-17 13:27:46 +01:00
|
|
|
src[j] = f->last_picture.f->data[j] + f->last_picture.f->linesize[j] *
|
2024-07-04 10:22:53 +02:00
|
|
|
(sc->slice_y >> sv) + ((sc->slice_x >> sh) << pixshift);
|
2017-05-08 02:28:07 +02:00
|
|
|
|
|
|
|
|
}
|
2024-07-22 10:46:26 +02:00
|
|
|
|
2014-12-18 20:07:28 +01:00
|
|
|
av_image_copy(dst, p->linesize, src,
|
2013-04-27 22:21:16 +02:00
|
|
|
f->last_picture.f->linesize,
|
2025-01-05 13:42:47 +09:00
|
|
|
f->pix_fmt,
|
2024-07-04 10:22:53 +02:00
|
|
|
sc->slice_width,
|
|
|
|
|
sc->slice_height);
|
2024-07-16 18:21:29 +02:00
|
|
|
|
|
|
|
|
f->slice_damaged[i] = 1;
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
2025-01-05 15:20:02 +09:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int decode_frame(AVCodecContext *avctx, AVFrame *rframe,
|
|
|
|
|
int *got_frame, AVPacket *avpkt)
|
|
|
|
|
{
|
|
|
|
|
FFV1Context *f = avctx->priv_data;
|
|
|
|
|
int ret;
|
|
|
|
|
AVFrame *p;
|
2025-01-05 15:27:30 +09:00
|
|
|
const FFHWAccel *hwaccel = NULL;
|
2025-01-05 15:20:02 +09:00
|
|
|
|
|
|
|
|
/* This is copied onto the first slice's range coder context */
|
|
|
|
|
RangeCoder c;
|
|
|
|
|
|
|
|
|
|
ff_progress_frame_unref(&f->last_picture);
|
2025-01-05 15:27:30 +09:00
|
|
|
av_refstruct_unref(&f->hwaccel_last_picture_private);
|
2025-01-05 15:20:02 +09:00
|
|
|
|
2025-01-05 15:27:30 +09:00
|
|
|
FFSWAP(ProgressFrame, f->picture, f->last_picture);
|
|
|
|
|
FFSWAP(void *, f->hwaccel_picture_private, f->hwaccel_last_picture_private);
|
2025-01-05 15:20:02 +09:00
|
|
|
|
|
|
|
|
f->avctx = avctx;
|
|
|
|
|
f->frame_damaged = 0;
|
|
|
|
|
|
|
|
|
|
ret = decode_header(avctx, &c, avpkt->data, avpkt->size);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
2025-03-15 16:09:28 -03:00
|
|
|
if (avctx->debug & FF_DEBUG_PICT_INFO)
|
|
|
|
|
av_log(avctx, AV_LOG_DEBUG, "ver:%d keyframe:%d coder:%d ec:%d slices:%d bps:%d\n",
|
|
|
|
|
f->version, !!f->key_frame, f->ac, f->ec, f->slice_count, f->avctx->bits_per_raw_sample);
|
|
|
|
|
|
|
|
|
|
if (avctx->skip_frame >= AVDISCARD_ALL)
|
|
|
|
|
return avpkt->size;
|
|
|
|
|
|
2025-01-05 15:27:30 +09:00
|
|
|
if (avctx->hwaccel)
|
|
|
|
|
hwaccel = ffhwaccel(avctx->hwaccel);
|
|
|
|
|
|
2025-01-05 15:20:02 +09:00
|
|
|
ret = ff_progress_frame_get_buffer(avctx, &f->picture,
|
|
|
|
|
AV_GET_BUFFER_FLAG_REF);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
2025-01-05 15:27:30 +09:00
|
|
|
ret = ff_hwaccel_frame_priv_alloc(avctx, &f->hwaccel_picture_private);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
2025-01-05 15:20:02 +09:00
|
|
|
p = f->picture.f;
|
|
|
|
|
|
|
|
|
|
p->pict_type = AV_PICTURE_TYPE_I; //FIXME I vs. P
|
|
|
|
|
p->flags = (p->flags & ~AV_FRAME_FLAG_KEY) | f->key_frame;
|
|
|
|
|
|
|
|
|
|
if (f->version < 3 && avctx->field_order > AV_FIELD_PROGRESSIVE) {
|
|
|
|
|
/* we have interlaced material flagged in container */
|
|
|
|
|
p->flags |= AV_FRAME_FLAG_INTERLACED;
|
|
|
|
|
if (avctx->field_order == AV_FIELD_TT || avctx->field_order == AV_FIELD_TB)
|
|
|
|
|
p->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 15:27:30 +09:00
|
|
|
/* Start */
|
|
|
|
|
if (hwaccel) {
|
2025-03-13 16:26:40 +00:00
|
|
|
ret = hwaccel->start_frame(avctx, avpkt->buf, avpkt->data, avpkt->size);
|
2025-01-05 15:27:30 +09:00
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 15:20:02 +09:00
|
|
|
ff_thread_finish_setup(avctx);
|
|
|
|
|
|
2025-01-05 15:27:30 +09:00
|
|
|
/* Decode slices */
|
|
|
|
|
if (hwaccel) {
|
|
|
|
|
uint8_t *buf_end = avpkt->data + avpkt->size;
|
|
|
|
|
|
|
|
|
|
if (!(p->flags & AV_FRAME_FLAG_KEY) && f->last_picture.f)
|
|
|
|
|
ff_progress_frame_await(&f->last_picture, f->slice_count - 1);
|
|
|
|
|
|
|
|
|
|
for (int i = f->slice_count - 1; i >= 0; i--) {
|
|
|
|
|
uint8_t *pos;
|
|
|
|
|
uint32_t len;
|
|
|
|
|
ret = find_next_slice(avctx, avpkt->data, buf_end, i,
|
|
|
|
|
&pos, &len);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
buf_end -= len;
|
|
|
|
|
|
|
|
|
|
ret = hwaccel->decode_slice(avctx, pos, len);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ret = decode_slices(avctx, c, avpkt);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finalize */
|
|
|
|
|
if (hwaccel) {
|
|
|
|
|
ret = hwaccel->end_frame(avctx);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2025-01-05 15:20:02 +09:00
|
|
|
|
2022-09-02 21:51:35 +02:00
|
|
|
ff_progress_frame_report(&f->picture, INT_MAX);
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2022-09-02 21:51:35 +02:00
|
|
|
ff_progress_frame_unref(&f->last_picture);
|
2025-01-05 15:27:30 +09:00
|
|
|
av_refstruct_unref(&f->hwaccel_last_picture_private);
|
2022-03-30 21:33:24 +02:00
|
|
|
if ((ret = av_frame_ref(rframe, f->picture.f)) < 0)
|
2013-04-27 22:21:16 +02:00
|
|
|
return ret;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2012-11-21 21:34:46 +01:00
|
|
|
*got_frame = 1;
|
2012-10-21 14:05:46 +02:00
|
|
|
|
2025-01-05 15:20:02 +09:00
|
|
|
return avpkt->size;
|
2012-10-21 14:05:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-03 14:54:51 +02:00
|
|
|
#if HAVE_THREADS
|
2013-04-27 22:24:14 +02:00
|
|
|
static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
|
|
|
|
|
{
|
|
|
|
|
FFV1Context *fsrc = src->priv_data;
|
|
|
|
|
FFV1Context *fdst = dst->priv_data;
|
|
|
|
|
|
|
|
|
|
if (dst == src)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2024-07-10 20:18:24 +02:00
|
|
|
fdst->version = fsrc->version;
|
|
|
|
|
fdst->micro_version = fsrc->micro_version;
|
2025-01-18 01:49:38 +01:00
|
|
|
fdst->combined_version = fsrc->combined_version;
|
2024-07-10 20:18:24 +02:00
|
|
|
fdst->chroma_planes = fsrc->chroma_planes;
|
|
|
|
|
fdst->chroma_h_shift = fsrc->chroma_h_shift;
|
|
|
|
|
fdst->chroma_v_shift = fsrc->chroma_v_shift;
|
|
|
|
|
fdst->transparency = fsrc->transparency;
|
|
|
|
|
fdst->plane_count = fsrc->plane_count;
|
|
|
|
|
fdst->ac = fsrc->ac;
|
|
|
|
|
fdst->colorspace = fsrc->colorspace;
|
2025-02-05 15:45:24 +01:00
|
|
|
fdst->pix_fmt = fsrc->pix_fmt;
|
2025-01-05 15:27:30 +09:00
|
|
|
fdst->configured_pix_fmt = fsrc->configured_pix_fmt;
|
2024-07-10 20:18:24 +02:00
|
|
|
|
|
|
|
|
fdst->ec = fsrc->ec;
|
|
|
|
|
fdst->intra = fsrc->intra;
|
|
|
|
|
fdst->key_frame_ok = fsrc->key_frame_ok;
|
|
|
|
|
|
|
|
|
|
fdst->packed_at_lsb = fsrc->packed_at_lsb;
|
|
|
|
|
fdst->slice_count = fsrc->slice_count;
|
2021-04-21 19:25:22 +02:00
|
|
|
fdst->use32bit = fsrc->use32bit;
|
|
|
|
|
memcpy(fdst->state_transition, fsrc->state_transition,
|
|
|
|
|
sizeof(fdst->state_transition));
|
2024-07-08 11:36:58 +02:00
|
|
|
|
|
|
|
|
// in version 1 there is a single per-keyframe quant table, so
|
|
|
|
|
// we need to propagate it between threads
|
|
|
|
|
if (fsrc->version < 2)
|
|
|
|
|
memcpy(fdst->quant_tables[0], fsrc->quant_tables[0], sizeof(fsrc->quant_tables[0]));
|
2021-04-21 19:25:22 +02:00
|
|
|
|
2024-07-03 13:24:23 +02:00
|
|
|
for (int i = 0; i < fdst->num_h_slices * fdst->num_v_slices; i++) {
|
2024-07-04 10:22:53 +02:00
|
|
|
FFV1SliceContext *sc = &fdst->slices[i];
|
|
|
|
|
const FFV1SliceContext *sc0 = &fsrc->slices[i];
|
|
|
|
|
|
2024-10-15 22:37:56 +02:00
|
|
|
av_refstruct_replace(&sc->plane, sc0->plane);
|
lavc/ffv1: change FFV1SliceContext.plane into a RefStruct object
Frame threading in the FFV1 decoder works in a very unusual way - the
state that needs to be propagated from the previous frame is not decoded
pixels(¹), but each slice's entropy coder state after decoding the slice.
For that purpose, the decoder's update_thread_context() callback stores
a pointer to the previous frame thread's private data. Then, when
decoding each slice, the frame thread uses the standard progress
mechanism to wait for the corresponding slice in the previous frame to
be completed, then copies the entropy coder state from the
previously-stored pointer.
This approach is highly dubious, as update_thread_context() should be
the only point where frame-thread contexts come into direct contact.
There are no guarantees that the stored pointer will be valid at all, or
will contain any particular data after update_thread_context() finishes.
More specifically, this code can break due to the fact that keyframes
reset entropy coder state and thus do not need to wait for the previous
frame. As an example, consider a decoder process with 2 frame threads -
thread 0 with its context 0, and thread 1 with context 1 - decoding a
previous frame P, current frame F, followed by a keyframe K. Then
consider concurrent execution consistent with the following sequence of
events:
* thread 0 starts decoding P
* thread 0 reads P's slice header, then calls
ff_thread_finish_setup() allowing next frame thread to start
* main thread calls update_thread_context() to transfer state from
context 0 to context 1; context 1 stores a pointer to context 0's private
data
* thread 1 starts decoding F
* thread 1 reads F's slice header, then calls
ff_thread_finish_setup() allowing the next frame thread to start
decoding
* thread 0 finishes decoding P
* thread 0 starts decoding K; since K is a keyframe, it does not
wait for F and reallocates the arrays holding entropy coder state
* thread 0 finishes decoding K
* thread 1 reads entropy coder state from its stored pointer to context
0, however it finds state from K rather than from P
This execution is currently prevented by special-casing FFV1 in the
generic frame threading code, however that is supremely ugly. It also
involves unnecessary copies of the state arrays, when in fact they can
only be used by one thread at a time.
This commit addresses these deficiencies by changing the array of
PlaneContext (each of which contains the allocated state arrays)
embedded in FFV1SliceContext into a RefStruct object. This object can
then be propagated across frame threads in standard manner. Since the
code structure guarantees only one thread accesses it at a time, no
copies are necessary. It is also re-created for keyframes, solving the
above issue cleanly.
Special-casing of FFV1 in the generic frame threading code will be
removed in a later commit.
(¹) except in the case of a damaged slice, when previous frame's pixels
are used directly
2024-07-11 11:08:55 +02:00
|
|
|
|
2024-07-04 10:22:53 +02:00
|
|
|
if (fsrc->version < 3) {
|
|
|
|
|
sc->slice_x = sc0->slice_x;
|
|
|
|
|
sc->slice_y = sc0->slice_y;
|
|
|
|
|
sc->slice_width = sc0->slice_width;
|
|
|
|
|
sc->slice_height = sc0->slice_height;
|
|
|
|
|
}
|
2021-04-21 19:37:12 +02:00
|
|
|
}
|
2013-04-27 16:15:33 +02:00
|
|
|
|
2024-10-15 22:37:56 +02:00
|
|
|
av_refstruct_replace(&fdst->slice_damaged, fsrc->slice_damaged);
|
2024-07-16 18:21:29 +02:00
|
|
|
|
2015-09-24 23:49:30 +02:00
|
|
|
av_assert1(fdst->max_slice_count == fsrc->max_slice_count);
|
2013-04-27 22:24:14 +02:00
|
|
|
|
2022-09-02 21:51:35 +02:00
|
|
|
ff_progress_frame_replace(&fdst->picture, &fsrc->picture);
|
2025-01-05 15:27:30 +09:00
|
|
|
av_refstruct_replace(&fdst->hwaccel_picture_private,
|
|
|
|
|
fsrc->hwaccel_picture_private);
|
2013-04-27 22:24:14 +02:00
|
|
|
|
2013-04-27 16:15:33 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2015-09-16 22:22:27 -04:00
|
|
|
#endif
|
2013-04-27 16:15:33 +02:00
|
|
|
|
2022-09-02 20:51:24 +02:00
|
|
|
static av_cold int ffv1_decode_close(AVCodecContext *avctx)
|
|
|
|
|
{
|
|
|
|
|
FFV1Context *const s = avctx->priv_data;
|
|
|
|
|
|
2022-09-02 21:51:35 +02:00
|
|
|
ff_progress_frame_unref(&s->picture);
|
2025-01-05 15:27:30 +09:00
|
|
|
av_refstruct_unref(&s->hwaccel_picture_private);
|
|
|
|
|
|
2022-09-02 21:51:35 +02:00
|
|
|
ff_progress_frame_unref(&s->last_picture);
|
2025-01-05 15:27:30 +09:00
|
|
|
av_refstruct_unref(&s->hwaccel_last_picture_private);
|
2025-02-02 22:55:45 -03:00
|
|
|
|
|
|
|
|
ff_ffv1_close(s);
|
2022-09-02 20:51:24 +02:00
|
|
|
|
2025-02-02 22:55:45 -03:00
|
|
|
return 0;
|
2022-09-02 20:51:24 +02:00
|
|
|
}
|
|
|
|
|
|
2022-03-16 21:09:54 +01:00
|
|
|
const FFCodec ff_ffv1_decoder = {
|
|
|
|
|
.p.name = "ffv1",
|
2022-08-29 13:38:02 +02:00
|
|
|
CODEC_LONG_NAME("FFmpeg video codec #1"),
|
2022-03-16 21:09:54 +01:00
|
|
|
.p.type = AVMEDIA_TYPE_VIDEO,
|
|
|
|
|
.p.id = AV_CODEC_ID_FFV1,
|
2012-10-21 14:05:46 +02:00
|
|
|
.priv_data_size = sizeof(FFV1Context),
|
|
|
|
|
.init = decode_init,
|
2022-09-02 20:51:24 +02:00
|
|
|
.close = ffv1_decode_close,
|
2022-03-30 23:28:24 +02:00
|
|
|
FF_CODEC_DECODE_CB(decode_frame),
|
2022-08-29 15:03:21 +02:00
|
|
|
UPDATE_THREAD_CONTEXT(update_thread_context),
|
2022-10-16 14:49:12 +02:00
|
|
|
.p.capabilities = AV_CODEC_CAP_DR1 |
|
2015-07-27 22:21:19 +02:00
|
|
|
AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS,
|
2022-09-02 21:51:35 +02:00
|
|
|
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
|
2025-03-15 16:09:28 -03:00
|
|
|
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
|
2022-09-02 21:51:35 +02:00
|
|
|
FF_CODEC_CAP_USES_PROGRESSFRAMES,
|
2025-01-05 15:27:30 +09:00
|
|
|
.hw_configs = (const AVCodecHWConfigInternal *const []) {
|
2025-03-10 03:04:39 +00:00
|
|
|
#if CONFIG_FFV1_VULKAN_HWACCEL
|
|
|
|
|
HWACCEL_VULKAN(ffv1),
|
|
|
|
|
#endif
|
2025-01-05 15:27:30 +09:00
|
|
|
NULL
|
|
|
|
|
},
|
2012-10-21 14:05:46 +02:00
|
|
|
};
|