00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #include <stdio.h>
00051 #include <stdlib.h>
00052
00053 #include "avcodec.h"
00054 #include "get_bits.h"
00055
00056 #include <zlib.h>
00057
00058 typedef struct FlashSVContext {
00059 AVCodecContext *avctx;
00060 AVFrame frame;
00061 int image_width, image_height;
00062 int block_width, block_height;
00063 uint8_t* tmpblock;
00064 int block_size;
00065 z_stream zstream;
00066 } FlashSVContext;
00067
00068
00069 static void copy_region(uint8_t *sptr, uint8_t *dptr,
00070 int dx, int dy, int h, int w, int stride)
00071 {
00072 int i;
00073
00074 for (i = dx+h; i > dx; i--)
00075 {
00076 memcpy(dptr+(i*stride)+dy*3, sptr, w*3);
00077 sptr += w*3;
00078 }
00079 }
00080
00081
00082 static av_cold int flashsv_decode_init(AVCodecContext *avctx)
00083 {
00084 FlashSVContext *s = avctx->priv_data;
00085 int zret;
00086
00087 s->avctx = avctx;
00088 s->zstream.zalloc = Z_NULL;
00089 s->zstream.zfree = Z_NULL;
00090 s->zstream.opaque = Z_NULL;
00091 zret = inflateInit(&(s->zstream));
00092 if (zret != Z_OK) {
00093 av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret);
00094 return 1;
00095 }
00096 avctx->pix_fmt = PIX_FMT_BGR24;
00097 s->frame.data[0] = NULL;
00098
00099 return 0;
00100 }
00101
00102
00103 static int flashsv_decode_frame(AVCodecContext *avctx,
00104 void *data, int *data_size,
00105 AVPacket *avpkt)
00106 {
00107 const uint8_t *buf = avpkt->data;
00108 int buf_size = avpkt->size;
00109 FlashSVContext *s = avctx->priv_data;
00110 int h_blocks, v_blocks, h_part, v_part, i, j;
00111 GetBitContext gb;
00112
00113
00114 if (buf_size == 0)
00115 return 0;
00116 if (buf_size < 4)
00117 return -1;
00118
00119 init_get_bits(&gb, buf, buf_size * 8);
00120
00121
00122 s->block_width = 16* (get_bits(&gb, 4)+1);
00123 s->image_width = get_bits(&gb,12);
00124 s->block_height= 16* (get_bits(&gb, 4)+1);
00125 s->image_height= get_bits(&gb,12);
00126
00127
00128 h_blocks = s->image_width / s->block_width;
00129 h_part = s->image_width % s->block_width;
00130 v_blocks = s->image_height / s->block_height;
00131 v_part = s->image_height % s->block_height;
00132
00133
00134
00135 if(s->block_size < s->block_width*s->block_height) {
00136 av_free(s->tmpblock);
00137 if ((s->tmpblock = av_malloc(3*s->block_width*s->block_height)) == NULL) {
00138 av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
00139 return -1;
00140 }
00141 }
00142 s->block_size = s->block_width*s->block_height;
00143
00144
00145 if((avctx->width==0) && (avctx->height==0)){
00146 avctx->width = s->image_width;
00147 avctx->height = s->image_height;
00148 }
00149
00150
00151 if ((avctx->width != s->image_width) || (avctx->height != s->image_height)) {
00152 av_log(avctx, AV_LOG_ERROR, "Frame width or height differs from first frames!\n");
00153 av_log(avctx, AV_LOG_ERROR, "fh = %d, fv %d vs ch = %d, cv = %d\n",avctx->height,
00154 avctx->width,s->image_height,s->image_width);
00155 return -1;
00156 }
00157
00158 av_log(avctx, AV_LOG_DEBUG, "image: %dx%d block: %dx%d num: %dx%d part: %dx%d\n",
00159 s->image_width, s->image_height, s->block_width, s->block_height,
00160 h_blocks, v_blocks, h_part, v_part);
00161
00162 s->frame.reference = 1;
00163 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00164 if(avctx->reget_buffer(avctx, &s->frame) < 0){
00165 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00166 return -1;
00167 }
00168
00169
00170 for (j = 0; j < v_blocks + (v_part?1:0); j++)
00171 {
00172
00173 int hp = j*s->block_height;
00174 int hs = (j<v_blocks)?s->block_height:v_part;
00175
00176
00177
00178 for (i = 0; i < h_blocks + (h_part?1:0); i++)
00179 {
00180 int wp = i*s->block_width;
00181 int ws = (i<h_blocks)?s->block_width:h_part;
00182
00183
00184 int size = get_bits(&gb, 16);
00185 if (8 * size > get_bits_left(&gb)) {
00186 avctx->release_buffer(avctx, &s->frame);
00187 s->frame.data[0] = NULL;
00188 return -1;
00189 }
00190
00191 if (size == 0) {
00192
00193 } else {
00194
00195 int ret = inflateReset(&(s->zstream));
00196 if (ret != Z_OK)
00197 {
00198 av_log(avctx, AV_LOG_ERROR, "error in decompression (reset) of block %dx%d\n", i, j);
00199
00200 }
00201 s->zstream.next_in = buf+(get_bits_count(&gb)/8);
00202 s->zstream.avail_in = size;
00203 s->zstream.next_out = s->tmpblock;
00204 s->zstream.avail_out = s->block_size*3;
00205 ret = inflate(&(s->zstream), Z_FINISH);
00206 if (ret == Z_DATA_ERROR)
00207 {
00208 av_log(avctx, AV_LOG_ERROR, "Zlib resync occurred\n");
00209 inflateSync(&(s->zstream));
00210 ret = inflate(&(s->zstream), Z_FINISH);
00211 }
00212
00213 if ((ret != Z_OK) && (ret != Z_STREAM_END))
00214 {
00215 av_log(avctx, AV_LOG_ERROR, "error in decompression of block %dx%d: %d\n", i, j, ret);
00216
00217 }
00218 copy_region(s->tmpblock, s->frame.data[0], s->image_height-(hp+hs+1), wp, hs, ws, s->frame.linesize[0]);
00219 skip_bits_long(&gb, 8*size);
00220 }
00221 }
00222 }
00223
00224 *data_size = sizeof(AVFrame);
00225 *(AVFrame*)data = s->frame;
00226
00227 if ((get_bits_count(&gb)/8) != buf_size)
00228 av_log(avctx, AV_LOG_ERROR, "buffer not fully consumed (%d != %d)\n",
00229 buf_size, (get_bits_count(&gb)/8));
00230
00231
00232 return buf_size;
00233 }
00234
00235
00236 static av_cold int flashsv_decode_end(AVCodecContext *avctx)
00237 {
00238 FlashSVContext *s = avctx->priv_data;
00239 inflateEnd(&(s->zstream));
00240
00241 if (s->frame.data[0])
00242 avctx->release_buffer(avctx, &s->frame);
00243
00244
00245 av_free(s->tmpblock);
00246
00247 return 0;
00248 }
00249
00250
00251 AVCodec ff_flashsv_decoder = {
00252 "flashsv",
00253 AVMEDIA_TYPE_VIDEO,
00254 CODEC_ID_FLASHSV,
00255 sizeof(FlashSVContext),
00256 flashsv_decode_init,
00257 NULL,
00258 flashsv_decode_end,
00259 flashsv_decode_frame,
00260 CODEC_CAP_DR1,
00261 .pix_fmts = (const enum PixelFormat[]){PIX_FMT_BGR24, PIX_FMT_NONE},
00262 .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video v1"),
00263 };