Mercurial > libavcodec.hg
view tscc.c @ 2601:c31a28f27d9a libavcodec
increasing precission of the quantization parameter
this is needed as the quantization stepsize for each subband is also in this precission and insignificant changes to the wavelet like scaling its coefficients slightly differently would lead to wildly variing PSNR and bitrate
note, a encoder could also simply choose to leave the least significant bits of the quantization parameters zero which would give the exact previous behaviour except a y very tiny number of bits in the header
author | michael |
---|---|
date | Sat, 09 Apr 2005 22:15:48 +0000 |
parents | 5e9f8eef19b9 |
children | ef2149182f1c |
line wrap: on
line source
/* * TechSmith Camtasia decoder * Copyright (c) 2004 Konstantin Shishkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /** * @file tscc.c * TechSmith Camtasia decoder * * Fourcc: TSCC * * Codec is very simple: * it codes picture (picture difference, really) * with algorithm almost identical to Windows RLE8, * only without padding and with greater pixel sizes, * then this coded picture is packed with ZLib * * Supports: BGR8,BGR555,BGR24 - only BGR8 and BGR555 tested * */ #include <stdio.h> #include <stdlib.h> #include "common.h" #include "avcodec.h" #ifdef CONFIG_ZLIB #include <zlib.h> #endif /* * Decoder context */ typedef struct TsccContext { AVCodecContext *avctx; AVFrame pic; // Bits per pixel int bpp; // Decompressed data size unsigned int decomp_size; // Decompression buffer unsigned char* decomp_buf; int height; #ifdef CONFIG_ZLIB z_stream zstream; #endif } CamtasiaContext; /* * * Decode RLE - almost identical to Windows BMP RLE8 * and enhanced to bigger color depths * */ static int decode_rle(CamtasiaContext *c, unsigned int srcsize) { unsigned char *src = c->decomp_buf; unsigned char *output, *output_end; int p1, p2, line=c->height, pos=0, i; output = c->pic.data[0] + (c->height - 1) * c->pic.linesize[0]; output_end = c->pic.data[0] + (c->height) * c->pic.linesize[0]; while(src < c->decomp_buf + srcsize) { p1 = *src++; if(p1 == 0) { //Escape code p2 = *src++; if(p2 == 0) { //End-of-line output = c->pic.data[0] + (--line) * c->pic.linesize[0]; if (line < 0) return -1; pos = 0; continue; } else if(p2 == 1) { //End-of-picture return 0; } else if(p2 == 2) { //Skip p1 = *src++; p2 = *src++; line -= p2; if (line < 0) return -1; pos += p1; output = c->pic.data[0] + line * c->pic.linesize[0] + pos * (c->bpp / 8); continue; } // Copy data if (output + p2 * (c->bpp / 8) > output_end) { src += p2 * (c->bpp / 8); continue; } for(i = 0; i < p2 * (c->bpp / 8); i++) { *output++ = *src++; } // RLE8 copy is actually padded - and runs are not! if(c->bpp == 8 && (p2 & 1)) { src++; } pos += p2; } else { //Run of pixels int pix[4]; //original pixel switch(c->bpp){ case 8: pix[0] = *src++; break; case 16: pix[0] = *src++; pix[1] = *src++; break; case 24: pix[0] = *src++; pix[1] = *src++; pix[2] = *src++; break; case 32: pix[0] = *src++; pix[1] = *src++; pix[2] = *src++; pix[3] = *src++; break; } if (output + p1 * (c->bpp / 8) > output_end) continue; for(i = 0; i < p1; i++) { switch(c->bpp){ case 8: *output++ = pix[0]; break; case 16: *output++ = pix[0]; *output++ = pix[1]; break; case 24: *output++ = pix[0]; *output++ = pix[1]; *output++ = pix[2]; break; case 32: *output++ = pix[0]; *output++ = pix[1]; *output++ = pix[2]; *output++ = pix[3]; break; } } pos += p1; } } av_log(c->avctx, AV_LOG_ERROR, "Camtasia warning: no End-of-picture code\n"); return 1; } /* * * Decode a frame * */ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size) { CamtasiaContext * const c = (CamtasiaContext *)avctx->priv_data; unsigned char *encoded = (unsigned char *)buf; unsigned char *outptr; #ifdef CONFIG_ZLIB int zret; // Zlib return code #endif int len = buf_size; if(c->pic.data[0]) avctx->release_buffer(avctx, &c->pic); c->pic.reference = 1; c->pic.buffer_hints = FF_BUFFER_HINTS_VALID; if(avctx->get_buffer(avctx, &c->pic) < 0){ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); return -1; } outptr = c->pic.data[0]; // Output image pointer #ifdef CONFIG_ZLIB zret = inflateReset(&(c->zstream)); if (zret != Z_OK) { av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret); return -1; } c->zstream.next_in = encoded; c->zstream.avail_in = len; c->zstream.next_out = c->decomp_buf; c->zstream.avail_out = c->decomp_size; zret = inflate(&(c->zstream), Z_FINISH); // Z_DATA_ERROR means empty picture if ((zret != Z_OK) && (zret != Z_STREAM_END) && (zret != Z_DATA_ERROR)) { av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", zret); return -1; } if(zret != Z_DATA_ERROR) decode_rle(c, c->zstream.avail_out); /* make the palette available on the way out */ if (c->avctx->pix_fmt == PIX_FMT_PAL8) { memcpy(c->pic.data[1], c->avctx->palctrl->palette, AVPALETTE_SIZE); if (c->avctx->palctrl->palette_changed) { c->pic.palette_has_changed = 1; c->avctx->palctrl->palette_changed = 0; } } #else av_log(avctx, AV_LOG_ERROR, "BUG! Zlib support not compiled in frame decoder.\n"); return -1; #endif *data_size = sizeof(AVFrame); *(AVFrame*)data = c->pic; /* always report that the buffer was completely consumed */ return buf_size; } /* * * Init tscc decoder * */ static int decode_init(AVCodecContext *avctx) { CamtasiaContext * const c = (CamtasiaContext *)avctx->priv_data; int zret; // Zlib return code c->avctx = avctx; avctx->has_b_frames = 0; c->pic.data[0] = NULL; c->height = avctx->height; if (avcodec_check_dimensions(avctx, avctx->height, avctx->width) < 0) { return 1; } #ifdef CONFIG_ZLIB // Needed if zlib unused or init aborted before inflateInit memset(&(c->zstream), 0, sizeof(z_stream)); #else av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n"); return 1; #endif switch(avctx->bits_per_sample){ case 8: avctx->pix_fmt = PIX_FMT_PAL8; break; case 16: avctx->pix_fmt = PIX_FMT_RGB555; break; case 24: avctx->pix_fmt = PIX_FMT_BGR24; break; case 32: avctx->pix_fmt = PIX_FMT_RGBA32; break; default: av_log(avctx, AV_LOG_ERROR, "Camtasia error: unknown depth %i bpp\n", avctx->bits_per_sample); return -1; } c->bpp = avctx->bits_per_sample; c->decomp_size = (avctx->width * c->bpp + (avctx->width + 254) / 255 + 2) * avctx->height + 2;//RLE in the 'best' case /* Allocate decompression buffer */ if (c->decomp_size) { if ((c->decomp_buf = av_malloc(c->decomp_size)) == NULL) { av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); return 1; } } #ifdef CONFIG_ZLIB c->zstream.zalloc = Z_NULL; c->zstream.zfree = Z_NULL; c->zstream.opaque = Z_NULL; zret = inflateInit(&(c->zstream)); if (zret != Z_OK) { av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret); return 1; } #endif return 0; } /* * * Uninit tscc decoder * */ static int decode_end(AVCodecContext *avctx) { CamtasiaContext * const c = (CamtasiaContext *)avctx->priv_data; av_freep(&c->decomp_buf); if (c->pic.data[0]) avctx->release_buffer(avctx, &c->pic); #ifdef CONFIG_ZLIB inflateEnd(&(c->zstream)); #endif return 0; } AVCodec tscc_decoder = { "camtasia", CODEC_TYPE_VIDEO, CODEC_ID_TSCC, sizeof(CamtasiaContext), decode_init, NULL, decode_end, decode_frame, CODEC_CAP_DR1, };