2 * SSA/ASS common functions
3 * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "libavutil/avassert.h"
25 #include "libavutil/avstring.h"
26 #include "libavutil/bprint.h"
27 #include "libavutil/common.h"
29 int ff_ass_subtitle_header(AVCodecContext
*avctx
,
30 const char *font
, int font_size
,
31 int color
, int back_color
,
32 int bold
, int italic
, int underline
,
35 avctx
->subtitle_header
= av_asprintf(
37 "; Script generated by FFmpeg/Lavc%s\r\n"
38 "ScriptType: v4.00+\r\n"
46 "Fontname, Fontsize, "
47 "PrimaryColour, SecondaryColour, OutlineColour, BackColour, "
48 "Bold, Italic, Underline, StrikeOut, "
51 "BorderStyle, Outline, Shadow, "
52 "Alignment, MarginL, MarginR, MarginV, "
57 "%s,%d," /* Font{name,size} */
58 "&H%x,&H%x,&H%x,&H%x," /* {Primary,Secondary,Outline,Back}Colour */
59 "%d,%d,%d,0," /* Bold, Italic, Underline, StrikeOut */
60 "100,100," /* Scale{X,Y} */
61 "0,0," /* Spacing, Angle */
62 "1,1,0," /* BorderStyle, Outline, Shadow */
63 "%d,10,10,10," /* Alignment, Margin[LRV] */
64 "0\r\n" /* Encoding */
68 "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n",
69 !(avctx
->flags
& CODEC_FLAG_BITEXACT
) ? AV_STRINGIFY(LIBAVCODEC_VERSION
) : "",
70 font
, font_size
, color
, color
, back_color
, back_color
,
71 -bold
, -italic
, -underline
, alignment
);
73 if (!avctx
->subtitle_header
)
74 return AVERROR(ENOMEM
);
75 avctx
->subtitle_header_size
= strlen(avctx
->subtitle_header
);
79 int ff_ass_subtitle_header_default(AVCodecContext
*avctx
)
81 return ff_ass_subtitle_header(avctx
, ASS_DEFAULT_FONT
,
82 ASS_DEFAULT_FONT_SIZE
,
84 ASS_DEFAULT_BACK_COLOR
,
87 ASS_DEFAULT_UNDERLINE
,
88 ASS_DEFAULT_ALIGNMENT
);
91 static void insert_ts(AVBPrint
*buf
, int ts
)
94 av_bprintf(buf
, "9:59:59.99,");
98 h
= ts
/360000; ts
-= 360000*h
;
99 m
= ts
/ 6000; ts
-= 6000*m
;
100 s
= ts
/ 100; ts
-= 100*s
;
101 av_bprintf(buf
, "%d:%02d:%02d.%02d,", h
, m
, s
, ts
);
105 int ff_ass_bprint_dialog(AVBPrint
*buf
, const char *dialog
,
106 int ts_start
, int duration
, int raw
)
110 if (!raw
|| raw
== 2) {
115 dialog
= strchr(dialog
, ',');
117 return AVERROR_INVALIDDATA
;
120 /* extract Layer or Marked */
121 layer
= strtol(dialog
, (char**)&dialog
, 10);
123 return AVERROR_INVALIDDATA
;
126 av_bprintf(buf
, "Dialogue: %ld,", layer
);
127 insert_ts(buf
, ts_start
);
128 insert_ts(buf
, duration
== -1 ? -1 : ts_start
+ duration
);
130 av_bprintf(buf
, "Default,,0,0,0,,");
133 dlen
= strcspn(dialog
, "\n");
134 dlen
+= dialog
[dlen
] == '\n';
136 av_bprintf(buf
, "%.*s", dlen
, dialog
);
138 av_bprintf(buf
, "\r\n");
143 int ff_ass_add_rect(AVSubtitle
*sub
, const char *dialog
,
144 int ts_start
, int duration
, int raw
)
148 AVSubtitleRect
**rects
;
150 av_bprint_init(&buf
, 0, AV_BPRINT_SIZE_UNLIMITED
);
151 if ((ret
= ff_ass_bprint_dialog(&buf
, dialog
, ts_start
, duration
, raw
)) < 0)
154 if (!av_bprint_is_complete(&buf
))
157 rects
= av_realloc(sub
->rects
, (sub
->num_rects
+1) * sizeof(*sub
->rects
));
161 sub
->end_display_time
= FFMAX(sub
->end_display_time
, 10 * duration
);
162 rects
[sub
->num_rects
] = av_mallocz(sizeof(*rects
[0]));
163 rects
[sub
->num_rects
]->type
= SUBTITLE_ASS
;
164 ret
= av_bprint_finalize(&buf
, &rects
[sub
->num_rects
]->ass
);
171 ret
= AVERROR(ENOMEM
);
173 av_bprint_finalize(&buf
, NULL
);
177 int ff_ass_add_rect_bprint(AVSubtitle
*sub
, AVBPrint
*buf
,
178 int ts_start
, int duration
)
180 av_bprintf(buf
, "\r\n");
181 if (!av_bprint_is_complete(buf
))
182 return AVERROR(ENOMEM
);
183 return ff_ass_add_rect(sub
, buf
->str
, ts_start
, duration
, 0);
186 void ff_ass_bprint_text_event(AVBPrint
*buf
, const char *p
, int size
,
187 const char *linebreaks
, int keep_ass_markup
)
189 const char *p_end
= p
+ size
;
191 for (; p
< p_end
&& *p
; p
++) {
193 /* forced custom line breaks, not accounted as "normal" EOL */
194 if (linebreaks
&& strchr(linebreaks
, *p
)) {
195 av_bprintf(buf
, "\\N");
197 /* standard ASS escaping so random characters don't get mis-interpreted
199 } else if (!keep_ass_markup
&& strchr("{}\\", *p
)) {
200 av_bprintf(buf
, "\\%c", *p
);
202 /* some packets might end abruptly (no \0 at the end, like for example
203 * in some cases of demuxing from a classic video container), some
204 * might be terminated with \n or \r\n which we have to remove (for
205 * consistency with those who haven't), and we also have to deal with
206 * evil cases such as \r at the end of the buffer (and no \0 terminated
208 } else if (p
[0] == '\n') {
209 /* some stuff left so we can insert a line break */
211 av_bprintf(buf
, "\\N");
212 } else if (p
[0] == '\r' && p
< p_end
- 1 && p
[1] == '\n') {
213 /* \r followed by a \n, we can skip it. We don't insert the \N yet
214 * because we don't know if it is followed by more text */
217 /* finally, a sane character */
219 av_bprint_chars(buf
, *p
, 1);