From b1ea22c23e3f5f6db08a9fa48cbe7697fe806b9c Mon Sep 17 00:00:00 2001
From: John Stebbins <jstebbins@jetheaddev.com>
Date: Wed, 20 Mar 2024 09:08:52 +0100
Subject: [PATCH 02/22] 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 | 77 ++++++++++++++++++++++----------------------
 1 file changed, 39 insertions(+), 38 deletions(-)

diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 585a018e35..9511142708 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -4169,6 +4169,34 @@ 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)
 {
@@ -4243,8 +4271,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 (mov->mode & MODE_MP4) {
         if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
@@ -4841,35 +4871,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);
@@ -4908,14 +4909,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.39.5 (Apple Git-154)

