summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/rbcodec/codecs/libm4a/demux.c31
-rw-r--r--lib/rbcodec/codecs/libm4a/m4a.c148
-rw-r--r--lib/rbcodec/codecs/libm4a/m4a.h1
3 files changed, 127 insertions, 53 deletions
diff --git a/lib/rbcodec/codecs/libm4a/demux.c b/lib/rbcodec/codecs/libm4a/demux.c
index 3bf46efec6..e29ecb8339 100644
--- a/lib/rbcodec/codecs/libm4a/demux.c
+++ b/lib/rbcodec/codecs/libm4a/demux.c
@@ -349,6 +349,7 @@ static bool read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len)
349static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len) 349static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
350{ 350{
351 size_t size_remaining = chunk_len - 8; 351 size_t size_remaining = chunk_len - 8;
352 uint32_t numsizes, i;
352 353
353 /* version */ 354 /* version */
354 stream_read_uint8(qtmovie->stream); 355 stream_read_uint8(qtmovie->stream);
@@ -369,9 +370,37 @@ static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
369 } 370 }
370 size_remaining -= 4; 371 size_remaining -= 4;
371 372
372 qtmovie->res->num_sample_byte_sizes = stream_read_uint32(qtmovie->stream); 373 numsizes = stream_read_uint32(qtmovie->stream);
373 size_remaining -= 4; 374 size_remaining -= 4;
374 375
376 /* Because this table can be really large and is only used to improve seek
377 * accuracy, it's optional. In that case the seek code will fall back to a
378 * less accurate seek method. */
379 qtmovie->res->num_sample_byte_sizes = numsizes;
380 if (numsizes * sizeof(uint32_t) < CODEC_SIZE * 1 / 2)
381 qtmovie->res->sample_byte_sizes = malloc(numsizes * sizeof(uint32_t));
382 else
383 qtmovie->res->sample_byte_sizes = NULL;
384
385 if (qtmovie->res->sample_byte_sizes)
386 {
387 for (i = 0; i < numsizes; ++i)
388 {
389 qtmovie->res->sample_byte_sizes[i] =
390 stream_read_uint32(qtmovie->stream);
391 size_remaining -= 4;
392 }
393
394 if (size_remaining)
395 {
396 DEBUGF("extra bytes after stsz\n");
397 }
398 }
399 else
400 {
401 DEBUGF("stsz too large, ignoring it\n");
402 }
403
375 if (size_remaining) 404 if (size_remaining)
376 { 405 {
377 stream_skip(qtmovie->stream, size_remaining); 406 stream_skip(qtmovie->stream, size_remaining);
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. */
132static 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. */
152unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream, 139unsigned 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
diff --git a/lib/rbcodec/codecs/libm4a/m4a.h b/lib/rbcodec/codecs/libm4a/m4a.h
index aa8e768045..81b10c3a27 100644
--- a/lib/rbcodec/codecs/libm4a/m4a.h
+++ b/lib/rbcodec/codecs/libm4a/m4a.h
@@ -80,6 +80,7 @@ typedef struct
80 time_to_sample_t *time_to_sample; 80 time_to_sample_t *time_to_sample;
81 uint32_t num_time_to_samples; 81 uint32_t num_time_to_samples;
82 82
83 uint32_t *sample_byte_sizes;
83 uint32_t num_sample_byte_sizes; 84 uint32_t num_sample_byte_sizes;
84 85
85 uint32_t codecdata_len; 86 uint32_t codecdata_len;