FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavcodec
srtenc.c
Go to the documentation of this file.
1
/*
2
* SubRip subtitle encoder
3
* Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
4
*
5
* This file is part of FFmpeg.
6
*
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.
11
*
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.
16
*
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
20
*/
21
22
#include <stdarg.h>
23
#include "
avcodec.h
"
24
#include "
libavutil/avstring.h
"
25
#include "
libavutil/bprint.h
"
26
#include "
ass_split.h
"
27
#include "
ass.h
"
28
29
30
#define SRT_STACK_SIZE 64
31
32
typedef
struct
{
33
AVCodecContext
*
avctx
;
34
ASSSplitContext
*
ass_ctx
;
35
AVBPrint
buffer
;
36
char
stack[
SRT_STACK_SIZE
];
37
int
stack_ptr
;
38
int
alignment_applied
;
39
}
SRTContext
;
40
41
42
#ifdef __GNUC__
43
__attribute__ ((__format__ (__printf__, 2, 3)))
44
#endif
45
static
void
srt_print
(
SRTContext
*
s
,
const
char
*str, ...)
46
{
47
va_list vargs;
48
va_start(vargs, str);
49
av_vbprintf
(&s->
buffer
, str, vargs);
50
va_end(vargs);
51
}
52
53
static
int
srt_stack_push
(
SRTContext
*
s
,
const
char
c
)
54
{
55
if
(s->
stack_ptr
>=
SRT_STACK_SIZE
)
56
return
-1;
57
s->
stack
[s->
stack_ptr
++] =
c
;
58
return
0;
59
}
60
61
static
char
srt_stack_pop
(
SRTContext
*
s
)
62
{
63
if
(s->
stack_ptr
<= 0)
64
return
0;
65
return
s->
stack
[--s->
stack_ptr
];
66
}
67
68
static
int
srt_stack_find
(
SRTContext
*
s
,
const
char
c
)
69
{
70
int
i;
71
for
(i = s->
stack_ptr
-1; i >= 0; i--)
72
if
(s->
stack
[i] == c)
73
break
;
74
return
i;
75
}
76
77
static
void
srt_close_tag
(
SRTContext
*
s
,
char
tag
)
78
{
79
srt_print
(s,
"</%c%s>"
, tag, tag ==
'f'
?
"ont"
:
""
);
80
}
81
82
static
void
srt_stack_push_pop
(
SRTContext
*
s
,
const
char
c
,
int
close)
83
{
84
if
(close) {
85
int
i = c ?
srt_stack_find
(s, c) : 0;
86
if
(i < 0)
87
return
;
88
while
(s->
stack_ptr
!= i)
89
srt_close_tag
(s,
srt_stack_pop
(s));
90
}
else
if
(
srt_stack_push
(s, c) < 0)
91
av_log
(s->
avctx
,
AV_LOG_ERROR
,
"tag stack overflow\n"
);
92
}
93
94
static
void
srt_style_apply
(
SRTContext
*
s
,
const
char
*style)
95
{
96
ASSStyle
*st =
ff_ass_style_get
(s->
ass_ctx
, style);
97
if
(st) {
98
int
c
= st->
primary_color
& 0xFFFFFF;
99
if
(st->
font_name
&& strcmp(st->
font_name
,
ASS_DEFAULT_FONT
) ||
100
st->
font_size
!=
ASS_DEFAULT_FONT_SIZE
||
101
c !=
ASS_DEFAULT_COLOR
) {
102
srt_print
(s,
"<font"
);
103
if
(st->
font_name
&& strcmp(st->
font_name
,
ASS_DEFAULT_FONT
))
104
srt_print
(s,
" face=\"%s\""
, st->
font_name
);
105
if
(st->
font_size
!=
ASS_DEFAULT_FONT_SIZE
)
106
srt_print
(s,
" size=\"%d\""
, st->
font_size
);
107
if
(c !=
ASS_DEFAULT_COLOR
)
108
srt_print
(s,
" color=\"#%06x\""
,
109
(c & 0xFF0000) >> 16 | c & 0xFF00 | (c & 0xFF) << 16);
110
srt_print
(s,
">"
);
111
srt_stack_push
(s,
'f'
);
112
}
113
if
(st->
bold
!=
ASS_DEFAULT_BOLD
) {
114
srt_print
(s,
"<b>"
);
115
srt_stack_push
(s,
'b'
);
116
}
117
if
(st->
italic
!=
ASS_DEFAULT_ITALIC
) {
118
srt_print
(s,
"<i>"
);
119
srt_stack_push
(s,
'i'
);
120
}
121
if
(st->
underline
!=
ASS_DEFAULT_UNDERLINE
) {
122
srt_print
(s,
"<u>"
);
123
srt_stack_push
(s,
'u'
);
124
}
125
if
(st->
alignment
!=
ASS_DEFAULT_ALIGNMENT
) {
126
srt_print
(s,
"{\\an%d}"
, st->
alignment
);
127
s->
alignment_applied
= 1;
128
}
129
}
130
}
131
132
133
static
av_cold
int
srt_encode_init
(
AVCodecContext
*avctx)
134
{
135
SRTContext
*
s
= avctx->
priv_data
;
136
s->
avctx
= avctx;
137
s->
ass_ctx
=
ff_ass_split
(avctx->
subtitle_header
);
138
av_bprint_init
(&s->
buffer
, 0,
AV_BPRINT_SIZE_UNLIMITED
);
139
return
s->
ass_ctx
? 0 :
AVERROR_INVALIDDATA
;
140
}
141
142
static
void
srt_text_cb
(
void
*priv,
const
char
*text,
int
len
)
143
{
144
SRTContext
*
s
= priv;
145
av_bprint_append_data
(&s->
buffer
, text, len);
146
}
147
148
static
void
srt_new_line_cb
(
void
*priv,
int
forced)
149
{
150
srt_print
(priv,
"\r\n"
);
151
}
152
153
static
void
srt_style_cb
(
void
*priv,
char
style,
int
close)
154
{
155
srt_stack_push_pop
(priv, style, close);
156
if
(!close)
157
srt_print
(priv,
"<%c>"
, style);
158
}
159
160
static
void
srt_color_cb
(
void
*priv,
unsigned
int
color
,
unsigned
int
color_id)
161
{
162
if
(color_id > 1)
163
return
;
164
srt_stack_push_pop
(priv,
'f'
, color == 0xFFFFFFFF);
165
if
(color != 0xFFFFFFFF)
166
srt_print
(priv,
"<font color=\"#%06x\">"
,
167
(color & 0xFF0000) >> 16 | color & 0xFF00 | (color & 0xFF) << 16);
168
}
169
170
static
void
srt_font_name_cb
(
void
*priv,
const
char
*
name
)
171
{
172
srt_stack_push_pop
(priv,
'f'
, !name);
173
if
(name)
174
srt_print
(priv,
"<font face=\"%s\">"
, name);
175
}
176
177
static
void
srt_font_size_cb
(
void
*priv,
int
size
)
178
{
179
srt_stack_push_pop
(priv,
'f'
, size < 0);
180
if
(size >= 0)
181
srt_print
(priv,
"<font size=\"%d\">"
, size);
182
}
183
184
static
void
srt_alignment_cb
(
void
*priv,
int
alignment)
185
{
186
SRTContext
*
s
= priv;
187
if
(!s->
alignment_applied
&& alignment >= 0) {
188
srt_print
(s,
"{\\an%d}"
, alignment);
189
s->
alignment_applied
= 1;
190
}
191
}
192
193
static
void
srt_cancel_overrides_cb
(
void
*priv,
const
char
*style)
194
{
195
srt_stack_push_pop
(priv, 0, 1);
196
srt_style_apply
(priv, style);
197
}
198
199
static
void
srt_move_cb
(
void
*priv,
int
x1,
int
y1,
int
x2,
int
y2,
200
int
t1
,
int
t2
)
201
{
202
// TODO: add a AV_PKT_DATA_SUBTITLE_POSITION side data when a new subtitles
203
// encoding API passing the AVPacket is available.
204
}
205
206
static
void
srt_end_cb
(
void
*priv)
207
{
208
srt_stack_push_pop
(priv, 0, 1);
209
}
210
211
static
const
ASSCodesCallbacks
srt_callbacks
= {
212
.
text
=
srt_text_cb
,
213
.new_line =
srt_new_line_cb
,
214
.style =
srt_style_cb
,
215
.color =
srt_color_cb
,
216
.font_name =
srt_font_name_cb
,
217
.font_size =
srt_font_size_cb
,
218
.alignment =
srt_alignment_cb
,
219
.cancel_overrides =
srt_cancel_overrides_cb
,
220
.move =
srt_move_cb
,
221
.end =
srt_end_cb
,
222
};
223
224
static
int
srt_encode_frame
(
AVCodecContext
*avctx,
225
unsigned
char
*
buf
,
int
bufsize,
const
AVSubtitle
*sub)
226
{
227
SRTContext
*
s
= avctx->
priv_data
;
228
ASSDialog
*dialog;
229
int
i, num;
230
231
av_bprint_clear
(&s->
buffer
);
232
233
for
(i=0; i<sub->
num_rects
; i++) {
234
235
if
(sub->
rects
[i]->
type
!=
SUBTITLE_ASS
) {
236
av_log
(avctx,
AV_LOG_ERROR
,
"Only SUBTITLE_ASS type supported.\n"
);
237
return
AVERROR
(ENOSYS);
238
}
239
240
dialog =
ff_ass_split_dialog
(s->
ass_ctx
, sub->
rects
[i]->
ass
, 0, &num);
241
for
(; dialog && num--; dialog++) {
242
s->
alignment_applied
= 0;
243
srt_style_apply
(s, dialog->
style
);
244
ff_ass_split_override_codes
(&srt_callbacks, s, dialog->
text
);
245
}
246
}
247
248
if
(!
av_bprint_is_complete
(&s->
buffer
))
249
return
AVERROR
(ENOMEM);
250
if
(!s->
buffer
.len)
251
return
0;
252
253
if
(s->
buffer
.len > bufsize) {
254
av_log
(avctx,
AV_LOG_ERROR
,
"Buffer too small for ASS event.\n"
);
255
return
-1;
256
}
257
memcpy(buf, s->
buffer
.str, s->
buffer
.len);
258
259
return
s->
buffer
.len;
260
}
261
262
static
int
srt_encode_close
(
AVCodecContext
*avctx)
263
{
264
SRTContext
*
s
= avctx->
priv_data
;
265
ff_ass_split_free
(s->
ass_ctx
);
266
av_bprint_finalize
(&s->
buffer
,
NULL
);
267
return
0;
268
}
269
270
#if CONFIG_SRT_ENCODER
271
/* deprecated encoder */
272
AVCodec
ff_srt_encoder = {
273
.
name
=
"srt"
,
274
.long_name =
NULL_IF_CONFIG_SMALL
(
"SubRip subtitle"
),
275
.type =
AVMEDIA_TYPE_SUBTITLE
,
276
.id =
AV_CODEC_ID_SUBRIP
,
277
.priv_data_size =
sizeof
(
SRTContext
),
278
.
init
=
srt_encode_init
,
279
.encode_sub =
srt_encode_frame
,
280
.close =
srt_encode_close
,
281
};
282
#endif
283
284
#if CONFIG_SUBRIP_ENCODER
285
AVCodec
ff_subrip_encoder = {
286
.
name
=
"subrip"
,
287
.long_name =
NULL_IF_CONFIG_SMALL
(
"SubRip subtitle"
),
288
.type =
AVMEDIA_TYPE_SUBTITLE
,
289
.id =
AV_CODEC_ID_SUBRIP
,
290
.priv_data_size =
sizeof
(
SRTContext
),
291
.
init
=
srt_encode_init
,
292
.encode_sub =
srt_encode_frame
,
293
.close =
srt_encode_close
,
294
};
295
#endif
Generated on Sun Mar 8 2015 02:35:00 for FFmpeg by
1.8.2