textdec.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012 Clément Bœsch
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * Raw subtitles decoder
24  */
25 
26 #include "avcodec.h"
27 #include "ass.h"
28 #include "libavutil/bprint.h"
29 #include "libavutil/opt.h"
30 
31 typedef struct {
32  AVClass *class;
33  const char *linebreaks;
35 } TextContext;
36 
37 #define OFFSET(x) offsetof(TextContext, x)
38 #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
39 static const AVOption options[] = {
40  { "keep_ass_markup", "Set if ASS tags must be escaped", OFFSET(keep_ass_markup), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, .flags=SD },
41  { NULL }
42 };
43 
44 static int text_event_to_ass(const AVCodecContext *avctx, AVBPrint *buf,
45  const char *p, const char *p_end)
46 {
47  const TextContext *text = avctx->priv_data;
48 
49  for (; p < p_end && *p; p++) {
50 
51  /* forced custom line breaks, not accounted as "normal" EOL */
52  if (text->linebreaks && strchr(text->linebreaks, *p)) {
53  av_bprintf(buf, "\\N");
54 
55  /* standard ASS escaping so random characters don't get mis-interpreted
56  * as ASS */
57  } else if (!text->keep_ass_markup && strchr("{}\\", *p)) {
58  av_bprintf(buf, "\\%c", *p);
59 
60  /* some packets might end abruptly (no \0 at the end, like for example
61  * in some cases of demuxing from a classic video container), some
62  * might be terminated with \n or \r\n which we have to remove (for
63  * consistency with those who haven't), and we also have to deal with
64  * evil cases such as \r at the end of the buffer (and no \0 terminated
65  * character) */
66  } else if (p[0] == '\n') {
67  /* some stuff left so we can insert a line break */
68  if (p < p_end - 1)
69  av_bprintf(buf, "\\N");
70  } else if (p[0] == '\r' && p < p_end - 1 && p[1] == '\n') {
71  /* \r followed by a \n, we can skip it. We don't insert the \N yet
72  * because we don't know if it is followed by more text */
73  continue;
74 
75  /* finally, a sane character */
76  } else {
77  av_bprint_chars(buf, *p, 1);
78  }
79  }
80  av_bprintf(buf, "\r\n");
81  return 0;
82 }
83 
84 static int text_decode_frame(AVCodecContext *avctx, void *data,
85  int *got_sub_ptr, AVPacket *avpkt)
86 {
87  AVBPrint buf;
88  AVSubtitle *sub = data;
89  const char *ptr = avpkt->data;
90  const int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100});
91  const int ts_duration = avpkt->duration != -1 ?
92  av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;
93 
95  if (ptr && avpkt->size > 0 && *ptr &&
96  !text_event_to_ass(avctx, &buf, ptr, ptr + avpkt->size)) {
97  if (!av_bprint_is_complete(&buf)) {
98  av_bprint_finalize(&buf, NULL);
99  return AVERROR(ENOMEM);
100  }
101  ff_ass_add_rect(sub, buf.str, ts_start, ts_duration, 0);
102  }
103  *got_sub_ptr = sub->num_rects > 0;
104  av_bprint_finalize(&buf, NULL);
105  return avpkt->size;
106 }
107 
108 #define DECLARE_CLASS(decname) static const AVClass decname ## _decoder_class = { \
109  .class_name = #decname " decoder", \
110  .item_name = av_default_item_name, \
111  .option = decname ## _options, \
112  .version = LIBAVUTIL_VERSION_INT, \
113 }
114 
115 #if CONFIG_TEXT_DECODER
116 #define text_options options
118 
119 AVCodec ff_text_decoder = {
120  .name = "text",
121  .priv_data_size = sizeof(TextContext),
122  .long_name = NULL_IF_CONFIG_SMALL("Raw text subtitle"),
123  .type = AVMEDIA_TYPE_SUBTITLE,
124  .id = AV_CODEC_ID_TEXT,
125  .decode = text_decode_frame,
127  .priv_class = &text_decoder_class,
128 };
129 #endif
130 
131 #if CONFIG_VPLAYER_DECODER || CONFIG_PJS_DECODER || CONFIG_SUBVIEWER1_DECODER
132 
133 static int linebreak_init(AVCodecContext *avctx)
134 {
135  TextContext *text = avctx->priv_data;
136  text->linebreaks = "|";
137  return ff_ass_subtitle_header_default(avctx);
138 }
139 
140 #if CONFIG_VPLAYER_DECODER
141 #define vplayer_options options
142 DECLARE_CLASS(vplayer);
143 
144 AVCodec ff_vplayer_decoder = {
145  .name = "vplayer",
146  .priv_data_size = sizeof(TextContext),
147  .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitle"),
148  .type = AVMEDIA_TYPE_SUBTITLE,
149  .id = AV_CODEC_ID_VPLAYER,
150  .decode = text_decode_frame,
151  .init = linebreak_init,
152  .priv_class = &vplayer_decoder_class,
153 };
154 #endif
155 
156 #if CONFIG_PJS_DECODER
157 #define pjs_options options
158 DECLARE_CLASS(pjs);
159 
160 AVCodec ff_pjs_decoder = {
161  .name = "pjs",
162  .priv_data_size = sizeof(TextContext),
163  .long_name = NULL_IF_CONFIG_SMALL("PJS subtitle"),
164  .type = AVMEDIA_TYPE_SUBTITLE,
165  .id = AV_CODEC_ID_PJS,
166  .decode = text_decode_frame,
167  .init = linebreak_init,
168  .priv_class = &pjs_decoder_class,
169 };
170 #endif
171 
172 #if CONFIG_SUBVIEWER1_DECODER
173 #define subviewer1_options options
174 DECLARE_CLASS(subviewer1);
175 
176 AVCodec ff_subviewer1_decoder = {
177  .name = "subviewer1",
178  .priv_data_size = sizeof(TextContext),
179  .long_name = NULL_IF_CONFIG_SMALL("SubViewer1 subtitle"),
180  .type = AVMEDIA_TYPE_SUBTITLE,
182  .decode = text_decode_frame,
183  .init = linebreak_init,
184  .priv_class = &subviewer1_decoder_class,
185 };
186 #endif
187 
188 #endif /* text subtitles with '|' line break */
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:93
AVOption.
Definition: opt.h:251
text(-8, 1,'a)')
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:193
const char * linebreaks
Definition: textdec.c:33
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
int keep_ass_markup
Definition: textdec.c:34
AVOptions.
int ff_ass_subtitle_header_default(AVCodecContext *avctx)
Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS with default style.
Definition: ass.c:54
uint8_t * data
int duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:130
#define AV_BPRINT_SIZE_UNLIMITED
Convenience macros for special values for av_bprint_init() size_max parameter.
Definition: bprint.h:89
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Init a print buffer.
Definition: bprint.c:68
Spectrum Plot time data
static int av_bprint_is_complete(AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:166
static const AVOption options[]
Definition: textdec.c:39
const char * name
Name of the codec implementation.
external API header
int ff_ass_add_rect(AVSubtitle *sub, const char *dialog, int ts_start, int duration, int raw)
Add an ASS dialog line to an AVSubtitle as a new AVSubtitleRect.
Definition: ass.c:80
Buffer to print data progressively.
Definition: bprint.h:75
NULL
Definition: eval.c:55
main external API structure.
void * buf
Definition: avisynth_c.h:594
#define DECLARE_CLASS(decname)
Definition: textdec.c:108
Describe the class of an AVClass context structure.
Definition: log.h:50
rational number numerator/denominator
Definition: rational.h:43
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
#define OFFSET(x)
Definition: textdec.c:37
#define SD
Definition: textdec.c:38
raw UTF-8 text
first frame pointer p_end
Definition: stft_peak.m:15
static int text_event_to_ass(const AVCodecContext *avctx, AVBPrint *buf, const char *p, const char *p_end)
Definition: textdec.c:44
static int text_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt)
Definition: textdec.c:84
This structure stores compressed data.
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:116