Mercurial > libavcodec.hg
annotate flashsv.c @ 10061:09f2db2d7c90 libavcodec
Fix bug caused by difference in stride and picture width.
When a frame is allocated using libschroedinger routines, the frame data size
does not match the actual frame size if the width is not a multiple of 16. So
we cannot do a straightforward memcpy of the frame returned by libschroedinger
into the FFmpeg picture as the stride differs from the width.
Fix this bug by allocating for the libschroedinger frame with the dimensions
in AVCodecContext within libavcodec and passing the frame to libschroedinger.
patch by Anuradha Suraparaju, anuradha rd.bbc.co uk
author | diego |
---|---|
date | Sat, 15 Aug 2009 11:59:53 +0000 |
parents | 0dce4fe6e6f3 |
children | 38cfe222e1a4 |
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 /** | |
8718
e9d9d946f213
Use full internal pathname in doxygen @file directives.
diego
parents:
8210
diff
changeset
|
24 * @file libavcodec/flashsv.c |
3329 | 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" | |
9428 | 54 #include "get_bits.h" |
3329 | 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, | |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8718
diff
changeset
|
105 AVPacket *avpkt) |
3329 | 106 { |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8718
diff
changeset
|
107 const uint8_t *buf = avpkt->data; |
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8718
diff
changeset
|
108 int buf_size = avpkt->size; |
4827 | 109 FlashSVContext *s = avctx->priv_data; |
3329 | 110 int h_blocks, v_blocks, h_part, v_part, i, j; |
111 GetBitContext gb; | |
112 | |
113 /* no supplementary picture */ | |
114 if (buf_size == 0) | |
115 return 0; | |
116 | |
117 if(s->frame.data[0]) | |
118 avctx->release_buffer(avctx, &s->frame); | |
119 | |
120 init_get_bits(&gb, buf, buf_size * 8); | |
121 | |
122 /* start to parse the bitstream */ | |
123 s->block_width = 16* (get_bits(&gb, 4)+1); | |
124 s->image_width = get_bits(&gb,12); | |
125 s->block_height= 16* (get_bits(&gb, 4)+1); | |
126 s->image_height= get_bits(&gb,12); | |
127 | |
128 /* calculate amount of blocks and the size of the border blocks */ | |
129 h_blocks = s->image_width / s->block_width; | |
130 h_part = s->image_width % s->block_width; | |
131 v_blocks = s->image_height / s->block_height; | |
132 v_part = s->image_height % s->block_height; | |
133 | |
134 /* the block size could change between frames, make sure the buffer | |
135 * is large enough, if not, get a larger one */ | |
136 if(s->block_size < s->block_width*s->block_height) { | |
137 if (s->tmpblock != NULL) | |
138 av_free(s->tmpblock); | |
4370
e6eb67453d94
The block_size might be used incorrectly if it is not updated.
banan
parents:
4367
diff
changeset
|
139 if ((s->tmpblock = av_malloc(3*s->block_width*s->block_height)) == NULL) { |
3329 | 140 av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); |
141 return -1; | |
142 } | |
143 } | |
4370
e6eb67453d94
The block_size might be used incorrectly if it is not updated.
banan
parents:
4367
diff
changeset
|
144 s->block_size = s->block_width*s->block_height; |
3329 | 145 |
146 /* init the image size once */ | |
147 if((avctx->width==0) && (avctx->height==0)){ | |
148 avctx->width = s->image_width; | |
149 avctx->height = s->image_height; | |
150 } | |
151 | |
152 /* check for changes of image width and image height */ | |
153 if ((avctx->width != s->image_width) || (avctx->height != s->image_height)) { | |
154 av_log(avctx, AV_LOG_ERROR, "Frame width or height differs from first frames!\n"); | |
155 av_log(avctx, AV_LOG_ERROR, "fh = %d, fv %d vs ch = %d, cv = %d\n",avctx->height, | |
156 avctx->width,s->image_height,s->image_width); | |
157 return -1; | |
158 } | |
159 | |
160 av_log(avctx, AV_LOG_DEBUG, "image: %dx%d block: %dx%d num: %dx%d part: %dx%d\n", | |
161 s->image_width, s->image_height, s->block_width, s->block_height, | |
162 h_blocks, v_blocks, h_part, v_part); | |
163 | |
164 s->frame.reference = 1; | |
165 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID; | |
166 if (avctx->get_buffer(avctx, &s->frame) < 0) { | |
167 av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
168 return -1; | |
169 } | |
170 | |
171 /* loop over all block columns */ | |
172 for (j = 0; j < v_blocks + (v_part?1:0); j++) | |
173 { | |
174 | |
175 int hp = j*s->block_height; // horiz position in frame | |
176 int hs = (j<v_blocks)?s->block_height:v_part; // size of block | |
177 | |
178 | |
179 /* loop over all block rows */ | |
180 for (i = 0; i < h_blocks + (h_part?1:0); i++) | |
181 { | |
182 int wp = i*s->block_width; // vert position in frame | |
183 int ws = (i<h_blocks)?s->block_width:h_part; // size of block | |
184 | |
185 /* get the size of the compressed zlib chunk */ | |
186 int size = get_bits(&gb, 16); | |
187 | |
188 if (size == 0) { | |
189 /* no change, don't do anything */ | |
190 } else { | |
191 /* decompress block */ | |
192 int ret = inflateReset(&(s->zstream)); | |
193 if (ret != Z_OK) | |
194 { | |
195 av_log(avctx, AV_LOG_ERROR, "error in decompression (reset) of block %dx%d\n", i, j); | |
196 /* return -1; */ | |
197 } | |
198 s->zstream.next_in = buf+(get_bits_count(&gb)/8); | |
199 s->zstream.avail_in = size; | |
200 s->zstream.next_out = s->tmpblock; | |
201 s->zstream.avail_out = s->block_size*3; | |
202 ret = inflate(&(s->zstream), Z_FINISH); | |
203 if (ret == Z_DATA_ERROR) | |
204 { | |
6524 | 205 av_log(avctx, AV_LOG_ERROR, "Zlib resync occurred\n"); |
3329 | 206 inflateSync(&(s->zstream)); |
207 ret = inflate(&(s->zstream), Z_FINISH); | |
208 } | |
209 | |
210 if ((ret != Z_OK) && (ret != Z_STREAM_END)) | |
211 { | |
212 av_log(avctx, AV_LOG_ERROR, "error in decompression of block %dx%d: %d\n", i, j, ret); | |
213 /* return -1; */ | |
214 } | |
215 copy_region(s->tmpblock, s->frame.data[0], s->image_height-(hp+hs+1), wp, hs, ws, s->frame.linesize[0]); | |
8210 | 216 skip_bits_long(&gb, 8*size); /* skip the consumed bits */ |
3329 | 217 } |
218 } | |
219 } | |
220 | |
221 *data_size = sizeof(AVFrame); | |
222 *(AVFrame*)data = s->frame; | |
223 | |
224 if ((get_bits_count(&gb)/8) != buf_size) | |
225 av_log(avctx, AV_LOG_ERROR, "buffer not fully consumed (%d != %d)\n", | |
226 buf_size, (get_bits_count(&gb)/8)); | |
227 | |
228 /* report that the buffer was completely consumed */ | |
229 return buf_size; | |
230 } | |
231 | |
232 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6236
diff
changeset
|
233 static av_cold int flashsv_decode_end(AVCodecContext *avctx) |
3329 | 234 { |
4827 | 235 FlashSVContext *s = avctx->priv_data; |
3329 | 236 inflateEnd(&(s->zstream)); |
237 /* release the frame if needed */ | |
238 if (s->frame.data[0]) | |
239 avctx->release_buffer(avctx, &s->frame); | |
240 | |
241 /* free the tmpblock */ | |
242 if (s->tmpblock != NULL) | |
243 av_free(s->tmpblock); | |
244 | |
245 return 0; | |
246 } | |
247 | |
248 | |
249 AVCodec flashsv_decoder = { | |
250 "flashsv", | |
251 CODEC_TYPE_VIDEO, | |
252 CODEC_ID_FLASHSV, | |
253 sizeof(FlashSVContext), | |
254 flashsv_decode_init, | |
255 NULL, | |
256 flashsv_decode_end, | |
257 flashsv_decode_frame, | |
258 CODEC_CAP_DR1, | |
6788 | 259 .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
|
260 .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video v1"), |
3329 | 261 }; |