1 /*******************************************************************************
2  stsc.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 
quicktime_stsc_init(quicktime_stsc_t * stsc)28 void quicktime_stsc_init(quicktime_stsc_t *stsc)
29 {
30 	stsc->version = 0;
31 	stsc->flags = 0;
32 	stsc->total_entries = 0;
33 	stsc->entries_allocated = 0;
34 }
35 
quicktime_stsc_init_table(quicktime_t * file,quicktime_stsc_t * stsc)36 void quicktime_stsc_init_table(quicktime_t *file, quicktime_stsc_t *stsc)
37 {
38 	if(!stsc->entries_allocated)
39 	{
40 		stsc->total_entries = 1;
41 		stsc->entries_allocated = 2048;
42 		stsc->table = (quicktime_stsc_table_t*)calloc(1, sizeof(quicktime_stsc_table_t) * stsc->entries_allocated);
43 	}
44 }
45 
quicktime_stsc_init_video(quicktime_t * file,quicktime_stsc_t * stsc)46 void quicktime_stsc_init_video(quicktime_t *file, quicktime_stsc_t *stsc)
47 {
48 	quicktime_stsc_table_t *table;
49 	quicktime_stsc_init_table(file, stsc);
50 	table = &stsc->table[0];
51 	table->chunk = 1;
52 	table->samples = 1;
53 	table->id = 1;
54 }
55 
quicktime_stsc_init_audio(quicktime_t * file,quicktime_stsc_t * stsc,int sample_rate)56 void quicktime_stsc_init_audio(quicktime_t *file, quicktime_stsc_t *stsc, int sample_rate)
57 {
58 	quicktime_stsc_table_t *table;
59 	quicktime_stsc_init_table(file, stsc);
60 	table = &stsc->table[0];
61 	table->chunk = 1;
62 	table->samples = 0;         /* set this after completion or after every audio chunk is written */
63 	table->id = 1;
64 }
65 
quicktime_stsc_delete(quicktime_stsc_t * stsc)66 void quicktime_stsc_delete(quicktime_stsc_t *stsc)
67 {
68 	if(stsc->total_entries) free(stsc->table);
69 	stsc->total_entries = 0;
70 }
71 
quicktime_stsc_dump(quicktime_stsc_t * stsc)72 void quicktime_stsc_dump(quicktime_stsc_t *stsc)
73 {
74 	int i;
75 	lqt_dump("     sample to chunk (stsc)\n");
76 	lqt_dump("      version %d\n", stsc->version);
77 	lqt_dump("      flags %ld\n", stsc->flags);
78 	lqt_dump("      total_entries %ld\n", stsc->total_entries);
79 	for(i = 0; i < stsc->total_entries; i++)
80 	{
81 		lqt_dump("       chunk %ld samples %lx id %ld\n",
82 			stsc->table[i].chunk, stsc->table[i].samples, stsc->table[i].id);
83 	}
84 }
85 
quicktime_read_stsc(quicktime_t * file,quicktime_stsc_t * stsc)86 void quicktime_read_stsc(quicktime_t *file, quicktime_stsc_t *stsc)
87 {
88 	int i;
89 	stsc->version = quicktime_read_char(file);
90 	stsc->flags = quicktime_read_int24(file);
91 	stsc->total_entries = quicktime_read_int32(file);
92 
93 	stsc->entries_allocated = stsc->total_entries;
94 	stsc->table = (quicktime_stsc_table_t*)malloc(sizeof(quicktime_stsc_table_t) * stsc->total_entries);
95 	for(i = 0; i < stsc->total_entries; i++)
96 	{
97 		stsc->table[i].chunk = quicktime_read_int32(file);
98 		stsc->table[i].samples = quicktime_read_int32(file);
99 		stsc->table[i].id = quicktime_read_int32(file);
100 	}
101 }
102 
quicktime_compress_stsc(quicktime_stsc_t * stsc)103 void quicktime_compress_stsc(quicktime_stsc_t *stsc)
104   {
105   int i, last_same;
106 
107   /* This can happen, if a stream was created, but no
108      samples have been written. The resulting file will be
109      invalid anyway, just don't let us crash */
110 
111   if(!stsc->table)
112     return;
113 
114   for(i = 1, last_same = 0; i < stsc->total_entries; i++)
115     {
116     if(stsc->table[i].samples != stsc->table[last_same].samples)
117       {
118       /* An entry has a different sample count. */
119       last_same++;
120       if(last_same < i)
121         {
122         /* Move it up the list. */
123         stsc->table[last_same] = stsc->table[i];
124         }
125       }
126     }
127   last_same++;
128   stsc->total_entries = last_same;
129   }
130 
quicktime_write_stsc(quicktime_t * file,quicktime_stsc_t * stsc)131 void quicktime_write_stsc(quicktime_t *file, quicktime_stsc_t *stsc)
132   {
133   int i;
134   quicktime_atom_t atom;
135 
136   quicktime_atom_write_header(file, &atom, "stsc");
137 
138   quicktime_write_char(file, stsc->version);
139   quicktime_write_int24(file, stsc->flags);
140   quicktime_write_int32(file, stsc->total_entries);
141   for(i = 0; i < stsc->total_entries; i++)
142     {
143     quicktime_write_int32(file, stsc->table[i].chunk);
144     quicktime_write_int32(file, stsc->table[i].samples);
145     quicktime_write_int32(file, stsc->table[i].id);
146     }
147 
148   quicktime_atom_write_footer(file, &atom);
149   }
150 
quicktime_update_stsc(quicktime_stsc_t * stsc,long chunk,long samples)151 int quicktime_update_stsc(quicktime_stsc_t *stsc, long chunk, long samples)
152   {
153   chunk++;
154   if(chunk > stsc->entries_allocated)
155     {
156     stsc->entries_allocated = chunk * 2;
157     stsc->table =(quicktime_stsc_table_t*)realloc(stsc->table, sizeof(quicktime_stsc_table_t) * stsc->entries_allocated);
158     }
159 
160   stsc->table[chunk - 1].samples = samples;
161   stsc->table[chunk - 1].chunk = chunk;
162   stsc->table[chunk - 1].id = 1;
163   if(chunk > stsc->total_entries) stsc->total_entries = chunk;
164   return 0;
165   }
166 
167 /* Optimizing while writing doesn't allow seeks during recording so */
168 /* entries are created for every chunk and only optimized during */
169 /* writeout.  Unfortunately there's no way to keep audio synchronized */
170 /* after overwriting  a recording as the fractional audio chunk in the */
171 /* middle always overwrites the previous location of a larger chunk.  On */
172 /* writing, the table must be optimized.  RealProducer requires an  */
173 /* optimized table. */
174 
175