tscc.c 5.88 KB
Newer Older
1 2 3 4
/*
 * TechSmith Camtasia decoder
 * Copyright (c) 2004 Konstantin Shishkov
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * 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 14 15 16 17
 * 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
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 24 25 26 27 28 29 30 31 32 33
 */

/**
 * @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
 *
Mike Melanson's avatar
Mike Melanson committed
34
 * Supports: BGR8,BGR555,BGR24 - only BGR8 and BGR555 tested
35 36 37 38 39 40 41
 *
 */

#include <stdio.h>
#include <stdlib.h>

#include "avcodec.h"
42
#include "msrledec.h"
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

#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 a frame
 *
 */
Michael Niedermayer's avatar
Michael Niedermayer committed
74
static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, const uint8_t *buf, int buf_size)
75
{
76
    CamtasiaContext * const c = avctx->priv_data;
Michael Niedermayer's avatar
Michael Niedermayer committed
77
    const unsigned char *encoded = buf;
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    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;
    }
112 113


114
    if(zret != Z_DATA_ERROR)
115
        ff_msrle_decode(avctx, &c->pic, c->bpp, c->decomp_buf, c->zstream.avail_out);
116

Mike Melanson's avatar
Mike Melanson committed
117 118 119 120 121 122 123 124 125
    /* 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;
        }
    }

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
#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
 *
 */
145
static av_cold int decode_init(AVCodecContext *avctx)
146
{
147
    CamtasiaContext * const c = avctx->priv_data;
148 149 150 151 152 153 154
    int zret; // Zlib return code

    c->avctx = avctx;

    c->pic.data[0] = NULL;
    c->height = avctx->height;

155
    if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) {
156 157 158
        return 1;
    }

159 160
#ifdef CONFIG_ZLIB
    // Needed if zlib unused or init aborted before inflateInit
161
    memset(&(c->zstream), 0, sizeof(z_stream));
162 163 164 165
#else
    av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n");
    return 1;
#endif
166
    switch(avctx->bits_per_coded_sample){
Mike Melanson's avatar
Mike Melanson committed
167 168
    case  8: avctx->pix_fmt = PIX_FMT_PAL8; break;
    case 16: avctx->pix_fmt = PIX_FMT_RGB555; break;
Roberto Togni's avatar
Roberto Togni committed
169
    case 24:
170 171
             avctx->pix_fmt = PIX_FMT_BGR24;
             break;
172
    case 32: avctx->pix_fmt = PIX_FMT_RGB32; break;
173
    default: av_log(avctx, AV_LOG_ERROR, "Camtasia error: unknown depth %i bpp\n", avctx->bits_per_coded_sample);
174
             return -1;
175
    }
176
    c->bpp = avctx->bits_per_coded_sample;
Mike Melanson's avatar
Mike Melanson committed
177
    c->decomp_size = (avctx->width * c->bpp + (avctx->width + 254) / 255 + 2) * avctx->height + 2;//RLE in the 'best' case
178 179 180 181 182 183 184 185

    /* 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;
        }
    }
186

187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
#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
 *
 */
208
static av_cold int decode_end(AVCodecContext *avctx)
209
{
210
    CamtasiaContext * const c = avctx->priv_data;
211

Michael Niedermayer's avatar
Michael Niedermayer committed
212 213
    av_freep(&c->decomp_buf);

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
    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,
233
        .long_name = NULL_IF_CONFIG_SMALL("TechSmith Screen Capture Codec"),
234 235
};