Mercurial > libavcodec.hg
annotate sgidec.c @ 9896:bbefbca72722 libavcodec
Drop code that attempts to decode frames that are prefixed by junk.
Too often it ends up decoding random data into noise without detecting
it (for example after seeking of some MP3 data with oddly often occurring
startcode emulation).
Fixes issue1154.
| author | michael |
|---|---|
| date | Tue, 30 Jun 2009 03:57:27 +0000 |
| parents | 54bc8a2727b0 |
| children | 5b05416fcb6b |
| rev | line source |
|---|---|
| 4790 | 1 /* |
| 2 * SGI image decoder | |
| 3 * Todd Kirby <doubleshot@pacbell.net> | |
| 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 "bytestream.h" | |
| 24 #include "sgi.h" | |
| 25 | |
| 26 typedef struct SgiState { | |
| 27 AVFrame picture; | |
| 28 unsigned int width; | |
| 29 unsigned int height; | |
| 30 unsigned int depth; | |
| 31 int linesize; | |
| 32 } SgiState; | |
| 33 | |
| 34 /** | |
| 35 * Expand an RLE row into a channel. | |
| 36 * @param in_buf input buffer | |
| 37 * @param in_end end of input buffer | |
| 38 * @param out_buf Points to one line after the output buffer. | |
| 39 * @param out_end end of line in output buffer | |
| 40 * @param pixelstride pixel stride of input buffer | |
| 41 * @return size of output in bytes, -1 if buffer overflows | |
| 42 */ | |
| 6218 | 43 static int expand_rle_row(const uint8_t *in_buf, const uint8_t* in_end, |
| 4790 | 44 unsigned char *out_buf, uint8_t* out_end, int pixelstride) |
| 45 { | |
| 46 unsigned char pixel, count; | |
| 47 unsigned char *orig = out_buf; | |
| 48 | |
| 49 while (1) { | |
| 50 if(in_buf + 1 > in_end) return -1; | |
| 51 pixel = bytestream_get_byte(&in_buf); | |
| 52 if (!(count = (pixel & 0x7f))) { | |
| 53 return (out_buf - orig) / pixelstride; | |
| 54 } | |
| 55 | |
| 56 /* Check for buffer overflow. */ | |
| 57 if(out_buf + pixelstride * count >= out_end) return -1; | |
| 58 | |
| 59 if (pixel & 0x80) { | |
| 60 while (count--) { | |
| 61 *out_buf = bytestream_get_byte(&in_buf); | |
| 62 out_buf += pixelstride; | |
| 63 } | |
| 64 } else { | |
| 65 pixel = bytestream_get_byte(&in_buf); | |
| 66 | |
| 67 while (count--) { | |
| 68 *out_buf = pixel; | |
| 69 out_buf += pixelstride; | |
| 70 } | |
| 71 } | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 /** | |
| 76 * Read a run length encoded SGI image. | |
| 77 * @param out_buf output buffer | |
| 78 * @param in_buf input buffer | |
| 79 * @param in_end end of input buffer | |
| 80 * @param s the current image state | |
| 81 * @return 0 if no error, else return error number. | |
| 82 */ | |
| 6218 | 83 static int read_rle_sgi(unsigned char* out_buf, const uint8_t *in_buf, |
| 84 const uint8_t *in_end, SgiState* s) | |
| 4790 | 85 { |
| 86 uint8_t *dest_row; | |
| 87 unsigned int len = s->height * s->depth * 4; | |
| 6218 | 88 const uint8_t *start_table = in_buf; |
| 4790 | 89 unsigned int y, z; |
| 90 unsigned int start_offset; | |
| 91 | |
| 92 /* size of RLE offset and length tables */ | |
| 93 if(len * 2 > in_end - in_buf) { | |
| 94 return AVERROR_INVALIDDATA; | |
| 95 } | |
| 96 | |
| 97 in_buf -= SGI_HEADER_SIZE; | |
| 98 for (z = 0; z < s->depth; z++) { | |
| 99 dest_row = out_buf; | |
| 100 for (y = 0; y < s->height; y++) { | |
| 101 dest_row -= s->linesize; | |
| 102 start_offset = bytestream_get_be32(&start_table); | |
| 103 if(start_offset > in_end - in_buf) { | |
| 104 return AVERROR_INVALIDDATA; | |
| 105 } | |
| 106 if (expand_rle_row(in_buf + start_offset, in_end, dest_row + z, | |
| 107 dest_row + FFABS(s->linesize), s->depth) != s->width) | |
| 108 return AVERROR_INVALIDDATA; | |
| 109 } | |
| 110 } | |
| 111 return 0; | |
| 112 } | |
| 113 | |
| 114 /** | |
| 115 * Read an uncompressed SGI image. | |
| 116 * @param out_buf output buffer | |
| 117 * @param out_end end ofoutput buffer | |
| 118 * @param in_buf input buffer | |
| 119 * @param in_end end of input buffer | |
| 120 * @param s the current image state | |
| 121 * @return 0 if read success, otherwise return -1. | |
| 122 */ | |
| 123 static int read_uncompressed_sgi(unsigned char* out_buf, uint8_t* out_end, | |
| 6218 | 124 const uint8_t *in_buf, const uint8_t *in_end, SgiState* s) |
| 4790 | 125 { |
| 126 int x, y, z; | |
| 6218 | 127 const uint8_t *ptr; |
| 4790 | 128 unsigned int offset = s->height * s->width; |
| 129 | |
| 130 /* Test buffer size. */ | |
| 131 if (offset * s->depth > in_end - in_buf) { | |
| 132 return -1; | |
| 133 } | |
| 134 | |
| 135 for (y = s->height - 1; y >= 0; y--) { | |
| 136 out_end = out_buf + (y * s->linesize); | |
| 137 for (x = s->width; x > 0; x--) { | |
| 138 ptr = in_buf++; | |
| 139 for(z = 0; z < s->depth; z ++) { | |
| 140 bytestream_put_byte(&out_end, *ptr); | |
| 141 ptr += offset; | |
| 142 } | |
| 143 } | |
| 144 } | |
| 145 return 0; | |
| 146 } | |
| 147 | |
| 148 static int decode_frame(AVCodecContext *avctx, | |
| 149 void *data, int *data_size, | |
|
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
7040
diff
changeset
|
150 AVPacket *avpkt) |
| 4790 | 151 { |
|
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
7040
diff
changeset
|
152 const uint8_t *in_buf = avpkt->data; |
|
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
7040
diff
changeset
|
153 int buf_size = avpkt->size; |
| 4790 | 154 SgiState *s = avctx->priv_data; |
| 155 AVFrame *picture = data; | |
| 156 AVFrame *p = &s->picture; | |
| 6218 | 157 const uint8_t *in_end = in_buf + buf_size; |
| 4790 | 158 unsigned int dimension, bytes_per_channel, rle; |
| 159 int ret = 0; | |
| 160 uint8_t *out_buf, *out_end; | |
| 161 | |
| 162 if (buf_size < SGI_HEADER_SIZE){ | |
| 163 av_log(avctx, AV_LOG_ERROR, "buf_size too small (%d)\n", buf_size); | |
| 164 return -1; | |
| 165 } | |
| 166 | |
| 167 /* Test for SGI magic. */ | |
| 168 if (bytestream_get_be16(&in_buf) != SGI_MAGIC) { | |
| 169 av_log(avctx, AV_LOG_ERROR, "bad magic number\n"); | |
| 170 return -1; | |
| 171 } | |
| 172 | |
| 173 rle = bytestream_get_byte(&in_buf); | |
| 174 bytes_per_channel = bytestream_get_byte(&in_buf); | |
| 175 dimension = bytestream_get_be16(&in_buf); | |
| 176 s->width = bytestream_get_be16(&in_buf); | |
| 177 s->height = bytestream_get_be16(&in_buf); | |
| 178 s->depth = bytestream_get_be16(&in_buf); | |
| 179 | |
| 180 if (bytes_per_channel != 1) { | |
| 181 av_log(avctx, AV_LOG_ERROR, "wrong channel number\n"); | |
| 182 return -1; | |
| 183 } | |
| 184 | |
| 185 /* Check for supported image dimensions. */ | |
| 186 if (dimension != 2 && dimension != 3) { | |
| 187 av_log(avctx, AV_LOG_ERROR, "wrong dimension number\n"); | |
| 188 return -1; | |
| 189 } | |
| 190 | |
| 191 if (s->depth == SGI_GRAYSCALE) { | |
| 192 avctx->pix_fmt = PIX_FMT_GRAY8; | |
| 193 } else if (s->depth == SGI_RGB) { | |
| 194 avctx->pix_fmt = PIX_FMT_RGB24; | |
| 195 } else if (s->depth == SGI_RGBA) { | |
| 196 avctx->pix_fmt = PIX_FMT_RGBA; | |
| 197 } else { | |
| 198 av_log(avctx, AV_LOG_ERROR, "wrong picture format\n"); | |
| 199 return -1; | |
| 200 } | |
| 201 | |
| 202 if (avcodec_check_dimensions(avctx, s->width, s->height)) | |
| 203 return -1; | |
| 204 avcodec_set_dimensions(avctx, s->width, s->height); | |
| 205 | |
| 206 if (p->data[0]) | |
| 207 avctx->release_buffer(avctx, p); | |
| 208 | |
| 209 p->reference = 0; | |
| 210 if (avctx->get_buffer(avctx, p) < 0) { | |
| 211 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed.\n"); | |
| 212 return -1; | |
| 213 } | |
| 214 | |
| 215 p->pict_type = FF_I_TYPE; | |
| 216 p->key_frame = 1; | |
| 217 out_buf = p->data[0]; | |
| 218 | |
| 219 out_end = out_buf + p->linesize[0] * s->height; | |
| 220 | |
| 221 s->linesize = p->linesize[0]; | |
| 222 | |
| 223 /* Skip header. */ | |
| 224 in_buf += SGI_HEADER_SIZE - 12; | |
| 225 if (rle) { | |
| 226 ret = read_rle_sgi(out_end, in_buf, in_end, s); | |
| 227 } else { | |
| 228 ret = read_uncompressed_sgi(out_buf, out_end, in_buf, in_end, s); | |
| 229 } | |
| 230 | |
| 231 if (ret == 0) { | |
| 232 *picture = s->picture; | |
| 233 *data_size = sizeof(AVPicture); | |
| 234 return buf_size; | |
| 235 } else { | |
| 236 return -1; | |
| 237 } | |
| 238 } | |
| 239 | |
|
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6218
diff
changeset
|
240 static av_cold int sgi_init(AVCodecContext *avctx){ |
| 4790 | 241 SgiState *s = avctx->priv_data; |
| 242 | |
| 243 avcodec_get_frame_defaults(&s->picture); | |
| 244 avctx->coded_frame = &s->picture; | |
| 245 | |
| 246 return 0; | |
| 247 } | |
| 248 | |
|
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6218
diff
changeset
|
249 static av_cold int sgi_end(AVCodecContext *avctx) |
| 4790 | 250 { |
| 251 SgiState * const s = avctx->priv_data; | |
| 252 | |
| 253 if (s->picture.data[0]) | |
| 254 avctx->release_buffer(avctx, &s->picture); | |
| 255 | |
| 256 return 0; | |
| 257 } | |
| 258 | |
| 259 AVCodec sgi_decoder = { | |
| 260 "sgi", | |
| 261 CODEC_TYPE_VIDEO, | |
| 262 CODEC_ID_SGI, | |
| 263 sizeof(SgiState), | |
| 264 sgi_init, | |
| 265 NULL, | |
| 266 sgi_end, | |
| 267 decode_frame, | |
|
7040
e943e1409077
Make AVCodec long_names definition conditional depending on CONFIG_SMALL.
stefano
parents:
6722
diff
changeset
|
268 .long_name = NULL_IF_CONFIG_SMALL("SGI image"), |
| 4790 | 269 }; |
| 270 |
