コード例 #1
0
CAudioDecoder* CAudioDecoder::NewLC(CDemuxer *aDemuxer, CVideoTimer* aTimer, MPlayerObserver *aObserver)
	{
	 CAudioDecoder* self = new ( ELeave ) CAudioDecoder();
	 CleanupStack::PushL( self );
	 self->ConstructL( aDemuxer, aTimer, aObserver );
	 return self;
	}
コード例 #2
0
ファイル: PAPlayer.cpp プロジェクト: Saddamisalami/xbmc
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;
}
コード例 #3
0
ファイル: ThreadMain.cpp プロジェクト: jiemojiemo/ffmpeg-
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;
}
コード例 #4
0
ファイル: PAPlayer.cpp プロジェクト: mbolhuis/xbmc
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;
}
コード例 #5
0
ファイル: CodecFactory.cpp プロジェクト: Montellese/xbmc
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;
}
コード例 #6
0
void CAudioDecoder::after_decode(uv_work_t* req, int status)
{
	CAudioDecoder* self = (CAudioDecoder*)req->data;
	self->close();
}
コード例 #7
0
// static encode worker
void CAudioDecoder::decode_worker(uv_work_t* req)
{
	CAudioDecoder* self = (CAudioDecoder*)req->data;
	self->decode();
}
コード例 #8
0
// static function
int CAudioDecoder::fill_iobuffer(void * opaque, uint8_t *buf, int bufsize)
{
	CAudioDecoder* self = (CAudioDecoder*)opaque;
	return self->fill_iobuffer(buf, bufsize);
}
コード例 #9
0
ファイル: FileDirectoryFactory.cpp プロジェクト: Elzevir/xbmc
// 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;
}
コード例 #10
0
// 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;
}
コード例 #11
0
ファイル: paplayer_linux.cpp プロジェクト: Castlecard/plex
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;
}
コード例 #12
0
ファイル: CodecFactory.cpp プロジェクト: Montellese/xbmc
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());
}
コード例 #13
0
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;
}