]> git.sesse.net Git - ffmpeg/blob - libavcodec/assenc.c
Merge commit '50079a6aa93291e6dc9d9fb8d33da83f79e9311d'
[ffmpeg] / libavcodec / assenc.c
1 /*
2  * SSA/ASS 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 <string.h>
23
24 #include "avcodec.h"
25 #include "ass_split.h"
26 #include "ass.h"
27 #include "libavutil/avstring.h"
28 #include "libavutil/internal.h"
29 #include "libavutil/mem.h"
30
31 typedef struct {
32     int id; ///< current event id, ReadOrder field
33 } ASSEncodeContext;
34
35 static av_cold int ass_encode_init(AVCodecContext *avctx)
36 {
37     avctx->extradata = av_malloc(avctx->subtitle_header_size + 1);
38     if (!avctx->extradata)
39         return AVERROR(ENOMEM);
40     memcpy(avctx->extradata, avctx->subtitle_header, avctx->subtitle_header_size);
41     avctx->extradata_size = avctx->subtitle_header_size;
42     avctx->extradata[avctx->extradata_size] = 0;
43     return 0;
44 }
45
46 static int ass_encode_frame(AVCodecContext *avctx,
47                             unsigned char *buf, int bufsize,
48                             const AVSubtitle *sub)
49 {
50     ASSEncodeContext *s = avctx->priv_data;
51     int i, len, total_len = 0;
52
53     for (i=0; i<sub->num_rects; i++) {
54         char ass_line[2048];
55         const char *ass = sub->rects[i]->ass;
56
57         if (sub->rects[i]->type != SUBTITLE_ASS) {
58             av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
59             return -1;
60         }
61
62         if (strncmp(ass, "Dialogue: ", 10)) {
63             av_log(avctx, AV_LOG_ERROR, "AVSubtitle rectangle ass \"%s\""
64                    " does not look like a SSA markup\n", ass);
65             return AVERROR_INVALIDDATA;
66         }
67
68         if (avctx->codec->id == AV_CODEC_ID_ASS) {
69             long int layer;
70             char *p;
71
72             if (i > 0) {
73                 av_log(avctx, AV_LOG_ERROR, "ASS encoder supports only one "
74                        "ASS rectangle field.\n");
75                 return AVERROR_INVALIDDATA;
76             }
77
78             ass += 10; // skip "Dialogue: "
79             /* parse Layer field. If it's a Marked field, the content
80              * will be "Marked=N" instead of the layer num, so we will
81              * have layer=0, which is fine. */
82             layer = strtol(ass, &p, 10);
83
84 #define SKIP_ENTRY(ptr) do {        \
85     char *sep = strchr(ptr, ',');   \
86     if (sep)                        \
87         ptr = sep + 1;              \
88 } while (0)
89
90             SKIP_ENTRY(p); // skip layer or marked
91             SKIP_ENTRY(p); // skip start timestamp
92             SKIP_ENTRY(p); // skip end timestamp
93             snprintf(ass_line, sizeof(ass_line), "%d,%ld,%s", ++s->id, layer, p);
94             ass_line[strcspn(ass_line, "\r\n")] = 0;
95             ass = ass_line;
96         }
97         len = av_strlcpy(buf+total_len, ass, bufsize-total_len);
98
99         if (len > bufsize-total_len-1) {
100             av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
101             return -1;
102         }
103
104         total_len += len;
105     }
106
107     return total_len;
108 }
109
110 #if CONFIG_SSA_ENCODER
111 AVCodec ff_ssa_encoder = {
112     .name         = "ssa",
113     .long_name    = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
114     .type         = AVMEDIA_TYPE_SUBTITLE,
115     .id           = AV_CODEC_ID_SSA,
116     .init         = ass_encode_init,
117     .encode_sub   = ass_encode_frame,
118     .priv_data_size = sizeof(ASSEncodeContext),
119 };
120 #endif
121
122 #if CONFIG_ASS_ENCODER
123 AVCodec ff_ass_encoder = {
124     .name         = "ass",
125     .long_name    = NULL_IF_CONFIG_SMALL("ASS (Advanced SubStation Alpha) subtitle"),
126     .type         = AVMEDIA_TYPE_SUBTITLE,
127     .id           = AV_CODEC_ID_ASS,
128     .init         = ass_encode_init,
129     .encode_sub   = ass_encode_frame,
130     .priv_data_size = sizeof(ASSEncodeContext),
131 };
132 #endif