2 * DVD subtitle decoding
3 * Copyright (c) 2005 Fabrice Bellard
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "bitstream.h"
26 #include "libavutil/attributes.h"
27 #include "libavutil/colorspace.h"
28 #include "libavutil/imgutils.h"
29 #include "libavutil/avstring.h"
31 typedef struct DVDSubContext
{
36 static void yuv_a_to_rgba(const uint8_t *ycbcr
, const uint8_t *alpha
, uint32_t *rgba
, int num_values
)
38 const uint8_t *cm
= ff_crop_tab
+ MAX_NEG_CROP
;
41 int r_add
, g_add
, b_add
;
43 for (i
= num_values
; i
> 0; i
--) {
47 YUV_TO_RGB1_CCIR(cb
, cr
);
48 YUV_TO_RGB2_CCIR(r
, g
, b
, y
);
49 *rgba
++ = (*alpha
++ << 24) | (r
<< 16) | (g
<< 8) | b
;
53 static int decode_run_2bit(BitstreamContext
*bc
, int *color
)
58 for (t
= 1; v
< t
&& t
<= 0x40; t
<<= 2)
59 v
= (v
<< 4) | bitstream_read(bc
, 4);
61 if (v
< 4) { /* Code for fill rest of line */
67 static int decode_run_8bit(BitstreamContext
*bc
, int *color
)
70 int has_run
= bitstream_read_bit(bc
);
71 if (bitstream_read_bit(bc
))
72 *color
= bitstream_read(bc
, 8);
74 *color
= bitstream_read(bc
, 2);
76 if (bitstream_read_bit(bc
)) {
77 len
= bitstream_read(bc
, 7);
83 len
= bitstream_read(bc
, 3) + 2;
89 static int decode_rle(uint8_t *bitmap
, int linesize
, int w
, int h
,
90 const uint8_t *buf
, int start
, int buf_size
, int is_8bit
)
97 bit_len
= (buf_size
- start
) * 8;
98 bitstream_init(&bc
, buf
+ start
, bit_len
);
104 if (bitstream_tell(&bc
) > bit_len
)
107 len
= decode_run_8bit(&bc
, &color
);
109 len
= decode_run_2bit(&bc
, &color
);
110 len
= FFMIN(len
, w
- x
);
111 memset(d
+ x
, color
, len
);
120 bitstream_align(&bc
);
126 static void guess_palette(DVDSubContext
* ctx
,
127 uint32_t *rgba_palette
,
130 uint32_t subtitle_color
)
132 uint8_t color_used
[16] = { 0 };
133 int nb_opaque_colors
, i
, level
, j
, r
, g
, b
;
135 if (ctx
->has_palette
) {
136 for (i
= 0; i
< 4; i
++)
137 rgba_palette
[i
] = (ctx
->palette
[colormap
[i
]] & 0x00ffffff)
138 | ((alpha
[i
] * 17) << 24);
142 for(i
= 0; i
< 4; i
++)
145 nb_opaque_colors
= 0;
146 for(i
= 0; i
< 4; i
++) {
147 if (alpha
[i
] != 0 && !color_used
[colormap
[i
]]) {
148 color_used
[colormap
[i
]] = 1;
153 if (nb_opaque_colors
== 0)
156 j
= nb_opaque_colors
;
157 memset(color_used
, 0, 16);
158 for(i
= 0; i
< 4; i
++) {
160 if (!color_used
[colormap
[i
]]) {
161 level
= (0xff * j
) / nb_opaque_colors
;
162 r
= (((subtitle_color
>> 16) & 0xff) * level
) >> 8;
163 g
= (((subtitle_color
>> 8) & 0xff) * level
) >> 8;
164 b
= (((subtitle_color
>> 0) & 0xff) * level
) >> 8;
165 rgba_palette
[i
] = b
| (g
<< 8) | (r
<< 16) | ((alpha
[i
] * 17) << 24);
166 color_used
[colormap
[i
]] = (i
+ 1);
169 rgba_palette
[i
] = (rgba_palette
[color_used
[colormap
[i
]] - 1] & 0x00ffffff) |
170 ((alpha
[i
] * 17) << 24);
176 #define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))
178 static int decode_dvd_subtitles(DVDSubContext
*ctx
, AVSubtitle
*sub_header
,
179 const uint8_t *buf
, int buf_size
)
181 int cmd_pos
, pos
, cmd
, x1
, y1
, x2
, y2
, next_cmd_pos
;
182 int big_offsets
, offset_size
, is_8bit
= 0;
183 const uint8_t *yuv_palette
= 0;
184 uint8_t colormap
[4] = { 0 }, alpha
[256] = { 0 };
188 int64_t offset1
, offset2
;
192 memset(sub_header
, 0, sizeof(*sub_header
));
194 if (AV_RB16(buf
) == 0) { /* HD subpicture with 4-byte offsets */
204 cmd_pos
= READ_OFFSET(buf
+ cmd_pos
);
206 while (cmd_pos
> 0 && cmd_pos
< buf_size
- 2 - offset_size
) {
207 date
= AV_RB16(buf
+ cmd_pos
);
208 next_cmd_pos
= READ_OFFSET(buf
+ cmd_pos
+ 2);
209 ff_dlog(NULL
, "cmd_pos=0x%04x next=0x%04x date=%d\n",
210 cmd_pos
, next_cmd_pos
, date
);
211 pos
= cmd_pos
+ 2 + offset_size
;
214 x1
= y1
= x2
= y2
= 0;
215 while (pos
< buf_size
) {
217 ff_dlog(NULL
, "cmd=%02x\n", cmd
);
220 /* menu subpicture */
225 sub_header
->start_display_time
= (date
<< 10) / 90;
229 sub_header
->end_display_time
= (date
<< 10) / 90;
233 if ((buf_size
- pos
) < 2)
235 colormap
[3] = buf
[pos
] >> 4;
236 colormap
[2] = buf
[pos
] & 0x0f;
237 colormap
[1] = buf
[pos
+ 1] >> 4;
238 colormap
[0] = buf
[pos
+ 1] & 0x0f;
243 if ((buf_size
- pos
) < 2)
245 alpha
[3] = buf
[pos
] >> 4;
246 alpha
[2] = buf
[pos
] & 0x0f;
247 alpha
[1] = buf
[pos
+ 1] >> 4;
248 alpha
[0] = buf
[pos
+ 1] & 0x0f;
250 ff_dlog(NULL
, "alpha=%"PRIx8
"%"PRIx8
"%"PRIx8
"%"PRIx8
"\n",
251 alpha
[0], alpha
[1], alpha
[2], alpha
[3]);
255 if ((buf_size
- pos
) < 6)
257 x1
= (buf
[pos
] << 4) | (buf
[pos
+ 1] >> 4);
258 x2
= ((buf
[pos
+ 1] & 0x0f) << 8) | buf
[pos
+ 2];
259 y1
= (buf
[pos
+ 3] << 4) | (buf
[pos
+ 4] >> 4);
260 y2
= ((buf
[pos
+ 4] & 0x0f) << 8) | buf
[pos
+ 5];
263 ff_dlog(NULL
, "x1=%d x2=%d y1=%d y2=%d\n", x1
, x2
, y1
, y2
);
267 if ((buf_size
- pos
) < 4)
269 offset1
= AV_RB16(buf
+ pos
);
270 offset2
= AV_RB16(buf
+ pos
+ 2);
271 ff_dlog(NULL
, "offset1=0x%04"PRIx64
" offset2=0x%04"PRIx64
"\n", offset1
, offset2
);
275 if ((buf_size
- pos
) < 8)
277 offset1
= AV_RB32(buf
+ pos
);
278 offset2
= AV_RB32(buf
+ pos
+ 4);
279 ff_dlog(NULL
, "offset1=0x%04"PRIx64
" offset2=0x%04"PRIx64
"\n", offset1
, offset2
);
285 if ((buf_size
- pos
) < 768)
287 yuv_palette
= buf
+ pos
;
291 /* HD set contrast (alpha) */
292 if ((buf_size
- pos
) < 256)
294 for (i
= 0; i
< 256; i
++)
295 alpha
[i
] = 0xFF - buf
[pos
+i
];
302 ff_dlog(NULL
, "unrecognised subpicture command 0x%x\n", cmd
);
307 if (offset1
>= buf_size
|| offset2
>= buf_size
)
314 /* decode the bitmap */
321 if (w
> 0 && h
> 0) {
322 if (sub_header
->rects
) {
323 for (i
= 0; i
< sub_header
->num_rects
; i
++) {
324 av_freep(&sub_header
->rects
[i
]->data
[0]);
325 av_freep(&sub_header
->rects
[i
]->data
[1]);
326 av_freep(&sub_header
->rects
[i
]);
328 av_freep(&sub_header
->rects
);
329 sub_header
->num_rects
= 0;
332 sub_header
->rects
= av_mallocz(sizeof(*sub_header
->rects
));
333 if (!sub_header
->rects
)
335 sub_header
->rects
[0] = av_mallocz(sizeof(AVSubtitleRect
));
336 if (!sub_header
->rects
[0])
338 sub_header
->num_rects
= 1;
339 bitmap
= sub_header
->rects
[0]->data
[0] = av_malloc(w
* h
);
342 decode_rle(bitmap
, w
* 2, w
, (h
+ 1) / 2,
343 buf
, offset1
, buf_size
, is_8bit
);
344 decode_rle(bitmap
+ w
, w
* 2, w
, h
/ 2,
345 buf
, offset2
, buf_size
, is_8bit
);
346 sub_header
->rects
[0]->data
[1] = av_mallocz(AVPALETTE_SIZE
);
347 if (!sub_header
->rects
[0]->data
[1])
350 if (yuv_palette
== 0)
352 sub_header
->rects
[0]->nb_colors
= 256;
353 yuv_a_to_rgba(yuv_palette
, alpha
,
354 (uint32_t *)sub_header
->rects
[0]->data
[1],
357 sub_header
->rects
[0]->nb_colors
= 4;
359 (uint32_t *)sub_header
->rects
[0]->data
[1],
360 colormap
, alpha
, 0xffff00);
362 sub_header
->rects
[0]->x
= x1
;
363 sub_header
->rects
[0]->y
= y1
;
364 sub_header
->rects
[0]->w
= w
;
365 sub_header
->rects
[0]->h
= h
;
366 sub_header
->rects
[0]->type
= SUBTITLE_BITMAP
;
367 sub_header
->rects
[0]->linesize
[0] = w
;
370 FF_DISABLE_DEPRECATION_WARNINGS
373 AVSubtitleRect
*rect
;
374 rect
= sub_header
->rects
[0];
375 for (j
= 0; j
< 4; j
++) {
376 rect
->pict
.data
[j
] = rect
->data
[j
];
377 rect
->pict
.linesize
[j
] = rect
->linesize
[j
];
380 FF_ENABLE_DEPRECATION_WARNINGS
384 if (next_cmd_pos
== cmd_pos
)
386 cmd_pos
= next_cmd_pos
;
388 if (sub_header
->num_rects
> 0)
391 if (!sub_header
->rects
) {
392 for (i
= 0; i
< sub_header
->num_rects
; i
++) {
393 av_freep(&sub_header
->rects
[i
]->data
[0]);
394 av_freep(&sub_header
->rects
[i
]->data
[1]);
395 av_freep(&sub_header
->rects
[i
]);
397 av_freep(&sub_header
->rects
);
398 sub_header
->num_rects
= 0;
403 static int is_transp(const uint8_t *buf
, int pitch
, int n
,
404 const uint8_t *transp_color
)
407 for(i
= 0; i
< n
; i
++) {
408 if (!transp_color
[*buf
])
415 /* return 0 if empty rectangle, 1 if non empty */
416 static int find_smallest_bounding_rectangle(AVSubtitle
*s
)
418 uint8_t transp_color
[256] = { 0 };
419 int y1
, y2
, x1
, x2
, y
, w
, h
, i
;
422 if (s
->num_rects
== 0 || !s
->rects
|| s
->rects
[0]->w
<= 0 || s
->rects
[0]->h
<= 0)
425 for(i
= 0; i
< s
->rects
[0]->nb_colors
; i
++) {
426 if ((((uint32_t *)s
->rects
[0]->data
[1])[i
] >> 24) == 0)
430 while (y1
< s
->rects
[0]->h
&& is_transp(s
->rects
[0]->data
[0] + y1
* s
->rects
[0]->linesize
[0],
431 1, s
->rects
[0]->w
, transp_color
))
433 if (y1
== s
->rects
[0]->h
) {
434 av_freep(&s
->rects
[0]->data
[0]);
435 s
->rects
[0]->w
= s
->rects
[0]->h
= 0;
439 y2
= s
->rects
[0]->h
- 1;
440 while (y2
> 0 && is_transp(s
->rects
[0]->data
[0] + y2
* s
->rects
[0]->linesize
[0], 1,
441 s
->rects
[0]->w
, transp_color
))
444 while (x1
< (s
->rects
[0]->w
- 1) && is_transp(s
->rects
[0]->data
[0] + x1
, s
->rects
[0]->linesize
[0],
445 s
->rects
[0]->h
, transp_color
))
447 x2
= s
->rects
[0]->w
- 1;
448 while (x2
> 0 && is_transp(s
->rects
[0]->data
[0] + x2
, s
->rects
[0]->linesize
[0], s
->rects
[0]->h
,
453 bitmap
= av_malloc(w
* h
);
456 for(y
= 0; y
< h
; y
++) {
457 memcpy(bitmap
+ w
* y
, s
->rects
[0]->data
[0] + x1
+ (y1
+ y
) * s
->rects
[0]->linesize
[0], w
);
459 av_freep(&s
->rects
[0]->data
[0]);
460 s
->rects
[0]->data
[0] = bitmap
;
461 s
->rects
[0]->linesize
[0] = w
;
464 s
->rects
[0]->x
+= x1
;
465 s
->rects
[0]->y
+= y1
;
470 static void ppm_save(const char *filename
, uint8_t *bitmap
, int w
, int h
,
471 uint32_t *rgba_palette
)
476 f
= fopen(filename
, "w");
485 for(y
= 0; y
< h
; y
++) {
486 for(x
= 0; x
< w
; x
++) {
487 v
= rgba_palette
[bitmap
[y
* w
+ x
]];
488 putc((v
>> 16) & 0xff, f
);
489 putc((v
>> 8) & 0xff, f
);
490 putc((v
>> 0) & 0xff, f
);
497 static int dvdsub_decode(AVCodecContext
*avctx
,
498 void *data
, int *data_size
,
501 DVDSubContext
*ctx
= avctx
->priv_data
;
502 const uint8_t *buf
= avpkt
->data
;
503 int buf_size
= avpkt
->size
;
504 AVSubtitle
*sub
= data
;
507 is_menu
= decode_dvd_subtitles(ctx
, sub
, buf
, buf_size
);
515 if (!is_menu
&& find_smallest_bounding_rectangle(sub
) == 0)
519 ff_dlog(NULL
, "start=%"PRIu32
" ms end =%"PRIu32
" ms\n",
520 sub
->start_display_time
,
521 sub
->end_display_time
);
522 ppm_save("/tmp/a.ppm", sub
->rects
[0]->data
[0],
523 sub
->rects
[0]->w
, sub
->rects
[0]->h
, sub
->rects
[0]->data
[1]);
530 static av_cold
int dvdsub_init(AVCodecContext
*avctx
)
532 DVDSubContext
*ctx
= avctx
->priv_data
;
536 if (!avctx
->extradata
|| !avctx
->extradata_size
)
539 data
= av_malloc(avctx
->extradata_size
+ 1);
541 return AVERROR(ENOMEM
);
542 memcpy(data
, avctx
->extradata
, avctx
->extradata_size
);
543 data
[avctx
->extradata_size
] = '\0';
547 if (strncmp("palette:", cur
, 8) == 0) {
550 ctx
->has_palette
= 1;
551 for (i
= 0; i
< 16; i
++) {
552 ctx
->palette
[i
] = strtoul(p
, &p
, 16);
553 while (*p
== ',' || av_isspace(*p
))
556 } else if (!strncmp("size:", cur
, 5)) {
558 if (sscanf(cur
+ 5, "%dx%d", &w
, &h
) == 2) {
559 ret
= ff_set_dimensions(avctx
, w
, h
);
564 cur
+= strcspn(cur
, "\n\r");
565 cur
+= strspn(cur
, "\n\r");
573 AVCodec ff_dvdsub_decoder
= {
575 .long_name
= NULL_IF_CONFIG_SMALL("DVD subtitles"),
576 .type
= AVMEDIA_TYPE_SUBTITLE
,
577 .id
= AV_CODEC_ID_DVD_SUBTITLE
,
578 .priv_data_size
= sizeof(DVDSubContext
),
580 .decode
= dvdsub_decode
,