2 * Copyright (C) 2005-2008 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
23 #include "music/tags/OggTag.h"
25 #include "utils/log.h"
26 #include "utils/URIUtils.h"
28 using namespace MUSIC_INFO;
30 OGGCodec::OGGCodec() : m_callback(m_file)
35 m_DataFormat = AE_FMT_INVALID;
41 m_VorbisFile.datasource = NULL;
50 bool OGGCodec::Init(const CStdString &strFile1, unsigned int filecache)
54 CStdString strFile=strFile1;
60 CStdString strExtension;
61 URIUtils::GetExtension(strFile, strExtension);
63 // A bitstream inside a ogg file?
64 if (strExtension==".oggstream")
66 // Extract the bitstream to play
67 CStdString strFileName=URIUtils::GetFileName(strFile);
68 int iStart=strFileName.ReverseFind('-')+1;
69 m_CurrentStream = atoi(strFileName.substr(iStart, strFileName.size()-iStart-10).c_str())-1;
70 // The directory we are in, is the file
71 // that contains the bitstream to play,
73 CStdString strPath=strFile;
74 URIUtils::GetDirectory(strPath, strFile);
75 URIUtils::RemoveSlashAtEnd(strFile); // we want the filename
78 CFileItem item(strFile, false);
80 // Open the file to play
81 if (!m_file.Open(strFile, READ_CACHED))
83 CLog::Log(LOGERROR, "OGGCodec: Can't open %s", strFile1.c_str());
87 // setup ogg i/o callbacks
88 ov_callbacks oggIOCallbacks = m_callback.Get(strFile);
90 // open ogg file with decoder
91 if (m_dll.ov_open_callbacks(&m_callback, &m_VorbisFile, NULL, 0, oggIOCallbacks)!=0)
93 CLog::Log(LOGERROR, "OGGCodec: Can't open decoder for %s", strFile1.c_str());
97 long iStreams=m_dll.ov_streams(&m_VorbisFile);
100 if (m_CurrentStream > iStreams)
104 // Calculate the offset in secs where the bitstream starts
105 for (int i=0; i<m_CurrentStream; ++i)
106 m_TimeOffset += m_dll.ov_time_total(&m_VorbisFile, i);
109 vorbis_info* pInfo=m_dll.ov_info(&m_VorbisFile, m_CurrentStream);
112 CLog::Log(LOGERROR, "OGGCodec: Can't get stream info from %s", strFile1.c_str());
116 m_SampleRate = pInfo->rate;
117 m_Channels = pInfo->channels;
118 m_BitsPerSample = 16;
119 m_DataFormat = AE_FMT_S16NE;
120 if (item.IsInternetStream())
123 m_TotalTime = (int64_t)m_dll.ov_time_total(&m_VorbisFile, m_CurrentStream)*1000;
124 m_Bitrate = pInfo->bitrate_nominal;
125 if (m_Bitrate == 0 && m_TotalTime > 0 && !item.IsInternetStream())
126 m_Bitrate = (int)(m_file.GetLength()*8 / (m_TotalTime / 1000));
128 if (m_SampleRate==0 || m_Channels==0 || m_BitsPerSample==0 || m_TotalTime==0)
130 CLog::Log(LOGERROR, "OGGCodec: incomplete stream info from %s, SampleRate=%i, Channels=%i, BitsPerSample=%i, TotalTime=%"PRIu64, strFile1.c_str(), m_SampleRate, m_Channels, m_BitsPerSample, m_TotalTime);
134 // Get replay gain tags
135 vorbis_comment* pComments=m_dll.ov_comment(&m_VorbisFile, m_CurrentStream);
139 for (int i=0; i < pComments->comments; ++i)
141 CStdString strTag=pComments->user_comments[i];
142 oggTag.ParseTagEntry(strTag);
144 m_replayGain=oggTag.GetReplayGain();
147 // Seek to the logical bitstream to play
148 if (m_TimeOffset>0.0)
150 if (m_dll.ov_time_seek(&m_VorbisFile, m_TimeOffset)!=0)
152 CLog::Log(LOGERROR, "OGGCodec: Can't seek to the bitstream start time (%s)", strFile1.c_str());
160 void OGGCodec::DeInit()
162 if (m_VorbisFile.datasource)
163 m_dll.ov_clear(&m_VorbisFile);
164 m_VorbisFile.datasource = NULL;
168 int64_t OGGCodec::Seek(int64_t iSeekTime)
170 if (m_dll.ov_time_seek(&m_VorbisFile, m_TimeOffset+(double)(iSeekTime/1000.0f))!=0)
176 int OGGCodec::ReadPCM(BYTE *pBuffer, int size, int *actualsize)
181 // the maximum chunk size the vorbis decoder seem to return with one call is 4096
182 long lRead=m_dll.ov_read(&m_VorbisFile, (char*)pBuffer, size, 0, 2, 1, &iBitStream);
184 if (lRead == OV_HOLE)
187 // Our logical bitstream changed, we reached the eof
188 if (lRead > 0 && m_CurrentStream!=iBitStream)
193 CLog::Log(LOGERROR, "OGGCodec: Read error %lu", lRead);
204 bool OGGCodec::CanInit()
206 return m_dll.CanLoad();
209 CAEChannelInfo OGGCodec::GetChannelInfo()
211 static enum AEChannel map[8][9] = {
212 {AE_CH_FC, AE_CH_NULL},
213 {AE_CH_FL, AE_CH_FR, AE_CH_NULL},
214 {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_NULL},
215 {AE_CH_FL, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_NULL},
216 {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_NULL},
217 {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_LFE, AE_CH_NULL},
218 {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_NULL},
219 {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_LFE, AE_CH_NULL}
223 return CAEUtil::GuessChLayout(m_Channels);
225 return CAEChannelInfo(map[m_Channels - 1]);