initial commit
[goodguy/history.git] / cinelerra-5.0 / quicktime / moov.c
1 #include "funcprotos.h"
2 #include "quicktime.h"
3 #include "workarounds.h"
4
5 #include <string.h>
6 #include <zlib.h>
7
8
9 int quicktime_moov_init(quicktime_moov_t *moov)
10 {
11         int i;
12
13         moov->total_tracks = 0;
14         for(i = 0 ; i < MAXTRACKS; i++) moov->trak[i] = 0;
15         quicktime_mvhd_init(&(moov->mvhd));
16         quicktime_udta_init(&(moov->udta));
17         quicktime_ctab_init(&(moov->ctab));
18         return 0;
19 }
20
21 int quicktime_moov_delete(quicktime_moov_t *moov)
22 {
23         while(moov->total_tracks) quicktime_delete_trak(moov);
24         quicktime_mvhd_delete(&(moov->mvhd));
25         quicktime_udta_delete(&(moov->udta));
26         quicktime_ctab_delete(&(moov->ctab));
27         return 0;
28 }
29
30 void quicktime_moov_dump(quicktime_moov_t *moov)
31 {
32         int i;
33         printf("movie\n");
34         quicktime_mvhd_dump(&(moov->mvhd));
35         quicktime_udta_dump(&(moov->udta));
36         for(i = 0; i < moov->total_tracks; i++)
37                 quicktime_trak_dump(moov->trak[i]);
38         quicktime_ctab_dump(&(moov->ctab));
39 }
40
41 static void* zalloc(void *opaque, unsigned int items, unsigned int size)
42 {
43         return calloc(items, size);
44 }
45
46 static void zfree(void *opaque, void *ptr)
47 {
48         free(ptr);
49 }
50
51 static int read_cmov(quicktime_t *file,
52         quicktime_atom_t *parent_atom,
53         quicktime_atom_t *moov_atom)
54 {
55         quicktime_atom_t leaf_atom;
56
57         do
58         {
59                 quicktime_atom_read_header(file, &leaf_atom);
60
61 /* Algorithm used to compress */
62                 if(quicktime_atom_is(&leaf_atom, "dcom"))
63                 {
64                         char data[5];
65 //printf("read_cmov 1 %lld\n", quicktime_position(file));
66                         quicktime_read_data(file, data, 4);
67                         data[4] = 0;
68                         if(strcmp(data, "zlib"))
69                         {
70                                 fprintf(stderr, 
71                                         "read_cmov: compression '%c%c%c%c' not zlib.  Giving up and going to a movie.\n",
72                                         data[0],
73                                         data[1],
74                                         data[2],
75                                         data[3]);
76                                 return 1;
77                         }
78
79                         quicktime_atom_skip(file, &leaf_atom);
80                 }
81                 else
82 /* Size of uncompressed data followed by compressed data */
83                 if(quicktime_atom_is(&leaf_atom, "cmvd"))
84                 {
85 /* Size of uncompressed data */
86                         int uncompressed_size = quicktime_read_int32(file);
87 /* Read compressed data */
88                         int compressed_size = leaf_atom.end - quicktime_position(file);
89                         if(compressed_size > uncompressed_size)
90                         {
91                                 fprintf(stderr, 
92                                         "read_cmov: FYI compressed_size=%d uncompressed_size=%d\n",
93                                         compressed_size,
94                                         uncompressed_size);
95                         }
96
97                         unsigned char *data_in = calloc(1, compressed_size);
98                         quicktime_read_data(file, (char*)data_in, compressed_size);
99 /* Decompress to another buffer */
100                         unsigned char *data_out = calloc(1, uncompressed_size + 0x400);
101                         z_stream zlib;
102                         zlib.zalloc = zalloc;
103                         zlib.zfree = zfree;
104                         zlib.opaque = NULL;
105                         zlib.avail_out = uncompressed_size + 0x400;
106                         zlib.next_out = data_out;
107                         zlib.avail_in = compressed_size;
108                         zlib.next_in = data_in;
109                         inflateInit(&zlib);
110                         inflate(&zlib, Z_PARTIAL_FLUSH);
111                         inflateEnd(&zlib);
112                         free(data_in);
113                         file->moov_data = data_out;
114
115 /*
116  * FILE *test = fopen("/tmp/test", "w");
117  * fwrite(data_out, uncompressed_size, 1, test);
118  * fclose(test);
119  * exit(0);
120  */
121
122
123 /* Trick library into reading temporary buffer for the moov */
124                         file->moov_end = moov_atom->end;
125                         file->moov_size = moov_atom->size;
126                         moov_atom->end = moov_atom->start + uncompressed_size;
127                         moov_atom->size = uncompressed_size;
128                         file->old_preload_size = file->preload_size;
129                         file->old_preload_buffer = file->preload_buffer;
130                         file->old_preload_start = file->preload_start;
131                         file->old_preload_end = file->preload_end;
132                         file->old_preload_ptr = file->preload_ptr;
133                         file->preload_size = uncompressed_size;
134                         file->preload_buffer = (char *)data_out;
135                         file->preload_start = moov_atom->start;
136                         file->preload_end = file->preload_start + uncompressed_size;
137                         file->preload_ptr = 0;
138                         quicktime_set_position(file, file->preload_start + 8);
139 /* Try again */
140                         if(quicktime_read_moov(file, 
141                                 &file->moov, 
142                                 moov_atom))
143                                 return 1;
144 /* Exit the compressed state */
145                         moov_atom->size = file->moov_size;
146                         moov_atom->end = file->moov_end;
147                         file->preload_size = file->old_preload_size;
148                         file->preload_buffer = file->old_preload_buffer;
149                         file->preload_start = file->old_preload_start;
150                         file->preload_end = file->old_preload_end;
151                         file->preload_ptr = file->old_preload_ptr;
152                         quicktime_set_position(file, moov_atom->end);
153                 }
154                 else
155                         quicktime_atom_skip(file, &leaf_atom);
156         }while(quicktime_position(file) < parent_atom->end);
157         return 0;
158 }
159
160
161 int quicktime_read_moov(quicktime_t *file, 
162         quicktime_moov_t *moov, 
163         quicktime_atom_t *parent_atom)
164 {
165 /* mandatory mvhd */
166         quicktime_atom_t leaf_atom;
167
168 /* AVI translation: */
169 /* strh -> mvhd */
170
171         do
172         {
173 //printf("quicktime_read_moov 1 %llx\n", quicktime_position(file));
174                 quicktime_atom_read_header(file, &leaf_atom);
175
176 /*
177  * printf("quicktime_read_moov 2 %c%c%c%c\n", 
178  * leaf_atom.type[0],
179  * leaf_atom.type[1],
180  * leaf_atom.type[2],
181  * leaf_atom.type[3]);
182  */
183
184                 if(quicktime_atom_is(&leaf_atom, "cmov"))
185                 {
186                         file->compressed_moov = 1;
187                         if(read_cmov(file, &leaf_atom, parent_atom)) return 1;
188 /* Now were reading the compressed moov atom from the beginning. */
189                 }
190                 else
191                 if(quicktime_atom_is(&leaf_atom, "mvhd"))
192                 {
193                         quicktime_read_mvhd(file, &(moov->mvhd), &leaf_atom);
194                 }
195                 else
196                 if(quicktime_atom_is(&leaf_atom, "clip"))
197                 {
198                         quicktime_atom_skip(file, &leaf_atom);
199                 }
200                 else
201                 if(quicktime_atom_is(&leaf_atom, "trak"))
202                 {
203                         quicktime_trak_t *trak = quicktime_add_trak(file);
204                         quicktime_read_trak(file, trak, &leaf_atom);
205                 }
206                 else
207                 if(quicktime_atom_is(&leaf_atom, "udta"))
208                 {
209                         quicktime_read_udta(file, &(moov->udta), &leaf_atom);
210                         quicktime_atom_skip(file, &leaf_atom);
211                 }
212                 else
213                 if(quicktime_atom_is(&leaf_atom, "ctab"))
214                 {
215                         quicktime_read_ctab(file, &(moov->ctab));
216                 }
217                 else
218                         quicktime_atom_skip(file, &leaf_atom);
219         }while(quicktime_position(file) < parent_atom->end);
220
221         return 0;
222 }
223
224 void quicktime_write_moov(quicktime_t *file, 
225         quicktime_moov_t *moov,
226         int rewind)
227 {
228         quicktime_atom_t atom;
229         int i;
230         long int64_t_duration = 0;
231         long duration, timescale;
232         int result;
233
234
235 // Try moov header immediately
236         file->mdat.atom.end = quicktime_position(file);
237         result = quicktime_atom_write_header(file, &atom, "moov");
238
239 // Disk full.  Rewind and try again
240         if(result)
241         {
242                 quicktime_set_position(file, file->mdat.atom.end - (int64_t)0x100000);
243                 file->mdat.atom.end = quicktime_position(file);
244                 quicktime_atom_write_header(file, &atom, "moov");
245         }
246
247 /* get the duration from the int64_t track in the mvhd's timescale */
248         for(i = 0; i < moov->total_tracks; i++)
249         {
250                 quicktime_trak_fix_counts(file, moov->trak[i]);
251                 quicktime_trak_duration(moov->trak[i], &duration, &timescale);
252
253                 duration = (long)((float)duration / timescale * moov->mvhd.time_scale);
254
255                 if(duration > int64_t_duration)
256                 {
257                         int64_t_duration = duration;
258                 }
259         }
260         moov->mvhd.duration = int64_t_duration;
261         moov->mvhd.selection_duration = int64_t_duration;
262
263         quicktime_write_mvhd(file, &(moov->mvhd));
264         quicktime_write_udta(file, &(moov->udta));
265         for(i = 0; i < moov->total_tracks; i++)
266         {
267                 quicktime_write_trak(file, moov->trak[i], moov->mvhd.time_scale);
268         }
269         /*quicktime_write_ctab(file, &(moov->ctab)); */
270
271         quicktime_atom_write_footer(file, &atom);
272
273 // Rewind to end of mdat.  Breaks make_streamable
274 // This probably allows the file to be extended after writing the moov.
275         if(rewind) quicktime_set_position(file, file->mdat.atom.end);
276 }
277
278 void quicktime_update_durations(quicktime_moov_t *moov)
279 {
280         
281 }
282
283 int quicktime_shift_offsets(quicktime_moov_t *moov, int64_t offset)
284 {
285         int i;
286         for(i = 0; i < moov->total_tracks; i++)
287         {
288                 quicktime_trak_shift_offsets(moov->trak[i], offset);
289         }
290         return 0;
291 }