/src/ffmpeg/libavcodec/dvdsubdec.c
Line | Count | Source |
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 "codec_internal.h" |
24 | | #include "decode.h" |
25 | | #include "dvdsub.h" |
26 | | #include "get_bits.h" |
27 | | |
28 | | #include "libavutil/attributes.h" |
29 | | #include "libavutil/colorspace.h" |
30 | | #include "libavutil/file_open.h" |
31 | | #include "libavutil/mem.h" |
32 | | #include "libavutil/opt.h" |
33 | | #include "libavutil/bswap.h" |
34 | | |
35 | | typedef struct DVDSubContext |
36 | | { |
37 | | AVClass *class; |
38 | | uint32_t palette[16]; |
39 | | char *palette_str; |
40 | | char *ifo_str; |
41 | | int has_palette; |
42 | | uint8_t colormap[4]; |
43 | | uint8_t alpha[256]; |
44 | | uint8_t buf[0x10000]; |
45 | | int buf_size; |
46 | | int forced_subs_only; |
47 | | uint8_t used_color[256]; |
48 | | } DVDSubContext; |
49 | | |
50 | | static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values) |
51 | 3.76k | { |
52 | 3.76k | const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; |
53 | 3.76k | uint8_t r, g, b; |
54 | 3.76k | int i, y, cb, cr; |
55 | 3.76k | int r_add, g_add, b_add; |
56 | | |
57 | 968k | for (i = num_values; i > 0; i--) { |
58 | 964k | y = *ycbcr++; |
59 | 964k | cr = *ycbcr++; |
60 | 964k | cb = *ycbcr++; |
61 | 964k | YUV_TO_RGB1_CCIR(cb, cr); |
62 | 964k | YUV_TO_RGB2_CCIR(r, g, b, y); |
63 | 964k | *rgba++ = ((unsigned)*alpha++ << 24) | (r << 16) | (g << 8) | b; |
64 | 964k | } |
65 | 3.76k | } |
66 | | |
67 | | static int decode_run_2bit(GetBitContext *gb, int *color) |
68 | 1.19M | { |
69 | 1.19M | unsigned int v, t; |
70 | | |
71 | 1.19M | v = 0; |
72 | 3.34M | for (t = 1; v < t && t <= 0x40; t <<= 2) |
73 | 2.14M | v = (v << 4) | get_bits(gb, 4); |
74 | 1.19M | *color = v & 3; |
75 | 1.19M | if (v < 4) { /* Code for fill rest of line */ |
76 | 165k | return INT_MAX; |
77 | 165k | } |
78 | 1.03M | return v >> 2; |
79 | 1.19M | } |
80 | | |
81 | | static int decode_run_8bit(GetBitContext *gb, int *color) |
82 | 10.4M | { |
83 | 10.4M | int len; |
84 | 10.4M | int has_run = get_bits1(gb); |
85 | 10.4M | *color = get_bits(gb, 2 + 6*get_bits1(gb)); |
86 | 10.4M | if (has_run) { |
87 | 1.95M | if (get_bits1(gb)) { |
88 | 236k | len = get_bits(gb, 7); |
89 | 236k | if (len == 0) |
90 | 49.5k | len = INT_MAX; |
91 | 186k | else |
92 | 186k | len += 9; |
93 | 236k | } else |
94 | 1.71M | len = get_bits(gb, 3) + 2; |
95 | 1.95M | } else |
96 | 8.52M | len = 1; |
97 | 10.4M | return len; |
98 | 10.4M | } |
99 | | |
100 | | static int decode_rle(uint8_t *bitmap, int linesize, int w, int h, uint8_t used_color[256], |
101 | | const uint8_t *buf, int start, int buf_size, int is_8bit) |
102 | 20.8k | { |
103 | 20.8k | GetBitContext gb; |
104 | 20.8k | int bit_len; |
105 | 20.8k | int x, y, len, color; |
106 | 20.8k | uint8_t *d; |
107 | | |
108 | 20.8k | if (start >= buf_size) |
109 | 0 | return -1; |
110 | | |
111 | 20.8k | if (w <= 0 || h <= 0) |
112 | 0 | return -1; |
113 | | |
114 | 20.8k | bit_len = (buf_size - start) * 8; |
115 | 20.8k | init_get_bits(&gb, buf + start, bit_len); |
116 | | |
117 | 20.8k | x = 0; |
118 | 20.8k | y = 0; |
119 | 20.8k | d = bitmap; |
120 | 11.6M | for(;;) { |
121 | 11.6M | if (get_bits_count(&gb) > bit_len) |
122 | 823 | return -1; |
123 | 11.6M | if (is_8bit) |
124 | 10.4M | len = decode_run_8bit(&gb, &color); |
125 | 1.19M | else |
126 | 1.19M | len = decode_run_2bit(&gb, &color); |
127 | 11.6M | if (len != INT_MAX && len > w - x) |
128 | 440 | return AVERROR_INVALIDDATA; |
129 | 11.6M | len = FFMIN(len, w - x); |
130 | 11.6M | memset(d + x, color, len); |
131 | 11.6M | used_color[color] = 1; |
132 | 11.6M | x += len; |
133 | 11.6M | if (x >= w) { |
134 | 217k | y++; |
135 | 217k | if (y >= h) |
136 | 19.6k | break; |
137 | 197k | d += linesize; |
138 | 197k | x = 0; |
139 | | /* byte align */ |
140 | 197k | align_get_bits(&gb); |
141 | 197k | } |
142 | 11.6M | } |
143 | 19.6k | return 0; |
144 | 20.8k | } |
145 | | |
146 | | static void guess_palette(DVDSubContext* ctx, |
147 | | uint32_t *rgba_palette, |
148 | | uint32_t subtitle_color) |
149 | 5.64k | { |
150 | 5.64k | 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 | 5.64k | {0xff}, |
154 | 5.64k | {0x00, 0xff}, |
155 | 5.64k | {0x00, 0x80, 0xff}, |
156 | 5.64k | {0x00, 0x55, 0xaa, 0xff}, |
157 | 5.64k | }; |
158 | 5.64k | uint8_t color_used[16] = { 0 }; |
159 | 5.64k | int nb_opaque_colors, i, level, j, r, g, b; |
160 | 5.64k | uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha; |
161 | | |
162 | 5.64k | if(ctx->has_palette) { |
163 | 3.10k | for(i = 0; i < 4; i++) |
164 | 2.48k | rgba_palette[i] = (ctx->palette[colormap[i]] & 0x00ffffff) |
165 | 2.48k | | ((alpha[i] * 17U) << 24); |
166 | 621 | return; |
167 | 621 | } |
168 | | |
169 | 25.1k | for(i = 0; i < 4; i++) |
170 | 20.0k | rgba_palette[i] = 0; |
171 | | |
172 | 5.02k | nb_opaque_colors = 0; |
173 | 25.1k | for(i = 0; i < 4; i++) { |
174 | 20.0k | if (alpha[i] != 0 && !color_used[colormap[i]]) { |
175 | 3.69k | color_used[colormap[i]] = 1; |
176 | 3.69k | nb_opaque_colors++; |
177 | 3.69k | } |
178 | 20.0k | } |
179 | | |
180 | 5.02k | if (nb_opaque_colors == 0) |
181 | 2.84k | return; |
182 | | |
183 | 2.17k | j = 0; |
184 | 2.17k | memset(color_used, 0, 16); |
185 | 10.8k | for(i = 0; i < 4; i++) { |
186 | 8.70k | if (alpha[i] != 0) { |
187 | 5.35k | if (!color_used[colormap[i]]) { |
188 | 3.69k | level = level_map[nb_opaque_colors - 1][j]; |
189 | 3.69k | r = (((subtitle_color >> 16) & 0xff) * level) >> 8; |
190 | 3.69k | g = (((subtitle_color >> 8) & 0xff) * level) >> 8; |
191 | 3.69k | b = (((subtitle_color >> 0) & 0xff) * level) >> 8; |
192 | 3.69k | rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17U) << 24); |
193 | 3.69k | color_used[colormap[i]] = (i + 1); |
194 | 3.69k | j++; |
195 | 3.69k | } else { |
196 | 1.65k | rgba_palette[i] = (rgba_palette[color_used[colormap[i]] - 1] & 0x00ffffff) | |
197 | 1.65k | ((alpha[i] * 17U) << 24); |
198 | 1.65k | } |
199 | 5.35k | } |
200 | 8.70k | } |
201 | 2.17k | } |
202 | | |
203 | | static void reset_rects(AVSubtitle *sub_header) |
204 | 88.6k | { |
205 | 88.6k | int i; |
206 | | |
207 | 88.6k | if (sub_header->rects) { |
208 | 18.4k | for (i = 0; i < sub_header->num_rects; i++) { |
209 | 9.24k | av_freep(&sub_header->rects[i]->data[0]); |
210 | 9.24k | av_freep(&sub_header->rects[i]->data[1]); |
211 | 9.24k | av_freep(&sub_header->rects[i]); |
212 | 9.24k | } |
213 | 9.24k | av_freep(&sub_header->rects); |
214 | 9.24k | sub_header->num_rects = 0; |
215 | 9.24k | } |
216 | 88.6k | } |
217 | | |
218 | 64.1k | #define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a)) |
219 | | |
220 | | static int decode_dvd_subtitles(void *logctx, DVDSubContext *ctx, |
221 | | AVSubtitle *sub_header, const uint8_t *buf, int buf_size) |
222 | 82.4k | { |
223 | 82.4k | int cmd_pos, pos, cmd, x1, y1, x2, y2, next_cmd_pos; |
224 | 82.4k | int big_offsets, offset_size, is_8bit = 0; |
225 | 82.4k | const uint8_t *yuv_palette = NULL; |
226 | 82.4k | uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha; |
227 | 82.4k | int date; |
228 | 82.4k | int i; |
229 | 82.4k | int is_menu = 0; |
230 | 82.4k | uint32_t size; |
231 | 82.4k | int64_t offset1, offset2; |
232 | | |
233 | 82.4k | if (buf_size < 10) |
234 | 58.4k | return -1; |
235 | | |
236 | 24.0k | if (AV_RB16(buf) == 0) { /* HD subpicture with 4-byte offsets */ |
237 | 8.80k | big_offsets = 1; |
238 | 8.80k | offset_size = 4; |
239 | 8.80k | cmd_pos = 6; |
240 | 15.2k | } else { |
241 | 15.2k | big_offsets = 0; |
242 | 15.2k | offset_size = 2; |
243 | 15.2k | cmd_pos = 2; |
244 | 15.2k | } |
245 | | |
246 | 24.0k | size = READ_OFFSET(buf + (big_offsets ? 2 : 0)); |
247 | 24.0k | cmd_pos = READ_OFFSET(buf + cmd_pos); |
248 | | |
249 | 24.0k | if (cmd_pos < 0 || cmd_pos > buf_size - 2 - offset_size) { |
250 | 9.55k | if (cmd_pos > size) { |
251 | 1.07k | av_log(logctx, AV_LOG_ERROR, "Discarding invalid packet\n"); |
252 | 1.07k | return 0; |
253 | 1.07k | } |
254 | 8.47k | return AVERROR(EAGAIN); |
255 | 9.55k | } |
256 | | |
257 | 24.7k | while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) { |
258 | 16.1k | date = AV_RB16(buf + cmd_pos); |
259 | 16.1k | next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2); |
260 | 16.1k | ff_dlog(logctx, "cmd_pos=0x%04x next=0x%04x date=%d\n", |
261 | 16.1k | cmd_pos, next_cmd_pos, date); |
262 | 16.1k | pos = cmd_pos + 2 + offset_size; |
263 | 16.1k | offset1 = -1; |
264 | 16.1k | offset2 = -1; |
265 | 16.1k | x1 = y1 = x2 = y2 = 0; |
266 | 111k | while (pos < buf_size) { |
267 | 109k | cmd = buf[pos++]; |
268 | 109k | ff_dlog(logctx, "cmd=%02x\n", cmd); |
269 | 109k | switch(cmd) { |
270 | 36.6k | case 0x00: |
271 | | /* menu subpicture */ |
272 | 36.6k | is_menu = 1; |
273 | 36.6k | break; |
274 | 6.83k | case 0x01: |
275 | | /* set start date */ |
276 | 6.83k | sub_header->start_display_time = (date << 10) / 90; |
277 | 6.83k | break; |
278 | 5.27k | case 0x02: |
279 | | /* set end date */ |
280 | 5.27k | sub_header->end_display_time = (date << 10) / 90; |
281 | 5.27k | break; |
282 | 2.17k | case 0x03: |
283 | | /* set colormap */ |
284 | 2.17k | if ((buf_size - pos) < 2) |
285 | 201 | goto fail; |
286 | 1.97k | colormap[3] = buf[pos] >> 4; |
287 | 1.97k | colormap[2] = buf[pos] & 0x0f; |
288 | 1.97k | colormap[1] = buf[pos + 1] >> 4; |
289 | 1.97k | colormap[0] = buf[pos + 1] & 0x0f; |
290 | 1.97k | pos += 2; |
291 | 1.97k | break; |
292 | 2.84k | case 0x04: |
293 | | /* set alpha */ |
294 | 2.84k | if ((buf_size - pos) < 2) |
295 | 196 | goto fail; |
296 | 2.64k | alpha[3] = buf[pos] >> 4; |
297 | 2.64k | alpha[2] = buf[pos] & 0x0f; |
298 | 2.64k | alpha[1] = buf[pos + 1] >> 4; |
299 | 2.64k | alpha[0] = buf[pos + 1] & 0x0f; |
300 | 2.64k | pos += 2; |
301 | 2.64k | ff_dlog(logctx, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]); |
302 | 2.64k | break; |
303 | 12.5k | case 0x05: |
304 | 17.4k | case 0x85: |
305 | 17.4k | if ((buf_size - pos) < 6) |
306 | 221 | goto fail; |
307 | 17.1k | x1 = (buf[pos] << 4) | (buf[pos + 1] >> 4); |
308 | 17.1k | x2 = ((buf[pos + 1] & 0x0f) << 8) | buf[pos + 2]; |
309 | 17.1k | y1 = (buf[pos + 3] << 4) | (buf[pos + 4] >> 4); |
310 | 17.1k | y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5]; |
311 | 17.1k | if (cmd & 0x80) |
312 | 4.81k | is_8bit = 1; |
313 | 17.1k | ff_dlog(logctx, "x1=%d x2=%d y1=%d y2=%d\n", x1, x2, y1, y2); |
314 | 17.1k | pos += 6; |
315 | 17.1k | break; |
316 | 15.4k | case 0x06: |
317 | 15.4k | if ((buf_size - pos) < 4) |
318 | 200 | goto fail; |
319 | 15.2k | offset1 = AV_RB16(buf + pos); |
320 | 15.2k | offset2 = AV_RB16(buf + pos + 2); |
321 | 15.2k | ff_dlog(logctx, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2); |
322 | 15.2k | pos += 4; |
323 | 15.2k | break; |
324 | 4.11k | case 0x86: |
325 | 4.11k | if ((buf_size - pos) < 8) |
326 | 198 | goto fail; |
327 | 3.91k | offset1 = AV_RB32(buf + pos); |
328 | 3.91k | offset2 = AV_RB32(buf + pos + 4); |
329 | 3.91k | ff_dlog(logctx, "offset1=0x%04"PRIx64" offset2=0x%04"PRIx64"\n", offset1, offset2); |
330 | 3.91k | pos += 8; |
331 | 3.91k | break; |
332 | | |
333 | 4.01k | case 0x83: |
334 | | /* HD set palette */ |
335 | 4.01k | if ((buf_size - pos) < 768) |
336 | 220 | goto fail; |
337 | 3.79k | yuv_palette = buf + pos; |
338 | 3.79k | pos += 768; |
339 | 3.79k | break; |
340 | 2.34k | case 0x84: |
341 | | /* HD set contrast (alpha) */ |
342 | 2.34k | if ((buf_size - pos) < 256) |
343 | 202 | goto fail; |
344 | 549k | for (i = 0; i < 256; i++) |
345 | 547k | alpha[i] = 0xFF - buf[pos+i]; |
346 | 2.14k | pos += 256; |
347 | 2.14k | break; |
348 | | |
349 | 949 | case 0xff: |
350 | 949 | goto the_end; |
351 | 11.0k | default: |
352 | 11.0k | ff_dlog(logctx, "unrecognised subpicture command 0x%x\n", cmd); |
353 | 11.0k | goto the_end; |
354 | 109k | } |
355 | 109k | } |
356 | 14.6k | the_end: |
357 | 14.6k | if (offset1 >= buf_size || offset2 >= buf_size) |
358 | 565 | goto fail; |
359 | | |
360 | 14.1k | if (offset1 >= 0 && offset2 >= 0) { |
361 | 11.7k | int w, h; |
362 | 11.7k | uint8_t *bitmap; |
363 | | |
364 | | /* decode the bitmap */ |
365 | 11.7k | w = x2 - x1 + 1; |
366 | 11.7k | if (w < 0) |
367 | 253 | w = 0; |
368 | 11.7k | h = y2 - y1 + 1; |
369 | 11.7k | if (h < 0) |
370 | 371 | h = 0; |
371 | 11.7k | if (w > 0 && h > 1) { |
372 | 10.9k | reset_rects(sub_header); |
373 | 10.9k | memset(ctx->used_color, 0, sizeof(ctx->used_color)); |
374 | 10.9k | sub_header->rects = av_mallocz(sizeof(*sub_header->rects)); |
375 | 10.9k | if (!sub_header->rects) |
376 | 0 | goto fail; |
377 | 10.9k | sub_header->rects[0] = av_mallocz(sizeof(AVSubtitleRect)); |
378 | 10.9k | if (!sub_header->rects[0]) |
379 | 0 | goto fail; |
380 | 10.9k | sub_header->num_rects = 1; |
381 | 10.9k | bitmap = sub_header->rects[0]->data[0] = av_malloc(w * h); |
382 | 10.9k | if (!bitmap) |
383 | 0 | goto fail; |
384 | 10.9k | if (decode_rle(bitmap, w * 2, w, (h + 1) / 2, ctx->used_color, |
385 | 10.9k | buf, offset1, buf_size, is_8bit) < 0) |
386 | 913 | goto fail; |
387 | 9.98k | if (decode_rle(bitmap + w, w * 2, w, h / 2, ctx->used_color, |
388 | 9.98k | buf, offset2, buf_size, is_8bit) < 0) |
389 | 350 | goto fail; |
390 | 9.63k | sub_header->rects[0]->data[1] = av_mallocz(AVPALETTE_SIZE); |
391 | 9.63k | if (!sub_header->rects[0]->data[1]) |
392 | 0 | goto fail; |
393 | 9.63k | if (is_8bit) { |
394 | 3.99k | if (!yuv_palette) |
395 | 227 | goto fail; |
396 | 3.76k | sub_header->rects[0]->nb_colors = 256; |
397 | 3.76k | yuv_a_to_rgba(yuv_palette, alpha, |
398 | 3.76k | (uint32_t *)sub_header->rects[0]->data[1], |
399 | 3.76k | 256); |
400 | 5.64k | } else { |
401 | 5.64k | sub_header->rects[0]->nb_colors = 4; |
402 | 5.64k | guess_palette(ctx, (uint32_t*)sub_header->rects[0]->data[1], |
403 | 5.64k | 0xffffff); |
404 | 5.64k | } |
405 | 9.41k | sub_header->rects[0]->x = x1; |
406 | 9.41k | sub_header->rects[0]->y = y1; |
407 | 9.41k | sub_header->rects[0]->w = w; |
408 | 9.41k | sub_header->rects[0]->h = h; |
409 | 9.41k | sub_header->rects[0]->type = SUBTITLE_BITMAP; |
410 | 9.41k | sub_header->rects[0]->linesize[0] = w; |
411 | 9.41k | sub_header->rects[0]->flags = is_menu ? AV_SUBTITLE_FLAG_FORCED : 0; |
412 | 9.41k | } |
413 | 11.7k | } |
414 | 12.6k | if (next_cmd_pos < cmd_pos) { |
415 | 2.08k | av_log(logctx, AV_LOG_ERROR, "Invalid command offset\n"); |
416 | 2.08k | break; |
417 | 2.08k | } |
418 | 10.5k | if (next_cmd_pos == cmd_pos) |
419 | 214 | break; |
420 | 10.3k | cmd_pos = next_cmd_pos; |
421 | 10.3k | } |
422 | 10.9k | if (sub_header->num_rects > 0) |
423 | 9.10k | return is_menu; |
424 | 5.37k | fail: |
425 | 5.37k | reset_rects(sub_header); |
426 | 5.37k | return -1; |
427 | 10.9k | } |
428 | | |
429 | | static int is_transp(const uint8_t *buf, int pitch, int n, |
430 | | const uint8_t *transp_color) |
431 | 587k | { |
432 | 587k | int i; |
433 | 37.2M | for(i = 0; i < n; i++) { |
434 | 36.6M | if (!transp_color[*buf]) |
435 | 3.36k | return 0; |
436 | 36.6M | buf += pitch; |
437 | 36.6M | } |
438 | 584k | return 1; |
439 | 587k | } |
440 | | |
441 | | /* return 0 if empty rectangle, 1 if non empty */ |
442 | | static int find_smallest_bounding_rectangle(DVDSubContext *ctx, AVSubtitle *s) |
443 | 9.67k | { |
444 | 9.67k | uint8_t transp_color[256] = { 0 }; |
445 | 9.67k | int y1, y2, x1, x2, y, w, h, i; |
446 | 9.67k | uint8_t *bitmap; |
447 | 9.67k | int transparent = 1; |
448 | | |
449 | 9.67k | if (s->num_rects == 0 || !s->rects || s->rects[0]->w <= 0 || s->rects[0]->h <= 0) |
450 | 1.07k | return 0; |
451 | | |
452 | 989k | for(i = 0; i < s->rects[0]->nb_colors; i++) { |
453 | 980k | if ((((uint32_t *)s->rects[0]->data[1])[i] >> 24) == 0) { |
454 | 976k | transp_color[i] = 1; |
455 | 976k | } else if (ctx->used_color[i]) |
456 | 2.04k | transparent = 0; |
457 | 980k | } |
458 | 8.60k | if (transparent) |
459 | 7.44k | return 0; |
460 | 1.15k | y1 = 0; |
461 | 4.51k | while (y1 < s->rects[0]->h && is_transp(s->rects[0]->data[0] + y1 * s->rects[0]->linesize[0], |
462 | 4.51k | 1, s->rects[0]->w, transp_color)) |
463 | 3.35k | y1++; |
464 | 1.15k | if (y1 == s->rects[0]->h) { |
465 | 0 | av_freep(&s->rects[0]->data[0]); |
466 | 0 | s->rects[0]->w = s->rects[0]->h = 0; |
467 | 0 | return 0; |
468 | 0 | } |
469 | | |
470 | 1.15k | y2 = s->rects[0]->h - 1; |
471 | 3.19k | while (y2 > 0 && is_transp(s->rects[0]->data[0] + y2 * s->rects[0]->linesize[0], 1, |
472 | 2.79k | s->rects[0]->w, transp_color)) |
473 | 2.04k | y2--; |
474 | 1.15k | x1 = 0; |
475 | 2.32k | while (x1 < (s->rects[0]->w - 1) && is_transp(s->rects[0]->data[0] + x1, s->rects[0]->linesize[0], |
476 | 1.95k | s->rects[0]->h, transp_color)) |
477 | 1.16k | x1++; |
478 | 1.15k | x2 = s->rects[0]->w - 1; |
479 | 578k | while (x2 > 0 && is_transp(s->rects[0]->data[0] + x2, s->rects[0]->linesize[0], s->rects[0]->h, |
480 | 578k | transp_color)) |
481 | 577k | x2--; |
482 | 1.15k | w = x2 - x1 + 1; |
483 | 1.15k | h = y2 - y1 + 1; |
484 | 1.15k | bitmap = av_malloc(w * h); |
485 | 1.15k | if (!bitmap) |
486 | 0 | return 1; |
487 | 28.3k | for(y = 0; y < h; y++) { |
488 | 27.1k | memcpy(bitmap + w * y, s->rects[0]->data[0] + x1 + (y1 + y) * s->rects[0]->linesize[0], w); |
489 | 27.1k | } |
490 | 1.15k | av_freep(&s->rects[0]->data[0]); |
491 | 1.15k | s->rects[0]->data[0] = bitmap; |
492 | 1.15k | s->rects[0]->linesize[0] = w; |
493 | 1.15k | s->rects[0]->w = w; |
494 | 1.15k | s->rects[0]->h = h; |
495 | 1.15k | s->rects[0]->x += x1; |
496 | 1.15k | s->rects[0]->y += y1; |
497 | | |
498 | 1.15k | return 1; |
499 | 1.15k | } |
500 | | |
501 | | static int append_to_cached_buf(AVCodecContext *avctx, |
502 | | const uint8_t *buf, int buf_size) |
503 | 16.2k | { |
504 | 16.2k | DVDSubContext *ctx = avctx->priv_data; |
505 | | |
506 | 16.2k | av_assert0(buf_size >= 0 && ctx->buf_size <= sizeof(ctx->buf)); |
507 | 16.2k | if (buf_size >= sizeof(ctx->buf) - ctx->buf_size) { |
508 | 66 | av_log(avctx, AV_LOG_WARNING, "Attempt to reconstruct " |
509 | 66 | "too large SPU packets aborted.\n"); |
510 | 66 | ctx->buf_size = 0; |
511 | 66 | return AVERROR_INVALIDDATA; |
512 | 66 | } |
513 | 16.1k | memcpy(ctx->buf + ctx->buf_size, buf, buf_size); |
514 | 16.1k | ctx->buf_size += buf_size; |
515 | 16.1k | return 0; |
516 | 16.2k | } |
517 | | |
518 | | static int dvdsub_decode(AVCodecContext *avctx, AVSubtitle *sub, |
519 | | int *data_size, const AVPacket *avpkt) |
520 | 82.5k | { |
521 | 82.5k | DVDSubContext *ctx = avctx->priv_data; |
522 | 82.5k | const uint8_t *buf = avpkt->data; |
523 | 82.5k | int buf_size = avpkt->size; |
524 | 82.5k | int appended = 0; |
525 | 82.5k | int is_menu; |
526 | | |
527 | 82.5k | if (ctx->buf_size) { |
528 | 14.8k | int ret = append_to_cached_buf(avctx, buf, buf_size); |
529 | 14.8k | if (ret < 0) { |
530 | 35 | *data_size = 0; |
531 | 35 | return ret; |
532 | 35 | } |
533 | 14.8k | buf = ctx->buf; |
534 | 14.8k | buf_size = ctx->buf_size; |
535 | 14.8k | appended = 1; |
536 | 14.8k | } |
537 | | |
538 | 82.4k | is_menu = decode_dvd_subtitles(avctx, ctx, sub, buf, buf_size); |
539 | 82.4k | if (is_menu == AVERROR(EAGAIN)) { |
540 | 8.47k | *data_size = 0; |
541 | 8.47k | return appended ? 0 : append_to_cached_buf(avctx, buf, buf_size); |
542 | 8.47k | } |
543 | | |
544 | 73.9k | if (is_menu < 0) { |
545 | 63.8k | ctx->buf_size = 0; |
546 | 72.3k | no_subtitle: |
547 | 72.3k | reset_rects(sub); |
548 | 72.3k | *data_size = 0; |
549 | | |
550 | 72.3k | return buf_size; |
551 | 63.8k | } |
552 | 10.1k | if (!is_menu && find_smallest_bounding_rectangle(ctx, sub) == 0) |
553 | 8.51k | goto no_subtitle; |
554 | | |
555 | 1.65k | if (ctx->forced_subs_only && !(sub->rects[0]->flags & AV_SUBTITLE_FLAG_FORCED)) |
556 | 0 | goto no_subtitle; |
557 | | |
558 | 1.65k | ctx->buf_size = 0; |
559 | 1.65k | *data_size = 1; |
560 | 1.65k | return buf_size; |
561 | 1.65k | } |
562 | | |
563 | | static int parse_ifo_palette(void *logctx, DVDSubContext *ctx, char *p) |
564 | 0 | { |
565 | 0 | FILE *ifo; |
566 | 0 | char ifostr[12]; |
567 | 0 | uint32_t sp_pgci, pgci, off_pgc, pgc; |
568 | 0 | uint8_t r, g, b, yuv[65], *buf; |
569 | 0 | int i, y, cb, cr, r_add, g_add, b_add; |
570 | 0 | int ret = 0; |
571 | 0 | const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; |
572 | |
|
573 | 0 | ctx->has_palette = 0; |
574 | 0 | if ((ifo = avpriv_fopen_utf8(p, "r")) == NULL) { |
575 | 0 | av_log(logctx, AV_LOG_WARNING, "Unable to open IFO file \"%s\": %s\n", p, av_err2str(AVERROR(errno))); |
576 | 0 | return AVERROR_EOF; |
577 | 0 | } |
578 | 0 | if (fread(ifostr, 12, 1, ifo) != 1 || memcmp(ifostr, "DVDVIDEO-VTS", 12)) { |
579 | 0 | av_log(logctx, AV_LOG_WARNING, "\"%s\" is not a proper IFO file\n", p); |
580 | 0 | ret = AVERROR_INVALIDDATA; |
581 | 0 | goto end; |
582 | 0 | } |
583 | 0 | if (fseek(ifo, 0xCC, SEEK_SET) == -1) { |
584 | 0 | ret = AVERROR(errno); |
585 | 0 | goto end; |
586 | 0 | } |
587 | 0 | if (fread(&sp_pgci, 4, 1, ifo) == 1) { |
588 | 0 | pgci = av_be2ne32(sp_pgci) * 2048; |
589 | 0 | if (fseek(ifo, pgci + 0x0C, SEEK_SET) == -1) { |
590 | 0 | ret = AVERROR(errno); |
591 | 0 | goto end; |
592 | 0 | } |
593 | 0 | if (fread(&off_pgc, 4, 1, ifo) == 1) { |
594 | 0 | pgc = pgci + av_be2ne32(off_pgc); |
595 | 0 | if (fseek(ifo, pgc + 0xA4, SEEK_SET) == -1) { |
596 | 0 | ret = AVERROR(errno); |
597 | 0 | goto end; |
598 | 0 | } |
599 | 0 | if (fread(yuv, 64, 1, ifo) == 1) { |
600 | 0 | buf = yuv; |
601 | 0 | for(i=0; i<16; i++) { |
602 | 0 | y = *++buf; |
603 | 0 | cr = *++buf; |
604 | 0 | cb = *++buf; |
605 | 0 | YUV_TO_RGB1_CCIR(cb, cr); |
606 | 0 | YUV_TO_RGB2_CCIR(r, g, b, y); |
607 | 0 | ctx->palette[i] = (r << 16) + (g << 8) + b; |
608 | 0 | buf++; |
609 | 0 | } |
610 | 0 | ctx->has_palette = 1; |
611 | 0 | } |
612 | 0 | } |
613 | 0 | } |
614 | 0 | if (ctx->has_palette == 0) { |
615 | 0 | av_log(logctx, AV_LOG_WARNING, "Failed to read palette from IFO file \"%s\"\n", p); |
616 | 0 | ret = AVERROR_INVALIDDATA; |
617 | 0 | } |
618 | 0 | end: |
619 | 0 | fclose(ifo); |
620 | 0 | return ret; |
621 | 0 | } |
622 | | |
623 | | static int dvdsub_parse_extradata(AVCodecContext *avctx) |
624 | 2.08k | { |
625 | 2.08k | DVDSubContext *ctx = (DVDSubContext*) avctx->priv_data; |
626 | 2.08k | char *dataorig, *data; |
627 | 2.08k | int ret; |
628 | | |
629 | 2.08k | if (!avctx->extradata || !avctx->extradata_size) |
630 | 1.85k | return 0; |
631 | | |
632 | 235 | dataorig = data = av_malloc(avctx->extradata_size+1); |
633 | 235 | if (!data) |
634 | 0 | return AVERROR(ENOMEM); |
635 | 235 | memcpy(data, avctx->extradata, avctx->extradata_size); |
636 | 235 | data[avctx->extradata_size] = '\0'; |
637 | | |
638 | 2.76k | for(;;) { |
639 | 2.76k | int pos = strcspn(data, "\n\r"); |
640 | 2.76k | if (pos==0 && *data==0) |
641 | 235 | break; |
642 | | |
643 | 2.52k | if (strncmp("palette:", data, 8) == 0) { |
644 | 376 | ctx->has_palette = 1; |
645 | 376 | ff_dvdsub_parse_palette(ctx->palette, data + 8); |
646 | 2.15k | } else if (strncmp("size:", data, 5) == 0) { |
647 | 92 | int w, h; |
648 | 92 | if (sscanf(data + 5, "%dx%d", &w, &h) == 2) { |
649 | 0 | ret = ff_set_dimensions(avctx, w, h); |
650 | 0 | if (ret < 0) |
651 | 0 | goto fail; |
652 | 0 | } |
653 | 92 | } |
654 | | |
655 | 2.52k | data += pos; |
656 | 2.52k | data += strspn(data, "\n\r"); |
657 | 2.52k | } |
658 | | |
659 | 235 | ret = 0; |
660 | 235 | fail: |
661 | 235 | av_free(dataorig); |
662 | 235 | return ret; |
663 | 235 | } |
664 | | |
665 | | static av_cold int dvdsub_init(AVCodecContext *avctx) |
666 | 2.08k | { |
667 | 2.08k | DVDSubContext *ctx = avctx->priv_data; |
668 | 2.08k | int ret; |
669 | | |
670 | 2.08k | if ((ret = dvdsub_parse_extradata(avctx)) < 0) |
671 | 0 | return ret; |
672 | | |
673 | 2.08k | if (ctx->ifo_str) |
674 | 0 | parse_ifo_palette(avctx, ctx, ctx->ifo_str); |
675 | 2.08k | if (ctx->palette_str) { |
676 | 0 | ctx->has_palette = 1; |
677 | 0 | ff_dvdsub_parse_palette(ctx->palette, ctx->palette_str); |
678 | 0 | } |
679 | 2.08k | if (ctx->has_palette) { |
680 | 120 | int i; |
681 | 120 | av_log(avctx, AV_LOG_DEBUG, "palette:"); |
682 | 2.04k | for(i=0;i<16;i++) |
683 | 1.92k | av_log(avctx, AV_LOG_DEBUG, " 0x%06"PRIx32, ctx->palette[i]); |
684 | 120 | av_log(avctx, AV_LOG_DEBUG, "\n"); |
685 | 120 | } |
686 | | |
687 | 2.08k | return 0; |
688 | 2.08k | } |
689 | | |
690 | | static av_cold void dvdsub_flush(AVCodecContext *avctx) |
691 | 31.2k | { |
692 | 31.2k | DVDSubContext *ctx = avctx->priv_data; |
693 | 31.2k | ctx->buf_size = 0; |
694 | 31.2k | } |
695 | | |
696 | | #define OFFSET(field) offsetof(DVDSubContext, field) |
697 | | #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM |
698 | | static const AVOption options[] = { |
699 | | { "palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD }, |
700 | | { "ifo_palette", "obtain the global palette from .IFO file", OFFSET(ifo_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD }, |
701 | | { "forced_subs_only", "Only show forced subtitles", OFFSET(forced_subs_only), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, SD}, |
702 | | { NULL } |
703 | | }; |
704 | | static const AVClass dvdsub_class = { |
705 | | .class_name = "dvdsubdec", |
706 | | .item_name = av_default_item_name, |
707 | | .option = options, |
708 | | .version = LIBAVUTIL_VERSION_INT, |
709 | | }; |
710 | | |
711 | | const FFCodec ff_dvdsub_decoder = { |
712 | | .p.name = "dvdsub", |
713 | | CODEC_LONG_NAME("DVD subtitles"), |
714 | | .p.type = AVMEDIA_TYPE_SUBTITLE, |
715 | | .p.id = AV_CODEC_ID_DVD_SUBTITLE, |
716 | | .priv_data_size = sizeof(DVDSubContext), |
717 | | .init = dvdsub_init, |
718 | | FF_CODEC_DECODE_SUB_CB(dvdsub_decode), |
719 | | .flush = dvdsub_flush, |
720 | | .p.priv_class = &dvdsub_class, |
721 | | }; |