2 * DivX (XSUB) subtitle encoder
3 * Copyright (c) 2005 DivX, Inc.
4 * Copyright (c) 2009 Bjorn Axelsson
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "bytestream.h"
28 * Number of pixels to pad left and right.
30 * The official encoder pads the subtitles with two pixels on either side,
31 * but until we find out why, we won't do it (we will pad to have width
32 * divisible by 2 though).
35 #define PADDING_COLOR 0
38 * Encodes a single color run. At most 16 bits will be used.
39 * \param len length of the run, values > 255 mean "until end of line", may not be < 0.
40 * \param color color to encode, only the lowest two bits are used and all others must be 0.
42 static void put_xsub_rle(PutBitContext
*pb
, int len
, int color
)
45 put_bits(pb
, 2 + ((ff_log2_tab
[len
] >> 1) << 2), len
);
48 put_bits(pb
, 2, color
);
52 * Encodes a 4-color bitmap with XSUB rle.
54 * The encoded bitmap may be wider than the source bitmap due to padding.
56 static int xsub_encode_rle(PutBitContext
*pb
, const uint8_t *bitmap
,
57 int linesize
, int w
, int h
)
59 int x0
, x1
, y
, len
, color
= PADDING_COLOR
;
61 for (y
= 0; y
< h
; y
++) {
64 // Make sure we have enough room for at least one run and padding
65 if (pb
->size_in_bits
- put_bits_count(pb
) < 7*8)
69 color
= bitmap
[x1
++] & 3;
70 while (x1
< w
&& (bitmap
[x1
] & 3) == color
)
73 if (PADDING
&& x0
== 0) {
74 if (color
== PADDING_COLOR
) {
78 put_xsub_rle(pb
, PADDING
, PADDING_COLOR
);
81 // Run can't be longer than 255, unless it is the rest of a row
82 if (x1
== w
&& color
== PADDING_COLOR
) {
83 len
+= PADDING
+ (w
&1);
85 len
= FFMIN(len
, 255);
86 put_xsub_rle(pb
, len
, color
);
90 if (color
!= PADDING_COLOR
&& (PADDING
+ (w
&1)))
91 put_xsub_rle(pb
, PADDING
+ (w
&1), PADDING_COLOR
);
101 static int make_tc(uint64_t ms
, int *tc
)
103 static const int tc_divs
[3] = { 1000, 60, 60 };
105 for (i
=0; i
<3; i
++) {
106 tc
[i
] = ms
% tc_divs
[i
];
113 static int xsub_encode(AVCodecContext
*avctx
, unsigned char *buf
,
114 int bufsize
, void *data
)
116 AVSubtitle
*h
= data
;
117 uint64_t startTime
= h
->pts
/ 1000; // FIXME: need better solution...
118 uint64_t endTime
= startTime
+ h
->end_display_time
- h
->start_display_time
;
119 int start_tc
[4], end_tc
[4];
120 uint8_t *hdr
= buf
+ 27; // Point behind the timestamp
122 uint16_t width
, height
;
126 if (bufsize
< 27 + 7*2 + 4*3) {
127 av_log(avctx
, AV_LOG_ERROR
, "Buffer too small for XSUB header.\n");
131 // TODO: support multiple rects
132 if (h
->num_rects
> 1)
133 av_log(avctx
, AV_LOG_WARNING
, "Only single rects supported (%d in subtitle.)\n", h
->num_rects
);
135 // TODO: render text-based subtitles into bitmaps
136 if (!h
->rects
[0]->pict
.data
[0] || !h
->rects
[0]->pict
.data
[1]) {
137 av_log(avctx
, AV_LOG_WARNING
, "No subtitle bitmap available.\n");
141 // TODO: color reduction, similar to dvdsub encoder
142 if (h
->rects
[0]->nb_colors
> 4)
143 av_log(avctx
, AV_LOG_WARNING
, "No more than 4 subtitle colors supported (%d found.)\n", h
->rects
[0]->nb_colors
);
145 // TODO: Palette swapping if color zero is not transparent
146 if (((uint32_t *)h
->rects
[0]->pict
.data
[1])[0] & 0xff)
147 av_log(avctx
, AV_LOG_WARNING
, "Color index 0 is not transparent. Transparency will be messed up.\n");
149 if (make_tc(startTime
, start_tc
) || make_tc(endTime
, end_tc
)) {
150 av_log(avctx
, AV_LOG_WARNING
, "Time code >= 100 hours.\n");
155 "[%02d:%02d:%02d.%03d-%02d:%02d:%02d.%03d]",
156 start_tc
[3], start_tc
[2], start_tc
[1], start_tc
[0],
157 end_tc
[3], end_tc
[2], end_tc
[1], end_tc
[0]);
159 // Width and height must probably be multiples of 2.
160 // 2 pixels required on either side of subtitle.
161 // Possibly due to limitations of hardware renderers.
162 // TODO: check if the bitmap is already padded
163 width
= FFALIGN(h
->rects
[0]->w
, 2) + PADDING
* 2;
164 height
= FFALIGN(h
->rects
[0]->h
, 2);
166 bytestream_put_le16(&hdr
, width
);
167 bytestream_put_le16(&hdr
, height
);
168 bytestream_put_le16(&hdr
, h
->rects
[0]->x
);
169 bytestream_put_le16(&hdr
, h
->rects
[0]->y
);
170 bytestream_put_le16(&hdr
, h
->rects
[0]->x
+ width
);
171 bytestream_put_le16(&hdr
, h
->rects
[0]->y
+ height
);
173 rlelenptr
= hdr
; // Will store length of first field here later.
178 bytestream_put_be24(&hdr
, ((uint32_t *)h
->rects
[0]->pict
.data
[1])[i
]);
181 // RLE buffer. Reserve 2 bytes for possible padding after the last row.
182 init_put_bits(&pb
, hdr
, bufsize
- (hdr
- buf
) - 2);
183 if (xsub_encode_rle(&pb
, h
->rects
[0]->pict
.data
[0],
184 h
->rects
[0]->pict
.linesize
[0]*2,
185 h
->rects
[0]->w
, (h
->rects
[0]->h
+ 1) >> 1))
187 bytestream_put_le16(&rlelenptr
, put_bits_count(&pb
) >> 3); // Length of first field
189 if (xsub_encode_rle(&pb
, h
->rects
[0]->pict
.data
[0] + h
->rects
[0]->pict
.linesize
[0],
190 h
->rects
[0]->pict
.linesize
[0]*2,
191 h
->rects
[0]->w
, h
->rects
[0]->h
>> 1))
194 // Enforce total height to be be multiple of 2
195 if (h
->rects
[0]->h
& 1) {
196 put_xsub_rle(&pb
, h
->rects
[0]->w
, PADDING_COLOR
);
202 return hdr
- buf
+ put_bits_count(&pb
)/8;
205 static av_cold
int xsub_encoder_init(AVCodecContext
*avctx
)
207 if (!avctx
->codec_tag
)
208 avctx
->codec_tag
= MKTAG('D','X','S','B');
213 AVCodec xsub_encoder
= {
221 .long_name
= NULL_IF_CONFIG_SMALL("DivX subtitles (XSUB)"),