[FFmpeg-devel,3/3] avformat/mpegtsenc: add support for service and provider names with utf8 encoding

Submitted by Marton Balint on Feb. 11, 2019, 10:42 p.m.

Details

Message ID 20190211224206.30345-3-cus@passwd.hu
State New
Headers show

Commit Message

Marton Balint Feb. 11, 2019, 10:42 p.m.
Signed-off-by: Marton Balint <cus@passwd.hu>
---
 libavformat/mpegtsenc.c | 76 +++++++++++++++++++++++++++++++------------------
 1 file changed, 49 insertions(+), 27 deletions(-)

Patch hide | download patch | download mbox

diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index 4470b7120c..a600394619 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -54,8 +54,8 @@  typedef struct MpegTSSection {
 typedef struct MpegTSService {
     MpegTSSection pmt; /* MPEG-2 PMT table context */
     int sid;           /* service ID */
-    char *name;
-    char *provider_name;
+    uint8_t *name;
+    uint8_t *provider_name;
     int pcr_pid;
     int pcr_packet_count;
     int pcr_packet_period;
@@ -264,26 +264,10 @@  static void mpegts_write_pat(AVFormatContext *s)
                           data, q - data);
 }
 
-/* NOTE: !str is accepted for an empty string */
-static void putstr8(uint8_t **q_ptr, const char *str, int write_len)
+static void putbuf(uint8_t **q_ptr, const uint8_t *buf, int len)
 {
-    uint8_t *q;
-    int len;
-
-    q = *q_ptr;
-    if (!str)
-        len = 0;
-    else
-        len = strlen(str);
-    if (write_len)
-        *q++ = len;
-    if (!str) {
-        *q_ptr = q;
-        return;
-    }
-    memcpy(q, str, len);
-    q     += len;
-    *q_ptr = q;
+    memcpy(*q_ptr, buf, len);
+    *q_ptr += len;
 }
 
 static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
@@ -646,9 +630,9 @@  static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
                 *q++ = 0x26; /* metadata descriptor */
                 *q++ = 13;
                 put16(&q, 0xffff);    /* metadata application format */
-                putstr8(&q, tag, 0);
+                putbuf(&q, tag, strlen(tag));
                 *q++ = 0xff;        /* metadata format */
-                putstr8(&q, tag, 0);
+                putbuf(&q, tag, strlen(tag));
                 *q++ = 0;            /* metadata service ID */
                 *q++ = 0xF;          /* metadata_locator_record_flag|MPEG_carriage_flags|reserved */
             }
@@ -695,8 +679,8 @@  static void mpegts_write_sdt(AVFormatContext *s)
         desc_len_ptr = q;
         q++;
         *q++         = ts->service_type;
-        putstr8(&q, service->provider_name, 1);
-        putstr8(&q, service->name, 1);
+        putbuf(&q, service->provider_name, service->provider_name[0] + 1);
+        putbuf(&q, service->name, service->name[0] + 1);
         desc_len_ptr[0] = q - desc_len_ptr - 1;
 
         /* fill descriptor length */
@@ -709,6 +693,44 @@  static void mpegts_write_sdt(AVFormatContext *s)
                           data, q - data);
 }
 
+/* This allocates a buffer with a string with the correct encoding and also
+ * sets the first byte as the length. !str is accepted for an empty string.
+ *
+ * If the string is already encoded, invalid UTF-8 or has no multibyte sequence
+ * then we keep it as is, otherwise we signal UTF-8 encoding. */
+static uint8_t *encode_str8(const char *str)
+{
+    size_t str_len;
+    uint8_t *buf = av_malloc(256);
+    if (!buf)
+        return NULL;
+    if (!str)
+        str = "";
+    str_len = strlen(str);
+    if (str[0] && (unsigned)str[0] >= 0x20) {   /* Make sure the string is not already encoded. */
+        const uint8_t *q = str;
+        int has_multibyte = 0;
+        while (*q) {
+            uint32_t code;
+            GET_UTF8(code, *q++, goto invalid;) /* Is it valid UTF-8? */
+            has_multibyte |= (code > 127);      /* Does it have multibyte UTF-8 chars in it? */
+        }
+        if (has_multibyte) {                    /* If we have multibyte chars and valid UTF-8, then encode as such! */
+            str_len = FFMIN(str_len, 254);
+            buf[0] = str_len + 1;
+            buf[1] = 0x15;
+            memcpy(&buf[2], str, str_len);
+            return buf;
+        }
+    }
+invalid:
+    /* Otherwise let's just encode the string as is! */
+    str_len = FFMIN(255, str_len);
+    buf[0] = str_len;
+    memcpy(&buf[1], str, str_len);
+    return buf;
+}
+
 static MpegTSService *mpegts_add_service(MpegTSWrite *ts, int sid,
                                          const char *provider_name,
                                          const char *name)
@@ -721,8 +743,8 @@  static MpegTSService *mpegts_add_service(MpegTSWrite *ts, int sid,
     service->pmt.pid       = ts->pmt_start_pid + ts->nb_services;
     service->sid           = sid;
     service->pcr_pid       = 0x1fff;
-    service->provider_name = av_strdup(provider_name);
-    service->name          = av_strdup(name);
+    service->provider_name = encode_str8(provider_name);
+    service->name          = encode_str8(name);
     if (!service->provider_name || !service->name)
         goto fail;
     if (av_dynarray_add_nofree(&ts->services, &ts->nb_services, service) < 0)