From patchwork Fri Jan 22 10:37:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Jan_Ekstr=C3=B6m?= X-Patchwork-Id: 25106 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:ab61:0:0:0:0:0 with SMTP id u88csp1062083ybi; Fri, 22 Jan 2021 02:45:26 -0800 (PST) X-Google-Smtp-Source: ABdhPJzqWunn1WlO7/oyQfUDJ0WMf20Ac7Y/5FaHlQJWivBjeAb3DbQB/FW/ftCu28ubV9oDCOdn X-Received: by 2002:a17:906:4bc1:: with SMTP id x1mr2563992ejv.509.1611312326024; Fri, 22 Jan 2021 02:45:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1611312326; cv=none; d=google.com; s=arc-20160816; b=vGtfmqSOBL2XtSyHvK5N/gnEuXj+r+UT/VI0kgwhlyoq4dO/vIgWpqjvDFqL3HPODp nvmmhThoWNdhLXiIqelq0qUcUeRT00GQNqn3MlfDNIWX37zTEy7kwqH9Gw0iid0XXtko nHNcLW2DdjwVaqWZOmBVkoVQnHamD4e/j8rtv8ILBNUhZtMwSF9hlH4YOPP1rr+nPHeh pJj0QrD2ZfkZotji7k0lvCav3scLQJXsyMLeEJRQEDUgbm4sytB7EKfTh2FACojZueh2 iOtvnS+dbjoNAr0zVlznXZdF4/45qdRbsg3p5N4KNzNtKeuY/wPuVqhXInvJbqs1Xwd5 FR1Q== 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=CAz4K8Q+Hn1YzWYYBfgVyX/3eNuqOhcQignYMOs3Sug=; b=HITCwp3Mek9mZ8nsGKhCiRWvwlNOv4rJAB/md1ZcCRUFdCzDGuGAnC1viD5GtV2rPM dEjfuQDdpbbSNpHSTgEgAGRrhh/NDhW1GsPyOOWydf05Wp+Yd1VKFEiclzRQ1HvZDPTc 5mTxmWF9anJWw5aiBsjur2TO+kRvxujiNEm0IEACupsfCjongZqT8/KPxfO2F7Fce5L0 XZuxVxI3M36zVcyLANbWFQGLxd4hyGefv6SoSb+qNg6gbzdQc8ETf01lO9PhwzcmugDW WNUnTs4bgfMqdJ4UeSiuFri5Z94jtpUR4dTTEsZCsfUoJIfJCnMExu1ra/XwHDLVZUcX WjOw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=ro9zPwTS; 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 r18si1168855edi.216.2021.01.22.02.45.25; Fri, 22 Jan 2021 02:45:26 -0800 (PST) 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=20161025 header.b=ro9zPwTS; 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 279536880CA; Fri, 22 Jan 2021 12:45:23 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ed1-f46.google.com (mail-ed1-f46.google.com [209.85.208.46]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 86240688128 for ; Fri, 22 Jan 2021 12:45:16 +0200 (EET) Received: by mail-ed1-f46.google.com with SMTP id s11so6003500edd.5 for ; Fri, 22 Jan 2021 02:45:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=m1yZwq9IlDE2+HFILR3smsGgsMx/AUqmBDDXX8hBKNw=; b=ro9zPwTSImxr/2qgE/TjC3ZILQIMTy+12TwSjdGv5XsuzZtcwQeaciTZBzzi4jrlxP fOHWgG6J3fPQ/bEzvckQkrSocejPEzQnIAHLbujkISr9TyLJEyLG5qgWra0S8K5yXPWo XVCmf8fo/Eu1wOdUBcET7yZtucrybHHO065SGiZQYWdvlJqQ5cAGSvVUf63OfpO/BJ5Z X/DN50p78w3rLJLMzzfESFKgWJZsUydN1Itc4FNFLeLcqnoX2Fy605cQqO5NCxFapay5 bF49IeJ5QWHuu/ljjycP9y+C8DQjA6XYMmKfy+Fao+Nd/VEFtGpco3ShYNUTROj+pwFR Ioxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=m1yZwq9IlDE2+HFILR3smsGgsMx/AUqmBDDXX8hBKNw=; b=Ihk4WXzkAiyP97yw56uZ0QutGXScst3cO68KabVRPuuzBdJJX1/FVoV1ADPpDfNfLF Cq4bgzDnBqXQZ5V8esnZvxvRCMIrUYXqJk6svRRnZK2Z5278GW7ZDD4GdDEAFjOTR96y k4BR3ntS492Gjxn0rqHYt9scRMuxMgPdiqKq6M5dHM7vZ/fDfgTohNr8l9TSI3fnqwBo Z6PrfFv7PLT/6VyNXW6a/F41qnuQ/cJucTxuH1zbnvvixvX8widdde7Fjq+2R7029Cvc WpjgEWleEZxv+MsiGYcmqlwER9zbnj56eVd8NYUbnroMVuSkcAcJPPXGhFZMLfmenp1L YfFg== X-Gm-Message-State: AOAM5330XJvxb8DLwcm247/8xyPI2E2zpVFur/Vwhucg3lj3KEfnK/4l 4q3Gu4ldATim/dvDV+MpzdGrU/z+hyg= X-Received: by 2002:a19:ed0a:: with SMTP id y10mr1869954lfy.601.1611311858663; Fri, 22 Jan 2021 02:37:38 -0800 (PST) Received: from localhost.localdomain (91-159-194-103.elisa-laajakaista.fi. [91.159.194.103]) by smtp.gmail.com with ESMTPSA id g2sm831626lfb.255.2021.01.22.02.37.37 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Jan 2021 02:37:38 -0800 (PST) From: =?utf-8?q?Jan_Ekstr=C3=B6m?= To: ffmpeg-devel@ffmpeg.org Date: Fri, 22 Jan 2021 12:37:31 +0200 Message-Id: <20210122103734.24420-2-jeebjp@gmail.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210122103734.24420-1-jeebjp@gmail.com> References: <20210122103734.24420-1-jeebjp@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 1/4] avutil/{avstring, bprint}: add XML escaping from ffprobe to avutil X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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: +uW31jAdbpy7 Content-Length: 4523 From: Stefano Sabatini --- libavutil/avstring.h | 7 ++++--- libavutil/bprint.c | 15 +++++++++++++++ tools/ffescape.c | 7 ++++--- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/libavutil/avstring.h b/libavutil/avstring.h index ee225585b3..189b4726a5 100644 --- a/libavutil/avstring.h +++ b/libavutil/avstring.h @@ -321,9 +321,10 @@ int av_match_name(const char *name, const char *names); char *av_append_path_component(const char *path, const char *component); enum AVEscapeMode { - AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode. - AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping. - AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping. + AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode. + AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping. + AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping. + AV_ESCAPE_MODE_XML_CHAR_DATA, ///< Use XML non-markup character data escaping. }; /** diff --git a/libavutil/bprint.c b/libavutil/bprint.c index 2f059c5ba6..7cdbb75095 100644 --- a/libavutil/bprint.c +++ b/libavutil/bprint.c @@ -283,6 +283,21 @@ void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_cha av_bprint_chars(dstbuf, '\'', 1); break; + case AV_ESCAPE_MODE_XML_CHAR_DATA: + /* escape XML non-markup character data as per 2.4 */ + /* [^<&]* - ([^<&]* ']]>' [^<&]*) */ + for (; *src; src++) { + switch (*src) { + case '&' : av_bprintf(dstbuf, "%s", "&"); break; + case '<' : av_bprintf(dstbuf, "%s", "<"); break; + case '>' : av_bprintf(dstbuf, "%s", ">"); break; + case '"' : av_bprintf(dstbuf, "%s", """); break; + case '\'': av_bprintf(dstbuf, "%s", "'"); break; + default: av_bprint_chars(dstbuf, *src, 1); + } + } + break; + /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */ default: /* \-escape characters */ diff --git a/tools/ffescape.c b/tools/ffescape.c index 0530d28c6d..e18f1edaf9 100644 --- a/tools/ffescape.c +++ b/tools/ffescape.c @@ -101,9 +101,10 @@ int main(int argc, char **argv) break; } case 'm': - if (!strcmp(optarg, "auto")) escape_mode = AV_ESCAPE_MODE_AUTO; - else if (!strcmp(optarg, "backslash")) escape_mode = AV_ESCAPE_MODE_BACKSLASH; - else if (!strcmp(optarg, "quote")) escape_mode = AV_ESCAPE_MODE_QUOTE; + if (!strcmp(optarg, "auto")) escape_mode = AV_ESCAPE_MODE_AUTO; + else if (!strcmp(optarg, "backslash")) escape_mode = AV_ESCAPE_MODE_BACKSLASH; + else if (!strcmp(optarg, "quote")) escape_mode = AV_ESCAPE_MODE_QUOTE; + else if (!strcmp(optarg, "xml_char_data")) escape_mode = AV_ESCAPE_MODE_XML_CHAR_DATA; else { av_log(NULL, AV_LOG_ERROR, "Invalid value '%s' for option -m, " From patchwork Fri Jan 22 10:37:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Jan_Ekstr=C3=B6m?= X-Patchwork-Id: 25104 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:ab61:0:0:0:0:0 with SMTP id u88csp1058316ybi; Fri, 22 Jan 2021 02:37:57 -0800 (PST) X-Google-Smtp-Source: ABdhPJyr4M+UiPXnvTgIIffu/0zBEmVKGJrN2uiUZIoC1B+GPhwtjLBNW6DQ+kAceFdUo+HbcnXa X-Received: by 2002:aa7:d401:: with SMTP id z1mr2653153edq.213.1611311877480; Fri, 22 Jan 2021 02:37:57 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1611311877; cv=none; d=google.com; s=arc-20160816; b=hn+kzxVp50ZzPMQGq5Z6UDTn3vzjs+jbmJably+bAz8y0d4FpBCMi9uqGQQSn4EBzx W3HCURQLJAQgVmNPN1O295QgSitOrc/IUt/LIybVT/J92PubGblteuCgm45ECdb/eP4k 0Jmbpn64DniVu93zw+zidPzOgQyL7zKNGK2ehf5ghfCmM9GMYhNAjl6+nJD8nJXSIL/G K3EFMGNspNiZQlRmC4v+TXo72M58+hiBmmv3UH2w9Q9ujTwMvNaX8wL+MkMz6x3lPePG mwOjdvKhNmK9raiDjR74j3ZB/u3kXj2hh3Vl0Ag92BlyQBojFVdi9WuP/RM+LSNSxCFW dNhA== 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=hLv2hw8f4OqCc+jG4cw5eSGJW2XizP70JCqurlxtJgs=; b=DMZjMuCRzJ31fe+AepQ6RCDPEplx+YSHj7kHpyNsMVTHjmRhdm04GeFo/Tfo3aRQSD Ft0Lyh5v8M6Xkuv7RANqOWmVN6YnG/H9xHo8ZtC2IugQoZVsouLgp5tReFYtzzJvXbO9 f3D/dtoatO4gHkjTYQY9SVk65M52KrbP5vuSEuJ6uyfFY4PuI269qtXxJdWQyDijcQrP po9as5OvN9ss6xBOQmuH8f36TKCu3GU+dDZ88GK5MKHYMhMqojzhA8NkjevGH/clOBzm Mq84S0ggqU1azYQHqHkSBjSl7EaRC7jm42wuECHvwz5KYl5Re3O0nLezuthVvzyoqlHX pD1Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=ZMeqtfWZ; 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 qh14si2884667ejb.360.2021.01.22.02.37.56; Fri, 22 Jan 2021 02:37:57 -0800 (PST) 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=20161025 header.b=ZMeqtfWZ; 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 6A4E968A215; Fri, 22 Jan 2021 12:37:47 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lj1-f173.google.com (mail-lj1-f173.google.com [209.85.208.173]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 0903D68A27A for ; Fri, 22 Jan 2021 12:37:40 +0200 (EET) Received: by mail-lj1-f173.google.com with SMTP id n11so5954612lji.5 for ; Fri, 22 Jan 2021 02:37:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=0tqesKxf9Q+k2/HqKtigHhunyL1BUuz0/niwUhS0CRo=; b=ZMeqtfWZqZzRepUsFFX+vEvFpo6OATO+Qnyrxmr1SzSe+mywNePxty3B95/yqgHHkn 6uwkfj7PvRes0H537eAlWIulTRayK7lRfNtihmhiqX5/AzScYloJqYBHSFe529mWgLkz FX4XWGAYq+B52/mv95ObFeQW/In+6NLtmoblX+coLlvRhZVy3gEUqghbaMV10sbH+DiO 2e0tOpkq0G1wmmoG2BLBqwRvi42hPraUWlAYJZjVygHWp6rkzV4i3WJEohANPSBCH78A 0mlmuUUMmbHr71W4aLOMSpe2eIqadb4conmvqWgBz8HaBl6pEPJY09lCTa7xUnKmEmQz JIqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=0tqesKxf9Q+k2/HqKtigHhunyL1BUuz0/niwUhS0CRo=; b=LytpJASeEd/OWMCQLHQxnLyTx493ttAimxvQ5+1W6xjU6cmMRmAyQodCtyELy6ukCL 3e0jybj1ML5U564th+jD2GL6RDoFh0LoYedZTpLl80lDDjXmQSy6FD18ofsLsvImA1Ph 0X0Sgv/X+te5JaECZM7N9DoBWw8W7Bde1rVUxe9XNQgsMmT1iVhe7V3us89PwLyCdpU+ XrCCjD7EP3ehm2xYETl4ddEI1ie1M1x2MFb1ooPM/bKvpk0mLtQa5a2ytyJrGfR9E1H/ MHO/qxNQVzHHO4tDqgxIxlHQ9FBf6wIwCtcB/E1yqODHgZccUJq9fyeQ3HDlzb6TqsYM eYNA== X-Gm-Message-State: AOAM532QSDb4mTvYkEACbz5Gei888khs2y7MF84Xks9zZKpUW4FTuHu0 xam0YLBIZb1ZRLIU4jeNlmSIXQgb5RI= X-Received: by 2002:a2e:80d2:: with SMTP id r18mr857667ljg.453.1611311859465; Fri, 22 Jan 2021 02:37:39 -0800 (PST) Received: from localhost.localdomain (91-159-194-103.elisa-laajakaista.fi. [91.159.194.103]) by smtp.gmail.com with ESMTPSA id g2sm831626lfb.255.2021.01.22.02.37.38 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Jan 2021 02:37:38 -0800 (PST) From: =?utf-8?q?Jan_Ekstr=C3=B6m?= To: ffmpeg-devel@ffmpeg.org Date: Fri, 22 Jan 2021 12:37:32 +0200 Message-Id: <20210122103734.24420-3-jeebjp@gmail.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210122103734.24420-1-jeebjp@gmail.com> References: <20210122103734.24420-1-jeebjp@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 2/4] avutil/{avstring, bprint}: add XML attribute value escape modes X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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: p0xLEtBhqQIS Content-Length: 6177 From: Jan Ekström Signed-off-by: Jan Ekström --- libavutil/avstring.h | 10 ++++++---- libavutil/bprint.c | 26 ++++++++++++++++++++++++++ tools/ffescape.c | 10 ++++++---- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/libavutil/avstring.h b/libavutil/avstring.h index 189b4726a5..c83aa9cf57 100644 --- a/libavutil/avstring.h +++ b/libavutil/avstring.h @@ -321,10 +321,12 @@ int av_match_name(const char *name, const char *names); char *av_append_path_component(const char *path, const char *component); enum AVEscapeMode { - AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode. - AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping. - AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping. - AV_ESCAPE_MODE_XML_CHAR_DATA, ///< Use XML non-markup character data escaping. + AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode. + AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping. + AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping. + AV_ESCAPE_MODE_XML_CHAR_DATA, ///< Use XML non-markup character data escaping. + AV_ESCAPE_MODE_XML_ATT_VALUE_SINGLE_QUOTED, ///< Use XML single quoted attribute value escaping. + AV_ESCAPE_MODE_XML_ATT_VALUE_DOUBLE_QUOTED, ///< Use XML double quoted attribute value escaping. }; /** diff --git a/libavutil/bprint.c b/libavutil/bprint.c index 7cdbb75095..c42ccdeee5 100644 --- a/libavutil/bprint.c +++ b/libavutil/bprint.c @@ -298,6 +298,32 @@ void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_cha } break; + case AV_ESCAPE_MODE_XML_ATT_VALUE_SINGLE_QUOTED: + /* escape XML single quoted attribute values as per 2.3 */ + /* "'" ([^<&'] | Reference)* "'" */ + for (; *src; src++) { + switch (*src) { + case '&' : av_bprintf(dstbuf, "%s", "&"); break; + case '<' : av_bprintf(dstbuf, "%s", "<"); break; + case '\'': av_bprintf(dstbuf, "%s", "'"); break; + default: av_bprint_chars(dstbuf, *src, 1); + } + } + break; + + case AV_ESCAPE_MODE_XML_ATT_VALUE_DOUBLE_QUOTED: + /* escape XML double quoted attribute values as per 2.3 */ + /* '"' ([^<&"] | Reference)* '"' */ + for (; *src; src++) { + switch (*src) { + case '&' : av_bprintf(dstbuf, "%s", "&"); break; + case '<' : av_bprintf(dstbuf, "%s", "<"); break; + case '"' : av_bprintf(dstbuf, "%s", """); break; + default: av_bprint_chars(dstbuf, *src, 1); + } + } + break; + /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */ default: /* \-escape characters */ diff --git a/tools/ffescape.c b/tools/ffescape.c index e18f1edaf9..c827e0b301 100644 --- a/tools/ffescape.c +++ b/tools/ffescape.c @@ -101,10 +101,12 @@ int main(int argc, char **argv) break; } case 'm': - if (!strcmp(optarg, "auto")) escape_mode = AV_ESCAPE_MODE_AUTO; - else if (!strcmp(optarg, "backslash")) escape_mode = AV_ESCAPE_MODE_BACKSLASH; - else if (!strcmp(optarg, "quote")) escape_mode = AV_ESCAPE_MODE_QUOTE; - else if (!strcmp(optarg, "xml_char_data")) escape_mode = AV_ESCAPE_MODE_XML_CHAR_DATA; + if (!strcmp(optarg, "auto")) escape_mode = AV_ESCAPE_MODE_AUTO; + else if (!strcmp(optarg, "backslash")) escape_mode = AV_ESCAPE_MODE_BACKSLASH; + else if (!strcmp(optarg, "quote")) escape_mode = AV_ESCAPE_MODE_QUOTE; + else if (!strcmp(optarg, "xml_char_data")) escape_mode = AV_ESCAPE_MODE_XML_CHAR_DATA; + else if (!strcmp(optarg, "xml_att_value_single_quoted")) escape_mode = AV_ESCAPE_MODE_XML_ATT_VALUE_SINGLE_QUOTED; + else if (!strcmp(optarg, "xml_att_value_double_quoted")) escape_mode = AV_ESCAPE_MODE_XML_ATT_VALUE_DOUBLE_QUOTED; else { av_log(NULL, AV_LOG_ERROR, "Invalid value '%s' for option -m, " From patchwork Fri Jan 22 10:37:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Jan_Ekstr=C3=B6m?= X-Patchwork-Id: 25108 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:ab61:0:0:0:0:0 with SMTP id u88csp1060906ybi; Fri, 22 Jan 2021 02:43:15 -0800 (PST) X-Google-Smtp-Source: ABdhPJx8SLY2qyAcxl/7F7QbYsDEdbOa09EG6lu9y039etaC2Gf0Ow91v1SBWO+00E7XXyvw+U4+ X-Received: by 2002:a17:906:3b92:: with SMTP id u18mr2577220ejf.7.1611312195609; Fri, 22 Jan 2021 02:43:15 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1611312195; cv=none; d=google.com; s=arc-20160816; b=iBoahJtIkinWJ1K4Cuk/l1gw0n4q2R/2WcL/c+L04J7W8djMT+dx5lYbUdriNugJ8+ 8GJHekjnF1sQYBqz9e7yjDmh/9mgicaIxHkaB7o90/CzLJNkX0P7NEHQenzOnjdEzPVO I/U/mIh3BMRKxT38eVRgKt3I0F2/GtPPWdM0IJfRrKhAmBKrAYbe/HzmZ88mXkVD2TSx dtZmvclxc+qpyOzEdWu9ifMxKr28Lqo+7qhYgEiAqQVur6KvmIgQVA0JOKB6EW6k+c/x l9t/Uw7dMRndmSkGt4KQSeGpoIUUxl1ZyrgzWdYsMELues9S/GP/NDCpruyja8fUb39I nSGQ== 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=iy4OUMzQxJ4ZxBdWSD1v5XmK49voVPIFZpXZ3SR7Ito=; b=cdyQXTp3B1cd64K6CMKkVw+Qoah5vYhPdZzoSNKxMI4eTu2dxaoeUPOqP98Zyenhhe 9kvxx1M0eu8TyrGLcRRnbaJT7uTuU2k6m1SqG9i2OEYn260JSKSoyWfyG1FMlKEh8SNV QFdJhUgVs7d6embV95Y1SH6s/TDRg7mDLkmnqpc9+1eqDj3aaxbpGni6iHXNYMbF30MO Mnu15zAus0MmItiQ7zh1SdzrBtYljMP6eywV4D04w3e1SGlhbeXRwn/ZhdoxgFRy3qO8 +ENLjgUo6WVTxb7khkRk/I1ANYEs4oyfA55lJxRQRDq9raAmrRZh3pQDIB6+8NGQpw2g 3IYQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=hC4jC7Pf; 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 p11si2688522edh.139.2021.01.22.02.43.15; Fri, 22 Jan 2021 02:43:15 -0800 (PST) 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=20161025 header.b=hC4jC7Pf; 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 F135B68A329; Fri, 22 Jan 2021 12:43:11 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lf1-f53.google.com (mail-lf1-f53.google.com [209.85.167.53]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 0D997680911 for ; Fri, 22 Jan 2021 12:43:04 +0200 (EET) Received: by mail-lf1-f53.google.com with SMTP id q12so6851744lfo.12 for ; Fri, 22 Jan 2021 02:43:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=xfUaZHFWslGnA5rr3bfxUXCxnwh2EGy7WvkfggPToOk=; b=hC4jC7PfNa6n4g2e4FXABupzJmN1cucaLZPrt2PKgiiMokefDtI8wGFnORh7G2WhXX MpU9qsERwK+oDkczbDkdrXQJQUdAYZRJD2LxudZoVWPUDaFy77caBgNS1DoSGUYdJ6Wl l2nwpi5UFvdz4jpsUoAdFH0y14p0oPWd5aMEfIPXHKSRkYiJ5zcYYQF6Vdnmd0fRyUj+ Z46iAvFHwKH4oUEE49WsVVFPQt/+ad8kqmhETWfWpTmN4L2cnT+5ri6Is+l16sRJ0wS6 f7RZkTbIYekN+becF+X+l/Mau1DzwWzSBxaawnKDdZHvQt1z5WkcMqz8ACiWomoE685d 3uUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=xfUaZHFWslGnA5rr3bfxUXCxnwh2EGy7WvkfggPToOk=; b=t/A9aJhtx3ZMcmCb6aoneeJ0TpGFqSY7cEnHmFUKSZmFTV55daOpqIPwyyeKIsNMht q4G1/DZlQtNOPl+D0pBV2OakbEvzIbPTX76/kFjBAY7qXD8wWMySvAvgV44GQsIQjiPq VfL3dpBHMX8evFIpNQiKN1w+xjVMcGLTpzuaLNcp5CwHban/MVWMkmAfJWoqTLvnYDtR csEsCrmaKAEF5NTMRiuh39AXq6v/DQK3PNz7xA9HNrNIja3aojzr7GwtCL5ZTQrX3QHp 5Z90StFMWs2U54NwIn4d6PJgDv0NXBeKXc++XintNBOvMFztcisnTq+/jZvuW7yXVZW/ pTyA== X-Gm-Message-State: AOAM533E9ksFdQq1YWjHVFFbjdEYMswzNSwKtJ7aqkfETH+2Y6ro2kCF JIywbiDAgo0kRo64ldZmtKJx3tXeWVo= X-Received: by 2002:a05:6512:32a2:: with SMTP id q2mr296199lfe.625.1611311860293; Fri, 22 Jan 2021 02:37:40 -0800 (PST) Received: from localhost.localdomain (91-159-194-103.elisa-laajakaista.fi. [91.159.194.103]) by smtp.gmail.com with ESMTPSA id g2sm831626lfb.255.2021.01.22.02.37.39 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Jan 2021 02:37:39 -0800 (PST) From: =?utf-8?q?Jan_Ekstr=C3=B6m?= To: ffmpeg-devel@ffmpeg.org Date: Fri, 22 Jan 2021 12:37:33 +0200 Message-Id: <20210122103734.24420-4-jeebjp@gmail.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210122103734.24420-1-jeebjp@gmail.com> References: <20210122103734.24420-1-jeebjp@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 3/4] ffprobe: switch to av_bprint_escape for XML escaping X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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: k1r5Up8OW323 Content-Length: 3344 From: Jan Ekström Signed-off-by: Jan Ekström --- fftools/ffprobe.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c index 3453aa09ff..564c062331 100644 --- a/fftools/ffprobe.c +++ b/fftools/ffprobe.c @@ -1672,24 +1672,6 @@ static av_cold int xml_init(WriterContext *wctx) return 0; } -static const char *xml_escape_str(AVBPrint *dst, const char *src, void *log_ctx) -{ - const char *p; - - for (p = src; *p; p++) { - switch (*p) { - case '&' : av_bprintf(dst, "%s", "&"); break; - case '<' : av_bprintf(dst, "%s", "<"); break; - case '>' : av_bprintf(dst, "%s", ">"); break; - case '"' : av_bprintf(dst, "%s", """); break; - case '\'': av_bprintf(dst, "%s", "'"); break; - default: av_bprint_chars(dst, *p, 1); - } - } - - return dst->str; -} - #define XML_INDENT() printf("%*c", xml->indent_level * 4, ' ') static void xml_print_section_header(WriterContext *wctx) @@ -1761,14 +1743,22 @@ static void xml_print_str(WriterContext *wctx, const char *key, const char *valu if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) { XML_INDENT(); + av_bprint_escape(&buf, key, NULL, + AV_ESCAPE_MODE_XML_ATT_VALUE_DOUBLE_QUOTED, 0); printf("<%s key=\"%s\"", - section->element_name, xml_escape_str(&buf, key, wctx)); + section->element_name, buf.str); av_bprint_clear(&buf); - printf(" value=\"%s\"/>\n", xml_escape_str(&buf, value, wctx)); + + av_bprint_escape(&buf, value, NULL, + AV_ESCAPE_MODE_XML_ATT_VALUE_DOUBLE_QUOTED, 0); + printf(" value=\"%s\"/>\n", buf.str); } else { if (wctx->nb_item[wctx->level]) printf(" "); - printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx)); + + av_bprint_escape(&buf, value, NULL, + AV_ESCAPE_MODE_XML_ATT_VALUE_DOUBLE_QUOTED, 0); + printf("%s=\"%s\"", key, buf.str); } av_bprint_finalize(&buf, NULL); From patchwork Fri Jan 22 10:37:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Jan_Ekstr=C3=B6m?= X-Patchwork-Id: 25107 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:ab61:0:0:0:0:0 with SMTP id u88csp1061612ybi; Fri, 22 Jan 2021 02:44:37 -0800 (PST) X-Google-Smtp-Source: ABdhPJzn6PwzflBQXUmeg5Ce6k88Qjh7WuP1XVIEXFVvSQEsjemNU5uq0IWqO4Q3iUplLbR+SGuv X-Received: by 2002:a05:6402:1751:: with SMTP id v17mr2746298edx.289.1611312277831; Fri, 22 Jan 2021 02:44:37 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1611312277; cv=none; d=google.com; s=arc-20160816; b=qFhvD0hdomr05xNHG2kXAtE8lg1wVvdXIUWO+hYjPCji18HR75HgzjXRNPzQ8tSH3n uIMKLrhbTH9KxedW68n4TFVaVy6UtgvlNJMiywdpnA3JuZytVvw8js1G06Vg57r4ooNF tUQ1oa0PLpQsLwjPcSetN2+5xQXGBIfqXZ1jMwDSi+V8eN3TxtcsokfLyq5VWwoi51pA YjxqpKf26YsinqHxs8asXkPTxuF/uQmJdmER8RLW5JDL1QShxCIXyP5pTfqU7SzlLBa+ i1D5O0OAxITlaf9EIuJYrSGtwpSjPtu+Q2AFFCUOddpEKKLKIG2Y8nJD9A/kjB8Oph3Q ytYA== 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=i2JDYyVtaQXRi1LCKlWrkeQ4GqyI2nFSFxOaqJ8Wqn4=; b=Tg+omQeZaGDMQzXmiMxSa+pAQ3e2WIE2RbH+tfDeIEMqyGjkFiEQJ5ghXPVwc3LSaK dA2x0WZ3XoggwKKJ6hhyk5wbbb4mrChMnNiEH6yNkr53Z05VXPU+N1uP8zVi+EN4Z9q3 VU8Xtnuyq2u0pR9XVwnQd6fmnk8ZEG//E7+Vxq0BmMMhVlxJxdNyDNa8TGkeqJhLhtNB YNfaUvg7ri//XJ9HP7GmN4dNJeCyt9DOB4pByDP5SOwgkml2/1tQstsNy3NCCtI4n7K6 GIF65QAuwu+pfK8xV/M24fpIDTdb0Q0HYlrFVQtZ5kH3Jzq68bSH6hRZPTB4OAzH9zK8 88Dw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=peXzm3ze; 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 v4si3392928edt.439.2021.01.22.02.44.37; Fri, 22 Jan 2021 02:44:37 -0800 (PST) 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=20161025 header.b=peXzm3ze; 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 0D62968A331; Fri, 22 Jan 2021 12:44:35 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lj1-f173.google.com (mail-lj1-f173.google.com [209.85.208.173]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 185D7689C96 for ; Fri, 22 Jan 2021 12:44:28 +0200 (EET) Received: by mail-lj1-f173.google.com with SMTP id e7so5948627ljg.10 for ; Fri, 22 Jan 2021 02:44:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=9O9XMB3MQPgzSi0KLQWTc5sfH3ZpcAFiA6rxguhpZd8=; b=peXzm3zeEbo+HA3HSpgaU3JSvPRAAjCdGtysAyMsVuolGoKiD4sSxmRtinfFRrvZXQ qd+qlNeMaB5pFXQQB6fMeYHwUeY9z5pz+Zb/1fasUDOs0PyVWhZBHL7mIOB+QHieeimQ FyINzmbOe1N59q2M7Ej91yV1EKNOvA/aQa1EX4IMpHdQbZLVfMCsve1mh3sOkhxaohV2 9837slfQxUFbOFfn2l55D+P40+1NHf8V2VlqpQ6nqp9DBJ+VfARHGBtI3Li4v2l8F3TK 4BRv7EqZ8KOaBd+omVJUc7tjIHwn9iAyNmhlF34M8WdkXlVuZH81LYs3aHkOeKI7HULf owcw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=9O9XMB3MQPgzSi0KLQWTc5sfH3ZpcAFiA6rxguhpZd8=; b=WNQVwRtfKb8ltFR8gATCEOU+jgb50fDXJS3UH8A6+V5zMWW3Jr/Wx4C72gN4vxKeSd idTsZyBe2ZG0oca3PvBKViOoXIVWsUA4ahE9kWwD7AB296n3T+fLZ68Riq4syVItVRK6 yFwPK1ne+VkDytq4cwnRJqoWPG+clenv2e6AcX9ad38U5lzhGXDgHtqTd+tlFQTsl3vC 5jm6Cr98sfBCgeYgrmkUd9Ia7a9eOi0+Io/DjS0tAFLb7kkZc2agp/0BMi3JlZ//RTPu yhNbBaX+3mLKSfpY2vDDU5lF86sPA8zSyIkbwbSulkmDBiun8iezE1RPUsMJpRGRYcb0 SZvQ== X-Gm-Message-State: AOAM531G0cuhUqPsFdIAQ+qgQEhLFqsACLIwYgBkChgA8Ue8KVCZgMca rv0R5Dc+L6J6kFDMrw499Mp6C7uZARM= X-Received: by 2002:ac2:47f8:: with SMTP id b24mr118360lfp.108.1611311861244; Fri, 22 Jan 2021 02:37:41 -0800 (PST) Received: from localhost.localdomain (91-159-194-103.elisa-laajakaista.fi. [91.159.194.103]) by smtp.gmail.com with ESMTPSA id g2sm831626lfb.255.2021.01.22.02.37.40 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Jan 2021 02:37:40 -0800 (PST) From: =?utf-8?q?Jan_Ekstr=C3=B6m?= To: ffmpeg-devel@ffmpeg.org Date: Fri, 22 Jan 2021 12:37:34 +0200 Message-Id: <20210122103734.24420-5-jeebjp@gmail.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210122103734.24420-1-jeebjp@gmail.com> References: <20210122103734.24420-1-jeebjp@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 4/4] {avcodec, avformat}: add TTML encoder and muxer X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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: CPeVhS3K7XIv Content-Length: 32158 From: Jan Ekström Enables encoding of other subtitle formats into TTML and writing them out as such documents. Signed-off-by: Jan Ekström --- Changelog | 1 + doc/general_contents.texi | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/ttmlenc.c | 179 +++++++++++++++++++++++++++++++++++++ libavcodec/version.h | 4 +- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/ttmlenc.c | 166 ++++++++++++++++++++++++++++++++++ libavformat/version.h | 4 +- tests/fate/subtitles.mak | 3 + tests/ref/fate/sub-ttmlenc | 122 +++++++++++++++++++++++++ 12 files changed, 480 insertions(+), 4 deletions(-) create mode 100644 libavcodec/ttmlenc.c create mode 100644 libavformat/ttmlenc.c create mode 100644 tests/ref/fate/sub-ttmlenc diff --git a/Changelog b/Changelog index 0b27c15122..9a6aeb4128 100644 --- a/Changelog +++ b/Changelog @@ -56,6 +56,7 @@ version : - shufflepixels filter - tmidequalizer filter - estdif filter +- TTML subtitle encoder and muxer version 4.3: diff --git a/doc/general_contents.texi b/doc/general_contents.texi index 443e8ed8d1..d799382f84 100644 --- a/doc/general_contents.texi +++ b/doc/general_contents.texi @@ -1334,6 +1334,7 @@ performance on systems without hardware floating point support). @item SubViewer v1 @tab @tab X @tab @tab X @item SubViewer @tab @tab X @tab @tab X @item TED Talks captions @tab @tab X @tab @tab X +@item TTML @tab X @tab @tab X @tab @item VobSub (IDX+SUB) @tab @tab X @tab @tab X @item VPlayer @tab @tab X @tab @tab X @item WebVTT @tab X @tab X @tab X @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 5ce3ee0ec9..d26e0264de 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -669,6 +669,7 @@ OBJS-$(CONFIG_TSCC_DECODER) += tscc.o msrledec.o OBJS-$(CONFIG_TSCC2_DECODER) += tscc2.o OBJS-$(CONFIG_TTA_DECODER) += tta.o ttadata.o ttadsp.o OBJS-$(CONFIG_TTA_ENCODER) += ttaenc.o ttaencdsp.o ttadata.o +OBJS-$(CONFIG_TTML_ENCODER) += ttmlenc.o ass_split.o OBJS-$(CONFIG_TWINVQ_DECODER) += twinvqdec.o twinvq.o metasound_data.o OBJS-$(CONFIG_TXD_DECODER) += txd.o OBJS-$(CONFIG_ULTI_DECODER) += ulti.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index f00d524747..81d20c44ec 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -686,6 +686,7 @@ extern AVCodec ff_subviewer_decoder; extern AVCodec ff_subviewer1_decoder; extern AVCodec ff_text_encoder; extern AVCodec ff_text_decoder; +extern AVCodec ff_ttml_encoder; extern AVCodec ff_vplayer_decoder; extern AVCodec ff_webvtt_encoder; extern AVCodec ff_webvtt_decoder; diff --git a/libavcodec/ttmlenc.c b/libavcodec/ttmlenc.c new file mode 100644 index 0000000000..a9b1411467 --- /dev/null +++ b/libavcodec/ttmlenc.c @@ -0,0 +1,179 @@ +/* + * TTML subtitle encoder + * Copyright (c) 2020 24i + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * TTML subtitle encoder + * @see https://www.w3.org/TR/ttml1/ + * @see https://www.w3.org/TR/ttml2/ + * @see https://www.w3.org/TR/ttml-imsc/rec + */ + +#include "avcodec.h" +#include "libavutil/avstring.h" +#include "libavutil/bprint.h" +#include "ass_split.h" +#include "ass.h" + +typedef struct { + AVCodecContext *avctx; + ASSSplitContext *ass_ctx; + AVBPrint buffer; +} TTMLContext; + +static void ttml_text_cb(void *priv, const char *text, int len) +{ + TTMLContext *s = priv; + AVBPrint cur_line = { 0 }; + AVBPrint *buffer = &s->buffer; + + av_bprint_init(&cur_line, len, AV_BPRINT_SIZE_UNLIMITED); + + av_bprint_append_data(&cur_line, text, len); + if (!av_bprint_is_complete(&cur_line)) { + av_log(s->avctx, AV_LOG_ERROR, + "Failed to move the current subtitle dialog to AVBPrint!\n"); + av_bprint_finalize(&cur_line, NULL); + return; + } + + + av_bprint_escape(buffer, cur_line.str, NULL, AV_ESCAPE_MODE_XML_CHAR_DATA, + 0); + + av_bprint_finalize(&cur_line, NULL); +} + +static void ttml_new_line_cb(void *priv, int forced) +{ + TTMLContext *s = priv; + + av_bprintf(&s->buffer, "
"); +} + +static const ASSCodesCallbacks ttml_callbacks = { + .text = ttml_text_cb, + .new_line = ttml_new_line_cb, +}; + +static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf, + int bufsize, const AVSubtitle *sub) +{ + TTMLContext *s = avctx->priv_data; + ASSDialog *dialog; + int i; + + av_bprint_clear(&s->buffer); + + for (i=0; inum_rects; i++) { + const char *ass = sub->rects[i]->ass; + + if (sub->rects[i]->type != SUBTITLE_ASS) { + av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n"); + return AVERROR(EINVAL); + } + +#if FF_API_ASS_TIMING + if (!strncmp(ass, "Dialogue: ", 10)) { + int num; + dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num); + + for (; dialog && num--; dialog++) { + ff_ass_split_override_codes(&ttml_callbacks, s, dialog->text); + } + } else { +#endif + dialog = ff_ass_split_dialog2(s->ass_ctx, ass); + if (!dialog) + return AVERROR(ENOMEM); + + ff_ass_split_override_codes(&ttml_callbacks, s, dialog->text); + ff_ass_free_dialog(&dialog); +#if FF_API_ASS_TIMING + } +#endif + } + + if (!av_bprint_is_complete(&s->buffer)) + return AVERROR(ENOMEM); + if (!s->buffer.len) + return 0; + + // force null-termination, so in case our destination buffer is + // too small, the return value is larger than bufsize minus null. + if (av_strlcpy(buf, s->buffer.str, bufsize) > bufsize - 1) { + av_log(avctx, AV_LOG_ERROR, "Buffer too small for TTML event.\n"); + return AVERROR_BUFFER_TOO_SMALL; + } + + return s->buffer.len; +} + +static av_cold int ttml_encode_close(AVCodecContext *avctx) +{ + TTMLContext *s = avctx->priv_data; + + ff_ass_split_free(s->ass_ctx); + + av_bprint_finalize(&s->buffer, NULL); + + return 0; +} + +static av_cold int ttml_encode_init(AVCodecContext *avctx) +{ + int ret = AVERROR_BUG; + TTMLContext *s = avctx->priv_data; + + s->avctx = avctx; + + if (!(s->ass_ctx = ff_ass_split(avctx->subtitle_header))) { + ret = AVERROR_INVALIDDATA; + goto failure; + } + + if (!(avctx->extradata = av_malloc(4 + AV_INPUT_BUFFER_PADDING_SIZE))) { + ret = AVERROR(ENOMEM); + goto failure; + } + avctx->extradata_size = 4; + + av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED); + + return 0; + +failure: + ff_ass_split_free(s->ass_ctx); + av_bprint_finalize(&s->buffer, NULL); + + return ret; +} + +AVCodec ff_ttml_encoder = { + .name = "ttml", + .long_name = NULL_IF_CONFIG_SMALL("TTML subtitle"), + .type = AVMEDIA_TYPE_SUBTITLE, + .id = AV_CODEC_ID_TTML, + .priv_data_size = sizeof(TTMLContext), + .init = ttml_encode_init, + .encode_sub = ttml_encode_frame, + .close = ttml_encode_close, +}; diff --git a/libavcodec/version.h b/libavcodec/version.h index 9f80caa9e0..807062af7f 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,8 +28,8 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 58 -#define LIBAVCODEC_VERSION_MINOR 117 -#define LIBAVCODEC_VERSION_MICRO 101 +#define LIBAVCODEC_VERSION_MINOR 118 +#define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ diff --git a/libavformat/Makefile b/libavformat/Makefile index 3a8fbcbe5f..f39a613901 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -543,6 +543,7 @@ OBJS-$(CONFIG_TRUEHD_DEMUXER) += rawdec.o mlpdec.o OBJS-$(CONFIG_TRUEHD_MUXER) += rawenc.o OBJS-$(CONFIG_TTA_DEMUXER) += tta.o apetag.o img2.o OBJS-$(CONFIG_TTA_MUXER) += ttaenc.o apetag.o img2.o +OBJS-$(CONFIG_TTML_MUXER) += ttmlenc.o OBJS-$(CONFIG_TTY_DEMUXER) += tty.o sauce.o OBJS-$(CONFIG_TY_DEMUXER) += ty.o OBJS-$(CONFIG_TXD_DEMUXER) += txd.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 6990af55f4..f4454e8362 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -442,6 +442,7 @@ extern AVInputFormat ff_truehd_demuxer; extern AVOutputFormat ff_truehd_muxer; extern AVInputFormat ff_tta_demuxer; extern AVOutputFormat ff_tta_muxer; +extern AVOutputFormat ff_ttml_muxer; extern AVInputFormat ff_txd_demuxer; extern AVInputFormat ff_tty_demuxer; extern AVInputFormat ff_ty_demuxer; diff --git a/libavformat/ttmlenc.c b/libavformat/ttmlenc.c new file mode 100644 index 0000000000..826f110f86 --- /dev/null +++ b/libavformat/ttmlenc.c @@ -0,0 +1,166 @@ +/* + * TTML subtitle muxer + * Copyright (c) 2020 24i + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * TTML subtitle muxer + * @see https://www.w3.org/TR/ttml1/ + * @see https://www.w3.org/TR/ttml2/ + * @see https://www.w3.org/TR/ttml-imsc/rec + */ + +#include "avformat.h" +#include "internal.h" + +enum TTMLPacketType { + PACKET_TYPE_PARAGRAPH, + PACKET_TYPE_DOCUMENT, +}; + +typedef struct TTMLMuxContext { + enum TTMLPacketType input_type; + unsigned int document_written; +} TTMLMuxContext; + +static const char ttml_header_text[] = +"\n" +"\n" +" \n" +"
\n"; + +static const char ttml_footer_text[] = +"
\n" +" \n" +"\n"; + +static void ttml_write_time(AVIOContext *pb, const char tag[], + int64_t millisec) +{ + int64_t sec, min, hour; + sec = millisec / 1000; + millisec -= 1000 * sec; + min = sec / 60; + sec -= 60 * min; + hour = min / 60; + min -= 60 * hour; + + avio_printf(pb, "%s=\"%02"PRId64":%02"PRId64":%02"PRId64".%03"PRId64"\"", + tag, hour, min, sec, millisec); +} + +static int ttml_write_header(AVFormatContext *ctx) +{ + TTMLMuxContext *ttml_ctx = ctx->priv_data; + ttml_ctx->document_written = 0; + + if (ctx->nb_streams != 1 || + ctx->streams[0]->codecpar->codec_id != AV_CODEC_ID_TTML) { + av_log(ctx, AV_LOG_ERROR, "Exactly one TTML stream is required!\n"); + return AVERROR(EINVAL); + } + + { + AVStream *st = ctx->streams[0]; + AVIOContext *pb = ctx->pb; + + AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, + 0); + const char *printed_lang = (lang && lang->value) ? lang->value : ""; + + // Not perfect, but decide whether the packet is a document or not + // by the existence of extradata. + ttml_ctx->input_type = st->codecpar->extradata ? + PACKET_TYPE_PARAGRAPH : + PACKET_TYPE_DOCUMENT; + + avpriv_set_pts_info(st, 64, 1, 1000); + + if (ttml_ctx->input_type == PACKET_TYPE_PARAGRAPH) + avio_printf(pb, ttml_header_text, printed_lang); + } + + return 0; +} + +static int ttml_write_packet(AVFormatContext *ctx, AVPacket *pkt) +{ + TTMLMuxContext *ttml_ctx = ctx->priv_data; + AVIOContext *pb = ctx->pb; + + switch (ttml_ctx->input_type) { + case PACKET_TYPE_PARAGRAPH: + // write out a paragraph element with the given contents. + avio_printf(pb, " pts); + avio_w8(pb, '\n'); + ttml_write_time(pb, " end", pkt->pts + pkt->duration); + avio_printf(pb, ">"); + avio_write(pb, pkt->data, pkt->size); + avio_printf(pb, "

\n"); + break; + case PACKET_TYPE_DOCUMENT: + // dump the given document out as-is. + if (ttml_ctx->document_written) { + av_log(ctx, AV_LOG_ERROR, + "Attempting to write multiple TTML documents into a " + "single document! The XML specification forbids this " + "as there has to be a single root tag.\n"); + return AVERROR(EINVAL); + } + avio_write(pb, pkt->data, pkt->size); + ttml_ctx->document_written = 1; + break; + default: + av_log(ctx, AV_LOG_ERROR, "Invalid TTML input packet type!\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +static int ttml_write_trailer(AVFormatContext *ctx) +{ + TTMLMuxContext *ttml_ctx = ctx->priv_data; + AVIOContext *pb = ctx->pb; + + if (ttml_ctx->input_type == PACKET_TYPE_PARAGRAPH) + avio_printf(pb, ttml_footer_text); + + return 0; +} + +AVOutputFormat ff_ttml_muxer = { + .name = "ttml", + .long_name = NULL_IF_CONFIG_SMALL("TTML subtitle"), + .extensions = "ttml", + .mime_type = "text/ttml", + .priv_data_size = sizeof(TTMLMuxContext), + .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | + AVFMT_TS_NONSTRICT, + .subtitle_codec = AV_CODEC_ID_TTML, + .write_header = ttml_write_header, + .write_packet = ttml_write_packet, + .write_trailer = ttml_write_trailer, +}; diff --git a/libavformat/version.h b/libavformat/version.h index a2b5901e74..b12ce3a843 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,8 +32,8 @@ // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium) // Also please add any ticket numbers that you believe might be affected here #define LIBAVFORMAT_VERSION_MAJOR 58 -#define LIBAVFORMAT_VERSION_MINOR 65 -#define LIBAVFORMAT_VERSION_MICRO 101 +#define LIBAVFORMAT_VERSION_MINOR 66 +#define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ diff --git a/tests/fate/subtitles.mak b/tests/fate/subtitles.mak index 6323d0f93d..ee65afe35b 100644 --- a/tests/fate/subtitles.mak +++ b/tests/fate/subtitles.mak @@ -106,6 +106,9 @@ fate-sub-scc: CMD = fmtstdout ass -ss 57 -i $(TARGET_SAMPLES)/sub/witch.scc FATE_SUBTITLES-$(call ALLYES, MPEGTS_DEMUXER DVBSUB_DECODER DVBSUB_ENCODER) += fate-sub-dvb fate-sub-dvb: CMD = framecrc -i $(TARGET_SAMPLES)/sub/dvbsubtest_filter.ts -map s:0 -c dvbsub +FATE_SUBTITLES-$(call ALLYES, FILE_PROTOCOL PIPE_PROTOCOL SRT_DEMUXER SUBRIP_DECODER TTML_ENCODER TTML_MUXER) += fate-sub-ttmlenc +fate-sub-ttmlenc: CMD = fmtstdout ttml -i $(TARGET_SAMPLES)/sub/SubRip_capability_tester.srt + FATE_SUBTITLES-$(call ENCMUX, ASS, ASS) += $(FATE_SUBTITLES_ASS-yes) FATE_SUBTITLES += $(FATE_SUBTITLES-yes) diff --git a/tests/ref/fate/sub-ttmlenc b/tests/ref/fate/sub-ttmlenc new file mode 100644 index 0000000000..624f37d092 --- /dev/null +++ b/tests/ref/fate/sub-ttmlenc @@ -0,0 +1,122 @@ + + + +
+

Don't show this text it may be used to insert hidden data

+

SubRip subtitles capability tester 1.3o by ale5000
Use VLC 1.1 or higher as reference for most things and MPC Home Cinema for others
This text should be blue
This text should be red
This text should be black
If you see this with the normal font, the player don't (fully) support font face

+

Hidden

+

This text should be small
This text should be normal
This text should be big

+

This should be an E with an accent: È
日本語
This text should be bold, italics and underline
This text should be small and green
This text should be small and red
This text should be big and brown

+

This line should be bold
This line should be italics
This line should be underline
This line should be strikethrough
Both lines
should be underline

+

>
It would be a good thing to
hide invalid html tags that are closed and show the text in them
but show un-closed invalid html tags
Show not opened tags
<

+

and also
hide invalid html tags with parameters that are closed and show the text in them
but show un-closed invalid html tags
This text should be showed underlined without problems also: 2<3,5>1,4<6
This shouldn't be underlined

+

This text should be in the normal position...

+

This text should NOT be in the normal position

+

Implementation is the same of the ASS tag
This text should be at the
top and horizontally centered

+

This text should be at the
middle and horizontally centered

+

This text should be at the
bottom and horizontally centered

+

This text should be at the
top and horizontally at the left

+

This text should be at the
middle and horizontally at the left
(The second position must be ignored)

+

This text should be at the
bottom and horizontally at the left

+

This text should be at the
top and horizontally at the right

+

This text should be at the
middle and horizontally at the right

+

This text should be at the
bottom and horizontally at the right

+

This could be the most difficult thing to implement

+

First text

+

Second, it shouldn't overlap first

+

Third, it should replace second

+

Fourth, it shouldn't overlap first and third

+

Fifth, it should replace third

+

Sixth, it shouldn't be
showed overlapped

+

TEXT 1 (bottom)

+

text 2

+

Hide these tags:
also hide these tags:
but show this: {normal text}

+


\ N is a forced line break
\ h is a hard space
Normal spaces at the start and at the end of the line are trimmed while hard spaces are not trimmed.
The\hline\hwill\hnever\hbreak\hautomatically\hright\hbefore\hor\hafter\ha\hhard\hspace.\h:-D

+


\h\h\h\h\hA (05 hard spaces followed by a letter)
A (Normal spaces followed by a letter)
A (No hard spaces followed by a letter)

+

\h\h\h\h\hA (05 hard spaces followed by a letter)
A (Normal spaces followed by a letter)
A (No hard spaces followed by a letter)
Show this: \TEST and this: \-)

+


A letter followed by 05 hard spaces: A\h\h\h\h\h
A letter followed by normal spaces: A
A letter followed by no hard spaces: A
05 hard spaces between letters: A\h\h\h\h\hA
5 normal spaces between letters: A A

^--Forced line break

+

Both line should be strikethrough,
yes.
Correctly closed tags
should be hidden.

+

It shouldn't be strikethrough,
not opened tag showed as text.
Not opened tag showed as text.

+

Three lines should be strikethrough,
yes.
Not closed tags showed as text

+

Both line should be strikethrough but
the wrong closing tag should be showed

+
+ +