|
808
|
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 /**
|
|
|
24 * @file tscc.c
|
|
|
25 * TechSmith Camtasia decoder
|
|
|
26 *
|
|
|
27 * Fourcc: TSCC
|
|
|
28 *
|
|
|
29 * Codec is very simple:
|
|
|
30 * it codes picture (picture difference, really)
|
|
|
31 * with algorithm almost identical to Windows RLE8,
|
|
|
32 * only without padding and with greater pixel sizes,
|
|
|
33 * then this coded picture is packed with ZLib
|
|
|
34 *
|
|
|
35 * Supports: BGR8,BGR555,BGR24 - only BGR8 and BGR555 tested
|
|
|
36 *
|
|
|
37 */
|
|
|
38
|
|
|
39 #include <stdio.h>
|
|
|
40 #include <stdlib.h>
|
|
|
41
|
|
|
42 #include "common.h"
|
|
|
43 #include "avcodec.h"
|
|
|
44
|
|
|
45 #ifdef CONFIG_ZLIB
|
|
|
46 #include <zlib.h>
|
|
|
47 #endif
|
|
|
48
|
|
|
49
|
|
|
50 /*
|
|
|
51 * Decoder context
|
|
|
52 */
|
|
|
53 typedef struct TsccContext {
|
|
|
54
|
|
|
55 AVCodecContext *avctx;
|
|
|
56 AVFrame pic;
|
|
|
57
|
|
|
58 // Bits per pixel
|
|
|
59 int bpp;
|
|
|
60 // Decompressed data size
|
|
|
61 unsigned int decomp_size;
|
|
|
62 // Decompression buffer
|
|
|
63 unsigned char* decomp_buf;
|
|
|
64 int height;
|
|
|
65 #ifdef CONFIG_ZLIB
|
|
|
66 z_stream zstream;
|
|
|
67 #endif
|
|
|
68 } CamtasiaContext;
|
|
|
69
|
|
|
70 /*
|
|
|
71 *
|
|
|
72 * Decode RLE - almost identical to Windows BMP RLE8
|
|
|
73 * and enhanced to bigger color depths
|
|
|
74 *
|
|
|
75 */
|
|
|
76
|
|
|
77 static int decode_rle(CamtasiaContext *c, unsigned int srcsize)
|
|
|
78 {
|
|
|
79 unsigned char *src = c->decomp_buf;
|
|
|
80 unsigned char *output, *output_end;
|
|
|
81 int p1, p2, line=c->height, pos=0, i;
|
|
|
82 uint16_t pix16;
|
|
|
83 uint32_t pix32;
|
|
|
84
|
|
|
85 output = c->pic.data[0] + (c->height - 1) * c->pic.linesize[0];
|
|
|
86 output_end = c->pic.data[0] + (c->height) * c->pic.linesize[0];
|
|
|
87 while(src < c->decomp_buf + srcsize) {
|
|
|
88 p1 = *src++;
|
|
|
89 if(p1 == 0) { //Escape code
|
|
|
90 p2 = *src++;
|
|
|
91 if(p2 == 0) { //End-of-line
|
|
|
92 output = c->pic.data[0] + (--line) * c->pic.linesize[0];
|
|
|
93 if (line < 0)
|
|
|
94 return -1;
|
|
|
95 pos = 0;
|
|
|
96 continue;
|
|
|
97 } else if(p2 == 1) { //End-of-picture
|
|
|
98 return 0;
|
|
|
99 } else if(p2 == 2) { //Skip
|
|
|
100 p1 = *src++;
|
|
|
101 p2 = *src++;
|
|
|
102 line -= p2;
|
|
|
103 if (line < 0)
|
|
|
104 return -1;
|
|
|
105 pos += p1;
|
|
|
106 output = c->pic.data[0] + line * c->pic.linesize[0] + pos * (c->bpp / 8);
|
|
|
107 continue;
|
|
|
108 }
|
|
|
109 // Copy data
|
|
|
110 if (output + p2 * (c->bpp / 8) > output_end) {
|
|
|
111 src += p2 * (c->bpp / 8);
|
|
|
112 continue;
|
|
|
113 }
|
|
|
114 if ((c->bpp == 8) || (c->bpp == 24)) {
|
|
|
115 for(i = 0; i < p2 * (c->bpp / 8); i++) {
|
|
|
116 *output++ = *src++;
|
|
|
117 }
|
|
|
118 // RLE8 copy is actually padded - and runs are not!
|
|
|
119 if(c->bpp == 8 && (p2 & 1)) {
|
|
|
120 src++;
|
|
|
121 }
|
|
|
122 } else if (c->bpp == 16) {
|
|
|
123 for(i = 0; i < p2; i++) {
|
|
|
124 pix16 = LE_16(src);
|
|
|
125 src += 2;
|
|
|
126 *(uint16_t*)output = pix16;
|
|
|
127 output += 2;
|
|
|
128 }
|
|
|
129 } else if (c->bpp == 32) {
|
|
|
130 for(i = 0; i < p2; i++) {
|
|
|
131 pix32 = LE_32(src);
|
|
|
132 src += 4;
|
|
|
133 *(uint32_t*)output = pix32;
|
|
|
134 output += 4;
|
|
|
135 }
|
|
|
136 }
|
|
|
137 pos += p2;
|
|
|
138 } else { //Run of pixels
|
|
|
139 int pix[4]; //original pixel
|
|
|
140 switch(c->bpp){
|
|
|
141 case 8: pix[0] = *src++;
|
|
|
142 break;
|
|
|
143 case 16: pix16 = LE_16(src);
|
|
|
144 src += 2;
|
|
|
145 *(uint16_t*)pix = pix16;
|
|
|
146 break;
|
|
|
147 case 24: pix[0] = *src++;
|
|
|
148 pix[1] = *src++;
|
|
|
149 pix[2] = *src++;
|
|
|
150 break;
|
|
|
151 case 32: pix32 = LE_32(src);
|
|
|
152 src += 4;
|
|
|
153 *(uint32_t*)pix = pix32;
|
|
|
154 break;
|
|
|
155 }
|
|
|
156 if (output + p1 * (c->bpp / 8) > output_end)
|
|
|
157 continue;
|
|
|
158 for(i = 0; i < p1; i++) {
|
|
|
159 switch(c->bpp){
|
|
|
160 case 8: *output++ = pix[0];
|
|
|
161 break;
|
|
|
162 case 16: *(uint16_t*)output = pix16;
|
|
|
163 output += 2;
|
|
|
164 break;
|
|
|
165 case 24: *output++ = pix[0];
|
|
|
166 *output++ = pix[1];
|
|
|
167 *output++ = pix[2];
|
|
|
168 break;
|
|
|
169 case 32: *(uint32_t*)output = pix32;
|
|
|
170 output += 4;
|
|
|
171 break;
|
|
|
172 }
|
|
|
173 }
|
|
|
174 pos += p1;
|
|
|
175 }
|
|
|
176 }
|
|
|
177
|
|
|
178 av_log(c->avctx, AV_LOG_ERROR, "Camtasia warning: no End-of-picture code\n");
|
|
|
179 return 1;
|
|
|
180 }
|
|
|
181
|
|
|
182 /*
|
|
|
183 *
|
|
|
184 * Decode a frame
|
|
|
185 *
|
|
|
186 */
|
|
|
187 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size)
|
|
|
188 {
|
|
|
189 CamtasiaContext * const c = (CamtasiaContext *)avctx->priv_data;
|
|
|
190 unsigned char *encoded = (unsigned char *)buf;
|
|
|
191 unsigned char *outptr;
|
|
|
192 #ifdef CONFIG_ZLIB
|
|
|
193 int zret; // Zlib return code
|
|
|
194 #endif
|
|
|
195 int len = buf_size;
|
|
|
196
|
|
|
197 if(c->pic.data[0])
|
|
|
198 avctx->release_buffer(avctx, &c->pic);
|
|
|
199
|
|
|
200 c->pic.reference = 1;
|
|
|
201 c->pic.buffer_hints = FF_BUFFER_HINTS_VALID;
|
|
|
202 if(avctx->get_buffer(avctx, &c->pic) < 0){
|
|
|
203 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
|
|
|
204 return -1;
|
|
|
205 }
|
|
|
206
|
|
|
207 outptr = c->pic.data[0]; // Output image pointer
|
|
|
208
|
|
|
209 #ifdef CONFIG_ZLIB
|
|
|
210 zret = inflateReset(&(c->zstream));
|
|
|
211 if (zret != Z_OK) {
|
|
|
212 av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret);
|
|
|
213 return -1;
|
|
|
214 }
|
|
|
215 c->zstream.next_in = encoded;
|
|
|
216 c->zstream.avail_in = len;
|
|
|
217 c->zstream.next_out = c->decomp_buf;
|
|
|
218 c->zstream.avail_out = c->decomp_size;
|
|
|
219 zret = inflate(&(c->zstream), Z_FINISH);
|
|
|
220 // Z_DATA_ERROR means empty picture
|
|
|
221 if ((zret != Z_OK) && (zret != Z_STREAM_END) && (zret != Z_DATA_ERROR)) {
|
|
|
222 av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", zret);
|
|
|
223 return -1;
|
|
|
224 }
|
|
|
225
|
|
|
226
|
|
|
227 if(zret != Z_DATA_ERROR)
|
|
|
228 decode_rle(c, c->zstream.avail_out);
|
|
|
229
|
|
|
230 /* make the palette available on the way out */
|
|
|
231 if (c->avctx->pix_fmt == PIX_FMT_PAL8) {
|
|
|
232 memcpy(c->pic.data[1], c->avctx->palctrl->palette, AVPALETTE_SIZE);
|
|
|
233 if (c->avctx->palctrl->palette_changed) {
|
|
|
234 c->pic.palette_has_changed = 1;
|
|
|
235 c->avctx->palctrl->palette_changed = 0;
|
|
|
236 }
|
|
|
237 }
|
|
|
238
|
|
|
239 #else
|
|
|
240 av_log(avctx, AV_LOG_ERROR, "BUG! Zlib support not compiled in frame decoder.\n");
|
|
|
241 return -1;
|
|
|
242 #endif
|
|
|
243
|
|
|
244 *data_size = sizeof(AVFrame);
|
|
|
245 *(AVFrame*)data = c->pic;
|
|
|
246
|
|
|
247 /* always report that the buffer was completely consumed */
|
|
|
248 return buf_size;
|
|
|
249 }
|
|
|
250
|
|
|
251
|
|
|
252
|
|
|
253 /*
|
|
|
254 *
|
|
|
255 * Init tscc decoder
|
|
|
256 *
|
|
|
257 */
|
|
|
258 static int decode_init(AVCodecContext *avctx)
|
|
|
259 {
|
|
|
260 CamtasiaContext * const c = (CamtasiaContext *)avctx->priv_data;
|
|
|
261 int zret; // Zlib return code
|
|
|
262
|
|
|
263 c->avctx = avctx;
|
|
|
264 avctx->has_b_frames = 0;
|
|
|
265
|
|
|
266 c->pic.data[0] = NULL;
|
|
|
267 c->height = avctx->height;
|
|
|
268
|
|
|
269 if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) {
|
|
|
270 return 1;
|
|
|
271 }
|
|
|
272
|
|
|
273 #ifdef CONFIG_ZLIB
|
|
|
274 // Needed if zlib unused or init aborted before inflateInit
|
|
|
275 memset(&(c->zstream), 0, sizeof(z_stream));
|
|
|
276 #else
|
|
|
277 av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n");
|
|
|
278 return 1;
|
|
|
279 #endif
|
|
|
280 switch(avctx->bits_per_sample){
|
|
|
281 case 8: avctx->pix_fmt = PIX_FMT_PAL8; break;
|
|
|
282 case 16: avctx->pix_fmt = PIX_FMT_RGB555; break;
|
|
|
283 case 24:
|
|
|
284 avctx->pix_fmt = PIX_FMT_BGR24;
|
|
|
285 break;
|
|
|
286 case 32: avctx->pix_fmt = PIX_FMT_RGBA32; break;
|
|
|
287 default: av_log(avctx, AV_LOG_ERROR, "Camtasia error: unknown depth %i bpp\n", avctx->bits_per_sample);
|
|
|
288 return -1;
|
|
|
289 }
|
|
|
290 c->bpp = avctx->bits_per_sample;
|
|
|
291 c->decomp_size = (avctx->width * c->bpp + (avctx->width + 254) / 255 + 2) * avctx->height + 2;//RLE in the 'best' case
|
|
|
292
|
|
|
293 /* Allocate decompression buffer */
|
|
|
294 if (c->decomp_size) {
|
|
|
295 if ((c->decomp_buf = av_malloc(c->decomp_size)) == NULL) {
|
|
|
296 av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
|
|
|
297 return 1;
|
|
|
298 }
|
|
|
299 }
|
|
|
300
|
|
|
301 #ifdef CONFIG_ZLIB
|
|
|
302 c->zstream.zalloc = Z_NULL;
|
|
|
303 c->zstream.zfree = Z_NULL;
|
|
|
304 c->zstream.opaque = Z_NULL;
|
|
|
305 zret = inflateInit(&(c->zstream));
|
|
|
306 if (zret != Z_OK) {
|
|
|
307 av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret);
|
|
|
308 return 1;
|
|
|
309 }
|
|
|
310 #endif
|
|
|
311
|
|
|
312 return 0;
|
|
|
313 }
|
|
|
314
|
|
|
315
|
|
|
316
|
|
|
317 /*
|
|
|
318 *
|
|
|
319 * Uninit tscc decoder
|
|
|
320 *
|
|
|
321 */
|
|
|
322 static int decode_end(AVCodecContext *avctx)
|
|
|
323 {
|
|
|
324 CamtasiaContext * const c = (CamtasiaContext *)avctx->priv_data;
|
|
|
325
|
|
|
326 av_freep(&c->decomp_buf);
|
|
|
327
|
|
|
328 if (c->pic.data[0])
|
|
|
329 avctx->release_buffer(avctx, &c->pic);
|
|
|
330 #ifdef CONFIG_ZLIB
|
|
|
331 inflateEnd(&(c->zstream));
|
|
|
332 #endif
|
|
|
333
|
|
|
334 return 0;
|
|
|
335 }
|
|
|
336
|
|
|
337 AVCodec tscc_decoder = {
|
|
|
338 "camtasia",
|
|
|
339 CODEC_TYPE_VIDEO,
|
|
|
340 CODEC_ID_TSCC,
|
|
|
341 sizeof(CamtasiaContext),
|
|
|
342 decode_init,
|
|
|
343 NULL,
|
|
|
344 decode_end,
|
|
|
345 decode_frame,
|
|
|
346 CODEC_CAP_DR1,
|
|
|
347 };
|
|
|
348
|