Libav
|
00001 /* 00002 * CamStudio decoder 00003 * Copyright (c) 2006 Reimar Doeffinger 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg 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 * FFmpeg 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 FFmpeg; 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, 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 += linelen; 00046 dst -= f->linesize[0]; 00047 } 00048 } 00049 00050 static void add_frame_default(AVFrame *f, const uint8_t *src, 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 dst -= f->linesize[0] + linelen; 00059 } 00060 } 00061 00062 #if !HAVE_BIGENDIAN 00063 #define copy_frame_16 copy_frame_default 00064 #define copy_frame_32 copy_frame_default 00065 #define add_frame_16 add_frame_default 00066 #define add_frame_32 add_frame_default 00067 #else 00068 static void copy_frame_16(AVFrame *f, const uint8_t *src, 00069 int linelen, int height) { 00070 int i, j; 00071 uint8_t *dst = f->data[0]; 00072 dst += (height - 1) * f->linesize[0]; 00073 for (i = height; i; i--) { 00074 for (j = linelen / 2; j; j--) { 00075 dst[0] = src[1]; 00076 dst[1] = src[0]; 00077 src += 2; 00078 dst += 2; 00079 } 00080 dst -= f->linesize[0] + linelen; 00081 } 00082 } 00083 00084 static void copy_frame_32(AVFrame *f, const uint8_t *src, 00085 int linelen, int height) { 00086 int i, j; 00087 uint8_t *dst = f->data[0]; 00088 dst += (height - 1) * f->linesize[0]; 00089 for (i = height; i; i--) { 00090 for (j = linelen / 4; j; j--) { 00091 dst[0] = src[3]; 00092 dst[1] = src[2]; 00093 dst[2] = src[1]; 00094 dst[3] = src[0]; 00095 src += 4; 00096 dst += 4; 00097 } 00098 dst -= f->linesize[0] + linelen; 00099 } 00100 } 00101 00102 static void add_frame_16(AVFrame *f, const uint8_t *src, 00103 int linelen, int height) { 00104 int i, j; 00105 uint8_t *dst = f->data[0]; 00106 dst += (height - 1) * f->linesize[0]; 00107 for (i = height; i; i--) { 00108 for (j = linelen / 2; j; j--) { 00109 dst[0] += src[1]; 00110 dst[1] += src[0]; 00111 src += 2; 00112 dst += 2; 00113 } 00114 dst -= f->linesize[0] + linelen; 00115 } 00116 } 00117 00118 static void add_frame_32(AVFrame *f, const uint8_t *src, 00119 int linelen, int height) { 00120 int i, j; 00121 uint8_t *dst = f->data[0]; 00122 dst += (height - 1) * f->linesize[0]; 00123 for (i = height; i; i--) { 00124 for (j = linelen / 4; j; j--) { 00125 dst[0] += src[3]; 00126 dst[1] += src[2]; 00127 dst[2] += src[1]; 00128 dst[3] += src[0]; 00129 src += 4; 00130 dst += 4; 00131 } 00132 dst -= f->linesize[0] + linelen; 00133 } 00134 } 00135 #endif 00136 00137 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, 00138 AVPacket *avpkt) { 00139 const uint8_t *buf = avpkt->data; 00140 int buf_size = avpkt->size; 00141 CamStudioContext *c = avctx->priv_data; 00142 AVFrame *picture = data; 00143 00144 if (buf_size < 2) { 00145 av_log(avctx, AV_LOG_ERROR, "coded frame too small\n"); 00146 return -1; 00147 } 00148 00149 if (c->pic.data[0]) 00150 avctx->release_buffer(avctx, &c->pic); 00151 c->pic.reference = 1; 00152 c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE | 00153 FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; 00154 if (avctx->get_buffer(avctx, &c->pic) < 0) { 00155 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00156 return -1; 00157 } 00158 00159 // decompress data 00160 switch ((buf[0] >> 1) & 7) { 00161 case 0: { // lzo compression 00162 int outlen = c->decomp_size, inlen = buf_size - 2; 00163 if (av_lzo1x_decode(c->decomp_buf, &outlen, &buf[2], &inlen)) 00164 av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n"); 00165 break; 00166 } 00167 case 1: { // zlib compression 00168 #if CONFIG_ZLIB 00169 unsigned long dlen = c->decomp_size; 00170 if (uncompress(c->decomp_buf, &dlen, &buf[2], buf_size - 2) != Z_OK) 00171 av_log(avctx, AV_LOG_ERROR, "error during zlib decompression\n"); 00172 break; 00173 #else 00174 av_log(avctx, AV_LOG_ERROR, "compiled without zlib support\n"); 00175 return -1; 00176 #endif 00177 } 00178 default: 00179 av_log(avctx, AV_LOG_ERROR, "unknown compression\n"); 00180 return -1; 00181 } 00182 00183 // flip upside down, add difference frame 00184 if (buf[0] & 1) { // keyframe 00185 c->pic.pict_type = FF_I_TYPE; 00186 c->pic.key_frame = 1; 00187 switch (c->bpp) { 00188 case 16: 00189 copy_frame_16(&c->pic, c->decomp_buf, c->linelen, c->height); 00190 break; 00191 case 32: 00192 copy_frame_32(&c->pic, c->decomp_buf, c->linelen, c->height); 00193 break; 00194 default: 00195 copy_frame_default(&c->pic, c->decomp_buf, c->linelen, c->height); 00196 } 00197 } else { 00198 c->pic.pict_type = FF_P_TYPE; 00199 c->pic.key_frame = 0; 00200 switch (c->bpp) { 00201 case 16: 00202 add_frame_16(&c->pic, c->decomp_buf, c->linelen, c->height); 00203 break; 00204 case 32: 00205 add_frame_32(&c->pic, c->decomp_buf, c->linelen, c->height); 00206 break; 00207 default: 00208 add_frame_default(&c->pic, c->decomp_buf, c->linelen, c->height); 00209 } 00210 } 00211 00212 *picture = c->pic; 00213 *data_size = sizeof(AVFrame); 00214 return buf_size; 00215 } 00216 00217 static av_cold int decode_init(AVCodecContext *avctx) { 00218 CamStudioContext *c = avctx->priv_data; 00219 switch (avctx->bits_per_coded_sample) { 00220 case 16: avctx->pix_fmt = PIX_FMT_RGB555; break; 00221 case 24: avctx->pix_fmt = PIX_FMT_BGR24; break; 00222 case 32: avctx->pix_fmt = PIX_FMT_RGB32; break; 00223 default: 00224 av_log(avctx, AV_LOG_ERROR, 00225 "CamStudio codec error: invalid depth %i bpp\n", 00226 avctx->bits_per_coded_sample); 00227 return 1; 00228 } 00229 c->bpp = avctx->bits_per_coded_sample; 00230 c->pic.data[0] = NULL; 00231 c->linelen = avctx->width * avctx->bits_per_coded_sample / 8; 00232 c->height = avctx->height; 00233 c->decomp_size = c->height * c->linelen; 00234 c->decomp_buf = av_malloc(c->decomp_size + AV_LZO_OUTPUT_PADDING); 00235 if (!c->decomp_buf) { 00236 av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); 00237 return 1; 00238 } 00239 return 0; 00240 } 00241 00242 static av_cold int decode_end(AVCodecContext *avctx) { 00243 CamStudioContext *c = avctx->priv_data; 00244 av_freep(&c->decomp_buf); 00245 if (c->pic.data[0]) 00246 avctx->release_buffer(avctx, &c->pic); 00247 return 0; 00248 } 00249 00250 AVCodec cscd_decoder = { 00251 "camstudio", 00252 AVMEDIA_TYPE_VIDEO, 00253 CODEC_ID_CSCD, 00254 sizeof(CamStudioContext), 00255 decode_init, 00256 NULL, 00257 decode_end, 00258 decode_frame, 00259 CODEC_CAP_DR1, 00260 .long_name = NULL_IF_CONFIG_SMALL("CamStudio"), 00261 }; 00262