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 }