diff options
Diffstat (limited to 'lib/rbcodec/codecs/libm4a/m4a.c')
-rw-r--r-- | lib/rbcodec/codecs/libm4a/m4a.c | 148 |
1 files changed, 96 insertions, 52 deletions
diff --git a/lib/rbcodec/codecs/libm4a/m4a.c b/lib/rbcodec/codecs/libm4a/m4a.c index 5fe778ac03..b967e15e7a 100644 --- a/lib/rbcodec/codecs/libm4a/m4a.c +++ b/lib/rbcodec/codecs/libm4a/m4a.c | |||
@@ -23,6 +23,13 @@ | |||
23 | #include <inttypes.h> | 23 | #include <inttypes.h> |
24 | #include "m4a.h" | 24 | #include "m4a.h" |
25 | 25 | ||
26 | #undef DEBUGF | ||
27 | #if defined(DEBUG) | ||
28 | #define DEBUGF stream->ci->debugf | ||
29 | #else | ||
30 | #define DEBUGF(...) | ||
31 | #endif | ||
32 | |||
26 | /* Implementation of the stream.h functions used by libalac */ | 33 | /* Implementation of the stream.h functions used by libalac */ |
27 | 34 | ||
28 | #define _Swap32(v) do { \ | 35 | #define _Swap32(v) do { \ |
@@ -127,76 +134,113 @@ int m4a_check_sample_offset(demux_res_t *demux_res, uint32_t frame, uint32_t *st | |||
127 | return demux_res->lookup_table[i].offset; | 134 | return demux_res->lookup_table[i].offset; |
128 | } | 135 | } |
129 | 136 | ||
130 | /* Find the exact or preceding frame in lookup_table[]. Return both frame | ||
131 | * and byte position of this match. */ | ||
132 | static void gather_offset(demux_res_t *demux_res, uint32_t *frame, uint32_t *offset) | ||
133 | { | ||
134 | uint32_t i = 0; | ||
135 | for (i=0; i<demux_res->num_lookup_table; ++i) | ||
136 | { | ||
137 | if (demux_res->lookup_table[i].offset == 0) | ||
138 | break; | ||
139 | if (demux_res->lookup_table[i].sample > *frame) | ||
140 | break; | ||
141 | } | ||
142 | i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ *frame. */ | ||
143 | *frame = demux_res->lookup_table[i].sample; | ||
144 | *offset = demux_res->lookup_table[i].offset; | ||
145 | } | ||
146 | |||
147 | /* Seek to desired sound sample location. Return 1 on success (and modify | 137 | /* Seek to desired sound sample location. Return 1 on success (and modify |
148 | * sound_samples_done and current_sample), 0 if failed. | 138 | * sound_samples_done and current_sample), 0 if failed. */ |
149 | * | ||
150 | * Find the sample (=frame) that contains the given sound sample, find a best | ||
151 | * fit for this sample in the lookup_table[], seek to the byte position. */ | ||
152 | unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream, | 139 | unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream, |
153 | uint32_t sound_sample_loc, uint32_t* sound_samples_done, | 140 | uint32_t sound_sample_loc, uint32_t* sound_samples_done, |
154 | int* current_sample) | 141 | int* current_sample) |
155 | { | 142 | { |
156 | uint32_t i = 0; | 143 | uint32_t i, sample_i, sound_sample_i; |
157 | uint32_t tmp_var, tmp_cnt, tmp_dur; | 144 | uint32_t time, time_cnt, time_dur; |
158 | uint32_t new_sample = 0; /* Holds the amount of chunks/frames. */ | 145 | uint32_t chunk, chunk_first_sample; |
159 | uint32_t new_sound_sample = 0; /* Sums up total amount of samples. */ | 146 | uint32_t offset; |
160 | uint32_t new_pos; /* Holds the desired chunk/frame index. */ | 147 | time_to_sample_t *tts_tab = demux_res->time_to_sample; |
161 | 148 | sample_offset_t *tco_tab = demux_res->lookup_table; | |
162 | /* First check we have the appropriate metadata - we should always | 149 | uint32_t *tsz_tab = demux_res->sample_byte_sizes; |
163 | * have it. | 150 | |
164 | */ | 151 | /* First check we have the required metadata - we should always have it. */ |
165 | if (!demux_res->num_time_to_samples || !demux_res->num_sample_byte_sizes) | 152 | if (!demux_res->num_time_to_samples || !demux_res->num_sample_byte_sizes) |
166 | { | 153 | { |
167 | return 0; | 154 | return 0; |
168 | } | 155 | } |
169 | 156 | ||
170 | /* Find the destination block from time_to_sample array */ | 157 | /* The 'sound_sample_loc' we have is PCM-based and not directly usable. |
171 | time_to_sample_t *tab = demux_res->time_to_sample; | 158 | * We need to convert it to an MP4 sample number 'sample_i' first. */ |
172 | while (i < demux_res->num_time_to_samples) | 159 | sample_i = sound_sample_i = 0; |
160 | for (time = 0; time < demux_res->num_time_to_samples; ++time) | ||
173 | { | 161 | { |
174 | tmp_cnt = tab[i].sample_count; | 162 | time_cnt = tts_tab[time].sample_count; |
175 | tmp_dur = tab[i].sample_duration; | 163 | time_dur = tts_tab[time].sample_duration; |
176 | tmp_var = tmp_cnt * tmp_dur; | 164 | uint32_t time_var = time_cnt * time_dur; |
177 | if (sound_sample_loc <= new_sound_sample + tmp_var) | 165 | |
166 | if (sound_sample_loc < sound_sample_i + time_var) | ||
178 | { | 167 | { |
179 | tmp_var = (sound_sample_loc - new_sound_sample); | 168 | time_var = sound_sample_loc - sound_sample_i; |
180 | new_sample += tmp_var / tmp_dur; | 169 | sample_i += time_var / time_dur; |
181 | new_sound_sample += tmp_var; | ||
182 | break; | 170 | break; |
183 | } | 171 | } |
184 | new_sample += tmp_cnt; | 172 | |
185 | new_sound_sample += tmp_var; | 173 | sample_i += time_cnt; |
186 | ++i; | 174 | sound_sample_i += time_var; |
175 | } | ||
176 | |||
177 | /* Find the chunk after 'sample_i'. */ | ||
178 | for (chunk = 1; chunk < demux_res->num_lookup_table; ++chunk) | ||
179 | { | ||
180 | if (tco_tab[chunk].offset == 0) | ||
181 | break; | ||
182 | if (tco_tab[chunk].sample > sample_i) | ||
183 | break; | ||
187 | } | 184 | } |
188 | 185 | ||
189 | /* We know the new sample (=frame), now calculate the file position. */ | 186 | /* The preceding chunk is the one that contains 'sample_i'. */ |
190 | gather_offset(demux_res, &new_sample, &new_pos); | 187 | chunk--; |
188 | chunk_first_sample = tco_tab[chunk].sample; | ||
189 | offset = tco_tab[chunk].offset; | ||
191 | 190 | ||
192 | /* We know the new file position, so let's try to seek to it */ | 191 | /* Compute the PCM sample number of the chunk's first sample |
193 | if (stream->ci->seek_buffer(new_pos)) | 192 | * to get an accurate base for sound_sample_i. */ |
193 | i = sound_sample_i = 0; | ||
194 | for (time = 0; time < demux_res->num_time_to_samples; ++time) | ||
194 | { | 195 | { |
195 | *sound_samples_done = new_sound_sample; | 196 | time_cnt = tts_tab[time].sample_count; |
196 | *current_sample = new_sample; | 197 | time_dur = tts_tab[time].sample_duration; |
198 | |||
199 | if (chunk_first_sample < i + time_cnt) | ||
200 | { | ||
201 | sound_sample_i += (chunk_first_sample - i) * time_dur; | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | i += time_cnt; | ||
206 | sound_sample_i += time_cnt * time_dur; | ||
207 | } | ||
208 | |||
209 | DEBUGF("seek chunk=%lu, sample=%lu, soundsample=%lu, offset=%lu\n", | ||
210 | (unsigned long)chunk, (unsigned long)chunk_first_sample, | ||
211 | (unsigned long)sound_sample_i, (unsigned long)offset); | ||
212 | |||
213 | if (tsz_tab) { | ||
214 | /* We have a sample-to-bytes table available so we can do accurate | ||
215 | * seeking. Move one sample at a time and update the file offset and | ||
216 | * PCM sample offset as we go. */ | ||
217 | for (i = chunk_first_sample; | ||
218 | i < sample_i && i < demux_res->num_sample_byte_sizes; ++i) | ||
219 | { | ||
220 | /* this could be unnecessary */ | ||
221 | if (time_cnt == 0 && ++time < demux_res->num_time_to_samples) | ||
222 | { | ||
223 | time_cnt = tts_tab[time].sample_count; | ||
224 | time_dur = tts_tab[time].sample_duration; | ||
225 | } | ||
226 | |||
227 | offset += tsz_tab[i]; | ||
228 | sound_sample_i += time_dur; | ||
229 | time_cnt--; | ||
230 | } | ||
231 | } else { | ||
232 | /* No sample-to-bytes table available so we can only seek to the | ||
233 | * start of a chunk, which is often much lower resolution. */ | ||
234 | sample_i = chunk_first_sample; | ||
235 | } | ||
236 | |||
237 | if (stream->ci->seek_buffer(offset)) | ||
238 | { | ||
239 | *sound_samples_done = sound_sample_i; | ||
240 | *current_sample = sample_i; | ||
197 | return 1; | 241 | return 1; |
198 | } | 242 | } |
199 | 243 | ||
200 | return 0; | 244 | return 0; |
201 | } | 245 | } |
202 | 246 | ||