PR #20862 opened by Lynne URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20862 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20862.patch
This commit adds a few utilities, and fixes decoding of streams where the frame size changes. >From a09e8c5ac07c68b6cc8f8a85a2a7063909e7ec8b Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Wed, 5 Nov 2025 20:25:31 +0100 Subject: [PATCH 1/7] prores: call ff_get_format if width and height change The issue is that hardware decoders may have some state they depend on, which would get broken if the dimensions change. --- libavcodec/proresdec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libavcodec/proresdec.c b/libavcodec/proresdec.c index 40c15a0c85..5c6b505527 100644 --- a/libavcodec/proresdec.c +++ b/libavcodec/proresdec.c @@ -185,7 +185,7 @@ static av_cold int decode_init(AVCodecContext *avctx) static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, const int data_size, AVCodecContext *avctx) { - int hdr_size, width, height, flags; + int hdr_size, width, height, flags, dimensions_changed = 0; int version; const uint8_t *ptr; enum AVPixelFormat pix_fmt; @@ -214,6 +214,7 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, avctx->width, avctx->height, width, height); if ((ret = ff_set_dimensions(avctx, width, height)) < 0) return ret; + dimensions_changed = 1; } ctx->frame_type = (buf[12] >> 2) & 3; @@ -250,7 +251,7 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, } } - if (pix_fmt != ctx->pix_fmt) { + if (pix_fmt != ctx->pix_fmt || dimensions_changed) { #define HWACCEL_MAX (CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL + CONFIG_PRORES_VULKAN_HWACCEL) #if HWACCEL_MAX enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts; -- 2.49.1 >From e6e8d894f8e47d862cf8d94d17cce410f1c19d6f Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Wed, 5 Nov 2025 20:29:33 +0100 Subject: [PATCH 2/7] prores_raw: call ff_get_format if width and height change --- libavcodec/prores_raw.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libavcodec/prores_raw.c b/libavcodec/prores_raw.c index 0298956efd..65e0576619 100644 --- a/libavcodec/prores_raw.c +++ b/libavcodec/prores_raw.c @@ -329,7 +329,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt) { - int ret; + int ret, dimensions_changed = 0; ProResRAWContext *s = avctx->priv_data; DECLARE_ALIGNED(32, uint8_t, qmat)[64]; memset(qmat, 1, 64); @@ -390,13 +390,14 @@ static int decode_frame(AVCodecContext *avctx, avctx->width, avctx->height, w, h); if ((ret = ff_set_dimensions(avctx, w, h)) < 0) return ret; + dimensions_changed = 1; } avctx->coded_width = FFALIGN(w, 16); avctx->coded_height = FFALIGN(h, 16); enum AVPixelFormat pix_fmt = AV_PIX_FMT_BAYER_RGGB16; - if (pix_fmt != s->pix_fmt) { + if (pix_fmt != s->pix_fmt || dimensions_changed) { s->pix_fmt = pix_fmt; ret = get_pixel_format(avctx, pix_fmt); -- 2.49.1 >From e36c7d4bc52c2ca9c180d92854e851e5bacf46bc Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Wed, 5 Nov 2025 20:31:23 +0100 Subject: [PATCH 3/7] ffv1dec: call ff_get_format if width and height change --- libavcodec/ffv1.h | 1 + libavcodec/ffv1dec.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h index d6f25737f5..adf76b0644 100644 --- a/libavcodec/ffv1.h +++ b/libavcodec/ffv1.h @@ -139,6 +139,7 @@ typedef struct FFV1Context { uint32_t crcref; enum AVPixelFormat pix_fmt; enum AVPixelFormat configured_pix_fmt; + int configured_width, configured_height; const AVFrame *cur_enc_frame; int plane_count; diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c index 3d67798961..a70cd74af4 100644 --- a/libavcodec/ffv1dec.c +++ b/libavcodec/ffv1dec.c @@ -507,11 +507,15 @@ static int read_header(FFV1Context *f, RangeCoder *c) if (ret < 0) return ret; - if (f->configured_pix_fmt != f->pix_fmt) { + if (f->configured_pix_fmt != f->pix_fmt || + f->configured_width != f->avctx->width || + f->configured_height != f->avctx->height) { f->avctx->pix_fmt = get_pixel_format(f); if (f->avctx->pix_fmt < 0) return AVERROR(EINVAL); f->configured_pix_fmt = f->pix_fmt; + f->configured_width = f->avctx->width; + f->configured_height = f->avctx->height; } ff_dlog(f->avctx, "%d %d %d\n", -- 2.49.1 >From bf599bd2b37fb11e3ea99951d8afc076c9c18645 Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Tue, 4 Nov 2025 11:40:07 +0100 Subject: [PATCH 4/7] vulkan/ffv1: use u32vec2 for slice offsets Simplifies calculations slightly. --- libavcodec/vulkan/ffv1_dec_setup.comp | 4 ++-- libavcodec/vulkan_ffv1.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libavcodec/vulkan/ffv1_dec_setup.comp b/libavcodec/vulkan/ffv1_dec_setup.comp index 5da09df21c..fd297cb70a 100644 --- a/libavcodec/vulkan/ffv1_dec_setup.comp +++ b/libavcodec/vulkan/ffv1_dec_setup.comp @@ -114,8 +114,8 @@ void main(void) { const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x; - u8buf bs = u8buf(slice_data + slice_offsets[2*slice_idx + 0]); - uint32_t slice_size = slice_offsets[2*slice_idx + 1]; + u8buf bs = u8buf(slice_data + slice_offsets[slice_idx].x); + uint32_t slice_size = slice_offsets[slice_idx].y; rac_init_dec(slice_ctx[slice_idx].c, bs, slice_size); diff --git a/libavcodec/vulkan_ffv1.c b/libavcodec/vulkan_ffv1.c index b02bc71683..1ed9d7dd6c 100644 --- a/libavcodec/vulkan_ffv1.c +++ b/libavcodec/vulkan_ffv1.c @@ -697,7 +697,7 @@ static int init_setup_shader(FFV1Context *f, FFVulkanContext *s, .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .stages = VK_SHADER_STAGE_COMPUTE_BIT, .mem_quali = "readonly", - .buf_content = "uint32_t slice_offsets", + .buf_content = "u32vec2 slice_offsets", .buf_elems = 2*f->max_slice_count, }, { -- 2.49.1 >From 9ac4f6562f790636a23f08004f0f10a306219096 Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Thu, 6 Nov 2025 23:30:13 +0100 Subject: [PATCH 5/7] ffv1enc_vulkan: only use native image representation This was done for an unknown reason, and for whatever reason, non-rgb 8+ bit formats were broken by this. --- libavcodec/ffv1enc_vulkan.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/libavcodec/ffv1enc_vulkan.c b/libavcodec/ffv1enc_vulkan.c index d2908a09a9..86521af6c5 100644 --- a/libavcodec/ffv1enc_vulkan.c +++ b/libavcodec/ffv1enc_vulkan.c @@ -96,9 +96,6 @@ typedef struct VulkanEncodeFFv1Context { /* Intermediate frame pool */ AVBufferRef *intermediate_frames_ref; - /* Representation mode */ - enum FFVkShaderRepFormat rep_fmt; - int num_h_slices; int num_v_slices; int force_pcm; @@ -380,7 +377,7 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext *avctx, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); RET(ff_vk_create_imageviews(&fv->s, exec, src_views, src, - fv->rep_fmt)); + FF_VK_REP_NATIVE)); ff_vk_frame_barrier(&fv->s, exec, src, img_bar, &nb_img_bar, VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, @@ -402,7 +399,7 @@ static int vulkan_encode_ffv1_submit_frame(AVCodecContext *avctx, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); RET(ff_vk_create_imageviews(&fv->s, exec, tmp_views, tmp, - fv->rep_fmt)); + FF_VK_REP_NATIVE)); } /* Setup shader */ @@ -1084,7 +1081,7 @@ static int init_rct_search_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv) .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .dimensions = 2, .mem_layout = ff_vk_shader_rep_fmt(fv->s.frames->sw_format, - fv->rep_fmt), + FF_VK_REP_NATIVE), .elems = av_pix_fmt_count_planes(fv->s.frames->sw_format), .mem_quali = "readonly", .stages = VK_SHADER_STAGE_COMPUTE_BIT, @@ -1169,7 +1166,7 @@ static int init_setup_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv) .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .dimensions = 2, .mem_layout = ff_vk_shader_rep_fmt(fv->s.frames->sw_format, - fv->rep_fmt), + FF_VK_REP_NATIVE), .elems = av_pix_fmt_count_planes(fv->s.frames->sw_format), .mem_quali = "readonly", .stages = VK_SHADER_STAGE_COMPUTE_BIT, @@ -1355,7 +1352,7 @@ static int init_encode_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv) .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .dimensions = 2, .mem_layout = ff_vk_shader_rep_fmt(fv->s.frames->sw_format, - fv->rep_fmt), + FF_VK_REP_NATIVE), .elems = av_pix_fmt_count_planes(fv->s.frames->sw_format), .mem_quali = "readonly", .stages = VK_SHADER_STAGE_COMPUTE_BIT, @@ -1610,12 +1607,6 @@ static av_cold int vulkan_encode_ffv1_init(AVCodecContext *avctx) fv->is_rgb = !(f->colorspace == 0 && avctx->sw_pix_fmt != AV_PIX_FMT_YA8) && !(avctx->sw_pix_fmt == AV_PIX_FMT_YA8); - /* bits_per_raw_sample use regular unsigned representation, - * but in higher bit depths, the data is casted to int16_t */ - fv->rep_fmt = FF_VK_REP_UINT; - if (!fv->is_rgb && f->bits_per_raw_sample > 8) - fv->rep_fmt = FF_VK_REP_INT; - /* Init rct search shader */ fv->optimize_rct = fv->is_rgb && f->version >= 4 && !fv->force_pcm && fv->optimize_rct; -- 2.49.1 >From 16d8cb3b5e73a008582b1a0e523dfd5166c284d5 Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Wed, 5 Nov 2025 10:31:18 +0100 Subject: [PATCH 6/7] vulkan: add a function to flush or invalidate a buffer Just for convenience. --- libavutil/vulkan.c | 32 ++++++++++++++++++++++++++++++++ libavutil/vulkan.h | 7 +++++++ 2 files changed, 39 insertions(+) diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c index ef755ad6f7..5e23d78e1f 100644 --- a/libavutil/vulkan.c +++ b/libavutil/vulkan.c @@ -1167,6 +1167,37 @@ int ff_vk_map_buffers(FFVulkanContext *s, FFVkBuffer **buf, uint8_t *mem[], return 0; } +int ff_vk_flush_buffer(FFVulkanContext *s, FFVkBuffer *buf, + size_t offset, size_t mem_size, + int flush) +{ + VkResult ret; + FFVulkanFunctions *vk = &s->vkfn; + + if (buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) + return 0; + + const VkMappedMemoryRange flush_data = { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = buf->mem, + .offset = buf->virtual_offset + offset, + .size = mem_size, + }; + + if (flush) + ret = vk->FlushMappedMemoryRanges(s->hwctx->act_dev, 1, &flush_data); + else + ret = vk->InvalidateMappedMemoryRanges(s->hwctx->act_dev, 1, &flush_data); + + if (ret != VK_SUCCESS) { + av_log(s, AV_LOG_ERROR, "Failed to flush memory: %s\n", + ff_vk_ret2str(ret)); + return AVERROR_EXTERNAL; + } + + return 0; +} + int ff_vk_unmap_buffers(FFVulkanContext *s, FFVkBuffer **buf, int nb_buffers, int flush) { @@ -1181,6 +1212,7 @@ int ff_vk_unmap_buffers(FFVulkanContext *s, FFVkBuffer **buf, int nb_buffers, const VkMappedMemoryRange flush_buf = { .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, .memory = buf[i]->mem, + .offset = buf[i]->virtual_offset, .size = VK_WHOLE_SIZE, }; diff --git a/libavutil/vulkan.h b/libavutil/vulkan.h index e1c9a5792f..bdc20e4645 100644 --- a/libavutil/vulkan.h +++ b/libavutil/vulkan.h @@ -523,6 +523,13 @@ int ff_vk_create_buf(FFVulkanContext *s, FFVkBuffer *buf, size_t size, void *pNext, void *alloc_pNext, VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags); +/** + * Flush or invalidate a single buffer, with a given size and offset. + */ +int ff_vk_flush_buffer(FFVulkanContext *s, FFVkBuffer *buf, + size_t offset, size_t mem_size, + int flush); + /** * Buffer management code. */ -- 2.49.1 >From ee00bfe9d34769a0784b21295ab5ee4a3dd80307 Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Wed, 5 Nov 2025 15:29:57 +0100 Subject: [PATCH 7/7] vulkan: allow arrays of buffers Could be useful. --- libavutil/vulkan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c index 5e23d78e1f..3633cb5516 100644 --- a/libavutil/vulkan.c +++ b/libavutil/vulkan.c @@ -2580,10 +2580,11 @@ print: GLSLA("%s", desc[i].buf_content); } GLSLA("\n}"); - } else if (desc[i].elems > 0) { - GLSLA("[%i]", desc[i].elems); } + if (desc[i].elems > 0) + GLSLA("[%i]", desc[i].elems); + GLSLA(";"); GLSLA("\n"); } -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
