From patchwork Tue Jul 2 16:49:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Almer X-Patchwork-Id: 50292 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:cc64:0:b0:482:c625:d099 with SMTP id k4csp2654259vqv; Tue, 2 Jul 2024 12:19:05 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXgV+iyFl0zh0mE7mTAuP2mnicSAZOqlD17Vkx+RiAZHTYWnRwdCG+f3dITPFOPJoPrWQj4OuIonHfSRelW8xVPL1Uv4bxtynC5gQ== X-Google-Smtp-Source: AGHT+IEXkTerpGJmuHmwC4gcm0SWlPOlyFWoHJMDEyDZv+EQIQKO/9rmwH5lNbrobexmy5eUaUes X-Received: by 2002:a05:6402:5d92:b0:586:1d26:1b4c with SMTP id 4fb4d7f45d1cf-587a0fdbf00mr5785477a12.37.1719947945406; Tue, 02 Jul 2024 12:19:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1719947945; cv=none; d=google.com; s=arc-20160816; b=LievXX8sqO6OVSXYutnuJanHxXtyhKXaNzGmRhaAdxQB1kSpy441aE1ocVFugFykFY iNd04TAfyRVZGpLmN1VMqaeURyJWOZGzlb8VaTMJYeD/oU1us+glT41r2NvjzYeVu10g iza+SnUmDIErwox7WwJUCXLu0vjx6SnKzADKGwgPepBPXs0z1lg9aSkl/NhTjNdou2io HF3m4QNsYNgEI8o7H8Dg7F6g/ErLyYTZFbc5B0GpD2J/DHsv/4P4npb1x4C5AGNv5Bvf DjUl5qZQDbxOW8tc11s1GAAy+fpTjHSOmQcJI21x3H2ugLWD4whypW6R3xZIz6Co0DgB ivBw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:references:in-reply-to:message-id :date:to:from:dkim-signature:delivered-to; bh=dn3zkyNTqBvrH3ZDusylYCe1VPqA7p5BC/KEIxS6UdI=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=TnyXtBbYRpzyiCq4N23zx4bk0DccJpjeLU50hgp4XDXW8/6KQl9GXApFQk8ZJlCPVe XWkQ8zI6yZRAhSbg/S3FQYpTWCiQK8HPcpIeLe2vHUUTxFppig+xHpMiR/Y6+5HltWMI NYA5bteBv7+GzqvAt40a9FgAZD3mNfKhtoOnefUcPMldN0/DIgP1l26iYwuGE5jxBm+P seYK8J8x8juSWfe4cNos94QUcTwqn6JvgrdaMtWyJ9SKaOe+gEknJJ4qYmDfV6oMmsvM DblgLlCrBBjexmvmokKdt+K/3FUuZMGC3dFyJMkl2b/7DHGDj2b7FPze4yssYWf6TRei b+Qg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20230601 header.b="gysY/CAL"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id 4fb4d7f45d1cf-58c70ace9e8si187447a12.646.2024.07.02.12.19.04; Tue, 02 Jul 2024 12:19:05 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20230601 header.b="gysY/CAL"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 18C3868D78D; Tue, 2 Jul 2024 19:49:29 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pl1-f171.google.com (mail-pl1-f171.google.com [209.85.214.171]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2E2B868C0F3 for ; Tue, 2 Jul 2024 19:49:21 +0300 (EEST) Received: by mail-pl1-f171.google.com with SMTP id d9443c01a7336-1f8395a530dso20837885ad.0 for ; Tue, 02 Jul 2024 09:49:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1719938959; x=1720543759; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=E7X26gF7AZmsehTrj/4sTbeEO2RVzk5iMxRHDV0++dc=; b=gysY/CALxLxCrHJlKtPG/mApSV5dxMn09ePELegkXqhs1A8UCS1KNTM/hhsi6T+t/7 4ULpOHjl28nW2UUlJIP2B55r9Ko+9PSXtZ2qYybcMBT/YUlFIIPALUEWMVVuzpqkLyp0 K/C60FtoEnxRvAYdf7JSuv4hDfV5XPGVzt9+bWyaTGwSJrTnuYkbcSCLTcFsO/k26AJd Z2dQPtu8IcyQI7D07zxo1fhdSS8hF+me5iCjZZAO/k3LJKr4NPvaOEOrPGPi/+5Zgnhl xDisLU6Xo6YYwpbG/1QCzgAHTq4pPJtnVEeFDDXMYcf7x6ovJsKtDoi0N7BOAg3t8Xm+ XHZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1719938959; x=1720543759; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=E7X26gF7AZmsehTrj/4sTbeEO2RVzk5iMxRHDV0++dc=; b=DYzD93pywIpmwQj3hPV19cFvbxNZVFHqfcQQvDhKbRgfB7HoJcmhGdHcchJqYHgerf fsjweoI3AOBdySGSxxRkl5vVWLoCaZ+BrOipHaLjBOyKBkD+py9rO11A+Wbq/ucSxUg0 Jcw+ob+EEudaP9owEcXY8RClOExX2pPNmNhfhDq5BSNoue6lznHVAlKqvVNCvJPAzYPm ROi1hJ3WN+rD6GNYlqZkhlOHbM4X6I9ePB+KRZsH/qsK/CQs7SGKeYQS20QK1700AqeH hvDima9r5S4iOxPyfkHLs8gYJrwEgenn2NiYi6ozbFxwh4eQ9z8DF1Zx1cTABm6CUSB0 W5PQ== X-Gm-Message-State: AOJu0Yy45kFgMebAmZWNqtPA86ZOOh+N5kqc06XCuc/5c7Llb245Vvxj 1kjmJqyjdMe4uKzwPrkIg4ILUQ6oXfUj9ep9aYdq/M42PLHL1fcpb0PKBg== X-Received: by 2002:a17:902:f550:b0:1fa:cea0:bacd with SMTP id d9443c01a7336-1fadbd22795mr63340615ad.67.1719938958727; Tue, 02 Jul 2024 09:49:18 -0700 (PDT) Received: from localhost.localdomain ([190.194.167.233]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1fac1569d06sm86372585ad.212.2024.07.02.09.49.17 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 02 Jul 2024 09:49:18 -0700 (PDT) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Tue, 2 Jul 2024 13:49:36 -0300 Message-ID: <20240702164936.6140-1-jamrial@gmail.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <171931078242.21847.5755059493417163903@lain.khirnov.net> References: <171931078242.21847.5755059493417163903@lain.khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 5/6 v3] fftools/ffmpeg: support applying container level cropping X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: J1AS8guuR8C1 Signed-off-by: James Almer --- doc/ffmpeg.texi | 16 ++++++++++++++++ fftools/ffmpeg.h | 15 +++++++++++++++ fftools/ffmpeg_demux.c | 26 ++++++++++++++++++++++++++ fftools/ffmpeg_filter.c | 10 ++++++++++ fftools/ffmpeg_opt.c | 25 +++++++++++++++++++++++++ 5 files changed, 92 insertions(+) diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index f25f6192eb..f75ed681cf 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -1262,6 +1262,22 @@ disabled, all output frames of filter graph might not be in the same resolution and may be inadequate for some encoder/muxer. Therefore, it is not recommended to disable it unless you really know what you are doing. Disable autoscale at your own risk. + +@item -apply_cropping +Automatically crop the video according to file metadata. Default is @emph{all}. + +@table @option +@item none (0) +Don't apply any cropping metadata. +@item all (1) +Apply both codec and container level croppping. This is the default mode. +@item codec (2) +Apply codec level croppping. +@item container (3) +Apply container level croppping. + +@end table + @end table @section Advanced Video options diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index fe75706afd..810a5fa66c 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -155,6 +155,7 @@ typedef struct OptionsContext { SpecifierOptList hwaccel_devices; SpecifierOptList hwaccel_output_formats; SpecifierOptList autorotate; + SpecifierOptList apply_cropping; /* output options */ StreamMap *stream_maps; @@ -239,6 +240,7 @@ enum IFilterFlags { IFILTER_FLAG_AUTOROTATE = (1 << 0), IFILTER_FLAG_REINIT = (1 << 1), IFILTER_FLAG_CFR = (1 << 2), + IFILTER_FLAG_CROP = (1 << 3), }; typedef struct InputFilterOptions { @@ -254,6 +256,11 @@ typedef struct InputFilterOptions { * accurate */ AVRational framerate; + unsigned crop_top; + unsigned crop_bottom; + unsigned crop_left; + unsigned crop_right; + int sub2video_width; int sub2video_height; @@ -539,6 +546,13 @@ typedef struct KeyframeForceCtx { typedef struct Encoder Encoder; +enum CroppingType { + CROP_DISABLED = 0, + CROP_ALL, + CROP_CODEC, + CROP_CONTAINER, +}; + typedef struct OutputStream { const AVClass *class; @@ -715,6 +729,7 @@ AVDictionary *strip_specifiers(const AVDictionary *dict); int find_codec(void *logctx, const char *name, enum AVMediaType type, int encoder, const AVCodec **codec); int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global); +int parse_and_set_cropping(const char *arg, int *out); int filtergraph_is_simple(const FilterGraph *fg); int init_simple_filtergraph(InputStream *ist, OutputStream *ost, diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c index 1ca8d804ae..409d41eba7 100644 --- a/fftools/ffmpeg_demux.c +++ b/fftools/ffmpeg_demux.c @@ -66,6 +66,7 @@ typedef struct DemuxStream { int have_sub2video; int reinit_filters; int autorotate; + int apply_cropping; int wrap_correction_done; @@ -1000,11 +1001,22 @@ int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, ist->filters[ist->nb_filters - 1] = ifilter; if (ist->par->codec_type == AVMEDIA_TYPE_VIDEO) { + const AVPacketSideData *sd = av_packet_side_data_get(ist->par->coded_side_data, + ist->par->nb_coded_side_data, + AV_PKT_DATA_FRAME_CROPPING); if (ist->framerate.num > 0 && ist->framerate.den > 0) { opts->framerate = ist->framerate; opts->flags |= IFILTER_FLAG_CFR; } else opts->framerate = av_guess_frame_rate(d->f.ctx, ist->st, NULL); + if (sd && sd->size >= sizeof(uint32_t) * 4) { + opts->crop_top = AV_RL32(sd->data + 0); + opts->crop_bottom = AV_RL32(sd->data + 4); + opts->crop_left = AV_RL32(sd->data + 8); + opts->crop_right = AV_RL32(sd->data + 12); + if (ds->apply_cropping && ds->apply_cropping != CROP_CODEC) + opts->flags |= IFILTER_FLAG_CROP; + } } else if (ist->par->codec_type == AVMEDIA_TYPE_SUBTITLE) { /* Compute the size of the canvas for the subtitles stream. If the subtitles codecpar has set a size, use it. Otherwise use the @@ -1215,6 +1227,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) InputStream *ist; char *framerate = NULL, *hwaccel_device = NULL; const char *hwaccel = NULL; + const char *apply_cropping = NULL; char *hwaccel_output_format = NULL; char *codec_tag = NULL; char *bsfs = NULL; @@ -1241,6 +1254,16 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) ds->autorotate = 1; MATCH_PER_STREAM_OPT(autorotate, i, ds->autorotate, ic, st); + ds->apply_cropping = CROP_ALL; + MATCH_PER_STREAM_OPT(apply_cropping, str, apply_cropping, ic, st); + if (apply_cropping) { + ret = parse_and_set_cropping(apply_cropping, &ds->apply_cropping); + if (ret < 0) { + av_log(ist, AV_LOG_ERROR, "Invalid apply_cropping value '%s'.\n", apply_cropping); + return ret; + } + } + MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st); if (codec_tag) { uint32_t tag = strtol(codec_tag, &next, 0); @@ -1362,6 +1385,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) ds->dec_opts.flags |= DECODER_FLAG_BITEXACT * !!o->bitexact; + av_dict_set_int(&ds->decoder_opts, "apply_cropping", + ds->apply_cropping && ds->apply_cropping != CROP_CONTAINER, 0); + /* Attached pics are sparse, therefore we would not want to delay their decoding * till EOF. */ if (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC) diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 12cca684b4..f3087afc88 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -1701,6 +1701,16 @@ static int configure_input_video_filter(FilterGraph *fg, AVFilterGraph *graph, desc = av_pix_fmt_desc_get(ifp->format); av_assert0(desc); + if ((ifp->opts.flags & IFILTER_FLAG_CROP)) { + char crop_buf[64]; + snprintf(crop_buf, sizeof(crop_buf), "w=iw-%d-%d:h=ih-%d-%d", + ifp->opts.crop_left, ifp->opts.crop_right, + ifp->opts.crop_top, ifp->opts.crop_bottom); + ret = insert_filter(&last_filter, &pad_idx, "crop", crop_buf); + if (ret < 0) + return ret; + } + // TODO: insert hwaccel enabled filters like transpose_vaapi into the graph ifp->displaymatrix_applied = 0; if ((ifp->opts.flags & IFILTER_FLAG_AUTOROTATE) && diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 910e4a336b..fb104a356d 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -217,6 +217,28 @@ int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_id return 0; } +int parse_and_set_cropping(const char *arg, int *out) +{ + const AVOption opts[] = { + { "apply_cropping", NULL, 0, AV_OPT_TYPE_INT, + { .i64 = CROP_ALL }, CROP_DISABLED, CROP_CONTAINER, AV_OPT_FLAG_DECODING_PARAM, .unit = "apply_cropping" }, + { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CROP_DISABLED }, .unit = "apply_cropping" }, + { "all", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CROP_ALL }, .unit = "apply_cropping" }, + { "codec", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CROP_CODEC }, .unit = "apply_cropping" }, + { "container", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CROP_CONTAINER }, .unit = "apply_cropping" }, + { NULL }, + }; + const AVClass class = { + .class_name = "apply_cropping", + .item_name = av_default_item_name, + .option = opts, + .version = LIBAVUTIL_VERSION_INT, + }; + const AVClass *pclass = &class; + + return av_opt_eval_int(&pclass, opts, arg, out); +} + /* Correct input file start times based on enabled streams */ static void correct_input_start_times(void) { @@ -1732,6 +1754,9 @@ const OptionDef options[] = { { "autoscale", OPT_TYPE_BOOL, OPT_PERSTREAM | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(autoscale) }, "automatically insert a scale filter at the end of the filter graph" }, + { "apply_cropping", OPT_TYPE_STRING, OPT_VIDEO | OPT_PERSTREAM | OPT_EXPERT | OPT_INPUT, + { .off = OFFSET(apply_cropping) }, + "select the cropping to apply" }, { "fix_sub_duration_heartbeat", OPT_TYPE_BOOL, OPT_VIDEO | OPT_EXPERT | OPT_PERSTREAM | OPT_OUTPUT, { .off = OFFSET(fix_sub_duration_heartbeat) }, "set this video output stream to be a heartbeat stream for "