static gint vorbis_check_fd(const gchar *filename, VFSFile *stream) { OggVorbis_File vfile; gint result; /* * The open function performs full stream detection and machine * initialization. If it returns zero, the stream *is* Vorbis and * we're fully ready to decode. */ memset(&vfile, 0, sizeof(vfile)); result = ov_test_callbacks (stream, & vfile, NULL, 0, vfs_is_streaming (stream) ? vorbis_callbacks_stream : vorbis_callbacks); switch (result) { case OV_EREAD: #ifdef DEBUG g_message("** vorbis.c: Media read error: %s", filename); #endif return FALSE; break; case OV_ENOTVORBIS: #ifdef DEBUG g_message("** vorbis.c: Not Vorbis data: %s", filename); #endif return FALSE; break; case OV_EVERSION: #ifdef DEBUG g_message("** vorbis.c: Version mismatch: %s", filename); #endif return FALSE; break; case OV_EBADHEADER: #ifdef DEBUG g_message("** vorbis.c: Invalid Vorbis bistream header: %s", filename); #endif return FALSE; break; case OV_EFAULT: #ifdef DEBUG g_message("** vorbis.c: Internal logic fault while reading %s", filename); #endif return FALSE; break; case 0: break; default: break; } ov_clear(&vfile); return TRUE; }
LIBMTP_track_t *track_metadata(Tuple *from_tuple) { LIBMTP_track_t *tr; gchar *filename, *uri_path; VFSFile *f; uint64_t filesize; struct stat sb; uri_path = strdup_tuple_filename (from_tuple); gchar *tmp = g_strescape(uri_path,NULL); filename=g_filename_from_uri(tmp,NULL,NULL); g_free(tmp); /* dealing the stream upload (invalidating)*/ if(filename) { f = vfs_fopen(uri_path,"r"); g_free(uri_path); if(vfs_is_streaming(f)) { vfs_fclose(f); g_free(filename); return NULL; } } else { g_print("Warning! the filename is NULL, exiting"); return NULL; } if ( stat(filename, &sb) == -1 ) { #if DEBUG g_print("ERROR! encountered while stat()'ing \"%s\"\n",filename); #endif g_free(filename); return NULL; } filesize = (uint64_t) sb.st_size; /* track metadata*/ tr = LIBMTP_new_track_t(); tr->title = strdup_tuple_field (from_tuple, FIELD_TITLE); tr->artist = strdup_tuple_field (from_tuple, FIELD_ARTIST); tr->album = strdup_tuple_field (from_tuple, FIELD_ALBUM); tr->filesize = filesize; tr->filename = strdup_tuple_field (from_tuple, FIELD_FILE_NAME); tr->duration = (uint32_t)tuple_get_int(from_tuple, FIELD_LENGTH, NULL); tr->filetype = find_filetype (filename); tr->genre = strdup_tuple_field (from_tuple, FIELD_GENRE); tr->date = strdup_tuple_field (from_tuple, FIELD_YEAR); g_free(filename); return tr; }
static gboolean get_song_image (const gchar * filename, VFSFile * file, void * * data, gint64 * size) { OggVorbis_File vfile; if (ov_open_callbacks (file, & vfile, NULL, 0, vfs_is_streaming (file) ? vorbis_callbacks_stream : vorbis_callbacks) < 0) return FALSE; vorbis_comment * comment = ov_comment (& vfile, -1); if (! comment) goto ERR; const gchar * s = vorbis_comment_query (comment, "METADATA_BLOCK_PICTURE", 0); if (! s) goto ERR; gsize length2; void * data2 = g_base64_decode (s, & length2); if (! data2 || length2 < 8) goto PARSE_ERR; gint mime_length = GUINT32_FROM_BE (* (guint32 *) (data2 + 4)); if (length2 < 8 + mime_length + 4) goto PARSE_ERR; gint desc_length = GUINT32_FROM_BE (* (guint32 *) (data2 + 8 + mime_length)); if (length2 < 8 + mime_length + 4 + desc_length + 20) goto PARSE_ERR; * size = GUINT32_FROM_BE (* (guint32 *) (data2 + 8 + mime_length + 4 + desc_length + 16)); if (length2 < 8 + mime_length + 4 + desc_length + 20 + * size) goto PARSE_ERR; * data = g_malloc (* size); memcpy (* data, (char *) data2 + 8 + mime_length + 4 + desc_length + 20, * size); g_free (data2); ov_clear (& vfile); return TRUE; PARSE_ERR: fprintf (stderr, "vorbis: Error parsing METADATA_BLOCK_PICTURE in %s.\n", filename); g_free (data2); ERR: ov_clear (& vfile); return FALSE; }
static Tuple * get_song_tuple (const gchar * filename, VFSFile * file) { OggVorbis_File vfile; /* avoid thread interaction */ Tuple *tuple = NULL; /* * The open function performs full stream detection and * machine initialization. If it returns zero, the stream * *is* Vorbis and we're fully ready to decode. */ if (ov_open_callbacks (file, & vfile, NULL, 0, vfs_is_streaming (file) ? vorbis_callbacks_stream : vorbis_callbacks) < 0) return NULL; tuple = get_tuple_for_vorbisfile(&vfile, filename); ov_clear(&vfile); return tuple; }
static Tuple * get_tuple_for_vorbisfile(OggVorbis_File * vorbisfile, const gchar *filename) { Tuple *tuple; gint length; vorbis_comment *comment = NULL; tuple = tuple_new_from_filename(filename); length = vfs_is_streaming (vorbisfile->datasource) ? -1 : ov_time_total (vorbisfile, -1) * 1000; /* associate with tuple */ tuple_set_int(tuple, FIELD_LENGTH, length); if ((comment = ov_comment(vorbisfile, -1)) != NULL) { gchar *tmps; set_tuple_str(tuple, FIELD_TITLE, comment, "title"); set_tuple_str(tuple, FIELD_ARTIST, comment, "artist"); set_tuple_str(tuple, FIELD_ALBUM, comment, "album"); set_tuple_str(tuple, FIELD_GENRE, comment, "genre"); set_tuple_str(tuple, FIELD_COMMENT, comment, "comment"); if ((tmps = vorbis_comment_query(comment, "tracknumber", 0)) != NULL) tuple_set_int(tuple, FIELD_TRACK_NUMBER, atoi(tmps)); if ((tmps = vorbis_comment_query (comment, "date", 0)) != NULL) tuple_set_int (tuple, FIELD_YEAR, atoi (tmps)); } vorbis_info * info = ov_info (vorbisfile, -1); tuple_set_format (tuple, "Ogg Vorbis", info->channels, info->rate, info->bitrate_nominal / 1000); tuple_set_str(tuple, FIELD_MIMETYPE, "application/ogg"); return tuple; }
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 int wv_can_seek(void *id) { return (vfs_is_streaming((VFSFile *) id) == FALSE); }
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; }