diff options
| author | Tim Redfern <tim@eclectronics.org> | 2013-12-29 12:19:38 +0000 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2013-12-29 12:19:38 +0000 |
| commit | f7813a5324be39d13ab536c245d15dfc602a7849 (patch) | |
| tree | fad99148b88823d34a5df2f0a25881a002eb291b /ffmpeg/libavcodec/ass.c | |
| parent | b7a5a477b8ff4d4e3028b9dfb9a9df0a41463f92 (diff) | |
basic type mechanism working
Diffstat (limited to 'ffmpeg/libavcodec/ass.c')
| -rw-r--r-- | ffmpeg/libavcodec/ass.c | 144 |
1 files changed, 113 insertions, 31 deletions
diff --git a/ffmpeg/libavcodec/ass.c b/ffmpeg/libavcodec/ass.c index db0fdd8..ccc9570 100644 --- a/ffmpeg/libavcodec/ass.c +++ b/ffmpeg/libavcodec/ass.c @@ -23,6 +23,7 @@ #include "ass.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/bprint.h" #include "libavutil/common.h" int ff_ass_subtitle_header(AVCodecContext *avctx, @@ -53,55 +54,136 @@ int ff_ass_subtitle_header(AVCodecContext *avctx, int ff_ass_subtitle_header_default(AVCodecContext *avctx) { return ff_ass_subtitle_header(avctx, ASS_DEFAULT_FONT, - ASS_DEFAULT_FONT_SIZE, - ASS_DEFAULT_COLOR, - ASS_DEFAULT_BACK_COLOR, - ASS_DEFAULT_BOLD, - ASS_DEFAULT_ITALIC, - ASS_DEFAULT_UNDERLINE, - ASS_DEFAULT_ALIGNMENT); + ASS_DEFAULT_FONT_SIZE, + ASS_DEFAULT_COLOR, + ASS_DEFAULT_BACK_COLOR, + ASS_DEFAULT_BOLD, + ASS_DEFAULT_ITALIC, + ASS_DEFAULT_UNDERLINE, + ASS_DEFAULT_ALIGNMENT); } -static int ts_to_string(char *str, int strlen, int ts) +static void insert_ts(AVBPrint *buf, int ts) { - int h, m, s; - h = ts/360000; ts -= 360000*h; - m = ts/ 6000; ts -= 6000*m; - s = ts/ 100; ts -= 100*s; - return snprintf(str, strlen, "%d:%02d:%02d.%02d", h, m, s, ts); + if (ts == -1) { + av_bprintf(buf, "9:59:59.99,"); + } else { + int h, m, s; + + h = ts/360000; ts -= 360000*h; + m = ts/ 6000; ts -= 6000*m; + s = ts/ 100; ts -= 100*s; + av_bprintf(buf, "%d:%02d:%02d.%02d,", h, m, s, ts); + } } -int ff_ass_add_rect(AVSubtitle *sub, const char *dialog, - int ts_start, int duration, int raw) +int ff_ass_bprint_dialog(AVBPrint *buf, const char *dialog, + int ts_start, int duration, int raw) { - int len = 0, dlen; - char s_start[16], s_end[16], header[48] = {0}; - AVSubtitleRect **rects; + int dlen; + + if (!raw || raw == 2) { + long int layer = 0; + + if (raw == 2) { + /* skip ReadOrder */ + dialog = strchr(dialog, ','); + if (!dialog) + return AVERROR_INVALIDDATA; + dialog++; - if (!raw) { - ts_to_string(s_start, sizeof(s_start), ts_start); - if (duration == -1) - snprintf(s_end, sizeof(s_end), "9:59:59.99"); - else - ts_to_string(s_end, sizeof(s_end), ts_start + duration); - len = snprintf(header, sizeof(header), "Dialogue: 0,%s,%s,Default,", - s_start, s_end); - av_assert0(len < sizeof(header)); + /* extract Layer or Marked */ + layer = strtol(dialog, (char**)&dialog, 10); + if (*dialog != ',') + return AVERROR_INVALIDDATA; + dialog++; + } + av_bprintf(buf, "Dialogue: %ld,", layer); + insert_ts(buf, ts_start); + insert_ts(buf, duration == -1 ? -1 : ts_start + duration); + if (raw != 2) + av_bprintf(buf, "Default,"); } dlen = strcspn(dialog, "\n"); dlen += dialog[dlen] == '\n'; + av_bprintf(buf, "%.*s", dlen, dialog); + if (raw == 2) + av_bprintf(buf, "\r\n"); + + return dlen; +} + +int ff_ass_add_rect(AVSubtitle *sub, const char *dialog, + int ts_start, int duration, int raw) +{ + AVBPrint buf; + int ret, dlen; + AVSubtitleRect **rects; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + if ((ret = ff_ass_bprint_dialog(&buf, dialog, ts_start, duration, raw)) < 0) + goto err; + dlen = ret; + if (!av_bprint_is_complete(&buf)) + goto errnomem; + rects = av_realloc(sub->rects, (sub->num_rects+1) * sizeof(*sub->rects)); if (!rects) - return AVERROR(ENOMEM); + goto errnomem; sub->rects = rects; sub->end_display_time = FFMAX(sub->end_display_time, 10 * duration); rects[sub->num_rects] = av_mallocz(sizeof(*rects[0])); rects[sub->num_rects]->type = SUBTITLE_ASS; - rects[sub->num_rects]->ass = av_malloc(len + dlen + 1); - strcpy (rects[sub->num_rects]->ass , header); - av_strlcpy(rects[sub->num_rects]->ass + len, dialog, dlen + 1); + ret = av_bprint_finalize(&buf, &rects[sub->num_rects]->ass); + if (ret < 0) + goto err; sub->num_rects++; return dlen; + +errnomem: + ret = AVERROR(ENOMEM); +err: + av_bprint_finalize(&buf, NULL); + return ret; +} + +void ff_ass_bprint_text_event(AVBPrint *buf, const char *p, int size, + const char *linebreaks, int keep_ass_markup) +{ + const char *p_end = p + size; + + for (; p < p_end && *p; p++) { + + /* forced custom line breaks, not accounted as "normal" EOL */ + if (linebreaks && strchr(linebreaks, *p)) { + av_bprintf(buf, "\\N"); + + /* standard ASS escaping so random characters don't get mis-interpreted + * as ASS */ + } else if (!keep_ass_markup && strchr("{}\\", *p)) { + av_bprintf(buf, "\\%c", *p); + + /* some packets might end abruptly (no \0 at the end, like for example + * in some cases of demuxing from a classic video container), some + * might be terminated with \n or \r\n which we have to remove (for + * consistency with those who haven't), and we also have to deal with + * evil cases such as \r at the end of the buffer (and no \0 terminated + * character) */ + } else if (p[0] == '\n') { + /* some stuff left so we can insert a line break */ + if (p < p_end - 1) + av_bprintf(buf, "\\N"); + } else if (p[0] == '\r' && p < p_end - 1 && p[1] == '\n') { + /* \r followed by a \n, we can skip it. We don't insert the \N yet + * because we don't know if it is followed by more text */ + continue; + + /* finally, a sane character */ + } else { + av_bprint_chars(buf, *p, 1); + } + } + av_bprintf(buf, "\r\n"); } |
