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