1/* 2 * TechSmith Camtasia decoder 3 * Copyright (c) 2004 Konstantin Shishkov 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * TechSmith Camtasia decoder 25 * 26 * Fourcc: TSCC 27 * 28 * Codec is very simple: 29 * it codes picture (picture difference, really) 30 * with algorithm almost identical to Windows RLE8, 31 * only without padding and with greater pixel sizes, 32 * then this coded picture is packed with ZLib 33 * 34 * Supports: BGR8,BGR555,BGR24 - only BGR8 and BGR555 tested 35 */ 36 37#include <stdio.h> 38#include <stdlib.h> 39 40#include "avcodec.h" 41#include "codec_internal.h" 42#include "decode.h" 43#include "internal.h" 44#include "msrledec.h" 45#include "zlib_wrapper.h" 46 47#include <zlib.h> 48 49typedef struct TsccContext { 50 51 AVCodecContext *avctx; 52 AVFrame *frame; 53 54 // Bits per pixel 55 int bpp; 56 // Decompressed data size 57 unsigned int decomp_size; 58 // Decompression buffer 59 unsigned char* decomp_buf; 60 GetByteContext gb; 61 int height; 62 FFZStream zstream; 63 64 uint32_t pal[256]; 65} CamtasiaContext; 66 67static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, 68 int *got_frame, AVPacket *avpkt) 69{ 70 const uint8_t *buf = avpkt->data; 71 int buf_size = avpkt->size; 72 CamtasiaContext * const c = avctx->priv_data; 73 z_stream *const zstream = &c->zstream.zstream; 74 AVFrame *frame = c->frame; 75 int ret; 76 int palette_has_changed = 0; 77 78 if (c->avctx->pix_fmt == AV_PIX_FMT_PAL8) { 79 palette_has_changed = ff_copy_palette(c->pal, avpkt, avctx); 80 } 81 82 ret = inflateReset(zstream); 83 if (ret != Z_OK) { 84 av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret); 85 return AVERROR_UNKNOWN; 86 } 87 zstream->next_in = buf; 88 zstream->avail_in = buf_size; 89 zstream->next_out = c->decomp_buf; 90 zstream->avail_out = c->decomp_size; 91 ret = inflate(zstream, Z_FINISH); 92 // Z_DATA_ERROR means empty picture 93 if (ret == Z_DATA_ERROR && !palette_has_changed) { 94 return buf_size; 95 } 96 97 if ((ret != Z_OK) && (ret != Z_STREAM_END) && (ret != Z_DATA_ERROR)) { 98 av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", ret); 99 return AVERROR_UNKNOWN; 100 } 101 102 if ((ret = ff_reget_buffer(avctx, frame, 0)) < 0) 103 return ret; 104 105 if (ret != Z_DATA_ERROR) { 106 bytestream2_init(&c->gb, c->decomp_buf, 107 c->decomp_size - zstream->avail_out); 108 ff_msrle_decode(avctx, frame, c->bpp, &c->gb); 109 } 110 111 /* make the palette available on the way out */ 112 if (c->avctx->pix_fmt == AV_PIX_FMT_PAL8) { 113 frame->palette_has_changed = palette_has_changed; 114 memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); 115 } 116 117 if ((ret = av_frame_ref(rframe, frame)) < 0) 118 return ret; 119 *got_frame = 1; 120 121 /* always report that the buffer was completely consumed */ 122 return buf_size; 123} 124 125static av_cold int decode_init(AVCodecContext *avctx) 126{ 127 CamtasiaContext * const c = avctx->priv_data; 128 129 c->avctx = avctx; 130 131 c->height = avctx->height; 132 133 switch(avctx->bits_per_coded_sample){ 134 case 8: avctx->pix_fmt = AV_PIX_FMT_PAL8; break; 135 case 16: avctx->pix_fmt = AV_PIX_FMT_RGB555; break; 136 case 24: 137 avctx->pix_fmt = AV_PIX_FMT_BGR24; 138 break; 139 case 32: avctx->pix_fmt = AV_PIX_FMT_0RGB32; break; 140 default: av_log(avctx, AV_LOG_ERROR, "Camtasia error: unknown depth %i bpp\n", avctx->bits_per_coded_sample); 141 return AVERROR_PATCHWELCOME; 142 } 143 c->bpp = avctx->bits_per_coded_sample; 144 // buffer size for RLE 'best' case when 2-byte code precedes each pixel and there may be padding after it too 145 c->decomp_size = (((avctx->width * c->bpp + 7) >> 3) + 3 * avctx->width + 2) * avctx->height + 2; 146 147 /* Allocate decompression buffer */ 148 if (c->decomp_size) { 149 if (!(c->decomp_buf = av_malloc(c->decomp_size))) { 150 av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); 151 return AVERROR(ENOMEM); 152 } 153 } 154 155 c->frame = av_frame_alloc(); 156 if (!c->frame) 157 return AVERROR(ENOMEM); 158 159 return ff_inflate_init(&c->zstream, avctx); 160} 161 162static av_cold int decode_end(AVCodecContext *avctx) 163{ 164 CamtasiaContext * const c = avctx->priv_data; 165 166 av_freep(&c->decomp_buf); 167 av_frame_free(&c->frame); 168 ff_inflate_end(&c->zstream); 169 170 return 0; 171} 172 173const FFCodec ff_tscc_decoder = { 174 .p.name = "camtasia", 175 .p.long_name = NULL_IF_CONFIG_SMALL("TechSmith Screen Capture Codec"), 176 .p.type = AVMEDIA_TYPE_VIDEO, 177 .p.id = AV_CODEC_ID_TSCC, 178 .priv_data_size = sizeof(CamtasiaContext), 179 .init = decode_init, 180 .close = decode_end, 181 FF_CODEC_DECODE_CB(decode_frame), 182 .p.capabilities = AV_CODEC_CAP_DR1, 183 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 184}; 185