yading@10
|
1 /*
|
yading@10
|
2 * SSA/ASS encoder
|
yading@10
|
3 * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
|
yading@10
|
4 *
|
yading@10
|
5 * This file is part of FFmpeg.
|
yading@10
|
6 *
|
yading@10
|
7 * FFmpeg is free software; you can redistribute it and/or
|
yading@10
|
8 * modify it under the terms of the GNU Lesser General Public
|
yading@10
|
9 * License as published by the Free Software Foundation; either
|
yading@10
|
10 * version 2.1 of the License, or (at your option) any later version.
|
yading@10
|
11 *
|
yading@10
|
12 * FFmpeg is distributed in the hope that it will be useful,
|
yading@10
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@10
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
yading@10
|
15 * Lesser General Public License for more details.
|
yading@10
|
16 *
|
yading@10
|
17 * You should have received a copy of the GNU Lesser General Public
|
yading@10
|
18 * License along with FFmpeg; if not, write to the Free Software
|
yading@10
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@10
|
20 */
|
yading@10
|
21
|
yading@10
|
22 #include <string.h>
|
yading@10
|
23
|
yading@10
|
24 #include "avcodec.h"
|
yading@10
|
25 #include "ass_split.h"
|
yading@10
|
26 #include "ass.h"
|
yading@10
|
27 #include "libavutil/avstring.h"
|
yading@10
|
28 #include "libavutil/internal.h"
|
yading@10
|
29 #include "libavutil/mem.h"
|
yading@10
|
30
|
yading@10
|
31 typedef struct {
|
yading@10
|
32 int id; ///< current event id, ReadOrder field
|
yading@10
|
33 } ASSEncodeContext;
|
yading@10
|
34
|
yading@10
|
35 static av_cold int ass_encode_init(AVCodecContext *avctx)
|
yading@10
|
36 {
|
yading@10
|
37 avctx->extradata = av_malloc(avctx->subtitle_header_size + 1);
|
yading@10
|
38 if (!avctx->extradata)
|
yading@10
|
39 return AVERROR(ENOMEM);
|
yading@10
|
40 memcpy(avctx->extradata, avctx->subtitle_header, avctx->subtitle_header_size);
|
yading@10
|
41 avctx->extradata_size = avctx->subtitle_header_size;
|
yading@10
|
42 avctx->extradata[avctx->extradata_size] = 0;
|
yading@10
|
43 return 0;
|
yading@10
|
44 }
|
yading@10
|
45
|
yading@10
|
46 static int ass_encode_frame(AVCodecContext *avctx,
|
yading@10
|
47 unsigned char *buf, int bufsize,
|
yading@10
|
48 const AVSubtitle *sub)
|
yading@10
|
49 {
|
yading@10
|
50 ASSEncodeContext *s = avctx->priv_data;
|
yading@10
|
51 int i, len, total_len = 0;
|
yading@10
|
52
|
yading@10
|
53 for (i=0; i<sub->num_rects; i++) {
|
yading@10
|
54 char ass_line[2048];
|
yading@10
|
55 const char *ass = sub->rects[i]->ass;
|
yading@10
|
56
|
yading@10
|
57 if (sub->rects[i]->type != SUBTITLE_ASS) {
|
yading@10
|
58 av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
|
yading@10
|
59 return -1;
|
yading@10
|
60 }
|
yading@10
|
61
|
yading@10
|
62 if (strncmp(ass, "Dialogue: ", 10)) {
|
yading@10
|
63 av_log(avctx, AV_LOG_ERROR, "AVSubtitle rectangle ass \"%s\""
|
yading@10
|
64 " does not look like a SSA markup\n", ass);
|
yading@10
|
65 return AVERROR_INVALIDDATA;
|
yading@10
|
66 }
|
yading@10
|
67
|
yading@10
|
68 if (avctx->codec->id == AV_CODEC_ID_ASS) {
|
yading@10
|
69 long int layer;
|
yading@10
|
70 char *p;
|
yading@10
|
71
|
yading@10
|
72 if (i > 0) {
|
yading@10
|
73 av_log(avctx, AV_LOG_ERROR, "ASS encoder supports only one "
|
yading@10
|
74 "ASS rectangle field.\n");
|
yading@10
|
75 return AVERROR_INVALIDDATA;
|
yading@10
|
76 }
|
yading@10
|
77
|
yading@10
|
78 ass += 10; // skip "Dialogue: "
|
yading@10
|
79 /* parse Layer field. If it's a Marked field, the content
|
yading@10
|
80 * will be "Marked=N" instead of the layer num, so we will
|
yading@10
|
81 * have layer=0, which is fine. */
|
yading@10
|
82 layer = strtol(ass, &p, 10);
|
yading@10
|
83 if (*p) p += strcspn(p, ",") + 1; // skip layer or marked
|
yading@10
|
84 if (*p) p += strcspn(p, ",") + 1; // skip start timestamp
|
yading@10
|
85 if (*p) p += strcspn(p, ",") + 1; // skip end timestamp
|
yading@10
|
86 snprintf(ass_line, sizeof(ass_line), "%d,%ld,%s", ++s->id, layer, p);
|
yading@10
|
87 ass_line[strcspn(ass_line, "\r\n")] = 0;
|
yading@10
|
88 ass = ass_line;
|
yading@10
|
89 }
|
yading@10
|
90 len = av_strlcpy(buf+total_len, ass, bufsize-total_len);
|
yading@10
|
91
|
yading@10
|
92 if (len > bufsize-total_len-1) {
|
yading@10
|
93 av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
|
yading@10
|
94 return -1;
|
yading@10
|
95 }
|
yading@10
|
96
|
yading@10
|
97 total_len += len;
|
yading@10
|
98 }
|
yading@10
|
99
|
yading@10
|
100 return total_len;
|
yading@10
|
101 }
|
yading@10
|
102
|
yading@10
|
103 #if CONFIG_SSA_ENCODER
|
yading@10
|
104 AVCodec ff_ssa_encoder = {
|
yading@10
|
105 .name = "ssa",
|
yading@10
|
106 .long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
|
yading@10
|
107 .type = AVMEDIA_TYPE_SUBTITLE,
|
yading@10
|
108 .id = AV_CODEC_ID_SSA,
|
yading@10
|
109 .init = ass_encode_init,
|
yading@10
|
110 .encode_sub = ass_encode_frame,
|
yading@10
|
111 .priv_data_size = sizeof(ASSEncodeContext),
|
yading@10
|
112 };
|
yading@10
|
113 #endif
|
yading@10
|
114
|
yading@10
|
115 #if CONFIG_ASS_ENCODER
|
yading@10
|
116 AVCodec ff_ass_encoder = {
|
yading@10
|
117 .name = "ass",
|
yading@10
|
118 .long_name = NULL_IF_CONFIG_SMALL("ASS (Advanced SubStation Alpha) subtitle"),
|
yading@10
|
119 .type = AVMEDIA_TYPE_SUBTITLE,
|
yading@10
|
120 .id = AV_CODEC_ID_ASS,
|
yading@10
|
121 .init = ass_encode_init,
|
yading@10
|
122 .encode_sub = ass_encode_frame,
|
yading@10
|
123 .priv_data_size = sizeof(ASSEncodeContext),
|
yading@10
|
124 };
|
yading@10
|
125 #endif
|