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

Marton Balint cus at passwd.hu
Wed Feb 20 00:09:31 EET 2019



On Tue, 12 Feb 2019, Marton Balint wrote:

> Signed-off-by: Marton Balint <cus at passwd.hu>
> ---
> libavformat/mpegtsenc.c | 88 +++++++++++++++++++++++++++++--------------------
> 1 file changed, 53 insertions(+), 35 deletions(-)

Ping, will push soon.

Regards,
Marton

>
> diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
> index 4470b7120c..523ac65d55 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[256];
> +    uint8_t provider_name[256];
>     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,10 +693,47 @@ static void mpegts_write_sdt(AVFormatContext *s)
>                           data, q - data);
> }
> 
> -static MpegTSService *mpegts_add_service(MpegTSWrite *ts, int sid,
> +/* This stores a string in buf 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 int encode_str8(uint8_t *buf, const char *str)
> +{
> +    size_t str_len;
> +    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! */
> +            if (str_len > 254)
> +                return AVERROR(EINVAL);
> +            buf[0] = str_len + 1;
> +            buf[1] = 0x15;
> +            memcpy(&buf[2], str, str_len);
> +            return 0;
> +        }
> +    }
> +invalid:
> +    /* Otherwise let's just encode the string as is! */
> +    if (str_len > 255)
> +        return AVERROR(EINVAL);
> +    buf[0] = str_len;
> +    memcpy(&buf[1], str, str_len);
> +    return 0;
> +}
> +
> +static MpegTSService *mpegts_add_service(AVFormatContext *s, int sid,
>                                          const char *provider_name,
>                                          const char *name)
> {
> +    MpegTSWrite *ts = s->priv_data;
>     MpegTSService *service;
>
>     service = av_mallocz(sizeof(MpegTSService));
> @@ -721,17 +742,16 @@ 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);
> -    if (!service->provider_name || !service->name)
> +    if (encode_str8(service->provider_name, provider_name) < 0 ||
> +        encode_str8(service->name, name) < 0) {
> +        av_log(s, AV_LOG_ERROR, "Too long service or provider name\n");
>         goto fail;
> +    }
>     if (av_dynarray_add_nofree(&ts->services, &ts->nb_services, service) < 0)
>         goto fail;
>
>     return service;
> fail:
> -    av_freep(&service->provider_name);
> -    av_freep(&service->name);
>     av_free(service);
>     return NULL;
> }
> @@ -790,7 +810,7 @@ static int mpegts_init(AVFormatContext *s)
>         service_name  = title ? title->value : DEFAULT_SERVICE_NAME;
>         provider      = av_dict_get(s->metadata, "service_provider", NULL, 0);
>         provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME;
> -        service       = mpegts_add_service(ts, ts->service_id,
> +        service       = mpegts_add_service(s, ts->service_id,
>                                            provider_name, service_name);
>
>         if (!service)
> @@ -809,7 +829,7 @@ static int mpegts_init(AVFormatContext *s)
>             service_name  = title ? title->value : DEFAULT_SERVICE_NAME;
>             provider      = av_dict_get(program->metadata, "service_provider", NULL, 0);
>             provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME;
> -            service       = mpegts_add_service(ts, program->id,
> +            service       = mpegts_add_service(s, program->id,
>                                                provider_name, service_name);
>
>             if (!service)
> @@ -1839,8 +1859,6 @@ static void mpegts_deinit(AVFormatContext *s)
>
>     for (i = 0; i < ts->nb_services; i++) {
>         service = ts->services[i];
> -        av_freep(&service->provider_name);
> -        av_freep(&service->name);
>         av_freep(&service);
>     }
>     av_freep(&ts->services);
> -- 
> 2.16.4
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


More information about the ffmpeg-devel mailing list