SoundSource::OpenResult SoundSourceOpus::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) { // From opus/opusfile.h // On Windows, this string must be UTF-8 (to allow access to // files whose names cannot be represented in the current // MBCS code page). // All other systems use the native character encoding. #ifdef _WIN32 QByteArray qBAFilename = getLocalFileName().toUtf8(); #else QByteArray qBAFilename = getLocalFileName().toLocal8Bit(); #endif int errorCode = 0; DEBUG_ASSERT(!m_pOggOpusFile); m_pOggOpusFile = op_open_file(qBAFilename.constData(), &errorCode); if (!m_pOggOpusFile) { qWarning() << "Failed to open OggOpus file:" << getUrlString() << "errorCode" << errorCode; return OpenResult::FAILED; } if (!op_seekable(m_pOggOpusFile)) { qWarning() << "SoundSourceOpus:" << "Stream in" << getUrlString() << "is not seekable"; return OpenResult::UNSUPPORTED_FORMAT; } const int channelCount = op_channel_count(m_pOggOpusFile, kCurrentStreamLink); if (0 < channelCount) { setChannelCount(channelCount); } else { qWarning() << "Failed to read channel configuration of OggOpus file:" << getUrlString(); return OpenResult::FAILED; } const ogg_int64_t pcmTotal = op_pcm_total(m_pOggOpusFile, kEntireStreamLink); if (0 <= pcmTotal) { setFrameCount(pcmTotal); } else { qWarning() << "Failed to read total length of OggOpus file:" << getUrlString(); return OpenResult::FAILED; } const opus_int32 bitrate = op_bitrate(m_pOggOpusFile, kEntireStreamLink); if (0 < bitrate) { setBitrate(bitrate / 1000); } else { qWarning() << "Failed to determine bitrate of OggOpus file:" << getUrlString(); return OpenResult::FAILED; } setSamplingRate(kSamplingRate); m_curFrameIndex = getMinFrameIndex(); return OpenResult::SUCCEEDED; }
Result SoundSourceSndFile::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) { DEBUG_ASSERT(!m_pSndFile); SF_INFO sfInfo; #ifdef __WINDOWS__ // Pointer valid until string changed const QString fileName(getLocalFileName()); LPCWSTR lpcwFilename = (LPCWSTR) fileName.utf16(); m_pSndFile = sf_wchar_open(lpcwFilename, SFM_READ, &sfInfo); #else memset(&sfInfo, 0, sizeof(sfInfo)); m_pSndFile = sf_open(getLocalFileNameBytes().constData(), SFM_READ, &sfInfo); #endif if (!m_pSndFile) { // sf_format_check is only for writes qWarning() << "Error opening libsndfile file:" << getUrlString() << sf_strerror(m_pSndFile); return ERR; } if (sf_error(m_pSndFile) > 0) { qWarning() << "Error opening libsndfile file:" << getUrlString() << sf_strerror(m_pSndFile); return ERR; } setChannelCount(sfInfo.channels); setFrameRate(sfInfo.samplerate); setFrameCount(sfInfo.frames); return OK; }
//0:success, 1:error reply, -1:not completed int insertPplState(ppl* p) { char url[1000]; int len_headers=6; htmlContent* h; int result; printf("inserting ppl state...\n"); httpRequestHeader* headers = (httpRequestHeader*)malloc(len_headers*sizeof(httpRequestHeader)); strcpy(headers[0].name, "ItemName"); sprintf(headers[0].value,"%d%c%ld",p->uid, AWS_API_KEY_SEPARATOR, p->ts); strcpy(headers[1].name, "Attribute.1.Name"); strcpy(headers[1].value, "nfoer"); strcpy(headers[2].name, "Attribute.1.Value"); sprintf(headers[2].value, "%d",p->nfoer); strcpy(headers[3].name, "Attribute.2.Name"); strcpy(headers[3].value, "nsaying"); strcpy(headers[4].name, "Attribute.2.Value"); sprintf(headers[4].value, "%d",p->nsaying); strcat(headers[5].name, "DomainName"); strcpy(headers[5].value, "weibopplclustering"); //strcpy(headers[4].value, p->nsaying); getUrlString(url, HTTP_METHOD_GET, AWS_API_SDB_NAME_PUTATTRIBUTE, headers, len_headers); // httpGet(url, cbPutAttributes, printf("insertpplstate url=\n%s\n", url); result = -1; //0:success, 1:error reply, -1:not completed h = createHtmlContent(); h->z = (void*)&result; httpGet(url, cbPutAttributes, h); return *((int*)h->z); }
SoundSource::OpenResult SoundSourceMediaFoundation::tryOpen(const AudioSourceConfig& audioSrcCfg) { if (SUCCEEDED(m_hrCoInitialize)) { qWarning() << "Cannot reopen MediaFoundation file" << getUrlString(); return OpenResult::FAILED; } const QString fileName(getLocalFileName()); if (sDebug) { qDebug() << "open()" << fileName; } // Initialize the COM library. m_hrCoInitialize = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); if (FAILED(m_hrCoInitialize)) { qWarning() << "SSMF: failed to initialize COM"; return OpenResult::FAILED; } // Initialize the Media Foundation platform. m_hrMFStartup = MFStartup(MF_VERSION); if (FAILED(m_hrCoInitialize)) { qWarning() << "SSMF: failed to initialize Media Foundation"; return OpenResult::FAILED; } // Create the source reader to read the input file. // Note: we cannot use QString::toStdWString since QT 4 is compiled with // '/Zc:wchar_t-' flag and QT 5 not const ushort* const fileNameUtf16 = fileName.utf16(); static_assert(sizeof(wchar_t) == sizeof(ushort), "QString::utf16(): wchar_t and ushort have different sizes"); HRESULT hr = MFCreateSourceReaderFromURL( reinterpret_cast<const wchar_t*>(fileNameUtf16), nullptr, &m_pReader); if (FAILED(hr)) { qWarning() << "SSMF: Error opening input file:" << fileName; return OpenResult::FAILED; } if (!configureAudioStream(audioSrcCfg)) { qWarning() << "SSMF: Error configuring audio stream."; return OpenResult::FAILED; } if (!readProperties()) { qWarning() << "SSMF::readProperties failed"; return OpenResult::FAILED; } //Seek to position 0, which forces us to skip over all the header frames. //This makes sure we're ready to just let the Analyzer rip and it'll //get the number of samples it expects (ie. no header frames). seekSampleFrame(0); return OpenResult::SUCCEEDED; }
Result SoundSourceOggVorbis::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) { m_pFile = new QFile(getLocalFileName()); if(!m_pFile->open(QFile::ReadOnly)) { qWarning() << "Failed to open OggVorbis file:" << getUrlString(); return ERR; } if (ov_open_callbacks(m_pFile, &m_vf, NULL, 0, s_callbacks) < 0) { qDebug() << "oggvorbis: Input does not appear to be an Ogg bitstream."; return ERR; } if (!ov_seekable(&m_vf)) { qWarning() << "OggVorbis file is not seekable:" << getUrlString(); return ERR; } // lookup the ogg's channels and sample rate const vorbis_info* vi = ov_info(&m_vf, kCurrentBitstreamLink); if (!vi) { qWarning() << "Failed to read OggVorbis file:" << getUrlString(); return ERR; } setChannelCount(vi->channels); setSamplingRate(vi->rate); if (0 < vi->bitrate_nominal) { setBitrate(vi->bitrate_nominal / 1000); } else { if ((0 < vi->bitrate_lower) && (vi->bitrate_lower == vi->bitrate_upper)) { setBitrate(vi->bitrate_lower / 1000); } } ogg_int64_t pcmTotal = ov_pcm_total(&m_vf, kEntireBitstreamLink); if (0 <= pcmTotal) { setFrameCount(pcmTotal); } else { qWarning() << "Failed to read total length of OggVorbis file:" << getUrlString(); return ERR; } return OK; }
void SoundSourceSndFile::close() { if (m_pSndFile) { const int closeResult = sf_close(m_pSndFile); if (0 == closeResult) { m_pSndFile = nullptr; } else { qWarning() << "Failed to close file:" << closeResult << sf_strerror(m_pSndFile) << getUrlString(); } } }
Result SoundSourceMediaFoundation::tryOpen(const Mixxx::AudioSourceConfig& audioSrcCfg) { if (SUCCEEDED(m_hrCoInitialize)) { qWarning() << "Cannot reopen MediaFoundation file" << getUrlString(); return ERR; } const QString fileName(getLocalFileName()); if (sDebug) { qDebug() << "open()" << fileName; } // Initialize the COM library. m_hrCoInitialize = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); if (FAILED(m_hrCoInitialize)) { qWarning() << "SSMF: failed to initialize COM"; return ERR; } // Initialize the Media Foundation platform. m_hrMFStartup = MFStartup(MF_VERSION); if (FAILED(m_hrCoInitialize)) { qWarning() << "SSMF: failed to initialize Media Foundation"; return ERR; } QString qurlStr(fileName); // http://social.msdn.microsoft.com/Forums/en/netfxbcl/thread/35c6a451-3507-40c8-9d1c-8d4edde7c0cc // gives maximum path + file length as 248 + 260, using that -bkgood m_wcFilename = new wchar_t[248 + 260]; int wcFilenameLength(fileName.toWCharArray(m_wcFilename)); // toWCharArray does not append a null terminator to the string! m_wcFilename[wcFilenameLength] = '\0'; // Create the source reader to read the input file. HRESULT hr = MFCreateSourceReaderFromURL(m_wcFilename, NULL, &m_pReader); if (FAILED(hr)) { qWarning() << "SSMF: Error opening input file:" << fileName; return ERR; } if (!configureAudioStream(audioSrcCfg)) { qWarning() << "SSMF: Error configuring audio stream."; return ERR; } //Seek to position 0, which forces us to skip over all the header frames. //This makes sure we're ready to just let the Analyser rip and it'll //get the number of samples it expects (ie. no header frames). seekSampleFrame(0); return OK; }
Result SoundSourceOggVorbis::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) { const QByteArray qbaFilename(getLocalFileNameBytes()); if (0 != ov_fopen(qbaFilename.constData(), &m_vf)) { qWarning() << "Failed to open OggVorbis file:" << getUrlString(); return ERR; } if (!ov_seekable(&m_vf)) { qWarning() << "OggVorbis file is not seekable:" << getUrlString(); return ERR; } // lookup the ogg's channels and sample rate const vorbis_info* vi = ov_info(&m_vf, kCurrentBitstreamLink); if (!vi) { qWarning() << "Failed to read OggVorbis file:" << getUrlString(); return ERR; } setChannelCount(vi->channels); setFrameRate(vi->rate); if (0 < vi->bitrate_nominal) { setBitrate(vi->bitrate_nominal / 1000); } else { if ((0 < vi->bitrate_lower) && (vi->bitrate_lower == vi->bitrate_upper)) { setBitrate(vi->bitrate_lower / 1000); } } ogg_int64_t pcmTotal = ov_pcm_total(&m_vf, kEntireBitstreamLink); if (0 <= pcmTotal) { setFrameCount(pcmTotal); } else { qWarning() << "Failed to read total length of OggVorbis file:" << getUrlString(); return ERR; } return OK; }
Result SoundSourceSndFile::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) { DEBUG_ASSERT(!m_pSndFile); SF_INFO sfInfo; memset(&sfInfo, 0, sizeof(sfInfo)); #ifdef __WINDOWS__ // Note: we cannot use QString::toStdWString since QT 4 is compiled with // '/Zc:wchar_t-' flag and QT 5 not const QString localFileName(QDir::toNativeSeparators(getLocalFileName())); const ushort* const fileNameUtf16 = localFileName.utf16(); static_assert(sizeof(wchar_t) == sizeof(ushort), "QString::utf16(): wchar_t and ushort have different sizes"); m_pSndFile = sf_wchar_open( reinterpret_cast<wchar_t*>(const_cast<ushort*>(fileNameUtf16)), SFM_READ, &sfInfo); #else m_pSndFile = sf_open(getLocalFileName().toLocal8Bit(), SFM_READ, &sfInfo); #endif if (!m_pSndFile) { // sf_format_check is only for writes qWarning() << "Error opening libsndfile file:" << getUrlString() << sf_strerror(m_pSndFile); return ERR; } if (sf_error(m_pSndFile) > 0) { qWarning() << "Error opening libsndfile file:" << getUrlString() << sf_strerror(m_pSndFile); return ERR; } setChannelCount(sfInfo.channels); setSamplingRate(sfInfo.samplerate); setFrameCount(sfInfo.frames); return OK; }
SoundSource::OpenResult SoundSourceSndFile::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) { DEBUG_ASSERT(!m_pSndFile); SF_INFO sfInfo; memset(&sfInfo, 0, sizeof(sfInfo)); #ifdef __WINDOWS__ // Note: we cannot use QString::toStdWString since QT 4 is compiled with // '/Zc:wchar_t-' flag and QT 5 not const QString localFileName(QDir::toNativeSeparators(getLocalFileName())); const ushort* const fileNameUtf16 = localFileName.utf16(); static_assert(sizeof(wchar_t) == sizeof(ushort), "QString::utf16(): wchar_t and ushort have different sizes"); m_pSndFile = sf_wchar_open( reinterpret_cast<wchar_t*>(const_cast<ushort*>(fileNameUtf16)), SFM_READ, &sfInfo); #else m_pSndFile = sf_open(getLocalFileName().toLocal8Bit(), SFM_READ, &sfInfo); #endif switch (sf_error(m_pSndFile)) { case SF_ERR_NO_ERROR: DEBUG_ASSERT(m_pSndFile != nullptr); break; // continue case SF_ERR_UNRECOGNISED_FORMAT: return OpenResult::UNSUPPORTED_FORMAT; default: const QString errorMsg(sf_strerror(m_pSndFile)); if (errorMsg.toLower().indexOf("unknown format") != -1) { // NOTE(uklotzde 2016-05-11): This actually happens when // trying to open a file with a supported file extension // that contains data in an unsupported format! return OpenResult::UNSUPPORTED_FORMAT; } else { qWarning() << "Error opening libsndfile file:" << getUrlString() << errorMsg; return OpenResult::FAILED; } } setChannelCount(sfInfo.channels); setSamplingRate(sfInfo.samplerate); setFrameCount(sfInfo.frames); return OpenResult::SUCCEEDED; }
SINT SoundSourceM4A::readSampleFrames( SINT numberOfFrames, CSAMPLE* sampleBuffer) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); const SINT numberOfFramesTotal = math_min( numberOfFrames, getMaxFrameIndex() - m_curFrameIndex); const SINT numberOfSamplesTotal = frames2samples(numberOfFramesTotal); CSAMPLE* pSampleBuffer = sampleBuffer; SINT numberOfSamplesRemaining = numberOfSamplesTotal; while (0 < numberOfSamplesRemaining) { if (!m_sampleBuffer.isEmpty()) { // Consume previously decoded sample data const SampleBuffer::ReadableChunk readableChunk( m_sampleBuffer.readFromHead(numberOfSamplesRemaining)); if (pSampleBuffer) { SampleUtil::copy(pSampleBuffer, readableChunk.data(), readableChunk.size()); pSampleBuffer += readableChunk.size(); } m_curFrameIndex += samples2frames(readableChunk.size()); DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfSamplesRemaining >= readableChunk.size()); numberOfSamplesRemaining -= readableChunk.size(); if (0 == numberOfSamplesRemaining) { break; // exit loop } } // All previously decoded sample data has been consumed now DEBUG_ASSERT(m_sampleBuffer.isEmpty()); if (0 == m_inputBufferLength) { // Fill input buffer from file if (isValidSampleBlockId(m_curSampleBlockId)) { // Read data for next sample block into input buffer u_int8_t* pInputBuffer = &m_inputBuffer[0]; u_int32_t inputBufferLength = m_inputBuffer.size(); // in/out parameter if (!MP4ReadSample(m_hFile, m_trackId, m_curSampleBlockId, &pInputBuffer, &inputBufferLength, NULL, NULL, NULL, NULL)) { qWarning() << "Failed to read MP4 input data for sample block" << m_curSampleBlockId << "(" << "min =" << kSampleBlockIdMin << "," << "max =" << m_maxSampleBlockId << ")"; break; // abort } ++m_curSampleBlockId; m_inputBufferLength = inputBufferLength; m_inputBufferOffset = 0; } } DEBUG_ASSERT(0 <= m_inputBufferLength); if (0 == m_inputBufferLength) { break; // EOF } // NOTE(uklotzde): The sample buffer for NeAACDecDecode2 has to // be big enough for a whole block of decoded samples, which // contains up to kFramesPerSampleBlock frames. Otherwise // we need to use a temporary buffer. CSAMPLE* pDecodeBuffer; // in/out parameter SINT decodeBufferCapacity; const SINT decodeBufferCapacityMin = frames2samples(kFramesPerSampleBlock); if (pSampleBuffer && (decodeBufferCapacityMin <= numberOfSamplesRemaining)) { // Decode samples directly into sampleBuffer pDecodeBuffer = pSampleBuffer; decodeBufferCapacity = numberOfSamplesRemaining; } else { // Decode next sample block into temporary buffer const SINT writeToTailCount = math_max( numberOfSamplesRemaining, decodeBufferCapacityMin); const SampleBuffer::WritableChunk writableChunk( m_sampleBuffer.writeToTail(writeToTailCount)); pDecodeBuffer = writableChunk.data(); decodeBufferCapacity = writableChunk.size(); } DEBUG_ASSERT(decodeBufferCapacityMin <= decodeBufferCapacity); NeAACDecFrameInfo decFrameInfo; void* pDecodeResult = NeAACDecDecode2( m_hDecoder, &decFrameInfo, &m_inputBuffer[m_inputBufferOffset], m_inputBufferLength, reinterpret_cast<void**>(&pDecodeBuffer), decodeBufferCapacity * sizeof(*pDecodeBuffer)); // Verify the decoding result if (0 != decFrameInfo.error) { qWarning() << "AAC decoding error:" << decFrameInfo.error << NeAACDecGetErrorMessage(decFrameInfo.error) << getUrlString(); break; // abort } DEBUG_ASSERT(pDecodeResult == pDecodeBuffer); // verify the in/out parameter // Verify the decoded sample data for consistency if (getChannelCount() != decFrameInfo.channels) { qWarning() << "Corrupt or unsupported AAC file:" << "Unexpected number of channels" << decFrameInfo.channels << "<>" << getChannelCount(); break; // abort } if (getFrameRate() != SINT(decFrameInfo.samplerate)) { qWarning() << "Corrupt or unsupported AAC file:" << "Unexpected sample rate" << decFrameInfo.samplerate << "<>" << getFrameRate(); break; // abort } // Consume input data m_inputBufferLength -= decFrameInfo.bytesconsumed; m_inputBufferOffset += decFrameInfo.bytesconsumed; // Consume decoded output data const SINT numberOfSamplesDecoded = decFrameInfo.samples; DEBUG_ASSERT(numberOfSamplesDecoded <= decodeBufferCapacity); SINT numberOfSamplesRead; if (pDecodeBuffer == pSampleBuffer) { numberOfSamplesRead = math_min(numberOfSamplesDecoded, numberOfSamplesRemaining); pSampleBuffer += numberOfSamplesRead; } else { m_sampleBuffer.readFromTail(decodeBufferCapacity - numberOfSamplesDecoded); const SampleBuffer::ReadableChunk readableChunk( m_sampleBuffer.readFromHead(numberOfSamplesRemaining)); numberOfSamplesRead = readableChunk.size(); if (pSampleBuffer) { SampleUtil::copy(pSampleBuffer, readableChunk.data(), numberOfSamplesRead); pSampleBuffer += numberOfSamplesRead; } } // The decoder might decode more samples than actually needed // at the end of the file! When the end of the file has been // reached decoding can be restarted by seeking to a new // position. DEBUG_ASSERT(numberOfSamplesDecoded >= numberOfSamplesRead); m_curFrameIndex += samples2frames(numberOfSamplesRead); DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfSamplesRemaining >= numberOfSamplesRead); numberOfSamplesRemaining -= numberOfSamplesRead; } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfSamplesTotal >= numberOfSamplesRemaining); return samples2frames(numberOfSamplesTotal - numberOfSamplesRemaining); }
Result SoundSourceM4A::tryOpen(const AudioSourceConfig& audioSrcCfg) { DEBUG_ASSERT(MP4_INVALID_FILE_HANDLE == m_hFile); /* open MP4 file, check for >= ver 1.9.1 */ #if MP4V2_PROJECT_version_hex <= 0x00010901 m_hFile = MP4Read(getLocalFileNameBytes().constData(), 0); #else m_hFile = MP4Read(getLocalFileNameBytes().constData()); #endif if (MP4_INVALID_FILE_HANDLE == m_hFile) { qWarning() << "Failed to open file for reading:" << getUrlString(); return ERR; } m_trackId = findFirstAudioTrackId(m_hFile); if (MP4_INVALID_TRACK_ID == m_trackId) { qWarning() << "No AAC track found:" << getUrlString(); return ERR; } const MP4SampleId numberOfSamples = MP4GetTrackNumberOfSamples(m_hFile, m_trackId); if (0 >= numberOfSamples) { qWarning() << "Failed to read number of samples from file:" << getUrlString(); return ERR; } m_maxSampleBlockId = kSampleBlockIdMin + (numberOfSamples - 1); // Determine the maximum input size (in bytes) of a // sample block for the selected track. const u_int32_t maxSampleBlockInputSize = MP4GetTrackMaxSampleSize(m_hFile, m_trackId); m_inputBuffer.resize(maxSampleBlockInputSize, 0); DEBUG_ASSERT(NULL == m_hDecoder); // not already opened m_hDecoder = NeAACDecOpen(); if (!m_hDecoder) { qWarning() << "Failed to open the AAC decoder!"; return ERR; } NeAACDecConfigurationPtr pDecoderConfig = NeAACDecGetCurrentConfiguration( m_hDecoder); pDecoderConfig->outputFormat = FAAD_FMT_FLOAT; if ((kChannelCountMono == audioSrcCfg.channelCountHint) || (kChannelCountStereo == audioSrcCfg.channelCountHint)) { pDecoderConfig->downMatrix = 1; } else { pDecoderConfig->downMatrix = 0; } pDecoderConfig->defObjectType = LC; if (!NeAACDecSetConfiguration(m_hDecoder, pDecoderConfig)) { qWarning() << "Failed to configure AAC decoder!"; return ERR; } u_int8_t* configBuffer = NULL; u_int32_t configBufferSize = 0; if (!MP4GetTrackESConfiguration(m_hFile, m_trackId, &configBuffer, &configBufferSize)) { /* failed to get mpeg-4 audio config... this is ok. * NeAACDecInit2() will simply use default values instead. */ qWarning() << "Failed to read the MP4 audio configuration." << "Continuing with default values."; } SAMPLERATE_TYPE sampleRate; unsigned char channelCount; if (0 > NeAACDecInit2(m_hDecoder, configBuffer, configBufferSize, &sampleRate, &channelCount)) { free(configBuffer); qWarning() << "Failed to initialize the AAC decoder!"; return ERR; } else { free(configBuffer); } setChannelCount(channelCount); setFrameRate(sampleRate); setFrameCount(getFrameCountForSampleBlockId(m_maxSampleBlockId)); // Resize temporary buffer for decoded sample data const SINT sampleBufferCapacity = frames2samples(kFramesPerSampleBlock); m_sampleBuffer.resetCapacity(sampleBufferCapacity); // Invalidate current position to enforce the following // seek operation m_curFrameIndex = getMaxFrameIndex(); // (Re-)Start decoding at the beginning of the file seekSampleFrame(getMinFrameIndex()); return OK; }
Result SoundSourceM4A::tryOpen(const AudioSourceConfig& audioSrcCfg) { DEBUG_ASSERT(MP4_INVALID_FILE_HANDLE == m_hFile); // open MP4 file, check for >= ver 1.9.1 // From mp4v2/file.h: // * On Windows, this should be a UTF-8 encoded string. // * On other platforms, it should be an 8-bit encoding that is // * appropriate for the platform, locale, file system, etc. // * (prefer to use UTF-8 when possible). #if MP4V2_PROJECT_version_hex <= 0x00010901 m_hFile = MP4Read(getLocalFileName().toUtf8().constData(), 0); #else m_hFile = MP4Read(getLocalFileName().toUtf8().constData()); #endif if (MP4_INVALID_FILE_HANDLE == m_hFile) { qWarning() << "Failed to open file for reading:" << getUrlString(); return ERR; } m_trackId = findFirstAudioTrackId(m_hFile); if (MP4_INVALID_TRACK_ID == m_trackId) { qWarning() << "No AAC track found:" << getUrlString(); return ERR; } // Read fixed sample duration. If the sample duration is not // fixed (that is, if the number of frames per sample block varies // through the file), the call returns MP4_INVALID_DURATION. We // can't currently handle these. m_framesPerSampleBlock = MP4GetTrackFixedSampleDuration(m_hFile, m_trackId); if (MP4_INVALID_DURATION == m_framesPerSampleBlock) { qWarning() << "Unable to decode tracks with non-fixed sample durations: " << getUrlString(); return ERR; } const MP4SampleId numberOfSamples = MP4GetTrackNumberOfSamples(m_hFile, m_trackId); if (0 >= numberOfSamples) { qWarning() << "Failed to read number of samples from file:" << getUrlString(); return ERR; } m_maxSampleBlockId = kSampleBlockIdMin + (numberOfSamples - 1); // Determine the maximum input size (in bytes) of a // sample block for the selected track. const u_int32_t maxSampleBlockInputSize = MP4GetTrackMaxSampleSize(m_hFile, m_trackId); m_inputBuffer.resize(maxSampleBlockInputSize, 0); DEBUG_ASSERT(nullptr == m_hDecoder); // not already opened m_hDecoder = NeAACDecOpen(); if (!m_hDecoder) { qWarning() << "Failed to open the AAC decoder!"; return ERR; } NeAACDecConfigurationPtr pDecoderConfig = NeAACDecGetCurrentConfiguration( m_hDecoder); pDecoderConfig->outputFormat = FAAD_FMT_FLOAT; if ((kChannelCountMono == audioSrcCfg.channelCountHint) || (kChannelCountStereo == audioSrcCfg.channelCountHint)) { pDecoderConfig->downMatrix = 1; } else { pDecoderConfig->downMatrix = 0; } pDecoderConfig->defObjectType = LC; if (!NeAACDecSetConfiguration(m_hDecoder, pDecoderConfig)) { qWarning() << "Failed to configure AAC decoder!"; return ERR; } u_int8_t* configBuffer = nullptr; u_int32_t configBufferSize = 0; if (!MP4GetTrackESConfiguration(m_hFile, m_trackId, &configBuffer, &configBufferSize)) { /* failed to get mpeg-4 audio config... this is ok. * NeAACDecInit2() will simply use default values instead. */ qWarning() << "Failed to read the MP4 audio configuration." << "Continuing with default values."; } SAMPLERATE_TYPE sampleRate; unsigned char channelCount; if (0 > NeAACDecInit2(m_hDecoder, configBuffer, configBufferSize, &sampleRate, &channelCount)) { free(configBuffer); qWarning() << "Failed to initialize the AAC decoder!"; return ERR; } else { free(configBuffer); } // Calculate how many sample blocks we need to decode in advance // of a random seek in order to get the recommended number of // prefetch frames m_numberOfPrefetchSampleBlocks = (kNumberOfPrefetchFrames + (m_framesPerSampleBlock - 1)) / m_framesPerSampleBlock; setChannelCount(channelCount); setFrameRate(sampleRate); setFrameCount(((m_maxSampleBlockId - kSampleBlockIdMin) + 1) * m_framesPerSampleBlock); // Resize temporary buffer for decoded sample data const SINT sampleBufferCapacity = frames2samples(m_framesPerSampleBlock); m_sampleBuffer.resetCapacity(sampleBufferCapacity); // Invalidate current position to enforce the following // seek operation m_curFrameIndex = getMaxFrameIndex(); // (Re-)Start decoding at the beginning of the file seekSampleFrame(getMinFrameIndex()); return OK; }
SoundSource::OpenResult SoundSourceOggVorbis::tryOpen( OpenMode /*mode*/, const OpenParams& /*config*/) { m_pFile = std::make_unique<QFile>(getLocalFileName()); if (!m_pFile->open(QFile::ReadOnly)) { kLogger.warning() << "Failed to open file for" << getUrlString(); return OpenResult::Failed; } const int initDecoderResult = ov_open_callbacks(m_pFile.get(), &m_vf, nullptr, 0, s_callbacks); switch (initDecoderResult) { case 0: // success -> continue break; case OV_ENOTVORBIS: case OV_EVERSION: kLogger.warning() << "Unsupported format in" << getUrlString(); return OpenResult::Aborted; default: kLogger.warning() << "Failed to initialize decoder for" << getUrlString(); return OpenResult::Failed; } if (!ov_seekable(&m_vf)) { kLogger.warning() << "Stream in" << getUrlString() << "is not seekable"; return OpenResult::Aborted; } // lookup the ogg's channels and sample rate const vorbis_info* vi = ov_info(&m_vf, kCurrentBitstreamLink); if (!vi) { kLogger.warning() << "Failed to read stream info from" << getUrlString(); return OpenResult::Failed; } setChannelCount(vi->channels); setSampleRate(vi->rate); if (0 < vi->bitrate_nominal) { initBitrateOnce(vi->bitrate_nominal / 1000); } else { if ((0 < vi->bitrate_lower) && (vi->bitrate_lower == vi->bitrate_upper)) { initBitrateOnce(vi->bitrate_lower / 1000); } } ogg_int64_t pcmTotal = ov_pcm_total(&m_vf, kEntireBitstreamLink); if (0 <= pcmTotal) { initFrameIndexRangeOnce(IndexRange::forward(0, pcmTotal)); } else { kLogger.warning() << "Failed to read read total length of" << getUrlString(); return OpenResult::Failed; } return OpenResult::Succeeded; }
// Rendering the Descriptor in proper format (bitlengths, etc.) to an ostream bool PVA_FF_ObjectDescriptor::renderToFileStream(MP4_AUTHOR_FF_FILE_IO_WRAP *fp) { int32 rendered = 0; // Keep track of number of bytes rendered // Render the base class members int32 numBytes = renderBaseDescriptorMembers(fp); if (numBytes == 0) { return false; } rendered += numBytes; // Pack and render ODID, urlFlag, and reserved uint16 data = (uint16)((getObjectDescriptorID() & 0x0fffff) << 6); // (10 bits) if (getUrlFlag()) { data |= 0x20; // Set urlFlag bit } data |= _reserved; // (5 bits) reserved 0b11111 if (!PVA_FF_AtomUtils::render16(fp, data)) { return false; } rendered += 2; if (getUrlFlag()) { // Render _urlLength if (!PVA_FF_AtomUtils::render8(fp, getUrlLength())) { return false; } rendered += 1; // Render url string if (getUrlLength() > 0) { if (!PVA_FF_AtomUtils::renderString(fp, getUrlString())) { return false; } } rendered += getUrlLength(); } else { // Render the vector of ESDescriptors - actually render their ESIDs if (_pES_ID_Ref_Vec != NULL) { for (uint32 i = 0; i < _pES_ID_Ref_Vec->size(); i++) { PVA_FF_ES_ID_Ref* ref = (*_pES_ID_Ref_Vec)[i]; if (!ref->renderToFileStream(fp)) { return false; } rendered += ref->getSizeOfDescriptorObject(); } } } return true; }