1 /*
2 * DVD subtitle decoding
3 * Copyright (c) 2005 Fabrice Bellard
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 */
27
28 //#define DEBUG
29
31 {
39
41 {
45 int r_add, g_add, b_add;
46
47 for (i = num_values; i > 0; i--) {
48 y = *ycbcr++;
49 cr = *ycbcr++;
50 cb = *ycbcr++;
53 *rgba++ = (*alpha++ << 24) | (r << 16) | (g << 8) | b;
54 }
55 }
56
58 {
60
61 v = 0;
62 for (t = 1; v < t && t <= 0x40; t <<= 2)
64 *color = v & 3;
65 if (v < 4) { /* Code for fill rest of line */
66 return INT_MAX;
67 }
68 return v >> 2;
69 }
70
72 {
77 else
79 if (has_run) {
82 if (len == 0)
83 len = INT_MAX;
84 else
85 len += 9;
86 } else
88 } else
89 len = 1;
91 }
92
94 const uint8_t *buf,
int start,
int buf_size,
int is_8bit)
95 {
97 int bit_len;
100
101 bit_len = (buf_size - start) * 8;
103
104 x = 0;
105 y = 0;
106 d = bitmap;
107 for(;;) {
109 return -1;
110 if (is_8bit)
112 else
114 len =
FFMIN(len, w - x);
115 memset(d + x, color, len);
117 if (x >= w) {
118 y++;
119 if (y >= h)
120 break;
121 d += linesize;
122 x = 0;
123 /* byte align */
125 }
126 }
127 return 0;
128 }
129
132 uint32_t subtitle_color)
133 {
134 static const uint8_t level_map[4][4] = {
135 // this configuration (full range, lowest to highest) in tests
136 // seemed most common, so assume this
137 {0xff},
138 {0x00, 0xff},
139 {0x00, 0x80, 0xff},
140 {0x00, 0x55, 0xaa, 0xff},
141 };
142 uint8_t color_used[16] = { 0 };
143 int nb_opaque_colors, i,
level, j,
r,
g,
b;
145
147 for(i = 0; i < 4; i++)
148 rgba_palette[i] = (ctx->
palette[colormap[i]] & 0x00ffffff)
149 | ((alpha[i] * 17) << 24);
150 return;
151 }
152
153 for(i = 0; i < 4; i++)
154 rgba_palette[i] = 0;
155
156 nb_opaque_colors = 0;
157 for(i = 0; i < 4; i++) {
158 if (alpha[i] != 0 && !color_used[colormap[i]]) {
159 color_used[colormap[i]] = 1;
160 nb_opaque_colors++;
161 }
162 }
163
164 if (nb_opaque_colors == 0)
165 return;
166
167 j = 0;
168 memset(color_used, 0, 16);
169 for(i = 0; i < 4; i++) {
170 if (alpha[i] != 0) {
171 if (!color_used[colormap[i]]) {
172 level = level_map[nb_opaque_colors][j];
173 r = (((subtitle_color >> 16) & 0xff) *
level) >> 8;
174 g = (((subtitle_color >> 8) & 0xff) *
level) >> 8;
175 b = (((subtitle_color >> 0) & 0xff) *
level) >> 8;
176 rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17) << 24);
177 color_used[colormap[i]] = (i + 1);
178 j++;
179 } else {
180 rgba_palette[i] = (rgba_palette[color_used[colormap[i]] - 1] & 0x00ffffff) |
181 ((alpha[i] * 17) << 24);
182 }
183 }
184 }
185 }
186
187 #define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))
188
190 const uint8_t *buf,
int buf_size)
191 {
192 int cmd_pos, pos, cmd, x1, y1, x2, y2, offset1, offset2, next_cmd_pos;
193 int big_offsets, offset_size, is_8bit = 0;
194 const uint8_t *yuv_palette = 0;
196 int date;
197 int i;
198 int is_menu = 0;
199
200 if (buf_size < 10)
201 return -1;
202
203 if (
AV_RB16(buf) == 0) {
/* HD subpicture with 4-byte offsets */
204 big_offsets = 1;
205 offset_size = 4;
206 cmd_pos = 6;
207 } else {
208 big_offsets = 0;
209 offset_size = 2;
210 cmd_pos = 2;
211 }
212
214
215 while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) {
218 av_dlog(
NULL,
"cmd_pos=0x%04x next=0x%04x date=%d\n",
219 cmd_pos, next_cmd_pos, date);
220 pos = cmd_pos + 2 + offset_size;
221 offset1 = -1;
222 offset2 = -1;
223 x1 = y1 = x2 = y2 = 0;
224 while (pos < buf_size) {
225 cmd = buf[pos++];
227 switch(cmd) {
228 case 0x00:
229 /* menu subpicture */
230 is_menu = 1;
231 break;
232 case 0x01:
233 /* set start date */
235 break;
236 case 0x02:
237 /* set end date */
239 break;
240 case 0x03:
241 /* set colormap */
242 if ((buf_size - pos) < 2)
243 goto fail;
244 colormap[3] = buf[pos] >> 4;
245 colormap[2] = buf[pos] & 0x0f;
246 colormap[1] = buf[pos + 1] >> 4;
247 colormap[0] = buf[pos + 1] & 0x0f;
248 pos += 2;
249 break;
250 case 0x04:
251 /* set alpha */
252 if ((buf_size - pos) < 2)
253 goto fail;
254 alpha[3] = buf[pos] >> 4;
255 alpha[2] = buf[pos] & 0x0f;
256 alpha[1] = buf[pos + 1] >> 4;
257 alpha[0] = buf[pos + 1] & 0x0f;
258 pos += 2;
259 av_dlog(
NULL,
"alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]);
260 break;
261 case 0x05:
262 case 0x85:
263 if ((buf_size - pos) < 6)
264 goto fail;
265 x1 = (buf[pos] << 4) | (buf[pos + 1] >> 4);
266 x2 = ((buf[pos + 1] & 0x0f) << 8) | buf[pos + 2];
267 y1 = (buf[pos + 3] << 4) | (buf[pos + 4] >> 4);
268 y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5];
269 if (cmd & 0x80)
270 is_8bit = 1;
271 av_dlog(
NULL,
"x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2);
272 pos += 6;
273 break;
274 case 0x06:
275 if ((buf_size - pos) < 4)
276 goto fail;
278 offset2 =
AV_RB16(buf + pos + 2);
279 av_dlog(
NULL,
"offset1=0x%04x offset2=0x%04x\n", offset1, offset2);
280 pos += 4;
281 break;
282 case 0x86:
283 if ((buf_size - pos) < 8)
284 goto fail;
286 offset2 =
AV_RB32(buf + pos + 4);
287 av_dlog(
NULL,
"offset1=0x%04x offset2=0x%04x\n", offset1, offset2);
288 pos += 8;
289 break;
290
291 case 0x83:
292 /* HD set palette */
293 if ((buf_size - pos) < 768)
294 goto fail;
295 yuv_palette = buf + pos;
296 pos += 768;
297 break;
298 case 0x84:
299 /* HD set contrast (alpha) */
300 if ((buf_size - pos) < 256)
301 goto fail;
302 for (i = 0; i < 256; i++)
303 alpha[i] = 0xFF - buf[pos+i];
304 pos += 256;
305 break;
306
307 case 0xff:
308 goto the_end;
309 default:
310 av_dlog(
NULL,
"unrecognised subpicture command 0x%x\n", cmd);
311 goto the_end;
312 }
313 }
314 the_end:
315 if (offset1 >= 0) {
316 int w, h;
318
319 /* decode the bitmap */
320 w = x2 - x1 + 1;
321 if (w < 0)
322 w = 0;
323 h = y2 - y1;
324 if (h < 0)
325 h = 0;
326 if (w > 0 && h > 0) {
328 for (i = 0; i < sub_header->
num_rects; i++) {
332 }
335 }
336
343 buf, offset1, buf_size, is_8bit);
345 buf, offset2, buf_size, is_8bit);
347 if (is_8bit) {
348 if (yuv_palette == 0)
349 goto fail;
352 } else {
355 0xffff00);
356 }
357 sub_header->
rects[0]->
x = x1;
358 sub_header->
rects[0]->
y = y1;
359 sub_header->
rects[0]->
w = w;
360 sub_header->
rects[0]->
h = h;
364 }
365 }
366 if (next_cmd_pos < cmd_pos) {
368 break;
369 }
370 if (next_cmd_pos == cmd_pos)
371 break;
372 cmd_pos = next_cmd_pos;
373 }
375 return is_menu;
376 fail:
378 for (i = 0; i < sub_header->
num_rects; i++) {
382 }
385 }
386 return -1;
387 }
388
391 {
392 int i;
393 for(i = 0; i < n; i++) {
394 if (!transp_color[*buf])
395 return 0;
396 buf += pitch;
397 }
398 return 1;
399 }
400
401 /* return 0 if empty rectangle, 1 if non empty */
403 {
404 uint8_t transp_color[256] = { 0 };
405 int y1, y2, x1, x2, y, w, h, i;
407
409 return 0;
410
413 transp_color[i] = 1;
414 }
415 y1 = 0;
417 1, s->
rects[0]->
w, transp_color))
418 y1++;
419 if (y1 == s->
rects[0]->
h) {
422 return 0;
423 }
424
427 s->
rects[0]->
w, transp_color))
428 y2--;
429 x1 = 0;
431 s->
rects[0]->
h, transp_color))
432 x1++;
435 transp_color))
436 x2--;
437 w = x2 - x1 + 1;
438 h = y2 - y1 + 1;
440 if (!bitmap)
441 return 1;
442 for(y = 0; y < h; y++) {
444 }
452 return 1;
453 }
454
455 #ifdef DEBUG
456 #undef fprintf
457 #undef perror
458 #undef exit
459 static void ppm_save(
const char *filename,
uint8_t *bitmap,
int w,
int h,
460 uint32_t *rgba_palette)
461 {
462 int x, y, v;
463 FILE *f;
464
465 f = fopen(filename, "w");
466 if (!f) {
467 perror(filename);
468 exit(1);
469 }
470 fprintf(f, "P6\n"
471 "%d %d\n"
472 "%d\n",
473 w, h, 255);
474 for(y = 0; y < h; y++) {
475 for(x = 0; x < w; x++) {
476 v = rgba_palette[bitmap[y * w + x]];
477 putc((v >> 16) & 0xff, f);
478 putc((v >> 8) & 0xff, f);
479 putc((v >> 0) & 0xff, f);
480 }
481 }
482 fclose(f);
483 }
484 #endif
485
487 void *
data,
int *data_size,
489 {
492 int buf_size = avpkt->
size;
494 int is_menu;
495
497
498 if (is_menu < 0) {
499 no_subtitle:
500 *data_size = 0;
501
502 return buf_size;
503 }
505 goto no_subtitle;
506
507 #if defined(DEBUG)
509 sub->start_display_time,
510 sub->end_display_time);
511 ppm_save("/tmp/a.ppm", sub->rects[0]->pict.data[0],
512 sub->rects[0]->w, sub->rects[0]->h, sub->rects[0]->pict.data[1]);
513 #endif
514
515 *data_size = 1;
516 return buf_size;
517 }
518
520 {
521 int i;
522
524 for(i=0;i<16;i++) {
525 ctx->
palette[i] = strtoul(p, &p, 16);
526 while(*p == ',' || isspace(*p))
527 p++;
528 }
529 }
530
532 {
534 char *dataorig, *
data;
535
537 return 1;
538
544
545 for(;;) {
546 int pos = strcspn(
data,
"\n\r");
547 if (pos==0 && *
data==0)
548 break;
549
550 if (strncmp(
"palette:",
data, 8) == 0) {
552 }
else if (strncmp(
"size:",
data, 5) == 0) {
553 int w, h;
554 if (sscanf(
data + 5,
"%dx%d", &w, &h) == 2 &&
557 }
558
561 }
562
564 return 1;
565 }
566
568 {
570 int ret;
571
573 return ret;
574
578 int i;
580 for(i=0;i<16;i++)
583 }
584
585 return 1;
586 }
587
588 #define OFFSET(field) offsetof(DVDSubContext, field)
589 #define VD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
593 };
599 };
600
609 .priv_class = &class,
610 };