Mercurial > libavcodec.hg
annotate sgidec.c @ 8991:ca768cb2bfb6 libavcodec
Use last decoded SPS as current SPS in order to parse picture timing SEI
correctly. This works around an apparent H.264 standard deficiency.
Patch by Ivan Schreter, schreter gmx net
author | cehoyos |
---|---|
date | Fri, 20 Feb 2009 16:20:01 +0000 |
parents | e943e1409077 |
children | 54bc8a2727b0 |
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, | |
6218 | 150 const uint8_t *in_buf, int buf_size) |
4790 | 151 { |
152 SgiState *s = avctx->priv_data; | |
153 AVFrame *picture = data; | |
154 AVFrame *p = &s->picture; | |
6218 | 155 const uint8_t *in_end = in_buf + buf_size; |
4790 | 156 unsigned int dimension, bytes_per_channel, rle; |
157 int ret = 0; | |
158 uint8_t *out_buf, *out_end; | |
159 | |
160 if (buf_size < SGI_HEADER_SIZE){ | |
161 av_log(avctx, AV_LOG_ERROR, "buf_size too small (%d)\n", buf_size); | |
162 return -1; | |
163 } | |
164 | |
165 /* Test for SGI magic. */ | |
166 if (bytestream_get_be16(&in_buf) != SGI_MAGIC) { | |
167 av_log(avctx, AV_LOG_ERROR, "bad magic number\n"); | |
168 return -1; | |
169 } | |
170 | |
171 rle = bytestream_get_byte(&in_buf); | |
172 bytes_per_channel = bytestream_get_byte(&in_buf); | |
173 dimension = bytestream_get_be16(&in_buf); | |
174 s->width = bytestream_get_be16(&in_buf); | |
175 s->height = bytestream_get_be16(&in_buf); | |
176 s->depth = bytestream_get_be16(&in_buf); | |
177 | |
178 if (bytes_per_channel != 1) { | |
179 av_log(avctx, AV_LOG_ERROR, "wrong channel number\n"); | |
180 return -1; | |
181 } | |
182 | |
183 /* Check for supported image dimensions. */ | |
184 if (dimension != 2 && dimension != 3) { | |
185 av_log(avctx, AV_LOG_ERROR, "wrong dimension number\n"); | |
186 return -1; | |
187 } | |
188 | |
189 if (s->depth == SGI_GRAYSCALE) { | |
190 avctx->pix_fmt = PIX_FMT_GRAY8; | |
191 } else if (s->depth == SGI_RGB) { | |
192 avctx->pix_fmt = PIX_FMT_RGB24; | |
193 } else if (s->depth == SGI_RGBA) { | |
194 avctx->pix_fmt = PIX_FMT_RGBA; | |
195 } else { | |
196 av_log(avctx, AV_LOG_ERROR, "wrong picture format\n"); | |
197 return -1; | |
198 } | |
199 | |
200 if (avcodec_check_dimensions(avctx, s->width, s->height)) | |
201 return -1; | |
202 avcodec_set_dimensions(avctx, s->width, s->height); | |
203 | |
204 if (p->data[0]) | |
205 avctx->release_buffer(avctx, p); | |
206 | |
207 p->reference = 0; | |
208 if (avctx->get_buffer(avctx, p) < 0) { | |
209 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed.\n"); | |
210 return -1; | |
211 } | |
212 | |
213 p->pict_type = FF_I_TYPE; | |
214 p->key_frame = 1; | |
215 out_buf = p->data[0]; | |
216 | |
217 out_end = out_buf + p->linesize[0] * s->height; | |
218 | |
219 s->linesize = p->linesize[0]; | |
220 | |
221 /* Skip header. */ | |
222 in_buf += SGI_HEADER_SIZE - 12; | |
223 if (rle) { | |
224 ret = read_rle_sgi(out_end, in_buf, in_end, s); | |
225 } else { | |
226 ret = read_uncompressed_sgi(out_buf, out_end, in_buf, in_end, s); | |
227 } | |
228 | |
229 if (ret == 0) { | |
230 *picture = s->picture; | |
231 *data_size = sizeof(AVPicture); | |
232 return buf_size; | |
233 } else { | |
234 return -1; | |
235 } | |
236 } | |
237 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6218
diff
changeset
|
238 static av_cold int sgi_init(AVCodecContext *avctx){ |
4790 | 239 SgiState *s = avctx->priv_data; |
240 | |
241 avcodec_get_frame_defaults(&s->picture); | |
242 avctx->coded_frame = &s->picture; | |
243 | |
244 return 0; | |
245 } | |
246 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6218
diff
changeset
|
247 static av_cold int sgi_end(AVCodecContext *avctx) |
4790 | 248 { |
249 SgiState * const s = avctx->priv_data; | |
250 | |
251 if (s->picture.data[0]) | |
252 avctx->release_buffer(avctx, &s->picture); | |
253 | |
254 return 0; | |
255 } | |
256 | |
257 AVCodec sgi_decoder = { | |
258 "sgi", | |
259 CODEC_TYPE_VIDEO, | |
260 CODEC_ID_SGI, | |
261 sizeof(SgiState), | |
262 sgi_init, | |
263 NULL, | |
264 sgi_end, | |
265 decode_frame, | |
7040
e943e1409077
Make AVCodec long_names definition conditional depending on CONFIG_SMALL.
stefano
parents:
6722
diff
changeset
|
266 .long_name = NULL_IF_CONFIG_SMALL("SGI image"), |
4790 | 267 }; |
268 |