Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * DVD subtitle encoding | ||
3 | * Copyright (c) 2005 Wolfram Gloger | ||
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 | #include "avcodec.h" | ||
22 | #include "bytestream.h" | ||
23 | #include "codec_internal.h" | ||
24 | #include "dvdsub.h" | ||
25 | #include "libavutil/avassert.h" | ||
26 | #include "libavutil/bprint.h" | ||
27 | #include "libavutil/imgutils.h" | ||
28 | #include "libavutil/mem.h" | ||
29 | #include "libavutil/opt.h" | ||
30 | |||
31 | typedef struct { | ||
32 | AVClass *class; | ||
33 | uint32_t global_palette[16]; | ||
34 | char *palette_str; | ||
35 | int even_rows_fix; | ||
36 | } DVDSubtitleContext; | ||
37 | |||
38 | // ncnt is the nibble counter | ||
39 | #define PUTNIBBLE(val)\ | ||
40 | do {\ | ||
41 | if (ncnt++ & 1)\ | ||
42 | *q++ = bitbuf | ((val) & 0x0f);\ | ||
43 | else\ | ||
44 | bitbuf = (val) << 4;\ | ||
45 | } while(0) | ||
46 | |||
47 | 86 | static void dvd_encode_rle(uint8_t **pq, | |
48 | const uint8_t *bitmap, int linesize, | ||
49 | int w, int h, | ||
50 | const int cmap[256]) | ||
51 | { | ||
52 | uint8_t *q; | ||
53 | 86 | unsigned int bitbuf = 0; | |
54 | int ncnt; | ||
55 | int x, y, len, color; | ||
56 | |||
57 | 86 | q = *pq; | |
58 | |||
59 |
2/2✓ Branch 0 taken 1563 times.
✓ Branch 1 taken 86 times.
|
1649 | for (y = 0; y < h; ++y) { |
60 | 1563 | ncnt = 0; | |
61 |
2/2✓ Branch 0 taken 118206 times.
✓ Branch 1 taken 1563 times.
|
119769 | for(x = 0; x < w; x += len) { |
62 | 118206 | color = bitmap[x]; | |
63 |
2/2✓ Branch 0 taken 471493 times.
✓ Branch 1 taken 1563 times.
|
473056 | for (len=1; x+len < w; ++len) |
64 |
2/2✓ Branch 0 taken 116643 times.
✓ Branch 1 taken 354850 times.
|
471493 | if (bitmap[x+len] != color) |
65 | 116643 | break; | |
66 | 118206 | color = cmap[color]; | |
67 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 118206 times.
|
118206 | av_assert0(color < 4); |
68 |
2/2✓ Branch 0 taken 94474 times.
✓ Branch 1 taken 23732 times.
|
118206 | if (len < 0x04) { |
69 |
2/2✓ Branch 0 taken 46942 times.
✓ Branch 1 taken 47532 times.
|
94474 | PUTNIBBLE((len << 2)|color); |
70 |
2/2✓ Branch 0 taken 21030 times.
✓ Branch 1 taken 2702 times.
|
23732 | } else if (len < 0x10) { |
71 |
2/2✓ Branch 0 taken 10167 times.
✓ Branch 1 taken 10863 times.
|
21030 | PUTNIBBLE(len >> 2); |
72 |
2/2✓ Branch 0 taken 10863 times.
✓ Branch 1 taken 10167 times.
|
21030 | PUTNIBBLE((len << 2)|color); |
73 |
2/2✓ Branch 0 taken 1843 times.
✓ Branch 1 taken 859 times.
|
2702 | } else if (len < 0x40) { |
74 |
2/2✓ Branch 0 taken 847 times.
✓ Branch 1 taken 996 times.
|
1843 | PUTNIBBLE(0); |
75 |
2/2✓ Branch 0 taken 996 times.
✓ Branch 1 taken 847 times.
|
1843 | PUTNIBBLE(len >> 2); |
76 |
2/2✓ Branch 0 taken 847 times.
✓ Branch 1 taken 996 times.
|
1843 | PUTNIBBLE((len << 2)|color); |
77 |
2/2✓ Branch 0 taken 321 times.
✓ Branch 1 taken 538 times.
|
859 | } else if (x+len == w) { |
78 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 205 times.
|
321 | PUTNIBBLE(0); |
79 |
2/2✓ Branch 0 taken 205 times.
✓ Branch 1 taken 116 times.
|
321 | PUTNIBBLE(0); |
80 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 205 times.
|
321 | PUTNIBBLE(0); |
81 |
2/2✓ Branch 0 taken 205 times.
✓ Branch 1 taken 116 times.
|
321 | PUTNIBBLE(color); |
82 | } else { | ||
83 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 512 times.
|
538 | if (len > 0xff) |
84 | 26 | len = 0xff; | |
85 |
2/2✓ Branch 0 taken 147 times.
✓ Branch 1 taken 391 times.
|
538 | PUTNIBBLE(0); |
86 |
2/2✓ Branch 0 taken 391 times.
✓ Branch 1 taken 147 times.
|
538 | PUTNIBBLE(len >> 6); |
87 |
2/2✓ Branch 0 taken 147 times.
✓ Branch 1 taken 391 times.
|
538 | PUTNIBBLE(len >> 2); |
88 |
2/2✓ Branch 0 taken 391 times.
✓ Branch 1 taken 147 times.
|
538 | PUTNIBBLE((len << 2)|color); |
89 | } | ||
90 | } | ||
91 | /* end of line */ | ||
92 |
2/2✓ Branch 0 taken 739 times.
✓ Branch 1 taken 824 times.
|
1563 | if (ncnt & 1) |
93 |
1/2✓ Branch 0 taken 739 times.
✗ Branch 1 not taken.
|
739 | PUTNIBBLE(0); |
94 | 1563 | bitmap += linesize; | |
95 | } | ||
96 | |||
97 | 86 | *pq = q; | |
98 | 86 | } | |
99 | |||
100 | 45795 | static int color_distance(uint32_t a, uint32_t b) | |
101 | { | ||
102 | 45795 | int r = 0, d, i; | |
103 | 45795 | int alpha_a = 8, alpha_b = 8; | |
104 | |||
105 |
2/2✓ Branch 0 taken 183180 times.
✓ Branch 1 taken 45795 times.
|
228975 | for (i = 24; i >= 0; i -= 8) { |
106 | 183180 | d = alpha_a * (int)((a >> i) & 0xFF) - | |
107 | 183180 | alpha_b * (int)((b >> i) & 0xFF); | |
108 | 183180 | r += d * d; | |
109 | 183180 | alpha_a = a >> 28; | |
110 | 183180 | alpha_b = b >> 28; | |
111 | } | ||
112 | 45795 | return r; | |
113 | } | ||
114 | |||
115 | /** | ||
116 | * Count colors used in a rectangle, quantizing alpha and grouping by | ||
117 | * nearest global palette entry. | ||
118 | */ | ||
119 | 43 | static void count_colors(AVCodecContext *avctx, unsigned hits[33], | |
120 | const AVSubtitleRect *r) | ||
121 | { | ||
122 | 43 | DVDSubtitleContext *dvdc = avctx->priv_data; | |
123 | 43 | unsigned count[256] = { 0 }; | |
124 | 43 | uint32_t *palette = (uint32_t *)r->data[1]; | |
125 | uint32_t color; | ||
126 | 43 | int x, y, i, j, match, d, best_d, av_uninit(best_j); | |
127 | 43 | uint8_t *p = r->data[0]; | |
128 | |||
129 |
2/2✓ Branch 0 taken 1563 times.
✓ Branch 1 taken 43 times.
|
1606 | for (y = 0; y < r->h; y++) { |
130 |
2/2✓ Branch 0 taken 472147 times.
✓ Branch 1 taken 1563 times.
|
473710 | for (x = 0; x < r->w; x++) |
131 | 472147 | count[*(p++)]++; | |
132 | 1563 | p += r->linesize[0] - r->w; | |
133 | } | ||
134 |
2/2✓ Branch 0 taken 11008 times.
✓ Branch 1 taken 43 times.
|
11051 | for (i = 0; i < 256; i++) { |
135 |
2/2✓ Branch 0 taken 10836 times.
✓ Branch 1 taken 172 times.
|
11008 | if (!count[i]) /* avoid useless search */ |
136 | 10836 | continue; | |
137 | 172 | color = palette[i]; | |
138 | /* 0: transparent, 1-16: semi-transparent, 17-33 opaque */ | ||
139 |
3/4✓ Branch 0 taken 86 times.
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
|
172 | match = color < 0x33000000 ? 0 : color < 0xCC000000 ? 1 : 17; |
140 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 86 times.
|
172 | if (match) { |
141 | 86 | best_d = INT_MAX; | |
142 |
2/2✓ Branch 0 taken 1376 times.
✓ Branch 1 taken 86 times.
|
1462 | for (j = 0; j < 16; j++) { |
143 | 1376 | d = color_distance(0xFF000000 | color, | |
144 | 1376 | 0xFF000000 | dvdc->global_palette[j]); | |
145 |
2/2✓ Branch 0 taken 172 times.
✓ Branch 1 taken 1204 times.
|
1376 | if (d < best_d) { |
146 | 172 | best_d = d; | |
147 | 172 | best_j = j; | |
148 | } | ||
149 | } | ||
150 | 86 | match += best_j; | |
151 | } | ||
152 | 172 | hits[match] += count[i]; | |
153 | } | ||
154 | 43 | } | |
155 | |||
156 | 43 | static void select_palette(AVCodecContext *avctx, int out_palette[4], | |
157 | int out_alpha[4], unsigned hits[33]) | ||
158 | { | ||
159 | 43 | DVDSubtitleContext *dvdc = avctx->priv_data; | |
160 | int i, j, bright, mult; | ||
161 | uint32_t color; | ||
162 | 43 | int selected[4] = { 0 }; | |
163 | 43 | uint32_t pseudopal[33] = { 0 }; | |
164 | 43 | uint32_t refcolor[3] = { 0x00000000, 0xFFFFFFFF, 0xFF000000 }; | |
165 | |||
166 | /* Bonus for transparent: if the rectangle fits tightly the text, the | ||
167 | background color can be quite rare, but it would be ugly without it */ | ||
168 | 43 | hits[0] *= 16; | |
169 | /* Bonus for bright colors */ | ||
170 |
2/2✓ Branch 0 taken 688 times.
✓ Branch 1 taken 43 times.
|
731 | for (i = 0; i < 16; i++) { |
171 |
2/2✓ Branch 0 taken 602 times.
✓ Branch 1 taken 86 times.
|
688 | if (!(hits[1 + i] + hits[17 + i])) |
172 | 602 | continue; /* skip unused colors to gain time */ | |
173 | 86 | color = dvdc->global_palette[i]; | |
174 | 86 | bright = 0; | |
175 |
2/2✓ Branch 0 taken 258 times.
✓ Branch 1 taken 86 times.
|
344 | for (j = 0; j < 3; j++, color >>= 8) |
176 |
3/4✓ Branch 0 taken 86 times.
✓ Branch 1 taken 172 times.
✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
|
258 | bright += (color & 0xFF) < 0x40 || (color & 0xFF) >= 0xC0; |
177 | 86 | mult = 2 + FFMIN(bright, 2); | |
178 | 86 | hits[ 1 + i] *= mult; | |
179 | 86 | hits[17 + i] *= mult; | |
180 | } | ||
181 | |||
182 | /* Select four most frequent colors */ | ||
183 |
2/2✓ Branch 0 taken 172 times.
✓ Branch 1 taken 43 times.
|
215 | for (i = 0; i < 4; i++) { |
184 |
2/2✓ Branch 0 taken 5676 times.
✓ Branch 1 taken 172 times.
|
5848 | for (j = 0; j < 33; j++) |
185 |
2/2✓ Branch 0 taken 129 times.
✓ Branch 1 taken 5547 times.
|
5676 | if (hits[j] > hits[selected[i]]) |
186 | 129 | selected[i] = j; | |
187 | 172 | hits[selected[i]] = 0; | |
188 | } | ||
189 | |||
190 | /* Order the colors like in most DVDs: | ||
191 | 0: background, 1: foreground, 2: outline */ | ||
192 |
2/2✓ Branch 0 taken 688 times.
✓ Branch 1 taken 43 times.
|
731 | for (i = 0; i < 16; i++) { |
193 | 688 | pseudopal[ 1 + i] = 0x80000000 | dvdc->global_palette[i]; | |
194 | 688 | pseudopal[17 + i] = 0xFF000000 | dvdc->global_palette[i]; | |
195 | } | ||
196 |
2/2✓ Branch 0 taken 129 times.
✓ Branch 1 taken 43 times.
|
172 | for (i = 0; i < 3; i++) { |
197 | 129 | int best_d = color_distance(refcolor[i], pseudopal[selected[i]]); | |
198 |
2/2✓ Branch 0 taken 258 times.
✓ Branch 1 taken 129 times.
|
387 | for (j = i + 1; j < 4; j++) { |
199 | 258 | int d = color_distance(refcolor[i], pseudopal[selected[j]]); | |
200 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 258 times.
|
258 | if (d < best_d) { |
201 | ✗ | FFSWAP(int, selected[i], selected[j]); | |
202 | ✗ | best_d = d; | |
203 | } | ||
204 | } | ||
205 | } | ||
206 | |||
207 | /* Output */ | ||
208 |
2/2✓ Branch 0 taken 172 times.
✓ Branch 1 taken 43 times.
|
215 | for (i = 0; i < 4; i++) { |
209 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 86 times.
|
172 | out_palette[i] = selected[i] ? (selected[i] - 1) & 0xF : 0; |
210 |
3/4✓ Branch 0 taken 86 times.
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
|
172 | out_alpha [i] = !selected[i] ? 0 : selected[i] < 17 ? 0x80 : 0xFF; |
211 | } | ||
212 | 43 | } | |
213 | |||
214 | 43 | static void build_color_map(AVCodecContext *avctx, int cmap[], | |
215 | const uint32_t palette[], | ||
216 | const int out_palette[], unsigned int const out_alpha[]) | ||
217 | { | ||
218 | 43 | DVDSubtitleContext *dvdc = avctx->priv_data; | |
219 | int i, j, d, best_d; | ||
220 | uint32_t pseudopal[4]; | ||
221 | |||
222 |
2/2✓ Branch 0 taken 172 times.
✓ Branch 1 taken 43 times.
|
215 | for (i = 0; i < 4; i++) |
223 | 172 | pseudopal[i] = (out_alpha[i] << 24) | | |
224 | 172 | dvdc->global_palette[out_palette[i]]; | |
225 |
2/2✓ Branch 0 taken 11008 times.
✓ Branch 1 taken 43 times.
|
11051 | for (i = 0; i < 256; i++) { |
226 | 11008 | best_d = INT_MAX; | |
227 |
2/2✓ Branch 0 taken 44032 times.
✓ Branch 1 taken 11008 times.
|
55040 | for (j = 0; j < 4; j++) { |
228 | 44032 | d = color_distance(pseudopal[j], palette[i]); | |
229 |
2/2✓ Branch 0 taken 11094 times.
✓ Branch 1 taken 32938 times.
|
44032 | if (d < best_d) { |
230 | 11094 | cmap[i] = j; | |
231 | 11094 | best_d = d; | |
232 | } | ||
233 | } | ||
234 | } | ||
235 | 43 | } | |
236 | |||
237 | ✗ | static void copy_rectangle(AVSubtitleRect *dst, AVSubtitleRect *src, int cmap[]) | |
238 | { | ||
239 | int x, y; | ||
240 | uint8_t *p, *q; | ||
241 | |||
242 | ✗ | p = src->data[0]; | |
243 | ✗ | q = dst->data[0] + (src->x - dst->x) + | |
244 | ✗ | (src->y - dst->y) * dst->linesize[0]; | |
245 | ✗ | for (y = 0; y < src->h; y++) { | |
246 | ✗ | for (x = 0; x < src->w; x++) | |
247 | ✗ | *(q++) = cmap[*(p++)]; | |
248 | ✗ | p += src->linesize[0] - src->w; | |
249 | ✗ | q += dst->linesize[0] - src->w; | |
250 | } | ||
251 | ✗ | } | |
252 | |||
253 | 43 | static int encode_dvd_subtitles(AVCodecContext *avctx, | |
254 | uint8_t *outbuf, int outbuf_size, | ||
255 | const AVSubtitle *h) | ||
256 | { | ||
257 | 43 | DVDSubtitleContext *dvdc = avctx->priv_data; | |
258 | uint8_t *q, *qq; | ||
259 | int offset1, offset2; | ||
260 | 43 | int i, rects = h->num_rects, ret; | |
261 | 43 | unsigned global_palette_hits[33] = { 0 }; | |
262 | int cmap[256]; | ||
263 | int out_palette[4]; | ||
264 | int out_alpha[4]; | ||
265 | AVSubtitleRect vrect; | ||
266 | 43 | uint8_t *vrect_data = NULL; | |
267 | int x2, y2; | ||
268 | 43 | int forced = 0; | |
269 | |||
270 |
2/4✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 43 times.
|
43 | if (rects == 0 || !h->rects) |
271 | ✗ | return AVERROR(EINVAL); | |
272 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 43 times.
|
86 | for (i = 0; i < rects; i++) |
273 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if (h->rects[i]->type != SUBTITLE_BITMAP) { |
274 | ✗ | av_log(avctx, AV_LOG_ERROR, "Bitmap subtitle required\n"); | |
275 | ✗ | return AVERROR(EINVAL); | |
276 | } | ||
277 | /* Mark this subtitle forced if any of the rectangles is forced. */ | ||
278 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 43 times.
|
86 | for (i = 0; i < rects; i++) |
279 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if ((h->rects[i]->flags & AV_SUBTITLE_FLAG_FORCED) != 0) { |
280 | ✗ | forced = 1; | |
281 | ✗ | break; | |
282 | } | ||
283 | |||
284 | 43 | vrect = *h->rects[0]; | |
285 | |||
286 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if (rects > 1) { |
287 | /* DVD subtitles can have only one rectangle: build a virtual | ||
288 | rectangle containing all actual rectangles. | ||
289 | The data of the rectangles will be copied later, when the palette | ||
290 | is decided, because the rectangles may have different palettes. */ | ||
291 | ✗ | int xmin = h->rects[0]->x, xmax = xmin + h->rects[0]->w; | |
292 | ✗ | int ymin = h->rects[0]->y, ymax = ymin + h->rects[0]->h; | |
293 | ✗ | for (i = 1; i < rects; i++) { | |
294 | ✗ | xmin = FFMIN(xmin, h->rects[i]->x); | |
295 | ✗ | ymin = FFMIN(ymin, h->rects[i]->y); | |
296 | ✗ | xmax = FFMAX(xmax, h->rects[i]->x + h->rects[i]->w); | |
297 | ✗ | ymax = FFMAX(ymax, h->rects[i]->y + h->rects[i]->h); | |
298 | } | ||
299 | ✗ | vrect.x = xmin; | |
300 | ✗ | vrect.y = ymin; | |
301 | ✗ | vrect.w = xmax - xmin; | |
302 | ✗ | vrect.h = ymax - ymin; | |
303 | ✗ | if ((ret = av_image_check_size(vrect.w, vrect.h, 0, avctx)) < 0) | |
304 | ✗ | return ret; | |
305 | |||
306 | /* Count pixels outside the virtual rectangle as transparent */ | ||
307 | ✗ | global_palette_hits[0] = vrect.w * vrect.h; | |
308 | ✗ | for (i = 0; i < rects; i++) | |
309 | ✗ | global_palette_hits[0] -= h->rects[i]->w * h->rects[i]->h; | |
310 | } | ||
311 | |||
312 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 43 times.
|
86 | for (i = 0; i < rects; i++) |
313 | 43 | count_colors(avctx, global_palette_hits, h->rects[i]); | |
314 | 43 | select_palette(avctx, out_palette, out_alpha, global_palette_hits); | |
315 | |||
316 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if (rects > 1) { |
317 | ✗ | if (!(vrect_data = av_calloc(vrect.w, vrect.h))) | |
318 | ✗ | return AVERROR(ENOMEM); | |
319 | ✗ | vrect.data [0] = vrect_data; | |
320 | ✗ | vrect.linesize[0] = vrect.w; | |
321 | ✗ | for (i = 0; i < rects; i++) { | |
322 | ✗ | build_color_map(avctx, cmap, (uint32_t *)h->rects[i]->data[1], | |
323 | out_palette, out_alpha); | ||
324 | ✗ | copy_rectangle(&vrect, h->rects[i], cmap); | |
325 | } | ||
326 | ✗ | for (i = 0; i < 4; i++) | |
327 | ✗ | cmap[i] = i; | |
328 | } else { | ||
329 | 43 | build_color_map(avctx, cmap, (uint32_t *)h->rects[0]->data[1], | |
330 | out_palette, out_alpha); | ||
331 | } | ||
332 | |||
333 | 43 | av_log(avctx, AV_LOG_DEBUG, "Selected palette:"); | |
334 |
2/2✓ Branch 0 taken 172 times.
✓ Branch 1 taken 43 times.
|
215 | for (i = 0; i < 4; i++) |
335 | 172 | av_log(avctx, AV_LOG_DEBUG, " 0x%06"PRIx32"@@%02x (0x%x,0x%x)", | |
336 | 172 | dvdc->global_palette[out_palette[i]], out_alpha[i], | |
337 | 172 | out_palette[i], out_alpha[i] >> 4); | |
338 | 43 | av_log(avctx, AV_LOG_DEBUG, "\n"); | |
339 | |||
340 | // encode data block | ||
341 | 43 | q = outbuf + 4; | |
342 | 43 | offset1 = q - outbuf; | |
343 | // worst case memory requirement: 1 nibble per pixel.. | ||
344 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if ((q - outbuf) + vrect.w * vrect.h / 2 + 17 + 21 > outbuf_size) { |
345 | ✗ | av_log(NULL, AV_LOG_ERROR, "dvd_subtitle too big\n"); | |
346 | ✗ | ret = AVERROR_BUFFER_TOO_SMALL; | |
347 | ✗ | goto fail; | |
348 | } | ||
349 | 43 | dvd_encode_rle(&q, vrect.data[0], vrect.w * 2, | |
350 | 43 | vrect.w, (vrect.h + 1) >> 1, cmap); | |
351 | 43 | offset2 = q - outbuf; | |
352 | 43 | dvd_encode_rle(&q, vrect.data[0] + vrect.w, vrect.w * 2, | |
353 | 43 | vrect.w, vrect.h >> 1, cmap); | |
354 | |||
355 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
43 | if (dvdc->even_rows_fix && (vrect.h & 1)) { |
356 | // Work-around for some players that want the height to be even. | ||
357 | ✗ | vrect.h++; | |
358 | ✗ | *q++ = 0x00; // 0x00 0x00 == empty row, i.e. fully transparent | |
359 | ✗ | *q++ = 0x00; | |
360 | } | ||
361 | |||
362 | // set data packet size | ||
363 | 43 | qq = outbuf + 2; | |
364 | 43 | bytestream_put_be16(&qq, q - outbuf); | |
365 | |||
366 | // send start display command | ||
367 | 43 | bytestream_put_be16(&q, (h->start_display_time*90) >> 10); | |
368 | 43 | bytestream_put_be16(&q, (q - outbuf) /*- 2 */ + 8 + 12 + 2); | |
369 | 43 | *q++ = 0x03; // palette - 4 nibbles | |
370 | 43 | *q++ = (out_palette[3] << 4) | out_palette[2]; | |
371 | 43 | *q++ = (out_palette[1] << 4) | out_palette[0]; | |
372 | 43 | *q++ = 0x04; // alpha - 4 nibbles | |
373 | 43 | *q++ = (out_alpha[3] & 0xF0) | (out_alpha[2] >> 4); | |
374 | 43 | *q++ = (out_alpha[1] & 0xF0) | (out_alpha[0] >> 4); | |
375 | |||
376 | // 12 bytes per rect | ||
377 | 43 | x2 = vrect.x + vrect.w - 1; | |
378 | 43 | y2 = vrect.y + vrect.h - 1; | |
379 | |||
380 |
2/4✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43 times.
✗ Branch 3 not taken.
|
43 | if ((avctx->width > 0 && x2 > avctx->width) || |
381 |
2/4✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 43 times.
|
43 | (avctx->height > 0 && y2 > avctx->height)) { |
382 | ✗ | av_log(avctx, AV_LOG_ERROR, "canvas_size(%d:%d) is too small(%d:%d) for render\n", | |
383 | avctx->width, avctx->height, x2, y2); | ||
384 | ✗ | ret = AVERROR(EINVAL); | |
385 | ✗ | goto fail; | |
386 | } | ||
387 | 43 | *q++ = 0x05; | |
388 | // x1 x2 -> 6 nibbles | ||
389 | 43 | *q++ = vrect.x >> 4; | |
390 | 43 | *q++ = (vrect.x << 4) | ((x2 >> 8) & 0xf); | |
391 | 43 | *q++ = x2; | |
392 | // y1 y2 -> 6 nibbles | ||
393 | 43 | *q++ = vrect.y >> 4; | |
394 | 43 | *q++ = (vrect.y << 4) | ((y2 >> 8) & 0xf); | |
395 | 43 | *q++ = y2; | |
396 | |||
397 | 43 | *q++ = 0x06; | |
398 | // offset1, offset2 | ||
399 | 43 | bytestream_put_be16(&q, offset1); | |
400 | 43 | bytestream_put_be16(&q, offset2); | |
401 | |||
402 | 43 | *q++ = forced ? 0x00 : 0x01; // start command | |
403 | 43 | *q++ = 0xff; // terminating command | |
404 | |||
405 | // send stop display command last | ||
406 | 43 | bytestream_put_be16(&q, (h->end_display_time*90) >> 10); | |
407 | 43 | bytestream_put_be16(&q, (q - outbuf) - 2 /*+ 4*/); | |
408 | 43 | *q++ = 0x02; // set end | |
409 | 43 | *q++ = 0xff; // terminating command | |
410 | |||
411 | 43 | qq = outbuf; | |
412 | 43 | bytestream_put_be16(&qq, q - outbuf); | |
413 | |||
414 | 43 | av_log(NULL, AV_LOG_DEBUG, "subtitle_packet size=%"PTRDIFF_SPECIFIER"\n", q - outbuf); | |
415 | 43 | ret = q - outbuf; | |
416 | |||
417 | 43 | fail: | |
418 | 43 | av_free(vrect_data); | |
419 | 43 | return ret; | |
420 | } | ||
421 | |||
422 | 1 | static int bprint_to_extradata(AVCodecContext *avctx, struct AVBPrint *buf) | |
423 | { | ||
424 | int ret; | ||
425 | char *str; | ||
426 | |||
427 | 1 | ret = av_bprint_finalize(buf, &str); | |
428 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret < 0) |
429 | ✗ | return ret; | |
430 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!av_bprint_is_complete(buf)) { |
431 | ✗ | av_free(str); | |
432 | ✗ | return AVERROR(ENOMEM); | |
433 | } | ||
434 | |||
435 | 1 | avctx->extradata = str; | |
436 | /* Note: the string is NUL terminated (so extradata can be read as a | ||
437 | * string), but the ending character is not accounted in the size (in | ||
438 | * binary formats you are likely not supposed to mux that character). When | ||
439 | * extradata is copied, it is also padded with AV_INPUT_BUFFER_PADDING_SIZE | ||
440 | * zeros. */ | ||
441 | 1 | avctx->extradata_size = buf->len; | |
442 | 1 | return 0; | |
443 | } | ||
444 | |||
445 | 1 | static int dvdsub_init(AVCodecContext *avctx) | |
446 | { | ||
447 | 1 | DVDSubtitleContext *dvdc = avctx->priv_data; | |
448 | static const uint32_t default_palette[16] = { | ||
449 | 0x000000, 0x0000FF, 0x00FF00, 0xFF0000, | ||
450 | 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFFFFF, | ||
451 | 0x808000, 0x8080FF, 0x800080, 0x80FF80, | ||
452 | 0x008080, 0xFF8080, 0x555555, 0xAAAAAA, | ||
453 | }; | ||
454 | AVBPrint extradata; | ||
455 | int i, ret; | ||
456 | |||
457 | av_assert0(sizeof(dvdc->global_palette) == sizeof(default_palette)); | ||
458 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (dvdc->palette_str) { |
459 | ✗ | ff_dvdsub_parse_palette(dvdc->global_palette, dvdc->palette_str); | |
460 | } else { | ||
461 | 1 | memcpy(dvdc->global_palette, default_palette, sizeof(dvdc->global_palette)); | |
462 | } | ||
463 | |||
464 | 1 | av_bprint_init(&extradata, 0, AV_BPRINT_SIZE_AUTOMATIC); | |
465 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | if (avctx->width && avctx->height) |
466 | 1 | av_bprintf(&extradata, "size: %dx%d\n", avctx->width, avctx->height); | |
467 | 1 | av_bprintf(&extradata, "palette:"); | |
468 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
|
17 | for (i = 0; i < 16; i++) |
469 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
|
16 | av_bprintf(&extradata, " %06"PRIx32"%c", |
470 | 16 | dvdc->global_palette[i] & 0xFFFFFF, i < 15 ? ',' : '\n'); | |
471 | |||
472 | 1 | ret = bprint_to_extradata(avctx, &extradata); | |
473 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret < 0) |
474 | ✗ | return ret; | |
475 | |||
476 | 1 | return 0; | |
477 | } | ||
478 | |||
479 | 43 | static int dvdsub_encode(AVCodecContext *avctx, | |
480 | unsigned char *buf, int buf_size, | ||
481 | const AVSubtitle *sub) | ||
482 | { | ||
483 | //DVDSubtitleContext *s = avctx->priv_data; | ||
484 | int ret; | ||
485 | |||
486 | 43 | ret = encode_dvd_subtitles(avctx, buf, buf_size, sub); | |
487 | 43 | return ret; | |
488 | } | ||
489 | |||
490 | #define OFFSET(x) offsetof(DVDSubtitleContext, x) | ||
491 | #define SE AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM | ||
492 | static const AVOption options[] = { | ||
493 | {"palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SE }, | ||
494 | {"even_rows_fix", "Make number of rows even (workaround for some players)", OFFSET(even_rows_fix), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, SE}, | ||
495 | { NULL }, | ||
496 | }; | ||
497 | |||
498 | static const AVClass dvdsubenc_class = { | ||
499 | .class_name = "VOBSUB subtitle encoder", | ||
500 | .item_name = av_default_item_name, | ||
501 | .option = options, | ||
502 | .version = LIBAVUTIL_VERSION_INT, | ||
503 | }; | ||
504 | |||
505 | const FFCodec ff_dvdsub_encoder = { | ||
506 | .p.name = "dvdsub", | ||
507 | CODEC_LONG_NAME("DVD subtitles"), | ||
508 | .p.type = AVMEDIA_TYPE_SUBTITLE, | ||
509 | .p.id = AV_CODEC_ID_DVD_SUBTITLE, | ||
510 | .init = dvdsub_init, | ||
511 | FF_CODEC_ENCODE_SUB_CB(dvdsub_encode), | ||
512 | .p.priv_class = &dvdsubenc_class, | ||
513 | .priv_data_size = sizeof(DVDSubtitleContext), | ||
514 | }; | ||
515 |