Libav 0.7.1
|
00001 /* 00002 * CamStudio decoder 00003 * Copyright (c) 2006 Reimar Doeffinger 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 #include <stdio.h> 00022 #include <stdlib.h> 00023 00024 #include "avcodec.h" 00025 00026 #if CONFIG_ZLIB 00027 #include <zlib.h> 00028 #endif 00029 #include "libavutil/lzo.h" 00030 00031 typedef struct { 00032 AVFrame pic; 00033 int linelen, height, bpp; 00034 unsigned int decomp_size; 00035 unsigned char* decomp_buf; 00036 } CamStudioContext; 00037 00038 static void copy_frame_default(AVFrame *f, const uint8_t *src, int src_stride, 00039 int linelen, int height) { 00040 int i; 00041 uint8_t *dst = f->data[0]; 00042 dst += (height - 1) * f->linesize[0]; 00043 for (i = height; i; i--) { 00044 memcpy(dst, src, linelen); 00045 src += src_stride; 00046 dst -= f->linesize[0]; 00047 } 00048 } 00049 00050 static void add_frame_default(AVFrame *f, const uint8_t *src, int src_stride, 00051 int linelen, int height) { 00052 int i, j; 00053 uint8_t *dst = f->data[0]; 00054 dst += (height - 1) * f->linesize[0]; 00055 for (i = height; i; i--) { 00056 for (j = linelen; j; j--) 00057 *dst++ += *src++; 00058 src += src_stride - linelen; 00059 dst -= f->linesize[0] + linelen; 00060 } 00061 } 00062 00063 #if !HAVE_BIGENDIAN 00064 #define copy_frame_16(f, s, l, h) copy_frame_default(f, s, l, l, h) 00065 #define copy_frame_32(f, s, l, h) copy_frame_default(f, s, l, l, h) 00066 #define add_frame_16(f, s, l, h) add_frame_default(f, s, l, l, h) 00067 #define add_frame_32(f, s, l, h) add_frame_default(f, s, l, l, h) 00068 #else 00069 static void copy_frame_16(AVFrame *f, const uint8_t *src, 00070 int linelen, int height) { 00071 int i, j; 00072 uint8_t *dst = f->data[0]; 00073 dst += (height - 1) * f->linesize[0]; 00074 for (i = height; i; i--) { 00075 for (j = linelen / 2; j; j--) { 00076 dst[0] = src[1]; 00077 dst[1] = src[0]; 00078 src += 2; 00079 dst += 2; 00080 } 00081 dst -= f->linesize[0] + linelen; 00082 } 00083 } 00084 00085 static void copy_frame_32(AVFrame *f, const uint8_t *src, 00086 int linelen, int height) { 00087 int i, j; 00088 uint8_t *dst = f->data[0]; 00089 dst += (height - 1) * f->linesize[0]; 00090 for (i = height; i; i--) { 00091 for (j = linelen / 4; j; j--) { 00092 dst[0] = src[3]; 00093 dst[1] = src[2]; 00094 dst[2] = src[1]; 00095 dst[3] = src[0]; 00096 src += 4; 00097 dst += 4; 00098 } 00099 dst -= f->linesize[0] + linelen; 00100 } 00101 } 00102 00103 static void add_frame_16(AVFrame *f, const uint8_t *src, 00104 int linelen, int height) { 00105 int i, j; 00106 uint8_t *dst = f->data[0]; 00107 dst += (height - 1) * f->linesize[0]; 00108 for (i = height; i; i--) { 00109 for (j = linelen / 2; j; j--) { 00110 dst[0] += src[1]; 00111 dst[1] += src[0]; 00112 src += 2; 00113 dst += 2; 00114 } 00115 dst -= f->linesize[0] + linelen; 00116 } 00117 } 00118 00119 static void add_frame_32(AVFrame *f, const uint8_t *src, 00120 int linelen, int height) { 00121 int i, j; 00122 uint8_t *dst = f->data[0]; 00123 dst += (height - 1) * f->linesize[0]; 00124 for (i = height; i; i--) { 00125 for (j = linelen / 4; j; j--) { 00126 dst[0] += src[3]; 00127 dst[1] += src[2]; 00128 dst[2] += src[1]; 00129 dst[3] += src[0]; 00130 src += 4; 00131 dst += 4; 00132 } 00133 dst -= f->linesize[0] + linelen; 00134 } 00135 } 00136 #endif 00137 00138 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, 00139 AVPacket *avpkt) { 00140 const uint8_t *buf = avpkt->data; 00141 int buf_size = avpkt->size; 00142 CamStudioContext *c = avctx->priv_data; 00143 AVFrame *picture = data; 00144 00145 if (buf_size < 2) { 00146 av_log(avctx, AV_LOG_ERROR, "coded frame too small\n"); 00147 return -1; 00148 } 00149 00150 if (c->pic.data[0]) 00151 avctx->release_buffer(avctx, &c->pic); 00152 c->pic.reference = 1; 00153 c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE | 00154 FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; 00155 if (avctx->get_buffer(avctx, &c->pic) < 0) { 00156 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00157 return -1; 00158 } 00159 00160 // decompress data 00161 switch ((buf[0] >> 1) & 7) { 00162 case 0: { // lzo compression 00163 int outlen = c->decomp_size, inlen = buf_size - 2; 00164 if (av_lzo1x_decode(c->decomp_buf, &outlen, &buf[2], &inlen)) 00165 av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n"); 00166 break; 00167 } 00168 case 1: { // zlib compression 00169 #if CONFIG_ZLIB 00170 unsigned long dlen = c->decomp_size; 00171 if (uncompress(c->decomp_buf, &dlen, &buf[2], buf_size - 2) != Z_OK) 00172 av_log(avctx, AV_LOG_ERROR, "error during zlib decompression\n"); 00173 break; 00174 #else 00175 av_log(avctx, AV_LOG_ERROR, "compiled without zlib support\n"); 00176 return -1; 00177 #endif 00178 } 00179 default: 00180 av_log(avctx, AV_LOG_ERROR, "unknown compression\n"); 00181 return -1; 00182 } 00183 00184 // flip upside down, add difference frame 00185 if (buf[0] & 1) { // keyframe 00186 c->pic.pict_type = AV_PICTURE_TYPE_I; 00187 c->pic.key_frame = 1; 00188 switch (c->bpp) { 00189 case 16: 00190 copy_frame_16(&c->pic, c->decomp_buf, c->linelen, c->height); 00191 break; 00192 case 32: 00193 copy_frame_32(&c->pic, c->decomp_buf, c->linelen, c->height); 00194 break; 00195 default: 00196 copy_frame_default(&c->pic, c->decomp_buf, FFALIGN(c->linelen, 4), 00197 c->linelen, c->height); 00198 } 00199 } else { 00200 c->pic.pict_type = AV_PICTURE_TYPE_P; 00201 c->pic.key_frame = 0; 00202 switch (c->bpp) { 00203 case 16: 00204 add_frame_16(&c->pic, c->decomp_buf, c->linelen, c->height); 00205 break; 00206 case 32: 00207 add_frame_32(&c->pic, c->decomp_buf, c->linelen, c->height); 00208 break; 00209 default: 00210 add_frame_default(&c->pic, c->decomp_buf, FFALIGN(c->linelen, 4), 00211 c->linelen, c->height); 00212 } 00213 } 00214 00215 *picture = c->pic; 00216 *data_size = sizeof(AVFrame); 00217 return buf_size; 00218 } 00219 00220 static av_cold int decode_init(AVCodecContext *avctx) { 00221 CamStudioContext *c = avctx->priv_data; 00222 int stride; 00223 switch (avctx->bits_per_coded_sample) { 00224 case 16: avctx->pix_fmt = PIX_FMT_RGB555; break; 00225 case 24: avctx->pix_fmt = PIX_FMT_BGR24; break; 00226 case 32: avctx->pix_fmt = PIX_FMT_RGB32; break; 00227 default: 00228 av_log(avctx, AV_LOG_ERROR, 00229 "CamStudio codec error: invalid depth %i bpp\n", 00230 avctx->bits_per_coded_sample); 00231 return AVERROR_INVALIDDATA; 00232 } 00233 c->bpp = avctx->bits_per_coded_sample; 00234 c->pic.data[0] = NULL; 00235 c->linelen = avctx->width * avctx->bits_per_coded_sample / 8; 00236 c->height = avctx->height; 00237 stride = c->linelen; 00238 if (avctx->bits_per_coded_sample == 24) 00239 stride = FFALIGN(stride, 4); 00240 c->decomp_size = c->height * stride; 00241 c->decomp_buf = av_malloc(c->decomp_size + AV_LZO_OUTPUT_PADDING); 00242 if (!c->decomp_buf) { 00243 av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); 00244 return AVERROR(ENOMEM); 00245 } 00246 return 0; 00247 } 00248 00249 static av_cold int decode_end(AVCodecContext *avctx) { 00250 CamStudioContext *c = avctx->priv_data; 00251 av_freep(&c->decomp_buf); 00252 if (c->pic.data[0]) 00253 avctx->release_buffer(avctx, &c->pic); 00254 return 0; 00255 } 00256 00257 AVCodec ff_cscd_decoder = { 00258 "camstudio", 00259 AVMEDIA_TYPE_VIDEO, 00260 CODEC_ID_CSCD, 00261 sizeof(CamStudioContext), 00262 decode_init, 00263 NULL, 00264 decode_end, 00265 decode_frame, 00266 CODEC_CAP_DR1, 00267 .long_name = NULL_IF_CONFIG_SMALL("CamStudio"), 00268 }; 00269