int TrackDuration::duration(const QFileInfo &fileinfo) { QString fn = fileinfo.absoluteFilePath(); if (fn.isEmpty()) return 0; QFile file(fn); if (!file.open(QFile::ReadOnly)) return 0; mad_stream infostream; mad_header infoheader; mad_timer_t infotimer; mad_stream_init(&infostream); mad_header_init(&infoheader); mad_timer_reset(&infotimer); qint64 r; qint64 l = 0; unsigned char* buf = new unsigned char[INPUT_BUFFER_SIZE]; while (!file.atEnd()) { if (l < INPUT_BUFFER_SIZE) { r = file.read(reinterpret_cast<char*>(buf) + l, INPUT_BUFFER_SIZE - l); l += r; } mad_stream_buffer(&infostream, buf, l); for (;;) { if (mad_header_decode(&infoheader, &infostream)) { if (!MAD_RECOVERABLE(infostream.error)) break; if (infostream.error == MAD_ERROR_LOSTSYNC) { TagLib::ID3v2::Header header; uint size = (uint)(infostream.bufend - infostream.this_frame); if (size >= header.size()) { header.setData(TagLib::ByteVector(reinterpret_cast<const char*>(infostream.this_frame), size)); uint tagsize = header.tagSize(); if (tagsize > 0) { mad_stream_skip(&infostream, qMin(tagsize, size)); continue; } } } qDebug() << "header decode error while getting file info" << infostream.error; continue; } mad_timer_add(&infotimer, infoheader.duration); } if (infostream.error != MAD_ERROR_BUFLEN && infostream.error != MAD_ERROR_BUFPTR) break; memmove(buf, infostream.next_frame, &(buf[l]) - infostream.next_frame); l -= (infostream.next_frame - buf); } mad_stream_finish(&infostream); mad_header_finish(&infoheader); delete[] buf; return timerToMs(&infotimer); }
/* * NAME: frame->init() * DESCRIPTION: initialize frame struct */ void mad_frame_init(struct mad_frame *frame) { mad_header_init(&frame->header); frame->options = 0; // frame->overlap = 0; mad_frame_mute(frame); }
static int mp_init (int samplerate) { mad_stream_init (&Stream); mad_frame_init (&Frame); mad_synth_init (&Synth); mad_header_init (&Header); mp_samplerate_target = samplerate; return 1; }
static void scan_file (FILE * fd, int *length, int *bitrate) { struct mad_stream stream; struct mad_header header; mad_timer_t timer; unsigned char buffer[8192]; unsigned int buflen = 0; mad_stream_init (&stream); mad_header_init (&header); timer = mad_timer_zero; while (1) { if (buflen < 8192) { int bytes = 0; bytes = fread (buffer + buflen, 1, 8192 - buflen, fd); if (bytes <= 0) break; buflen += bytes; } mad_stream_buffer (&stream, buffer, buflen); while (1) { if (mad_header_decode (&header, &stream) == -1) { if (!MAD_RECOVERABLE (stream.error)) break; continue; } if (length) mad_timer_add (&timer, header.duration); } if (stream.error != MAD_ERROR_BUFLEN) break; memmove (buffer, stream.next_frame, &buffer[buflen] - stream.next_frame); buflen -= stream.next_frame - &buffer[0]; SDL_Delay(1); } mad_header_finish (&header); mad_stream_finish (&stream); if (length) *length = mad_timer_count (timer, MAD_UNITS_MILLISECONDS); }
static int mp_init (music_player_t *music, int samplerate) { mp_player_t *mp = (mp_player_t*)music; mad_stream_init (&mp->Stream); mad_frame_init (&mp->Frame); mad_synth_init (&mp->Synth); mad_header_init (&mp->Header); mp->mp_samplerate_target = samplerate; return 1; }
int Mp3PspStream::initStream() { DEBUG_ENTER_FUNC(); if (_state != MP3_STATE_INIT) deinitStream(); // Init MAD mad_stream_init(&_stream); mad_header_init(&_header); // Reset the stream data _inStream->seek(0, SEEK_SET); _totalTime = mad_timer_zero; _posInFrame = 0; // Update state _state = MP3_STATE_READY; // Read the first few sample bytes into the buffer readMP3DataIntoBuffer(); return true; }
/* Following two functions are adapted from mad_timer, from the libmad distribution */ void scan(void const *ptr, ssize_t len, buffer *buf) { struct mad_stream stream; struct mad_header header; struct xing xing; unsigned long bitrate = 0; int has_xing = 0; int is_vbr = 0; mad_stream_init(&stream); mad_header_init(&header); mad_stream_buffer(&stream, ptr, len); buf->num_frames = 0; /* There are three ways of calculating the length of an mp3: 1) Constant bitrate: One frame can provide the information needed: # of frames and duration. Just see how long it is and do the division. 2) Variable bitrate: Xing tag. It provides the number of frames. Each frame has the same number of samples, so just use that. 3) All: Count up the frames and duration of each frames by decoding each one. We do this if we've no other choice, i.e. if it's a VBR file with no Xing tag. */ while (1) { if (mad_header_decode(&header, &stream) == -1) { if (MAD_RECOVERABLE(stream.error)) continue; else break; } /* Limit xing testing to the first frame header */ if (!buf->num_frames++) { if(parse_xing(&xing, stream.anc_ptr, stream.anc_bitlen)) { is_vbr = 1; if (xing.flags & XING_FRAMES) { /* We use the Xing tag only for frames. If it doesn't have that information, it's useless to us and we have to treat it as a normal VBR file */ has_xing = 1; buf->num_frames = xing.frames; break; } } } /* Test the first n frames to see if this is a VBR file */ if (!is_vbr && !(buf->num_frames > 20)) { if (bitrate && header.bitrate != bitrate) { is_vbr = 1; } else { bitrate = header.bitrate; } } /* We have to assume it's not a VBR file if it hasn't already been marked as one and we've checked n frames for different bitrates */ else if (!is_vbr) { break; } mad_timer_add(&buf->duration, header.duration); } if (!is_vbr) { double time = (len * 8.0) / (header.bitrate); /* time in seconds */ double timefrac = (double)time - ((long)(time)); long nsamples = 32 * MAD_NSBSAMPLES(&header); /* samples per frame */ /* samplerate is a constant */ buf->num_frames = (long) (time * header.samplerate / nsamples); mad_timer_set(&buf->duration, (long)time, (long)(timefrac*100), 100); } else if (has_xing) { /* modify header.duration since we don't need it anymore */ mad_timer_multiply(&header.duration, buf->num_frames); buf->duration = header.duration; } else { /* the durations have been added up, and the number of frames counted. We do nothing here. */ } mad_header_finish(&header); mad_stream_finish(&stream); }
SoundSource::OpenResult SoundSourceMp3::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) { DEBUG_ASSERT(!hasValidChannelCount()); DEBUG_ASSERT(!hasValidSamplingRate()); DEBUG_ASSERT(!m_file.isOpen()); if (!m_file.open(QIODevice::ReadOnly)) { qWarning() << "Failed to open file:" << m_file.fileName(); return OpenResult::FAILED; } // Get a pointer to the file using memory mapped IO m_fileSize = m_file.size(); m_pFileData = m_file.map(0, m_fileSize); // NOTE(uklotzde): If the file disappears unexpectedly while mapped // a SIGBUS error might occur that is not handled and will terminate // Mixxx immediately. This behavior is documented in the manpage of // mmap(). It has already appeared due to hardware errors and is // described in the following bug report: // https://bugs.launchpad.net/mixxx/+bug/1452005 // Transfer it to the mad stream-buffer: mad_stream_options(&m_madStream, MAD_OPTION_IGNORECRC); mad_stream_buffer(&m_madStream, m_pFileData, m_fileSize); DEBUG_ASSERT(m_pFileData == m_madStream.this_frame); DEBUG_ASSERT(m_seekFrameList.empty()); m_avgSeekFrameCount = 0; m_curFrameIndex = getMinFrameIndex(); int headerPerSamplingRate[kSamplingRateCount]; for (int i = 0; i < kSamplingRateCount; ++i) { headerPerSamplingRate[i] = 0; } // Decode all the headers and calculate audio properties unsigned long sumBitrate = 0; mad_header madHeader; mad_header_init(&madHeader); SINT maxChannelCount = getChannelCount(); do { if (!decodeFrameHeader(&madHeader, &m_madStream, true)) { if (isStreamValid(m_madStream)) { // Skip frame continue; } else { // Abort decoding break; } } // Grab data from madHeader const unsigned int madSampleRate = madHeader.samplerate; // TODO(XXX): Replace DEBUG_ASSERT with static_assert // MAD must not change its enum values! DEBUG_ASSERT(MAD_UNITS_8000_HZ == 8000); const mad_units madUnits = static_cast<mad_units>(madSampleRate); const long madFrameLength = mad_timer_count(madHeader.duration, madUnits); if (0 >= madFrameLength) { qWarning() << "Skipping MP3 frame with invalid length" << madFrameLength << "in:" << m_file.fileName(); // Skip frame continue; } const SINT madChannelCount = MAD_NCHANNELS(&madHeader); if (isValidChannelCount(maxChannelCount) && (madChannelCount != maxChannelCount)) { qWarning() << "Differing number of channels" << madChannelCount << "<>" << maxChannelCount << "in some MP3 frame headers:" << m_file.fileName(); } maxChannelCount = math_max(madChannelCount, maxChannelCount); const int samplingRateIndex = getIndexBySamplingRate(madSampleRate); if (samplingRateIndex >= kSamplingRateCount) { qWarning() << "Invalid sample rate:" << m_file.fileName() << madSampleRate; // Abort mad_header_finish(&madHeader); return OpenResult::FAILED; } // Count valid frames separated by its sampling rate headerPerSamplingRate[samplingRateIndex]++; addSeekFrame(m_curFrameIndex, m_madStream.this_frame); // Accumulate data from the header sumBitrate += madHeader.bitrate; // Update current stream position m_curFrameIndex += madFrameLength; DEBUG_ASSERT(m_madStream.this_frame); DEBUG_ASSERT(0 <= (m_madStream.this_frame - m_pFileData)); } while (quint64(m_madStream.this_frame - m_pFileData) < m_fileSize); mad_header_finish(&madHeader); if (MAD_ERROR_NONE != m_madStream.error) { // Unreachable code for recoverable errors DEBUG_ASSERT(!MAD_RECOVERABLE(m_madStream.error)); if (MAD_ERROR_BUFLEN != m_madStream.error) { qWarning() << "Unrecoverable MP3 header error:" << mad_stream_errorstr(&m_madStream); // Abort return OpenResult::FAILED; } } if (m_seekFrameList.empty()) { // This is not a working MP3 file. qWarning() << "SSMP3: This is not a working MP3 file:" << m_file.fileName(); // Abort return OpenResult::FAILED; } int mostCommonSamplingRateIndex = kSamplingRateCount; // invalid int mostCommonSamplingRateCount = 0; int differentRates = 0; for (int i = 0; i < kSamplingRateCount; ++i) { // Find most common sampling rate if (mostCommonSamplingRateCount < headerPerSamplingRate[i]) { mostCommonSamplingRateCount = headerPerSamplingRate[i]; mostCommonSamplingRateIndex = i; differentRates++; } } if (differentRates > 1) { qWarning() << "Differing sampling rate in some headers:" << m_file.fileName(); for (int i = 0; i < kSamplingRateCount; ++i) { if (0 < headerPerSamplingRate[i]) { qWarning() << headerPerSamplingRate[i] << "MP3 headers with sampling rate" << getSamplingRateByIndex(i); } } qWarning() << "MP3 files with varying sample rate are not supported!"; qWarning() << "Since this happens most likely due to a corrupt file"; qWarning() << "Mixxx tries to plays it with the most common sample rate for this file"; } if (mostCommonSamplingRateIndex < kSamplingRateCount) { setSamplingRate(getSamplingRateByIndex(mostCommonSamplingRateIndex)); } else { qWarning() << "No single valid sampling rate in header"; // Abort return OpenResult::FAILED; } // Initialize the AudioSource setChannelCount(maxChannelCount); setFrameCount(m_curFrameIndex); // Calculate average values m_avgSeekFrameCount = getFrameCount() / m_seekFrameList.size(); const unsigned long avgBitrate = sumBitrate / m_seekFrameList.size(); setBitrate(avgBitrate / 1000); // Terminate m_seekFrameList addSeekFrame(m_curFrameIndex, 0); // Reset positions m_curFrameIndex = getMinFrameIndex(); // Restart decoding at the beginning of the audio stream m_curFrameIndex = restartDecoding(m_seekFrameList.front()); if (m_curFrameIndex != m_seekFrameList.front().frameIndex) { qWarning() << "Failed to start decoding:" << m_file.fileName(); // Abort return OpenResult::FAILED; } return OpenResult::SUCCEEDED; }
static void MP3_getInfo() { int FrameCount = 0; struct mad_stream stream; struct mad_header header; mad_stream_init (&stream); mad_header_init (&header); MP3_info.fileSize = size; mad_timer_reset(&MP3_info.length); mad_stream_buffer (&stream, mp3_data, size); while (1){ if (mad_header_decode (&header, &stream) == -1){ if (MAD_RECOVERABLE(stream.error)){ continue; }else{ break; } } //Informazioni solo dal primo frame: if (FrameCount == 0){ switch (header.layer) { case MAD_LAYER_I: strcpy(MP3_info.layer,"I"); break; case MAD_LAYER_II: strcpy(MP3_info.layer,"II"); break; case MAD_LAYER_III: strcpy(MP3_info.layer,"III"); break; default: strcpy(MP3_info.layer,"unknown"); break; } MP3_info.kbit = header.bitrate / 1000; MP3_info.hz = header.samplerate; switch (header.mode) { case MAD_MODE_SINGLE_CHANNEL: strcpy(MP3_info.mode, "single channel"); break; case MAD_MODE_DUAL_CHANNEL: strcpy(MP3_info.mode, "dual channel"); break; case MAD_MODE_JOINT_STEREO: strcpy(MP3_info.mode, "joint (MS/intensity) stereo"); break; case MAD_MODE_STEREO: strcpy(MP3_info.mode, "normal LR stereo"); break; default: strcpy(MP3_info.mode, "unknown"); break; } switch (header.emphasis) { case MAD_EMPHASIS_NONE: strcpy(MP3_info.emphasis,"no"); break; case MAD_EMPHASIS_50_15_US: strcpy(MP3_info.emphasis,"50/15 us"); break; case MAD_EMPHASIS_CCITT_J_17: strcpy(MP3_info.emphasis,"CCITT J.17"); break; case MAD_EMPHASIS_RESERVED: strcpy(MP3_info.emphasis,"reserved(!)"); break; default: strcpy(MP3_info.emphasis,"unknown"); break; } } FrameCount++; mad_timer_add (&MP3_info.length, header.duration); } mad_header_finish (&header); mad_stream_finish (&stream); MP3_info.frames = FrameCount; mad_timer_string(MP3_info.length, MP3_info.strLength, "%02lu:%02u:%02u", MAD_UNITS_HOURS, MAD_UNITS_MILLISECONDS, 0); }
static int get_format(bgav_stream_t * s) { mad_priv_t * priv; const char * version_string; struct mad_header h; priv = s->decoder_priv; mad_header_init(&h); mad_header_decode(&h, &priv->stream); /* Get audio format and create frame */ s->data.audio.format.samplerate = h.samplerate; if(h.mode == MAD_MODE_SINGLE_CHANNEL) s->data.audio.format.num_channels = 1; else s->data.audio.format.num_channels = 2; s->data.audio.format.samplerate = h.samplerate; s->data.audio.format.sample_format = GAVL_SAMPLE_FLOAT; s->data.audio.format.interleave_mode = GAVL_INTERLEAVE_NONE; s->data.audio.format.samples_per_frame = MAD_NSBSAMPLES(&h) * 32; if(!s->codec_bitrate) { if(s->container_bitrate == GAVL_BITRATE_VBR) s->codec_bitrate = GAVL_BITRATE_VBR; else s->codec_bitrate = h.bitrate; } gavl_set_channel_setup(&s->data.audio.format); if(h.flags & MAD_FLAG_MPEG_2_5_EXT) { if(h.layer == 3) s->data.audio.preroll = s->data.audio.format.samples_per_frame * 30; else s->data.audio.preroll = s->data.audio.format.samples_per_frame; version_string = "2.5"; } else if(h.flags & MAD_FLAG_LSF_EXT) { if(h.layer == 3) s->data.audio.preroll = s->data.audio.format.samples_per_frame * 30; else s->data.audio.preroll = s->data.audio.format.samples_per_frame; version_string = "2"; } else { if(h.layer == 3) s->data.audio.preroll = s->data.audio.format.samples_per_frame * 10; else s->data.audio.preroll = s->data.audio.format.samples_per_frame; version_string = "1"; } gavl_metadata_set_nocpy(&s->m, GAVL_META_FORMAT, bgav_sprintf("MPEG-%s layer %d", version_string, h.layer)); priv->audio_frame = gavl_audio_frame_create(&s->data.audio.format); return 1; }
// This is a shorter and faster version of scanFile(), that only scans the samplerate and number of Channels of the stream. void mpgDecoder::readMetaFromFile( playListItem * pli ) { #ifdef HAVE_MAD // use QFile as input Buffer, which is needed by libMad, cause it cannot detect EOF.... QFile madFile(pli->getFile()); madFile.open( QIODevice::ReadOnly ); unsigned char buffer[65536]; mad_stream scanStream; mad_header scanHeader; mad_stream_init (&scanStream); mad_header_init (&scanHeader); // get some more Byte from File... int readCnt = 0; while( !madFile.atEnd() && readCnt < 65536 ) { buffer[readCnt] = madFile.read(1).at(0); readCnt++; } if (madFile.atEnd()) return; mad_stream_buffer (&scanStream, buffer, readCnt ); while (1) { if (mad_header_decode (&scanHeader, &scanStream) == -1) { if (scanStream.error == MAD_ERROR_BUFLEN) break; if (!MAD_RECOVERABLE (scanStream.error)) break; continue; } } pli->setSamplerate( scanHeader.samplerate ); pli->setChannels( MAD_NCHANNELS(&scanHeader) ); mad_header_finish (&scanHeader); mad_stream_finish (&scanStream); #endif // read ID3 Metadata #ifdef HAVE_ID3TAG id3_file* id3f = id3_file_open( pli->getFile().toAscii(), ID3_FILE_MODE_READONLY ); id3_tag* id3 = id3_file_tag( id3f ); // only overwrite metadata of playlist-item if files contains own ones... QString temp = getID3String(id3, ID3_FRAME_ARTIST); if(!temp.isEmpty()) pli->setArtist( temp ); temp = getID3String(id3, ID3_FRAME_TITLE); if(!temp.isEmpty()) pli->setTitle( temp ); temp = getID3String(id3, ID3_FRAME_GENRE); if(!temp.isEmpty()) pli->setGenre( temp ); id3_file_close( id3f ); #endif }
//Get info on file: //Uso LibMad per calcolare la durata del pezzo perché //altrimenti dovrei gestire il buffer anche nella seekNextFrame (senza è troppo lenta). //E' una porcheria ma è più semplice. :) int MP3MEgetInfo(){ unsigned long FrameCount = 0; int fd = -1; int bufferSize = 1024*496; u8 *localBuffer; long singleDataRed = 0; struct mad_stream stream; struct mad_header header; int timeFromID3 = 0; float mediumBitrate = 0.0f; int has_xing = 0; struct xing xing; memset(&xing, 0, sizeof(xing)); if (!MP3ME_tagRead) getMP3METagInfo(MP3ME_fileName, &MP3ME_info); mad_stream_init (&stream); mad_header_init (&header); fd = sceIoOpen(MP3ME_fileName, PSP_O_RDONLY, 0777); if (fd < 0) return -1; long size = sceIoLseek(fd, 0, PSP_SEEK_END); sceIoLseek(fd, 0, PSP_SEEK_SET); MP3ME_tagsize = ID3v2TagSize(MP3ME_fileName); double startPos = MP3ME_tagsize; sceIoLseek32(fd, startPos, PSP_SEEK_SET); //Check for xing frame: unsigned char *xing_buffer; xing_buffer = (unsigned char *)malloc(XING_BUFFER_SIZE); if (xing_buffer != NULL) { sceIoRead(fd, xing_buffer, XING_BUFFER_SIZE); if(parse_xing(xing_buffer, 0, &xing)) { if (xing.flags & XING_FRAMES && xing.frames){ has_xing = 1; bufferSize = 50 * 1024; } } free(xing_buffer); xing_buffer = NULL; } size -= startPos; if (size < bufferSize * 3) bufferSize = size; localBuffer = (unsigned char *) malloc(sizeof(unsigned char) * bufferSize); unsigned char *buff = localBuffer; MP3ME_info.fileType = MP3_TYPE; MP3ME_info.defaultCPUClock = MP3ME_defaultCPUClock; MP3ME_info.needsME = 1; MP3ME_info.fileSize = size; MP3ME_filesize = size; MP3ME_info.framesDecoded = 0; double totalBitrate = 0; int i = 0; for (i=0; i<3; i++){ memset(localBuffer, 0, bufferSize); singleDataRed = sceIoRead(fd, localBuffer, bufferSize); mad_stream_buffer (&stream, localBuffer, singleDataRed); while (1){ if (mad_header_decode (&header, &stream) == -1){ if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN) break; else if (MAD_RECOVERABLE(stream.error)){ continue; }else{ break; } } //Informazioni solo dal primo frame: if (FrameCount++ == 0){ switch (header.layer) { case MAD_LAYER_I: strcpy(MP3ME_info.layer,"I"); break; case MAD_LAYER_II: strcpy(MP3ME_info.layer,"II"); break; case MAD_LAYER_III: strcpy(MP3ME_info.layer,"III"); break; default: strcpy(MP3ME_info.layer,"unknown"); break; } MP3ME_info.kbit = header.bitrate / 1000; MP3ME_info.instantBitrate = header.bitrate; MP3ME_info.hz = header.samplerate; switch (header.mode) { case MAD_MODE_SINGLE_CHANNEL: strcpy(MP3ME_info.mode, "single channel"); break; case MAD_MODE_DUAL_CHANNEL: strcpy(MP3ME_info.mode, "dual channel"); break; case MAD_MODE_JOINT_STEREO: strcpy(MP3ME_info.mode, "joint (MS/intensity) stereo"); break; case MAD_MODE_STEREO: strcpy(MP3ME_info.mode, "normal LR stereo"); break; default: strcpy(MP3ME_info.mode, "unknown"); break; } switch (header.emphasis) { case MAD_EMPHASIS_NONE: strcpy(MP3ME_info.emphasis,"no"); break; case MAD_EMPHASIS_50_15_US: strcpy(MP3ME_info.emphasis,"50/15 us"); break; case MAD_EMPHASIS_CCITT_J_17: strcpy(MP3ME_info.emphasis,"CCITT J.17"); break; case MAD_EMPHASIS_RESERVED: strcpy(MP3ME_info.emphasis,"reserved(!)"); break; default: strcpy(MP3ME_info.emphasis,"unknown"); break; } //Check if lenght found in tag info: if (MP3ME_info.length > 0){ timeFromID3 = 1; break; } if (has_xing) break; } totalBitrate += header.bitrate; } if (size == bufferSize) break; else if (i==0) sceIoLseek(fd, startPos + size/3, PSP_SEEK_SET); else if (i==1) sceIoLseek(fd, startPos + 2 * size/3, PSP_SEEK_SET); if (timeFromID3 || has_xing) break; } mad_header_finish (&header); mad_stream_finish (&stream); if (buff){ free(buff); buff = NULL; } sceIoClose(fd); int secs = 0; if (has_xing) { /* modify header.duration since we don't need it anymore */ mad_timer_multiply(&header.duration, xing.frames); secs = mad_timer_count(header.duration, MAD_UNITS_SECONDS); MP3ME_info.length = secs; } else if (!MP3ME_info.length){ mediumBitrate = totalBitrate / (float)FrameCount; secs = size * 8 / mediumBitrate; MP3ME_info.length = secs; }else{ secs = MP3ME_info.length; } //Formatto in stringa la durata totale: int h = secs / 3600; int m = (secs - h * 3600) / 60; int s = secs - h * 3600 - m * 60; snprintf(MP3ME_info.strLength, sizeof(MP3ME_info.strLength), "%2.2i:%2.2i:%2.2i", h, m, s); return 0; }
static int himd_mp3stream_split_frames(struct himd_mp3stream * stream, unsigned int databytes, unsigned int firstframe, unsigned int lastframe, struct himderrinfo * status) { int gotdata = 1; unsigned int i; struct mad_stream madstream; struct mad_header madheader; /* stream->frameptrs is NULL if the current frame has not been splitted yet */ g_warn_if_fail(stream->frameptrs == NULL); stream->frameptrs = malloc((lastframe - firstframe + 2) * sizeof stream->frameptrs[0]); if(!stream->frameptrs) { set_status_printf(status, HIMD_ERROR_OUT_OF_MEMORY, _("Can't allocate memory for %u frame pointers"), lastframe-firstframe+2); return -1; } /* parse block */ mad_stream_init(&madstream); mad_header_init(&madheader); mad_stream_buffer(&madstream, &stream->blockbuf[0x20], databytes+MAD_BUFFER_GUARD); /* drop unneeded frames in front */ while(firstframe > 0) { if(mad_header_decode(&madheader, &madstream) < 0) { set_status_printf(status, HIMD_ERROR_BAD_DATA_FORMAT, _("Still %u frames to skip: %s"), firstframe, mad_stream_errorstr(&madstream)); gotdata = 0; goto cleanup_decoder; } firstframe--; lastframe--; } /* store needed frames */ for(i = 0;i <= lastframe;i++) { if(mad_header_decode(&madheader, &madstream) < 0 && (madstream.error != MAD_ERROR_LOSTSYNC || i != lastframe)) { set_status_printf(status, HIMD_ERROR_BAD_DATA_FORMAT, _("Frame %u of %u to store: %s"), i+1, lastframe, mad_stream_errorstr(&madstream)); gotdata = 0; goto cleanup_decoder; } stream->frameptrs[i] = madstream.this_frame; } stream->frameptrs[i] = madstream.next_frame; stream->frames = lastframe+1; stream->curframe = 0; cleanup_decoder: mad_header_finish(&madheader); mad_stream_finish(&madstream); if(!gotdata) return -1; return 0; }
static int mad_frame_seek(input_object *obj, int frame) { struct mad_local_data *data; struct mad_header header; int skip; ssize_t byte_offset; if (!obj) return 0; data = (struct mad_local_data *)obj->local_data; if (!data || !data->seekable) return 0; //alsaplayer_error("frame_seek(..., %d)", frame); mad_header_init(&header); data->bytes_avail = 0; if (frame <= data->highest_frame) { skip = 0; if (frame > 4) { skip = 3; } byte_offset = data->frames[frame-skip]; /* Prepare the buffer for a read */ fill_buffer(data, byte_offset); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); skip++; while (skip != 0) { skip--; mad_frame_decode(&data->frame, &data->stream); if (skip == 0) mad_synth_frame (&data->synth, &data->frame); } data->bytes_avail = data->stream.bufend - data->stream.next_frame; data->current_frame = frame; data->seeking = 0; return data->current_frame; } data->seeking = 1; fill_buffer(data, data->frames[data->highest_frame]); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); while (data->highest_frame < frame) { if (data->bytes_avail < 3072) { fill_buffer(data, data->map_offset + MAD_BUFSIZE - data->bytes_avail); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); } if (mad_header_decode(&header, &data->stream) == -1) { if (!MAD_RECOVERABLE(data->stream.error)) { fill_buffer(data, 0); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); data->seeking = 0; return 0; } } data->frames[++data->highest_frame] = data->map_offset + data->stream.this_frame - data->mad_map; data->bytes_avail = data->stream.bufend - data->stream.next_frame; } data->current_frame = data->highest_frame; if (data->current_frame > 4) { skip = 3; fill_buffer(data, data->frames[data->current_frame-skip]); mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail); skip++; while (skip != 0) { skip--; mad_frame_decode(&data->frame, &data->stream); if (skip == 0) mad_synth_frame (&data->synth, &data->frame); data->bytes_avail = data->stream.bufend - data->stream.next_frame; } } data->seeking = 0; return data->current_frame; return 0; }
MadDecoderPrivate() : outputBuffer(0), outputPointer(0), outputBufferEnd(0) { mad_header_init( &firstHeader ); }
static int count_time_internal (struct mp3_data *data) { struct xing xing; unsigned long bitrate = 0; int has_xing = 0; int is_vbr = 0; int num_frames = 0; mad_timer_t duration = mad_timer_zero; struct mad_header header; int good_header = 0; /* Have we decoded any header? */ mad_header_init (&header); xing_init (&xing); /* There are three ways of calculating the length of an mp3: 1) Constant bitrate: One frame can provide the information needed: # of frames and duration. Just see how long it is and do the division. 2) Variable bitrate: Xing tag. It provides the number of frames. Each frame has the same number of samples, so just use that. 3) All: Count up the frames and duration of each frames by decoding each one. We do this if we've no other choice, i.e. if it's a VBR file with no Xing tag. */ while (1) { /* Fill the input buffer if needed */ if (data->stream.buffer == NULL || data->stream.error == MAD_ERROR_BUFLEN) { if (!fill_buff(data)) break; } if (mad_header_decode(&header, &data->stream) == -1) { if (MAD_RECOVERABLE(data->stream.error)) continue; else if (data->stream.error == MAD_ERROR_BUFLEN) continue; else { debug ("Can't decode header: %s", mad_stream_errorstr( &data->stream)); break; } } good_header = 1; /* Limit xing testing to the first frame header */ if (!num_frames++) { if (xing_parse(&xing, data->stream.anc_ptr, data->stream.anc_bitlen) != -1) { is_vbr = 1; debug ("Has XING header"); if (xing.flags & XING_FRAMES) { has_xing = 1; num_frames = xing.frames; break; } debug ("XING header doesn't contain number of " "frames."); } } /* Test the first n frames to see if this is a VBR file */ if (!is_vbr && !(num_frames > 20)) { if (bitrate && header.bitrate != bitrate) { debug ("Detected VBR after %d frames", num_frames); is_vbr = 1; } else bitrate = header.bitrate; } /* We have to assume it's not a VBR file if it hasn't already * been marked as one and we've checked n frames for different * bitrates */ else if (!is_vbr) { debug ("Fixed rate MP3"); break; } mad_timer_add (&duration, header.duration); } if (!good_header) return -1; if (!is_vbr) { /* time in seconds */ double time = (data->size * 8.0) / (header.bitrate); double timefrac = (double)time - ((long)(time)); /* samples per frame */ long nsamples = 32 * MAD_NSBSAMPLES(&header); /* samplerate is a constant */ num_frames = (long) (time * header.samplerate / nsamples); /* the average bitrate is the constant bitrate */ data->avg_bitrate = bitrate; mad_timer_set(&duration, (long)time, (long)(timefrac*100), 100); } else if (has_xing) { mad_timer_multiply (&header.duration, num_frames); duration = header.duration; } else { /* the durations have been added up, and the number of frames counted. We do nothing here. */ debug ("Counted duration by counting frames durations in " "VBR file."); } if (data->avg_bitrate == -1 && mad_timer_count(duration, MAD_UNITS_SECONDS) > 0) { data->avg_bitrate = data->size / mad_timer_count(duration, MAD_UNITS_SECONDS) * 8; } mad_header_finish(&header); debug ("MP3 time: %ld", mad_timer_count (duration, MAD_UNITS_SECONDS)); return mad_timer_count (duration, MAD_UNITS_SECONDS); }
int64 MadDecoder::getDurationMs(unsigned char* buffer, size_t bufferSize) { struct mad_stream madStream; struct mad_frame madFrame; struct mad_header madHeader; mad_timer_t time = mad_timer_zero; bool depadded = false; bool vbr = false; size_t tagsize = 0; size_t consumed = 0; size_t numFrames = 0; size_t initialBitrate = 0; mad_stream_init(&madStream); mad_header_init(&madHeader); mad_frame_init(&madFrame); do // Read data from the MP3 file { int padding = 0; size_t leftover = madStream.bufend - madStream.next_frame; memcpy(buffer, madStream.this_frame, leftover); int bytesRead = fread(buffer + leftover, (size_t)1, bufferSize - leftover, handle_); if (bytesRead <= 0) { break; } for (; !depadded && padding < bytesRead && !buffer[padding]; ++padding); depadded = true; mad_stream_buffer(&madStream, buffer + padding, leftover + bytesRead - padding); while (true) // decode frame headers { madStream.error = MAD_ERROR_NONE; if (mad_header_decode(&madHeader, &madStream) == -1) { if (madStream.error == MAD_ERROR_BUFLEN) // Normal behaviour; get some more data from the file break; if (MAD_RECOVERABLE(madStream.error) == 0) break; if (madStream.error == MAD_ERROR_LOSTSYNC) { unsigned available = (madStream.bufend - madStream.this_frame); tagsize = getId3TagSize(madStream.this_frame, (size_t)available); if (tagsize) // It's some ID3 tags, so just skip { if (tagsize >= available) { _fseeki64(handle_, (int64)(tagsize - available), SEEK_CUR); depadded = false; } mad_stream_skip(&madStream, std::min(tagsize, available)); } } continue; // not an audio frame } mad_timer_add(&time, madHeader.duration); consumed += madStream.next_frame - madStream.this_frame; if (numFrames == 0) { initialBitrate = madHeader.bitrate; // Get the precise frame count from the XING header if present madFrame.header = madHeader; if (mad_frame_decode(&madFrame, &madStream) == -1) { if (MAD_RECOVERABLE(madStream.error) == 0) { break; } } if ((numFrames = xingFrames(madStream.anc_ptr, madStream.anc_bitlen))) { mad_timer_multiply(&time, (signed long)numFrames); break; } } else { vbr |= madHeader.bitrate != initialBitrate; } // If not VBR, we can time just a few frames then extrapolate (not exact!) if (++numFrames == 25 && !vbr) { struct stat st; fstat(fileno(handle_), &st); timerMultiply(&time, (double)(st.st_size - tagsize) / consumed); break; } } // while(true) } while (madStream.error == MAD_ERROR_BUFLEN); mad_frame_finish(&madFrame); mad_header_finish(&madHeader); mad_stream_finish(&madStream); rewind(handle_); return mad_timer_count(time, MAD_UNITS_MILLISECONDS); }
void LibMadWrapper::open() { // avoid multiple calls to open() if (this->infile != nullptr) { return; } this->infile = fopen(this->Filename.c_str(), "rb"); if (this->infile == nullptr) { THROW_RUNTIME_ERROR("fopen failed, errno: " << string(strerror(errno))); } int fd = fileno(this->infile); this->mpeglen = getFileSize(fd); this->mpegbuf = static_cast<unsigned char *>(mmap(nullptr, this->mpeglen, PROT_READ, MAP_SHARED, fd, 0)); if (this->mpegbuf == MAP_FAILED) { THROW_RUNTIME_ERROR("mmap failed for File \"" << this->Filename << ")\""); } this->stream = new struct mad_stream; mad_stream_init(this->stream); /* load buffer with MPEG audio data */ mad_stream_buffer(this->stream, this->mpegbuf, this->mpeglen); // we want to know how many pcm frames there are decoded in this file // therefore decode header of every mpeg frame // pretty expensive, so only to this once if (this->numFrames == 0) { struct mad_header header; mad_header_init(&header); // try to find a valid header int ret = this->findValidHeader(header); if (ret != 0) { // only free the locally used header here, this->stream and this->mpegbuf are freed in LibMadWrapper::close() mad_header_finish(&header); THROW_RUNTIME_ERROR("unable to find a valid frame-header for File \"" + this->Filename + "\""); } this->Format.SetVoices(1); // a first valid header is good, but it may contain garbage this->Format.VoiceChannels[0] = MAD_NCHANNELS(&header); this->Format.SampleRate = header.samplerate; CLOG(LogLevel_t::Debug, "found a first valid header within File \"" << this->Filename << "\"\n\tchannels: " << MAD_NCHANNELS(&header) << "\nsrate: " << header.samplerate); // no clue what this 32 does // stolen from mad_synth_frame() in synth.c this->numFrames += 32 * MAD_NSBSAMPLES(&header); // try to find a second valid header ret = this->findValidHeader(header); if (ret == 0) { // better use format infos from this header this->Format.VoiceChannels[0] = max<int>(MAD_NCHANNELS(&header), this->Format.VoiceChannels[0]); this->Format.SampleRate = header.samplerate; CLOG(LogLevel_t::Debug, "found a second valid header within File \"" << this->Filename << "\"\n\tchannels: " << MAD_NCHANNELS(&header) << "\nsrate: " << header.samplerate); this->numFrames += 32 * MAD_NSBSAMPLES(&header); // now lets go on and decode rest of file while (1) { if (mad_header_decode(&header, this->stream) != 0) { if (MAD_RECOVERABLE(this->stream->error)) { continue; } else { break; } } // sanity checks if (this->Format.Channels() != MAD_NCHANNELS(&header)) { CLOG(LogLevel_t::Warning, "channelcount varies (now: " << MAD_NCHANNELS(&header) << ") within File \"" << this->Filename << ")\""); if (!gConfig.MadPermissive) { THROW_RUNTIME_ERROR("invalid mp3: channelcount varies"); } } if (this->Format.SampleRate != header.samplerate) { CLOG(LogLevel_t::Warning, "samplerate varies (now: " << header.samplerate << ") within File \"" << this->Filename << ")\""); if (!gConfig.MadPermissive) { THROW_RUNTIME_ERROR("invalid mp3: samplerate varies"); } } this->numFrames += 32 * MAD_NSBSAMPLES(&header); } } else { CLOG(LogLevel_t::Warning, "only one valid header found, probably no valid mp3 File \"" << this->Filename << "\""); } // somehow reset libmad stream mad_stream_finish(this->stream); mad_stream_init(this->stream); /* load buffer with MPEG audio data */ mad_stream_buffer(this->stream, this->mpegbuf, this->mpeglen); mad_header_finish(&header); } this->frame.hasValue = true; mad_frame_init(&this->frame.Value); this->synth.hasValue = true; mad_synth_init(&this->synth.Value); }
// the following function has been copied from XMMS' mad input plugin // Copyright (C) 2001-2002 Sam Clegg void mpgDecoder::scanFile( ) { #ifdef HAVE_MAD mad_stream scanStream; mad_header scanHeader; int remainder = 0; int data_used = 0; int pos = 0; unsigned char buffer[4096]; // reset file, so we can read from the beginning madFile->reset(); mad_timer_reset( endPositionTimer ); mad_stream_init (&scanStream); mad_header_init (&scanHeader); while (1) { remainder = scanStream.bufend - scanStream.next_frame; memcpy (buffer, scanStream.this_frame, remainder); // get some more Byte from File... int readCnt = 0; unsigned char* readStart; readStart = buffer+remainder; while( !madFile->atEnd() && readCnt < (4096 - remainder) ) { readStart[readCnt] = madFile->read(1).at(0); readCnt++; } if (madFile->atEnd()) break; mad_stream_buffer (&scanStream, buffer, readCnt + remainder); while (1) { if (mad_header_decode (&scanHeader, &scanStream) == -1) { if (scanStream.error == MAD_ERROR_BUFLEN) { break; } if (!MAD_RECOVERABLE (scanStream.error)) { break; } continue; } pos++; data_used += scanStream.next_frame - scanStream.this_frame; mad_timer_add( endPositionTimer, scanHeader.duration ); if (pos == 1) { sampleRate = scanHeader.samplerate; channels = MAD_NCHANNELS(&scanHeader); } } if (scanStream.error != MAD_ERROR_BUFLEN) break; } mad_header_finish (&scanHeader); mad_stream_finish (&scanStream); // reset the file again, so we can read from the beginning when playing madFile->reset(); #endif }