diff --git a/doc/APIchanges b/doc/APIchanges index a3a978c43b..2b0f3ab87e 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -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 until the next libavformat major + version bumped. + 2026-07-14 - xxxxxxxxxx - lavu 61.5.100 - hwcontext_cuda.h Add AVCUDAFramesContext and AVCUDAArrayFrameDescriptor. diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 2ebe889b54..e5a6481aa8 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -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 "--", 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-" for lang only; "comment--" + 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-" for lang only; "lyrics--" + 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". diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index 3e931d2bd2..1b4d4e65ef 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -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 - * "--". + * A non-empty descriptor produces "--" 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: -- */ - 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) { diff --git a/libavformat/version.h b/libavformat/version.h index e2634b85ae..384cbd49cc 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -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, \ diff --git a/libavformat/version_major.h b/libavformat/version_major.h index 1e43129016..f0eaa170b4 100644 --- a/libavformat/version_major.h +++ b/libavformat/version_major.h @@ -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 */ diff --git a/tests/ref/fate/id3v2-reenc-remux-keep b/tests/ref/fate/id3v2-reenc-remux-keep index e685b11291..7bf43f0612 100644 --- a/tests/ref/fate/id3v2-reenc-remux-keep +++ b/tests/ref/fate/id3v2-reenc-remux-keep @@ -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] diff --git a/tests/ref/fate/id3v2-wma-comm b/tests/ref/fate/id3v2-wma-comm index 68d113862c..e2f19f5077 100644 --- a/tests/ref/fate/id3v2-wma-comm +++ b/tests/ref/fate/id3v2-wma-comm @@ -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 diff --git a/tests/ref/fate/id3v2-wma-comm-asf_o b/tests/ref/fate/id3v2-wma-comm-asf_o index 639f0a02ce..5d8e02aac6 100644 --- a/tests/ref/fate/id3v2-wma-comm-asf_o +++ b/tests/ref/fate/id3v2-wma-comm-asf_o @@ -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