Mercurial > audlegacy-plugins
comparison src/alac/plugin.c @ 3154:d7eea4d29d4a
alac: Restructuring from Hans de Goede. (Closes #69)
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Tue, 12 May 2009 15:33:49 -0500 |
parents | 87b0c47089e5 |
children |
comparison
equal
deleted
inserted
replaced
3153:3a1d7d680816 | 3154:d7eea4d29d4a |
---|---|
50 | 50 |
51 #include "demux.h" | 51 #include "demux.h" |
52 #include "decomp.h" | 52 #include "decomp.h" |
53 #include "stream.h" | 53 #include "stream.h" |
54 | 54 |
55 static int input_opened = 0; | 55 static void decode_thread(InputPlayback *playback); |
56 | |
57 gpointer decode_thread(void *args); | |
58 static GThread *playback_thread; | 56 static GThread *playback_thread; |
59 static int seek_to = -1; | 57 static guint64 seek_to = -1; |
58 static guint64 packet0_offset; | |
60 | 59 |
61 extern void set_endian(); | 60 extern void set_endian(); |
62 | 61 |
63 static void alac_about(void) | 62 static void alac_about(void) |
64 { | 63 { |
168 aud_vfs_fclose(input_file); | 167 aud_vfs_fclose(input_file); |
169 | 168 |
170 return build_aud_tuple_from_demux(&demux_res, filename); | 169 return build_aud_tuple_from_demux(&demux_res, filename); |
171 } | 170 } |
172 | 171 |
173 static InputPlayback *playback; | 172 static void play_file(InputPlayback *playback) |
174 | 173 { |
175 static void play_file(InputPlayback *data) | |
176 { | |
177 char *filename = data->filename; | |
178 playback = data; | |
179 playback->playing = TRUE; | 174 playback->playing = TRUE; |
180 playback_thread = g_thread_self(); | 175 playback_thread = g_thread_self(); |
181 playback->set_pb_ready(playback); | 176 playback->set_pb_ready(playback); |
182 decode_thread(filename); | 177 decode_thread(playback); |
183 } | 178 } |
184 | 179 |
185 static void stop(InputPlayback * data) | 180 static void stop(InputPlayback *playback) |
186 { | 181 { |
187 playback->playing = FALSE; | 182 playback->playing = FALSE; |
188 g_thread_join(playback_thread); | 183 g_thread_join(playback_thread); |
189 data->output->close_audio(); | 184 playback->output->close_audio(); |
190 } | 185 } |
191 | 186 |
192 static void do_pause(InputPlayback *data, short paused) | 187 static void do_pause(InputPlayback *playback, short paused) |
193 { | 188 { |
194 data->output->pause(paused); | 189 playback->output->pause(paused); |
195 } | 190 } |
196 | 191 |
197 static void seek(InputPlayback * data, gint time) | 192 static void mseek(InputPlayback* playback, gulong millisecond) |
198 { | 193 { |
199 seek_to = time; | 194 if (!playback->playing) |
200 } | 195 return; |
201 | 196 |
202 void GetBuffer(demux_res_t *demux_res) | 197 seek_to = millisecond; |
203 { | 198 |
204 unsigned long destBufferSize = 1024*16; /* 16kb buffer = 4096 frames = 1 alac sample */ | 199 while (seek_to != -1) |
205 void *pDestBuffer = malloc(destBufferSize); | 200 g_usleep(10000); |
206 int bytes_read = 0; | 201 } |
207 | 202 |
208 unsigned int buffer_size = 1024*128; | 203 static void seek(InputPlayback *playback, gint time) |
209 void *buffer; | 204 { |
210 | 205 mseek(playback, time * 1000); |
211 unsigned int i; | 206 } |
212 | 207 |
213 buffer = malloc(buffer_size); | 208 static guint64 get_packet_offset(demux_res_t *demux_res, guint packet) |
214 | 209 { |
215 for (i = 0; i < demux_res->num_sample_byte_sizes && playback->playing; i++) | 210 guint i; |
211 guint64 offset = 0; | |
212 | |
213 for (i = 0; i < packet; i++) | |
214 offset += demux_res->sample_byte_size[i]; | |
215 | |
216 return offset; | |
217 } | |
218 | |
219 static guint handle_seek(InputPlayback *playback, | |
220 demux_res_t *demux_res, guint current_packet) | |
221 { | |
222 guint i, packet; | |
223 guint64 offset, begin, end; | |
224 guint64 target = (seek_to * demux_res->sample_rate) / 1000; | |
225 | |
226 begin = 0; | |
227 packet = 0; | |
228 for (i = 0; i < demux_res->num_time_to_samples; i++) | |
216 { | 229 { |
217 uint32_t sample_byte_size; | 230 end = begin + demux_res->time_to_sample[i].sample_count * |
218 | 231 demux_res->time_to_sample[i].sample_duration; |
232 if (target >= begin && target < end) | |
233 { | |
234 offset = (target - begin) / | |
235 demux_res->time_to_sample[i].sample_duration; | |
236 /* Calculate packet to seek to */ | |
237 packet += offset; | |
238 /* Calculate resulting seek time */ | |
239 seek_to = (begin + offset * | |
240 demux_res->time_to_sample[i].sample_duration) * 1000 / | |
241 demux_res->sample_rate; | |
242 /* Do the actual seek and flush */ | |
243 offset = get_packet_offset(demux_res, packet) + packet0_offset; | |
244 stream_setpos(demux_res->stream, offset); | |
245 playback->output->flush(seek_to); | |
246 return packet; | |
247 } | |
248 begin = end; | |
249 packet += demux_res->time_to_sample[i].sample_count; | |
250 } | |
251 | |
252 /* If we get here we somehow failed to find the target sample */ | |
253 return current_packet; | |
254 } | |
255 | |
256 static guint get_max_packet_size(demux_res_t *demux_res) | |
257 { | |
258 guint i; | |
259 guint max = 0; | |
260 | |
261 for (i = 0; i < demux_res->num_sample_byte_sizes; i++) | |
262 if (demux_res->sample_byte_size[i] > max) | |
263 max = demux_res->sample_byte_size[i]; | |
264 | |
265 return max; | |
266 } | |
267 | |
268 static guint get_max_packet_duration(demux_res_t *demux_res) | |
269 { | |
270 guint i; | |
271 guint max = 0; | |
272 | |
273 for (i = 0; i < demux_res->num_time_to_samples; i++) | |
274 if (demux_res->time_to_sample[i].sample_duration > max) | |
275 max = demux_res->time_to_sample[i].sample_duration; | |
276 | |
277 return max; | |
278 } | |
279 | |
280 void GetBuffer(InputPlayback *playback, demux_res_t *demux_res) | |
281 { | |
282 void *pDestBuffer = malloc(get_max_packet_duration(demux_res) * 4); | |
283 void *buffer = malloc(get_max_packet_size(demux_res)); | |
284 guint i = 0; | |
285 | |
286 while (playback->playing) | |
287 { | |
219 int outputBytes; | 288 int outputBytes; |
220 | 289 |
221 #if 0 | 290 if (seek_to != -1) |
222 /* XXX: Horribly inaccurate seek. -nenolod */ | 291 { |
223 if (seek_to != -1) | 292 i = handle_seek(playback, demux_res, i); |
224 { | 293 seek_to = -1; |
225 gulong duration = | 294 } |
226 (demux_res->num_sample_byte_sizes * (float)((1024 * demux_res->sample_size) - 1.0) / | 295 |
227 (float)(demux_res->sample_rate / 251)); | 296 if (i < demux_res->num_sample_byte_sizes) |
228 | 297 { |
229 i = (duration - seek_to) / demux_res->num_sample_byte_sizes; | 298 /* just get one sample for now */ |
230 | 299 stream_read(demux_res->stream, demux_res->sample_byte_size[i], buffer); |
231 g_print("seek to ALAC frame: %d\n", i); | 300 |
232 | 301 /* now fetch */ |
233 seek_to = -1; | 302 decode_frame(demux_res->alac, buffer, pDestBuffer, &outputBytes); |
234 } | 303 |
235 #endif | 304 /* write */ |
236 | 305 playback->pass_audio(playback, FMT_S16_LE, demux_res->num_channels, outputBytes, pDestBuffer, &playback->playing); |
237 /* just get one sample for now */ | 306 |
238 sample_byte_size = demux_res->sample_byte_size[i]; | 307 i++; |
239 | 308 |
240 if (buffer_size < sample_byte_size) | 309 /* When we are at the end stop pre-buffering */ |
241 return; | 310 if (i == demux_res->num_sample_byte_sizes) |
242 | 311 { |
243 stream_read(demux_res->stream, sample_byte_size, buffer); | 312 playback->output->buffer_free(); |
244 | 313 playback->output->buffer_free(); |
245 /* now fetch */ | 314 } |
246 outputBytes = destBufferSize; | 315 } |
247 decode_frame(demux_res->alac, buffer, pDestBuffer, &outputBytes); | 316 else |
248 | 317 { |
249 /* write */ | 318 /* Wait for output buffer to drain */ |
250 bytes_read += outputBytes; | 319 if (!playback->output->buffer_playing()) |
251 | 320 playback->playing = FALSE; |
252 playback->pass_audio(playback, FMT_S16_LE, demux_res->num_channels, outputBytes, pDestBuffer, &playback->playing); | 321 |
322 if (playback->playing) | |
323 g_usleep(40000); | |
324 } | |
253 } | 325 } |
254 | 326 |
255 free(buffer); | 327 free(buffer); |
256 free(pDestBuffer); | 328 free(pDestBuffer); |
257 } | 329 } |
263 .about = alac_about, | 335 .about = alac_about, |
264 .play_file = play_file, | 336 .play_file = play_file, |
265 .stop = stop, | 337 .stop = stop, |
266 .pause = do_pause, | 338 .pause = do_pause, |
267 .seek = seek, | 339 .seek = seek, |
340 .mseek = mseek, | |
268 .get_song_tuple = build_tuple, | 341 .get_song_tuple = build_tuple, |
269 .is_our_file_from_vfs = is_our_fd, | 342 .is_our_file_from_vfs = is_our_fd, |
270 .vfs_extensions = fmts, | 343 .vfs_extensions = fmts, |
271 }; | 344 }; |
272 | 345 |
273 InputPlugin *alac_iplist[] = { &alac_ip, NULL }; | 346 InputPlugin *alac_iplist[] = { &alac_ip, NULL }; |
274 | 347 |
275 DECLARE_PLUGIN(alac, NULL, NULL, alac_iplist, NULL, NULL, NULL, NULL, NULL); | 348 DECLARE_PLUGIN(alac, NULL, NULL, alac_iplist, NULL, NULL, NULL, NULL, NULL); |
276 | 349 |
277 gpointer decode_thread(void *args) | 350 static void decode_thread(InputPlayback *playback) |
278 { | 351 { |
279 demux_res_t demux_res; | 352 demux_res_t demux_res; |
280 VFSFile *input_file; | 353 VFSFile *input_file; |
281 stream_t *input_stream; | 354 stream_t *input_stream; |
282 Tuple *ti; | 355 Tuple *ti; |
284 | 357 |
285 memset(&demux_res, 0, sizeof(demux_res)); | 358 memset(&demux_res, 0, sizeof(demux_res)); |
286 | 359 |
287 set_endian(); | 360 set_endian(); |
288 | 361 |
289 input_file = aud_vfs_fopen((char *) args, "rb"); | 362 input_file = aud_vfs_fopen(playback->filename, "rb"); |
363 if (!input_file) | |
364 goto exit; | |
365 | |
290 input_stream = stream_create_file(input_file, 1); | 366 input_stream = stream_create_file(input_file, 1); |
291 | |
292 if (!input_stream) | |
293 return NULL; | |
294 | 367 |
295 /* if qtmovie_read returns successfully, the stream is up to | 368 /* if qtmovie_read returns successfully, the stream is up to |
296 * the movie data, which can be used directly by the decoder */ | 369 * the movie data, which can be used directly by the decoder */ |
297 if (!qtmovie_read(input_stream, &demux_res)) | 370 if (!qtmovie_read(input_stream, &demux_res)) |
298 return NULL; | 371 goto exit_free_stream; |
299 | 372 |
300 demux_res.stream = input_stream; | 373 demux_res.stream = input_stream; |
374 packet0_offset = stream_tell(input_stream); | |
301 | 375 |
302 /* Get the titlestring ready. */ | 376 /* Get the titlestring ready. */ |
303 ti = build_aud_tuple_from_demux(&demux_res, (char *) args); | 377 ti = build_aud_tuple_from_demux(&demux_res, playback->filename); |
304 title = aud_tuple_formatter_make_title_string(ti, aud_get_gentitle_format()); | 378 title = aud_tuple_formatter_make_title_string(ti, aud_get_gentitle_format()); |
305 | 379 |
306 /* initialise the sound converter */ | 380 /* initialise the sound converter */ |
307 demux_res.alac = create_alac(demux_res.sample_size, demux_res.num_channels); | 381 demux_res.alac = create_alac(demux_res.sample_size, demux_res.num_channels); |
308 alac_set_info(demux_res.alac, demux_res.codecdata); | 382 alac_set_info(demux_res.alac, demux_res.codecdata); |
309 | 383 |
310 playback->output->open_audio(FMT_S16_LE, demux_res.sample_rate, demux_res.num_channels); | 384 if (!playback->output->open_audio(FMT_S16_LE, demux_res.sample_rate, demux_res.num_channels)) |
385 goto exit_free_alac; | |
386 | |
311 playback->set_params(playback, title, get_duration(&demux_res), -1, demux_res.sample_rate, demux_res.num_channels); | 387 playback->set_params(playback, title, get_duration(&demux_res), -1, demux_res.sample_rate, demux_res.num_channels); |
312 | 388 |
313 /* will convert the entire buffer */ | 389 /* will convert the entire buffer */ |
314 GetBuffer(&demux_res); | 390 GetBuffer(playback, &demux_res); |
315 | 391 |
316 if (playback->playing) { | 392 playback->output->close_audio(); |
317 playback->output->buffer_free(); | 393 exit_free_alac: |
318 playback->output->buffer_free(); | 394 free(demux_res.alac); |
319 while (playback->output->buffer_playing() && playback->playing) | 395 exit_free_stream: |
320 g_usleep(100000); | |
321 } | |
322 | |
323 stream_destroy(input_stream); | 396 stream_destroy(input_stream); |
324 | 397 aud_vfs_fclose(input_file); |
325 if (input_opened) | 398 exit: |
326 aud_vfs_fclose(input_file); | |
327 | |
328 playback->output->close_audio(); | |
329 | |
330 playback->playing = FALSE; | 399 playback->playing = FALSE; |
331 | 400 return; |
332 return NULL; | 401 } |
333 } |