3
* XImge to QT file module, todo: sound support :)
5
* Copyright (C) 1998 Rasca, Berlin
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.
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.
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.
22
#include "../config.h" /* autoconf output */
27
#include <X11/Intrinsic.h>
28
#include <X11/StringDefs.h>
41
/* reserved space for the moov atom
43
#define HEADER_SIZE 1024
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;
53
static struct jpeg_compress_struct jinfo;
56
static png_structp p_ptr= NULL;
57
static png_infop pinfo = NULL;
61
* remember offset of every frame during capturing
64
save_offset (int picno, int file_offset)
66
static int size = 1024;
70
/* alloc offsets for 1024 frames */
71
offset = (int *) malloc (sizeof(int) * size);
72
} else if (picno > size - 1) {
75
offset = realloc (offset, sizeof (int) * size);
78
offset[picno] = file_offset;
80
printf ("offset: %d -> %d\n", picno, file_offset);
83
perror ("save_offset()");
89
* for TrueColor and DirectColor
90
* write a Qt out to the named file pointer
93
XImageToQTFC (FILE *fp, XImage *image, Job *job)
95
int row, col, i, j, pad;
98
static int line_size = 0;
101
static struct jpeg_error_mgr jerr;
104
static png_color_8 sig_bit;
108
printf ("XImageToQTFC() flags=%d\n", job->flags);
110
/* destroy the old one, we need this static pointer to could
111
* access it also in MngClean()
114
if ( job->state & VC_START ) {
115
/* it's the first call, prepare some stuff
118
dump_ximage_info (image);
120
/* xanim don't know about free or skip, so we use a dummy mdat
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);
128
save_offset (pic_no++, ftell(qtfp));
129
GetColorInfo (image, &ci);
131
if (job->target == CAP_QTJ) {
132
/* we use jpeg codec */
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;
149
fprintf (stderr, "Warning: JPEG not compiled in!\n");
150
codec = GT_VID_FMT_RAW;
151
bpp = image->bits_per_pixel;
153
} else if (job->target == CAP_QTP) {
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;
164
if (0/*setjmp (p_ptr->jmpbuf)*/) {
165
printf ("fatal error!\n");
166
job->state = VC_STOP;
169
codec = GT_VID_FMT_PNG;
170
if (image->bits_per_pixel == 32)
171
bpp = 32; /* store with alpha */
175
fprintf (stderr, "Warning: PNG not compiled in!\n");
176
codec = GT_VID_FMT_RAW;
177
bpp = image->bits_per_pixel;
179
} else /* CAP_QTR */ {
180
codec = GT_VID_FMT_RAW;
181
bpp = image->bits_per_pixel;
183
line_size = image->width * bpp / 8;
184
line = malloc (line_size);
186
save_offset (pic_no++, ftell(qtfp));
188
if (codec == GT_VID_FMT_JPEG)
189
jpeg_start_compress (&jinfo, TRUE);
192
if (codec == GT_VID_FMT_PNG)
193
p_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
194
(void *)NULL, NULL, NULL);
199
/* what a dirty hack, just to pass the right pointer to ->write() */
200
if (codec == GT_VID_FMT_JPEG)
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);
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);
219
png_write_info (p_ptr, pinfo);
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
227
switch (image->bits_per_pixel) {
229
/* for 16bpp and 15bpp x server
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;
244
p16 = (unsigned short *) image->data;
245
pad = (image->bytes_per_line - (image->width << 1)) >> 1;
246
for (row = 0; row < image->height; row++) {
248
for (col = 0; col < image->width; col++) {
249
*p8 = ((*p16 & image->red_mask) >> r_shift0);
251
*p8 = (((*p8 << 8) - 1) >> r_shift1) +
252
(((*p8 << 8) - 1) >> r_shift2);
254
*p8 = ((*p16 & image->green_mask) >> g_shift0);
256
*p8 = (((*p8 << 8) - 1) >> g_shift1) +
257
(((*p8 << 8) - 1) >> g_shift2);
259
*p8 = ((*p16++ & image->blue_mask) >> b_shift0);
261
*p8 = (((*p8 << 8) - 1) >> b_shift1) +
262
(((*p8 << 8) - 1) >> b_shift2);
265
(*job->write) (line, 1, line_size, fp);
268
} else if (codec == GT_VID_FMT_PNG) {
269
p16 = (unsigned short *) image->data;
270
for (row = 0; row < image->height; row++) {
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;
277
(*job->write) (line, 1, line_size, fp);
278
p16 += image->bytes_per_line >> 1;
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) {
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);
293
line[j++] = ((unsigned char *)&t16)[1];
294
line[j++] = ((unsigned char *)&t16)[0];
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
301
p16 += (image->bytes_per_line -
302
(image->bits_per_pixel >> 3) * image->width) >> 1;
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);
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
318
p16 += (image->bytes_per_line -
319
(image->bits_per_pixel >> 3) * image->width) >> 1;
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++;
332
(*job->write) (line, 1, line_size, fp);
333
p16 += image->bytes_per_line >> 1;
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;
345
p8 = (unsigned char *) image->data;
347
if (image->byte_order == LSBFirst) {
349
for (row = 0; row < image->height; row++) {
351
for (col = 0, i=0; col < image->width; col++) {
352
/* we have to swap all RGBs :( */
358
(*job->write) (line, 1, line_size, fp);
359
p8 += image->bytes_per_line;
361
} else /* MSBFirst */ {
362
for (row = 0; row < image->height; row++) {
365
(*job->write) (p8, 1, line_size, fp);
366
p8 += image->bytes_per_line;
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++) {
385
for (col = 0; col < image->width; col++) {
386
*p8++ = ((*p32 & rmask) >> rshift);
387
*p8++ = ((*p32 & gmask) >> gshift);
388
*p8++ = ((*p32 & bmask) >> bshift);
391
(*job->write) (line, 1, line_size, fp);
392
p32 += (image->bytes_per_line - (image->bits_per_pixel >>3)
393
* image->width) >> 2;
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++) {
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);
416
(*job->write) (line, 1, line_size, fp);
417
p32 += (image->bytes_per_line - (image->bits_per_pixel >>3)
418
* image->width) >> 2;
425
printf ("bits_per_pixel not supported: %d\n",image->bits_per_pixel);
430
if (codec == GT_VID_FMT_JPEG) {
431
jpeg_finish_compress (&jinfo);
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);
444
* for indexed color source
447
XImageToQTF8 (FILE *fp, XImage *image, Job *job)
449
/* not done until now */
450
printf ("Visual not supported: %d\n",image->bits_per_pixel);
454
* for GrayScale and StaticGray visual
457
XImageToQTFG (FILE *fp, XImage *image, Job *job)
462
static struct jpeg_error_mgr jerr;
466
printf ("XImageToQTFG() flags=%d\n", job->flags);
468
/* destroy the old one, we need this static pointer to could
469
* access it also in MngClean()
472
if ( job->state & VC_START ) {
473
/* it's the first call, prepare some stuff
476
dump_ximage_info (image);
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);
485
save_offset (pic_no++, ftell(qtfp));
487
if (job->target == CAP_QTJ) {
488
/* we use jpeg codec */
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;
504
fprintf (stderr, "Warning: JPEG not compiled in!\n");
505
codec = GT_VID_FMT_RAW;
507
} else if (job->target == CAP_QTP) {
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;
518
codec = GT_VID_FMT_PNG;
520
fprintf (stderr, "Warning: PNG not compiled in!\n");
521
codec = GT_VID_FMT_RAW;
523
} else /* CAP_QTR */ {
524
codec = GT_VID_FMT_RAW;
525
line = malloc (image->width * image->height);
528
save_offset (pic_no++, ftell(qtfp));
530
if (codec == GT_VID_FMT_JPEG)
531
jpeg_start_compress (&jinfo, TRUE);
534
if (codec == GT_VID_FMT_PNG)
535
p_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
536
(void *)NULL, NULL, NULL);
541
/* what a dirty hack, just to pass the right pointer to ->write() */
542
if (codec == GT_VID_FMT_JPEG)
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);
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
560
switch (image->bits_per_pixel) {
562
p8 = (unsigned char *) image->data;
563
if (codec == GT_VID_FMT_RAW) {
565
for (row = 0; row < image->height; row++) {
567
for (col = 0; col < image->height; col++) {
570
(*job->write) (line, 1, image->width, fp);
571
p8 += image->bytes_per_line;
574
for (row = 0; row < image->height; row++) {
577
(*job->write) (p8, 1, image->width, fp);
578
p8 += image->bytes_per_line;
584
printf ("bits_per_pixel not supported: %d\n",image->bits_per_pixel);
588
if (codec == GT_VID_FMT_JPEG) {
589
jpeg_finish_compress (&jinfo);
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);
602
* clean up some allocated stuff and write some
603
* control data in the qt file
608
unsigned long mdat_size, moov_pos;
616
gt_hdlr_atom *minf_hdlr, *mdia_hdlr;
621
gt_atom *stbl, *minf, *dinf, *mdia, *trak, *moov;
622
int no_of_frames = job->pic_no - job->start_no, i;
625
printf ("QtClean() state=%d\n", job->state);
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);
637
/* sample description atom */
638
stsd = gt_alloc_atom (GTA_sample_desc, 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);
656
strcpy (stsd->tab->comp_name+1, GT_COMP_RAW);
657
stsd->tab->comp_name[0] = strlen (GT_COMP_RAW);
659
if ((bpp == 8) && (job->win_attr.visual->class == StaticGray)) {
660
stsd->tab->depth = 40; /* 8 bit gray scale */
662
stsd->tab->depth = bpp;
664
stsd->tab->ctab_id = -1;
666
/* time to sample atom */
667
stts = gt_alloc_atom (GTA_time_to_sample, 1);
669
stts->tab->num_samples = no_of_frames;
670
stts->tab->duration = job->time_per_frame;
672
/* sample to chunk */
673
stsc = gt_alloc_atom (GTA_sample_to_chunk, 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!? */
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;
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); */
694
/* sample chunk offset atom */
695
stco = gt_alloc_atom (GTA_chunk_offset, 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);
702
stbl = gt_alloc_atom (GTA_sample_table, 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;
710
stsd->size + stts->size + stsc->size + stsz->size + stco->size;
712
/* video media information header */
713
vmhd = gt_alloc_atom (GTA_video_media_header, 0);
715
/* grmode, opcolor ? */
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;
724
dref = gt_alloc_atom (GTA_data_ref, 1);
726
dref->tab->size = 12;
727
dref->tab->type = GT_ALIAS;
728
dref->tab->flags[2]= 0x01; /* self reference */
731
dinf = gt_alloc_atom (GTA_data_info, 1);
733
dinf->suba[0] = (gt_atom *)dref;
734
dinf->size = 8 + dref->size;
736
/* media information atom */
737
minf = gt_alloc_atom (GTA_media_info, 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;
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;
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);
765
mdia = gt_alloc_atom (GTA_media, 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;
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();
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;
786
trak = gt_alloc_atom (GTA_track, 2);
788
trak->suba[0] = (gt_atom *)tkhd;
789
trak->suba[1] = (gt_atom *)mdia;
790
trak->size += tkhd->size + mdia->size;
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;
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;
819
/* movie atom, with 3 subatoms */
820
moov = gt_alloc_atom (GTA_movie, 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;
828
printf ("size of moov atom: %d bytes\n", moov->size);
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);
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);
843
if (codec == GT_VID_FMT_JPEG)
844
jpeg_destroy_compress (&jinfo);