From patchwork Thu Aug 25 00:27:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: rcombs X-Patchwork-Id: 37463 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:139a:b0:8f:1db5:eae2 with SMTP id w26csp26238pzh; Wed, 24 Aug 2022 17:27:55 -0700 (PDT) X-Google-Smtp-Source: AA6agR4g6MO/XXGwN6fIXNcMJ/lBoicKOUVguIiv81do63Xim6vz+joQu99KP4bmmUd1x9E+Lfz6 X-Received: by 2002:a17:907:75f2:b0:73d:585e:547b with SMTP id jz18-20020a17090775f200b0073d585e547bmr844651ejc.147.1661387275641; Wed, 24 Aug 2022 17:27:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1661387275; cv=none; d=google.com; s=arc-20160816; b=L8D88NPmPklZV04Ex4cJDLKRlHz/KdDjaMAOe00pTjijfT28Lc8KSaN0sJBINjT4mf Feo/oA34nIIQoD7dwrQREh4kXGCcEjO1d4QTKlhvc5oOA8arRY69tE0baloSsiurUxGZ p7SCZlHpm4yrpXjypjHotQrgPSAvAeFgHEFQU1YQJnD3P+wGt5mHUe779tsxTv4O8XZf DtuJS92bV+NegiTjYhlPIs1zWubWKdvFkQMeSy9EgTh8L2+rbm/bvZvtuYScZVuYQOUL IYyTh47oGk+Zqv4bHstt4o1HSWj8MiY/HY0HvF1BOvqP5WrZ1ywEP6EvCt8K0QvDFq6N Vp/g== 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=4VT+FGLohU0G8rRJ8WhVUHzm05EL7Qi5ZDyxr0AZyWg=; b=Jtu0o4S8DpfoW/0p2A2x0k8QzoU4sOySSCu0K/OQJinCRgM2PXrZ0/EDQK8EDJ7bER nFgpsRmXv5dhF0QkoqEdtSlGhNF2ND2bggFAvM7e2CZAaMcQaACNKEbqYXTyW7tq2u8j VYmbvHR/u2G1y1KQmqIdu55Pm6sCNjCzDeipsReY0YUmDuADoOFP5HmLbb5vZqdihBPR EwGs19CVdKL3z5l0NoaxrVcAFoX+1VlQvQ2PmlcHc4GTEVgllGHjpCokkgxwfC00dtuw 59LGVhp3bpeugP4vIp+pBFHsXAxLECiXOvcD6N06spE4pChSGOwJmksOBAYzLRZDFiKZ ADZQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@rcombs.me header.s=google header.b=r67IuHoZ; 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=QUARANTINE sp=QUARANTINE dis=NONE) header.from=rcombs.me Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id f6-20020a17090631c600b00730a07ef039si2578165ejf.423.2022.08.24.17.27.55; Wed, 24 Aug 2022 17:27:55 -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=@rcombs.me header.s=google header.b=r67IuHoZ; 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=QUARANTINE sp=QUARANTINE dis=NONE) header.from=rcombs.me Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 7BCB368B993; Thu, 25 Aug 2022 03:27:38 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qt1-f175.google.com (mail-qt1-f175.google.com [209.85.160.175]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 21A9968B937 for ; Thu, 25 Aug 2022 03:27:31 +0300 (EEST) Received: by mail-qt1-f175.google.com with SMTP id a4so14085384qto.10 for ; Wed, 24 Aug 2022 17:27:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rcombs.me; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc; bh=kSRRoBFkBOWQ1BGEXZopxUfT2hRwJvMLYOw8EvMyDFI=; b=r67IuHoZybrRfJo6wcVj6f2SW64Ul8ZLSCvJwTkbbMuJL0Drh6MzuBHkr42WNxXz2x vMhMsPihnsI1bBANEOgCw+DVU/6UbsZTIWEZztbCwyCYXOvCHbFlkmQFylrPwYCX+Agd Dc7ML0SmqibvrJ+Wf3AK3qV16ZEsy4VFWa3pAUBhcCtVxyEyiLegnUydspck/PTL/bRn fjssBD28Hgxb+2ETsKvw1awzRzHGmM07CGkZkk95SCkyxiiryFKJ1GEiqVNL5Xn3+qKD wZ3+D+ZnOCXMTOZuHzF09do/J8XWvADIpYRrO5iI4U77mpTc+SglS55swlKQpVUM2G1w rvxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc; bh=kSRRoBFkBOWQ1BGEXZopxUfT2hRwJvMLYOw8EvMyDFI=; b=004XwcFDhlp/kxcsc1UxiHbG8IxPN9JeZIKAt4OEaZFl0LRtakfjihjAuwlC6+a4kP U+h5hM67wzozCvhABp3oHZVnmM9c5RHSHbPfx6x25qve90hiKKS4ryX+LKGVfXjKNFUi HrBNafq0si6u1T2lmlpQwYv9YusNlYNVxmvXN+lOULSqtNr2zEC+l9QsOZaQsOufsmgD PXFCpLEVNyE7zcI237h7cBlDZNU17eoJayY3Q+Rc5wpkCOtLjKSh17MGnu7SnKBHlmE+ XBebruzSgVRrl3O90ePJX7RvYR+8tZqhxgtb3pgoB1agWEg3A9BPQ9RhKW6novR7uSuT dNyw== X-Gm-Message-State: ACgBeo19Fxv+9qkto96q3l6BoV0Z/mA23VA7UqG40/LtLsBHc+gCmu2w Zp7eFTh1Zrdqlh/F36m8no0Xk8VXGl/H X-Received: by 2002:ac8:5cc2:0:b0:344:50c9:5308 with SMTP id s2-20020ac85cc2000000b0034450c95308mr1683021qta.602.1661387249728; Wed, 24 Aug 2022 17:27:29 -0700 (PDT) Received: from localhost.localdomain ([192.210.24.132]) by smtp.gmail.com with ESMTPSA id i22-20020a05620a405600b006bba9575621sm16521091qko.68.2022.08.24.17.27.29 for (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Wed, 24 Aug 2022 17:27:29 -0700 (PDT) From: rcombs To: ffmpeg-devel@ffmpeg.org Date: Wed, 24 Aug 2022 19:27:22 -0500 Message-Id: <20220825002722.79902-3-rcombs@rcombs.me> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220825002722.79902-1-rcombs@rcombs.me> References: <20220825002722.79902-1-rcombs@rcombs.me> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 3/3] lavf/id3v2dec: support multiple values and TIPL frames 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: ztv072pfVzHP Fixes https://trac.ffmpeg.org/ticket/6949 Ordinary text frames in ID3v2 are allowed to have multiple (null-separated) values. This technically isn't allowed in TXXX, but it's used in practice by Picard, and supporting it is harmless. TIPL/IPL (Involved People List) and TMCL (Musician Credits List) work similarly to TXXX, but alternate key-value-key-value. --- libavformat/id3v2.c | 49 ++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index 191a305ffb..335a1436b2 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -321,8 +321,12 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, AVDictionary **metadata, const char *key) { uint8_t *dst; - int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL; + uint8_t *dst_key = NULL; + int encoding, dict_flags = AV_DICT_MULTIKEY | AV_DICT_DONT_STRDUP_VAL | AV_DICT_DEDUP; unsigned genre; + int count = 0; + int is_tipl = !(strcmp(key, "TIPL") && strcmp(key, "TMCL") && + strcmp(key, "IPL")); if (taglen < 1) return; @@ -330,30 +334,33 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, encoding = avio_r8(pb); taglen--; /* account for encoding type byte */ - if (decode_str(s, pb, encoding, &dst, &taglen) < 0) { - av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key); - return; - } - - if (!(strcmp(key, "TCON") && strcmp(key, "TCO")) && - (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1) && - genre <= ID3v1_GENRE_MAX) { - av_freep(&dst); - dst = av_strdup(ff_id3v1_genre_str[genre]); - } else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) { - /* dst now contains the key, need to get value */ - key = dst; + while (taglen > 1) { if (decode_str(s, pb, encoding, &dst, &taglen) < 0) { av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key); - av_freep(&key); return; } - dict_flags |= AV_DICT_DONT_STRDUP_KEY; - } else if (!*dst) - av_freep(&dst); - if (dst) - av_dict_set(metadata, key, dst, dict_flags); + count++; + + if (!(strcmp(key, "TCON") && strcmp(key, "TCO")) && + (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1) && + genre <= ID3v1_GENRE_MAX) { + av_freep(&dst); + dst = av_strdup(ff_id3v1_genre_str[genre]); + } else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX")) || + (is_tipl && (count & 1))) { + /* dst now contains the key, need to get value */ + av_free(dst_key); + key = dst_key = dst; + continue; + } else if (!*dst) + av_freep(&dst); + + if (dst) + av_dict_set(metadata, key, dst, dict_flags); + } + + av_free(dst_key); } static void read_uslt(AVFormatContext *s, AVIOContext *pb, int taglen, @@ -1039,7 +1046,7 @@ static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata, pbx = &pb_local.pub; // read from sync buffer } #endif - if (tag[0] == 'T') + if (tag[0] == 'T' || !strcmp(tag, "IPL")) /* parse text tag */ read_ttag(s, pbx, tlen, metadata, tag); else if (!memcmp(tag, "USLT", 4))