[FFmpeg-devel] [PATCH 2/2] movtextenc.c: Support for Bold, Italic and Underlined styles

Philip Langdale philipl at overt.org
Sat Jun 20 19:55:24 CEST 2015


On Thu, 18 Jun 2015 22:20:05 +0530
Niklesh Lalwani <niklesh.lalwani at iitb.ac.in> wrote:

> Updated patch.
> 
> Thanks,
> Niklesh

> From faae5cbec4772b81f124c09326010ddafc7aa780 Mon Sep 17 00:00:00 2001
> From: Niklesh <niklesh.lalwani at iitb.ac.in>
> Date: Thu, 18 Jun 2015 22:04:54 +0530
> Subject: [PATCH 2/2] movtextenc.c: Support for Bold, Italic and
> Underlined styles
> 
> Signed-off-by: Niklesh <niklesh.lalwani at iitb.ac.in>
> ---
>  libavcodec/movtextenc.c | 165
> ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 145
> insertions(+), 20 deletions(-)
> 
> diff --git a/libavcodec/movtextenc.c b/libavcodec/movtextenc.c
> index 1b8f454..1d38dda 100644
> --- a/libavcodec/movtextenc.c
> +++ b/libavcodec/movtextenc.c
> @@ -24,14 +24,38 @@
>  #include "libavutil/avassert.h"
>  #include "libavutil/avstring.h"
>  #include "libavutil/intreadwrite.h"
> +#include "libavutil/mem.h"
> +#include "libavutil/common.h"
>  #include "ass_split.h"
>  #include "ass.h"
>  
> +#define STYLE_FLAG_BOLD         (1<<0)
> +#define STYLE_FLAG_ITALIC       (1<<1)
> +#define STYLE_FLAG_UNDERLINE    (1<<2)
> +#define STYLE_RECORD_SIZE       12
> +#define SIZE_ADD                10
> +
> +
> +typedef struct {
> +    uint16_t style_start;
> +    uint16_t style_end;
> +    uint8_t style_flag;
> +} StyleBox;
> +
>  typedef struct {
>      ASSSplitContext *ass_ctx;
> -    char buffer[2048];
> -    char *ptr;
> -    char *end;
> +    AVBPrint buffer;
> +    StyleBox **style_attributes;
> +    StyleBox *style_attributes_temp;
> +    int count;
> +    uint8_t style_box_flag;
> +    uint32_t tsmb_size;
> +    uint32_t tsmb_type;
> +    uint16_t style_entries;
> +    uint16_t style_fontID;
> +    uint8_t style_fontsize;
> +    uint32_t style_color;
> +    uint16_t text_pos;
>  } MovTextContext;
>  
>  
> @@ -79,32 +103,98 @@ static av_cold int
> mov_text_encode_init(AVCodecContext *avctx) if (!avctx->extradata)
>          return AVERROR(ENOMEM);
>  
> +    av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED);
> +
>      memcpy(avctx->extradata, text_sample_entry,
> avctx->extradata_size); 
>      s->ass_ctx = ff_ass_split(avctx->subtitle_header);
>      return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
>  }
>  
> +static void mov_text_style_cb(void *priv, const char style, int
> close) +{
> +    MovTextContext *s = priv;
> +    if (!close) {
> +        if (s->style_box_flag == 0) {   //first style entry
> +
> +            s->style_attributes_temp =
> av_malloc(sizeof(*s->style_attributes_temp));
> +            if (!s->style_attributes_temp)
> +                return AVERROR(ENOMEM);
> +
> +            s->style_attributes_temp->style_flag = 0;
> +            s->style_attributes_temp->style_start =
> AV_RB16(&s->text_pos);
> +        } else {
> +            if (s->style_attributes_temp->style_flag) { //break the
> style record here and start a new one
> +                s->style_attributes_temp->style_end =
> AV_RB16(&s->text_pos);
> +                av_dynarray_add(&s->style_attributes, &s->count,
> s->style_attributes_temp); +
> +                s->style_attributes_temp =
> av_malloc(sizeof(*s->style_attributes_temp));
> +                if (!s->style_attributes_temp)
> +                    return AVERROR(ENOMEM);
> +
> +                s->style_attributes_temp->style_flag =
> s->style_attributes[s->count - 1]->style_flag;
> +                s->style_attributes_temp->style_start =
> AV_RB16(&s->text_pos);
> +            } else {
> +                s->style_attributes_temp->style_flag = 0;
> +                s->style_attributes_temp->style_start =
> AV_RB16(&s->text_pos);
> +            }
> +        }
> +        switch (style){
> +        case 'b':
> +            s->style_attributes_temp->style_flag |= STYLE_FLAG_BOLD;
> +            break;
> +        case 'i':
> +            s->style_attributes_temp->style_flag |=
> STYLE_FLAG_ITALIC;
> +            break;
> +        case 'u':
> +            s->style_attributes_temp->style_flag |=
> STYLE_FLAG_UNDERLINE;
> +            break;
> +        }
> +    } else {
> +        s->style_attributes_temp->style_end = AV_RB16(&s->text_pos);
> +        av_dynarray_add(&s->style_attributes, &s->count,
> s->style_attributes_temp); +
> +        s->style_attributes_temp =
> av_malloc(sizeof(*s->style_attributes_temp));
> +        if (!s->style_attributes_temp)
> +            return AVERROR(ENOMEM);
> +
> +        s->style_attributes_temp->style_flag =
> s->style_attributes[s->count - 1]->style_flag;
> +        switch (style){
> +        case 'b':
> +            s->style_attributes_temp->style_flag &= ~STYLE_FLAG_BOLD;
> +            break;
> +        case 'i':
> +            s->style_attributes_temp->style_flag &=
> ~STYLE_FLAG_ITALIC;
> +            break;
> +        case 'u':
> +            s->style_attributes_temp->style_flag &=
> ~STYLE_FLAG_UNDERLINE;
> +            break;
> +        }
> +        if (s->style_attributes_temp->style_flag) { //start of new
> style record
> +            s->style_attributes_temp->style_start =
> AV_RB16(&s->text_pos);
> +        }
> +    }
> +    s->style_box_flag = 1;
> +}
> +
>  static void mov_text_text_cb(void *priv, const char *text, int len)
>  {
>      MovTextContext *s = priv;
> -    av_assert0(s->end >= s->ptr);
> -    av_strlcpy(s->ptr, text, FFMIN(s->end - s->ptr, len + 1));
> -    s->ptr += FFMIN(s->end - s->ptr, len);
> +    av_bprint_append_data(&s->buffer, text, len);
> +    s->text_pos += len;
>  }
>  
>  static void mov_text_new_line_cb(void *priv, int forced)
>  {
>      MovTextContext *s = priv;
> -    av_assert0(s->end >= s->ptr);
> -    av_strlcpy(s->ptr, "\n", FFMIN(s->end - s->ptr, 2));
> -    if (s->end > s->ptr)
> -        s->ptr++;
> +    av_bprint_append_data(&s->buffer, "\n", 2);
> +    s->text_pos += 2;
>  }
>  
>  static const ASSCodesCallbacks mov_text_callbacks = {
>      .text     = mov_text_text_cb,
>      .new_line = mov_text_new_line_cb,
> +    .style    = mov_text_style_cb,
>  };
>  
>  static int mov_text_encode_frame(AVCodecContext *avctx, unsigned
> char *buf, @@ -112,10 +202,12 @@ static int
> mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf, {
>      MovTextContext *s = avctx->priv_data;
>      ASSDialog *dialog;
> -    int i, len, num;
> +    int i, j, num, length;
>  
> -    s->ptr = s->buffer;
> -    s->end = s->ptr + sizeof(s->buffer);
> +    s->text_pos = 0;
> +    s->count = 0;
> +    s->style_box_flag = 0;
> +    s->style_entries = 0;
>  
>      for (i = 0; i < sub->num_rects; i++) {
>  
> @@ -128,28 +220,61 @@ static int mov_text_encode_frame(AVCodecContext
> *avctx, unsigned char *buf, for (; dialog && num--; dialog++) {
>              ff_ass_split_override_codes(&mov_text_callbacks, s,
> dialog->text); }
> +        if (s->style_box_flag) {
> +            s->tsmb_size = s->count * STYLE_RECORD_SIZE +
> SIZE_ADD;  //size of one style record is 12 bytes
> +            s->tsmb_size = AV_RB32(&s->tsmb_size);
> +            s->tsmb_type = MKTAG('s','t','y','l');
> +            s->style_entries = AV_RB16(&s->count);
> +            s->style_fontID = 0x00 | 0x01<<8;
> +            s->style_fontsize = 0x12;
> +            s->style_color = MKTAG(0xFF, 0xFF, 0xFF, 0xFF);
> +            /*The above three attributes are hard coded for now
> +            but will come from ASS style in the future*/
> +            av_bprint_append_data(&s->buffer, &s->tsmb_size, 4);
> +            av_bprint_append_data(&s->buffer, &s->tsmb_type, 4);
> +            av_bprint_append_data(&s->buffer, &s->style_entries, 2);
> +            for (j = 0; j < s->count; j++) {
> +                av_bprint_append_data(&s->buffer,
> &s->style_attributes[j]->style_start, 2);
> +                av_bprint_append_data(&s->buffer,
> &s->style_attributes[j]->style_end, 2);
> +                av_bprint_append_data(&s->buffer, &s->style_fontID,
> 2);
> +                av_bprint_append_data(&s->buffer,
> &s->style_attributes[j]->style_flag, 1);
> +                av_bprint_append_data(&s->buffer,
> &s->style_fontsize, 1);
> +                av_bprint_append_data(&s->buffer, &s->style_color,
> 4);
> +            }
> +            for (j = 0; j < s->count; j++) {
> +                av_freep(&s->style_attributes[j]);
> +            }
> +            av_freep(&s->style_attributes);
> +            av_freep(&s->style_attributes_temp);
> +        }
>      }
>  
> -    if (s->ptr == s->buffer)
> -        return 0;
> -
> -    AV_WB16(buf, strlen(s->buffer));
> +    AV_WB16(buf, s->text_pos);
>      buf += 2;
>  
> -    len = av_strlcpy(buf, s->buffer, bufsize - 2);
> +    if (!av_bprint_is_complete(&s->buffer))
> +        return AVERROR(ENOMEM);
> +    if (!s->buffer.len)
> +        return 0;
>  
> -    if (len > bufsize-3) {
> +    if (s->buffer.len > bufsize - 3) {
>          av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS
> event.\n"); return AVERROR(EINVAL);
>      }

You need to call av_brpint_clear in eahc of these failure cases.
The normal pattern would be to set 'length' to the error code
and then 'goto exit;' which would ensure you always clear it.

Otherwise, on the next frame, it will still have all the old
data in it.

> -    return len + 2;
> +    memcpy(buf, s->buffer.str, s->buffer.len);
> +    length = s->buffer.len + 2;
> +
> +    av_bprint_clear(&s->buffer);
> +
> +    return length;
>  }
>  
>  static int mov_text_encode_close(AVCodecContext *avctx)
>  {
>      MovTextContext *s = avctx->priv_data;
>      ff_ass_split_free(s->ass_ctx);
> +    av_bprint_finalize(&s->buffer, NULL);
>      return 0;
>  }
>  
> -- 
> 1.9.1
> 



--phil


More information about the ffmpeg-devel mailing list