Mercurial > libavcodec.hg
annotate flashsv.c @ 8204:507854688c43 libavcodec
Some BMP files have file size declared in the header equal to headers size
without image data, so try to correct that value before conducting checks on
declared file size.
author | kostya |
---|---|
date | Mon, 24 Nov 2008 11:24:02 +0000 |
parents | e943e1409077 |
children | e1f9d8919cb5 |
rev | line source |
---|---|
3329 | 1 /* |
2 * Flash Screen Video decoder | |
3 * Copyright (C) 2004 Alex Beregszaszi | |
4 * Copyright (C) 2006 Benjamin Larsson | |
5 * | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3329
diff
changeset
|
6 * This file is part of FFmpeg. |
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3329
diff
changeset
|
7 * |
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3329
diff
changeset
|
8 * FFmpeg is free software; you can redistribute it and/or |
3329 | 9 * modify it under the terms of the GNU Lesser General Public |
10 * License as published by the Free Software Foundation; either | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3329
diff
changeset
|
11 * version 2.1 of the License, or (at your option) any later version. |
3329 | 12 * |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3329
diff
changeset
|
13 * FFmpeg is distributed in the hope that it will be useful, |
3329 | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 * Lesser General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU Lesser General Public | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3329
diff
changeset
|
19 * License along with FFmpeg; if not, write to the Free Software |
3329 | 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 */ | |
22 | |
23 /** | |
24 * @file flashsv.c | |
25 * Flash Screen Video decoder | |
26 * @author Alex Beregszaszi | |
27 * @author Benjamin Larsson | |
28 */ | |
29 | |
30 /* Bitstream description | |
31 * The picture is divided into blocks that are zlib compressed. | |
32 * | |
33 * The decoder is fed complete frames, the frameheader contains: | |
34 * 4bits of block width | |
35 * 12bits of frame width | |
36 * 4bits of block height | |
37 * 12bits of frame height | |
38 * | |
39 * Directly after the header are the compressed blocks. The blocks | |
40 * have their compressed size represented with 16bits in the beginnig. | |
41 * If the size = 0 then the block is unchanged from the previous frame. | |
42 * All blocks are decompressed until the buffer is consumed. | |
43 * | |
44 * Encoding ideas, a basic encoder would just use a fixed block size. | |
45 * Block sizes can be multipels of 16, from 16 to 256. The blocks don't | |
46 * have to be quadratic. A brute force search with a set of diffrent | |
47 * block sizes should give a better result then to just use a fixed size. | |
48 */ | |
49 | |
50 #include <stdio.h> | |
51 #include <stdlib.h> | |
52 | |
53 #include "avcodec.h" | |
54 #include "bitstream.h" | |
55 | |
4372 | 56 #include <zlib.h> |
57 | |
3329 | 58 typedef struct FlashSVContext { |
59 AVCodecContext *avctx; | |
60 AVFrame frame; | |
61 int image_width, image_height; | |
62 int block_width, block_height; | |
63 uint8_t* tmpblock; | |
64 int block_size; | |
65 z_stream zstream; | |
66 } FlashSVContext; | |
67 | |
68 | |
69 static void copy_region(uint8_t *sptr, uint8_t *dptr, | |
70 int dx, int dy, int h, int w, int stride) | |
71 { | |
72 int i; | |
73 | |
74 for (i = dx+h; i > dx; i--) | |
75 { | |
76 memcpy(dptr+(i*stride)+dy*3, sptr, w*3); | |
77 sptr += w*3; | |
78 } | |
79 } | |
80 | |
81 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6236
diff
changeset
|
82 static av_cold int flashsv_decode_init(AVCodecContext *avctx) |
3329 | 83 { |
4827 | 84 FlashSVContext *s = avctx->priv_data; |
3329 | 85 int zret; // Zlib return code |
86 | |
87 s->avctx = avctx; | |
88 s->zstream.zalloc = Z_NULL; | |
89 s->zstream.zfree = Z_NULL; | |
90 s->zstream.opaque = Z_NULL; | |
91 zret = inflateInit(&(s->zstream)); | |
92 if (zret != Z_OK) { | |
93 av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret); | |
94 return 1; | |
95 } | |
96 avctx->pix_fmt = PIX_FMT_BGR24; | |
97 s->frame.data[0] = NULL; | |
98 | |
99 return 0; | |
100 } | |
101 | |
102 | |
103 static int flashsv_decode_frame(AVCodecContext *avctx, | |
104 void *data, int *data_size, | |
6236 | 105 const uint8_t *buf, int buf_size) |
3329 | 106 { |
4827 | 107 FlashSVContext *s = avctx->priv_data; |
3329 | 108 int h_blocks, v_blocks, h_part, v_part, i, j; |
109 GetBitContext gb; | |
110 | |
111 /* no supplementary picture */ | |
112 if (buf_size == 0) | |
113 return 0; | |
114 | |
115 if(s->frame.data[0]) | |
116 avctx->release_buffer(avctx, &s->frame); | |
117 | |
118 init_get_bits(&gb, buf, buf_size * 8); | |
119 | |
120 /* start to parse the bitstream */ | |
121 s->block_width = 16* (get_bits(&gb, 4)+1); | |
122 s->image_width = get_bits(&gb,12); | |
123 s->block_height= 16* (get_bits(&gb, 4)+1); | |
124 s->image_height= get_bits(&gb,12); | |
125 | |
126 /* calculate amount of blocks and the size of the border blocks */ | |
127 h_blocks = s->image_width / s->block_width; | |
128 h_part = s->image_width % s->block_width; | |
129 v_blocks = s->image_height / s->block_height; | |
130 v_part = s->image_height % s->block_height; | |
131 | |
132 /* the block size could change between frames, make sure the buffer | |
133 * is large enough, if not, get a larger one */ | |
134 if(s->block_size < s->block_width*s->block_height) { | |
135 if (s->tmpblock != NULL) | |
136 av_free(s->tmpblock); | |
4370
e6eb67453d94
The block_size might be used incorrectly if it is not updated.
banan
parents:
4367
diff
changeset
|
137 if ((s->tmpblock = av_malloc(3*s->block_width*s->block_height)) == NULL) { |
3329 | 138 av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); |
139 return -1; | |
140 } | |
141 } | |
4370
e6eb67453d94
The block_size might be used incorrectly if it is not updated.
banan
parents:
4367
diff
changeset
|
142 s->block_size = s->block_width*s->block_height; |
3329 | 143 |
144 /* init the image size once */ | |
145 if((avctx->width==0) && (avctx->height==0)){ | |
146 avctx->width = s->image_width; | |
147 avctx->height = s->image_height; | |
148 } | |
149 | |
150 /* check for changes of image width and image height */ | |
151 if ((avctx->width != s->image_width) || (avctx->height != s->image_height)) { | |
152 av_log(avctx, AV_LOG_ERROR, "Frame width or height differs from first frames!\n"); | |
153 av_log(avctx, AV_LOG_ERROR, "fh = %d, fv %d vs ch = %d, cv = %d\n",avctx->height, | |
154 avctx->width,s->image_height,s->image_width); | |
155 return -1; | |
156 } | |
157 | |
158 av_log(avctx, AV_LOG_DEBUG, "image: %dx%d block: %dx%d num: %dx%d part: %dx%d\n", | |
159 s->image_width, s->image_height, s->block_width, s->block_height, | |
160 h_blocks, v_blocks, h_part, v_part); | |
161 | |
162 s->frame.reference = 1; | |
163 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID; | |
164 if (avctx->get_buffer(avctx, &s->frame) < 0) { | |
165 av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
166 return -1; | |
167 } | |
168 | |
169 /* loop over all block columns */ | |
170 for (j = 0; j < v_blocks + (v_part?1:0); j++) | |
171 { | |
172 | |
173 int hp = j*s->block_height; // horiz position in frame | |
174 int hs = (j<v_blocks)?s->block_height:v_part; // size of block | |
175 | |
176 | |
177 /* loop over all block rows */ | |
178 for (i = 0; i < h_blocks + (h_part?1:0); i++) | |
179 { | |
180 int wp = i*s->block_width; // vert position in frame | |
181 int ws = (i<h_blocks)?s->block_width:h_part; // size of block | |
182 | |
183 /* get the size of the compressed zlib chunk */ | |
184 int size = get_bits(&gb, 16); | |
185 | |
186 if (size == 0) { | |
187 /* no change, don't do anything */ | |
188 } else { | |
189 /* decompress block */ | |
190 int ret = inflateReset(&(s->zstream)); | |
191 if (ret != Z_OK) | |
192 { | |
193 av_log(avctx, AV_LOG_ERROR, "error in decompression (reset) of block %dx%d\n", i, j); | |
194 /* return -1; */ | |
195 } | |
196 s->zstream.next_in = buf+(get_bits_count(&gb)/8); | |
197 s->zstream.avail_in = size; | |
198 s->zstream.next_out = s->tmpblock; | |
199 s->zstream.avail_out = s->block_size*3; | |
200 ret = inflate(&(s->zstream), Z_FINISH); | |
201 if (ret == Z_DATA_ERROR) | |
202 { | |
6524 | 203 av_log(avctx, AV_LOG_ERROR, "Zlib resync occurred\n"); |
3329 | 204 inflateSync(&(s->zstream)); |
205 ret = inflate(&(s->zstream), Z_FINISH); | |
206 } | |
207 | |
208 if ((ret != Z_OK) && (ret != Z_STREAM_END)) | |
209 { | |
210 av_log(avctx, AV_LOG_ERROR, "error in decompression of block %dx%d: %d\n", i, j, ret); | |
211 /* return -1; */ | |
212 } | |
213 copy_region(s->tmpblock, s->frame.data[0], s->image_height-(hp+hs+1), wp, hs, ws, s->frame.linesize[0]); | |
214 skip_bits(&gb, 8*size); /* skip the consumed bits */ | |
215 } | |
216 } | |
217 } | |
218 | |
219 *data_size = sizeof(AVFrame); | |
220 *(AVFrame*)data = s->frame; | |
221 | |
222 if ((get_bits_count(&gb)/8) != buf_size) | |
223 av_log(avctx, AV_LOG_ERROR, "buffer not fully consumed (%d != %d)\n", | |
224 buf_size, (get_bits_count(&gb)/8)); | |
225 | |
226 /* report that the buffer was completely consumed */ | |
227 return buf_size; | |
228 } | |
229 | |
230 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6236
diff
changeset
|
231 static av_cold int flashsv_decode_end(AVCodecContext *avctx) |
3329 | 232 { |
4827 | 233 FlashSVContext *s = avctx->priv_data; |
3329 | 234 inflateEnd(&(s->zstream)); |
235 /* release the frame if needed */ | |
236 if (s->frame.data[0]) | |
237 avctx->release_buffer(avctx, &s->frame); | |
238 | |
239 /* free the tmpblock */ | |
240 if (s->tmpblock != NULL) | |
241 av_free(s->tmpblock); | |
242 | |
243 return 0; | |
244 } | |
245 | |
246 | |
247 AVCodec flashsv_decoder = { | |
248 "flashsv", | |
249 CODEC_TYPE_VIDEO, | |
250 CODEC_ID_FLASHSV, | |
251 sizeof(FlashSVContext), | |
252 flashsv_decode_init, | |
253 NULL, | |
254 flashsv_decode_end, | |
255 flashsv_decode_frame, | |
256 CODEC_CAP_DR1, | |
6788 | 257 .pix_fmts = (enum PixelFormat[]){PIX_FMT_BGR24, PIX_FMT_NONE}, |
7040
e943e1409077
Make AVCodec long_names definition conditional depending on CONFIG_SMALL.
stefano
parents:
6788
diff
changeset
|
258 .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video v1"), |
3329 | 259 }; |