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
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
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
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
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
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;
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
00106
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,
00125 1,
00126 &bitstream);
00127
00128 if (result < 0) {
00129
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* ) {
00209
00210
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 }