input_ogg.cpp

Go to the documentation of this file.
00001 #include <algorithm>
00002 #include <string.h>
00003 #include "input_ogg.h"
00004 #include "types.h"
00005 #include "utility.h"
00006 
00007 
00008 namespace audiere {
00009 
00010   typedef ogg_int64_t int64_t;
00011 
00012 
00013   OGGInputStream::OGGInputStream() {
00014     m_file = 0;
00015 
00016     m_channel_count = 0;
00017     m_sample_rate   = 0;
00018     m_sample_format = SF_S16;
00019   }
00020 
00021 
00022   OGGInputStream::~OGGInputStream() {
00023     // were we initialized successfully?
00024     if (m_file) {
00025       ov_clear(&m_vorbis_file);
00026     }
00027   }
00028 
00029 
00030   bool
00031   OGGInputStream::initialize(FilePtr file) {
00032     m_file = file;
00033 
00034     // custom ogg vorbis callbacks
00035     ov_callbacks callbacks;
00036     callbacks.read_func  = FileRead;
00037     callbacks.seek_func  = FileSeek;
00038     callbacks.close_func = FileClose;
00039     callbacks.tell_func  = FileTell;
00040 
00041     // open ogg vorbis stream
00042     int result = ov_open_callbacks(file.get(), &m_vorbis_file, 0, 0, callbacks);
00043     if (result) {
00044       m_file = 0;
00045       return false;
00046     }
00047 
00048     // calculate stream type
00049     vorbis_info* vi = ov_info(&m_vorbis_file, -1);
00050     if (!vi) {
00051       ov_clear(&m_vorbis_file);
00052       m_file = 0;
00053       return false;
00054     }
00055 
00056     // read metadata
00057     vorbis_comment* comments = ov_comment(&m_vorbis_file, -1);
00058     if (comments) {
00059       addTag("vendor", comments->vendor, "vorbis");
00060       for (int i = 0; i < comments->comments; ++i) {
00061         std::string kv = comments->user_comments[i];
00062         std::string key;
00063         std::string value;
00064         std::string::iterator eq = std::find(kv.begin(), kv.end(), '=');
00065         if (eq != kv.end()) {
00066           key.assign(kv.begin(), eq);
00067           value.assign(eq + 1, kv.end());
00068         } else {
00069           key = kv;
00070         }
00071         addTag(key, value, "vorbis");
00072       }
00073     }
00074 
00075     m_channel_count = vi->channels;
00076     m_sample_rate   = vi->rate;
00077     m_sample_format = SF_S16; // see constructor
00078 
00079     return true;
00080   }
00081 
00082 
00083   void
00084   OGGInputStream::getFormat(
00085     int& channel_count,
00086     int& sample_rate,
00087     SampleFormat& sample_format)
00088   {
00089     channel_count = m_channel_count;
00090     sample_rate   = m_sample_rate;
00091     sample_format = m_sample_format;
00092   }
00093 
00094 
00095   int
00096   OGGInputStream::doRead(int frame_count, void* buffer) {
00097     int sample_size = m_channel_count * GetSampleSize(m_sample_format);
00098 
00099     u8* out = (u8*)buffer;
00100 
00101     int samples_left = frame_count;
00102     int total_read = 0;
00103     while (samples_left > 0) {
00104 
00105       // check to see if the stream format has changed
00106       // if so, treat it as an EndOfStream
00107       vorbis_info* vi = ov_info(&m_vorbis_file, -1);
00108       if (vi && (m_sample_rate != vi->rate || m_channel_count != vi->channels)) {
00109         break;
00110       }
00111 
00112 #ifdef WORDS_BIGENDIAN
00113 #define ENDIANNESS 1
00114 #else
00115 #define ENDIANNESS 0
00116 #endif
00117 
00118       int bitstream;
00119       long result = ov_read(
00120         &m_vorbis_file,
00121         (char*)out,
00122         samples_left * sample_size,
00123         ENDIANNESS,
00124         2,  // 16-bit
00125         1,  // signed
00126         &bitstream);
00127 
00128       if (result < 0) {
00129         // if error, ignore it
00130         continue;
00131       } else if (result == 0) {
00132         break;
00133       }
00134 
00135       u32 samples_read = (u32)(result / sample_size);
00136 
00137       out += samples_read * sample_size;
00138       samples_left -= samples_read;
00139       total_read   += samples_read;
00140     }
00141 
00142     return total_read;
00143   }
00144 
00145 
00146   void
00147   OGGInputStream::reset() {
00148     ov_pcm_seek(&m_vorbis_file, 0);
00149   }
00150 
00151 
00152   bool
00153   OGGInputStream::isSeekable() {
00154     return (ov_seekable(&m_vorbis_file) != 0);
00155   }
00156 
00157 
00158   int
00159   OGGInputStream::getLength() {
00160     if (isSeekable()) {
00161       return static_cast<int>(ov_pcm_total(&m_vorbis_file, -1));
00162     } else {
00163       return 0;
00164     }
00165   }
00166 
00167 
00168   void
00169   OGGInputStream::setPosition(int position) {
00170     if (isSeekable()) {
00171       ov_pcm_seek(&m_vorbis_file, position);
00172     }
00173   }
00174 
00175 
00176   int
00177   OGGInputStream::getPosition() {
00178     if (isSeekable()) {
00179       return static_cast<int>(ov_pcm_tell(&m_vorbis_file));
00180     } else {
00181       return 0;
00182     }
00183   }
00184 
00185 
00186   size_t
00187   OGGInputStream::FileRead(void* buffer, size_t size, size_t n, void* opaque) {
00188     File* file = reinterpret_cast<File*>(opaque);
00189     return file->read(buffer, size * n) / size;
00190   }
00191 
00192 
00193   int
00194   OGGInputStream::FileSeek(void* opaque, ogg_int64_t offset, int whence) {
00195     File* file = reinterpret_cast<File*>(opaque);
00196     File::SeekMode type;
00197     switch (whence) {
00198       case SEEK_SET: type = File::BEGIN;   break;
00199       case SEEK_CUR: type = File::CURRENT; break;
00200       case SEEK_END: type = File::END;     break;
00201       default: return -1;
00202     }
00203     return (file->seek((int)offset, type) ? 0 : -1);
00204   }
00205 
00206 
00207   int
00208   OGGInputStream::FileClose(void* /*opaque*/) {
00209     // we don't have to do anything
00210     // (read: don't trust ogg vorbis with handling file closes)
00211     return 0;
00212   }
00213 
00214 
00215   long
00216   OGGInputStream::FileTell(void* opaque) {
00217     File* file = reinterpret_cast<File*>(opaque);
00218     return file->tell();
00219   }
00220 
00221 }

Generated on Mon Feb 13 23:07:47 2006 for audiere by  doxygen 1.4.6