libavformat/id3v2: deprecate legacy COMM descriptor-as-key behavior

This commit is contained in:
Romain Beauxis
2026-03-11 19:14:47 -05:00
parent eb107d8772
commit b0c702aec2
8 changed files with 68 additions and 28 deletions

View File

@@ -2,6 +2,12 @@ The last version increases of all libraries were on 2026-06-23.
API changes, most recent first:
2026-07-xx - xxxxxxxxxx - lavf 63.5.101 - version_major.h
Deprecate using descriptor for metadata tag name in id3v2 COMM tags.
COMM Tags are duplicated, exporting deprecated named tag along with
new <tag>-<description>-<lang> tag until the next libavformat major
version bumped.
2026-07-14 - xxxxxxxxxx - lavu 61.5.100 - hwcontext_cuda.h
Add AVCUDAFramesContext and AVCUDAArrayFrameDescriptor.

View File

@@ -357,6 +357,15 @@ struct AVFrame;
* - Several modifiers can be applied to the tag name. This is done by
* appending a dash character ('-') and the modifier name in the order
* they appear in the list below -- e.g. foo-eng-sort, not foo-sort-eng.
* - descriptor -- some formats (e.g. ID3v2 COMM and USLT frames) attach
* a free-form descriptor to a tag to distinguish multiple instances.
* The full key format is "<tag>-<descriptor>-<lang>", but either
* component may be absent. When writing, the last dash-separated suffix
* is interpreted as a language code if it is a valid ISO 639-2/B code;
* otherwise the entire portion after the first dash is treated as a
* descriptor. Examples: "comment-eng" (lang only),
* "comment-MusicMatch_Bio-eng" (descriptor + lang),
* "comment-foobar" (descriptor only, foobar is not a valid lang code).
* - language -- a tag whose value is localized for a particular language
* is appended with the ISO 639-2/B 3-letter language code.
* For example: Author-ger=Michael, Author-eng=Mike
@@ -381,6 +390,9 @@ struct AVFrame;
e.g. "Various Artists" for compilation albums.
artist -- main creator of the work
comment -- any additional description of the file.
ID3v2 COMM frames: bare "comment" has no lang or descriptor;
"comment-<lang>" for lang only; "comment-<descriptor>-<lang>"
for both (see descriptor modifier above).
composer -- who composed the work, if different from artist.
copyright -- name of copyright holder.
creation_time-- date when the file was created, preferably in ISO 8601.
@@ -394,6 +406,10 @@ struct AVFrame;
language -- main language in which the work is performed, preferably
in ISO 639-2 format. Multiple languages can be specified by
separating them with commas.
lyrics -- lyrics for the work.
ID3v2 USLT frames: bare "lyrics" has no lang or descriptor;
"lyrics-<lang>" for lang only; "lyrics-<descriptor>-<lang>"
for both (see descriptor modifier above).
performer -- artist who performed the work, if different from artist.
E.g for "Also sprach Zarathustra", artist would be "Richard
Strauss" and performer "London Philharmonic Orchestra".

View File

@@ -39,7 +39,6 @@
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "libavcodec/png.h"
#include "avio_internal.h"
#include "avlanguage.h"
@@ -379,9 +378,7 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
/**
* Parse a lang descr tag such as COMM and USLT.
*
* COMM with a non-empty descriptor: the descriptor becomes the bare key
* (e.g. "MusicMatch_Bio"). USLT and all other cases produce
* "<base>-<descriptor>-<lang>".
* A non-empty descriptor produces "<base>-<descriptor>-<lang>" keys.
*/
static void read_lang_descr_tag(AVFormatContext *s, AVIOContext *pb,
const char *key, int taglen,
@@ -424,29 +421,35 @@ static void read_lang_descr_tag(AVFormatContext *s, AVIOContext *pb,
}
if (descriptor && *descriptor) {
#if FF_API_OLD_ID3V2_COMMENT
if (!strcmp(key, "comment")) {
/* legacy COMM: non-empty descriptor becomes the metadata key */
flags |= AV_DICT_DONT_STRDUP_KEY;
key = (char *)descriptor;
descriptor = NULL;
} else {
/* USLT: <tag>-<descriptor>-<lang> */
if (av_strnlen(language, 3) > 0)
full_key = av_asprintf("%s-%s-%s", key, descriptor, language);
else if (strlen((char *)descriptor) == 3 &&
ff_convert_lang_to((char *)descriptor, AV_LANG_ISO639_2_BIBL))
/* Descriptor looks like a lang code: add trailing lang to
* keep the key unambiguous on the write side. */
full_key = av_asprintf("%s-%s-und", key, descriptor);
else
full_key = av_asprintf("%s-%s", key, descriptor);
if (!full_key) {
av_freep(&descriptor);
av_freep(&dst);
return;
}
key = full_key;
av_log(s, AV_LOG_WARNING,
"Deprecated: COMM descriptor '%s' used as metadata key. "
"This will change in a future version.\n", descriptor);
av_dict_set(metadata, (const char *)descriptor, (const char *)dst,
AV_DICT_DONT_OVERWRITE);
}
#endif
int descr_len = strlen((char *)descriptor);
if (av_strnlen(language, 3) > 0)
full_key = av_asprintf("%s-%s-%s", key, descriptor, language);
// descr = "eng"
else if ((descr_len == 3 &&
ff_convert_lang_to((char *)descriptor, AV_LANG_ISO639_2_BIBL)) ||
// descr = Foo-eng
(descr_len > 4 && descriptor[descr_len-4] == '-' &&
ff_convert_lang_to((char *)descriptor+descr_len-3, AV_LANG_ISO639_2_BIBL))) {
/* Descriptor looks like a lang code: add trailing lang to
* keep the key unambiguous on the write side. */
full_key = av_asprintf("%s-%s-und", key, descriptor);
} else
full_key = av_asprintf("%s-%s", key, descriptor);
if (!full_key) {
av_freep(&descriptor);
av_freep(&dst);
return;
}
key = full_key;
} else if (av_strnlen(language, 3) == 3) {
full_key = av_asprintf("%s-%s", key, language);
if (!full_key) {

View File

@@ -32,7 +32,7 @@
#include "version_major.h"
#define LIBAVFORMAT_VERSION_MINOR 5
#define LIBAVFORMAT_VERSION_MICRO 100
#define LIBAVFORMAT_VERSION_MICRO 101
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \

View File

@@ -47,6 +47,8 @@
#define FF_API_LCEVC_STRUCT (LIBAVFORMAT_VERSION_MAJOR < 64)
#define FF_API_OLD_ID3V2_COMMENT (LIBAVFORMAT_VERSION_MAJOR < 64)
#define FF_API_R_FRAME_RATE 1
#endif /* AVFORMAT_VERSION_MAJOR_H */

View File

@@ -1,9 +1,12 @@
263462774b77f2b20a9cb5cbe492f910 *tests/data/fate/id3v2-reenc-remux-keep.mp3
192072 tests/data/fate/id3v2-reenc-remux-keep.mp3
f68df33ad53e6175269f7ea876b492e3 *tests/data/fate/id3v2-reenc-remux-keep.mp3
192378 tests/data/fate/id3v2-reenc-remux-keep.mp3
[FORMAT]
TAG:title=7rk
TAG:iTunPGAP=0
TAG:comment-iTunPGAP-eng=0
TAG:encoded_by=iTunes 12.7.0.166
TAG:iTunNORM= 00000362 000004C0 0000308F 00003CC5 00000DAC 00000DAC 00007D14 00007AC9 000007C1 0000175E
TAG:comment-iTunNORM-eng= 00000362 000004C0 0000308F 00003CC5 00000DAC 00000DAC 00007D14 00007AC9 000007C1 0000175E
TAG:iTunSMPB= 00000000 00000210 0000086A 0000000000066486 00000000 0002DA9D 00000000 00000000 00000000 00000000 00000000 00000000
TAG:comment-iTunSMPB-eng= 00000000 00000210 0000086A 0000000000066486 00000000 0002DA9D 00000000 00000000 00000000 00000000 00000000 00000000
[/FORMAT]

View File

@@ -11,11 +11,16 @@ TAG:genre=Inconnu
TAG:comment-eng=
TAG:lyrics-eng=
TAG:MusicMatch_Bio=
TAG:comment-MusicMatch_Bio-eng=
TAG:TLEN=286000
TAG:MusicMatch_Tempo=
TAG:comment-MusicMatch_Tempo-eng=
TAG:MusicMatch_Mood=
TAG:comment-MusicMatch_Mood-eng=
TAG:MusicMatch_Preference=
TAG:comment-MusicMatch_Preference-eng=
TAG:MusicMatch_Situation=
TAG:comment-MusicMatch_Situation-eng=
TAG:track=5
TAG:composer=Jacques Higelin
TAG:WM/EncodingTime=127518048290000000

View File

@@ -13,11 +13,16 @@ TAG:genre=Inconnu
TAG:comment-eng=
TAG:lyrics-eng=
TAG:MusicMatch_Bio=
TAG:comment-MusicMatch_Bio-eng=
TAG:TLEN=286000
TAG:MusicMatch_Tempo=
TAG:comment-MusicMatch_Tempo-eng=
TAG:MusicMatch_Mood=
TAG:comment-MusicMatch_Mood-eng=
TAG:MusicMatch_Preference=
TAG:comment-MusicMatch_Preference-eng=
TAG:MusicMatch_Situation=
TAG:comment-MusicMatch_Situation-eng=
TAG:WM/TrackNumber=5
TAG:WM/Composer=Jacques Higelin
TAG:WM/Genre=Inconnu