/* * NAME: tag->query() * DESCRIPTION: if a tag begins at the given location, return its size */ signed long id3_tag_query(id3_byte_t const *data, id3_length_t length) { unsigned int version; int flags; id3_length_t size; flags = tagtype(data, length); assert(data); switch (tagtype(data, length)) { case TAGTYPE_ID3V1: return 128; case TAGTYPE_ID3V2: parse_header(&data, &version, &flags, &size); if (flags & ID3_TAG_FLAG_FOOTERPRESENT) size += 10; return 10 + size; case TAGTYPE_ID3V2_FOOTER: parse_header(&data, &version, &flags, &size); return -size - 10; case TAGTYPE_NONE: break; } return 0; }
/* Attempts to read an ID3 tag at the current location in stream and * consume it all. Returns SOX_EOF if no tag is found. Its up to * caller to recover. * */ static int sox_mp3_inputtag(sox_format_t * ft) { priv_t *p = (priv_t *) ft->priv; int rc = SOX_EOF; size_t remaining; size_t tagsize; /* FIXME: This needs some more work if we are to ever * look at the ID3 frame. This is because the Stream * may not be able to hold the complete ID3 frame. * We should consume the whole frame inside tagtype() * instead of outside of tagframe(). That would support * recovering when Stream contains less then 8-bytes (header) * and also when ID3v2 is bigger then Stream buffer size. * Need to pass in stream so that buffer can be * consumed as well as letting additional data to be * read in. */ remaining = p->Stream.bufend - p->Stream.next_frame; if ((tagsize = tagtype(p->Stream.this_frame, remaining))) { p->mad_stream_skip(&p->Stream, tagsize); rc = SOX_SUCCESS; } /* We know that a valid frame hasn't been found yet * so help libmad out and go back into frame seek mode. * This is true whether an ID3 tag was found or not. */ p->mad_stream_sync(&p->Stream); return rc; }
int id3_tag_query(char *data, int length) { unsigned int version; int flags; int size; switch (tagtype(data, length)) { case TAGTYPE_ID3V1: return 128; case TAGTYPE_ID3V2: parse_header(&data, &version, &flags, &size); if (flags) size += 10; return 10 + size; case TAGTYPE_ID3V2_FOOTER: parse_header(&data, &version, &flags, &size); return -size - 10; case TAGTYPE_NONE: break; } return 0; }
/* * NAME: tag->parse() * DESCRIPTION: parse a complete ID3 tag */ struct id3_tag *id3_tag_parse(id3_byte_t const *data, id3_length_t length) { id3_byte_t const *ptr; unsigned int version; int flags; id3_length_t size; switch (tagtype(data, length)) { case TAGTYPE_ID3V1: return (length < 128) ? 0 : v1_parse(data); case TAGTYPE_ID3V2: break; case TAGTYPE_ID3V2_FOOTER: case TAGTYPE_NONE: return 0; } /* ID3v2.x */ ptr = data; parse_header(&ptr, &version, &flags, &size); switch (ID3_TAG_VERSION_MAJOR(version)) { case 4: if (flags & ID3_TAG_FLAG_FOOTERPRESENT) size += 10; case 2: case 3: return (length < 10 + size) ? 0 : v2_parse(data); } return 0; }
static int sox_mp3seek(sox_format_t * ft, uint64_t offset) { priv_t * p = (priv_t *) ft->priv; size_t initial_bitrate = p->Frame.header.bitrate; size_t tagsize = 0, consumed = 0; sox_bool vbr = sox_false; /* Variable Bit Rate */ sox_bool depadded = sox_false; uint64_t to_skip_samples = 0; /* Reset all */ rewind((FILE*)ft->fp); mad_timer_reset(&p->Timer); p->FrameCount = 0; /* They where opened in startread */ mad_synth_finish(&p->Synth); p->mad_frame_finish(&p->Frame); p->mad_stream_finish(&p->Stream); p->mad_stream_init(&p->Stream); p->mad_frame_init(&p->Frame); p->mad_synth_init(&p->Synth); offset /= ft->signal.channels; to_skip_samples = offset; while(sox_true) { /* Read data from the MP3 file */ int read, padding = 0; size_t leftover = p->Stream.bufend - p->Stream.next_frame; memcpy(p->mp3_buffer, p->Stream.this_frame, leftover); read = fread(p->mp3_buffer + leftover, (size_t) 1, p->mp3_buffer_size - leftover, (FILE*)ft->fp); if (read <= 0) { lsx_debug("seek failure. unexpected EOF (frames=%" PRIuPTR " leftover=%" PRIuPTR ")", p->FrameCount, leftover); break; } for (; !depadded && padding < read && !p->mp3_buffer[padding]; ++padding); depadded = sox_true; p->mad_stream_buffer(&p->Stream, p->mp3_buffer + padding, leftover + read - padding); while (sox_true) { /* Decode frame headers */ static unsigned short samples; p->Stream.error = MAD_ERROR_NONE; /* Not an audio frame */ if (p->mad_header_decode(&p->Frame.header, &p->Stream) == -1) { if (p->Stream.error == MAD_ERROR_BUFLEN) break; /* Normal behaviour; get some more data from the file */ if (!MAD_RECOVERABLE(p->Stream.error)) { lsx_warn("unrecoverable MAD error"); break; } if (p->Stream.error == MAD_ERROR_LOSTSYNC) { unsigned available = (p->Stream.bufend - p->Stream.this_frame); tagsize = tagtype(p->Stream.this_frame, (size_t) available); if (tagsize) { /* It's some ID3 tags, so just skip */ if (tagsize >= available) { fseeko((FILE*)ft->fp, (off_t)(tagsize - available), SEEK_CUR); depadded = sox_false; } p->mad_stream_skip(&p->Stream, min(tagsize, available)); } else lsx_warn("MAD lost sync"); } else lsx_warn("recoverable MAD error"); continue; } consumed += p->Stream.next_frame - p->Stream.this_frame; vbr |= (p->Frame.header.bitrate != initial_bitrate); samples = 32 * MAD_NSBSAMPLES(&p->Frame.header); p->FrameCount++; p->mad_timer_add(&p->Timer, p->Frame.header.duration); if(to_skip_samples <= samples) { p->mad_frame_decode(&p->Frame,&p->Stream); p->mad_synth_frame(&p->Synth, &p->Frame); p->cursamp = to_skip_samples; return SOX_SUCCESS; } else to_skip_samples -= samples; /* If not VBR, we can extrapolate frame size */ if (p->FrameCount == 64 && !vbr) { p->FrameCount = offset / samples; to_skip_samples = offset % samples; if (SOX_SUCCESS != lsx_seeki(ft, (off_t)(p->FrameCount * consumed / 64 + tagsize), SEEK_SET)) return SOX_EOF; /* Reset Stream for refilling buffer */ p->mad_stream_finish(&p->Stream); p->mad_stream_init(&p->Stream); break; } } }; return SOX_EOF; }