LCOV - code coverage report
Current view: top level - libavcodec - dvdsubdec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 266 440 60.5 %
Date: 2017-12-15 18:13:28 Functions: 14 17 82.4 %

          Line data    Source code
       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             :  */
      21             : 
      22             : #include "avcodec.h"
      23             : #include "get_bits.h"
      24             : #include "internal.h"
      25             : 
      26             : #include "libavutil/attributes.h"
      27             : #include "libavutil/colorspace.h"
      28             : #include "libavutil/opt.h"
      29             : #include "libavutil/imgutils.h"
      30             : #include "libavutil/avstring.h"
      31             : #include "libavutil/bswap.h"
      32             : 
      33             : typedef struct DVDSubContext
      34             : {
      35             :   AVClass *class;
      36             :   uint32_t palette[16];
      37             :   char    *palette_str;
      38             :   char    *ifo_str;
      39             :   int      has_palette;
      40             :   uint8_t  colormap[4];
      41             :   uint8_t  alpha[256];
      42             :   uint8_t  buf[0x10000];
      43             :   int      buf_size;
      44             :   int      forced_subs_only;
      45             : #ifdef DEBUG
      46             :   int sub_id;
      47             : #endif
      48             : } DVDSubContext;
      49             : 
      50           0 : static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values)
      51             : {
      52           0 :     const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
      53             :     uint8_t r, g, b;
      54             :     int i, y, cb, cr;
      55             :     int r_add, g_add, b_add;
      56             : 
      57           0 :     for (i = num_values; i > 0; i--) {
      58           0 :         y = *ycbcr++;
      59           0 :         cr = *ycbcr++;
      60           0 :         cb = *ycbcr++;
      61           0 :         YUV_TO_RGB1_CCIR(cb, cr);
      62           0 :         YUV_TO_RGB2_CCIR(r, g, b, y);
      63           0 :         *rgba++ = ((unsigned)*alpha++ << 24) | (r << 16) | (g << 8) | b;
      64             :     }
      65           0 : }
      66             : 
      67      149254 : static int decode_run_2bit(GetBitContext *gb, int *color)
      68             : {
      69             :     unsigned int v, t;
      70             : 
      71      149254 :     v = 0;
      72      398577 :     for (t = 1; v < t && t <= 0x40; t <<= 2)
      73      249323 :         v = (v << 4) | get_bits(gb, 4);
      74      149254 :     *color = v & 3;
      75      149254 :     if (v < 4) { /* Code for fill rest of line */
      76       21028 :         return INT_MAX;
      77             :     }
      78      128226 :     return v >> 2;
      79             : }
      80             : 
      81           0 : static int decode_run_8bit(GetBitContext *gb, int *color)
      82             : {
      83             :     int len;
      84           0 :     int has_run = get_bits1(gb);
      85           0 :     if (get_bits1(gb))
      86           0 :         *color = get_bits(gb, 8);
      87             :     else
      88           0 :         *color = get_bits(gb, 2);
      89           0 :     if (has_run) {
      90           0 :         if (get_bits1(gb)) {
      91           0 :             len = get_bits(gb, 7);
      92           0 :             if (len == 0)
      93           0 :                 len = INT_MAX;
      94             :             else
      95           0 :                 len += 9;
      96             :         } else
      97           0 :             len = get_bits(gb, 3) + 2;
      98             :     } else
      99           0 :         len = 1;
     100           0 :     return len;
     101             : }
     102             : 
     103          88 : static int decode_rle(uint8_t *bitmap, int linesize, int w, int h,
     104             :                       const uint8_t *buf, int start, int buf_size, int is_8bit)
     105             : {
     106             :     GetBitContext gb;
     107             :     int bit_len;
     108             :     int x, y, len, color;
     109             :     uint8_t *d;
     110             : 
     111          88 :     if (start >= buf_size)
     112           0 :         return -1;
     113             : 
     114          88 :     if (w <= 0 || h <= 0)
     115           0 :         return -1;
     116             : 
     117          88 :     bit_len = (buf_size - start) * 8;
     118          88 :     init_get_bits(&gb, buf + start, bit_len);
     119             : 
     120          88 :     x = 0;
     121          88 :     y = 0;
     122          88 :     d = bitmap;
     123             :     for(;;) {
     124      298420 :         if (get_bits_count(&gb) > bit_len)
     125           0 :             return -1;
     126      149254 :         if (is_8bit)
     127           0 :             len = decode_run_8bit(&gb, &color);
     128             :         else
     129      149254 :             len = decode_run_2bit(&gb, &color);
     130      149254 :         len = FFMIN(len, w - x);
     131      149254 :         memset(d + x, color, len);
     132      149254 :         x += len;
     133      149254 :         if (x >= w) {
     134       21028 :             y++;
     135       21028 :             if (y >= h)
     136          88 :                 break;
     137       20940 :             d += linesize;
     138       20940 :             x = 0;
     139             :             /* byte align */
     140       20940 :             align_get_bits(&gb);
     141             :         }
     142             :     }
     143          88 :     return 0;
     144             : }
     145             : 
     146          44 : static void guess_palette(DVDSubContext* ctx,
     147             :                           uint32_t *rgba_palette,
     148             :                           uint32_t subtitle_color)
     149             : {
     150             :     static const uint8_t level_map[4][4] = {
     151             :         // this configuration (full range, lowest to highest) in tests
     152             :         // seemed most common, so assume this
     153             :         {0xff},
     154             :         {0x00, 0xff},
     155             :         {0x00, 0x80, 0xff},
     156             :         {0x00, 0x55, 0xaa, 0xff},
     157             :     };
     158          44 :     uint8_t color_used[16] = { 0 };
     159             :     int nb_opaque_colors, i, level, j, r, g, b;
     160          44 :     uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha;
     161             : 
     162          44 :     if(ctx->has_palette) {
     163         220 :         for(i = 0; i < 4; i++)
     164         528 :             rgba_palette[i] = (ctx->palette[colormap[i]] & 0x00ffffff)
     165         352 :                               | ((alpha[i] * 17U) << 24);
     166          88 :         return;
     167             :     }
     168             : 
     169           0 :     for(i = 0; i < 4; i++)
     170           0 :         rgba_palette[i] = 0;
     171             : 
     172           0 :     nb_opaque_colors = 0;
     173           0 :     for(i = 0; i < 4; i++) {
     174           0 :         if (alpha[i] != 0 && !color_used[colormap[i]]) {
     175           0 :             color_used[colormap[i]] = 1;
     176           0 :             nb_opaque_colors++;
     177             :         }
     178             :     }
     179             : 
     180           0 :     if (nb_opaque_colors == 0)
     181           0 :         return;
     182             : 
     183           0 :     j = 0;
     184           0 :     memset(color_used, 0, 16);
     185           0 :     for(i = 0; i < 4; i++) {
     186           0 :         if (alpha[i] != 0) {
     187           0 :             if (!color_used[colormap[i]])  {
     188           0 :                 level = level_map[nb_opaque_colors - 1][j];
     189           0 :                 r = (((subtitle_color >> 16) & 0xff) * level) >> 8;
     190           0 :                 g = (((subtitle_color >> 8) & 0xff) * level) >> 8;
     191           0 :                 b = (((subtitle_color >> 0) & 0xff) * level) >> 8;
     192           0 :                 rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17U) << 24);
     193           0 :                 color_used[colormap[i]] = (i + 1);
     194           0 :                 j++;
     195             :             } else {
     196           0 :                 rgba_palette[i] = (rgba_palette[color_used[colormap[i]] - 1] & 0x00ffffff) |
     197           0 :                                     ((alpha[i] * 17U) << 24);
     198             :             }
     199             :         }
     200             :     }
     201             : }
     202             : 
     203          44 : static void reset_rects(AVSubtitle *sub_header)
     204             : {
     205             :     int i;
     206             : 
     207          44 :     if (sub_header->rects) {
     208           0 :         for (i = 0; i < sub_header->num_rects; i++) {
     209           0 :             av_freep(&sub_header->rects[i]->data[0]);
     210           0 :             av_freep(&sub_header->rects[i]->data[1]);
     211           0 :             av_freep(&sub_header->rects[i]);
     212             :         }
     213           0 :         av_freep(&sub_header->rects);
     214           0 :         sub_header->num_rects = 0;
     215             :     }
     216          44 : }
     217             : 
     218             : #define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))
     219             : 
     220          47 : static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
     221             :                                 const uint8_t *buf, int buf_size)
     222             : {
     223             :     int cmd_pos, pos, cmd, x1, y1, x2, y2, next_cmd_pos;
     224          47 :     int big_offsets, offset_size, is_8bit = 0;
     225          47 :     const uint8_t *yuv_palette = NULL;
     226          47 :     uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha;
     227             :     int date;
     228             :     int i;
     229          47 :     int is_menu = 0;
     230             :     uint32_t size;
     231             :     int64_t offset1, offset2;
     232             : 
     233          47 :     if (buf_size < 10)
     234           0 :         return -1;
     235             : 
     236          47 :     if (AV_RB16(buf) == 0) {   /* HD subpicture with 4-byte offsets */
     237           0 :         big_offsets = 1;
     238           0 :         offset_size = 4;
     239           0 :         cmd_pos = 6;
     240             :     } else {
     241          47 :         big_offsets = 0;
     242          47 :         offset_size = 2;
     243          47 :         cmd_pos = 2;
     244             :     }
     245             : 
     246          47 :     size = READ_OFFSET(buf + (big_offsets ? 2 : 0));
     247          47 :     cmd_pos = READ_OFFSET(buf + cmd_pos);
     248             : 
     249          47 :     if (cmd_pos < 0 || cmd_pos > buf_size - 2 - offset_size) {
     250           3 :         if (cmd_pos > size) {
     251           0 :             av_log(ctx, AV_LOG_ERROR, "Discarding invalid packet\n");
     252           0 :             return 0;
     253             :         }
     254           3 :         return AVERROR(EAGAIN);
     255             :     }
     256             : 
     257         131 :     while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) {
     258          87 :         date = AV_RB16(buf + cmd_pos);
     259          87 :         next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2);
     260             :         ff_dlog(NULL, "cmd_pos=0x%04x next=0x%04x date=%d\n",
     261             :                 cmd_pos, next_cmd_pos, date);
     262          87 :         pos = cmd_pos + 2 + offset_size;
     263          87 :         offset1 = -1;
     264          87 :         offset2 = -1;
     265          87 :         x1 = y1 = x2 = y2 = 0;
     266         437 :         while (pos < buf_size) {
     267         350 :             cmd = buf[pos++];
     268             :             ff_dlog(NULL, "cmd=%02x\n", cmd);
     269         350 :             switch(cmd) {
     270           0 :             case 0x00:
     271             :                 /* menu subpicture */
     272           0 :                 is_menu = 1;
     273           0 :                 break;
     274          44 :             case 0x01:
     275             :                 /* set start date */
     276          44 :                 sub_header->start_display_time = (date << 10) / 90;
     277          44 :                 break;
     278          43 :             case 0x02:
     279             :                 /* set end date */
     280          43 :                 sub_header->end_display_time = (date << 10) / 90;
     281          43 :                 break;
     282          44 :             case 0x03:
     283             :                 /* set colormap */
     284          44 :                 if ((buf_size - pos) < 2)
     285           0 :                     goto fail;
     286          44 :                 colormap[3] = buf[pos] >> 4;
     287          44 :                 colormap[2] = buf[pos] & 0x0f;
     288          44 :                 colormap[1] = buf[pos + 1] >> 4;
     289          44 :                 colormap[0] = buf[pos + 1] & 0x0f;
     290          44 :                 pos += 2;
     291          44 :                 break;
     292          44 :             case 0x04:
     293             :                 /* set alpha */
     294          44 :                 if ((buf_size - pos) < 2)
     295           0 :                     goto fail;
     296          44 :                 alpha[3] = buf[pos] >> 4;
     297          44 :                 alpha[2] = buf[pos] & 0x0f;
     298          44 :                 alpha[1] = buf[pos + 1] >> 4;
     299          44 :                 alpha[0] = buf[pos + 1] & 0x0f;
     300          44 :                 pos += 2;
     301             :                 ff_dlog(NULL, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]);
     302          44 :                 break;
     303          44 :             case 0x05:
     304             :             case 0x85:
     305          44 :                 if ((buf_size - pos) < 6)
     306           0 :                     goto fail;
     307          44 :                 x1 = (buf[pos] << 4) | (buf[pos + 1] >> 4);
     308          44 :                 x2 = ((buf[pos + 1] & 0x0f) << 8) | buf[pos + 2];
     309          44 :                 y1 = (buf[pos + 3] << 4) | (buf[pos + 4] >> 4);
     310          44 :                 y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5];
     311          44 :                 if (cmd & 0x80)
     312           0 :                     is_8bit = 1;
     313             :                 ff_dlog(NULL, "x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2);
     314          44 :                 pos += 6;
     315          44 :                 break;
     316          44 :             case 0x06:
     317          44 :                 if ((buf_size - pos) < 4)
     318           0 :                     goto fail;
     319          44 :                 offset1 = AV_RB16(buf + pos);
     320          44 :                 offset2 = AV_RB16(buf + pos + 2);
     321             :                 ff_dlog(NULL, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2);
     322          44 :                 pos += 4;
     323          44 :                 break;
     324           0 :             case 0x86:
     325           0 :                 if ((buf_size - pos) < 8)
     326           0 :                     goto fail;
     327           0 :                 offset1 = AV_RB32(buf + pos);
     328           0 :                 offset2 = AV_RB32(buf + pos + 4);
     329             :                 ff_dlog(NULL, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2);
     330           0 :                 pos += 8;
     331           0 :                 break;
     332             : 
     333           0 :             case 0x83:
     334             :                 /* HD set palette */
     335           0 :                 if ((buf_size - pos) < 768)
     336           0 :                     goto fail;
     337           0 :                 yuv_palette = buf + pos;
     338           0 :                 pos += 768;
     339           0 :                 break;
     340           0 :             case 0x84:
     341             :                 /* HD set contrast (alpha) */
     342           0 :                 if ((buf_size - pos) < 256)
     343           0 :                     goto fail;
     344           0 :                 for (i = 0; i < 256; i++)
     345           0 :                     alpha[i] = 0xFF - buf[pos+i];
     346           0 :                 pos += 256;
     347           0 :                 break;
     348             : 
     349          87 :             case 0xff:
     350          87 :                 goto the_end;
     351           0 :             default:
     352             :                 ff_dlog(NULL, "unrecognised subpicture command 0x%x\n", cmd);
     353           0 :                 goto the_end;
     354             :             }
     355             :         }
     356           0 :     the_end:
     357          87 :         if (offset1 >= buf_size || offset2 >= buf_size)
     358             :             goto fail;
     359             : 
     360          87 :         if (offset1 >= 0 && offset2 >= 0) {
     361             :             int w, h;
     362             :             uint8_t *bitmap;
     363             : 
     364             :             /* decode the bitmap */
     365          44 :             w = x2 - x1 + 1;
     366          44 :             if (w < 0)
     367           0 :                 w = 0;
     368          44 :             h = y2 - y1 + 1;
     369          44 :             if (h < 0)
     370           0 :                 h = 0;
     371          44 :             if (w > 0 && h > 1) {
     372          44 :                 reset_rects(sub_header);
     373             : 
     374          44 :                 sub_header->rects = av_mallocz(sizeof(*sub_header->rects));
     375          44 :                 if (!sub_header->rects)
     376           0 :                     goto fail;
     377          44 :                 sub_header->rects[0] = av_mallocz(sizeof(AVSubtitleRect));
     378          44 :                 if (!sub_header->rects[0])
     379           0 :                     goto fail;
     380          44 :                 sub_header->num_rects = 1;
     381          44 :                 bitmap = sub_header->rects[0]->data[0] = av_malloc(w * h);
     382          44 :                 if (!bitmap)
     383           0 :                     goto fail;
     384          44 :                 if (decode_rle(bitmap, w * 2, w, (h + 1) / 2,
     385             :                                buf, offset1, buf_size, is_8bit) < 0)
     386           0 :                     goto fail;
     387          44 :                 if (decode_rle(bitmap + w, w * 2, w, h / 2,
     388             :                                buf, offset2, buf_size, is_8bit) < 0)
     389           0 :                     goto fail;
     390          44 :                 sub_header->rects[0]->data[1] = av_mallocz(AVPALETTE_SIZE);
     391          44 :                 if (!sub_header->rects[0]->data[1])
     392           0 :                     goto fail;
     393          44 :                 if (is_8bit) {
     394           0 :                     if (!yuv_palette)
     395           0 :                         goto fail;
     396           0 :                     sub_header->rects[0]->nb_colors = 256;
     397           0 :                     yuv_a_to_rgba(yuv_palette, alpha,
     398           0 :                                   (uint32_t *)sub_header->rects[0]->data[1],
     399             :                                   256);
     400             :                 } else {
     401          44 :                     sub_header->rects[0]->nb_colors = 4;
     402          44 :                     guess_palette(ctx, (uint32_t*)sub_header->rects[0]->data[1],
     403             :                                   0xffff00);
     404             :                 }
     405          44 :                 sub_header->rects[0]->x = x1;
     406          44 :                 sub_header->rects[0]->y = y1;
     407          44 :                 sub_header->rects[0]->w = w;
     408          44 :                 sub_header->rects[0]->h = h;
     409          44 :                 sub_header->rects[0]->type = SUBTITLE_BITMAP;
     410          44 :                 sub_header->rects[0]->linesize[0] = w;
     411          44 :                 sub_header->rects[0]->flags = is_menu ? AV_SUBTITLE_FLAG_FORCED : 0;
     412             : 
     413             : #if FF_API_AVPICTURE
     414             : FF_DISABLE_DEPRECATION_WARNINGS
     415         220 :                 for (i = 0; i < 4; i++) {
     416         176 :                     sub_header->rects[0]->pict.data[i] = sub_header->rects[0]->data[i];
     417         176 :                     sub_header->rects[0]->pict.linesize[i] = sub_header->rects[0]->linesize[i];
     418             :                 }
     419             : FF_ENABLE_DEPRECATION_WARNINGS
     420             : #endif
     421             :             }
     422             :         }
     423          87 :         if (next_cmd_pos < cmd_pos) {
     424           0 :             av_log(ctx, AV_LOG_ERROR, "Invalid command offset\n");
     425           0 :             break;
     426             :         }
     427          87 :         if (next_cmd_pos == cmd_pos)
     428          44 :             break;
     429          43 :         cmd_pos = next_cmd_pos;
     430             :     }
     431          44 :     if (sub_header->num_rects > 0)
     432          44 :         return is_menu;
     433           0 :  fail:
     434           0 :     reset_rects(sub_header);
     435           0 :     return -1;
     436             : }
     437             : 
     438       38664 : static int is_transp(const uint8_t *buf, int pitch, int n,
     439             :                      const uint8_t *transp_color)
     440             : {
     441             :     int i;
     442    23192950 :     for(i = 0; i < n; i++) {
     443    23154462 :         if (!transp_color[*buf])
     444         176 :             return 0;
     445    23154286 :         buf += pitch;
     446             :     }
     447       38488 :     return 1;
     448             : }
     449             : 
     450             : /* return 0 if empty rectangle, 1 if non empty */
     451          44 : static int find_smallest_bounding_rectangle(AVSubtitle *s)
     452             : {
     453          44 :     uint8_t transp_color[256] = { 0 };
     454             :     int y1, y2, x1, x2, y, w, h, i;
     455             :     uint8_t *bitmap;
     456             : 
     457          44 :     if (s->num_rects == 0 || !s->rects || s->rects[0]->w <= 0 || s->rects[0]->h <= 0)
     458           0 :         return 0;
     459             : 
     460         220 :     for(i = 0; i < s->rects[0]->nb_colors; i++) {
     461         176 :         if ((((uint32_t *)s->rects[0]->data[1])[i] >> 24) == 0)
     462          88 :             transp_color[i] = 1;
     463             :     }
     464          44 :     y1 = 0;
     465       32092 :     while (y1 < s->rects[0]->h && is_transp(s->rects[0]->data[0] + y1 * s->rects[0]->linesize[0],
     466       16024 :                                   1, s->rects[0]->w, transp_color))
     467       15980 :         y1++;
     468          44 :     if (y1 == s->rects[0]->h) {
     469           0 :         av_freep(&s->rects[0]->data[0]);
     470           0 :         s->rects[0]->w = s->rects[0]->h = 0;
     471           0 :         return 0;
     472             :     }
     473             : 
     474          44 :     y2 = s->rects[0]->h - 1;
     475        7032 :     while (y2 > 0 && is_transp(s->rects[0]->data[0] + y2 * s->rects[0]->linesize[0], 1,
     476        3494 :                                s->rects[0]->w, transp_color))
     477        3450 :         y2--;
     478          44 :     x1 = 0;
     479       19122 :     while (x1 < (s->rects[0]->w - 1) && is_transp(s->rects[0]->data[0] + x1, s->rects[0]->linesize[0],
     480        9539 :                                         s->rects[0]->h, transp_color))
     481        9495 :         x1++;
     482          44 :     x2 = s->rects[0]->w - 1;
     483        9651 :     while (x2 > 0 && is_transp(s->rects[0]->data[0] + x2, s->rects[0]->linesize[0], s->rects[0]->h,
     484             :                                   transp_color))
     485        9563 :         x2--;
     486          44 :     w = x2 - x1 + 1;
     487          44 :     h = y2 - y1 + 1;
     488          44 :     bitmap = av_malloc(w * h);
     489          44 :     if (!bitmap)
     490           0 :         return 1;
     491        1642 :     for(y = 0; y < h; y++) {
     492        1598 :         memcpy(bitmap + w * y, s->rects[0]->data[0] + x1 + (y1 + y) * s->rects[0]->linesize[0], w);
     493             :     }
     494          44 :     av_freep(&s->rects[0]->data[0]);
     495          44 :     s->rects[0]->data[0] = bitmap;
     496          44 :     s->rects[0]->linesize[0] = w;
     497          44 :     s->rects[0]->w = w;
     498          44 :     s->rects[0]->h = h;
     499          44 :     s->rects[0]->x += x1;
     500          44 :     s->rects[0]->y += y1;
     501             : 
     502             : #if FF_API_AVPICTURE
     503             : FF_DISABLE_DEPRECATION_WARNINGS
     504         220 :     for (i = 0; i < 4; i++) {
     505         176 :         s->rects[0]->pict.data[i] = s->rects[0]->data[i];
     506         176 :         s->rects[0]->pict.linesize[i] = s->rects[0]->linesize[i];
     507             :     }
     508             : FF_ENABLE_DEPRECATION_WARNINGS
     509             : #endif
     510             : 
     511          44 :     return 1;
     512             : }
     513             : 
     514             : #ifdef DEBUG
     515             : #define ALPHA_MIX(A,BACK,FORE) (((255-(A)) * (BACK) + (A) * (FORE)) / 255)
     516             : static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
     517             :                      uint32_t *rgba_palette)
     518             : {
     519             :     int x, y, alpha;
     520             :     uint32_t v;
     521             :     int back[3] = {0, 255, 0};  /* green background */
     522             :     FILE *f;
     523             : 
     524             :     f = fopen(filename, "w");
     525             :     if (!f) {
     526             :         perror(filename);
     527             :         return;
     528             :     }
     529             :     fprintf(f, "P6\n"
     530             :             "%d %d\n"
     531             :             "%d\n",
     532             :             w, h, 255);
     533             :     for(y = 0; y < h; y++) {
     534             :         for(x = 0; x < w; x++) {
     535             :             v = rgba_palette[bitmap[y * w + x]];
     536             :             alpha = v >> 24;
     537             :             putc(ALPHA_MIX(alpha, back[0], (v >> 16) & 0xff), f);
     538             :             putc(ALPHA_MIX(alpha, back[1], (v >> 8) & 0xff), f);
     539             :             putc(ALPHA_MIX(alpha, back[2], (v >> 0) & 0xff), f);
     540             :         }
     541             :     }
     542             :     fclose(f);
     543             : }
     544             : #endif
     545             : 
     546           6 : static int append_to_cached_buf(AVCodecContext *avctx,
     547             :                                 const uint8_t *buf, int buf_size)
     548             : {
     549           6 :     DVDSubContext *ctx = avctx->priv_data;
     550             : 
     551           6 :     av_assert0(buf_size >= 0 && ctx->buf_size <= sizeof(ctx->buf));
     552           6 :     if (buf_size >= sizeof(ctx->buf) - ctx->buf_size) {
     553           0 :         av_log(avctx, AV_LOG_WARNING, "Attempt to reconstruct "
     554             :                "too large SPU packets aborted.\n");
     555           0 :         ctx->buf_size = 0;
     556           0 :         return AVERROR_INVALIDDATA;
     557             :     }
     558           6 :     memcpy(ctx->buf + ctx->buf_size, buf, buf_size);
     559           6 :     ctx->buf_size += buf_size;
     560           6 :     return 0;
     561             : }
     562             : 
     563          47 : static int dvdsub_decode(AVCodecContext *avctx,
     564             :                          void *data, int *data_size,
     565             :                          AVPacket *avpkt)
     566             : {
     567          47 :     DVDSubContext *ctx = avctx->priv_data;
     568          47 :     const uint8_t *buf = avpkt->data;
     569          47 :     int buf_size = avpkt->size;
     570          47 :     AVSubtitle *sub = data;
     571          47 :     int appended = 0;
     572             :     int is_menu;
     573             : 
     574          47 :     if (ctx->buf_size) {
     575           3 :         int ret = append_to_cached_buf(avctx, buf, buf_size);
     576           3 :         if (ret < 0) {
     577           0 :             *data_size = 0;
     578           0 :             return ret;
     579             :         }
     580           3 :         buf = ctx->buf;
     581           3 :         buf_size = ctx->buf_size;
     582           3 :         appended = 1;
     583             :     }
     584             : 
     585          47 :     is_menu = decode_dvd_subtitles(ctx, sub, buf, buf_size);
     586          47 :     if (is_menu == AVERROR(EAGAIN)) {
     587           3 :         *data_size = 0;
     588           3 :         return appended ? 0 : append_to_cached_buf(avctx, buf, buf_size);
     589             :     }
     590             : 
     591          44 :     if (is_menu < 0) {
     592           0 :     no_subtitle:
     593           0 :         reset_rects(sub);
     594           0 :         *data_size = 0;
     595             : 
     596           0 :         return buf_size;
     597             :     }
     598          44 :     if (!is_menu && find_smallest_bounding_rectangle(sub) == 0)
     599           0 :         goto no_subtitle;
     600             : 
     601          44 :     if (ctx->forced_subs_only && !(sub->rects[0]->flags & AV_SUBTITLE_FLAG_FORCED))
     602           0 :         goto no_subtitle;
     603             : 
     604             : #if defined(DEBUG)
     605             :     {
     606             :     char ppm_name[32];
     607             : 
     608             :     snprintf(ppm_name, sizeof(ppm_name), "/tmp/%05d.ppm", ctx->sub_id++);
     609             :     ff_dlog(NULL, "start=%d ms end =%d ms\n",
     610             :             sub->start_display_time,
     611             :             sub->end_display_time);
     612             :     ppm_save(ppm_name, sub->rects[0]->data[0],
     613             :              sub->rects[0]->w, sub->rects[0]->h, (uint32_t*) sub->rects[0]->data[1]);
     614             :     }
     615             : #endif
     616             : 
     617          44 :     ctx->buf_size = 0;
     618          44 :     *data_size = 1;
     619          44 :     return buf_size;
     620             : }
     621             : 
     622           6 : static void parse_palette(DVDSubContext *ctx, char *p)
     623             : {
     624             :     int i;
     625             : 
     626           6 :     ctx->has_palette = 1;
     627         102 :     for(i=0;i<16;i++) {
     628          96 :         ctx->palette[i] = strtoul(p, &p, 16);
     629         378 :         while(*p == ',' || av_isspace(*p))
     630         186 :             p++;
     631             :     }
     632           6 : }
     633             : 
     634           0 : static int parse_ifo_palette(DVDSubContext *ctx, char *p)
     635             : {
     636             :     FILE *ifo;
     637             :     char ifostr[12];
     638             :     uint32_t sp_pgci, pgci, off_pgc, pgc;
     639             :     uint8_t r, g, b, yuv[65], *buf;
     640             :     int i, y, cb, cr, r_add, g_add, b_add;
     641           0 :     int ret = 0;
     642           0 :     const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
     643             : 
     644           0 :     ctx->has_palette = 0;
     645           0 :     if ((ifo = fopen(p, "r")) == NULL) {
     646           0 :         av_log(ctx, AV_LOG_WARNING, "Unable to open IFO file \"%s\": %s\n", p, av_err2str(AVERROR(errno)));
     647           0 :         return AVERROR_EOF;
     648             :     }
     649           0 :     if (fread(ifostr, 12, 1, ifo) != 1 || memcmp(ifostr, "DVDVIDEO-VTS", 12)) {
     650           0 :         av_log(ctx, AV_LOG_WARNING, "\"%s\" is not a proper IFO file\n", p);
     651           0 :         ret = AVERROR_INVALIDDATA;
     652           0 :         goto end;
     653             :     }
     654           0 :     if (fseek(ifo, 0xCC, SEEK_SET) == -1) {
     655           0 :         ret = AVERROR(errno);
     656           0 :         goto end;
     657             :     }
     658           0 :     if (fread(&sp_pgci, 4, 1, ifo) == 1) {
     659           0 :         pgci = av_be2ne32(sp_pgci) * 2048;
     660           0 :         if (fseek(ifo, pgci + 0x0C, SEEK_SET) == -1) {
     661           0 :             ret = AVERROR(errno);
     662           0 :             goto end;
     663             :         }
     664           0 :         if (fread(&off_pgc, 4, 1, ifo) == 1) {
     665           0 :             pgc = pgci + av_be2ne32(off_pgc);
     666           0 :             if (fseek(ifo, pgc + 0xA4, SEEK_SET) == -1) {
     667           0 :                 ret = AVERROR(errno);
     668           0 :                 goto end;
     669             :             }
     670           0 :             if (fread(yuv, 64, 1, ifo) == 1) {
     671           0 :                 buf = yuv;
     672           0 :                 for(i=0; i<16; i++) {
     673           0 :                     y  = *++buf;
     674           0 :                     cr = *++buf;
     675           0 :                     cb = *++buf;
     676           0 :                     YUV_TO_RGB1_CCIR(cb, cr);
     677           0 :                     YUV_TO_RGB2_CCIR(r, g, b, y);
     678           0 :                     ctx->palette[i] = (r << 16) + (g << 8) + b;
     679           0 :                     buf++;
     680             :                 }
     681           0 :                 ctx->has_palette = 1;
     682             :             }
     683             :         }
     684             :     }
     685           0 :     if (ctx->has_palette == 0) {
     686           0 :         av_log(ctx, AV_LOG_WARNING, "Failed to read palette from IFO file \"%s\"\n", p);
     687           0 :         ret = AVERROR_INVALIDDATA;
     688             :     }
     689           0 : end:
     690           0 :     fclose(ifo);
     691           0 :     return ret;
     692             : }
     693             : 
     694           8 : static int dvdsub_parse_extradata(AVCodecContext *avctx)
     695             : {
     696           8 :     DVDSubContext *ctx = (DVDSubContext*) avctx->priv_data;
     697             :     char *dataorig, *data;
     698           8 :     int ret = 1;
     699             : 
     700           8 :     if (!avctx->extradata || !avctx->extradata_size)
     701           2 :         return 1;
     702             : 
     703           6 :     dataorig = data = av_malloc(avctx->extradata_size+1);
     704           6 :     if (!data)
     705           0 :         return AVERROR(ENOMEM);
     706           6 :     memcpy(data, avctx->extradata, avctx->extradata_size);
     707           6 :     data[avctx->extradata_size] = '\0';
     708             : 
     709          50 :     for(;;) {
     710          56 :         int pos = strcspn(data, "\n\r");
     711          56 :         if (pos==0 && *data==0)
     712           6 :             break;
     713             : 
     714          50 :         if (strncmp("palette:", data, 8) == 0) {
     715           6 :             parse_palette(ctx, data + 8);
     716          44 :         } else if (strncmp("size:", data, 5) == 0) {
     717             :             int w, h;
     718           6 :             if (sscanf(data + 5, "%dx%d", &w, &h) == 2) {
     719           6 :                ret = ff_set_dimensions(avctx, w, h);
     720           6 :                if (ret < 0)
     721           0 :                    goto fail;
     722             :             }
     723             :         }
     724             : 
     725          50 :         data += pos;
     726          50 :         data += strspn(data, "\n\r");
     727             :     }
     728             : 
     729           6 : fail:
     730           6 :     av_free(dataorig);
     731           6 :     return ret;
     732             : }
     733             : 
     734           8 : static av_cold int dvdsub_init(AVCodecContext *avctx)
     735             : {
     736           8 :     DVDSubContext *ctx = avctx->priv_data;
     737             :     int ret;
     738             : 
     739           8 :     if ((ret = dvdsub_parse_extradata(avctx)) < 0)
     740           0 :         return ret;
     741             : 
     742           8 :     if (ctx->ifo_str)
     743           0 :         parse_ifo_palette(ctx, ctx->ifo_str);
     744           8 :     if (ctx->palette_str)
     745           0 :         parse_palette(ctx, ctx->palette_str);
     746           8 :     if (ctx->has_palette) {
     747             :         int i;
     748           6 :         av_log(avctx, AV_LOG_DEBUG, "palette:");
     749         102 :         for(i=0;i<16;i++)
     750          96 :             av_log(avctx, AV_LOG_DEBUG, " 0x%06"PRIx32, ctx->palette[i]);
     751           6 :         av_log(avctx, AV_LOG_DEBUG, "\n");
     752             :     }
     753             : 
     754           8 :     return 1;
     755             : }
     756             : 
     757           8 : static void dvdsub_flush(AVCodecContext *avctx)
     758             : {
     759           8 :     DVDSubContext *ctx = avctx->priv_data;
     760           8 :     ctx->buf_size = 0;
     761           8 : }
     762             : 
     763           8 : static av_cold int dvdsub_close(AVCodecContext *avctx)
     764             : {
     765           8 :     dvdsub_flush(avctx);
     766           8 :     return 0;
     767             : }
     768             : 
     769             : #define OFFSET(field) offsetof(DVDSubContext, field)
     770             : #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
     771             : static const AVOption options[] = {
     772             :     { "palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
     773             :     { "ifo_palette", "obtain the global palette from .IFO file", OFFSET(ifo_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
     774             :     { "forced_subs_only", "Only show forced subtitles", OFFSET(forced_subs_only), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, SD},
     775             :     { NULL }
     776             : };
     777             : static const AVClass dvdsub_class = {
     778             :     .class_name = "dvdsubdec",
     779             :     .item_name  = av_default_item_name,
     780             :     .option     = options,
     781             :     .version    = LIBAVUTIL_VERSION_INT,
     782             : };
     783             : 
     784             : AVCodec ff_dvdsub_decoder = {
     785             :     .name           = "dvdsub",
     786             :     .long_name      = NULL_IF_CONFIG_SMALL("DVD subtitles"),
     787             :     .type           = AVMEDIA_TYPE_SUBTITLE,
     788             :     .id             = AV_CODEC_ID_DVD_SUBTITLE,
     789             :     .priv_data_size = sizeof(DVDSubContext),
     790             :     .init           = dvdsub_init,
     791             :     .decode         = dvdsub_decode,
     792             :     .flush          = dvdsub_flush,
     793             :     .close          = dvdsub_close,
     794             :     .priv_class     = &dvdsub_class,
     795             : };

Generated by: LCOV version 1.13