2 * DVD subtitle decoding for ffmpeg
3 * Copyright (c) 2005 Fabrice Bellard.
5 * This file is part of FFmpeg.
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.
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.
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
22 #include "bitstream.h"
23 #include "colorspace.h"
28 static void yuv_a_to_rgba(const uint8_t *ycbcr
, const uint8_t *alpha
, uint32_t *rgba
, int num_values
)
30 uint8_t *cm
= ff_cropTbl
+ MAX_NEG_CROP
;
33 int r_add
, g_add
, b_add
;
35 for (i
= num_values
; i
> 0; i
--) {
39 YUV_TO_RGB1_CCIR(cb
, cr
);
40 YUV_TO_RGB2_CCIR(r
, g
, b
, y
);
41 *rgba
++ = (*alpha
++ << 24) | (r
<< 16) | (g
<< 8) | b
;
45 static int decode_run_2bit(GetBitContext
*gb
, int *color
)
50 for (t
= 1; v
< t
&& t
<= 0x40; t
<<= 2)
51 v
= (v
<< 4) | get_bits(gb
, 4);
53 if (v
< 4) { /* Code for fill rest of line */
59 static int decode_run_8bit(GetBitContext
*gb
, int *color
)
62 int has_run
= get_bits1(gb
);
64 *color
= get_bits(gb
, 8);
66 *color
= get_bits(gb
, 2);
69 len
= get_bits(gb
, 7);
75 len
= get_bits(gb
, 3) + 2;
81 static int decode_rle(uint8_t *bitmap
, int linesize
, int w
, int h
,
82 const uint8_t *buf
, int start
, int buf_size
, int is_8bit
)
89 bit_len
= (buf_size
- start
) * 8;
90 init_get_bits(&gb
, buf
+ start
, bit_len
);
96 if (get_bits_count(&gb
) > bit_len
)
99 len
= decode_run_8bit(&gb
, &color
);
101 len
= decode_run_2bit(&gb
, &color
);
102 len
= FFMIN(len
, w
- x
);
103 memset(d
+ x
, color
, len
);
118 static void guess_palette(uint32_t *rgba_palette
,
121 uint32_t subtitle_color
)
123 uint8_t color_used
[16];
124 int nb_opaque_colors
, i
, level
, j
, r
, g
, b
;
126 for(i
= 0; i
< 4; i
++)
129 memset(color_used
, 0, 16);
130 nb_opaque_colors
= 0;
131 for(i
= 0; i
< 4; i
++) {
132 if (alpha
[i
] != 0 && !color_used
[colormap
[i
]]) {
133 color_used
[colormap
[i
]] = 1;
138 if (nb_opaque_colors
== 0)
141 j
= nb_opaque_colors
;
142 memset(color_used
, 0, 16);
143 for(i
= 0; i
< 4; i
++) {
145 if (!color_used
[colormap
[i
]]) {
146 level
= (0xff * j
) / nb_opaque_colors
;
147 r
= (((subtitle_color
>> 16) & 0xff) * level
) >> 8;
148 g
= (((subtitle_color
>> 8) & 0xff) * level
) >> 8;
149 b
= (((subtitle_color
>> 0) & 0xff) * level
) >> 8;
150 rgba_palette
[i
] = b
| (g
<< 8) | (r
<< 16) | ((alpha
[i
] * 17) << 24);
151 color_used
[colormap
[i
]] = (i
+ 1);
154 rgba_palette
[i
] = (rgba_palette
[color_used
[colormap
[i
]] - 1] & 0x00ffffff) |
155 ((alpha
[i
] * 17) << 24);
161 #define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))
163 static int decode_dvd_subtitles(AVSubtitle
*sub_header
,
164 const uint8_t *buf
, int buf_size
)
166 int cmd_pos
, pos
, cmd
, x1
, y1
, x2
, y2
, offset1
, offset2
, next_cmd_pos
;
167 int big_offsets
, offset_size
, is_8bit
= 0;
168 const uint8_t *yuv_palette
= 0;
169 uint8_t colormap
[4], alpha
[256];
176 sub_header
->rects
= NULL
;
177 sub_header
->num_rects
= 0;
178 sub_header
->start_display_time
= 0;
179 sub_header
->end_display_time
= 0;
181 if (AV_RB16(buf
) == 0) { /* HD subpicture with 4-byte offsets */
191 cmd_pos
= READ_OFFSET(buf
+ cmd_pos
);
193 while ((cmd_pos
+ 2 + offset_size
) < buf_size
) {
194 date
= AV_RB16(buf
+ cmd_pos
);
195 next_cmd_pos
= READ_OFFSET(buf
+ cmd_pos
+ 2);
197 av_log(NULL
, AV_LOG_INFO
, "cmd_pos=0x%04x next=0x%04x date=%d\n",
198 cmd_pos
, next_cmd_pos
, date
);
200 pos
= cmd_pos
+ 2 + offset_size
;
203 x1
= y1
= x2
= y2
= 0;
204 while (pos
< buf_size
) {
207 av_log(NULL
, AV_LOG_INFO
, "cmd=%02x\n", cmd
);
211 /* menu subpicture */
216 sub_header
->start_display_time
= (date
<< 10) / 90;
220 sub_header
->end_display_time
= (date
<< 10) / 90;
224 if ((buf_size
- pos
) < 2)
226 colormap
[3] = buf
[pos
] >> 4;
227 colormap
[2] = buf
[pos
] & 0x0f;
228 colormap
[1] = buf
[pos
+ 1] >> 4;
229 colormap
[0] = buf
[pos
+ 1] & 0x0f;
234 if ((buf_size
- pos
) < 2)
236 alpha
[3] = buf
[pos
] >> 4;
237 alpha
[2] = buf
[pos
] & 0x0f;
238 alpha
[1] = buf
[pos
+ 1] >> 4;
239 alpha
[0] = buf
[pos
+ 1] & 0x0f;
242 av_log(NULL
, AV_LOG_INFO
, "alpha=%x%x%x%x\n", alpha
[0],alpha
[1],alpha
[2],alpha
[3]);
247 if ((buf_size
- pos
) < 6)
249 x1
= (buf
[pos
] << 4) | (buf
[pos
+ 1] >> 4);
250 x2
= ((buf
[pos
+ 1] & 0x0f) << 8) | buf
[pos
+ 2];
251 y1
= (buf
[pos
+ 3] << 4) | (buf
[pos
+ 4] >> 4);
252 y2
= ((buf
[pos
+ 4] & 0x0f) << 8) | buf
[pos
+ 5];
256 av_log(NULL
, AV_LOG_INFO
, "x1=%d x2=%d y1=%d y2=%d\n",
262 if ((buf_size
- pos
) < 4)
264 offset1
= AV_RB16(buf
+ pos
);
265 offset2
= AV_RB16(buf
+ pos
+ 2);
267 av_log(NULL
, AV_LOG_INFO
, "offset1=0x%04x offset2=0x%04x\n", offset1
, offset2
);
272 if ((buf_size
- pos
) < 8)
274 offset1
= AV_RB32(buf
+ pos
);
275 offset2
= AV_RB32(buf
+ pos
+ 4);
277 av_log(NULL
, AV_LOG_INFO
, "offset1=0x%04x offset2=0x%04x\n", offset1
, offset2
);
284 if ((buf_size
- pos
) < 768)
286 yuv_palette
= buf
+ pos
;
290 /* HD set contrast (alpha) */
291 if ((buf_size
- pos
) < 256)
293 for (i
= 0; i
< 256; i
++)
294 alpha
[i
] = 0xFF - buf
[pos
+i
];
302 av_log(NULL
, AV_LOG_INFO
, "unrecognised subpicture command 0x%x\n", cmd
);
312 /* decode the bitmap */
319 if (w
> 0 && h
> 0) {
320 if (sub_header
->rects
!= NULL
) {
321 for (i
= 0; i
< sub_header
->num_rects
; i
++) {
322 av_free(sub_header
->rects
[i
].bitmap
);
323 av_free(sub_header
->rects
[i
].rgba_palette
);
325 av_freep(&sub_header
->rects
);
326 sub_header
->num_rects
= 0;
329 bitmap
= av_malloc(w
* h
);
330 sub_header
->rects
= av_mallocz(sizeof(AVSubtitleRect
));
331 sub_header
->num_rects
= 1;
332 sub_header
->rects
[0].bitmap
= bitmap
;
333 decode_rle(bitmap
, w
* 2, w
, (h
+ 1) / 2,
334 buf
, offset1
, buf_size
, is_8bit
);
335 decode_rle(bitmap
+ w
, w
* 2, w
, h
/ 2,
336 buf
, offset2
, buf_size
, is_8bit
);
338 if (yuv_palette
== 0)
340 sub_header
->rects
[0].rgba_palette
= av_malloc(256 * 4);
341 sub_header
->rects
[0].nb_colors
= 256;
342 yuv_a_to_rgba(yuv_palette
, alpha
, sub_header
->rects
[0].rgba_palette
, 256);
344 sub_header
->rects
[0].rgba_palette
= av_malloc(4 * 4);
345 sub_header
->rects
[0].nb_colors
= 4;
346 guess_palette(sub_header
->rects
[0].rgba_palette
,
347 colormap
, alpha
, 0xffff00);
349 sub_header
->rects
[0].x
= x1
;
350 sub_header
->rects
[0].y
= y1
;
351 sub_header
->rects
[0].w
= w
;
352 sub_header
->rects
[0].h
= h
;
353 sub_header
->rects
[0].linesize
= w
;
356 if (next_cmd_pos
== cmd_pos
)
358 cmd_pos
= next_cmd_pos
;
360 if (sub_header
->num_rects
> 0)
363 if (sub_header
->rects
!= NULL
) {
364 for (i
= 0; i
< sub_header
->num_rects
; i
++) {
365 av_free(sub_header
->rects
[i
].bitmap
);
366 av_free(sub_header
->rects
[i
].rgba_palette
);
368 av_freep(&sub_header
->rects
);
369 sub_header
->num_rects
= 0;
374 static int is_transp(const uint8_t *buf
, int pitch
, int n
,
375 const uint8_t *transp_color
)
378 for(i
= 0; i
< n
; i
++) {
379 if (!transp_color
[*buf
])
386 /* return 0 if empty rectangle, 1 if non empty */
387 static int find_smallest_bounding_rectangle(AVSubtitle
*s
)
389 uint8_t transp_color
[256];
390 int y1
, y2
, x1
, x2
, y
, w
, h
, i
;
393 if (s
->num_rects
== 0 || s
->rects
== NULL
|| s
->rects
[0].w
<= 0 || s
->rects
[0].h
<= 0)
396 memset(transp_color
, 0, 256);
397 for(i
= 0; i
< s
->rects
[0].nb_colors
; i
++) {
398 if ((s
->rects
[0].rgba_palette
[i
] >> 24) == 0)
402 while (y1
< s
->rects
[0].h
&& is_transp(s
->rects
[0].bitmap
+ y1
* s
->rects
[0].linesize
,
403 1, s
->rects
[0].w
, transp_color
))
405 if (y1
== s
->rects
[0].h
) {
406 av_freep(&s
->rects
[0].bitmap
);
407 s
->rects
[0].w
= s
->rects
[0].h
= 0;
411 y2
= s
->rects
[0].h
- 1;
412 while (y2
> 0 && is_transp(s
->rects
[0].bitmap
+ y2
* s
->rects
[0].linesize
, 1,
413 s
->rects
[0].w
, transp_color
))
416 while (x1
< (s
->rects
[0].w
- 1) && is_transp(s
->rects
[0].bitmap
+ x1
, s
->rects
[0].linesize
,
417 s
->rects
[0].h
, transp_color
))
419 x2
= s
->rects
[0].w
- 1;
420 while (x2
> 0 && is_transp(s
->rects
[0].bitmap
+ x2
, s
->rects
[0].linesize
, s
->rects
[0].h
,
425 bitmap
= av_malloc(w
* h
);
428 for(y
= 0; y
< h
; y
++) {
429 memcpy(bitmap
+ w
* y
, s
->rects
[0].bitmap
+ x1
+ (y1
+ y
) * s
->rects
[0].linesize
, w
);
431 av_freep(&s
->rects
[0].bitmap
);
432 s
->rects
[0].bitmap
= bitmap
;
433 s
->rects
[0].linesize
= w
;
445 static void ppm_save(const char *filename
, uint8_t *bitmap
, int w
, int h
,
446 uint32_t *rgba_palette
)
451 f
= fopen(filename
, "w");
460 for(y
= 0; y
< h
; y
++) {
461 for(x
= 0; x
< w
; x
++) {
462 v
= rgba_palette
[bitmap
[y
* w
+ x
]];
463 putc((v
>> 16) & 0xff, f
);
464 putc((v
>> 8) & 0xff, f
);
465 putc((v
>> 0) & 0xff, f
);
472 static int dvdsub_decode(AVCodecContext
*avctx
,
473 void *data
, int *data_size
,
474 const uint8_t *buf
, int buf_size
)
476 AVSubtitle
*sub
= (void *)data
;
479 is_menu
= decode_dvd_subtitles(sub
, buf
, buf_size
);
487 if (!is_menu
&& find_smallest_bounding_rectangle(sub
) == 0)
491 av_log(NULL
, AV_LOG_INFO
, "start=%d ms end =%d ms\n",
492 sub
->start_display_time
,
493 sub
->end_display_time
);
494 ppm_save("/tmp/a.ppm", sub
->rects
[0].bitmap
,
495 sub
->rects
[0].w
, sub
->rects
[0].h
, sub
->rects
[0].rgba_palette
);
502 AVCodec dvdsub_decoder
= {
505 CODEC_ID_DVD_SUBTITLE
,
511 .long_name
= NULL_IF_CONFIG_SMALL("DVD subtitles"),