Skip to content

Commit

Permalink
TechSmith Camtasia (TSCC) video decoder, courtesy of Konstantin Shishkov
Browse files Browse the repository at this point in the history
Originally committed as revision 3390 to svn://svn.ffmpeg.org/ffmpeg/trunk
  • Loading branch information
multimediamike committed Aug 14, 2004
1 parent df84ac2 commit 9d53d58
Show file tree
Hide file tree
Showing 8 changed files with 304 additions and 2 deletions.
3 changes: 2 additions & 1 deletion CREDITS
@@ -1,5 +1,5 @@
This file contains the name of the people who have contributed to
ffmpeg. The names are sorted alphabetically.
ffmpeg. The names are sorted alphabetically by last name.

Fabrice Bellard
Patrice Bensoussan
Expand All @@ -23,6 +23,7 @@ Michael Niedermayer
Fran�ois Revol
Roman Shaposhnik
Dieter Shirley
Konstantin Shishkov
Juan J. Sierralta
Ewald Snel
Leon van Stuivenberg
Expand Down
3 changes: 3 additions & 0 deletions Changelog
@@ -1,3 +1,6 @@
version <next>
- TechSmith Camtasia (TSCC) video decoder

version 0.4.9-pre1:

- DV encoder, DV muxer
Expand Down
1 change: 1 addition & 0 deletions doc/ffmpeg-doc.texi
Expand Up @@ -752,6 +752,7 @@ following image formats are supported:
@item VMD Video @tab @tab X @tab used in Sierra VMD files
@item MSZH @tab @tab X @tab Part of LCL
@item ZLIB @tab X @tab X @tab Part of LCL, encoder experimental
@item TechSmith Camtasia @tab @tab X @tab fourcc: TSCC
@end multitable

@code{X} means that the encoding (resp. decoding) is supported.
Expand Down
2 changes: 1 addition & 1 deletion libavcodec/Makefile
Expand Up @@ -20,7 +20,7 @@ OBJS= common.o utils.o mem.o allcodecs.o \
roqvideo.o dpcm.o interplayvideo.o xan.o rpza.o cinepak.o msrle.o \
msvideo1.o vqavideo.o idcinvideo.o adx.o rational.o faandct.o 8bps.o \
smc.o parser.o flicvideo.o truemotion1.o vmdav.o lcl.o qtrle.o g726.o \
flac.o vp3dsp.o integer.o snow.o
flac.o vp3dsp.o integer.o snow.o tscc.o

ifeq ($(AMR_NB),yes)
ifeq ($(AMR_NB_FIXED),yes)
Expand Down
1 change: 1 addition & 0 deletions libavcodec/allcodecs.c
Expand Up @@ -166,6 +166,7 @@ void avcodec_register_all(void)
register_avcodec(&xan_dpcm_decoder);
register_avcodec(&qtrle_decoder);
register_avcodec(&flac_decoder);
register_avcodec(&tscc_decoder);
#endif /* CONFIG_DECODERS */

#ifdef AMR_NB
Expand Down
2 changes: 2 additions & 0 deletions libavcodec/avcodec.h
Expand Up @@ -99,6 +99,7 @@ enum CodecID {
CODEC_ID_ZLIB,
CODEC_ID_QTRLE,
CODEC_ID_SNOW,
CODEC_ID_TSCC,

/* various pcm "codecs" */
CODEC_ID_PCM_S16LE,
Expand Down Expand Up @@ -1844,6 +1845,7 @@ extern AVCodec interplay_dpcm_decoder;
extern AVCodec xan_dpcm_decoder;
extern AVCodec qtrle_decoder;
extern AVCodec flac_decoder;
extern AVCodec tscc_decoder;

/* pcm codecs */
#define PCM_CODEC(id, name) \
Expand Down
293 changes: 293 additions & 0 deletions libavcodec/tscc.c
@@ -0,0 +1,293 @@
/*
* 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 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 char *src = c->decomp_buf;
unsigned char *output = c->pic.data[0];
int p1, p2, line=c->height, pos=0, i;
while(src < c->decomp_buf + c->decomp_size) {
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];
pos = 0;
continue;
} else if(p2 == 1) { //End-of-picture
return 0;
} else if(p2 == 2) { //Skip
p1 = *src++;
p2 = *src++;
line -= p2;
pos += p1;
output = c->pic.data[0] + line * c->pic.linesize[0] + pos * (c->bpp / 8);
continue;
}
// Copy data
for(i = 0; i < p2 * (c->bpp / 8); i++) {
*output++ = *src++;
}
pos += p2;
} else { //Run of pixels
int pix[3]; //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;
}
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;
}
}
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;

/* no supplementary picture */
if (buf_size == 0)
return 0;

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;
}
encoded = c->decomp_buf;
len = c->decomp_size;
if(zret != Z_DATA_ERROR)
decode_rle(c);
#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;

#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: av_log(avctx, AV_LOG_ERROR, "Camtasia warning: RGB8 is just guessed\n");
avctx->pix_fmt = PIX_FMT_PAL8;
break;
case 16: avctx->pix_fmt = PIX_FMT_RGB555;break;
case 24: av_log(avctx, AV_LOG_ERROR, "Camtasia warning: RGB24 is just guessed\n");
avctx->pix_fmt = PIX_FMT_BGR24;
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;
av_log(avctx, AV_LOG_INFO, "bpp=%i \n\n\n", c->bpp);
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;

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,
};

1 change: 1 addition & 0 deletions libavformat/avienc.c
Expand Up @@ -165,6 +165,7 @@ const CodecTag codec_bmp_tags[] = {
{ CODEC_ID_4XM, MKTAG('4', 'X', 'M', 'V') },
{ CODEC_ID_FLV1, MKTAG('F', 'L', 'V', '1') },
{ CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', '1') },
{ CODEC_ID_TSCC, MKTAG('t', 's', 'c', 'c') },
{ CODEC_ID_RAWVIDEO, 0 },
{ 0, 0 },
};
Expand Down

0 comments on commit 9d53d58

Please sign in to comment.