CAudioDecoder* CAudioDecoder::NewLC(CDemuxer *aDemuxer, CVideoTimer* aTimer, MPlayerObserver *aObserver) { CAudioDecoder* self = new ( ELeave ) CAudioDecoder(); CleanupStack::PushL( self ); self->ConstructL( aDemuxer, aTimer, aObserver ); return self; }
bool PAPlayer::AddPacketsToStream(int stream, CAudioDecoder &dec) { if (!m_pAudioDecoder[stream] || dec.GetStatus() == STATUS_NO_FILE) return false; bool ret = false; int amount = m_resampler[stream].GetInputSamples(); if (amount > 0 && amount <= (int)dec.GetDataSize()) { // resampler wants more data - let's feed it m_resampler[stream].PutFloatData((float *)dec.GetData(amount), amount); ret = true; } else if (m_resampler[stream].GetData(m_packet[stream][0].packet)) { // got some data from our resampler - construct audio packet m_packet[stream][0].length = PACKET_SIZE; m_packet[stream][0].stream = stream; unsigned char *pcmPtr = m_packet[stream][0].packet; int len = m_packet[stream][0].length; StreamCallback(&m_packet[stream][0]); memcpy(m_pcmBuffer[stream]+m_bufferPos[stream], pcmPtr, len); m_bufferPos[stream] += len; while (m_bufferPos[stream] >= (int)m_pAudioDecoder[stream]->GetChunkLen()) { int rtn = m_pAudioDecoder[stream]->AddPackets(m_pcmBuffer[stream], m_bufferPos[stream]); if (rtn > 0) { m_bufferPos[stream] -= rtn; memmove(m_pcmBuffer[stream], m_pcmBuffer[stream] + rtn, m_bufferPos[stream]); } else //no pcm data added { int sleepTime = MathUtils::round_int(m_pAudioDecoder[stream]->GetCacheTime() * 200.0); Sleep(std::max(sleepTime, 1)); } } // something done ret = true; } return ret; }
int AudioThread( void *data ) { cDecoder.OpenInputFile( url, AVMEDIA_TYPE_AUDIO ); AVCodecContext* audioCtx = cDecoder.getCodecContext(); transcoder.SwrInit(audioCtx); player.AudioInit(44100, 2, 1024, AV_SAMPLE_FMT_S16); for(;;) { AVFrame* audioFrame = cDecoder.Process(); if( audioFrame == NULL ) break; uint8_t* audioBuffer = transcoder.TransAudioFrame( audioFrame ); player.UpdateNbsamples( audioFrame ); player.Playsound( audioBuffer ); //printf( "%d\n", i++); } return 10; }
bool PAPlayer::AddPacketsToStream(int stream, CAudioDecoder &dec) { if (!m_pAudioDecoder[stream] || dec.GetStatus() == STATUS_NO_FILE) return false; bool ret = false; int amount = m_resampler[stream].GetInputSamples(); if (amount > 0 && amount <= (int)dec.GetDataSize()) { // resampler wants more data - let's feed it m_resampler[stream].PutFloatData((float *)dec.GetData(amount), amount); ret = true; } else if (m_Chunklen[stream] > m_pAudioDecoder[stream]->GetSpace()) { // resampler probably have data but wait until we can send atleast a packet ret = false; } else if (m_resampler[stream].GetData(m_packet[stream][0].packet)) { // got some data from our resampler - construct audio packet m_packet[stream][0].length = PACKET_SIZE; m_packet[stream][0].stream = stream; unsigned char *pcmPtr = m_packet[stream][0].packet; int len = m_packet[stream][0].length; StreamCallback(&m_packet[stream][0]); memcpy(m_pcmBuffer[stream]+m_bufferPos[stream], pcmPtr, len); m_bufferPos[stream] += len; while (m_bufferPos[stream] >= (int)m_pAudioDecoder[stream]->GetChunkLen()) { int rtn = m_pAudioDecoder[stream]->AddPackets(m_pcmBuffer[stream], m_bufferPos[stream]); m_bufferPos[stream] -= rtn; memcpy(m_pcmBuffer[stream], m_pcmBuffer[stream] + rtn, m_bufferPos[stream]); } // something done ret = true; } return ret; }
ICodec* CodecFactory::CreateCodec(const std::string &strFileType) { std::string fileType = strFileType; StringUtils::ToLower(fileType); BinaryAddonBaseList addonInfos; CServiceBroker::GetBinaryAddonManager().GetAddonInfos(addonInfos, true, ADDON_AUDIODECODER); for (const auto& addonInfo : addonInfos) { if (CAudioDecoder::GetExtensions(addonInfo).find("."+fileType) != std::string::npos) { CAudioDecoder* result = new CAudioDecoder(addonInfo); if (!result->CreateDecoder()) { delete result; return nullptr; } return result; } } VideoPlayerCodec *dvdcodec = new VideoPlayerCodec(); return dvdcodec; }
void CAudioDecoder::after_decode(uv_work_t* req, int status) { CAudioDecoder* self = (CAudioDecoder*)req->data; self->close(); }
// static encode worker void CAudioDecoder::decode_worker(uv_work_t* req) { CAudioDecoder* self = (CAudioDecoder*)req->data; self->decode(); }
// static function int CAudioDecoder::fill_iobuffer(void * opaque, uint8_t *buf, int bufsize) { CAudioDecoder* self = (CAudioDecoder*)opaque; return self->fill_iobuffer(buf, bufsize); }
// return NULL + set pItem->m_bIsFolder to remove it completely from list. IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem, const std::string& strMask) { if (url.IsProtocol("stack")) // disqualify stack as we need to work with each of the parts instead return NULL; std::string strExtension=URIUtils::GetExtension(url); StringUtils::ToLower(strExtension); if (!strExtension.empty()) { VECADDONS codecs; CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); addonCache.GetAddons(codecs, ADDON_AUDIODECODER); for (size_t i=0;i<codecs.size();++i) { std::shared_ptr<CAudioDecoder> dec(std::static_pointer_cast<CAudioDecoder>(codecs[i])); if (dec->HasTracks() && dec->GetExtensions().find(strExtension) != std::string::npos) { CAudioDecoder* result = new CAudioDecoder(*dec); result->Create(); if (result->ContainsFiles(url)) return result; delete result; return NULL; } } } if (CServiceBroker::IsBinaryAddonCacheUp()) { VECADDONS vfs; CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); addonCache.GetAddons(vfs, ADDON_VFS); for (size_t i=0;i<vfs.size();++i) { std::shared_ptr<CVFSEntry> dec(std::static_pointer_cast<CVFSEntry>(vfs[i])); if (!strExtension.empty() && dec->HasFileDirectories() && dec->GetExtensions().find(strExtension) != std::string::npos) { CVFSEntryIFileDirectoryWrapper* wrap = new CVFSEntryIFileDirectoryWrapper(dec); if (wrap->ContainsFiles(url)) { if (wrap->m_items.Size() == 1) { // one STORED file - collapse it down *pItem = *wrap->m_items[0]; } else { // compressed or more than one file -> create a dir pItem->SetPath(wrap->m_items.GetPath()); return wrap; } } else pItem->m_bIsFolder = true; delete wrap; return NULL; } } } if (pItem->IsRSS()) return new CRSSDirectory(); if (pItem->IsDiscImage()) return new CUDFDirectory(); #if defined(TARGET_ANDROID) if (url.IsFileType("apk")) { CURL zipURL = URIUtils::CreateArchivePath("apk", url); CFileItemList items; CDirectory::GetDirectory(zipURL, items, strMask); if (items.Size() == 0) // no files pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder) { // one STORED file - collapse it down *pItem = *items[0]; } else { // compressed or more than one file -> create a apk dir pItem->SetURL(zipURL); return new CAPKDirectory; } return NULL; } #endif if (url.IsFileType("zip")) { CURL zipURL = URIUtils::CreateArchivePath("zip", url); CFileItemList items; CDirectory::GetDirectory(zipURL, items, strMask); if (items.Size() == 0) // no files pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder) { // one STORED file - collapse it down *pItem = *items[0]; } else { // compressed or more than one file -> create a zip dir pItem->SetURL(zipURL); return new CZipDirectory; } return NULL; } if (url.IsFileType("rar") || url.IsFileType("001")) { std::vector<std::string> tokens; const std::string strPath = url.Get(); StringUtils::Tokenize(strPath,tokens,"."); if (tokens.size() > 2) { if (url.IsFileType("001")) { if (StringUtils::EqualsNoCase(tokens[tokens.size()-2], "ts")) // .ts.001 - treat as a movie file to scratch some users itch return NULL; } std::string token = tokens[tokens.size()-2]; if (StringUtils::StartsWith(token, "part")) // only list '.part01.rar' { // need this crap to avoid making mistakes - yeyh for the new rar naming scheme :/ struct __stat64 stat; int digits = token.size()-4; std::string strFormat = StringUtils::Format("part%%0%ii", digits); std::string strNumber = StringUtils::Format(strFormat.c_str(), 1); std::string strPath2 = strPath; StringUtils::Replace(strPath2,token,strNumber); if (atoi(token.substr(4).c_str()) > 1 && CFile::Stat(strPath2,&stat) == 0) { pItem->m_bIsFolder = true; return NULL; } } } CURL rarURL = URIUtils::CreateArchivePath("rar", url); CFileItemList items; CDirectory::GetDirectory(rarURL, items, strMask); if (items.Size() == 0) // no files - hide this pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0x30 && !items[0]->m_bIsFolder) { // one STORED file - collapse it down *pItem = *items[0]; } else { #ifdef HAS_FILESYSTEM_RAR // compressed or more than one file -> create a rar dir pItem->SetURL(rarURL); return new CRarDirectory; #else return NULL; #endif } return NULL; } if (url.IsFileType("xbt")) { CURL xbtUrl = URIUtils::CreateArchivePath("xbt", url); pItem->SetURL(xbtUrl); return new CXbtDirectory(); } if (url.IsFileType("xsp")) { // XBMC Smart playlist - just XML renamed to XSP // read the name of the playlist in CSmartPlaylist playlist; if (playlist.OpenAndReadName(url)) { pItem->SetLabel(playlist.GetName()); pItem->SetLabelPreformatted(true); } IFileDirectory* pDir=new CSmartPlaylistDirectory; return pDir; // treat as directory } if (CPlayListFactory::IsPlaylist(url)) { // Playlist file // currently we only return the directory if it contains // more than one file. Reason is that .pls and .m3u may be used // for links to http streams etc. IFileDirectory *pDir = new CPlaylistFileDirectory(); CFileItemList items; if (pDir->GetDirectory(url, items)) { if (items.Size() > 1) return pDir; } delete pDir; return NULL; } if (pItem->IsAudioBook()) { if (!pItem->HasMusicInfoTag() || pItem->m_lEndOffset <= 0) { std::unique_ptr<CAudioBookFileDirectory> pDir(new CAudioBookFileDirectory); if (pDir->ContainsFiles(url)) return pDir.release(); } return NULL; } return NULL; }
// return NULL + set pItem->m_bIsFolder to remove it completely from list. IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem, const std::string& strMask) { if (url.IsProtocol("stack")) // disqualify stack as we need to work with each of the parts instead return NULL; std::string strExtension=URIUtils::GetExtension(url); StringUtils::ToLower(strExtension); if (!strExtension.empty() && CServiceBroker::IsBinaryAddonCacheUp()) { BinaryAddonBaseList addonInfos; CServiceBroker::GetBinaryAddonManager().GetAddonInfos(addonInfos, true, ADDON_AUDIODECODER); for (const auto& addonInfo : addonInfos) { if (CAudioDecoder::HasTracks(addonInfo) && CAudioDecoder::GetExtensions(addonInfo).find(strExtension) != std::string::npos) { CAudioDecoder* result = new CAudioDecoder(addonInfo); if (!result->CreateDecoder() || !result->ContainsFiles(url)) { delete result; return nullptr; } return result; } } } if (!strExtension.empty() && CServiceBroker::IsBinaryAddonCacheUp()) { for (const auto& vfsAddon : CServiceBroker::GetVFSAddonCache().GetAddonInstances()) { if (vfsAddon->HasFileDirectories() && vfsAddon->GetExtensions().find(strExtension) != std::string::npos) { CVFSEntryIFileDirectoryWrapper* wrap = new CVFSEntryIFileDirectoryWrapper(vfsAddon); if (wrap->ContainsFiles(url)) { if (wrap->m_items.Size() == 1) { // one STORED file - collapse it down *pItem = *wrap->m_items[0]; } else { // compressed or more than one file -> create a dir pItem->SetPath(wrap->m_items.GetPath()); return wrap; } } else pItem->m_bIsFolder = true; delete wrap; return nullptr; } } } if (pItem->IsRSS()) return new CRSSDirectory(); if (pItem->IsDiscImage()) return new CUDFDirectory(); #if defined(TARGET_ANDROID) if (url.IsFileType("apk")) { CURL zipURL = URIUtils::CreateArchivePath("apk", url); CFileItemList items; CDirectory::GetDirectory(zipURL, items, strMask); if (items.Size() == 0) // no files pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder) { // one STORED file - collapse it down *pItem = *items[0]; } else { // compressed or more than one file -> create a apk dir pItem->SetURL(zipURL); return new CAPKDirectory; } return NULL; } #endif if (url.IsFileType("zip")) { CURL zipURL = URIUtils::CreateArchivePath("zip", url); CFileItemList items; CDirectory::GetDirectory(zipURL, items, strMask); if (items.Size() == 0) // no files pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder) { // one STORED file - collapse it down *pItem = *items[0]; } else { // compressed or more than one file -> create a zip dir pItem->SetURL(zipURL); return new CZipDirectory; } return NULL; } if (url.IsFileType("xbt")) { CURL xbtUrl = URIUtils::CreateArchivePath("xbt", url); pItem->SetURL(xbtUrl); return new CXbtDirectory(); } if (url.IsFileType("xsp")) { // XBMC Smart playlist - just XML renamed to XSP // read the name of the playlist in CSmartPlaylist playlist; if (playlist.OpenAndReadName(url)) { pItem->SetLabel(playlist.GetName()); pItem->SetLabelPreformatted(true); } IFileDirectory* pDir=new CSmartPlaylistDirectory; return pDir; // treat as directory } if (CPlayListFactory::IsPlaylist(url)) { // Playlist file // currently we only return the directory if it contains // more than one file. Reason is that .pls and .m3u may be used // for links to http streams etc. IFileDirectory *pDir = new CPlaylistFileDirectory(); CFileItemList items; if (pDir->GetDirectory(url, items)) { if (items.Size() > 1) return pDir; } delete pDir; return NULL; } if (pItem->IsAudioBook()) { if (!pItem->HasMusicInfoTag() || pItem->m_lEndOffset <= 0) { std::unique_ptr<CAudioBookFileDirectory> pDir(new CAudioBookFileDirectory); if (pDir->ContainsFiles(url)) return pDir.release(); } return NULL; } return NULL; }
bool PAPlayer::AddPacketsToStream(int stream, CAudioDecoder &dec) { if (!m_pStream[stream] || dec.GetStatus() == STATUS_NO_FILE) return false; bool ret = false; int nAvail = snd_pcm_frames_to_bytes(m_pStream[stream], snd_pcm_avail_update(m_pStream[stream])); if (nAvail < PACKET_SIZE) { return false; } if (m_resampler[stream].GetData(m_packet[stream][0].packet)) { // got some data from our resampler - construct audio packet m_packet[stream][0].length = PACKET_SIZE; m_packet[stream][0].stream = stream; unsigned char *pcmPtr = m_packet[stream][0].packet; // handle volume de-amp m_amp[stream].DeAmplify((short *)pcmPtr, m_packet[stream][0].length / 2); StreamCallback(&m_packet[stream][0]); while ( pcmPtr < m_packet[stream][0].packet + m_packet[stream][0].length) { int nPeriodSize = snd_pcm_frames_to_bytes(m_pStream[stream],m_periods[stream]); if ( pcmPtr + nPeriodSize > m_packet[stream][0].packet + m_packet[stream][0].length) { nPeriodSize = m_packet[stream][0].packet + m_packet[stream][0].length - pcmPtr; } int framesToWrite = snd_pcm_bytes_to_frames(m_pStream[stream],nPeriodSize); int writeResult = snd_pcm_writei(m_pStream[stream], pcmPtr, framesToWrite); if ( writeResult == -EPIPE ) { CLog::Log(LOGDEBUG, "PAPlayer::AddPacketsToStream - buffer underun (tried to write %d frames)", framesToWrite); int err = snd_pcm_prepare(m_pStream[stream]); CHECK_ALSA(LOGERROR,"prepare after EPIPE", err); } else if (writeResult != framesToWrite) { CLog::Log(LOGERROR, "PAPlayer::AddPacketsToStream - failed to write %d frames. " "bad write (err: %d) - %s", framesToWrite, writeResult, snd_strerror(writeResult)); break; } //else // m_bytesSentOut += nPeriodSize; pcmPtr += nPeriodSize; } // something done ret = true; } else { // resampler wants more data - let's feed it int amount = m_resampler[stream].GetInputSamples(); if (amount > 0 && amount <= (int)dec.GetDataSize()) { // needs some data - let's feed it m_resampler[stream].PutFloatData((float *)dec.GetData(amount), amount); ret = true; } } return ret; }
ICodec* CodecFactory::CreateCodecDemux(const CFileItem& file, unsigned int filecache) { CURL urlFile(file.GetDynPath()); std::string content = file.GetMimeType(); StringUtils::ToLower(content); if (!content.empty()) { BinaryAddonBaseList addonInfos; CServiceBroker::GetBinaryAddonManager().GetAddonInfos(addonInfos, true, ADDON_AUDIODECODER); for (const auto& addonInfo : addonInfos) { if (CAudioDecoder::GetMimetypes(addonInfo).find(content) != std::string::npos) { CAudioDecoder* result = new CAudioDecoder(addonInfo); if (!result->CreateDecoder()) { delete result; return nullptr; } return result; } } } if( content == "audio/mpeg" || content == "audio/mpeg3" || content == "audio/mp3" || content == "audio/aac" || content == "audio/aacp" || content == "audio/x-ms-wma" || content == "audio/x-ape" || content == "audio/ape" || content == "application/ogg" || content == "audio/ogg" || content == "audio/x-xbmc-pcm" || content == "audio/flac" || content == "audio/x-flac" || content == "application/x-flac" ) { VideoPlayerCodec *dvdcodec = new VideoPlayerCodec(); dvdcodec->SetContentType(content); return dvdcodec; } else if (urlFile.IsProtocol("shout")) { VideoPlayerCodec *dvdcodec = new VideoPlayerCodec(); dvdcodec->SetContentType("audio/mp3"); return dvdcodec; // if we got this far with internet radio - content-type was wrong. gamble on mp3. } else if (urlFile.IsFileType("wav") || content == "audio/wav" || content == "audio/x-wav") { VideoPlayerCodec *dvdcodec = new VideoPlayerCodec(); dvdcodec->SetContentType("audio/x-spdif-compressed"); if (dvdcodec->Init(file, filecache)) { return dvdcodec; } dvdcodec = new VideoPlayerCodec(); dvdcodec->SetContentType(content); return dvdcodec; } else return CreateCodec(urlFile.GetFileType()); }
IMusicInfoTagLoader* CMusicInfoTagLoaderFactory::CreateLoader(const CFileItem& item) { // dont try to read the tags for streams & shoutcast if (item.IsInternetStream()) return NULL; if (item.IsMusicDb()) return new CMusicInfoTagLoaderDatabase(); std::string strExtension = URIUtils::GetExtension(item.GetPath()); StringUtils::ToLower(strExtension); StringUtils::TrimLeft(strExtension, "."); if (strExtension.empty()) return NULL; VECADDONS codecs; CAddonMgr::GetInstance().GetAddons(codecs, ADDON_AUDIODECODER); for (size_t i=0;i<codecs.size();++i) { std::shared_ptr<CAudioDecoder> dec(std::static_pointer_cast<CAudioDecoder>(codecs[i])); if (dec->HasTags() && dec->GetExtensions().find("."+strExtension) != std::string::npos) { CAudioDecoder* result = new CAudioDecoder(*dec); result->Create(); return result; } } if (strExtension == "aac" || strExtension == "ape" || strExtension == "mac" || strExtension == "mp3" || strExtension == "wma" || strExtension == "flac" || strExtension == "m4a" || strExtension == "mp4" || strExtension == "mpc" || strExtension == "mpp" || strExtension == "mp+" || strExtension == "ogg" || strExtension == "oga" || strExtension == "oggstream" || strExtension == "opus" || strExtension == "aif" || strExtension == "aiff" || strExtension == "wav" || strExtension == "mod" || strExtension == "s3m" || strExtension == "it" || strExtension == "xm" || strExtension == "wv") { CTagLoaderTagLib *pTagLoader = new CTagLoaderTagLib(); return (IMusicInfoTagLoader*)pTagLoader; } #ifdef HAS_DVD_DRIVE else if (strExtension == "cdda") { CMusicInfoTagLoaderCDDA *pTagLoader = new CMusicInfoTagLoaderCDDA(); return (IMusicInfoTagLoader*)pTagLoader; } #endif else if (strExtension == "shn") { CMusicInfoTagLoaderSHN *pTagLoader = new CMusicInfoTagLoaderSHN(); return (IMusicInfoTagLoader*)pTagLoader; } else if (strExtension == "mka" || strExtension == "dsf" || strExtension == "dff") return new CMusicInfoTagLoaderFFmpeg(); return NULL; }