Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@
/libavfilter/vulkan/*.c
/.*/
!/.forgejo/
reference.heic
65 changes: 65 additions & 0 deletions fftools/ffmpeg_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ typedef struct FilterGraphPriv {

Scheduler *sch;
unsigned sch_idx;

// Metadata for stream group information (e.g., HEIF tiles)
AVDictionary *metadata;
} FilterGraphPriv;

static FilterGraphPriv *fgp_from_fg(FilterGraph *fg)
Expand Down Expand Up @@ -1039,6 +1042,7 @@ void fg_free(FilterGraph **pfg)

av_frame_free(&fgp->frame);
av_frame_free(&fgp->frame_enc);
av_dict_free(&fgp->metadata);

av_freep(pfg);
}
Expand Down Expand Up @@ -1333,6 +1337,63 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter)
}
}

// Extract HEIF metadata for auto-compositor filter when using stream group syntax
if ((ss.stream_list == STREAM_LIST_GROUP_IDX || ss.stream_list == STREAM_LIST_GROUP_ID) &&
ifilter->graph && strstr(ifilter->graph->graph_desc, "heif_auto_compositor")) {

AVStreamGroup *g = NULL;
if (ss.stream_list == STREAM_LIST_GROUP_IDX &&
ss.list_id >= 0 && ss.list_id < s->nb_stream_groups) {
g = s->stream_groups[ss.list_id];
} else if (ss.stream_list == STREAM_LIST_GROUP_ID) {
for (unsigned i = 0; i < s->nb_stream_groups; i++) {
if (ss.list_id == s->stream_groups[i]->id) {
g = s->stream_groups[i];
break;
}
}
}

if (g && g->type == AV_STREAM_GROUP_PARAMS_TILE_GRID) {
AVStreamGroupTileGrid *tile = g->params.tile_grid;

av_log(fg, AV_LOG_INFO, "HEIF stream group %d found: %d tiles, canvas %dx%d, presentation %dx%d\n",
ss.list_id, tile->nb_tiles, tile->coded_width, tile->coded_height, tile->width, tile->height);

// Store metadata with stream group specific keys for access by the filter
FilterGraphPriv *fgp = fgp_from_fg(ifilter->graph);
char key_prefix[32];
snprintf(key_prefix, sizeof(key_prefix), "heif_g%d", (int)ss.list_id);

av_dict_set(&fgp->metadata, av_asprintf("%s_canvas_w", key_prefix), av_asprintf("%d", tile->coded_width), AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
av_dict_set(&fgp->metadata, av_asprintf("%s_canvas_h", key_prefix), av_asprintf("%d", tile->coded_height), AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
av_dict_set(&fgp->metadata, av_asprintf("%s_presentation_w", key_prefix), av_asprintf("%d", tile->width), AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
av_dict_set(&fgp->metadata, av_asprintf("%s_presentation_h", key_prefix), av_asprintf("%d", tile->height), AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
av_dict_set(&fgp->metadata, av_asprintf("%s_horizontal_offset", key_prefix), av_asprintf("%d", tile->horizontal_offset), AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
av_dict_set(&fgp->metadata, av_asprintf("%s_vertical_offset", key_prefix), av_asprintf("%d", tile->vertical_offset), AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
av_dict_set(&fgp->metadata, av_asprintf("%s_total_tiles", key_prefix), av_asprintf("%d", tile->nb_tiles), AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);

// Store the stream group index for the filter to identify which group it's using
av_dict_set(&fgp->metadata, "heif_active_group", av_asprintf("%d", (int)ss.list_id), AV_DICT_DONT_STRDUP_VAL);

// Store tile positioning information using the offsets array
for (unsigned t = 0; t < tile->nb_tiles && t < g->nb_streams; t++) {
char key[64];

snprintf(key, sizeof(key), "%s_tile_%u_x", key_prefix, t);
av_dict_set(&fgp->metadata, key, av_asprintf("%d", tile->offsets[t].horizontal), AV_DICT_DONT_STRDUP_VAL);

snprintf(key, sizeof(key), "%s_tile_%u_y", key_prefix, t);
av_dict_set(&fgp->metadata, key, av_asprintf("%d", tile->offsets[t].vertical), AV_DICT_DONT_STRDUP_VAL);

snprintf(key, sizeof(key), "%s_tile_%u_index", key_prefix, t);
av_dict_set(&fgp->metadata, key, av_asprintf("%u", t), AV_DICT_DONT_STRDUP_VAL);
}

av_log(fg, AV_LOG_INFO, "Stored HEIF stream group %d metadata in filter graph for auto-compositor\n", (int)ss.list_id);
}
}

for (i = 0; i < s->nb_streams; i++) {
enum AVMediaType stream_type = s->streams[i]->codecpar->codec_type;
if (stream_type != type &&
Expand Down Expand Up @@ -1915,6 +1976,10 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt)
fgt->graph = avfilter_graph_alloc();
if (!fgt->graph)
return AVERROR(ENOMEM);

// Pass HEIF metadata to the filter graph opaque field for filter access
if (fgp->metadata)
fgt->graph->opaque = fgp->metadata;

if (simple) {
OutputFilterPriv *ofp = ofp_from_ofilter(fg->outputs[0]);
Expand Down
10 changes: 10 additions & 0 deletions libavcodec/hevc/hevcdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -3879,6 +3879,16 @@ static int hevc_receive_frame(AVCodecContext *avctx, AVFrame *frame)
if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN))
av_frame_remove_side_data(frame, AV_FRAME_DATA_FILM_GRAIN_PARAMS);

// Propagate packet metadata to frame metadata
av_log(avctx, AV_LOG_DEBUG, "HEVC decoder: Attempting to propagate packet metadata (packet has %d side data entries)\n", avpkt->side_data_elems);
ret = ff_decode_frame_props_from_pkt(avctx, frame, avpkt);
if (ret < 0) {
av_log(avctx, AV_LOG_WARNING, "Failed to propagate packet metadata to frame\n");
} else {
av_log(avctx, AV_LOG_DEBUG, "HEVC decoder: Successfully propagated metadata, frame now has %d metadata entries\n",
frame->metadata ? av_dict_count(frame->metadata) : 0);
}

return 0;
}

Expand Down
1 change: 1 addition & 0 deletions libavfilter/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ OBJS-$(CONFIG_GRAYWORLD_FILTER) += vf_grayworld.o
OBJS-$(CONFIG_GREYEDGE_FILTER) += vf_colorconstancy.o
OBJS-$(CONFIG_GUIDED_FILTER) += vf_guided.o framesync.o
OBJS-$(CONFIG_HALDCLUT_FILTER) += vf_lut3d.o framesync.o
OBJS-$(CONFIG_HEIF_AUTO_COMPOSITOR_FILTER) += vf_heif_tile_compositor_auto.o framesync.o
OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o
OBJS-$(CONFIG_HFLIP_VULKAN_FILTER) += vf_flip_vulkan.o vulkan.o
OBJS-$(CONFIG_HISTEQ_FILTER) += vf_histeq.o
Expand Down
1 change: 1 addition & 0 deletions libavfilter/allfilters.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ extern const FFFilter ff_vf_grayworld;
extern const FFFilter ff_vf_greyedge;
extern const FFFilter ff_vf_guided;
extern const FFFilter ff_vf_haldclut;
extern const FFFilter ff_vf_heif_auto_compositor;
extern const FFFilter ff_vf_hflip;
extern const FFFilter ff_vf_hflip_vulkan;
extern const FFFilter ff_vf_histeq;
Expand Down
Loading