1 /*******************************************************************************
2 avi_strl.c
3
4 libquicktime - A library for reading and writing quicktime/avi/mp4 files.
5 http://libquicktime.sourceforge.net
6
7 Copyright (C) 2002 Heroine Virtual Ltd.
8 Copyright (C) 2002-2011 Members of the libquicktime project.
9
10 This library is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free
12 Software Foundation; either version 2.1 of the License, or (at your option)
13 any later version.
14
15 This library is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18 details.
19
20 You should have received a copy of the GNU Lesser General Public License along
21 with this library; if not, write to the Free Software Foundation, Inc., 51
22 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *******************************************************************************/
24
25 #include "lqt_private.h"
26 #include <stdlib.h>
27 #include <string.h>
28
29 // Update during close:
30 // length
31 // samples per chunk
32 #define PADDING_SIZE 2048 /* Must be increased for codecs with really
33 large extradata (like Vorbis in AVI),
34 but we won't do such nonsense, will we? */
35
36
quicktime_new_strl()37 quicktime_strl_t* quicktime_new_strl()
38 {
39 quicktime_strl_t *strl = calloc(1, sizeof(quicktime_strl_t));
40 return strl;
41 }
42
43
quicktime_init_strl(quicktime_t * file,quicktime_audio_map_t * atrack,quicktime_video_map_t * vtrack,quicktime_trak_t * trak,quicktime_strl_t * strl)44 void quicktime_init_strl(quicktime_t *file,
45 quicktime_audio_map_t *atrack,
46 quicktime_video_map_t *vtrack,
47 quicktime_trak_t *trak,
48 quicktime_strl_t *strl)
49 {
50 quicktime_atom_t list_atom;
51 quicktime_atom_t junk_atom;
52 int i;
53 trak->strl = strl;
54 /* Construct tag */
55 if(vtrack)
56 {
57 strl->tag[0] = '0' + (trak->tkhd.track_id - 1) / 10;
58 strl->tag[1] = '0' + (trak->tkhd.track_id - 1) % 10;
59 strl->tag[2] = 'd';
60 strl->tag[3] = 'c';
61 }
62 else
63 if(atrack)
64 {
65 strl->tag[0] = '0' + (trak->tkhd.track_id - 1) / 10;
66 strl->tag[1] = '0' + (trak->tkhd.track_id - 1) % 10;
67 strl->tag[2] = 'w';
68 strl->tag[3] = 'b';
69 }
70
71
72 /* LIST 'strl' */
73 quicktime_atom_write_header(file, &list_atom, "LIST");
74 quicktime_write_char32(file, "strl");
75
76 /* vids */
77 if(vtrack)
78 {
79 strncpy(strl->strh.fccType, "vids", 4);
80 strncpy(strl->strh.fccHandler, trak->mdia.minf.stbl.stsd.table[0].format, 4);
81
82 /* framerate denominator */
83 strl->strh.dwScale = trak->mdia.minf.stbl.stts.table[0].sample_duration;
84 /* framerate numerator */
85 strl->strh.dwRate = trak->mdia.mdhd.time_scale;
86 strl->strh.dwQuality = 10000;
87 // strl->strh.dwSampleSize = (int)(trak->tkhd.track_width * trak->tkhd.track_height) * 3;
88 strl->strh.rcFrame.right = trak->tkhd.track_width;
89 strl->strh.rcFrame.bottom = trak->tkhd.track_height;
90
91 strl->is_video = 1;
92 }
93 else if(atrack)
94 {
95 strncpy(strl->strh.fccType, "auds", 4);
96 strl->strh.dwQuality = -1;
97 strl->is_audio = 1;
98 }
99 strl->strh_offset = quicktime_position(file);
100 quicktime_write_strh(file, &strl->strh);
101
102 /* strf */
103
104 if(vtrack)
105 {
106 strl->strf.bh.biSize = 40;
107 strl->strf.bh.biWidth = trak->tkhd.track_width;
108 strl->strf.bh.biHeight = trak->tkhd.track_height;
109 strl->strf.bh.biPlanes = 1;
110 strl->strf.bh.biBitCount = 24;
111 strncpy(strl->strf.bh.biCompression, trak->mdia.minf.stbl.stsd.table[0].format, 4);
112 strl->strf.bh.biSizeImage = trak->tkhd.track_width * trak->tkhd.track_height * 3; // biSizeImage
113 quicktime_write_strf_video(file, &strl->strf);
114 }
115 else if(atrack)
116 {
117 /* By now the codec is instantiated so the WAV ID is available. */
118 strl->strf.wf.type = LQT_WAVEFORMAT_WAVEFORMATEX;
119 strl->strf.wf.f.WAVEFORMAT.wFormatTag = atrack->wav_id;
120 strl->strf.wf.f.WAVEFORMAT.nChannels =
121 trak->mdia.minf.stbl.stsd.table[0].channels;
122 strl->strf.wf.f.WAVEFORMAT.nSamplesPerSec = atrack->samplerate;
123 quicktime_write_strf_audio(file, &strl->strf);
124 }
125
126 strl->end_pos = quicktime_position(file);
127
128 /* We write junk for 2 reasons:
129 *
130 * 1. The strf chunks might grow
131 * 2. The indx chunk might come as well
132 */
133
134 quicktime_atom_write_header(file, &junk_atom, "JUNK");
135 for(i = 0; i < PADDING_SIZE; i ++)
136 quicktime_write_char(file, 0);
137 quicktime_atom_write_footer(file, &junk_atom);
138
139 /* Initialize super index */
140 if(file->file_type == LQT_FILE_AVI_ODML)
141 quicktime_init_indx(file, &strl->indx, strl);
142
143 quicktime_atom_write_footer(file, &list_atom);
144 }
145
146
147
quicktime_delete_strl(quicktime_strl_t * strl)148 void quicktime_delete_strl(quicktime_strl_t *strl)
149 {
150 if(strl->is_video) quicktime_strf_delete_video(&strl->strf);
151 if(strl->is_audio) quicktime_strf_delete_audio(&strl->strf);
152 quicktime_delete_indx(&strl->indx);
153 free(strl);
154 }
155
quicktime_read_strl(quicktime_t * file,quicktime_strl_t * strl,quicktime_atom_t * parent_atom)156 void quicktime_read_strl(quicktime_t *file,
157 quicktime_strl_t *strl,
158 quicktime_atom_t *parent_atom)
159 {
160 quicktime_atom_t leaf_atom;
161
162 /* AVI translation: */
163 /* vids -> trak */
164 /* auds -> trak */
165 /* Only one track is in each strl object */
166 do
167 {
168 quicktime_atom_read_header(file, &leaf_atom);
169
170 // strh
171 if(quicktime_atom_is(&leaf_atom, "strh"))
172 {
173 quicktime_read_strh(file, &strl->strh, &leaf_atom);
174 }
175
176 else if(quicktime_atom_is(&leaf_atom, "strf"))
177 {
178 if(quicktime_match_32(strl->strh.fccType, "vids"))
179 quicktime_read_strf_video(file, &strl->strf, &leaf_atom);
180 else if(quicktime_match_32(strl->strh.fccType, "auds"))
181 quicktime_read_strf_audio(file, &strl->strf, &leaf_atom);
182 }
183 else if(quicktime_atom_is(&leaf_atom, "indx"))
184 // Super index.
185 // Read the super index + all the partial indexes now
186 {
187 quicktime_read_indx(file, strl, &leaf_atom);
188 strl->have_indx = 1;
189 }
190 quicktime_atom_skip(file, &leaf_atom);
191 } while(quicktime_position(file) < parent_atom->end);
192
193 }
194
195
196
quicktime_strl_2_qt(quicktime_t * file,quicktime_strl_t * strl)197 void quicktime_strl_2_qt(quicktime_t *file,
198 quicktime_strl_t *strl)
199 {
200 // These are 0 if no track is currently being processed.
201 // Set to 1 if audio or video track is being processed.
202 uint8_t codec[4] = { 0x00, 0x00, 0x00, 0x00 };
203 // int denominator;
204 // int numerator;
205 int frame_duration = 0;
206 int timescale = 0;
207 int width = 0;
208 int height = 0;
209 int depth = 0;
210 int frames = 0;
211 int bytes_per_sample = 0;
212 int bits_per_sample = 0;
213 int samples;
214 // int samples_per_chunk = 0;
215 int channels = 0;
216 int sample_rate = 0;
217 // int bytes_per_second;
218 quicktime_trak_t *trak = 0;
219
220 /* AVI translation: */
221 /* vids -> trak */
222 /* auds -> trak */
223 /* Only one track is in each strl object */
224
225 if(quicktime_match_32(strl->strh.fccType, "vids"))
226 {
227 /* Video */
228
229 trak = quicktime_add_trak(file);
230 trak->strl = strl;
231 width = 0;
232 height = 0;
233 depth = 24;
234 frames = 0;
235 strl->is_video = 1;
236
237
238 trak->tkhd.track_id = file->moov.mvhd.next_track_id;
239 file->moov.mvhd.next_track_id++;
240
241 if(strl->strh.dwScale != 0)
242 {
243 timescale = strl->strh.dwRate;
244 frame_duration = strl->strh.dwScale;
245 // frame_rate = (double)strl->dwRate / strl->dwScale;
246 }
247 else
248 {
249 // frame_rate = strl->dwRate;
250 timescale = strl->strh.dwRate;
251 frame_duration = 1;
252 }
253 frames = strl->strh.dwLength; // dwLength
254
255 width = strl->strf.bh.biWidth;
256 height = strl->strf.bh.biHeight;
257
258 /* Depth in bits */
259 depth = strl->strf.bh.biBitCount;
260
261 /* Generate quicktime structures */
262 quicktime_trak_init_video(file,
263 trak,
264 width,
265 height,
266 frame_duration,
267 timescale,
268 strl->strf.bh.biCompression);
269 quicktime_mhvd_init_video(file,
270 &file->moov.mvhd,
271 timescale);
272 trak->mdia.mdhd.duration = frames;
273 // trak->mdia.mdhd.time_scale = 1;
274 trak->mdia.minf.stbl.stsd.table[0].depth = depth;
275
276
277 }
278 else if(quicktime_match_32(strl->strh.fccType, "auds"))
279 {
280 trak = quicktime_add_trak(file);
281 trak->strl = strl;
282 channels = 2;
283 sample_rate = 0;
284 strl->is_audio = 1;
285
286 trak->tkhd.track_id = file->moov.mvhd.next_track_id;
287 file->moov.mvhd.next_track_id++;
288
289 samples = strl->strh.dwLength; // dwLength
290 bytes_per_sample = strl->strh.dwSampleSize; // dwSampleSize
291
292 if(strl->strf.wf.type != LQT_WAVEFORMAT_WAVEFORMAT)
293 {
294 bits_per_sample = strl->strf.wf.f.PCMWAVEFORMAT.wBitsPerSample;
295 }
296 else
297 bits_per_sample = 8;
298
299
300 channels = strl->strf.wf.f.WAVEFORMAT.nChannels;
301 sample_rate = strl->strf.wf.f.WAVEFORMAT.nSamplesPerSec;
302
303 quicktime_trak_init_audio(file,
304 trak,
305 channels,
306 sample_rate,
307 bits_per_sample,
308 (char*)codec);
309
310 if((strl->strh.dwSampleSize == 0) && (strl->strh.dwScale > 1))
311 trak->mdia.minf.is_audio_vbr = 1;
312
313 // We store a constant samples per chunk based on the
314 // packet size if sample_size zero
315 // and calculate the samples per chunk based on the chunk size if sample_size
316 // is nonzero.
317 // trak->mdia.minf.stbl.stsd.table[0].sample_size = bytes_per_sample;
318 trak->mdia.minf.stbl.stsd.table[0].compression_id =
319 strl->strf.wf.f.WAVEFORMAT.wFormatTag;
320
321 /* Synthesize stsc table for constant samples per chunk */
322 if(!bytes_per_sample)
323 {
324 /* Should be enough entries allocated in quicktime_stsc_init_table */
325 trak->mdia.minf.stbl.stsc.table[0].samples = strl->strh.dwScale;
326 trak->mdia.minf.stbl.stsc.total_entries = 1;
327 }
328 }
329 }
330
331
quicktime_finalize_strl(quicktime_t * file,quicktime_trak_t * trak,quicktime_strl_t * strl)332 void quicktime_finalize_strl(quicktime_t *file, quicktime_trak_t * trak,
333 quicktime_strl_t *strl)
334 {
335 int i;
336 quicktime_atom_t junk_atom;
337
338 int64_t old_pos, end_pos;
339 /* Rewrite stream headers */
340
341 if(!strl->strh.dwLength)
342 strl->strh.dwLength = quicktime_track_samples(file, trak);
343
344 // if(trak->mdia.minf.is_audio)
345 // strl->strh.dwSuggestedBufferSize = strl->strf.wf.f.WAVEFORMAT.nAvgBytesPerSec / 2;
346
347 old_pos = quicktime_position(file);
348
349 quicktime_set_position(file, strl->strh_offset);
350 quicktime_write_strh(file, &strl->strh);
351
352 if(trak->mdia.minf.is_video)
353 {
354 quicktime_write_strf_video(file, &strl->strf);
355 }
356 else if(trak->mdia.minf.is_audio)
357 {
358 quicktime_write_strf_audio(file, &strl->strf);
359 }
360
361 end_pos = quicktime_position(file);
362
363 // Finalize super indexes
364 if(file->file_type == LQT_FILE_AVI_ODML)
365 strl->indx.offset = end_pos;
366
367 quicktime_atom_write_header(file, &junk_atom, "JUNK");
368 for(i = 0; i < PADDING_SIZE - (end_pos - strl->end_pos); i ++)
369 quicktime_write_char(file, 0);
370 quicktime_atom_write_footer(file, &junk_atom);
371
372 strl->indx.size = quicktime_position(file) - strl->indx.offset;
373 }
374
quicktime_strl_dump(quicktime_strl_t * strl)375 void quicktime_strl_dump(quicktime_strl_t *strl)
376 {
377 lqt_dump("strl\n");
378 quicktime_strh_dump(&strl->strh);
379
380 if(!strncmp(strl->strh.fccType, "auds", 4))
381 quicktime_strf_dump_audio(&strl->strf);
382 if(!strncmp(strl->strh.fccType, "vids", 4))
383 quicktime_strf_dump_video(&strl->strf);
384
385 if(strl->have_indx)
386 {
387 quicktime_indx_dump(&strl->indx);
388 }
389 }
390