diff options
author | John Stebbins <[email protected]> | 2019-08-04 11:07:02 -0700 |
---|---|---|
committer | John Stebbins <[email protected]> | 2019-08-11 15:36:41 -0700 |
commit | 57e46db5dfc64db0c5bf5d67357fe3107d4bb8fd (patch) | |
tree | d25c5276edba375fd16f3f1a971365b92f4773a1 /contrib/ffmpeg | |
parent | 3999c06cb6194d5e537ce2460b80ecf2d2af81af (diff) |
ffmpeg: add support to read/write mp4 'titl' track tag
Diffstat (limited to 'contrib/ffmpeg')
3 files changed, 297 insertions, 11 deletions
diff --git a/contrib/ffmpeg/A05-mov-read-name-track-tag-written-by-movenc.patch b/contrib/ffmpeg/A05-mov-read-name-track-tag-written-by-movenc.patch index 514aa79d0..67e4d2868 100644 --- a/contrib/ffmpeg/A05-mov-read-name-track-tag-written-by-movenc.patch +++ b/contrib/ffmpeg/A05-mov-read-name-track-tag-written-by-movenc.patch @@ -1,14 +1,14 @@ -From b6ce7b6a4ec0429069f05e63edce907c0f80aaea Mon Sep 17 00:00:00 2001 +From 375d09561cb88a7002a833614dbd399446479cd1 Mon Sep 17 00:00:00 2001 From: John Stebbins <[email protected]> Date: Wed, 31 Jul 2019 15:27:40 -0700 -Subject: [PATCH] mov: read 'name' track tag written by movenc +Subject: [PATCH 1/3] mov: read 'name' track tag written by movenc --- libavformat/mov.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/libavformat/mov.c b/libavformat/mov.c -index 24de5429d1..fce69129d9 100644 +index 24de5429d1..1f933cccfd 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -306,6 +306,7 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) @@ -19,14 +19,14 @@ index 24de5429d1..fce69129d9 100644 switch (atom.type) { case MKTAG( '@','P','R','M'): key = "premiere_version"; raw = 1; break; -@@ -384,6 +385,7 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) - case MKTAG(0xa9,'m','a','k'): key = "make"; break; - case MKTAG(0xa9,'m','o','d'): key = "model"; break; - case MKTAG(0xa9,'n','a','m'): key = "title"; break; -+ case MKTAG( 'n','a','m','e'): key = "title"; break; - case MKTAG(0xa9,'o','p','e'): key = "original_artist"; break; - case MKTAG(0xa9,'p','r','d'): key = "producer"; break; - case MKTAG(0xa9,'p','r','f'): key = "performers"; break; +@@ -338,6 +339,7 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) + return mov_metadata_loci(c, pb, atom.size); + case MKTAG( 'm','a','n','u'): key = "make"; break; + case MKTAG( 'm','o','d','l'): key = "model"; break; ++ case MKTAG( 'n','a','m','e'): key = "title"; raw = 1; break; + case MKTAG( 'p','c','s','t'): key = "podcast"; + parse = mov_metadata_int8_no_padding; break; + case MKTAG( 'p','g','a','p'): key = "gapless_playback"; @@ -514,17 +516,23 @@ retry: } str[str_size] = 0; diff --git a/contrib/ffmpeg/A06-movenc-write-3gpp-track-titl-tag.patch b/contrib/ffmpeg/A06-movenc-write-3gpp-track-titl-tag.patch new file mode 100644 index 000000000..5c40e66a0 --- /dev/null +++ b/contrib/ffmpeg/A06-movenc-write-3gpp-track-titl-tag.patch @@ -0,0 +1,126 @@ +From e9dde141a5fc27df87eb4b3454e34d725b211708 Mon Sep 17 00:00:00 2001 +From: John Stebbins <[email protected]> +Date: Sun, 4 Aug 2019 10:52:30 -0700 +Subject: [PATCH 2/3] movenc: write 3gpp track 'titl' tag + +Apple software used to use 'name' raw tag for track titles. When they +rewrote everything with AVFoundation, they switched to using 3gpp 'titl' +tag for track titles and 'name' no longer works. +--- + libavformat/movenc.c | 78 +++++++++++++++++++++++--------------------- + 1 file changed, 40 insertions(+), 38 deletions(-) + +diff --git a/libavformat/movenc.c b/libavformat/movenc.c +index a96139077b..b1b6ef0e4e 100644 +--- a/libavformat/movenc.c ++++ b/libavformat/movenc.c +@@ -3077,6 +3077,35 @@ static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track) + return len + 24; + } + ++static uint16_t language_code(const char *str) ++{ ++ return (((str[0] - 0x60) & 0x1F) << 10) + ++ (((str[1] - 0x60) & 0x1F) << 5) + ++ (( str[2] - 0x60) & 0x1F); ++} ++ ++static int mov_write_3gp_udta_tag(AVIOContext *pb, AVDictionary *metadata, ++ const char *tag, const char *str) ++{ ++ int64_t pos = avio_tell(pb); ++ AVDictionaryEntry *t = av_dict_get(metadata, str, NULL, 0); ++ if (!t || !utf8len(t->value)) ++ return 0; ++ avio_wb32(pb, 0); /* size */ ++ ffio_wfourcc(pb, tag); /* type */ ++ avio_wb32(pb, 0); /* version + flags */ ++ if (!strcmp(tag, "yrrc")) ++ avio_wb16(pb, atoi(t->value)); ++ else { ++ avio_wb16(pb, language_code("eng")); /* language */ ++ avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */ ++ if (!strcmp(tag, "albm") && ++ (t = av_dict_get(metadata, "track", NULL, 0))) ++ avio_w8(pb, atoi(t->value)); ++ } ++ return update_size(pb, pos); ++} ++ + static int mov_write_track_metadata(AVIOContext *pb, AVStream *st, + const char *tag, const char *str) + { +@@ -3105,8 +3134,10 @@ static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov, + if (ret < 0) + return ret; + +- if (mov->mode & (MODE_MP4|MODE_MOV)) ++ if (mov->mode & (MODE_MP4|MODE_MOV)) { + mov_write_track_metadata(pb_buf, st, "name", "title"); ++ mov_write_3gp_udta_tag(pb_buf, st->metadata, "titl", "title"); ++ } + + if ((size = avio_close_dyn_buf(pb_buf, &buf)) > 0) { + avio_wb32(pb, size + 8); +@@ -3680,35 +3711,6 @@ static int ascii_to_wc(AVIOContext *pb, const uint8_t *b) + return 0; + } + +-static uint16_t language_code(const char *str) +-{ +- return (((str[0] - 0x60) & 0x1F) << 10) + +- (((str[1] - 0x60) & 0x1F) << 5) + +- (( str[2] - 0x60) & 0x1F); +-} +- +-static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s, +- const char *tag, const char *str) +-{ +- int64_t pos = avio_tell(pb); +- AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0); +- if (!t || !utf8len(t->value)) +- return 0; +- avio_wb32(pb, 0); /* size */ +- ffio_wfourcc(pb, tag); /* type */ +- avio_wb32(pb, 0); /* version + flags */ +- if (!strcmp(tag, "yrrc")) +- avio_wb16(pb, atoi(t->value)); +- else { +- avio_wb16(pb, language_code("eng")); /* language */ +- avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */ +- if (!strcmp(tag, "albm") && +- (t = av_dict_get(s->metadata, "track", NULL, 0))) +- avio_w8(pb, atoi(t->value)); +- } +- return update_size(pb, pos); +-} +- + static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s) + { + int64_t pos = avio_tell(pb); +@@ -3747,14 +3749,14 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov, + return ret; + + if (mov->mode & MODE_3GP) { +- mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist"); +- mov_write_3gp_udta_tag(pb_buf, s, "titl", "title"); +- mov_write_3gp_udta_tag(pb_buf, s, "auth", "author"); +- mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre"); +- mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment"); +- mov_write_3gp_udta_tag(pb_buf, s, "albm", "album"); +- mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright"); +- mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "perf", "artist"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "titl", "title"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "auth", "author"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "gnre", "genre"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "dscp", "comment"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "albm", "album"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "cprt", "copyright"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "yrrc", "date"); + mov_write_loci_tag(s, pb_buf); + } else if (mov->mode == MODE_MOV && !(mov->flags & FF_MOV_FLAG_USE_MDTA)) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4 + mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0); +-- +2.21.0 + diff --git a/contrib/ffmpeg/A07-mov-read-3gpp-udta-tags.patch b/contrib/ffmpeg/A07-mov-read-3gpp-udta-tags.patch new file mode 100644 index 000000000..6368c7180 --- /dev/null +++ b/contrib/ffmpeg/A07-mov-read-3gpp-udta-tags.patch @@ -0,0 +1,160 @@ +From 1b02b0afe201cd14a97d83dc08716bf9cc188cb0 Mon Sep 17 00:00:00 2001 +From: John Stebbins <[email protected]> +Date: Sun, 4 Aug 2019 10:59:38 -0700 +Subject: [PATCH 3/3] mov: read 3gpp udta tags + +--- + libavformat/mov.c | 110 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 107 insertions(+), 3 deletions(-) + +diff --git a/libavformat/mov.c b/libavformat/mov.c +index 1f933cccfd..0c365cde3e 100644 +--- a/libavformat/mov.c ++++ b/libavformat/mov.c +@@ -50,6 +50,7 @@ + #include "libavcodec/flac.h" + #include "libavcodec/mpegaudiodecheader.h" + #include "avformat.h" ++#include "avlanguage.h" + #include "internal.h" + #include "avio_internal.h" + #include "riff.h" +@@ -295,6 +296,82 @@ static int mov_metadata_hmmt(MOVContext *c, AVIOContext *pb, unsigned len) + return 0; + } + ++static int mov_read_3gp_udta_tag(MOVContext *c, AVIOContext *pb, MOVAtom atom) ++{ ++ const char *key; ++ AVDictionary *metadata; ++ uint16_t langcode = 0; ++ char key2[32], language[4] = {0}; ++ uint32_t str_size, version; ++ char *str; ++ ++ if (atom.size < 6) ++ return AVERROR_INVALIDDATA; ++ ++ switch (atom.type) { ++ case MKTAG( 'a','l','b','m'): key = "album"; break; ++ case MKTAG( 'a','u','t','h'): key = "author"; break; ++ case MKTAG( 'c','p','r','t'): key = "copyright"; break; ++ case MKTAG( 'd','s','c','p'): key = "comment"; break; ++ case MKTAG( 'g','n','r','e'): key = "genre"; break; ++ case MKTAG( 'p','e','r','f'): key = "artist"; break; ++ case MKTAG( 't','i','t','l'): key = "title"; break; ++ case MKTAG( 'y','r','r','c'): key = "date"; break; ++ default: return 0; ++ } ++ ++ version = avio_rb32(pb); // version + flags ++ if (version != 0) ++ return AVERROR_INVALIDDATA; ++ ++ if (MKTAG( 'y','r','r','c') == atom.type) { ++ int year; ++ year = avio_rb16(pb); ++ str = av_asprintf("%d", year); ++ if (!str) ++ return AVERROR(ENOMEM); ++ } else { ++ int ret; ++ const char *tmp; ++ langcode = avio_rb16(pb); ++ ff_mov_lang_to_iso639(langcode, language); ++ tmp = ff_convert_lang_to(language, AV_LANG_ISO639_2_BIBL); ++ if (!tmp) ++ return AVERROR_INVALIDDATA; ++ ++ str_size = atom.size - 6; ++ if (str_size <= 0 || str_size >= INT_MAX/2) ++ return AVERROR_INVALIDDATA; ++ ++ str = av_mallocz(str_size + 1); ++ if (!str) ++ return AVERROR(ENOMEM); ++ ++ ret = ffio_read_size(pb, str, str_size); ++ if (ret < 0) { ++ av_free(str); ++ return ret; ++ } ++ str[str_size] = 0; ++ } ++ ++ if (c->trak_index < 0) { ++ metadata = c->fc->metadata; ++ c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED; ++ } ++ else { ++ metadata = c->fc->streams[c->trak_index]->metadata; ++ } ++ av_dict_set(&metadata, key, str, 0); ++ if (*language && strcmp(language, "und")) { ++ snprintf(key2, sizeof(key2), "%s-%s", key, language); ++ av_dict_set(&metadata, key2, str, 0); ++ } ++ ++ av_freep(&str); ++ return 0; ++} ++ + static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) + { + char tmp_key[5]; +@@ -320,15 +397,33 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) + case MKTAG( 'c','a','t','g'): key = "category"; break; + case MKTAG( 'c','p','i','l'): key = "compilation"; + parse = mov_metadata_int8_no_padding; break; +- case MKTAG( 'c','p','r','t'): key = "copyright"; break; ++ case MKTAG( 'c','p','r','t'): ++ key = "copyright"; ++ if (!c->itunes_metadata) { ++ int64_t pos = avio_tell(pb); ++ int ret = mov_read_3gp_udta_tag(c, pb, atom); ++ if (ret != AVERROR_INVALIDDATA) ++ return ret; ++ avio_seek(pb, pos, SEEK_SET); ++ } ++ break; + case MKTAG( 'd','e','s','c'): key = "description"; break; + case MKTAG( 'd','i','s','k'): key = "disc"; + parse = mov_metadata_track_or_disc_number; break; + case MKTAG( 'e','g','i','d'): key = "episode_uid"; + parse = mov_metadata_int8_no_padding; break; + case MKTAG( 'F','I','R','M'): key = "firmware"; raw = 1; break; +- case MKTAG( 'g','n','r','e'): key = "genre"; +- parse = mov_metadata_gnre; break; ++ case MKTAG( 'g','n','r','e'): ++ key = "genre"; ++ parse = mov_metadata_gnre; ++ if (!c->itunes_metadata) { ++ int64_t pos = avio_tell(pb); ++ int ret = mov_read_3gp_udta_tag(c, pb, atom); ++ if (ret != AVERROR_INVALIDDATA) ++ return ret; ++ avio_seek(pb, pos, SEEK_SET); ++ } ++ break; + case MKTAG( 'h','d','v','d'): key = "hd_video"; + parse = mov_metadata_int8_no_padding; break; + case MKTAG( 'H','M','M','T'): +@@ -399,6 +494,15 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) + case MKTAG(0xa9,'w','r','n'): key = "warning"; break; + case MKTAG(0xa9,'w','r','t'): key = "composer"; break; + case MKTAG(0xa9,'x','y','z'): key = "location"; break; ++ case MKTAG( 'a','l','b','m'): ++ case MKTAG( 'a','u','t','h'): ++ case MKTAG( 'd','s','c','p'): ++ case MKTAG( 'p','e','r','f'): ++ case MKTAG( 't','i','t','l'): ++ case MKTAG( 'y','r','r','c'): ++ if (!c->itunes_metadata) { ++ return mov_read_3gp_udta_tag(c, pb, atom); ++ } + } + retry: + if (c->itunes_metadata && atom.size > 8) { +-- +2.21.0 + |