dvdsubdec.c
Go to the documentation of this file.
1 /*
2  * DVD subtitle decoding
3  * Copyright (c) 2005 Fabrice Bellard
4  *
5  * This file is part of Libav.
6  *
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.
11  *
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.
16  *
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
20  */
21 #include "avcodec.h"
22 #include "get_bits.h"
23 #include "dsputil.h"
24 #include "libavutil/colorspace.h"
25 
26 //#define DEBUG
27 
28 static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values)
29 {
31  uint8_t r, g, b;
32  int i, y, cb, cr;
33  int r_add, g_add, b_add;
34 
35  for (i = num_values; i > 0; i--) {
36  y = *ycbcr++;
37  cr = *ycbcr++;
38  cb = *ycbcr++;
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;
42  }
43 }
44 
45 static int decode_run_2bit(GetBitContext *gb, int *color)
46 {
47  unsigned int v, t;
48 
49  v = 0;
50  for (t = 1; v < t && t <= 0x40; t <<= 2)
51  v = (v << 4) | get_bits(gb, 4);
52  *color = v & 3;
53  if (v < 4) { /* Code for fill rest of line */
54  return INT_MAX;
55  }
56  return v >> 2;
57 }
58 
59 static int decode_run_8bit(GetBitContext *gb, int *color)
60 {
61  int len;
62  int has_run = get_bits1(gb);
63  if (get_bits1(gb))
64  *color = get_bits(gb, 8);
65  else
66  *color = get_bits(gb, 2);
67  if (has_run) {
68  if (get_bits1(gb)) {
69  len = get_bits(gb, 7);
70  if (len == 0)
71  len = INT_MAX;
72  else
73  len += 9;
74  } else
75  len = get_bits(gb, 3) + 2;
76  } else
77  len = 1;
78  return len;
79 }
80 
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)
83 {
84  GetBitContext gb;
85  int bit_len;
86  int x, y, len, color;
87  uint8_t *d;
88 
89  bit_len = (buf_size - start) * 8;
90  init_get_bits(&gb, buf + start, bit_len);
91 
92  x = 0;
93  y = 0;
94  d = bitmap;
95  for(;;) {
96  if (get_bits_count(&gb) > bit_len)
97  return -1;
98  if (is_8bit)
99  len = decode_run_8bit(&gb, &color);
100  else
101  len = decode_run_2bit(&gb, &color);
102  len = FFMIN(len, w - x);
103  memset(d + x, color, len);
104  x += len;
105  if (x >= w) {
106  y++;
107  if (y >= h)
108  break;
109  d += linesize;
110  x = 0;
111  /* byte align */
112  align_get_bits(&gb);
113  }
114  }
115  return 0;
116 }
117 
118 static void guess_palette(uint32_t *rgba_palette,
119  uint8_t *colormap,
120  uint8_t *alpha,
121  uint32_t subtitle_color)
122 {
123  uint8_t color_used[16] = { 0 };
124  int nb_opaque_colors, i, level, j, r, g, b;
125 
126  for(i = 0; i < 4; i++)
127  rgba_palette[i] = 0;
128 
129  nb_opaque_colors = 0;
130  for(i = 0; i < 4; i++) {
131  if (alpha[i] != 0 && !color_used[colormap[i]]) {
132  color_used[colormap[i]] = 1;
133  nb_opaque_colors++;
134  }
135  }
136 
137  if (nb_opaque_colors == 0)
138  return;
139 
140  j = nb_opaque_colors;
141  memset(color_used, 0, 16);
142  for(i = 0; i < 4; i++) {
143  if (alpha[i] != 0) {
144  if (!color_used[colormap[i]]) {
145  level = (0xff * j) / nb_opaque_colors;
146  r = (((subtitle_color >> 16) & 0xff) * level) >> 8;
147  g = (((subtitle_color >> 8) & 0xff) * level) >> 8;
148  b = (((subtitle_color >> 0) & 0xff) * level) >> 8;
149  rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17) << 24);
150  color_used[colormap[i]] = (i + 1);
151  j--;
152  } else {
153  rgba_palette[i] = (rgba_palette[color_used[colormap[i]] - 1] & 0x00ffffff) |
154  ((alpha[i] * 17) << 24);
155  }
156  }
157  }
158 }
159 
160 #define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))
161 
162 static int decode_dvd_subtitles(AVSubtitle *sub_header,
163  const uint8_t *buf, int buf_size)
164 {
165  int cmd_pos, pos, cmd, x1, y1, x2, y2, offset1, offset2, next_cmd_pos;
166  int big_offsets, offset_size, is_8bit = 0;
167  const uint8_t *yuv_palette = 0;
168  uint8_t colormap[4], alpha[256];
169  int date;
170  int i;
171  int is_menu = 0;
172 
173  if (buf_size < 10)
174  return -1;
175  memset(sub_header, 0, sizeof(*sub_header));
176 
177  if (AV_RB16(buf) == 0) { /* HD subpicture with 4-byte offsets */
178  big_offsets = 1;
179  offset_size = 4;
180  cmd_pos = 6;
181  } else {
182  big_offsets = 0;
183  offset_size = 2;
184  cmd_pos = 2;
185  }
186 
187  cmd_pos = READ_OFFSET(buf + cmd_pos);
188 
189  while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) {
190  date = AV_RB16(buf + cmd_pos);
191  next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2);
192  av_dlog(NULL, "cmd_pos=0x%04x next=0x%04x date=%d\n",
193  cmd_pos, next_cmd_pos, date);
194  pos = cmd_pos + 2 + offset_size;
195  offset1 = -1;
196  offset2 = -1;
197  x1 = y1 = x2 = y2 = 0;
198  while (pos < buf_size) {
199  cmd = buf[pos++];
200  av_dlog(NULL, "cmd=%02x\n", cmd);
201  switch(cmd) {
202  case 0x00:
203  /* menu subpicture */
204  is_menu = 1;
205  break;
206  case 0x01:
207  /* set start date */
208  sub_header->start_display_time = (date << 10) / 90;
209  break;
210  case 0x02:
211  /* set end date */
212  sub_header->end_display_time = (date << 10) / 90;
213  break;
214  case 0x03:
215  /* set colormap */
216  if ((buf_size - pos) < 2)
217  goto fail;
218  colormap[3] = buf[pos] >> 4;
219  colormap[2] = buf[pos] & 0x0f;
220  colormap[1] = buf[pos + 1] >> 4;
221  colormap[0] = buf[pos + 1] & 0x0f;
222  pos += 2;
223  break;
224  case 0x04:
225  /* set alpha */
226  if ((buf_size - pos) < 2)
227  goto fail;
228  alpha[3] = buf[pos] >> 4;
229  alpha[2] = buf[pos] & 0x0f;
230  alpha[1] = buf[pos + 1] >> 4;
231  alpha[0] = buf[pos + 1] & 0x0f;
232  pos += 2;
233  av_dlog(NULL, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]);
234  break;
235  case 0x05:
236  case 0x85:
237  if ((buf_size - pos) < 6)
238  goto fail;
239  x1 = (buf[pos] << 4) | (buf[pos + 1] >> 4);
240  x2 = ((buf[pos + 1] & 0x0f) << 8) | buf[pos + 2];
241  y1 = (buf[pos + 3] << 4) | (buf[pos + 4] >> 4);
242  y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5];
243  if (cmd & 0x80)
244  is_8bit = 1;
245  av_dlog(NULL, "x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2);
246  pos += 6;
247  break;
248  case 0x06:
249  if ((buf_size - pos) < 4)
250  goto fail;
251  offset1 = AV_RB16(buf + pos);
252  offset2 = AV_RB16(buf + pos + 2);
253  av_dlog(NULL, "offset1=0x%04x offset2=0x%04x\n", offset1, offset2);
254  pos += 4;
255  break;
256  case 0x86:
257  if ((buf_size - pos) < 8)
258  goto fail;
259  offset1 = AV_RB32(buf + pos);
260  offset2 = AV_RB32(buf + pos + 4);
261  av_dlog(NULL, "offset1=0x%04x offset2=0x%04x\n", offset1, offset2);
262  pos += 8;
263  break;
264 
265  case 0x83:
266  /* HD set palette */
267  if ((buf_size - pos) < 768)
268  goto fail;
269  yuv_palette = buf + pos;
270  pos += 768;
271  break;
272  case 0x84:
273  /* HD set contrast (alpha) */
274  if ((buf_size - pos) < 256)
275  goto fail;
276  for (i = 0; i < 256; i++)
277  alpha[i] = 0xFF - buf[pos+i];
278  pos += 256;
279  break;
280 
281  case 0xff:
282  goto the_end;
283  default:
284  av_dlog(NULL, "unrecognised subpicture command 0x%x\n", cmd);
285  goto the_end;
286  }
287  }
288  the_end:
289  if (offset1 >= 0) {
290  int w, h;
291  uint8_t *bitmap;
292 
293  /* decode the bitmap */
294  w = x2 - x1 + 1;
295  if (w < 0)
296  w = 0;
297  h = y2 - y1;
298  if (h < 0)
299  h = 0;
300  if (w > 0 && h > 0) {
301  if (sub_header->rects != NULL) {
302  for (i = 0; i < sub_header->num_rects; i++) {
303  av_freep(&sub_header->rects[i]->pict.data[0]);
304  av_freep(&sub_header->rects[i]->pict.data[1]);
305  av_freep(&sub_header->rects[i]);
306  }
307  av_freep(&sub_header->rects);
308  sub_header->num_rects = 0;
309  }
310 
311  bitmap = av_malloc(w * h);
312  sub_header->rects = av_mallocz(sizeof(*sub_header->rects));
313  sub_header->rects[0] = av_mallocz(sizeof(AVSubtitleRect));
314  sub_header->num_rects = 1;
315  sub_header->rects[0]->pict.data[0] = bitmap;
316  decode_rle(bitmap, w * 2, w, (h + 1) / 2,
317  buf, offset1, buf_size, is_8bit);
318  decode_rle(bitmap + w, w * 2, w, h / 2,
319  buf, offset2, buf_size, is_8bit);
320  sub_header->rects[0]->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
321  if (is_8bit) {
322  if (yuv_palette == 0)
323  goto fail;
324  sub_header->rects[0]->nb_colors = 256;
325  yuv_a_to_rgba(yuv_palette, alpha, (uint32_t*)sub_header->rects[0]->pict.data[1], 256);
326  } else {
327  sub_header->rects[0]->nb_colors = 4;
328  guess_palette((uint32_t*)sub_header->rects[0]->pict.data[1],
329  colormap, alpha, 0xffff00);
330  }
331  sub_header->rects[0]->x = x1;
332  sub_header->rects[0]->y = y1;
333  sub_header->rects[0]->w = w;
334  sub_header->rects[0]->h = h;
335  sub_header->rects[0]->type = SUBTITLE_BITMAP;
336  sub_header->rects[0]->pict.linesize[0] = w;
337  }
338  }
339  if (next_cmd_pos == cmd_pos)
340  break;
341  cmd_pos = next_cmd_pos;
342  }
343  if (sub_header->num_rects > 0)
344  return is_menu;
345  fail:
346  if (sub_header->rects != NULL) {
347  for (i = 0; i < sub_header->num_rects; i++) {
348  av_freep(&sub_header->rects[i]->pict.data[0]);
349  av_freep(&sub_header->rects[i]->pict.data[1]);
350  av_freep(&sub_header->rects[i]);
351  }
352  av_freep(&sub_header->rects);
353  sub_header->num_rects = 0;
354  }
355  return -1;
356 }
357 
358 static int is_transp(const uint8_t *buf, int pitch, int n,
359  const uint8_t *transp_color)
360 {
361  int i;
362  for(i = 0; i < n; i++) {
363  if (!transp_color[*buf])
364  return 0;
365  buf += pitch;
366  }
367  return 1;
368 }
369 
370 /* return 0 if empty rectangle, 1 if non empty */
372 {
373  uint8_t transp_color[256] = { 0 };
374  int y1, y2, x1, x2, y, w, h, i;
375  uint8_t *bitmap;
376 
377  if (s->num_rects == 0 || s->rects == NULL || s->rects[0]->w <= 0 || s->rects[0]->h <= 0)
378  return 0;
379 
380  for(i = 0; i < s->rects[0]->nb_colors; i++) {
381  if ((((uint32_t*)s->rects[0]->pict.data[1])[i] >> 24) == 0)
382  transp_color[i] = 1;
383  }
384  y1 = 0;
385  while (y1 < s->rects[0]->h && is_transp(s->rects[0]->pict.data[0] + y1 * s->rects[0]->pict.linesize[0],
386  1, s->rects[0]->w, transp_color))
387  y1++;
388  if (y1 == s->rects[0]->h) {
389  av_freep(&s->rects[0]->pict.data[0]);
390  s->rects[0]->w = s->rects[0]->h = 0;
391  return 0;
392  }
393 
394  y2 = s->rects[0]->h - 1;
395  while (y2 > 0 && is_transp(s->rects[0]->pict.data[0] + y2 * s->rects[0]->pict.linesize[0], 1,
396  s->rects[0]->w, transp_color))
397  y2--;
398  x1 = 0;
399  while (x1 < (s->rects[0]->w - 1) && is_transp(s->rects[0]->pict.data[0] + x1, s->rects[0]->pict.linesize[0],
400  s->rects[0]->h, transp_color))
401  x1++;
402  x2 = s->rects[0]->w - 1;
403  while (x2 > 0 && is_transp(s->rects[0]->pict.data[0] + x2, s->rects[0]->pict.linesize[0], s->rects[0]->h,
404  transp_color))
405  x2--;
406  w = x2 - x1 + 1;
407  h = y2 - y1 + 1;
408  bitmap = av_malloc(w * h);
409  if (!bitmap)
410  return 1;
411  for(y = 0; y < h; y++) {
412  memcpy(bitmap + w * y, s->rects[0]->pict.data[0] + x1 + (y1 + y) * s->rects[0]->pict.linesize[0], w);
413  }
414  av_freep(&s->rects[0]->pict.data[0]);
415  s->rects[0]->pict.data[0] = bitmap;
416  s->rects[0]->pict.linesize[0] = w;
417  s->rects[0]->w = w;
418  s->rects[0]->h = h;
419  s->rects[0]->x += x1;
420  s->rects[0]->y += y1;
421  return 1;
422 }
423 
424 #ifdef DEBUG
425 #undef fprintf
426 #undef perror
427 #undef exit
428 static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
429  uint32_t *rgba_palette)
430 {
431  int x, y, v;
432  FILE *f;
433 
434  f = fopen(filename, "w");
435  if (!f) {
436  perror(filename);
437  exit(1);
438  }
439  fprintf(f, "P6\n"
440  "%d %d\n"
441  "%d\n",
442  w, h, 255);
443  for(y = 0; y < h; y++) {
444  for(x = 0; x < w; x++) {
445  v = rgba_palette[bitmap[y * w + x]];
446  putc((v >> 16) & 0xff, f);
447  putc((v >> 8) & 0xff, f);
448  putc((v >> 0) & 0xff, f);
449  }
450  }
451  fclose(f);
452 }
453 #endif
454 
455 static int dvdsub_decode(AVCodecContext *avctx,
456  void *data, int *data_size,
457  AVPacket *avpkt)
458 {
459  const uint8_t *buf = avpkt->data;
460  int buf_size = avpkt->size;
461  AVSubtitle *sub = data;
462  int is_menu;
463 
464  is_menu = decode_dvd_subtitles(sub, buf, buf_size);
465 
466  if (is_menu < 0) {
467  no_subtitle:
468  *data_size = 0;
469 
470  return buf_size;
471  }
472  if (!is_menu && find_smallest_bounding_rectangle(sub) == 0)
473  goto no_subtitle;
474 
475 #if defined(DEBUG)
476  av_dlog(NULL, "start=%d ms end =%d ms\n",
477  sub->start_display_time,
478  sub->end_display_time);
479  ppm_save("/tmp/a.ppm", sub->rects[0]->pict.data[0],
480  sub->rects[0]->w, sub->rects[0]->h, sub->rects[0]->pict.data[1]);
481 #endif
482 
483  *data_size = 1;
484  return buf_size;
485 }
486 
488  .name = "dvdsub",
489  .type = AVMEDIA_TYPE_SUBTITLE,
491  .decode = dvdsub_decode,
492  .long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
493 };