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 ESMTPS id 98CD548A2D for ; Wed, 19 Feb 2025 20:08:23 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 447E668C2A0; Wed, 19 Feb 2025 22:08:08 +0200 (EET) Received: from mail-pl1-f175.google.com (mail-pl1-f175.google.com [209.85.214.175]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 7EC8A68C0E4 for ; Wed, 19 Feb 2025 22:08:00 +0200 (EET) Received: by mail-pl1-f175.google.com with SMTP id d9443c01a7336-220e989edb6so3336035ad.1 for ; Wed, 19 Feb 2025 12:08:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1739995679; x=1740600479; darn=ffmpeg.org; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date :references:in-reply-to:message-id:from:from:to:cc:subject:date :message-id:reply-to; bh=nFpEZs8aOJFuX8gqqFZeS2/852y+YahcdSTq/FwFN7g=; b=OaouGtGyc1Wy35xjCmhY/85UhmLVzMDLhessrYPkZEjypDiY02ai5yKdrSZ1DjCtcN OigZMBK6/jqBhu1g1qPxSsLGyJXFs0hR/hVKAWkajz/Z1Go8G34TKAi56CTY3aaZSREE iZ05XnFXTyRuzLkPZCQSUXo1ZrX/O+T5BlaiQ4H1wA8nOy5MQK1AuZG1WBD0IskxS83X nWxY395QnLtw9BJZNdXtfnk20oKrx9KOazGnVMbQifAj7kkmC+BMUtUV9dpXi0xi3mds /RSLHfWOfEuMicFmCrK98x2LcFcmnrP/1JOMUTahgfHxus7w5PUqiNlacD8XisAuU/bD CcJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739995679; x=1740600479; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date :references:in-reply-to:message-id:from:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=nFpEZs8aOJFuX8gqqFZeS2/852y+YahcdSTq/FwFN7g=; b=H9A0lBQ/ZzyfF2OsS83s8EXcOgKE4iCjTy39VkFLuY4s77vAHO1KOP+lza1Dl4GVGu JW5nWKKP0Uj7f8SQD6QUId5QDSYOOTNpYSQsrWvm+sR9xOQQr25Ouel6ZAuaNjeIZuol 4enLa9cUCIfTuYB5uGv/nsumZAzlg2kPpDnZnkXtUWqQvQPbL22P2qxAaciAc2wnfjRZ qRQmQyLeO63ioMfEbzm9dpKa4c/pxWiSLZRvmFc1vO3V90OL0RV86KR6vg8HwzyZaE0a qFKO6mrpB6xJMOFKzdpDFaYvf7BSeoCf6HrJu5I7VKh/Uy+FXDWI2xZII7B9wKeXkoH6 2bGw== X-Gm-Message-State: AOJu0YwZEI396VDcz0BseYizizWJWPToonER5g4eg3uyFGWFQ8lrbw80 M1SPDjElb5D5NjnCizBt13vizyhz4k326spWq5jlbnZK9NxbOIqgmbeYBA== X-Gm-Gg: ASbGncvNZQDJTW6PzPVRfGL1UIrMlXLEO+UJ6v0QWScWxUumArszrEmwNsl1C0U+2Y/ DFqzLBN/FDHMeVYyGlQM0aOeqoVivxOdkkLprM8Dqxjf0qV+NABi5lhcZCA/V2djBla/nRooQ4l OY4bV6x8GUtehGo4wIZ6r9q4Kn6Wki/hnArxNnaBlj1vou6xRJINQ46xVcjJ7TZLl8YmhITeTCe SoYocCia6LQq4S/Gt05Y+n3z8ZO7ROEzQB1ZB7M9NT/BMjWNbNuDshawu7ZkQR7nYzHgTCiDKM1 0tqEBCfD3X+JbAWrUUTyN6N6RVisyiwCBg== X-Google-Smtp-Source: AGHT+IEVCjDupl0DsiDdZ5aAvPz1y7WvjjVLuDzAmYWQAYM4uSOd3g1qmaeF/HJfzE+ibUE8teH1Ow== X-Received: by 2002:a05:6a00:4f96:b0:730:9a55:d921 with SMTP id d2e1a72fcca58-732617e63acmr26965033b3a.14.1739995678674; Wed, 19 Feb 2025 12:07:58 -0800 (PST) Received: from [127.0.0.1] (master.gitmailbox.com. [34.83.118.50]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7326b5ef448sm8278394b3a.173.2025.02.19.12.07.58 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 19 Feb 2025 12:07:58 -0800 (PST) From: softworkz X-Google-Original-From: softworkz Message-Id: <494f07298ffed191891d3070a49d19e9a3cdc625.1739995676.git.ffmpegagent@gmail.com> In-Reply-To: References: Date: Wed, 19 Feb 2025 20:07:55 +0000 Fcc: Sent MIME-Version: 1.0 To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] [PATCH 1/2] fftools/ffprobe: Add YAML output writer 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 Cc: softworkz 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: From: softworkz Signed-off-by: softworkz --- fftools/ffprobe.c | 147 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 1 deletion(-) diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c index 0270878ead..843c8df7f3 100644 --- a/fftools/ffprobe.c +++ b/fftools/ffprobe.c @@ -1980,6 +1980,150 @@ static Writer xml_writer = { .priv_class = &xml_class, }; + +/* YAML output */ + +typedef struct YMLContext { + const AVClass *class; + int indent_level; + int blank_lines; +} YMLContext; + +#undef OFFSET +#define OFFSET(x) offsetof(YMLContext, x) + +static const AVOption yml_options[] = { + { "blank_lines", "print blank lines for better readability", OFFSET(blank_lines), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, + { NULL } +}; + +DEFINE_WRITER_CLASS(yml); + +static av_cold int yml_init(WriterContext *wctx) +{ + YMLContext *yml = wctx->priv; + yml->indent_level = 0; + return 0; +} + +static int yml_is_plain(const char *s) +{ + if (!s || !*s) + return 0; + for (; *s; s++) { + if (!( (*s >= 'a' && *s <= 'z') || + (*s >= 'A' && *s <= 'Z') || + (*s >= '0' && *s <= '9') || + *s == '_' || *s == '-' || *s == '.' )) + return 0; + } + return 1; +} + +static void yml_print_quote_escape(WriterContext *wctx, const char *src) +{ + if (yml_is_plain(src)) { + writer_put_str(wctx, src); + } else { + writer_w8(wctx, '"'); + for (const char *p = src; *p; p++) { + unsigned char c = *p; + if (c == '\\' || c == '"') { + writer_w8(wctx, '\\'); + writer_w8(wctx, c); + } else if (c < 32 || c > 126) { + writer_printf(wctx, "\\u%04x", c); + } else { + writer_w8(wctx, c); + } + } + writer_w8(wctx, '"'); + } +} + +#define YML_INDENT() if (yml->indent_level > 0) writer_printf(wctx, "%*c", yml->indent_level * 2, ' ') +#define YML_BLANKLINE() if (yml->blank_lines ) writer_put_str(wctx, "\n"); + +/* At the top level, print yaml start marker '---'. If parent section is array, + * output a dash. If the section isn't merely a wrapper, its name as a mapping key. + * Otherwise, output the section name as a mapping key. */ +static void yml_print_section_header(WriterContext *wctx, const void *data) +{ + YMLContext *yml = wctx->priv; + const struct section *section = wctx->section[wctx->level]; + const struct section *parent = (wctx->level > 0) ? wctx->section[wctx->level-1] : NULL; + + if (wctx->level == 0) { + writer_put_str(wctx, "---\n"); + return; + } + + int parent_is_array = parent && (parent->flags & SECTION_FLAG_IS_ARRAY); + if (parent_is_array) { + YML_BLANKLINE(); + writer_printf(wctx, "%*c- ", yml->indent_level * 2, ' '); + if (!(section->flags & SECTION_FLAG_IS_WRAPPER)) { + writer_printf(wctx, "%s:\n", section->name); + } else { + writer_put_str(wctx, "\n"); + } + yml->indent_level++; + return; + } + + YML_INDENT(); + writer_put_str(wctx, section->name); + writer_put_str(wctx, ":\n"); + yml->indent_level++; +} + +static void yml_print_section_footer(WriterContext *wctx) +{ + YMLContext *yml = wctx->priv; + if (wctx->level == 0) { + writer_put_str(wctx, "...\n"); // yaml end document marker + } else { + if (wctx->level == 1) + YML_BLANKLINE(); + yml->indent_level--; + } +} + +static void yml_print_str(WriterContext *wctx, const char *key, const char *value) +{ + YMLContext *yml = wctx->priv; + YML_INDENT(); + + yml_print_quote_escape(wctx, key); + writer_put_str(wctx, ": "); + + yml_print_quote_escape(wctx, value); + writer_put_str(wctx, "\n"); +} + +static void yml_print_int(WriterContext *wctx, const char *key, int64_t value) +{ + YMLContext *yml = wctx->priv; + YML_INDENT(); + + yml_print_quote_escape(wctx, key); + writer_put_str(wctx, ": "); + + writer_printf(wctx, "%"PRId64"\n", value); +} + +static const Writer yml_writer = { + .name = "yml", + .priv_size = sizeof(YMLContext), + .init = yml_init, + .print_section_header = yml_print_section_header, + .print_section_footer = yml_print_section_footer, + .print_integer = yml_print_int, + .print_string = yml_print_str, + .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, + .priv_class = &yml_class, +}; + static void writer_register_all(void) { static int initialized; @@ -1995,6 +2139,7 @@ static void writer_register_all(void) writer_register(&ini_writer); writer_register(&json_writer); writer_register(&xml_writer); + writer_register(&yml_writer); } #define print_fmt(k, f, ...) do { \ @@ -4597,7 +4742,7 @@ static const OptionDef real_options[] = { { "pretty", OPT_TYPE_FUNC, 0, {.func_arg = opt_pretty}, "prettify the format of displayed values, make it more human readable" }, { "output_format", OPT_TYPE_STRING, 0, { &output_format }, - "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)", "format" }, + "set the output printing format (available formats are: default, compact, csv, flat, ini, yml, json, xml)", "format" }, { "print_format", OPT_TYPE_STRING, 0, { &output_format }, "alias for -output_format (deprecated)" }, { "of", OPT_TYPE_STRING, 0, { &output_format }, "alias for -output_format", "format" }, { "select_streams", OPT_TYPE_STRING, 0, { &stream_specifier }, "select the specified streams", "stream_specifier" }, -- ffmpeg-codebot _______________________________________________ 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".