Mercurial > audlegacy-plugins
comparison src/vorbis/vorbis.c @ 2329:7b38e28464ee
Modified the playback loop to fix the last seconds skip (fixes bug #87)
The time won't refresh durnig those few seconds, so it still needs some work...
author | Cristi Magherusan <majeru@atheme.org> |
---|---|
date | Sat, 19 Jan 2008 03:04:39 +0200 |
parents | a13b8f308dce |
children | db02ad480056 |
comparison
equal
deleted
inserted
replaced
2328:224727e6c73d | 2329:7b38e28464ee |
---|---|
1 /* | 1 /* |
2 * Copyright (C) Tony Arcieri <bascule@inferno.tusculum.edu> | 2 * Copyright (C) Tony Arcieri <bascule@inferno.tusculum.edu> |
3 * Copyright (C) 2001-2002 Haavard Kvaalen <havardk@xmms.org> | 3 * Copyright (C) 2001-2002 Haavard Kvaalen <havardk@xmms.org> |
4 * Copyright (C) 2007 William Pitcock <nenolod@sacredspiral.co.uk> | 4 * Copyright (C) 2007 William Pitcock <nenolod@sacredspiral.co.uk> |
5 * Copyright (C) 2008 Cristi Măgherușan <majeru@gentoo.ro> | |
5 * | 6 * |
6 * ReplayGain processing Copyright (C) 2002 Gian-Carlo Pascutto <gcp@sjeng.org> | 7 * ReplayGain processing Copyright (C) 2002 Gian-Carlo Pascutto <gcp@sjeng.org> |
7 * | 8 * |
8 * This program is free software; you can redistribute it and/or | 9 * This program is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU General Public License | 10 * modify it under the terms of the GNU General Public License |
228 seekneeded = -1; | 229 seekneeded = -1; |
229 playback->eof = FALSE; | 230 playback->eof = FALSE; |
230 } | 231 } |
231 } | 232 } |
232 | 233 |
233 static int | |
234 vorbis_process_data(InputPlayback *playback, int last_section, | |
235 gboolean use_rg, float rg_scale) | |
236 { | |
237 char pcmout[4096]; | |
238 int bytes; | |
239 float **pcm; | |
240 | |
241 /* | |
242 * A vorbis physical bitstream may consist of many logical | |
243 * sections (information for each of which may be fetched from | |
244 * the vf structure). This value is filled in by ov_read to | |
245 * alert us what section we're currently decoding in case we | |
246 * need to change playback settings at a section boundary | |
247 */ | |
248 int current_section = last_section; | |
249 | |
250 g_mutex_lock(vf_mutex); | |
251 if (use_rg) { | |
252 bytes = | |
253 ov_read_float(&vf, &pcm, sizeof(pcmout) / 2 / channels, | |
254 ¤t_section); | |
255 if (bytes > 0) | |
256 bytes = vorbis_process_replaygain(pcm, bytes, channels, | |
257 pcmout, rg_scale); | |
258 } | |
259 else { | |
260 bytes = ov_read(&vf, pcmout, sizeof(pcmout), | |
261 (int) (G_BYTE_ORDER == G_BIG_ENDIAN), | |
262 2, 1, ¤t_section); | |
263 } | |
264 | |
265 /* | |
266 * We got some sort of error. Bail. | |
267 */ | |
268 if (bytes <= 0 && bytes != OV_HOLE) { | |
269 g_mutex_unlock(vf_mutex); | |
270 playback->playing = 0; | |
271 playback->output->buffer_free(); | |
272 playback->output->buffer_free(); | |
273 playback->eof = TRUE; | |
274 return last_section; | |
275 } | |
276 | |
277 if (current_section != last_section) { | |
278 /* | |
279 * The info struct is different in each section. vf | |
280 * holds them all for the given bitstream. This | |
281 * requests the current one | |
282 */ | |
283 vorbis_info *vi = ov_info(&vf, -1); | |
284 | |
285 if (vi->channels > 2) { | |
286 playback->eof = TRUE; | |
287 g_mutex_unlock(vf_mutex); | |
288 return current_section; | |
289 } | |
290 | |
291 | |
292 if (vi->rate != samplerate || vi->channels != channels) { | |
293 samplerate = vi->rate; | |
294 channels = vi->channels; | |
295 playback->output->buffer_free(); | |
296 playback->output->buffer_free(); | |
297 playback->output->close_audio(); | |
298 if (!playback->output-> | |
299 open_audio(FMT_S16_NE, vi->rate, vi->channels)) { | |
300 playback->error = TRUE; | |
301 playback->eof = TRUE; | |
302 g_mutex_unlock(vf_mutex); | |
303 return current_section; | |
304 } | |
305 playback->output->flush(ov_time_tell(&vf) * 1000); | |
306 } | |
307 } | |
308 | |
309 g_mutex_unlock(vf_mutex); | |
310 | |
311 playback->pass_audio(playback, FMT_S16_NE, channels, bytes, pcmout, &playback->playing); | |
312 | |
313 if (!playback->playing) | |
314 return current_section; | |
315 | |
316 if (seekneeded != -1) | |
317 do_seek(playback); | |
318 | |
319 return current_section; | |
320 } | |
321 | |
322 static gpointer | 234 static gpointer |
323 vorbis_play_loop(gpointer arg) | 235 vorbis_play_loop(gpointer arg) |
324 { | 236 { |
325 InputPlayback *playback = arg; | 237 InputPlayback *playback = arg; |
326 char *filename = playback->filename; | 238 char *filename = playback->filename; |
348 | 260 |
349 fd = g_new0(VFSVorbisFile, 1); | 261 fd = g_new0(VFSVorbisFile, 1); |
350 fd->fd = stream; | 262 fd->fd = stream; |
351 datasource = (void *) fd; | 263 datasource = (void *) fd; |
352 | 264 |
265 char pcmout[4096]; | |
266 int bytes; | |
267 float **pcm; | |
268 | |
353 /* | 269 /* |
354 * The open function performs full stream detection and | 270 * The open function performs full stream detection and |
355 * machine initialization. None of the rest of ov_xx() works | 271 * machine initialization. None of the rest of ov_xx() works |
356 * without it | 272 * without it |
273 * | |
274 * A vorbis physical bitstream may consist of many logical | |
275 * sections (information for each of which may be fetched from | |
276 * the vf structure). This value is filled in by ov_read to | |
277 * alert us what section we're currently decoding in case we | |
278 * need to change playback settings at a section boundary | |
357 */ | 279 */ |
358 | 280 |
281 | |
359 g_mutex_lock(vf_mutex); | 282 g_mutex_lock(vf_mutex); |
360 if (ov_open_callbacks(datasource, &vf, NULL, 0, aud_vfs_is_streaming(fd->fd) ? vorbis_callbacks_stream : vorbis_callbacks) < 0) { | 283 if (ov_open_callbacks(datasource, &vf, NULL, 0, aud_vfs_is_streaming(fd->fd) ? vorbis_callbacks_stream : vorbis_callbacks) < 0) { |
361 vorbis_callbacks.close_func(datasource); | 284 vorbis_callbacks.close_func(datasource); |
362 g_mutex_unlock(vf_mutex); | 285 g_mutex_unlock(vf_mutex); |
363 playback->eof = TRUE; | 286 playback->eof = TRUE; |
401 * You can fetch the information for any section of the file | 324 * You can fetch the information for any section of the file |
402 * using the ov_ interface. | 325 * using the ov_ interface. |
403 */ | 326 */ |
404 | 327 |
405 while (playback->playing) { | 328 while (playback->playing) { |
406 int current_section; | 329 |
407 | |
408 if (seekneeded != -1) | |
409 do_seek(playback); | |
410 | |
411 if (playback->eof) { | 330 if (playback->eof) { |
412 g_usleep(20000); | 331 g_usleep(20000); |
413 continue; | 332 continue; |
414 } | 333 } |
415 | 334 |
416 current_section = vorbis_process_data(playback, last_section, | 335 if (seekneeded != -1) |
417 use_rg, rg_scale); | 336 do_seek(playback); |
418 | 337 |
419 if (current_section != last_section) { | 338 |
339 int current_section = last_section; | |
340 | |
341 g_mutex_lock(vf_mutex); | |
342 if (use_rg) { | |
343 bytes = | |
344 ov_read_float(&vf, &pcm, sizeof(pcmout) / 2 / channels, | |
345 ¤t_section); | |
346 if (bytes > 0) | |
347 bytes = vorbis_process_replaygain(pcm, bytes, channels, | |
348 pcmout, rg_scale); | |
349 } | |
350 else { | |
351 bytes = ov_read(&vf, pcmout, sizeof(pcmout), | |
352 (int) (G_BYTE_ORDER == G_BIG_ENDIAN), | |
353 2, 1, ¤t_section); | |
354 } | |
355 | |
356 /* | |
357 * We got some sort of error. Bail. | |
358 */ | |
359 if (bytes <= 0 && bytes != OV_HOLE) { | |
360 /* | |
361 * EOF | |
362 */ | |
363 playback->playing = 0; | |
364 playback->output->buffer_free(); | |
365 playback->output->buffer_free(); | |
366 playback->eof = TRUE; | |
367 current_section = last_section; | |
368 } | |
369 | |
370 | |
371 | |
372 if (current_section <= last_section) { | |
420 /* | 373 /* |
421 * set total play time, bitrate, rate, and channels of | 374 * The info struct is different in each section. vf |
422 * current section | 375 * holds them all for the given bitstream. This |
376 * requests the current one | |
423 */ | 377 */ |
424 if (title) | 378 vorbis_info *vi = ov_info(&vf, -1); |
425 g_free(title); | 379 |
426 | 380 if (vi->channels > 2) { |
427 g_mutex_lock(vf_mutex); | 381 playback->eof = TRUE; |
428 title = vorbis_generate_title(&vf, filename); | 382 g_mutex_unlock(vf_mutex); |
429 use_rg = vorbis_update_replaygain(&rg_scale); | 383 goto stop_processing; |
430 | 384 } |
431 if (time != -1) | 385 |
432 time = ov_time_total(&vf, -1) * 1000; | 386 |
433 | 387 if (vi->rate != samplerate || vi->channels != channels) { |
434 g_mutex_unlock(vf_mutex); | 388 samplerate = vi->rate; |
435 | 389 channels = vi->channels; |
436 playback->set_params(playback, title, time, br, samplerate, channels); | 390 playback->output->buffer_free(); |
437 timercount = playback->output->output_time(); | 391 playback->output->buffer_free(); |
438 | 392 playback->output->close_audio(); |
439 last_section = current_section; | 393 if (!playback->output-> |
394 open_audio(FMT_S16_NE, vi->rate, vi->channels)) { | |
395 playback->error = TRUE; | |
396 playback->eof = TRUE; | |
397 g_mutex_unlock(vf_mutex); | |
398 goto stop_processing; | |
399 } | |
400 playback->output->flush(ov_time_tell(&vf) * 1000); | |
401 } | |
440 } | 402 } |
441 } | 403 |
442 if (!playback->error) | 404 g_mutex_unlock(vf_mutex); |
443 playback->output->close_audio(); | 405 |
406 playback->pass_audio(playback, FMT_S16_NE, channels, bytes, pcmout, &playback->playing); | |
407 | |
408 if (!playback->playing) | |
409 goto stop_processing; | |
410 | |
411 if (seekneeded != -1) | |
412 do_seek(playback); | |
413 | |
414 stop_processing: | |
415 | |
416 if (current_section <= last_section) { | |
417 /* | |
418 * set total play time, bitrate, rate, and channels of | |
419 * current section | |
420 */ | |
421 if (title) | |
422 g_free(title); | |
423 | |
424 g_mutex_lock(vf_mutex); | |
425 title = vorbis_generate_title(&vf, filename); | |
426 use_rg = vorbis_update_replaygain(&rg_scale); | |
427 | |
428 if (time != -1) | |
429 time = ov_time_total(&vf, -1) * 1000; | |
430 | |
431 g_mutex_unlock(vf_mutex); | |
432 | |
433 playback->set_params(playback, title, time, br, samplerate, channels); | |
434 | |
435 timercount = playback->output->output_time(); | |
436 | |
437 last_section = current_section; | |
438 | |
439 } | |
440 } | |
441 | |
442 | |
443 | |
444 if (!playback->error) | |
445 playback->output->close_audio(); | |
444 /* fall through intentional */ | 446 /* fall through intentional */ |
445 | 447 |
446 play_cleanup: | 448 /*this loop makes it not skip the last ~4 seconds, but the playback |
447 g_free(title); | 449 * timer isn't updated in this period, so it still needs a bit of work |
448 | 450 * |
449 /* | 451 * majeru |
450 * ov_clear closes the stream if its open. Safe to call on an | |
451 * uninitialized structure as long as we've zeroed it | |
452 */ | 452 */ |
453 while(playback->output->buffer_playing()&& playback->output->buffer_free()) | |
454 g_usleep(50000); | |
455 | |
456 | |
457 play_cleanup: | |
458 g_free(title); | |
459 | |
460 /* | |
461 * ov_clear closes the stream if its open. Safe to call on an | |
462 * uninitialized structure as long as we've zeroed it | |
463 */ | |
453 g_mutex_lock(vf_mutex); | 464 g_mutex_lock(vf_mutex); |
454 ov_clear(&vf); | 465 ov_clear(&vf); |
455 g_mutex_unlock(vf_mutex); | 466 g_mutex_unlock(vf_mutex); |
456 playback->playing = 0; | 467 playback->playing = 0; |
468 playback->output->buffer_free(); | |
457 return NULL; | 469 return NULL; |
458 } | 470 } |
459 | 471 |
460 static void | 472 static void |
461 vorbis_play(InputPlayback *playback) | 473 vorbis_play(InputPlayback *playback) |
884 gint ret = 0; | 896 gint ret = 0; |
885 | 897 |
886 if (handle->probe == FALSE) | 898 if (handle->probe == FALSE) |
887 { | 899 { |
888 ret = aud_vfs_fclose(handle->fd); | 900 ret = aud_vfs_fclose(handle->fd); |
889 // g_free(handle); // it causes double free. i'm not really sure that commenting out at here is correct. --yaz | 901 /* g_free(handle); it causes double free. i'm not really sure that commenting out at here is correct. --yaz*/ |
890 } | 902 } |
891 | 903 |
892 return ret; | 904 return ret; |
893 } | 905 } |
894 | 906 |