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 * Encode 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 * Encode 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
);
93 avpriv_align_put_bits(pb
);
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
, const AVSubtitle
*h
)
116 uint64_t startTime
= h
->pts
/ 1000; // FIXME: need better solution...
117 uint64_t endTime
= startTime
+ h
->end_display_time
- h
->start_display_time
;
118 int start_tc
[4], end_tc
[4];
119 uint8_t *hdr
= buf
+ 27; // Point behind the timestamp
121 uint16_t width
, height
;
125 if (bufsize
< 27 + 7*2 + 4*3) {
126 av_log(avctx
, AV_LOG_ERROR
, "Buffer too small for XSUB header.\n");
130 // TODO: support multiple rects
131 if (h
->num_rects
!= 1)
132 av_log(avctx
, AV_LOG_WARNING
, "Only single rects supported (%d in subtitle.)\n", h
->num_rects
);
134 // TODO: render text-based subtitles into bitmaps
135 if (!h
->rects
[0]->pict
.data
[0] || !h
->rects
[0]->pict
.data
[1]) {
136 av_log(avctx
, AV_LOG_WARNING
, "No subtitle bitmap available.\n");
140 // TODO: color reduction, similar to dvdsub encoder
141 if (h
->rects
[0]->nb_colors
> 4)
142 av_log(avctx
, AV_LOG_WARNING
, "No more than 4 subtitle colors supported (%d found.)\n", h
->rects
[0]->nb_colors
);
144 // TODO: Palette swapping if color zero is not transparent
145 if (((uint32_t *)h
->rects
[0]->pict
.data
[1])[0] & 0xff000000)
146 av_log(avctx
, AV_LOG_WARNING
, "Color index 0 is not transparent. Transparency will be messed up.\n");
148 if (make_tc(startTime
, start_tc
) || make_tc(endTime
, end_tc
)) {
149 av_log(avctx
, AV_LOG_WARNING
, "Time code >= 100 hours.\n");
154 "[%02d:%02d:%02d.%03d-%02d:%02d:%02d.%03d]",
155 start_tc
[3], start_tc
[2], start_tc
[1], start_tc
[0],
156 end_tc
[3], end_tc
[2], end_tc
[1], end_tc
[0]);
158 // Width and height must probably be multiples of 2.
159 // 2 pixels required on either side of subtitle.
160 // Possibly due to limitations of hardware renderers.
161 // TODO: check if the bitmap is already padded
162 width
= FFALIGN(h
->rects
[0]->w
, 2) + PADDING
* 2;
163 height
= FFALIGN(h
->rects
[0]->h
, 2);
165 bytestream_put_le16(&hdr
, width
);
166 bytestream_put_le16(&hdr
, height
);
167 bytestream_put_le16(&hdr
, h
->rects
[0]->x
);
168 bytestream_put_le16(&hdr
, h
->rects
[0]->y
);
169 bytestream_put_le16(&hdr
, h
->rects
[0]->x
+ width
-1);
170 bytestream_put_le16(&hdr
, h
->rects
[0]->y
+ height
-1);
172 rlelenptr
= hdr
; // Will store length of first field here later.
177 bytestream_put_be24(&hdr
, ((uint32_t *)h
->rects
[0]->pict
.data
[1])[i
]);
180 // RLE buffer. Reserve 2 bytes for possible padding after the last row.
181 init_put_bits(&pb
, hdr
, bufsize
- (hdr
- buf
) - 2);
182 if (xsub_encode_rle(&pb
, h
->rects
[0]->pict
.data
[0],
183 h
->rects
[0]->pict
.linesize
[0]*2,
184 h
->rects
[0]->w
, (h
->rects
[0]->h
+ 1) >> 1))
186 bytestream_put_le16(&rlelenptr
, put_bits_count(&pb
) >> 3); // Length of first field
188 if (xsub_encode_rle(&pb
, h
->rects
[0]->pict
.data
[0] + h
->rects
[0]->pict
.linesize
[0],
189 h
->rects
[0]->pict
.linesize
[0]*2,
190 h
->rects
[0]->w
, h
->rects
[0]->h
>> 1))
193 // Enforce total height to be a multiple of 2
194 if (h
->rects
[0]->h
& 1) {
195 put_xsub_rle(&pb
, h
->rects
[0]->w
, PADDING_COLOR
);
196 avpriv_align_put_bits(&pb
);
201 return hdr
- buf
+ put_bits_count(&pb
)/8;
204 static av_cold
int xsub_encoder_init(AVCodecContext
*avctx
)
206 if (!avctx
->codec_tag
)
207 avctx
->codec_tag
= MKTAG('D','X','S','B');
209 avctx
->bits_per_coded_sample
= 4;
214 AVCodec ff_xsub_encoder
= {
216 .long_name
= NULL_IF_CONFIG_SMALL("DivX subtitles (XSUB)"),
217 .type
= AVMEDIA_TYPE_SUBTITLE
,
218 .id
= AV_CODEC_ID_XSUB
,
219 .init
= xsub_encoder_init
,
220 .encode_sub
= xsub_encode
,