PageRenderTime 98ms CodeModel.GetById 49ms app.highlight 45ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/cores/paplayer/OGGcodec.cpp

http://github.com/xbmc/xbmc
C++ | 215 lines | 151 code | 31 blank | 33 comment | 31 complexity | ea442edf9288d950a1a9b3ef3a25fcb7 MD5 | raw file
  1/*
  2 *      Copyright (C) 2005-2013 Team XBMC
  3 *      http://xbmc.org
  4 *
  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)
  8 *  any later version.
  9 *
 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.
 14 *
 15 *  You should have received a copy of the GNU General Public License
 16 *  along with XBMC; see the file COPYING.  If not, see
 17 *  <http://www.gnu.org/licenses/>.
 18 *
 19 */
 20
 21#include "OGGcodec.h"
 22#include "FileItem.h"
 23#include "utils/log.h"
 24#include "utils/URIUtils.h"
 25#include "cores/AudioEngine/Utils/AEUtil.h"
 26#include "music/tags/TagLoaderTagLib.h"
 27
 28OGGCodec::OGGCodec() : m_callback(m_file)
 29{
 30  m_SampleRate = 0;
 31  m_Channels = 0;
 32  m_BitsPerSample = 0;
 33  m_DataFormat = AE_FMT_INVALID;
 34  m_Bitrate = 0;
 35  m_CodecName = "ogg";
 36  m_TimeOffset = 0.0;
 37  m_CurrentStream=0;
 38  m_TotalTime = 0;
 39  m_inited = false;
 40  memset(&m_VorbisFile, 0, sizeof(m_VorbisFile));
 41}
 42
 43OGGCodec::~OGGCodec()
 44{
 45  DeInit();
 46}
 47
 48bool OGGCodec::Init(const CStdString &strFile1, unsigned int filecache)
 49{
 50  if (m_inited)
 51    return true;
 52  CStdString strFile=strFile1;
 53  if (!m_dll.Load())
 54    return false;
 55
 56  m_CurrentStream=0;
 57
 58  //  A bitstream inside a ogg file?
 59  if (URIUtils::HasExtension(strFile, ".oggstream"))
 60  {
 61    //  Extract the bitstream to play
 62    CStdString strFileName=URIUtils::GetFileName(strFile);
 63    int iStart=strFileName.ReverseFind('-')+1;
 64    m_CurrentStream = atoi(strFileName.substr(iStart, strFileName.size()-iStart-10).c_str())-1;
 65    //  The directory we are in, is the file
 66    //  that contains the bitstream to play,
 67    //  so extract it
 68    strFile = URIUtils::GetDirectory(strFile);
 69    URIUtils::RemoveSlashAtEnd(strFile); // we want the filename
 70  }
 71
 72  CFileItem item(strFile, false);
 73
 74  //  Open the file to play
 75  if (!m_file.Open(strFile, READ_CACHED))
 76  {
 77    CLog::Log(LOGERROR, "OGGCodec: Can't open %s", strFile1.c_str());
 78    return false;
 79  }
 80
 81  //  setup ogg i/o callbacks
 82  ov_callbacks oggIOCallbacks = m_callback.Get(strFile);
 83
 84  //  open ogg file with decoder
 85  if (m_dll.ov_open_callbacks(&m_callback, &m_VorbisFile, NULL, 0, oggIOCallbacks)!=0)
 86  {
 87    CLog::Log(LOGERROR, "OGGCodec: Can't open decoder for %s", strFile1.c_str());
 88    return false;
 89  }
 90
 91  long iStreams=m_dll.ov_streams(&m_VorbisFile);
 92  if (iStreams>1)
 93  {
 94    if (m_CurrentStream > iStreams)
 95      return false;
 96  }
 97
 98  //  Calculate the offset in secs where the bitstream starts
 99  for (int i=0; i<m_CurrentStream; ++i)
100    m_TimeOffset += m_dll.ov_time_total(&m_VorbisFile, i);
101
102  //  get file info
103  vorbis_info* pInfo=m_dll.ov_info(&m_VorbisFile, m_CurrentStream);
104  if (!pInfo)
105  {
106    CLog::Log(LOGERROR, "OGGCodec: Can't get stream info from %s", strFile1.c_str());
107    return false;
108  }
109
110  m_SampleRate = pInfo->rate;
111  m_Channels = pInfo->channels;
112  m_BitsPerSample = 16;
113  m_DataFormat = AE_FMT_S16NE;
114  if (item.IsInternetStream())
115    m_TotalTime = -1;
116  else
117    m_TotalTime = (int64_t)m_dll.ov_time_total(&m_VorbisFile, m_CurrentStream)*1000;
118  m_Bitrate = pInfo->bitrate_nominal;
119  if (m_Bitrate == 0 && m_TotalTime > 0 && !item.IsInternetStream())
120    m_Bitrate = (int)(m_file.GetLength()*8 / (m_TotalTime / 1000));
121
122  if (m_SampleRate==0 || m_Channels==0 || m_BitsPerSample==0 || m_TotalTime==0)
123  {
124    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);
125    return false;
126  }
127
128  //  Get replay gain tags
129  vorbis_comment* pComments=m_dll.ov_comment(&m_VorbisFile, m_CurrentStream);
130  if (pComments)
131  {
132    CTagLoaderTagLib tagLoaderTagLib;
133    tagLoaderTagLib.Load(strFile, m_tag, "oga");
134  }
135
136  //  Seek to the logical bitstream to play
137  if (m_TimeOffset>0.0)
138  {
139    if (m_dll.ov_time_seek(&m_VorbisFile, m_TimeOffset)!=0)
140    {
141      CLog::Log(LOGERROR, "OGGCodec: Can't seek to the bitstream start time (%s)", strFile1.c_str());
142      return false;
143    }
144  }
145
146  return true;
147}
148
149void OGGCodec::DeInit()
150{
151  if (m_VorbisFile.datasource)
152    m_dll.ov_clear(&m_VorbisFile);
153  m_VorbisFile.datasource = NULL;
154  m_inited = false;
155}
156
157int64_t OGGCodec::Seek(int64_t iSeekTime)
158{
159  if (m_dll.ov_time_seek(&m_VorbisFile, m_TimeOffset+(double)(iSeekTime/1000.0f))!=0)
160    return 0;
161
162  return iSeekTime;
163}
164
165int OGGCodec::ReadPCM(BYTE *pBuffer, int size, int *actualsize)
166{
167  *actualsize=0;
168  int iBitStream=-1;
169
170  //  the maximum chunk size the vorbis decoder seem to return with one call is 4096
171  long lRead=m_dll.ov_read(&m_VorbisFile, (char*)pBuffer, size, 0, 2, 1, &iBitStream);
172
173  if (lRead == OV_HOLE)
174    return READ_SUCCESS;
175
176  //  Our logical bitstream changed, we reached the eof
177  if (lRead > 0 && m_CurrentStream!=iBitStream)
178    lRead=0;
179
180  if (lRead<0)
181  {
182    CLog::Log(LOGERROR, "OGGCodec: Read error %lu", lRead);
183    return READ_ERROR;
184  }
185  else if (lRead==0)
186    return READ_EOF;
187  else
188    *actualsize=lRead;
189
190  return READ_SUCCESS;
191}
192
193bool OGGCodec::CanInit()
194{
195  return m_dll.CanLoad();
196}
197
198CAEChannelInfo OGGCodec::GetChannelInfo()
199{
200  static enum AEChannel map[8][9] = {
201    {AE_CH_FC, AE_CH_NULL},
202    {AE_CH_FL, AE_CH_FR, AE_CH_NULL},
203    {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_NULL},
204    {AE_CH_FL, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_NULL},
205    {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_NULL},
206    {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_LFE, AE_CH_NULL},
207    {AE_CH_FL, AE_CH_FC, AE_CH_FR, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_NULL},
208    {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}
209  };
210
211  if (m_Channels > 8)
212    return CAEUtil::GuessChLayout(m_Channels);
213
214  return CAEChannelInfo(map[m_Channels - 1]);
215}