You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-10-06 05:47:18 +02:00
avcodec/cbs_apv: store derived tile information in a per frame basis
If a single fragment contains more than one frame unit, the tile information stored
in the private context will only correspond to one of them.
Fixes: crash (out of array access)
Fixes: 435489659/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_APV_fuzzer-6194885205229568
Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 4b39d776c3
)
This commit is contained in:
@@ -35,6 +35,16 @@
|
|||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct APVDerivedTileInfo {
|
||||||
|
uint8_t tile_cols;
|
||||||
|
uint8_t tile_rows;
|
||||||
|
uint16_t num_tiles;
|
||||||
|
// The spec uses an extra element on the end of these arrays
|
||||||
|
// not corresponding to any tile.
|
||||||
|
uint16_t col_starts[APV_MAX_TILE_COLS + 1];
|
||||||
|
uint16_t row_starts[APV_MAX_TILE_ROWS + 1];
|
||||||
|
} APVDerivedTileInfo;
|
||||||
|
|
||||||
typedef struct APVDecodeContext {
|
typedef struct APVDecodeContext {
|
||||||
CodedBitstreamContext *cbc;
|
CodedBitstreamContext *cbc;
|
||||||
APVDSPContext dsp;
|
APVDSPContext dsp;
|
||||||
@@ -184,7 +194,7 @@ static int apv_decode_tile_component(AVCodecContext *avctx, void *data,
|
|||||||
APVRawFrame *input = data;
|
APVRawFrame *input = data;
|
||||||
APVDecodeContext *apv = avctx->priv_data;
|
APVDecodeContext *apv = avctx->priv_data;
|
||||||
const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data;
|
const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data;
|
||||||
const APVDerivedTileInfo *tile_info = &apv_cbc->tile_info;
|
const APVDerivedTileInfo *tile_info = &apv->tile_info;
|
||||||
|
|
||||||
int tile_index = job / apv_cbc->num_comp;
|
int tile_index = job / apv_cbc->num_comp;
|
||||||
int comp_index = job % apv_cbc->num_comp;
|
int comp_index = job % apv_cbc->num_comp;
|
||||||
@@ -297,12 +307,38 @@ fail:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void apv_derive_tile_info(APVDerivedTileInfo *ti,
|
||||||
|
const APVRawFrameHeader *fh)
|
||||||
|
{
|
||||||
|
int frame_width_in_mbs = (fh->frame_info.frame_width + (APV_MB_WIDTH - 1)) >> 4;
|
||||||
|
int frame_height_in_mbs = (fh->frame_info.frame_height + (APV_MB_HEIGHT - 1)) >> 4;
|
||||||
|
int start_mb, i;
|
||||||
|
|
||||||
|
start_mb = 0;
|
||||||
|
for (i = 0; start_mb < frame_width_in_mbs; i++) {
|
||||||
|
ti->col_starts[i] = start_mb * APV_MB_WIDTH;
|
||||||
|
start_mb += fh->tile_info.tile_width_in_mbs;
|
||||||
|
}
|
||||||
|
ti->col_starts[i] = frame_width_in_mbs * APV_MB_WIDTH;
|
||||||
|
ti->tile_cols = i;
|
||||||
|
|
||||||
|
start_mb = 0;
|
||||||
|
for (i = 0; start_mb < frame_height_in_mbs; i++) {
|
||||||
|
ti->row_starts[i] = start_mb * APV_MB_HEIGHT;
|
||||||
|
start_mb += fh->tile_info.tile_height_in_mbs;
|
||||||
|
}
|
||||||
|
ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT;
|
||||||
|
ti->tile_rows = i;
|
||||||
|
|
||||||
|
ti->num_tiles = ti->tile_cols * ti->tile_rows;
|
||||||
|
}
|
||||||
|
|
||||||
static int apv_decode(AVCodecContext *avctx, AVFrame *output,
|
static int apv_decode(AVCodecContext *avctx, AVFrame *output,
|
||||||
APVRawFrame *input)
|
APVRawFrame *input)
|
||||||
{
|
{
|
||||||
APVDecodeContext *apv = avctx->priv_data;
|
APVDecodeContext *apv = avctx->priv_data;
|
||||||
const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data;
|
const AVPixFmtDescriptor *desc = NULL;
|
||||||
const APVDerivedTileInfo *tile_info = &apv_cbc->tile_info;
|
APVDerivedTileInfo *tile_info = &apv->tile_info;
|
||||||
int err, job_count;
|
int err, job_count;
|
||||||
|
|
||||||
err = apv_decode_check_format(avctx, &input->frame_header);
|
err = apv_decode_check_format(avctx, &input->frame_header);
|
||||||
@@ -311,6 +347,9 @@ static int apv_decode(AVCodecContext *avctx, AVFrame *output,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
desc = av_pix_fmt_desc_get(avctx->pix_fmt);
|
||||||
|
av_assert0(desc);
|
||||||
|
|
||||||
err = ff_thread_get_buffer(avctx, output, 0);
|
err = ff_thread_get_buffer(avctx, output, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
@@ -318,9 +357,11 @@ static int apv_decode(AVCodecContext *avctx, AVFrame *output,
|
|||||||
apv->output_frame = output;
|
apv->output_frame = output;
|
||||||
atomic_store_explicit(&apv->tile_errors, 0, memory_order_relaxed);
|
atomic_store_explicit(&apv->tile_errors, 0, memory_order_relaxed);
|
||||||
|
|
||||||
|
apv_derive_tile_info(tile_info, &input->frame_header);
|
||||||
|
|
||||||
// Each component within a tile is independent of every other,
|
// Each component within a tile is independent of every other,
|
||||||
// so we can decode all in parallel.
|
// so we can decode all in parallel.
|
||||||
job_count = tile_info->num_tiles * apv_cbc->num_comp;
|
job_count = tile_info->num_tiles * desc->nb_components;
|
||||||
|
|
||||||
avctx->execute2(avctx, apv_decode_tile_component,
|
avctx->execute2(avctx, apv_decode_tile_component,
|
||||||
input, NULL, job_count);
|
input, NULL, job_count);
|
||||||
|
@@ -37,33 +37,18 @@ static int cbs_apv_get_num_comp(const APVRawFrameHeader *fh)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cbs_apv_derive_tile_info(APVDerivedTileInfo *ti,
|
static void cbs_apv_derive_tile_info(CodedBitstreamContext *ctx,
|
||||||
const APVRawFrameHeader *fh)
|
const APVRawFrameHeader *fh)
|
||||||
{
|
{
|
||||||
|
CodedBitstreamAPVContext *priv = ctx->priv_data;
|
||||||
int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16;
|
int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16;
|
||||||
int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16;
|
int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16;
|
||||||
int start_mb, i;
|
int tile_cols = (frame_width_in_mbs + fh->tile_info.tile_width_in_mbs - 1) / fh->tile_info.tile_width_in_mbs;
|
||||||
|
int tile_rows = (frame_height_in_mbs + fh->tile_info.tile_height_in_mbs - 1) / fh->tile_info.tile_height_in_mbs;
|
||||||
|
|
||||||
start_mb = 0;
|
av_assert0(tile_cols <= APV_MAX_TILE_COLS && tile_rows <= APV_MAX_TILE_ROWS);
|
||||||
for (i = 0; start_mb < frame_width_in_mbs; i++) {
|
|
||||||
ti->col_starts[i] = start_mb * APV_MB_WIDTH;
|
|
||||||
start_mb += fh->tile_info.tile_width_in_mbs;
|
|
||||||
}
|
|
||||||
av_assert0(i <= APV_MAX_TILE_COLS);
|
|
||||||
ti->col_starts[i] = frame_width_in_mbs * APV_MB_WIDTH;
|
|
||||||
ti->tile_cols = i;
|
|
||||||
|
|
||||||
start_mb = 0;
|
priv->num_tiles = tile_cols * tile_rows;
|
||||||
for (i = 0; start_mb < frame_height_in_mbs; i++) {
|
|
||||||
av_assert0(i < APV_MAX_TILE_ROWS);
|
|
||||||
ti->row_starts[i] = start_mb * APV_MB_HEIGHT;
|
|
||||||
start_mb += fh->tile_info.tile_height_in_mbs;
|
|
||||||
}
|
|
||||||
av_assert0(i <= APV_MAX_TILE_ROWS);
|
|
||||||
ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT;
|
|
||||||
ti->tile_rows = i;
|
|
||||||
|
|
||||||
ti->num_tiles = ti->tile_cols * ti->tile_rows;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -187,21 +187,11 @@ typedef struct APVRawMetadata {
|
|||||||
} APVRawMetadata;
|
} APVRawMetadata;
|
||||||
|
|
||||||
|
|
||||||
typedef struct APVDerivedTileInfo {
|
|
||||||
uint8_t tile_cols;
|
|
||||||
uint8_t tile_rows;
|
|
||||||
uint16_t num_tiles;
|
|
||||||
// The spec uses an extra element on the end of these arrays
|
|
||||||
// not corresponding to any tile.
|
|
||||||
uint16_t col_starts[APV_MAX_TILE_COLS + 1];
|
|
||||||
uint16_t row_starts[APV_MAX_TILE_ROWS + 1];
|
|
||||||
} APVDerivedTileInfo;
|
|
||||||
|
|
||||||
typedef struct CodedBitstreamAPVContext {
|
typedef struct CodedBitstreamAPVContext {
|
||||||
int bit_depth;
|
int bit_depth;
|
||||||
int num_comp;
|
int num_comp;
|
||||||
|
|
||||||
APVDerivedTileInfo tile_info;
|
uint16_t num_tiles;
|
||||||
} CodedBitstreamAPVContext;
|
} CodedBitstreamAPVContext;
|
||||||
|
|
||||||
#endif /* AVCODEC_CBS_APV_H */
|
#endif /* AVCODEC_CBS_APV_H */
|
||||||
|
@@ -128,10 +128,10 @@ static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw,
|
|||||||
|
|
||||||
ub(1, tile_size_present_in_fh_flag);
|
ub(1, tile_size_present_in_fh_flag);
|
||||||
|
|
||||||
cbs_apv_derive_tile_info(&priv->tile_info, fh);
|
cbs_apv_derive_tile_info(ctx, fh);
|
||||||
|
|
||||||
if (current->tile_size_present_in_fh_flag) {
|
if (current->tile_size_present_in_fh_flag) {
|
||||||
for (int t = 0; t < priv->tile_info.num_tiles; t++) {
|
for (int t = 0; t < priv->num_tiles; t++) {
|
||||||
us(32, tile_size_in_fh[t], 10, MAX_UINT_BITS(32), 1, t);
|
us(32, tile_size_in_fh[t], 10, MAX_UINT_BITS(32), 1, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,7 +262,7 @@ static int FUNC(frame)(CodedBitstreamContext *ctx, RWContext *rw,
|
|||||||
|
|
||||||
CHECK(FUNC(frame_header)(ctx, rw, ¤t->frame_header));
|
CHECK(FUNC(frame_header)(ctx, rw, ¤t->frame_header));
|
||||||
|
|
||||||
for (int t = 0; t < priv->tile_info.num_tiles; t++) {
|
for (int t = 0; t < priv->num_tiles; t++) {
|
||||||
us(32, tile_size[t], 10, MAX_UINT_BITS(32), 1, t);
|
us(32, tile_size[t], 10, MAX_UINT_BITS(32), 1, t);
|
||||||
|
|
||||||
CHECK(FUNC(tile)(ctx, rw, ¤t->tile[t],
|
CHECK(FUNC(tile)(ctx, rw, ¤t->tile[t],
|
||||||
|
Reference in New Issue
Block a user