static int mad_stream_info(input_object *obj, stream_info *info) { struct mad_local_data *data; unsigned len; char metadata[256]; char *s, *p; if (!obj || !info) return 0; data = (struct mad_local_data *)obj->local_data; if (data) { if (!data->parse_id3) { sprintf(data->sinfo.title, "%s", data->filename); } else if (!data->parsed_id3) { if (reader_seekable(data->mad_fd)) { parse_id3 (data->path, &data->sinfo); if ((len = strlen(data->sinfo.title))) { s = data->sinfo.title + (len - 1); while (s != data->sinfo.title && *s == ' ') *(s--) = '\0'; } if ((len = strlen(data->sinfo.artist))) { s = data->sinfo.artist + (len - 1); while (s != data->sinfo.artist && *s == ' ') *(s--) = '\0'; } } strncpy (data->sinfo.path, data->path, sizeof(data->sinfo.path)); data->parsed_id3 = 1; } memset(metadata, 0, sizeof(metadata)); if ((len = reader_metadata(data->mad_fd, sizeof(metadata), metadata))) { //alsaplayer_error("Metadata: %s", metadata); if ((s = strstr(metadata, "StreamTitle='"))) { s += 13; if ((p = strstr(s, "'"))) { *p = '\0'; snprintf(data->sinfo.title, 128, "%s", s); } else { alsaplayer_error("Malformed metadata: \"%s\"", metadata); } } } /* Restore permanently filled info */ memcpy (info, &data->sinfo, sizeof (data->sinfo)); /* Compose path, stream_type and status fields */ sprintf(info->stream_type, "MP3 %dKHz %s %-3ldkbit", data->frame.header.samplerate / 1000, obj->nr_channels == 2 ? "stereo" : "mono", data->frame.header.bitrate / 1000); if (data->seeking) sprintf(info->status, "Seeking..."); } return 1; }
static int mad_open(input_object *obj, const char *path) { struct mad_local_data *data; char *p; int mode; if (!obj) return 0; obj->local_data = malloc(sizeof(struct mad_local_data)); if (!obj->local_data) { puts("failed to allocate local data"); return 0; } data = (struct mad_local_data *)obj->local_data; memset(data, 0, sizeof(struct mad_local_data)); if ((data->mad_fd = reader_open(path, &reader_status, obj)) == NULL) { fprintf(stderr, "mad_open(obj, %s) failed\n", path); free(obj->local_data); obj->local_data = NULL; return 0; } obj->flags = 0; if (strncasecmp(path, "http://", 7) == 0) { obj->flags |= P_STREAMBASED; strcpy(data->sinfo.status, "Prebuffering"); } else { obj->flags |= P_FILEBASED; } if (!reader_seekable(data->mad_fd)) { data->seekable = 0; } else { obj->flags |= P_SEEK; obj->flags |= P_PERFECTSEEK; data->seekable = 1; } obj->flags |= P_REENTRANT; mad_init_decoder(data); memset(&data->xing, 0, sizeof(struct xing)); xing_init (&data->xing); data->mad_init = 1; fill_buffer(data, -1); //alsaplayer_error("initial bytes_avail = %d", data->bytes_avail); if (obj->flags & P_PERFECTSEEK) { data->offset = find_initial_frame(data->mad_map, data->bytes_avail < STREAM_BUFFER_SIZE ? data->bytes_avail : STREAM_BUFFER_SIZE); } else { data->offset = 0; } data->highest_frame = 0; if (data->offset < 0) { //fprintf(stderr, "mad_open() couldn't find valid MPEG header\n"); data->offset = 0; } //alsaplayer_error("data->offset = %d", data->offset); if (data->offset > data->bytes_avail) { data->seekable = 1; //alsaplayer_error("Need to refill buffer (data->offset = %d)", data->offset); fill_buffer(data, 0); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); } else { mad_stream_buffer(&data->stream, data->mad_map + data->offset, data->bytes_avail - data->offset); data->bytes_avail -= data->offset; } first_frame: if ((mad_header_decode(&data->frame.header, &data->stream) == -1)) { switch (data->stream.error) { case MAD_ERROR_BUFLEN: return 0; case MAD_ERROR_LOSTSYNC: case MAD_ERROR_BADEMPHASIS: case MAD_ERROR_BADBITRATE: case MAD_ERROR_BADLAYER: case MAD_ERROR_BADSAMPLERATE: //alsaplayer_error("Error %x (frame %d)", data->stream.error, data->current_frame); data->bytes_avail-=(data->stream.next_frame - data->stream.this_frame); goto first_frame; break; case MAD_ERROR_BADBITALLOC: return 0; case MAD_ERROR_BADCRC: alsaplayer_error("MAD_ERROR_BADCRC: %s", error_str(data->stream.error, data->str)); case MAD_ERROR_BADBIGVALUES: case MAD_ERROR_BADDATAPTR: break; default: alsaplayer_error("ERROR: %s", error_str(data->stream.error, data->str)); alsaplayer_error("No valid frame found at start (pos: %d, error: 0x%x --> %x %x %x %x) (%s)", data->offset, data->stream.error, data->stream.this_frame[0], data->stream.this_frame[1], data->stream.this_frame[2], data->stream.this_frame[3],path); return 0; } } mad_frame_decode(&data->frame, &data->stream); /* alsaplayer_error("xing parsing...%x %x %x %x (%x %d)", data->stream.this_frame[0], data->stream.this_frame[1], data->stream.this_frame[2], data->stream.this_frame[3], data->stream.anc_ptr, data->stream.anc_bitlen); */ if (xing_parse(&data->xing, data->stream.anc_ptr, data->stream.anc_bitlen) == 0) { // We use the xing data later on } mode = (data->frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? 1 : 2; data->samplerate = data->frame.header.samplerate; data->bitrate = data->frame.header.bitrate; mad_synth_frame (&data->synth, &data->frame); { struct mad_pcm *pcm = &data->synth.pcm; obj->nr_channels = pcm->channels; //alsaplayer_error("nr_channels = %d", obj->nr_channels); } //alsaplayer_error("Initial: %d, %d, %d", data->samplerate, data->bitrate, obj->nr_channels); /* Calculate some values */ data->bytes_avail = data->stream.bufend - data->stream.next_frame; { int64_t time; int64_t samples; int64_t frames; long oldpos = reader_tell(data->mad_fd); reader_seek(data->mad_fd, 0, SEEK_END); data->filesize = reader_tell(data->mad_fd); data->filesize -= data->offset; reader_seek(data->mad_fd, oldpos, SEEK_SET); if (data->bitrate) time = (data->filesize * 8) / (data->bitrate); else time = 0; samples = 32 * MAD_NSBSAMPLES(&data->frame.header); obj->frame_size = (int) samples << 2; /* Assume 16-bit stereo */ frames = data->samplerate * (time+1) / samples; if (data->xing.flags & XING_FRAMES) { obj->nr_frames = data->xing.frames; } else { obj->nr_frames = (int) frames; } obj->nr_tracks = 1; } /* Determine if nr_frames makes sense */ if (!(obj->flags & P_SEEK) && (obj->flags & P_STREAMBASED)) { obj->nr_frames = -1; } /* Allocate frame index */ if (!data->seekable || obj->nr_frames > 1000000 || (data->frames = (ssize_t *)malloc((obj->nr_frames + FRAME_RESERVE) * sizeof(ssize_t))) == NULL) { data->seekable = 0; // Given really } else { data->seekable = 1; data->frames[0] = 0; } data->mad_init = 1; p = strrchr(path, '/'); if (p) { strcpy(data->filename, ++p); } else { strcpy(data->filename, path); } strcpy(data->path, path); data->parse_id3 = prefs_get_bool(ap_prefs, "mad", "parse_id3", 1); return 1; }
static int flac_open (input_object * obj, const char * name) { if (!obj) return 0; if (!name) return 0; reader_type * rdr = reader_open (name, NULL, NULL); if (!rdr) { alsaplayer_error ("flac_open: reader_open failed"); return 0; } obj->flags = 0; Flac::FlacStream * f = 0; try { if (Flac::FlacStream::isFlacStream (name)) { if (reader_seekable (rdr)) { f = new Flac::FlacSeekableStream (name, rdr); obj->flags |= P_SEEK | P_PERFECTSEEK; } else f = new Flac::FlacStream (name, rdr); } #ifdef HAVE_LIBOGGFLC else { f = new Flac::OggFlacStream (name, rdr); } #endif } catch (...) { alsaplayer_error ("flac_open: unable to allocate memory for plugin."); delete f; reader_close (rdr); return 0; } if (f && f->open ()) { obj->block_size = f->engine ()->apBlockSize (); // attach a song info tag if (Flac::FlacTag::hasTag (f->name ())) { Flac::FlacTag * t = Flac::FlacTag::newTag (f->name ()); f->setTag (t); } if (strncasecmp (name, "http://", 7) == 0) obj->flags |= P_STREAMBASED; else obj->flags |= P_FILEBASED; obj->nr_channels = f->engine ()->apChannels (); obj->flags |= P_REENTRANT; obj->nr_blocks = f->engine ()->apBlocks (); obj->nr_tracks = 1; obj->ready = 1; obj->local_data = (void *) f; return 1; } else { alsaplayer_error ("flac_open: unable to open flac stream or " "unsupported flac stream (%s)", name); delete f; obj->block_size = 0; obj->nr_channels = 0; obj->flags = 0; obj->nr_blocks = 0; obj->nr_tracks = 0; obj->ready = 0; obj->local_data = 0; return 0; } }