diff --git a/libavcodec/ass.c b/libavcodec/ass.c new file mode 100644 index 0000000000..12aa8c7d15 --- /dev/null +++ b/libavcodec/ass.c @@ -0,0 +1,68 @@ +/* + * SSA/ASS common funtions + * Copyright (c) 2010 Aurelien Jacobs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "ass.h" + +void ff_ass_init(AVSubtitle *sub) +{ + memset(sub, 0, sizeof(*sub)); +} + +static int ts_to_string(char *str, int strlen, 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); +} + +int ff_ass_add_rect(AVSubtitle *sub, const char *dialog, + int ts_start, int ts_end, int raw) +{ + int len = 0, dlen, duration = ts_end - ts_start; + char s_start[16], s_end[16], header[48] = {0}; + AVSubtitleRect **rects; + + if (!raw) { + ts_to_string(s_start, sizeof(s_start), ts_start); + ts_to_string(s_end, sizeof(s_end), ts_end ); + len = snprintf(header, sizeof(header), "Dialogue: 0,%s,%s,", + s_start, s_end); + } + + dlen = strcspn(dialog, "\n"); + dlen += dialog[dlen] == '\n'; + + rects = av_realloc(sub->rects, (sub->num_rects+1) * sizeof(*sub->rects)); + if (!rects) + return AVERROR(ENOMEM); + 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); + strncpy(rects[sub->num_rects]->ass + len, dialog, dlen); + sub->num_rects++; + return dlen; +} diff --git a/libavcodec/ass.h b/libavcodec/ass.h new file mode 100644 index 0000000000..1c847f169b --- /dev/null +++ b/libavcodec/ass.h @@ -0,0 +1,53 @@ +/* + * SSA/ASS common funtions + * Copyright (c) 2010 Aurelien Jacobs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_ASS_H +#define AVCODEC_ASS_H + +#include "avcodec.h" + +/** + * Initialize an AVSubtitle structure for use with ff_ass_add_rect(). + * + * @param sub pointer to the AVSubtitle + */ +void ff_ass_init(AVSubtitle *sub); + +/** + * Add an ASS dialog line to an AVSubtitle as a new AVSubtitleRect. + * + * @param sub pointer to the AVSubtitle + * @param dialog ASS dialog to add to sub + * @param ts_start start timestamp for this dialog (in 1/100 second unit) + * @param ts_end end timestamp for this dialog (in 1/100 second unit) + * @param raw when set to 1, it indicates that dialog contains a whole ASS + * dialog line which should be copied as is. + * when set to 0, it indicates that dialog contains only the Text + * part of the ASS dialog line, the rest of the line + * will be generated. + * @return number of characters read from dialog. It can be less than the whole + * length of dialog, if dialog contains several lines of text. + * A negative value indicates an error. + */ +int ff_ass_add_rect(AVSubtitle *sub, const char *dialog, + int ts_start, int ts_end, int raw); + +#endif /* AVCODEC_ASS_H */ diff --git a/libavcodec/assdec.c b/libavcodec/assdec.c new file mode 100644 index 0000000000..0a7fd4821d --- /dev/null +++ b/libavcodec/assdec.c @@ -0,0 +1,62 @@ +/* + * SSA/ASS decoder + * Copyright (c) 2010 Aurelien Jacobs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "ass.h" + +static av_cold int ass_decode_init(AVCodecContext *avctx) +{ + avctx->subtitle_header = av_malloc(avctx->extradata_size); + if (!avctx->extradata) + return AVERROR(ENOMEM); + memcpy(avctx->subtitle_header, avctx->extradata, avctx->extradata_size); + avctx->subtitle_header_size = avctx->extradata_size; + return 0; +} + +static int ass_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, + AVPacket *avpkt) +{ + const char *ptr = avpkt->data; + int len, size = avpkt->size; + + ff_ass_init(data); + + while (size > 0) { + len = ff_ass_add_rect(data, ptr, 0, 0/* FIXME: duration */, 1); + if (len < 0) + return len; + ptr += len; + size -= len; + } + + *got_sub_ptr = avpkt->size > 0; + return avpkt->size; +} + +AVCodec ass_decoder = { + .name = "ass", + .long_name = NULL_IF_CONFIG_SMALL("Advanced SubStation Alpha subtitle"), + .type = AVMEDIA_TYPE_SUBTITLE, + .id = CODEC_ID_SSA, + .init = ass_decode_init, + .decode = ass_decode_frame, +}; diff --git a/libavcodec/assenc.c b/libavcodec/assenc.c new file mode 100644 index 0000000000..c6f017ce5d --- /dev/null +++ b/libavcodec/assenc.c @@ -0,0 +1,67 @@ +/* + * SSA/ASS encoder + * Copyright (c) 2010 Aurelien Jacobs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "libavutil/avstring.h" + +static av_cold int ass_encode_init(AVCodecContext *avctx) +{ + avctx->extradata = av_malloc(avctx->subtitle_header_size); + if (!avctx->extradata) + return AVERROR(ENOMEM); + memcpy(avctx->extradata, avctx->subtitle_header, avctx->subtitle_header_size); + avctx->extradata_size = avctx->subtitle_header_size; + return 0; +} + +static int ass_encode_frame(AVCodecContext *avctx, + unsigned char *buf, int bufsize, void *data) +{ + AVSubtitle *sub = data; + int i, len, total_len = 0; + + for (i=0; inum_rects; i++) { + if (sub->rects[i]->type != SUBTITLE_ASS) { + av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n"); + return -1; + } + + len = av_strlcpy(buf+total_len, sub->rects[i]->ass, bufsize-total_len); + + if (len > bufsize-total_len-1) { + av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n"); + return -1; + } + + total_len += len; + } + + return total_len; +} + +AVCodec ass_encoder = { + .name = "ass", + .long_name = NULL_IF_CONFIG_SMALL("Advanced SubStation Alpha subtitle"), + .type = AVMEDIA_TYPE_SUBTITLE, + .id = CODEC_ID_SSA, + .init = ass_encode_init, + .encode = ass_encode_frame, +};