Browse Source

fftools/ffmpeg_demux: create a filtegraph to merge HEIF tiles automatically

Signed-off-by: James Almer <jamrial@gmail.com>
James Almer 1 month ago
parent
commit
5ff8395e78
2 changed files with 94 additions and 0 deletions
  1. 88 0
      fftools/ffmpeg_demux.c
  2. 6 0
      fftools/ffmpeg_mux_init.c

+ 88 - 0
fftools/ffmpeg_demux.c

@@ -1641,14 +1641,102 @@ static DemuxStreamGroup *demux_stream_group_alloc(Demuxer *d, AVStreamGroup *stg
     return dsg;
     return dsg;
 }
 }
 
 
+static int istg_parse_tile_grid(const OptionsContext *o, Demuxer *d, InputStreamGroup *istg)
+{
+    InputFile *f = &d->f;
+    AVFormatContext *ic = d->f.ctx;
+    AVStreamGroup *stg = istg->stg;
+    const AVStreamGroupTileGrid *tg = stg->params.tile_grid;
+    OutputFilterOptions opts;
+    AVBPrint bp;
+    char *graph_str;
+    int autorotate = 1;
+    const char *apply_cropping = NULL;
+    int  ret;
+
+    if (tg->nb_tiles == 1)
+        return 0;
+
+    memset(&opts, 0, sizeof(opts));
+
+    opt_match_per_stream_group_int(istg, &o->autorotate, ic, stg, &autorotate);
+    if (autorotate)
+        opts.flags |= OFILTER_FLAG_AUTOROTATE;
+
+    opts.flags |= OFILTER_FLAG_CROP;
+    opt_match_per_stream_group_str(istg, &o->apply_cropping, ic, stg, &apply_cropping);
+    if (apply_cropping) {
+        char *p;
+        int crop = strtol(apply_cropping, &p, 0);
+        if (*p)
+            return AVERROR(EINVAL);
+        if (!crop)
+            opts.flags &= ~OFILTER_FLAG_CROP;
+    }
+
+    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+    for (int i = 0; i < tg->nb_tiles; i++)
+        av_bprintf(&bp, "[%d:g:%d:%d]", f->index, stg->index, tg->offsets[i].idx);
+    av_bprintf(&bp, "xstack=inputs=%d:layout=", tg->nb_tiles);
+    for (int i = 0; i < tg->nb_tiles - 1; i++)
+        av_bprintf(&bp, "%d_%d|", tg->offsets[i].horizontal,
+                                  tg->offsets[i].vertical);
+    av_bprintf(&bp, "%d_%d:fill=0x%02X%02X%02X@0x%02X", tg->offsets[tg->nb_tiles - 1].horizontal,
+                                                        tg->offsets[tg->nb_tiles - 1].vertical,
+                                                        tg->background[0], tg->background[1],
+                                                        tg->background[2], tg->background[3]);
+    av_bprintf(&bp, "[%d:g:%d]", f->index, stg->index);
+    ret = av_bprint_finalize(&bp, &graph_str);
+    if (ret < 0)
+        return ret;
+
+    if (tg->coded_width != tg->width || tg->coded_height != tg->height) {
+        opts.crop_top    = tg->vertical_offset;
+        opts.crop_bottom = tg->coded_height - tg->height - tg->vertical_offset;
+        opts.crop_left   = tg->horizontal_offset;
+        opts.crop_right  = tg->coded_width - tg->width - tg->horizontal_offset;
+    }
+
+    for (int i = 0; i < tg->nb_coded_side_data; i++) {
+        const AVPacketSideData *sd = &tg->coded_side_data[i];
+
+        ret = av_packet_side_data_to_frame(&opts.side_data, &opts.nb_side_data, sd, 0);
+        if (ret < 0 && ret != AVERROR(EINVAL))
+            return ret;
+    }
+
+    ret = fg_create(NULL, graph_str, d->sch, &opts);
+    if (ret < 0)
+        return ret;
+
+    istg->fg = filtergraphs[nb_filtergraphs-1];
+    istg->fg->is_internal = 1;
+
+    return 0;
+}
+
 static int istg_add(const OptionsContext *o, Demuxer *d, AVStreamGroup *stg)
 static int istg_add(const OptionsContext *o, Demuxer *d, AVStreamGroup *stg)
 {
 {
     DemuxStreamGroup *dsg;
     DemuxStreamGroup *dsg;
+    InputStreamGroup *istg;
+    int ret;
 
 
     dsg = demux_stream_group_alloc(d, stg);
     dsg = demux_stream_group_alloc(d, stg);
     if (!dsg)
     if (!dsg)
         return AVERROR(ENOMEM);
         return AVERROR(ENOMEM);
 
 
+    istg = &dsg->istg;
+
+    switch (stg->type) {
+    case AV_STREAM_GROUP_PARAMS_TILE_GRID:
+        ret = istg_parse_tile_grid(o, d, istg);
+        if (ret < 0)
+            return ret;
+        break;
+    default:
+        break;
+    }
+
     return 0;
     return 0;
 }
 }
 
 

+ 6 - 0
fftools/ffmpeg_mux_init.c

@@ -1630,6 +1630,12 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o)
             }
             }
 
 
             switch (istg->stg->type) {
             switch (istg->stg->type) {
+            case AV_STREAM_GROUP_PARAMS_TILE_GRID: {
+                const AVStreamGroupTileGrid *tg = istg->stg->params.tile_grid;
+                score += tg->width * (int64_t)tg->height
+                           + 5000000*!!(istg->stg->disposition & AV_DISPOSITION_DEFAULT);
+                break;
+            }
             default:
             default:
                 continue;
                 continue;
             }
             }