From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id 212DB47CAC for ; Mon, 15 Apr 2024 15:09:22 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id DC27A68C8F2; Mon, 15 Apr 2024 18:09:19 +0300 (EEST) Received: from mail-pl1-f179.google.com (mail-pl1-f179.google.com [209.85.214.179]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 27EC768C545 for ; Mon, 15 Apr 2024 18:09:14 +0300 (EEST) Received: by mail-pl1-f179.google.com with SMTP id d9443c01a7336-1e51398cc4eso32067805ad.2 for ; Mon, 15 Apr 2024 08:09:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1713193751; x=1713798551; 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=SjdTWgWa/sKIiwri0xW70yvPnpeI2CcaPYaUKGKt+yc=; b=m5bc5WX1F76JHhemK2tHkTrKsQco7xSQR7lCupxjtF6XmNUHRSjPVgQ6rYIg/hXQwC Ofcmf4VGwPrzXcP2pzTmntnFttwZw7t+NvuaGUjxRGIkqwmt5uBUq9lJCVuaffU32y6a QrDMRHKcfM7d87Jh1FqNRQEACBHm648Up+iePeKC5l8tJ1MkDJ3st2/gRVRGizHOjZr2 tC/SO5gbct3cjg+d90EwoxVgn1OT7N/hDd5Q0LryEuMsq7ZvYzbCeLyN/o0ovgj3Y5nw qflGOtH6m2qhIlkkDI4cSLnOYpFSpQazK7wa+fhDYCRnEQBYbbScGthx/pKOqd6UGB0o QT6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1713193751; x=1713798551; 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=SjdTWgWa/sKIiwri0xW70yvPnpeI2CcaPYaUKGKt+yc=; b=eCJ9qfHPrslq1/v91NGxWFfnClzbgDNMnxH0Ua4JKx2QMCmpIOl1850PROL5FKW6TW /cphbANFF1AZuEnKe6xo2Ht1T+Zr3heaeJOYM6zhiO5i1nKuQ+oUbmrtHbk9+cIItnWf dPbUWAMCjQEqSHbpPbnpqRy/nPS2ex3SSmEoCY4wP6fWfycGNINGzKjJFIs/zWub3SXr UHa3QBh55L70nI0r6FujryuPWi7wJcMnqprnFbxGMbm/lRZMlpxURu75v7cErmdJLmO1 7MaIfF/9SWRXaMNyKBQTVFkrcLmTkEgQnhD5IIUEOCqmYHXkCOepIE7lVMngLL4oLsYi rOcQ== X-Gm-Message-State: AOJu0YwZeVgtfagaqQ/PGa241d2qrA0bqymk2bhBC4d1GS2DPJJF0o6i BFGfBtqaAIp2/jngf2dl3AUdsrATMtOi9Zcp1EIx5EwswIuJRh7I2R1PPw== X-Google-Smtp-Source: AGHT+IHQUfRSbY7hCOkC2za647ebm2QtFR83bMxuU9M/6RhsWrIim6lwhyPmMesbDDOqu4eREERMUQ== X-Received: by 2002:a17:902:ce88:b0:1dc:7bc:d025 with SMTP id f8-20020a170902ce8800b001dc07bcd025mr14610864plg.4.1713193751127; Mon, 15 Apr 2024 08:09:11 -0700 (PDT) Received: from localhost.localdomain ([190.194.167.233]) by smtp.gmail.com with ESMTPSA id i5-20020a17090332c500b001e546a10c50sm8020123plr.286.2024.04.15.08.09.09 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Apr 2024 08:09:10 -0700 (PDT) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Mon, 15 Apr 2024 12:09:00 -0300 Message-ID: <20240415150900.1800-1-jamrial@gmail.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412231658.4625-1-jamrial@gmail.com> References: <20240412231658.4625-1-jamrial@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 4/4] fftools/ffmpeg_mux_init: allow mapping a stream group from one of the inputs 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 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: Do this by extending the -stream_group option to accept a map key where the value selects the input file and stream group. The can and should set the streams in the output that the copied group will reference, same as they'd do if they created a group from scratch. Example command line: ffmpeg -i input.iamf -map 0 -c:a copy -f null -stream_group \ map=0=0:st=0:st=1:st=2:st=3 -stream_group map=0=1:st=0:st=1:st=2:st=3 Signed-off-by: James Almer --- fftools/ffmpeg_mux_init.c | 154 +++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index 6d8bd5bcdf..a46b0628d8 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -2232,11 +2232,137 @@ fail: return ret; } +static int of_serialize_options(Muxer *mux, void *obj, AVBPrint *bp) +{ + char *ptr; + int ret; + + ret = av_opt_serialize(obj, 0, AV_OPT_SERIALIZE_SKIP_DEFAULTS | AV_OPT_SERIALIZE_SEARCH_CHILDREN, + &ptr, '=', ':'); + if (ret < 0) { + av_log(mux, AV_LOG_ERROR, "Failed to serialize group\n"); + return ret; + } + + av_bprintf(bp, "%s", ptr); + ret = strlen(ptr); + av_free(ptr); + + return ret; +} + +#define SERIALIZE(parent, child) do { \ + ret = of_serialize_options(mux, parent->child, bp); \ + if (ret < 0) \ + return ret; \ +} while (0) + +#define SERIALIZE_LOOP(parent, child, suffix, separator) do { \ + for (int j = 0; j < parent->nb_## child ## suffix; j++) { \ + av_bprintf(bp, separator#child "="); \ + SERIALIZE(parent, child ## suffix[j]); \ + } \ +} while (0) + +static int64_t get_stream_group_index_from_id(Muxer *mux, int64_t id) +{ + AVFormatContext *oc = mux->fc; + + for (unsigned i = 0; i < oc->nb_stream_groups; i++) + if (oc->stream_groups[i]->id == id) + return oc->stream_groups[i]->index; + + return AVERROR(EINVAL); +} + +static int of_map_group(Muxer *mux, AVDictionary **dict, AVBPrint *bp, const char *map) +{ + AVStreamGroup *stg; + int ret, file_idx, stream_idx; + char *ptr; + + file_idx = strtol(map, &ptr, 0); + if (file_idx >= nb_input_files || file_idx < 0 || map == ptr) { + av_log(mux, AV_LOG_ERROR, "Invalid input file index: %d.\n", file_idx); + return AVERROR(EINVAL); + } + + stream_idx = strtol(*ptr == '=' ? ptr + 1 : ptr, &ptr, 0); + if (*ptr || stream_idx >= input_files[file_idx]->ctx->nb_stream_groups || stream_idx < 0) { + av_log(mux, AV_LOG_ERROR, "Invalid input stream group index: %d.\n", stream_idx); + return AVERROR(EINVAL); + } + + stg = input_files[file_idx]->ctx->stream_groups[stream_idx]; + ret = of_serialize_options(mux, stg, bp); + if (ret < 0) + return ret; + + ret = av_dict_parse_string(dict, bp->str, "=", ":", 0); + if (ret < 0) + av_log(mux, AV_LOG_ERROR, "Error parsing mapped group specification %s\n", ptr); + av_dict_set_int(dict, "type", stg->type, 0); + + av_log(mux, AV_LOG_VERBOSE, "stg %s\n", bp->str); + av_bprint_clear(bp); + switch(stg->type) { + case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT: { + AVIAMFAudioElement *audio_element = stg->params.iamf_audio_element; + + if (audio_element->demixing_info) { + av_bprintf(bp, ",demixing="); + SERIALIZE(audio_element, demixing_info); + } + if (audio_element->recon_gain_info) { + av_bprintf(bp, ",recon_gain="); + SERIALIZE(audio_element, recon_gain_info); + } + SERIALIZE_LOOP(audio_element, layer, s, ","); + break; + } + case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION: { + AVIAMFMixPresentation *mix = stg->params.iamf_mix_presentation; + + for (int i = 0; i < mix->nb_submixes; i++) { + AVIAMFSubmix *submix = mix->submixes[i]; + + av_bprintf(bp, ",submix="); + SERIALIZE(mix, submixes[i]); + for (int j = 0; j < submix->nb_elements; j++) { + AVIAMFSubmixElement *element = submix->elements[j]; + int64_t id = get_stream_group_index_from_id(mux, element->audio_element_id); + + if (id < 0) { + av_log(mux, AV_LOG_ERROR, "Invalid or missing stream group index in" + "submix element"); + return id; + } + + av_bprintf(bp, "|element="); + SERIALIZE(submix, elements[j]); + if (ret) + av_bprintf(bp, ":"); + av_bprintf(bp, "stg=%"PRId64, id); + } + SERIALIZE_LOOP(submix, layout, s, "|"); + } + break; + } + default: + av_log(mux, AV_LOG_ERROR, "Unsupported mapped group type %d.\n", stg->type); + ret = AVERROR(EINVAL); + break; + } + av_log(mux, AV_LOG_VERBOSE, "extra %s\n", bp->str); + return 0; +} + static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) { AVFormatContext *oc = mux->fc; AVStreamGroup *stg; AVDictionary *dict = NULL, *tmp = NULL; + char *mapped_string = NULL; const AVDictionaryEntry *e; const AVOption opts[] = { { "type", "Set group type", offsetof(AVStreamGroup, type), AV_OPT_TYPE_INT, @@ -2262,8 +2388,31 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) return ret; } + av_dict_copy(&tmp, dict, 0); + e = av_dict_get(dict, "map", NULL, 0); + if (e) { + AVBPrint bp; + + if (ptr) { + av_log(mux, AV_LOG_ERROR, "Unexpected extra parameters when mapping a" + " stream group\n"); + ret = AVERROR(EINVAL); + goto end; + } + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); + ret = of_map_group(mux, &tmp, &bp, e->value); + if (ret < 0) { + av_bprint_finalize(&bp, NULL); + goto end; + } + + av_bprint_finalize(&bp, &mapped_string); + ptr = mapped_string; + } + // "type" is not a user settable AVOption in AVStreamGroup, so handle it here - e = av_dict_get(dict, "type", NULL, 0); + e = av_dict_get(tmp, "type", NULL, 0); if (!e) { av_log(mux, AV_LOG_ERROR, "No type specified for Stream Group in \"%s\"\n", token); ret = AVERROR(EINVAL); @@ -2278,7 +2427,6 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) goto end; } - av_dict_copy(&tmp, dict, 0); stg = avformat_stream_group_create(oc, type, &tmp); if (!stg) { ret = AVERROR(ENOMEM); @@ -2331,6 +2479,7 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) // make sure that nothing but "st" and "stg" entries are left in the dict e = NULL; + av_dict_set(&tmp, "map", NULL, 0); av_dict_set(&tmp, "type", NULL, 0); while (e = av_dict_iterate(tmp, e)) { if (!strcmp(e->key, "st") || !strcmp(e->key, "stg")) @@ -2343,6 +2492,7 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) ret = 0; end: + av_free(mapped_string); av_dict_free(&dict); av_dict_free(&tmp); -- 2.44.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".