Commit 5c83e281e6 for ffmpeg
commit 5c83e281e66c3274c6e868dc4ae4268cebf68d65
Author: James Almer <jamrial@gmail.com>
Date: Mon Oct 19 12:38:46 2026 -0300
avformat/mov: export Alpha type Stream Groups
Signed-off-by: James Almer <jamrial@gmail.com>
diff --git a/libavformat/isom.h b/libavformat/isom.h
index 2af2d73df2..18c2fe41b9 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -315,6 +315,7 @@ typedef struct HEIFItem {
int vflip;
int type;
int is_gainmap;
+ int is_alpha;
int is_idat_relative;
AVExifMetadata ifd;
uint8_t *icc_profile;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index ce68f53268..0a878d8b53 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -9451,9 +9451,13 @@ static int mov_read_auxc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
c->cur_item_id, aux_type.str);
item = get_heif_item(c, c->cur_item_id);
- if (item && (av_stristr(aux_type.str, "hdrgainmap")))
- item->is_gainmap = 1;
-
+ if (item) {
+ if ((av_stristr(aux_type.str, "hdrgainmap")))
+ item->is_gainmap = 1;
+ else if (strstr(aux_type.str, "urn:mpeg:hevc:2015:auxid:1") ||
+ strstr(aux_type.str, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha"))
+ item->is_alpha = 1;
+ }
return 0;
}
@@ -11759,9 +11763,66 @@ fail:
return err;
}
+static int mov_parse_heif_layered_video_auxl_alpha(AVFormatContext *s,
+ HEIFItem *base, HEIFItem *alpha)
+{
+ AVStreamGroupLayeredVideo *layered_video;
+ AVStreamGroup *stg;
+ int err;
+
+ if ((!alpha->st && !alpha->stg) ||
+ (!base->st && !base->stg)) {
+ av_log(s, AV_LOG_WARNING, "HEIF alpha id %d or its base doesn't reference "
+ "a stream or group\n",
+ alpha->item_id);
+ return 0;
+ }
+
+ stg = avformat_stream_group_create(s, AV_STREAM_GROUP_PARAMS_ALPHA, NULL);
+ if (!stg)
+ return AVERROR(ENOMEM);
+
+ stg->id = alpha->item_id;
+ layered_video = stg->params.layered_video;
+
+ layered_video->width = base->width;
+ layered_video->height = base->height;
+ layered_video->el_index = 1;
+
+ av_assert0(!base->st != !base->stg);
+ if (base->st)
+ err = avformat_stream_group_add_stream(stg, base->st);
+ else
+ err = avformat_stream_group_add_stream_group(stg, base->stg);
+ if (err < 0) {
+ if (err == AVERROR(EEXIST))
+ err = AVERROR_INVALIDDATA;
+ return err;
+ }
+
+ av_assert0(!alpha->st != !alpha->stg);
+ if (alpha->st)
+ err = avformat_stream_group_add_stream(stg, alpha->st);
+ else
+ err = avformat_stream_group_add_stream_group(stg, alpha->stg);
+ if (err < 0) {
+ if (err == AVERROR(EEXIST))
+ err = AVERROR_INVALIDDATA;
+ return err;
+ }
+
+ // Apply all references from the base image to the Alpha group
+ err = mov_apply_heif_item_references(s, base, &stg->coded_side_data,
+ &stg->nb_coded_side_data);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
// Parse Apple style Gain Map metadata from Exif values
// See https://developer.apple.com/documentation/appkit/applying-apple-hdr-effect-to-your-photos
-static int mov_parse_heif_layered_video_auxl(AVFormatContext *s,
+static int mov_parse_heif_layered_video_auxl_gmap(AVFormatContext *s,
HEIFItem *base, HEIFItem *gain_map)
{
AVStreamGroupLayeredVideo *layered_video;
@@ -11922,13 +11983,18 @@ static int mov_parse_heif_layered_video(AVFormatContext *s)
av_assert0(ref);
switch(item->iref_to_list[j].type) {
case MKTAG('a','u','x','l'):
- if (!item->is_gainmap)
+ if (item->is_alpha) {
+ err = mov_parse_heif_layered_video_auxl_alpha(s, ref, item);
+ if (err < 0)
+ return err;
break;
-
- err = mov_parse_heif_layered_video_auxl(s, ref, item);
- if (err < 0)
- return err;
- break;
+ }
+ if (item->is_gainmap) {
+ err = mov_parse_heif_layered_video_auxl_gmap(s, ref, item);
+ if (err < 0)
+ return err;
+ break;
+ }
}
}
}