static gboolean vorbis_play (const gchar * filename, VFSFile * file) { if (file == NULL) return FALSE; vorbis_info *vi; OggVorbis_File vf; gint last_section = -1; ReplayGainInfo rg_info; gfloat pcmout[PCM_BUFSIZE*sizeof(float)], **pcm; gint bytes, channels, samplerate, br; gchar * title = NULL; memset(&vf, 0, sizeof(vf)); gboolean error = FALSE; if (ov_open_callbacks (file, & vf, NULL, 0, vfs_is_streaming (file) ? vorbis_callbacks_stream : vorbis_callbacks) < 0) { error = TRUE; goto play_cleanup; } vi = ov_info(&vf, -1); if (vi->channels > 2) goto play_cleanup; br = vi->bitrate_nominal; channels = vi->channels; samplerate = vi->rate; aud_input_set_bitrate (br); if (!aud_input_open_audio(FMT_FLOAT, samplerate, channels)) { error = TRUE; goto play_cleanup; } vorbis_update_replaygain(&vf, &rg_info); aud_input_set_gain (& rg_info); /* * Note that chaining changes things here; A vorbis file may * be a mix of different channels, bitrates and sample rates. * You can fetch the information for any section of the file * using the ov_ interface. */ while (! aud_input_check_stop ()) { int seek_value = aud_input_check_seek(); if (seek_value >= 0 && ov_time_seek (& vf, (double) seek_value / 1000) < 0) { fprintf (stderr, "vorbis: seek failed\n"); error = TRUE; break; } gint current_section = last_section; bytes = ov_read_float(&vf, &pcm, PCM_FRAMES, ¤t_section); if (bytes == OV_HOLE) continue; if (bytes <= 0) break; bytes = vorbis_interleave_buffer (pcm, bytes, channels, pcmout); { /* try to detect when metadata has changed */ vorbis_comment * comment = ov_comment (& vf, -1); const gchar * new_title = (comment == NULL) ? NULL : vorbis_comment_query (comment, "title", 0); if (new_title != NULL && (title == NULL || strcmp (title, new_title))) { g_free (title); title = g_strdup (new_title); aud_input_set_tuple (get_tuple_for_vorbisfile (& vf, filename)); } } if (current_section != last_section) { /* * The info struct is different in each section. vf * holds them all for the given bitstream. This * requests the current one */ vi = ov_info(&vf, -1); if (vi->channels > 2) goto stop_processing; if (vi->rate != samplerate || vi->channels != channels) { samplerate = vi->rate; channels = vi->channels; if (!aud_input_open_audio(FMT_FLOAT, vi->rate, vi->channels)) { error = TRUE; goto stop_processing; } vorbis_update_replaygain(&vf, &rg_info); aud_input_set_gain (& rg_info); /* audio reopened */ } } aud_input_write_audio (pcmout, bytes); stop_processing: if (current_section != last_section) { aud_input_set_bitrate (br); last_section = current_section; } } /* main loop */ play_cleanup: ov_clear(&vf); g_free (title); return ! error; }
static gboolean vorbis_play (InputPlayback * playback, const gchar * filename, VFSFile * file, gint start_time, gint stop_time, gboolean pause) { if (file == NULL) return FALSE; vorbis_info *vi; OggVorbis_File vf; gint last_section = -1; ReplayGainInfo rg_info; gfloat pcmout[PCM_BUFSIZE*sizeof(float)], **pcm; gint bytes, channels, samplerate, br; gchar * title = NULL; seek_value = (start_time > 0) ? start_time : -1; stop_flag = FALSE; memset(&vf, 0, sizeof(vf)); gboolean error = FALSE; if (ov_open_callbacks (file, & vf, NULL, 0, vfs_is_streaming (file) ? vorbis_callbacks_stream : vorbis_callbacks) < 0) { error = TRUE; goto play_cleanup; } vi = ov_info(&vf, -1); if (vi->channels > 2) goto play_cleanup; br = vi->bitrate_nominal; channels = vi->channels; samplerate = vi->rate; playback->set_params (playback, br, samplerate, channels); if (!playback->output->open_audio(FMT_FLOAT, samplerate, channels)) { error = TRUE; goto play_cleanup; } playback->output->flush (start_time); if (pause) playback->output->pause (TRUE); vorbis_update_replaygain(&vf, &rg_info); playback->output->set_replaygain_info (& rg_info); playback->set_pb_ready(playback); /* * Note that chaining changes things here; A vorbis file may * be a mix of different channels, bitrates and sample rates. * You can fetch the information for any section of the file * using the ov_ interface. */ while (1) { if (stop_time >= 0 && playback->output->written_time () >= stop_time) goto DRAIN; pthread_mutex_lock (& seek_mutex); if (stop_flag) { pthread_mutex_unlock (& seek_mutex); break; } if (seek_value >= 0) { ov_time_seek (& vf, (double) seek_value / 1000); playback->output->flush (seek_value); seek_value = -1; } pthread_mutex_unlock (& seek_mutex); gint current_section = last_section; bytes = ov_read_float(&vf, &pcm, PCM_FRAMES, ¤t_section); if (bytes == OV_HOLE) continue; if (bytes <= 0) { DRAIN: break; } bytes = vorbis_interleave_buffer (pcm, bytes, channels, pcmout); { /* try to detect when metadata has changed */ vorbis_comment * comment = ov_comment (& vf, -1); const gchar * new_title = (comment == NULL) ? NULL : vorbis_comment_query (comment, "title", 0); if (new_title != NULL && (title == NULL || strcmp (title, new_title))) { g_free (title); title = g_strdup (new_title); playback->set_tuple (playback, get_tuple_for_vorbisfile (& vf, filename)); } } if (current_section != last_section) { /* * The info struct is different in each section. vf * holds them all for the given bitstream. This * requests the current one */ vi = ov_info(&vf, -1); if (vi->channels > 2) goto stop_processing; if (vi->rate != samplerate || vi->channels != channels) { samplerate = vi->rate; channels = vi->channels; if (!playback->output->open_audio(FMT_FLOAT, vi->rate, vi->channels)) { error = TRUE; goto stop_processing; } playback->output->flush(ov_time_tell(&vf) * 1000); vorbis_update_replaygain(&vf, &rg_info); playback->output->set_replaygain_info (& rg_info); /* audio reopened */ } } playback->output->write_audio (pcmout, bytes); stop_processing: if (current_section != last_section) { playback->set_params (playback, br, samplerate, channels); last_section = current_section; } } /* main loop */ pthread_mutex_lock (& seek_mutex); stop_flag = TRUE; pthread_mutex_unlock (& seek_mutex); play_cleanup: ov_clear(&vf); g_free (title); return ! error; }