~ubuntu-branches/ubuntu/jaunty/xvidcap/jaunty-proposed

« back to all changes in this revision

Viewing changes to src/xtoqtf.c

  • Committer: Bazaar Package Importer
  • Author(s): Christian Marillat
  • Date: 2004-08-29 10:53:42 UTC
  • Revision ID: james.westby@ubuntu.com-20040829105342-qgmnry37eadfkoxx
Tags: upstream-1.1.3
ImportĀ upstreamĀ versionĀ 1.1.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * xtoqtf.c,
 
3
 * XImge to QT file module, todo: sound support :)
 
4
 *
 
5
 * Copyright (C) 1998 Rasca, Berlin
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * This program 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
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
20
 */
 
21
 
 
22
#include "../config.h"  /* autoconf output */
 
23
 
 
24
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <time.h>
 
27
#include <X11/Intrinsic.h>
 
28
#include <X11/StringDefs.h>
 
29
#ifdef HAVE_LIBPNG
 
30
#include <zlib.h>
 
31
#include <png.h>
 
32
#endif
 
33
#ifdef HAVE_LIBJPEG
 
34
#include <jpeglib.h>
 
35
#endif
 
36
#include "job.h"
 
37
#include "xtoqtf.h"
 
38
#include "gt.h"
 
39
#include "colors.h"
 
40
 
 
41
/* reserved space for the moov atom
 
42
 */
 
43
#define HEADER_SIZE 1024
 
44
 
 
45
/* globals */
 
46
static unsigned char *line = NULL;
 
47
static FILE *qtfp = NULL;
 
48
static int bpp; /* bits per pixel in the qt file */
 
49
static gt_atom *space_atom, *data_atom;
 
50
static int codec = GT_VID_FMT_RAW, pic_no = 0;
 
51
static int *offset = NULL;
 
52
#ifdef HAVE_LIBJPEG
 
53
static struct jpeg_compress_struct jinfo;
 
54
#endif
 
55
#ifdef HAVE_LIBPNG
 
56
static png_structp p_ptr= NULL;
 
57
static png_infop pinfo = NULL;
 
58
#endif
 
59
 
 
60
/*
 
61
 * remember offset of every frame during capturing
 
62
 */
 
63
static void
 
64
save_offset (int picno, int file_offset)
 
65
{
 
66
        static int size = 1024;
 
67
        extern int *offset;
 
68
 
 
69
        if (!offset) {
 
70
                /* alloc offsets for 1024 frames */
 
71
                offset = (int *) malloc (sizeof(int) * size);
 
72
        } else if (picno > size - 1) {
 
73
                /* realloc */
 
74
                size += 1024;
 
75
                offset = realloc (offset, sizeof (int) * size);
 
76
        }
 
77
        if (offset) {
 
78
                offset[picno] = file_offset;
 
79
#ifdef DEBUG2
 
80
                printf ("offset: %d -> %d\n", picno, file_offset);
 
81
#endif
 
82
        } else {
 
83
                perror ("save_offset()");
 
84
                exit (99);
 
85
        }
 
86
}
 
87
 
 
88
/*
 
89
 * for TrueColor and DirectColor
 
90
 * write a Qt out to the named file pointer
 
91
 */
 
92
void
 
93
XImageToQTFC (FILE *fp, XImage *image, Job *job)
 
94
{
 
95
        int row, col, i, j, pad;
 
96
        unsigned char *p8;
 
97
        unsigned short *p16;
 
98
        static int line_size = 0;
 
99
        static ColorInfo ci;
 
100
#ifdef HAVE_LIBJPEG
 
101
        static struct jpeg_error_mgr jerr;
 
102
#endif
 
103
#ifdef HAVE_LIBPNG
 
104
        static png_color_8 sig_bit;
 
105
#endif
 
106
 
 
107
#ifdef DEBUG2
 
108
        printf ("XImageToQTFC() flags=%d\n", job->flags);
 
109
#endif
 
110
        /* destroy the old one, we need this static pointer to could
 
111
         * access it also in MngClean()
 
112
         */
 
113
 
 
114
        if ( job->state & VC_START ) {
 
115
                /* it's the first call, prepare some stuff
 
116
                 */
 
117
#ifdef DEBUG
 
118
                dump_ximage_info (image);
 
119
#endif
 
120
                /* xanim don't know about free or skip, so we use a dummy mdat
 
121
                 * atom here */
 
122
                qtfp = fp;
 
123
                space_atom = gt_alloc_atom (GTA_skip, HEADER_SIZE-8);
 
124
                data_atom = gt_alloc_atom (GTA_movie_data, 0);
 
125
                gt_write_atom (space_atom, qtfp);
 
126
                gt_write_atom (data_atom, qtfp);
 
127
                pic_no = 0;
 
128
                save_offset (pic_no++, ftell(qtfp));
 
129
                GetColorInfo (image, &ci);
 
130
 
 
131
                if (job->target == CAP_QTJ) {
 
132
                        /* we use jpeg codec */
 
133
#ifdef HAVE_LIBJPEG
 
134
                        jinfo.err = jpeg_std_error (&jerr);
 
135
                        jpeg_create_compress (&jinfo);
 
136
                        jpeg_stdio_dest (&jinfo, qtfp);
 
137
                        jinfo.image_width = image->width;
 
138
                        jinfo.image_height = image->height;
 
139
                        jinfo.input_components = 3;     /* only rgb24 is supported */
 
140
                        jinfo.in_color_space = JCS_RGB;
 
141
                        jpeg_set_defaults(&jinfo);
 
142
                        /* optional parameters */
 
143
                        jpeg_set_quality (&jinfo, job->quality, TRUE);
 
144
                        jinfo.dct_method = JDCT_FASTEST;
 
145
                        jpeg_start_compress (&jinfo, TRUE);
 
146
                        codec = GT_VID_FMT_JPEG;
 
147
                        bpp = 24;
 
148
#else
 
149
                        fprintf (stderr, "Warning: JPEG not compiled in!\n");
 
150
                        codec = GT_VID_FMT_RAW;
 
151
                        bpp = image->bits_per_pixel;
 
152
#endif
 
153
                } else if (job->target == CAP_QTP) {
 
154
#ifdef  HAVE_LIBPNG
 
155
                        /* to do */
 
156
                        p_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
 
157
                                                (void *)NULL, NULL, NULL);
 
158
                        pinfo = png_create_info_struct (p_ptr);
 
159
                        if (image->bits_per_pixel == 16) {
 
160
                                sig_bit.red   = ci.red_bit_depth;
 
161
                                sig_bit.green = ci.green_bit_depth;
 
162
                                sig_bit.blue  = ci.blue_bit_depth;
 
163
                        }
 
164
                        if (0/*setjmp (p_ptr->jmpbuf)*/) {
 
165
                                printf ("fatal error!\n");
 
166
                                job->state = VC_STOP;
 
167
                                return;
 
168
                        }
 
169
                        codec = GT_VID_FMT_PNG;
 
170
                        if (image->bits_per_pixel == 32)
 
171
                                bpp = 32;       /* store with alpha */
 
172
                        else
 
173
                                bpp = 24;
 
174
#else
 
175
                        fprintf (stderr, "Warning: PNG not compiled in!\n");
 
176
                        codec = GT_VID_FMT_RAW;
 
177
                        bpp = image->bits_per_pixel;
 
178
#endif
 
179
                } else /* CAP_QTR */ {
 
180
                        codec = GT_VID_FMT_RAW;
 
181
                        bpp = image->bits_per_pixel;
 
182
                }
 
183
                line_size = image->width * bpp / 8;
 
184
                line = malloc (line_size);
 
185
        } else {
 
186
                save_offset (pic_no++, ftell(qtfp));
 
187
#ifdef HAVE_LIBJPEG
 
188
                if (codec == GT_VID_FMT_JPEG)
 
189
                        jpeg_start_compress (&jinfo, TRUE);
 
190
#endif
 
191
#ifdef HAVE_LIBPNG
 
192
                if (codec == GT_VID_FMT_PNG)
 
193
                        p_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
 
194
                                                (void *)NULL, NULL, NULL);
 
195
#endif
 
196
        }
 
197
 
 
198
#ifdef HAVE_LIBJPEG
 
199
        /* what a dirty hack, just to pass the right pointer to ->write() */
 
200
        if (codec == GT_VID_FMT_JPEG)
 
201
                fp = (void *)&jinfo;
 
202
#endif
 
203
#ifdef HAVE_LIBPNG
 
204
        if (codec == GT_VID_FMT_PNG) {
 
205
                png_init_io (p_ptr, qtfp);
 
206
                png_set_compression_level (p_ptr, job->compress);
 
207
                if (image->bits_per_pixel == 32)
 
208
                        png_set_IHDR (p_ptr, pinfo, image->width, image->height, 8,
 
209
                                PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
 
210
                                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
 
211
                else
 
212
                        png_set_IHDR (p_ptr, pinfo, image->width, image->height, 8,
 
213
                                PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
 
214
                                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
 
215
                if (image->bits_per_pixel == 16) {
 
216
                        png_set_sBIT (p_ptr, pinfo, &sig_bit);
 
217
                        png_set_shift(p_ptr, &sig_bit);
 
218
                }
 
219
                png_write_info (p_ptr, pinfo);
 
220
                fp = (void *)p_ptr;
 
221
        }
 
222
#endif
 
223
 
 
224
        /* for ZPixmap bits_per_pixel could be 1,4,8,16,24,32
 
225
         * but for Direct- and TrueColor it could only be 8,16,24,32
 
226
         */
 
227
        switch (image->bits_per_pixel) {
 
228
                case 16:
 
229
                        /* for 16bpp and 15bpp x server
 
230
                         */
 
231
                        if (codec == GT_VID_FMT_JPEG) {
 
232
                                /* this should work for 16 and 15 bpp */
 
233
                                register unsigned long
 
234
                                        r_shift0 = ci.red_shift,
 
235
                                        r_shift1 = ci.red_bit_depth,
 
236
                                        r_shift2 = ci.red_bit_depth << 1,
 
237
                                        g_shift0 = ci.green_shift,
 
238
                                        g_shift1 = ci.green_bit_depth,
 
239
                                        g_shift2 = ci.green_bit_depth << 1,
 
240
                                        b_shift0 = ci.blue_shift,
 
241
                                        b_shift1 = ci.blue_bit_depth,
 
242
                                        b_shift2 = ci.blue_bit_depth << 1;
 
243
 
 
244
                                p16 = (unsigned short *) image->data;
 
245
                                pad = (image->bytes_per_line - (image->width << 1)) >> 1;
 
246
                                for (row = 0; row < image->height; row++) {
 
247
                                        p8 = line;
 
248
                                        for (col = 0; col < image->width; col++) {
 
249
                                                *p8 = ((*p16 & image->red_mask)  >> r_shift0);
 
250
                                                if (*p8)
 
251
                                                        *p8 = (((*p8 << 8) - 1) >> r_shift1) +
 
252
                                                                        (((*p8 << 8) - 1) >> r_shift2);
 
253
                                                p8++;
 
254
                                                *p8 = ((*p16 & image->green_mask) >> g_shift0);
 
255
                                                if (*p8)
 
256
                                                        *p8 = (((*p8 << 8) - 1) >> g_shift1) +
 
257
                                                                        (((*p8 << 8) - 1) >> g_shift2);
 
258
                                                p8++;
 
259
                                                *p8 = ((*p16++ & image->blue_mask) >> b_shift0);
 
260
                                                if (*p8)
 
261
                                                        *p8 = (((*p8 << 8) - 1) >> b_shift1) +
 
262
                                                                        (((*p8 << 8) - 1) >> b_shift2);
 
263
                                                p8++;
 
264
                                        }
 
265
                                        (*job->write) (line, 1, line_size, fp);
 
266
                                        p16 += pad;
 
267
                                }
 
268
                        } else if (codec == GT_VID_FMT_PNG) {
 
269
                                p16 = (unsigned short *) image->data;
 
270
                                for (row = 0; row < image->height; row++) {
 
271
                                        p8 = line;
 
272
                                        for (col = 0; col < image->width; col++) {
 
273
                                                *p8++ = (p16[col] & image->red_mask) >> ci.red_shift;
 
274
                                                *p8++ = (p16[col] & image->green_mask) >>ci.green_shift;
 
275
                                                *p8++ = (p16[col] & image->blue_mask) >>ci.blue_shift;
 
276
                                        }
 
277
                                        (*job->write) (line, 1, line_size, fp);
 
278
                                        p16 += image->bytes_per_line >> 1;
 
279
                                }
 
280
                        } else 
 
281
                        if (image->depth == 16) {
 
282
                                /* 16bpp, convert 565 to 555 which is
 
283
                                   needed by qt in raw rgb mode .. */
 
284
                                p16 = (unsigned short *) image->data;
 
285
                                if (image->byte_order == LSBFirst) {
 
286
                                        unsigned short t16;
 
287
                                        for (row = 0; row < image->height; row++) {
 
288
                                                for (i = 0, j=0; i < image->width; i++) {
 
289
                                                        t16 = ((*p16>>1) & (unsigned short)
 
290
                                                                (image->red_mask | image->green_mask)) |
 
291
                                                                (*p16 & (unsigned short)image->blue_mask);
 
292
 
 
293
                                                        line[j++] = ((unsigned char *)&t16)[1];
 
294
                                                        line[j++] = ((unsigned char *)&t16)[0];
 
295
                                                        p16++;
 
296
                                                }
 
297
                                                (*job->write) (line, 1, line_size, fp);
 
298
                                                /* eat paded bytes in the row ..
 
299
                                                 * ( bytes_per_line - bits_per_pixel / 8 * width ) / 2
 
300
                                                 */
 
301
                                                p16 += (image->bytes_per_line -
 
302
                                                        (image->bits_per_pixel >> 3) * image->width) >> 1;
 
303
                                        }
 
304
                                } else /* MSBFirst */ {
 
305
                                        unsigned short * t16;
 
306
                                        for (row = 0; row < image->height; row++) {
 
307
                                                t16 = (unsigned short *) line;
 
308
                                                for (i = 0; i < image->width; i++) {
 
309
                                                        t16[i] = ((*p16>>1) & (unsigned short)
 
310
                                                                (image->red_mask | image->green_mask)) |
 
311
                                                                (*p16 & (unsigned short)image->blue_mask);
 
312
                                                        p16++;
 
313
                                                }
 
314
                                                (*job->write) (line, 1, line_size, fp);
 
315
                                                /* eat paded bytes in the row ..
 
316
                                                 * ( bytes_per_line - bits_per_pixel / 8 * width ) / 2
 
317
                                                 */
 
318
                                                p16 += (image->bytes_per_line -
 
319
                                                        (image->bits_per_pixel >> 3) * image->width) >> 1;
 
320
                                        }
 
321
                                }
 
322
                        } else {
 
323
                                /* 15bpp */
 
324
                                p16 = (unsigned short *) image->data;
 
325
                                if (image->byte_order == LSBFirst) {
 
326
                                        for (row = 0; row < image->height; row++) {
 
327
                                                p8 = (unsigned char *) p16;
 
328
                                                for (i=0, j=0; i < image->width; i++) {
 
329
                                                        line[j] = p8[j+1]; j++;
 
330
                                                        line[j] = p8[j-1]; j++;
 
331
                                                }
 
332
                                                (*job->write) (line, 1, line_size, fp);
 
333
                                                p16 += image->bytes_per_line >> 1;
 
334
                                        }
 
335
                                } else /* MSBFirst */ {
 
336
                                        for (row = 0; row < image->height; row++) {
 
337
                                                (*job->write) (p16, 1, line_size, fp);
 
338
                                                p16 += image->bytes_per_line >> 1;
 
339
                                        }
 
340
                                }
 
341
                        }
 
342
                        break;
 
343
 
 
344
                case 24:
 
345
                        p8 = (unsigned char *) image->data;
 
346
 
 
347
                        if (image->byte_order == LSBFirst) {
 
348
                                unsigned char *t8;
 
349
                                for (row = 0; row < image->height; row++) {
 
350
                                        t8 = line;
 
351
                                        for (col = 0, i=0; col < image->width; col++) {
 
352
                                                /* we have to swap all RGBs :( */
 
353
                                                t8[i]   = p8[i+2];
 
354
                                                t8[i+1] = p8[i+1];
 
355
                                                t8[i+2] = p8[i];
 
356
                                                i += 3;
 
357
                                        }
 
358
                                        (*job->write) (line, 1, line_size, fp);
 
359
                                        p8 += image->bytes_per_line;
 
360
                                }
 
361
                        } else /* MSBFirst */ {
 
362
                                for (row = 0; row < image->height; row++) {
 
363
                                        /* write out the row
 
364
                                         */
 
365
                                        (*job->write) (p8, 1, line_size, fp);
 
366
                                        p8 += image->bytes_per_line;
 
367
                                }
 
368
                        }
 
369
                        break;
 
370
 
 
371
                case 32: /* alpha + RGB */
 
372
                        if (codec == GT_VID_FMT_JPEG) {
 
373
                                /* here we ignore the alpha channel,
 
374
                                 * cause jpeg can't save alpha values */
 
375
                                register unsigned int
 
376
                                        rmask = image->red_mask,
 
377
                                        gmask = image->green_mask,
 
378
                                        bmask = image->blue_mask,
 
379
                                        rshift= ci.red_shift,
 
380
                                        gshift= ci.green_shift,
 
381
                                        bshift= ci.blue_shift,
 
382
                                        *p32 = (unsigned int *) image->data;
 
383
                                for (row = 0; row < image->height; row++) {
 
384
                                        p8 = line;
 
385
                                        for (col = 0; col < image->width; col++) {
 
386
                                                *p8++ = ((*p32 & rmask) >> rshift);
 
387
                                                *p8++ = ((*p32 & gmask) >> gshift);
 
388
                                                *p8++ = ((*p32 & bmask) >> bshift);
 
389
                                                p32++;
 
390
                                        }
 
391
                                        (*job->write) (line, 1, line_size, fp);
 
392
                                        p32 += (image->bytes_per_line - (image->bits_per_pixel >>3)
 
393
                                                        * image->width) >> 2;
 
394
                                }
 
395
                        } else {
 
396
                                /* honor alpha channel */
 
397
                                register unsigned int
 
398
                                        rmask = image->red_mask,
 
399
                                        gmask = image->green_mask,
 
400
                                        bmask = image->blue_mask,
 
401
                                        amask = ci.alpha_mask,
 
402
                                        rshift= ci.red_shift,
 
403
                                        gshift= ci.green_shift,
 
404
                                        bshift= ci.blue_shift,
 
405
                                        ashift= ci.alpha_shift,
 
406
                                        *p32 = (unsigned int *) image->data;
 
407
                                for (row = 0; row < image->height; row++) {
 
408
                                        p8 = line;
 
409
                                        for (col = 0; col < image->width; col++) {
 
410
                                                *p8++ = ((*p32 & amask) >> ashift);
 
411
                                                *p8++ = ((*p32 & rmask) >> rshift);
 
412
                                                *p8++ = ((*p32 & gmask) >> gshift);
 
413
                                                *p8++ = ((*p32 & bmask) >> bshift);
 
414
                                                p32++;
 
415
                                        }
 
416
                                        (*job->write) (line, 1, line_size, fp);
 
417
                                        p32 += (image->bytes_per_line - (image->bits_per_pixel >>3)
 
418
                                                        * image->width) >> 2;
 
419
                                }
 
420
                        }
 
421
                        break;
 
422
 
 
423
                case 8:
 
424
                default:
 
425
                        printf ("bits_per_pixel not supported: %d\n",image->bits_per_pixel);
 
426
                        return;
 
427
                        break;
 
428
        }
 
429
#ifdef HAVE_LIBJPEG
 
430
        if (codec == GT_VID_FMT_JPEG) {
 
431
                jpeg_finish_compress (&jinfo);
 
432
        }
 
433
#endif
 
434
#ifdef HAVE_LIBPNG
 
435
        if (codec == GT_VID_FMT_PNG) {
 
436
                png_write_end (p_ptr, pinfo);
 
437
                /* release the sturctures, but don't free memory */
 
438
                png_destroy_write_struct (&p_ptr, NULL);
 
439
        }
 
440
#endif
 
441
}
 
442
 
 
443
/*
 
444
 * for indexed color source
 
445
 */
 
446
void
 
447
XImageToQTF8 (FILE *fp, XImage *image, Job *job)
 
448
{
 
449
        /* not done until now */
 
450
        printf ("Visual not supported: %d\n",image->bits_per_pixel);
 
451
}
 
452
 
 
453
/*
 
454
 * for GrayScale and StaticGray visual
 
455
 */
 
456
void
 
457
XImageToQTFG (FILE *fp, XImage *image, Job *job)
 
458
{
 
459
        int row, col;
 
460
        unsigned char *p8;
 
461
#ifdef HAVE_LIBJPEG
 
462
        static struct jpeg_error_mgr jerr;
 
463
#endif
 
464
 
 
465
#ifdef DEBUG
 
466
        printf ("XImageToQTFG() flags=%d\n", job->flags);
 
467
#endif
 
468
        /* destroy the old one, we need this static pointer to could
 
469
         * access it also in MngClean()
 
470
         */
 
471
 
 
472
        if ( job->state & VC_START ) {
 
473
                /* it's the first call, prepare some stuff
 
474
                 */
 
475
#ifdef DEBUG2
 
476
                dump_ximage_info (image);
 
477
#endif
 
478
                qtfp = fp;
 
479
                space_atom = gt_alloc_atom (GTA_skip, HEADER_SIZE-8);
 
480
                data_atom = gt_alloc_atom (GTA_movie_data, 0);
 
481
                gt_write_atom (space_atom, qtfp);
 
482
                gt_write_atom (data_atom, qtfp);
 
483
                pic_no = 0;
 
484
                bpp = 8;
 
485
                save_offset (pic_no++, ftell(qtfp));
 
486
 
 
487
                if (job->target == CAP_QTJ) {
 
488
                        /* we use jpeg codec */
 
489
#ifdef HAVE_LIBJPEG
 
490
                        jinfo.err = jpeg_std_error (&jerr);
 
491
                        jpeg_create_compress (&jinfo);
 
492
                        jpeg_stdio_dest (&jinfo, qtfp);
 
493
                        jinfo.image_width = image->width;
 
494
                        jinfo.image_height = image->height;
 
495
                        jinfo.input_components = 1;     /* 1 byte per pixel */
 
496
                        jinfo.in_color_space = JCS_GRAYSCALE;
 
497
                        jpeg_set_defaults(&jinfo);
 
498
                        /* optional parameters */
 
499
                        jpeg_set_quality (&jinfo, job->quality, TRUE);
 
500
                        jinfo.dct_method = JDCT_IFAST;
 
501
                        jpeg_start_compress (&jinfo, TRUE);
 
502
                        codec = GT_VID_FMT_JPEG;
 
503
#else
 
504
                        fprintf (stderr, "Warning: JPEG not compiled in!\n");
 
505
                        codec = GT_VID_FMT_RAW;
 
506
#endif
 
507
                } else if (job->target == CAP_QTP) {
 
508
#ifdef  HAVE_LIBPNG
 
509
                        /* to do */
 
510
                        p_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
 
511
                                                (void *)NULL, NULL, NULL);
 
512
                        pinfo = png_create_info_struct (p_ptr);
 
513
                        if (0/*setjmp (p_ptr->jmpbuf)*/) {
 
514
                                printf ("fatal error!\n");
 
515
                                job->state = VC_STOP;
 
516
                                return;
 
517
                        }
 
518
                        codec = GT_VID_FMT_PNG;
 
519
#else
 
520
                        fprintf (stderr, "Warning: PNG not compiled in!\n");
 
521
                        codec = GT_VID_FMT_RAW;
 
522
#endif
 
523
                } else /* CAP_QTR */ {
 
524
                        codec = GT_VID_FMT_RAW;
 
525
                        line = malloc (image->width * image->height);
 
526
                }
 
527
        } else {
 
528
                save_offset (pic_no++, ftell(qtfp));
 
529
#ifdef HAVE_LIBJPEG
 
530
                if (codec == GT_VID_FMT_JPEG)
 
531
                        jpeg_start_compress (&jinfo, TRUE);
 
532
#endif
 
533
#ifdef HAVE_LIBPNG
 
534
                if (codec == GT_VID_FMT_PNG)
 
535
                        p_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
 
536
                                                (void *)NULL, NULL, NULL);
 
537
#endif
 
538
        }
 
539
 
 
540
#ifdef HAVE_LIBJPEG
 
541
        /* what a dirty hack, just to pass the right pointer to ->write() */
 
542
        if (codec == GT_VID_FMT_JPEG)
 
543
                fp = (void *)&jinfo;
 
544
#endif
 
545
#ifdef HAVE_LIBPNG
 
546
        if (codec == GT_VID_FMT_PNG) {
 
547
                png_init_io (p_ptr, qtfp);
 
548
                png_set_compression_level (p_ptr, job->compress);
 
549
                png_set_IHDR (p_ptr, pinfo, image->width, image->height, 8,
 
550
                                PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
 
551
                                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
 
552
                png_write_info (p_ptr, pinfo);
 
553
                fp = (void *)p_ptr;
 
554
        }
 
555
#endif
 
556
 
 
557
        /* for ZPixmap bits_per_pixel could be 1,4,8,16,24,32
 
558
         * but for Direct- and TrueColor it could only be 8,16,24,32
 
559
         */
 
560
        switch (image->bits_per_pixel) {
 
561
                case 8:
 
562
                        p8 = (unsigned char *) image->data;
 
563
                        if (codec == GT_VID_FMT_RAW) {
 
564
                                unsigned char *t8;
 
565
                                for (row = 0; row < image->height; row++) {
 
566
                                        t8 = line;
 
567
                                        for (col = 0; col < image->height; col++) {
 
568
                                                *t8++ = ~p8[col];
 
569
                                        }
 
570
                                        (*job->write) (line, 1, image->width, fp);
 
571
                                        p8 += image->bytes_per_line;
 
572
                                }
 
573
                        } else {
 
574
                                for (row = 0; row < image->height; row++) {
 
575
                                        /* write out the row
 
576
                                         */
 
577
                                        (*job->write) (p8, 1, image->width, fp);
 
578
                                        p8 += image->bytes_per_line;
 
579
                                }
 
580
                        }
 
581
                        break;
 
582
 
 
583
                default:
 
584
                        printf ("bits_per_pixel not supported: %d\n",image->bits_per_pixel);
 
585
                        break;
 
586
        }
 
587
#ifdef HAVE_LIBJPEG
 
588
        if (codec == GT_VID_FMT_JPEG) {
 
589
                jpeg_finish_compress (&jinfo);
 
590
        }
 
591
#endif
 
592
#ifdef HAVE_LIBPNG
 
593
        if (codec == GT_VID_FMT_PNG) {
 
594
                png_write_end (p_ptr, pinfo);
 
595
                /* release the sturctures, but don't free memory */
 
596
                png_destroy_write_struct (&p_ptr, NULL);
 
597
        }
 
598
#endif
 
599
}
 
600
 
 
601
/*
 
602
 * clean up some allocated stuff and write some
 
603
 * control data in the qt file
 
604
 */
 
605
void
 
606
QtClean (Job *job)
 
607
{
 
608
        unsigned long mdat_size, moov_pos;
 
609
        gt_stsd_atom *stsd;
 
610
        gt_stts_atom *stts;
 
611
        gt_stsz_atom *stsz;
 
612
        gt_stsc_atom *stsc;
 
613
        gt_stco_atom *stco;
 
614
        gt_vmhd_atom *vmhd;
 
615
        gt_mdhd_atom *mdhd;
 
616
        gt_hdlr_atom *minf_hdlr, *mdia_hdlr;
 
617
        gt_dref_atom *dref;
 
618
        gt_tkhd_atom *tkhd;
 
619
        gt_mvhd_atom *mvhd;
 
620
        gt_udta_atom *udta;
 
621
        gt_atom *stbl, *minf, *dinf, *mdia, *trak, *moov;
 
622
        int no_of_frames = job->pic_no - job->start_no, i;
 
623
        
 
624
#ifdef DEBUG
 
625
        printf ("QtClean() state=%d\n", job->state);
 
626
#endif
 
627
        if (!qtfp) {
 
628
                return;
 
629
        }
 
630
        moov_pos = ftell (qtfp);
 
631
        save_offset (pic_no, moov_pos);
 
632
        mdat_size= moov_pos - HEADER_SIZE;
 
633
        fseek (qtfp, HEADER_SIZE, SEEK_SET);
 
634
        /* write length of mdat atom */
 
635
        gt_write4byte (mdat_size, qtfp);
 
636
 
 
637
        /* sample description atom */
 
638
        stsd = gt_alloc_atom (GTA_sample_desc, 1);
 
639
        stsd->count = 1;
 
640
        stsd->tab->size = 86;
 
641
        stsd->tab->format = codec;
 
642
        stsd->tab->index = 1;   /* points to an entry in 'dref' */
 
643
        stsd->tab->width = job->area->width;
 
644
        stsd->tab->height = job->area->height;
 
645
        stsd->tab->hres.high = 72;
 
646
        stsd->tab->vres.high = 72;
 
647
        stsd->tab->frame_count = 1;
 
648
        /* comp_name: max 1 + 31 chars */
 
649
        if (codec == GT_VID_FMT_JPEG) {
 
650
                strcpy (stsd->tab->comp_name+1, GT_COMP_JPEG);
 
651
                stsd->tab->comp_name[0] = strlen (GT_COMP_JPEG);
 
652
        } else if (codec == GT_VID_FMT_PNG) {
 
653
                strcpy (stsd->tab->comp_name+1, GT_COMP_PNG);
 
654
                stsd->tab->comp_name[0] = strlen (GT_COMP_PNG);
 
655
        } else {
 
656
                strcpy (stsd->tab->comp_name+1, GT_COMP_RAW);
 
657
                stsd->tab->comp_name[0] = strlen (GT_COMP_RAW);
 
658
        }
 
659
        if ((bpp == 8) && (job->win_attr.visual->class == StaticGray)) {
 
660
                stsd->tab->depth = 40; /* 8 bit gray scale */
 
661
        } else {
 
662
                stsd->tab->depth = bpp;
 
663
        }
 
664
        stsd->tab->ctab_id = -1;
 
665
 
 
666
        /* time to sample atom */
 
667
        stts = gt_alloc_atom (GTA_time_to_sample, 1);
 
668
        stts->count = 1;
 
669
        stts->tab->num_samples = no_of_frames;
 
670
        stts->tab->duration = job->time_per_frame;
 
671
 
 
672
        /* sample to chunk  */
 
673
        stsc = gt_alloc_atom (GTA_sample_to_chunk, 1);
 
674
        stsc->count = 1;
 
675
        stsc->tab->first_chunk = 1;
 
676
        stsc->tab->samples_per_chunk = stts->tab->num_samples;
 
677
        stsc->tab->sample_id = 1;       /* point to the first entry in the stsd tab!? */
 
678
 
 
679
        /* sample size atom .. */
 
680
        if (codec == 0xff /*GT_VID_FMT_RAW*/) {
 
681
                stsz = gt_alloc_atom (GTA_sample_size, 0);
 
682
                stsz->sample_size = job->area->width * job->area->height * bpp/ 8;
 
683
                stsz->count = 0;
 
684
        } else {
 
685
                stsz = gt_alloc_atom (GTA_sample_size, no_of_frames);
 
686
                stsz->sample_size = 0;
 
687
                stsz->count = no_of_frames;
 
688
                for (i = 0; i < no_of_frames; i++ ) {
 
689
                        stsz->tab[i].size = offset[i+1] - offset[i];
 
690
                        /* printf ("QtClean() size %d\n", stsz->tab[i].size); */
 
691
                }
 
692
        }
 
693
 
 
694
        /* sample chunk offset atom */
 
695
        stco = gt_alloc_atom (GTA_chunk_offset, 1);
 
696
        stco->count = 1;
 
697
        stco->tab[0].offset = HEADER_SIZE+8;    /*  offset of mdat */
 
698
        stco->size = sizeof (gt_stco_atom) - sizeof (stco->tab) +
 
699
                        stco->count * sizeof (gt_stco_entry);
 
700
 
 
701
        /* sample table */
 
702
        stbl = gt_alloc_atom (GTA_sample_table, 5);
 
703
        stbl->memb = 5;
 
704
        stbl->suba[0] = (gt_atom*)stsd;
 
705
        stbl->suba[1] = (gt_atom*)stts;
 
706
        stbl->suba[2] = (gt_atom*)stsc;
 
707
        stbl->suba[3] = (gt_atom*)stsz;
 
708
        stbl->suba[4] = (gt_atom*)stco;
 
709
        stbl->size = 8 +
 
710
                        stsd->size + stts->size + stsc->size + stsz->size + stco->size;
 
711
 
 
712
        /* video media information header */
 
713
        vmhd = gt_alloc_atom (GTA_video_media_header, 0);
 
714
        vmhd->flags[2] = 1;
 
715
        /* grmode, opcolor ? */
 
716
 
 
717
        /* data handler reference atom ??? */
 
718
        minf_hdlr = gt_alloc_atom (GTA_handler_ref, 0);
 
719
        minf_hdlr->comp_type = GT_DATA_REF;
 
720
        minf_hdlr->comp_subtype = GT_ALIAS;
 
721
        minf_hdlr->comp_man = GT_COMP_MAN;
 
722
 
 
723
        /* */
 
724
        dref = gt_alloc_atom (GTA_data_ref, 1);
 
725
        dref->count = 1;
 
726
        dref->tab->size = 12;
 
727
        dref->tab->type = GT_ALIAS;
 
728
        dref->tab->flags[2]= 0x01;      /* self reference */
 
729
 
 
730
        /* */
 
731
        dinf = gt_alloc_atom (GTA_data_info, 1);
 
732
        dinf->memb = 1;
 
733
        dinf->suba[0] = (gt_atom *)dref;
 
734
        dinf->size = 8 + dref->size;
 
735
 
 
736
        /* media information atom */
 
737
        minf = gt_alloc_atom (GTA_media_info, 4);
 
738
        minf->memb = 4;
 
739
        minf->suba[0] = (gt_atom *)vmhd;
 
740
        minf->suba[1] = (gt_atom *)minf_hdlr;
 
741
        minf->suba[2] = (gt_atom *)dinf;
 
742
        minf->suba[3] = (gt_atom *)stbl;
 
743
        minf->size += vmhd->size + minf_hdlr->size + dinf->size + stbl->size;
 
744
 
 
745
 
 
746
        /* media header */
 
747
        mdhd = gt_alloc_atom (GTA_media_header, 0);
 
748
        mdhd->ctime = gt_time();
 
749
        mdhd->mtime = gt_time();
 
750
        mdhd->time_scale = 1000;
 
751
        mdhd->duration = job->time_per_frame * no_of_frames;
 
752
 
 
753
        /* media handler reference atom */
 
754
        mdia_hdlr = gt_alloc_atom (GTA_handler_ref, strlen(GT_MID_HDLR_NAME));
 
755
        mdia_hdlr->comp_type = GT_MEDIA_REF;
 
756
        mdia_hdlr->comp_subtype = GT_VIDEO;
 
757
        mdia_hdlr->comp_man = GT_COMP_MAN;
 
758
        mdia_hdlr->comp_flags = 0x40000000;             /* ? */
 
759
        mdia_hdlr->comp_flags_mask = 0x00010047;        /* ? */
 
760
        strcpy (mdia_hdlr->comp_name+1, GT_MID_HDLR_NAME);
 
761
        mdia_hdlr->comp_name[0] = strlen (GT_MID_HDLR_NAME);
 
762
        mdia_hdlr->size = 32 + 1 +strlen (GT_MID_HDLR_NAME);
 
763
 
 
764
        /* media atom */
 
765
        mdia = gt_alloc_atom (GTA_media, 3);
 
766
        mdia->memb = 3;
 
767
        mdia->suba[0] = (gt_atom *)mdhd;
 
768
        mdia->suba[1] = (gt_atom *)mdia_hdlr;
 
769
        mdia->suba[2] = (gt_atom *)minf;
 
770
        mdia->size += mdhd->size + mdia_hdlr->size + minf->size;
 
771
 
 
772
        /* track header */
 
773
        tkhd = gt_alloc_atom (GTA_track_header,0);
 
774
        tkhd->flags[2] = (char)(0x01 | 0x02);
 
775
        tkhd->ctime = gt_time();
 
776
        tkhd->mtime = gt_time();
 
777
        tkhd->track_id = 1;
 
778
        tkhd->duration = job->time_per_frame * no_of_frames;
 
779
        tkhd->matrix[1]  = 1;   /* 1/1/1 */
 
780
        tkhd->matrix[17] = 1;
 
781
        tkhd->matrix[32] = 64;
 
782
        tkhd->width.high = job->area->width;
 
783
        tkhd->height.high= job->area->height;
 
784
 
 
785
        /* track */
 
786
        trak = gt_alloc_atom (GTA_track, 2);
 
787
        trak->memb = 2;
 
788
        trak->suba[0] = (gt_atom *)tkhd;
 
789
        trak->suba[1] = (gt_atom *)mdia;
 
790
        trak->size += tkhd->size + mdia->size;
 
791
 
 
792
        /* movie header */
 
793
        mvhd = gt_alloc_atom (GTA_movie_header, 0);
 
794
        mvhd->ctime = gt_time();
 
795
        mvhd->mtime = gt_time();
 
796
        mvhd->time_scale = 1000;
 
797
        mvhd->duration = tkhd->duration;
 
798
        mvhd->pref_rate.high = 1;
 
799
        mvhd->matrix[1] =  1;   /* 1/1/1 */
 
800
        mvhd->matrix[17] = 1;
 
801
        mvhd->matrix[32] = 64;
 
802
        mvhd->next_track_id = 2;
 
803
 
 
804
        /* user data
 
805
                no space for the text pointers is provided! */
 
806
        udta = gt_alloc_atom (GTA_user_data, 3);
 
807
        udta->tab[0]->type = GT_UD_INFO;
 
808
        udta->tab[0]->tlen = strlen ("Made by 'xvidcap'");
 
809
        udta->tab[0]->size = 8 + 4 + udta->tab[0]->tlen;
 
810
        udta->tab[0]->text = "Made by 'xvidcap'";
 
811
        udta->tab[1]->type = GT_UD_PRODUCER;
 
812
        udta->tab[1]->tlen = strlen ("XVidCap User");
 
813
        udta->tab[1]->size = 8 + 4 + udta->tab[1]->tlen;
 
814
        udta->tab[1]->text = "XVidCap User";
 
815
        udta->tab[2]->type = GT_UD_LOOP;
 
816
        udta->tab[2]->size = 8;
 
817
        udta->size = 8 +udta->tab[0]->size +udta->tab[1]->size +udta->tab[2]->size;
 
818
 
 
819
        /* movie atom, with 3 subatoms */
 
820
        moov = gt_alloc_atom (GTA_movie, 3);
 
821
        moov->memb = 3;
 
822
        moov->suba[0] = (gt_atom *)mvhd;
 
823
        moov->suba[1] = (gt_atom *)udta;
 
824
        moov->suba[2] = (gt_atom *)trak;
 
825
        moov->size += mvhd->size + udta->size + trak->size;
 
826
        
 
827
#ifdef DEBUG
 
828
        printf ("size of moov atom: %d bytes\n", moov->size);
 
829
#endif
 
830
        if (moov->size > HEADER_SIZE-8) {
 
831
                /* header size is too large, so add it at the end */
 
832
                fseek (qtfp, moov_pos, SEEK_SET);
 
833
                gt_write_atom (moov, qtfp);
 
834
        } else {
 
835
                fseek (qtfp, 0, SEEK_SET);
 
836
                gt_write_atom (moov, qtfp);
 
837
                space_atom->size = HEADER_SIZE - moov->size;
 
838
                gt_write_atom (space_atom, qtfp);
 
839
        }
 
840
        gt_atom_free (moov);
 
841
        qtfp = NULL;
 
842
#ifdef HAVE_LIBJPEG
 
843
        if (codec == GT_VID_FMT_JPEG)
 
844
                jpeg_destroy_compress (&jinfo);
 
845
#endif
 
846
        if (line) {
 
847
                free (line);
 
848
                line = NULL;
 
849
        }
 
850
}
 
851