enum decoder_command decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is, const struct tag *tag) { enum decoder_command cmd; assert(dc.state == DECODE_STATE_DECODE); assert(tag != NULL); /* save the tag */ if (decoder->decoder_tag != NULL) tag_free(decoder->decoder_tag); decoder->decoder_tag = tag_dup(tag); /* check for a new stream tag */ update_stream_tag(decoder, is); /* send tag to music pipe */ if (decoder->stream_tag != NULL) { /* merge with tag from input stream */ struct tag *merged; merged = tag_merge(decoder->stream_tag, decoder->decoder_tag); cmd = do_send_tag(decoder, is, merged); tag_free(merged); } else /* send only the decoder tag */ cmd = do_send_tag(decoder, is, tag); return cmd; }
static void decoder_run_song(struct decoder_control *dc, const struct song *song, const char *uri) { struct decoder decoder = { .dc = dc, }; int ret; decoder.timestamp = 0.0; decoder.seeking = false; decoder.song_tag = song->tag != NULL && song_is_file(song) ? tag_dup(song->tag) : NULL; decoder.stream_tag = NULL; decoder.decoder_tag = NULL; decoder.chunk = NULL; dc->state = DECODE_STATE_START; decoder_command_finished_locked(dc); pcm_convert_init(&decoder.conv_state); ret = song_is_file(song) ? decoder_run_file(&decoder, uri) : decoder_run_stream(&decoder, uri); decoder_unlock(dc); pcm_convert_deinit(&decoder.conv_state); /* flush the last chunk */ if (decoder.chunk != NULL) decoder_flush_chunk(&decoder); if (decoder.song_tag != NULL) tag_free(decoder.song_tag); if (decoder.stream_tag != NULL) tag_free(decoder.stream_tag); if (decoder.decoder_tag != NULL) tag_free(decoder.decoder_tag); decoder_lock(dc); dc->state = ret ? DECODE_STATE_STOP : DECODE_STATE_ERROR; }
int main(int argc, char **argv) { const char *decoder_name, *path; const struct decoder_plugin *plugin; struct tag *tag; bool empty; if (argc != 3) { g_printerr("Usage: read_tags DECODER FILE\n"); return 1; } decoder_name = argv[1]; path = argv[2]; input_stream_global_init(); decoder_plugin_init_all(); plugin = decoder_plugin_from_name(decoder_name); if (plugin == NULL) { g_printerr("No such decoder: %s\n", decoder_name); return 1; } tag = decoder_plugin_tag_dup(plugin, path); decoder_plugin_deinit_all(); input_stream_global_finish(); if (tag == NULL) { g_printerr("Failed to read tags\n"); return 1; } print_tag(tag); empty = tag_is_empty(tag); tag_free(tag); if (empty) { tag = tag_ape_load(path); if (tag == NULL) tag = tag_id3_load(path); if (tag != NULL) { print_tag(tag); tag_free(tag); } } return 0; }
struct tag * tag_merge_replace(struct tag *base, struct tag *add) { if (add == NULL) return base; if (base == NULL) return add; struct tag *tag = tag_merge(base, add); tag_free(base); tag_free(add); return tag; }
static struct tag * oggflac_tag_dup(const char *file) { struct tag *ret = NULL; FLAC__Metadata_Iterator *it; FLAC__StreamMetadata *block; FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new(); if (!(FLAC__metadata_chain_read_ogg(chain, file))) goto out; it = FLAC__metadata_iterator_new(); FLAC__metadata_iterator_init(it, chain); ret = tag_new(); do { if (!(block = FLAC__metadata_iterator_get_block(it))) break; flac_tag_apply_metadata(ret, NULL, block); } while (FLAC__metadata_iterator_next(it)); FLAC__metadata_iterator_delete(it); if (!tag_is_defined(ret)) { tag_free(ret); ret = NULL; } out: FLAC__metadata_chain_delete(chain); return ret; }
struct tag *tag_id3_import(struct id3_tag * tag) { struct tag *ret = tag_new(); getID3Info(tag, ID3_FRAME_ARTIST, TAG_ITEM_ARTIST, ret); getID3Info(tag, ID3_FRAME_ALBUM_ARTIST, TAG_ITEM_ALBUM_ARTIST, ret); getID3Info(tag, ID3_FRAME_ALBUM_ARTIST_SORT, TAG_ITEM_ALBUM_ARTIST, ret); getID3Info(tag, ID3_FRAME_TITLE, TAG_ITEM_TITLE, ret); getID3Info(tag, ID3_FRAME_ALBUM, TAG_ITEM_ALBUM, ret); getID3Info(tag, ID3_FRAME_TRACK, TAG_ITEM_TRACK, ret); getID3Info(tag, ID3_FRAME_YEAR, TAG_ITEM_DATE, ret); getID3Info(tag, ID3_FRAME_GENRE, TAG_ITEM_GENRE, ret); getID3Info(tag, ID3_FRAME_COMPOSER, TAG_ITEM_COMPOSER, ret); getID3Info(tag, ID3_FRAME_PERFORMER, TAG_ITEM_PERFORMER, ret); getID3Info(tag, ID3_FRAME_COMMENT, TAG_ITEM_COMMENT, ret); getID3Info(tag, ID3_FRAME_DISC, TAG_ITEM_DISC, ret); tag_id3_import_musicbrainz(ret, tag); if (tag_is_empty(ret)) { tag_free(ret); ret = NULL; } return ret; }
void song_free(struct song *song) { if (song->tag) tag_free(song->tag); g_free(song); }
bool song_file_update_inarchive(struct song *song) { const char *suffix; const struct decoder_plugin *plugin; assert(song_is_file(song)); /* check if there's a suffix and a plugin */ suffix = uri_get_suffix(song->uri); if (suffix == NULL) return false; plugin = decoder_plugin_from_suffix(suffix, false); if (plugin == NULL) return false; if (song->tag != NULL) tag_free(song->tag); //accept every file that has music suffix //because we don't support tag reading through //input streams song->tag = tag_new(); return true; }
struct tag *tag_id3_import(struct id3_tag * tag) { struct tag *ret = tag_new(); tag_id3_import_text(ret, tag, ID3_FRAME_ARTIST, TAG_ARTIST); tag_id3_import_text(ret, tag, ID3_FRAME_ALBUM_ARTIST, TAG_ALBUM_ARTIST); tag_id3_import_text(ret, tag, ID3_FRAME_ARTIST_SORT, TAG_ARTIST_SORT); tag_id3_import_text(ret, tag, ID3_FRAME_ALBUM_ARTIST_SORT, TAG_ALBUM_ARTIST_SORT); tag_id3_import_text(ret, tag, ID3_FRAME_TITLE, TAG_TITLE); tag_id3_import_text(ret, tag, ID3_FRAME_ALBUM, TAG_ALBUM); tag_id3_import_text(ret, tag, ID3_FRAME_TRACK, TAG_TRACK); tag_id3_import_text(ret, tag, ID3_FRAME_YEAR, TAG_DATE); tag_id3_import_text(ret, tag, ID3_FRAME_GENRE, TAG_GENRE); tag_id3_import_text(ret, tag, ID3_FRAME_COMPOSER, TAG_COMPOSER); tag_id3_import_text(ret, tag, "TPE3", TAG_PERFORMER); tag_id3_import_text(ret, tag, "TPE4", TAG_PERFORMER); tag_id3_import_comment(ret, tag, ID3_FRAME_COMMENT, TAG_COMMENT); tag_id3_import_text(ret, tag, ID3_FRAME_DISC, TAG_DISC); tag_id3_import_musicbrainz(ret, tag); tag_id3_import_ufid(ret, tag); if (tag_is_empty(ret)) { tag_free(ret); ret = NULL; } return ret; }
void flac_data_deinit(struct flac_data *data) { pcm_buffer_deinit(&data->buffer); if (data->tag != NULL) tag_free(data->tag); }
static int dump_input_stream(struct input_stream *is) { GError *error = NULL; char buffer[4096]; size_t num_read; ssize_t num_written; /* wait until the stream becomes ready */ while (!is->ready) { int ret = input_stream_buffer(is, &error); if (ret < 0) { /* error */ g_warning("%s", error->message); g_error_free(error); return 2; } if (ret == 0) /* nothing was buffered - wait */ g_usleep(10000); } /* print meta data */ if (is->mime != NULL) g_printerr("MIME type: %s\n", is->mime); /* read data and tags from the stream */ while (!input_stream_eof(is)) { struct tag *tag = input_stream_tag(is); if (tag != NULL) { g_printerr("Received a tag:\n"); tag_save(stderr, tag); tag_free(tag); } num_read = input_stream_read(is, buffer, sizeof(buffer), &error); if (num_read == 0) { if (error != NULL) { g_warning("%s", error->message); g_error_free(error); } break; } num_written = write(1, buffer, num_read); if (num_written <= 0) break; } return 0; }
enum decoder_command decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is, const struct tag *tag) { G_GNUC_UNUSED const struct decoder_control *dc = decoder->dc; enum decoder_command cmd; assert(dc->state == DECODE_STATE_DECODE); assert(dc->pipe != NULL); assert(tag != NULL); /* save the tag */ if (decoder->decoder_tag != NULL) tag_free(decoder->decoder_tag); decoder->decoder_tag = tag_dup(tag); /* check for a new stream tag */ update_stream_tag(decoder, is); /* check if we're seeking */ if (decoder_prepare_initial_seek(decoder)) /* during initial seek, no music chunk must be created until seeking is finished; skip the rest of the function here */ return DECODE_COMMAND_SEEK; /* send tag to music pipe */ if (decoder->stream_tag != NULL) { /* merge with tag from input stream */ struct tag *merged; merged = tag_merge(decoder->stream_tag, decoder->decoder_tag); cmd = do_send_tag(decoder, is, merged); tag_free(merged); } else /* send only the decoder tag */ cmd = do_send_tag(decoder, is, tag); return cmd; }
/*}}}*/ }; static int psize = sizeof (parseable) / sizeof (parseable[0]); tag_t * tag_alloc (void) /*{{{*/ { tag_t *t; if (t = (tag_t *) malloc (sizeof (tag_t))) { t -> name = xmlBufferCreate (); t -> cname = NULL; t -> hash = 0; t -> type = NULL; t -> topt = NULL; t -> value = xmlBufferCreate (); t -> parm = NULL; t -> used = false; t -> next = NULL; if ((! t -> name) || (! t -> value)) t = tag_free (t); } return t; }/*}}}*/ tag_t * tag_free (tag_t *t) /*{{{*/ { if (t) { if (t -> name) xmlBufferFree (t -> name); if (t -> cname) free (t -> cname); if (t -> type) free (t -> type); if (t -> value) xmlBufferFree (t -> value); if (t -> parm) var_free_all (t -> parm); free (t); } return NULL; }/*}}}*/ tag_t * tag_free_all (tag_t *t) /*{{{*/ { tag_t *tmp; while (tmp = t) { t = t -> next; tag_free (tmp); } return NULL; }/*}}}*/
static void vorbis_send_comments(struct decoder *decoder, struct input_stream *is, char **comments) { struct tag *tag = vorbis_comments_to_tag(comments); if (!tag) return; decoder_tag(decoder, is, tag); tag_free(tag); }
static void mp3_decode(struct decoder *decoder, struct input_stream *input_stream) { struct mp3_data data; GError *error = NULL; struct tag *tag = NULL; struct audio_format audio_format; if (!mp3_open(input_stream, &data, decoder, &tag)) { if (decoder_get_command(decoder) == DECODE_COMMAND_NONE) g_warning ("Input does not appear to be a mp3 bit stream.\n"); return; } if (!audio_format_init_checked(&audio_format, data.frame.header.samplerate, SAMPLE_FORMAT_S24_P32, MAD_NCHANNELS(&data.frame.header), &error)) { g_warning("%s", error->message); g_error_free(error); if (tag != NULL) tag_free(tag); mp3_data_finish(&data); return; } decoder_initialized(decoder, &audio_format, data.input_stream->seekable, data.total_time); if (tag != NULL) { decoder_tag(decoder, input_stream, tag); tag_free(tag); } while (mp3_read(&data)) ; mp3_data_finish(&data); }
static void input_despotify_close(struct input_stream *is) { struct input_despotify *ctx = (struct input_despotify *)is; if (ctx->tag != NULL) tag_free(ctx->tag); mpd_despotify_unregister_callback(callback); despotify_free_track(ctx->track); input_stream_deinit(&ctx->base); g_free(ctx); }
struct tag * vorbis_comments_to_tag(char **comments) { struct tag *tag = tag_new(); vorbis_comments_scan(comments, &add_tag_handler, tag); if (tag_is_empty(tag)) { tag_free(tag); tag = NULL; } return tag; }
bool song_file_update(struct song *song) { const char *suffix; char *path_fs; const struct decoder_plugin *plugin; struct stat st; assert(song_is_file(song)); /* check if there's a suffix and a plugin */ suffix = uri_get_suffix(song->url); if (suffix == NULL) return false; plugin = decoder_plugin_from_suffix(suffix, false); if (plugin == NULL) return false; path_fs = map_song_fs(song); if (path_fs == NULL) return false; if (song->tag != NULL) { tag_free(song->tag); song->tag = NULL; } if (stat(path_fs, &st) < 0 || !S_ISREG(st.st_mode)) { g_free(path_fs); return false; } song->mtime = st.st_mtime; do { song->tag = plugin->tag_dup(path_fs); if (song->tag != NULL) break; plugin = decoder_plugin_from_suffix(suffix, true); } while (plugin != NULL); if (song->tag != NULL && tag_is_empty(song->tag)) song->tag = tag_fallback(path_fs, song->tag); g_free(path_fs); return song->tag != NULL; }
static void flac_decoder_loop(struct flac_data *data, FLAC__StreamDecoder *flac_dec, FLAC__uint64 t_start, FLAC__uint64 t_end) { struct decoder *decoder = data->decoder; enum decoder_command cmd; data->first_frame = t_start; while (true) { if (data->tag != NULL && !tag_is_empty(data->tag)) { cmd = decoder_tag(data->decoder, data->input_stream, data->tag); tag_free(data->tag); data->tag = tag_new(); } else cmd = decoder_get_command(decoder); if (cmd == DECODE_COMMAND_SEEK) { FLAC__uint64 seek_sample = t_start + decoder_seek_where(decoder) * data->audio_format.sample_rate; if (seek_sample >= t_start && (t_end == 0 || seek_sample <= t_end) && FLAC__stream_decoder_seek_absolute(flac_dec, seek_sample)) { data->next_frame = seek_sample; data->position = 0; decoder_command_finished(decoder); } else decoder_seek_error(decoder); } else if (cmd == DECODE_COMMAND_STOP || FLAC__stream_decoder_get_state(flac_dec) == FLAC__STREAM_DECODER_END_OF_STREAM) break; if (t_end != 0 && data->next_frame >= t_end) /* end of this sub track */ break; if (!FLAC__stream_decoder_process_single(flac_dec)) { cmd = decoder_get_command(decoder); if (cmd != DECODE_COMMAND_SEEK) break; } } if (cmd != DECODE_COMMAND_STOP) { flacPrintErroredState(FLAC__stream_decoder_get_state(flac_dec)); FLAC__stream_decoder_finish(flac_dec); } }
/** * The decoder plugin failed to load any tags: fall back to the APE or * ID3 tag loader. */ static struct tag * tag_fallback(const char *path, struct tag *tag) { struct tag *fallback = tag_load_fallback(path); if (fallback != NULL) { /* tag was successfully loaded: copy the song duration, and destroy the old (empty) tag */ fallback->time = tag->time; tag_free(tag); return fallback; } else /* no APE/ID3 tag found: return the empty tag */ return tag; }
static bool mp3_open(struct input_stream *is, struct mp3_data *data, struct decoder *decoder, struct tag **tag) { mp3_data_init(data, decoder, is); *tag = NULL; if (!mp3_decode_first_frame(data, tag)) { mp3_data_finish(data); if (tag && *tag) tag_free(*tag); return false; } return true; }
void screen_free(void) { struct screen *s; while(!SLIST_EMPTY(&W->h.screen)) { s = SLIST_FIRST(&W->h.screen); SLIST_REMOVE_HEAD(&W->h.screen, next); infobar_free(s); tag_free(s); free(s); } }
static void copy_icy_tag(struct input_curl *c) { struct tag *tag = icy_tag(&c->icy_metadata); if (tag == NULL) return; if (c->tag != NULL) tag_free(c->tag); if (c->meta_name != NULL && !tag_has_type(tag, TAG_NAME)) tag_add_item(tag, TAG_NAME, c->meta_name); c->tag = tag; }
/** * Frees this stream (but not the input_stream struct itself). */ static void input_curl_free(struct input_curl *c) { if (c->tag != NULL) tag_free(c->tag); g_free(c->meta_name); input_curl_easy_free(c); if (c->multi != NULL) curl_multi_cleanup(c->multi); g_queue_free(c->buffers); g_free(c->url); input_stream_deinit(&c->base); g_free(c); }
static bool update_stream_tag(struct decoder *decoder, struct input_stream *is) { struct tag *tag; if (is == NULL) return false; tag = input_stream_tag(is); if (tag == NULL) return false; if (decoder->stream_tag != NULL) tag_free(decoder->stream_tag); decoder->stream_tag = tag; return true; }
tag_t * tag_alloc (void) /*{{{*/ { tag_t *t; if (t = (tag_t *) malloc (sizeof (tag_t))) { t -> name = xmlBufferCreate (); t -> cname = NULL; t -> hash = 0; t -> type = NULL; t -> topt = NULL; t -> value = xmlBufferCreate (); t -> parm = NULL; t -> used = false; t -> next = NULL; if ((! t -> name) || (! t -> value)) t = tag_free (t); } return t; }/*}}}*/
static void update_song_tag(struct song *song, const struct tag *new_tag) { if (song_is_file(song)) /* don't update tags of local files, only remote streams may change tags dynamically */ return; struct tag *old_tag = song->tag; song->tag = tag_dup(new_tag); if (old_tag != NULL) tag_free(old_tag); /* the main thread will update the playlist version when he receives this event */ event_pipe_emit(PIPE_EVENT_TAG); /* notify all clients that the tag of the current song has changed */ idle_add(IDLE_PLAYER); }
static bool update_stream_tag(struct decoder *decoder, struct input_stream *is) { struct tag *tag; tag = is != NULL ? input_stream_tag(is) : NULL; if (tag == NULL) { tag = decoder->song_tag; if (tag == NULL) return false; /* no stream tag present - submit the song tag instead */ decoder->song_tag = NULL; } if (decoder->stream_tag != NULL) tag_free(decoder->stream_tag); decoder->stream_tag = tag; return true; }
static void mp3_decode(struct decoder *decoder, struct input_stream *input_stream) { struct mp3_data data; struct tag *tag = NULL; struct replay_gain_info *replay_gain_info = NULL; struct audio_format audio_format; if (!mp3_open(input_stream, &data, decoder, &tag, &replay_gain_info)) { if (decoder_get_command(decoder) == DECODE_COMMAND_NONE) g_warning ("Input does not appear to be a mp3 bit stream.\n"); return; } mp3_audio_format(&data, &audio_format); decoder_initialized(decoder, &audio_format, data.input_stream->seekable, data.total_time); if (tag != NULL) { decoder_tag(decoder, input_stream, tag); tag_free(tag); } while (mp3_read(&data, &replay_gain_info)) ; if (replay_gain_info) replay_gain_info_free(replay_gain_info); if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK && data.mute_frame == MUTEFRAME_SEEK) decoder_command_finished(decoder); mp3_data_finish(&data); }
static void decoder_run_song(struct decoder_control *dc, const struct song *song, const char *uri) { struct decoder decoder = { .dc = dc, .initial_seek_pending = dc->start_ms > 0, .initial_seek_running = false, }; int ret; decoder.timestamp = 0.0; decoder.seeking = false; decoder.song_tag = song->tag != NULL && song_is_file(song) ? tag_dup(song->tag) : NULL; decoder.stream_tag = NULL; decoder.decoder_tag = NULL; decoder.chunk = NULL; dc->state = DECODE_STATE_START; decoder_command_finished_locked(dc); pcm_convert_init(&decoder.conv_state); ret = song_is_file(song) ? decoder_run_file(&decoder, uri) : decoder_run_stream(&decoder, uri); decoder_unlock(dc); pcm_convert_deinit(&decoder.conv_state); /* flush the last chunk */ if (decoder.chunk != NULL) decoder_flush_chunk(&decoder); if (decoder.song_tag != NULL) tag_free(decoder.song_tag); if (decoder.stream_tag != NULL) tag_free(decoder.stream_tag); if (decoder.decoder_tag != NULL) tag_free(decoder.decoder_tag); decoder_lock(dc); dc->state = ret ? DECODE_STATE_STOP : DECODE_STATE_ERROR; } static void decoder_run(struct decoder_control *dc) { const struct song *song = dc->song; char *uri; assert(song != NULL); if (song_is_file(song)) uri = map_song_fs(song); else uri = song_get_uri(song); if (uri == NULL) { dc->state = DECODE_STATE_ERROR; decoder_command_finished_locked(dc); return; } decoder_run_song(dc, song, uri); g_free(uri); } static gpointer decoder_task(gpointer arg) { struct decoder_control *dc = arg; decoder_lock(dc); do { assert(dc->state == DECODE_STATE_STOP || dc->state == DECODE_STATE_ERROR); switch (dc->command) { case DECODE_COMMAND_START: dc_mixramp_start(dc, NULL); dc_mixramp_prev_end(dc, dc->mixramp_end); dc->mixramp_end = NULL; /* Don't free, it's copied above. */ dc->replay_gain_prev_db = dc->replay_gain_db; dc->replay_gain_db = 0; /* fall through */ case DECODE_COMMAND_SEEK: decoder_run(dc); break; case DECODE_COMMAND_STOP: decoder_command_finished_locked(dc); break; case DECODE_COMMAND_NONE: decoder_wait(dc); break; } } while (dc->command != DECODE_COMMAND_NONE || !dc->quit); decoder_unlock(dc); return NULL; } void decoder_thread_start(struct decoder_control *dc) { GError *e = NULL; assert(dc->thread == NULL); dc->quit = false; dc->thread = g_thread_create(decoder_task, dc, true, &e); if (dc->thread == NULL) MPD_ERROR("Failed to spawn decoder task: %s", e->message); }