소스 검색

fftools/ffmpeg_filter: handle metadata from stream group in relevant the filtergraphs

Signed-off-by: James Almer <jamrial@gmail.com>
James Almer 1 개월 전
부모
커밋
433d18a1d9
3개의 변경된 파일93개의 추가작업 그리고 7개의 파일을 삭제
  1. 12 1
      fftools/ffmpeg.h
  2. 80 5
      fftools/ffmpeg_filter.c
  3. 1 1
      fftools/ffmpeg_opt.c

+ 12 - 1
fftools/ffmpeg.h

@@ -300,6 +300,8 @@ enum OFilterFlags {
     // produce 24-bit audio
     OFILTER_FLAG_AUDIO_24BIT        = (1 << 1),
     OFILTER_FLAG_AUTOSCALE          = (1 << 2),
+    OFILTER_FLAG_AUTOROTATE         = (1 << 3),
+    OFILTER_FLAG_CROP               = (1 << 4),
 };
 
 typedef struct OutputFilterOptions {
@@ -333,6 +335,11 @@ typedef struct OutputFilterOptions {
     enum AVColorRange   color_range;
     enum AVAlphaMode    alpha_mode;
 
+    unsigned            crop_top;
+    unsigned            crop_bottom;
+    unsigned            crop_left;
+    unsigned            crop_right;
+
     enum VideoSyncMethod vsync_method;
     AVRational           frame_rate;
     AVRational           max_frame_rate;
@@ -348,6 +355,9 @@ typedef struct OutputFilterOptions {
     const enum AVColorRange  *color_ranges;
     const enum AVAlphaMode   *alpha_modes;
 
+    AVFrameSideData   **side_data;
+    int                 nb_side_data;
+
     // for simple filtergraphs only, view specifier passed
     // along to the decoder
     const ViewSpecifier *vs;
@@ -827,7 +837,8 @@ int ofilter_bind_enc(OutputFilter *ofilter,
  * @param graph_desc Graph description; an av_malloc()ed string, filtergraph
  *                   takes ownership of it.
  */
-int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch);
+int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch,
+              const OutputFilterOptions *opts);
 
 void fg_free(FilterGraph **pfg);
 

+ 80 - 5
fftools/ffmpeg_filter.c

@@ -204,6 +204,11 @@ typedef struct OutputFilterPriv {
     enum AVColorRange       color_range;
     enum AVAlphaMode        alpha_mode;
 
+    unsigned                crop_top;
+    unsigned                crop_bottom;
+    unsigned                crop_left;
+    unsigned                crop_right;
+
     AVFrameSideData       **side_data;
     int                     nb_side_data;
 
@@ -228,6 +233,8 @@ typedef struct OutputFilterPriv {
     const enum AVColorRange *color_ranges;
     const enum AVAlphaMode *alpha_modes;
 
+    int32_t                 displaymatrix[9];
+
     AVRational              enc_timebase;
     int64_t                 trim_start_us;
     int64_t                 trim_duration_us;
@@ -818,7 +825,7 @@ int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc,
     ofp->needed = ofilter->bound = 1;
     av_freep(&ofilter->linklabel);
 
-    ofp->flags        = opts->flags;
+    ofp->flags       |= opts->flags;
     ofp->ts_offset    = opts->ts_offset;
     ofp->enc_timebase = opts->output_tb;
 
@@ -1078,7 +1085,8 @@ static const AVClass fg_class = {
     .category   = AV_CLASS_CATEGORY_FILTER,
 };
 
-int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch)
+int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch,
+              const OutputFilterOptions *opts)
 {
     FilterGraphPriv *fgp;
     FilterGraph      *fg;
@@ -1175,11 +1183,13 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch)
         const enum AVMediaType type = avfilter_pad_get_type(cur->filter_ctx->output_pads,
                                                             cur->pad_idx);
         OutputFilter *const ofilter = ofilter_alloc(fg, type);
+        OutputFilterPriv *ofp;
 
         if (!ofilter) {
             ret = AVERROR(ENOMEM);
             goto fail;
         }
+        ofp = ofp_from_ofilter(ofilter);
 
         ofilter->linklabel = cur->name;
         cur->name          = NULL;
@@ -1189,6 +1199,25 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch)
             ret = AVERROR(ENOMEM);
             goto fail;
         }
+
+        // opts should only be needed in this function to fill fields from filtergraphs
+        // whose output is meant to be treated as if it was stream, e.g. merged HEIF
+        // tile groups.
+        if (opts) {
+            ofp->flags        = opts->flags;
+            ofp->side_data    = opts->side_data;
+            ofp->nb_side_data = opts->nb_side_data;
+
+            ofp->crop_top     = opts->crop_top;
+            ofp->crop_bottom  = opts->crop_bottom;
+            ofp->crop_left    = opts->crop_left;
+            ofp->crop_right   = opts->crop_right;
+
+            const AVFrameSideData *sd = av_frame_side_data_get(ofp->side_data, ofp->nb_side_data,
+                                                               AV_FRAME_DATA_DISPLAYMATRIX);
+            if (sd)
+                memcpy(ofp->displaymatrix, sd->data, sizeof(ofp->displaymatrix));
+        }
     }
 
     if (!fg->nb_outputs) {
@@ -1225,7 +1254,7 @@ int fg_create_simple(FilterGraph **pfg,
     FilterGraphPriv *fgp;
     int ret;
 
-    ret = fg_create(pfg, graph_desc, sch);
+    ret = fg_create(pfg, graph_desc, sch, NULL);
     if (ret < 0)
         return ret;
     fg  = *pfg;
@@ -1603,6 +1632,53 @@ static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *gr
     if (ret < 0)
         return ret;
 
+    if (ofp->flags & OFILTER_FLAG_CROP) {
+        char crop_buf[64];
+        snprintf(crop_buf, sizeof(crop_buf), "w=iw-%u-%u:h=ih-%u-%u:x=%u:y=%u",
+                 ofp->crop_left, ofp->crop_right,
+                 ofp->crop_top,  ofp->crop_bottom,
+                 ofp->crop_left, ofp->crop_top);
+        ret = insert_filter(&last_filter, &pad_idx, "crop", crop_buf);
+        if (ret < 0)
+            return ret;
+    }
+
+    if (ofp->flags & OFILTER_FLAG_AUTOROTATE) {
+        int32_t *displaymatrix = ofp->displaymatrix;
+        double theta;
+
+        theta = get_rotation(displaymatrix);
+
+        if (fabs(theta - 90) < 1.0) {
+            ret = insert_filter(&last_filter, &pad_idx, "transpose",
+                                displaymatrix[3] > 0 ? "cclock_flip" : "clock");
+        } else if (fabs(theta - 180) < 1.0) {
+            if (displaymatrix[0] < 0) {
+                ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
+                if (ret < 0)
+                    return ret;
+            }
+            if (displaymatrix[4] < 0) {
+                ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
+            }
+        } else if (fabs(theta - 270) < 1.0) {
+            ret = insert_filter(&last_filter, &pad_idx, "transpose",
+                                displaymatrix[3] < 0 ? "clock_flip" : "cclock");
+        } else if (fabs(theta) > 1.0) {
+            char rotate_buf[64];
+            snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta);
+            ret = insert_filter(&last_filter, &pad_idx, "rotate", rotate_buf);
+        } else if (fabs(theta) < 1.0) {
+            if (displaymatrix && displaymatrix[4] < 0) {
+                ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
+            }
+        }
+        if (ret < 0)
+            return ret;
+
+        av_frame_side_data_remove(&ofp->side_data, &ofp->nb_side_data, AV_FRAME_DATA_DISPLAYMATRIX);
+    }
+
     if ((ofp->width || ofp->height) && (ofp->flags & OFILTER_FLAG_AUTOSCALE)) {
         char args[255];
         AVFilterContext *filter;
@@ -2100,12 +2176,11 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt)
         ret = av_buffersink_get_ch_layout(sink, &ofp->ch_layout);
         if (ret < 0)
             goto fail;
-        av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data);
         sd = av_buffersink_get_side_data(sink, &nb_sd);
         if (nb_sd)
             for (int j = 0; j < nb_sd; j++) {
                 ret = av_frame_side_data_clone(&ofp->side_data, &ofp->nb_side_data,
-                                               sd[j], 0);
+                                               sd[j], AV_FRAME_SIDE_DATA_FLAG_REPLACE);
                 if (ret < 0) {
                     av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data);
                     goto fail;

+ 1 - 1
fftools/ffmpeg_opt.c

@@ -1496,7 +1496,7 @@ int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch)
 
     /* create complex filtergraphs */
     for (int i = 0; i < go.nb_filtergraphs; i++) {
-        ret = fg_create(NULL, go.filtergraphs[i], sch);
+        ret = fg_create(NULL, go.filtergraphs[i], sch, NULL);
         go.filtergraphs[i] = NULL;
         if (ret < 0)
             goto fail;