Mercurial > libavcodec.hg
annotate xsubdec.c @ 12494:94eaea836bf4 libavcodec
Check avctx width/height more thoroughly (e.g. all values 0 except width would
have been accepted before).
Also do not fail if they are invalid but instead override them to 0.
This allows decoding e.g. MPEG video when only the container values are corrupted.
For encoding a value of 0,0 of course makes no sense, but was allowed
through before and will be caught by an extra check in the encode function.
author | reimar |
---|---|
date | Wed, 15 Sep 2010 04:46:55 +0000 |
parents | ffb3668ff7af |
children |
rev | line source |
---|---|
5493 | 1 /* |
2 * XSUB subtitle decoder | |
3 * Copyright (c) 2007 Reimar Döffinger | |
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 */ | |
12372
914f484bb476
Remove use of the deprecated function avcodec_check_dimensions(), use
stefano
parents:
11560
diff
changeset
|
21 #include "libavcore/imgutils.h" |
5483 | 22 #include "avcodec.h" |
9428 | 23 #include "get_bits.h" |
5483 | 24 #include "bytestream.h" |
25 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6218
diff
changeset
|
26 static av_cold int decode_init(AVCodecContext *avctx) { |
5483 | 27 avctx->pix_fmt = PIX_FMT_PAL8; |
28 return 0; | |
29 } | |
30 | |
5484 | 31 static const uint8_t tc_offsets[9] = { 0, 1, 3, 4, 6, 7, 9, 10, 11 }; |
8769 | 32 static const uint8_t tc_muls[9] = { 10, 6, 10, 6, 10, 10, 10, 10, 1 }; |
5484 | 33 |
10054
8ab9fbad11b2
Fix start_display_time/end_display_time to be relative to packet pts in xsub decoder.
reimar
parents:
10053
diff
changeset
|
34 static int64_t parse_timecode(const uint8_t *buf, int64_t packet_time) { |
5484 | 35 int i; |
36 int64_t ms = 0; | |
37 if (buf[2] != ':' || buf[5] != ':' || buf[8] != '.') | |
38 return AV_NOPTS_VALUE; | |
39 for (i = 0; i < sizeof(tc_offsets); i++) { | |
40 uint8_t c = buf[tc_offsets[i]] - '0'; | |
41 if (c > 9) return AV_NOPTS_VALUE; | |
42 ms = (ms + c) * tc_muls[i]; | |
43 } | |
10054
8ab9fbad11b2
Fix start_display_time/end_display_time to be relative to packet pts in xsub decoder.
reimar
parents:
10053
diff
changeset
|
44 return ms - packet_time; |
5484 | 45 } |
46 | |
5483 | 47 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8810
diff
changeset
|
48 AVPacket *avpkt) { |
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8810
diff
changeset
|
49 const uint8_t *buf = avpkt->data; |
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8810
diff
changeset
|
50 int buf_size = avpkt->size; |
5483 | 51 AVSubtitle *sub = data; |
6218 | 52 const uint8_t *buf_end = buf + buf_size; |
5483 | 53 uint8_t *bitmap; |
54 int w, h, x, y, rlelen, i; | |
10054
8ab9fbad11b2
Fix start_display_time/end_display_time to be relative to packet pts in xsub decoder.
reimar
parents:
10053
diff
changeset
|
55 int64_t packet_time = 0; |
5483 | 56 GetBitContext gb; |
57 | |
10050
b8313eb3dca8
Make sure AVSubtitle is initialized, memset it to 0.
reimar
parents:
9988
diff
changeset
|
58 memset(sub, 0, sizeof(*sub)); |
8810
367e4d405cd9
Set AVSubtitle format to 0. Neither dvdsubdec nor xsubdec intializes format
diego
parents:
8769
diff
changeset
|
59 |
5483 | 60 // check that at least header fits |
61 if (buf_size < 27 + 7 * 2 + 4 * 3) { | |
62 av_log(avctx, AV_LOG_ERROR, "coded frame too small\n"); | |
63 return -1; | |
64 } | |
65 | |
5484 | 66 // read start and end time |
67 if (buf[0] != '[' || buf[13] != '-' || buf[26] != ']') { | |
68 av_log(avctx, AV_LOG_ERROR, "invalid time code\n"); | |
69 return -1; | |
70 } | |
10054
8ab9fbad11b2
Fix start_display_time/end_display_time to be relative to packet pts in xsub decoder.
reimar
parents:
10053
diff
changeset
|
71 if (avpkt->pts != AV_NOPTS_VALUE) |
8ab9fbad11b2
Fix start_display_time/end_display_time to be relative to packet pts in xsub decoder.
reimar
parents:
10053
diff
changeset
|
72 packet_time = av_rescale_q(avpkt->pts, AV_TIME_BASE_Q, (AVRational){1, 1000}); |
8ab9fbad11b2
Fix start_display_time/end_display_time to be relative to packet pts in xsub decoder.
reimar
parents:
10053
diff
changeset
|
73 sub->start_display_time = parse_timecode(buf + 1, packet_time); |
8ab9fbad11b2
Fix start_display_time/end_display_time to be relative to packet pts in xsub decoder.
reimar
parents:
10053
diff
changeset
|
74 sub->end_display_time = parse_timecode(buf + 14, packet_time); |
5484 | 75 buf += 27; |
76 | |
5483 | 77 // read header |
78 w = bytestream_get_le16(&buf); | |
79 h = bytestream_get_le16(&buf); | |
12462
ffb3668ff7af
Use new imgutils.h API names, fix deprecation warnings.
stefano
parents:
12372
diff
changeset
|
80 if (av_image_check_size(w, h, 0, avctx) < 0) |
5483 | 81 return -1; |
82 x = bytestream_get_le16(&buf); | |
83 y = bytestream_get_le16(&buf); | |
84 // skip bottom right position, it gives no new information | |
85 bytestream_get_le16(&buf); | |
86 bytestream_get_le16(&buf); | |
87 rlelen = bytestream_get_le16(&buf); | |
88 | |
89 // allocate sub and set values | |
10053 | 90 sub->rects = av_mallocz(sizeof(*sub->rects)); |
91 sub->rects[0] = av_mallocz(sizeof(*sub->rects[0])); | |
92 sub->num_rects = 1; | |
8512
aa45029f5cd7
Change AVSubtitle.rects to an array of pointers so ABI does not break
michael
parents:
7040
diff
changeset
|
93 sub->rects[0]->x = x; sub->rects[0]->y = y; |
aa45029f5cd7
Change AVSubtitle.rects to an array of pointers so ABI does not break
michael
parents:
7040
diff
changeset
|
94 sub->rects[0]->w = w; sub->rects[0]->h = h; |
9988
b8a9cfe64488
Set subtitle type in DVD and XSUB subtitle decoders.
stefano
parents:
9428
diff
changeset
|
95 sub->rects[0]->type = SUBTITLE_BITMAP; |
8516
315b302fcd1d
Replace AVSubtitleRect.rgba_palette and bitmap by AVPicture.
michael
parents:
8512
diff
changeset
|
96 sub->rects[0]->pict.linesize[0] = w; |
315b302fcd1d
Replace AVSubtitleRect.rgba_palette and bitmap by AVPicture.
michael
parents:
8512
diff
changeset
|
97 sub->rects[0]->pict.data[0] = av_malloc(w * h); |
8512
aa45029f5cd7
Change AVSubtitle.rects to an array of pointers so ABI does not break
michael
parents:
7040
diff
changeset
|
98 sub->rects[0]->nb_colors = 4; |
10069
8ac9bc10b485
Always allocate a buffer of AVPALETTE_SIZE for palette in the subtitle
reimar
parents:
10054
diff
changeset
|
99 sub->rects[0]->pict.data[1] = av_mallocz(AVPALETTE_SIZE); |
5483 | 100 |
101 // read palette | |
8512
aa45029f5cd7
Change AVSubtitle.rects to an array of pointers so ABI does not break
michael
parents:
7040
diff
changeset
|
102 for (i = 0; i < sub->rects[0]->nb_colors; i++) |
8516
315b302fcd1d
Replace AVSubtitleRect.rgba_palette and bitmap by AVPicture.
michael
parents:
8512
diff
changeset
|
103 ((uint32_t*)sub->rects[0]->pict.data[1])[i] = bytestream_get_be24(&buf); |
5489
dc54869af30b
Colours except background should not be transparent
reimar
parents:
5488
diff
changeset
|
104 // make all except background (first entry) non-transparent |
8512
aa45029f5cd7
Change AVSubtitle.rects to an array of pointers so ABI does not break
michael
parents:
7040
diff
changeset
|
105 for (i = 1; i < sub->rects[0]->nb_colors; i++) |
8516
315b302fcd1d
Replace AVSubtitleRect.rgba_palette and bitmap by AVPicture.
michael
parents:
8512
diff
changeset
|
106 ((uint32_t*)sub->rects[0]->pict.data[1])[i] |= 0xff000000; |
5483 | 107 |
108 // process RLE-compressed data | |
109 rlelen = FFMIN(rlelen, buf_end - buf); | |
110 init_get_bits(&gb, buf, rlelen * 8); | |
8516
315b302fcd1d
Replace AVSubtitleRect.rgba_palette and bitmap by AVPicture.
michael
parents:
8512
diff
changeset
|
111 bitmap = sub->rects[0]->pict.data[0]; |
5483 | 112 for (y = 0; y < h; y++) { |
5490 | 113 // interlaced: do odd lines |
8516
315b302fcd1d
Replace AVSubtitleRect.rgba_palette and bitmap by AVPicture.
michael
parents:
8512
diff
changeset
|
114 if (y == (h + 1) / 2) bitmap = sub->rects[0]->pict.data[0] + w; |
5483 | 115 for (x = 0; x < w; ) { |
116 int log2 = ff_log2_tab[show_bits(&gb, 8)]; | |
5487
3039b660bf35
get rid of xsubdec array and calculate value instead
reimar
parents:
5486
diff
changeset
|
117 int run = get_bits(&gb, 14 - 4 * (log2 >> 1)); |
5982 | 118 int color = get_bits(&gb, 2); |
5483 | 119 run = FFMIN(run, w - x); |
120 // run length 0 means till end of row | |
121 if (!run) run = w - x; | |
5982 | 122 memset(bitmap, color, run); |
5483 | 123 bitmap += run; |
124 x += run; | |
125 } | |
5490 | 126 // interlaced, skip every second line |
127 bitmap += w; | |
5483 | 128 align_get_bits(&gb); |
129 } | |
130 *data_size = 1; | |
131 return buf_size; | |
132 } | |
133 | |
134 AVCodec xsub_decoder = { | |
135 "xsub", | |
11560
8a4984c5cacc
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
10069
diff
changeset
|
136 AVMEDIA_TYPE_SUBTITLE, |
5483 | 137 CODEC_ID_XSUB, |
138 0, | |
139 decode_init, | |
140 NULL, | |
141 NULL, | |
142 decode_frame, | |
7040
e943e1409077
Make AVCodec long_names definition conditional depending on CONFIG_SMALL.
stefano
parents:
6710
diff
changeset
|
143 .long_name = NULL_IF_CONFIG_SMALL("XSUB"), |
5483 | 144 }; |