00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <iostream>
00004 #include <string>
00005 #include <qobject.h>
00006 #include <qiodevice.h>
00007 using namespace std;
00008
00009 #include "vorbisdecoder.h"
00010 #include "constants.h"
00011 #include <mythtv/audiooutput.h>
00012 #include "metadata.h"
00013 #include "metaiooggvorbiscomment.h"
00014
00015 #include <mythtv/mythconfig.h>
00016 #include <mythtv/mythcontext.h>
00017
00018
00019
00020 static size_t oggread (void *buf, size_t size, size_t nmemb, void *src) {
00021 if (! src) return 0;
00022
00023 VorbisDecoder *dogg = (VorbisDecoder *) src;
00024 int len = dogg->input()->readBlock((char *) buf, (size * nmemb));
00025 return len / size;
00026 }
00027
00028 static int oggseek(void *src, int64_t offset, int whence) {
00029 VorbisDecoder *dogg = (VorbisDecoder *) src;
00030
00031 if (! dogg->input()->isDirectAccess())
00032 return -1;
00033
00034 long start = 0;
00035 switch (whence) {
00036 case SEEK_END:
00037 start = dogg->input()->size();
00038 break;
00039
00040 case SEEK_CUR:
00041 start = dogg->input()->at();
00042 break;
00043
00044 case SEEK_SET:
00045 default:
00046 start = 0;
00047 }
00048
00049 if (dogg->input()->at(start + offset))
00050 return 0;
00051 return -1;
00052 }
00053
00054 static int oggclose(void *src)
00055 {
00056 VorbisDecoder *dogg = (VorbisDecoder *) src;
00057 dogg->input()->close();
00058 return 0;
00059 }
00060
00061 static long oggtell(void *src)
00062 {
00063 VorbisDecoder *dogg = (VorbisDecoder *) src;
00064 long t = dogg->input()->at();
00065 return t;
00066 }
00067
00068 VorbisDecoder::VorbisDecoder(const QString &file, DecoderFactory *d,
00069 QIODevice *i, AudioOutput *o)
00070 : Decoder(d, i, o)
00071 {
00072 filename = file;
00073 inited = FALSE;
00074 user_stop = FALSE;
00075 stat = 0;
00076 output_buf = 0;
00077 output_bytes = 0;
00078 output_at = 0;
00079 bks = 0;
00080 done = FALSE;
00081 finish = FALSE;
00082 len = 0;
00083 freq = 0;
00084 bitrate = 0;
00085 seekTime = -1.0;
00086 totalTime = 0.0;
00087 chan = 0;
00088 }
00089
00090 VorbisDecoder::~VorbisDecoder(void)
00091 {
00092 if (inited)
00093 deinit();
00094
00095 if (output_buf)
00096 delete [] output_buf;
00097 output_buf = 0;
00098 }
00099
00100 void VorbisDecoder::stop()
00101 {
00102 user_stop = TRUE;
00103 }
00104
00105 void VorbisDecoder::flush(bool final)
00106 {
00107 ulong min = final ? 0 : bks;
00108
00109 while ((! done && ! finish) && output_bytes > min) {
00110
00111 if (user_stop || finish) {
00112 inited = FALSE;
00113 done = TRUE;
00114 } else {
00115 ulong sz = output_bytes < bks ? output_bytes : bks;
00116
00117 int samples = (sz*8)/(chan*16);
00118 if (output()->AddSamples(output_buf, samples, -1))
00119 {
00120 output_bytes -= sz;
00121 memmove(output_buf, output_buf + sz, output_bytes);
00122 output_at = output_bytes;
00123 } else {
00124 unlock();
00125 usleep(500);
00126 lock();
00127 done = user_stop;
00128 }
00129 }
00130 }
00131 }
00132
00133 bool VorbisDecoder::initialize()
00134 {
00135 bks = blockSize();
00136
00137 inited = user_stop = done = finish = FALSE;
00138 len = freq = bitrate = 0;
00139 stat = chan = 0;
00140 seekTime = -1.0;
00141 totalTime = 0.0;
00142
00143 if (! input()) {
00144 error("DecoderOgg: cannot initialize. No input.");
00145
00146 return FALSE;
00147 }
00148
00149 if (! output_buf)
00150 output_buf = new char[globalBufferSize];
00151 output_at = 0;
00152 output_bytes = 0;
00153
00154 if (! input()->isOpen()) {
00155 if (! input()->open(IO_ReadOnly)) {
00156 error("DecoderOgg: Failed to open input. Error " +
00157 QString::number(input()->status()) + ".");
00158 return FALSE;
00159 }
00160 }
00161
00162 ov_callbacks oggcb =
00163 {
00164 oggread,
00165 oggseek,
00166 oggclose,
00167 oggtell
00168 };
00169 if (ov_open_callbacks(this, &oggfile, NULL, 0, oggcb) < 0) {
00170 error("DecoderOgg: Cannot open stream.");
00171
00172 return FALSE;
00173 }
00174
00175 freq = 0;
00176 bitrate = ov_bitrate(&oggfile, -1) / 1000;
00177 chan = 0;
00178
00179 totalTime = long(ov_time_total(&oggfile, 0));
00180 totalTime = totalTime < 0 ? 0 : totalTime;
00181
00182 vorbis_info *ogginfo = ov_info(&oggfile, -1);
00183 if (ogginfo) {
00184 freq = ogginfo->rate;
00185 chan = ogginfo->channels;
00186 }
00187
00188 if (output())
00189 {
00190 output()->Reconfigure(16, chan, freq, false );
00191 output()->SetSourceBitrate(bitrate);
00192 }
00193
00194 inited = TRUE;
00195 return TRUE;
00196 }
00197
00198 void VorbisDecoder::seek(double pos)
00199 {
00200 seekTime = pos;
00201 }
00202
00203 void VorbisDecoder::deinit()
00204 {
00205 ov_clear(&oggfile);
00206
00207 inited = user_stop = done = finish = FALSE;
00208 len = freq = bitrate = 0;
00209 stat = chan = 0;
00210 setInput(0);
00211 setOutput(0);
00212 }
00213
00214 void VorbisDecoder::run()
00215 {
00216 lock();
00217
00218 if (! inited) {
00219 unlock();
00220
00221 return;
00222 }
00223
00224 stat = DecoderEvent::Decoding;
00225
00226 unlock();
00227
00228 {
00229 DecoderEvent e((DecoderEvent::Type) stat);
00230 dispatch(e);
00231 }
00232
00233 int section = 0;
00234
00235 while (! done && ! finish) {
00236 lock();
00237
00238
00239 if (seekTime >= 0.0) {
00240 ov_time_seek(&oggfile, double(seekTime));
00241 seekTime = -1.0;
00242 }
00243
00244 #ifdef WORDS_BIGENDIAN
00245 len = ov_read(&oggfile, (char *) (output_buf + output_at), bks, 1, 2, 1,
00246 §ion);
00247 #else
00248 len = ov_read(&oggfile, (char *) (output_buf + output_at), bks, 0, 2, 1,
00249 §ion);
00250 #endif
00251
00252 if (len > 0) {
00253 bitrate = ov_bitrate_instant(&oggfile) / 1000;
00254
00255 output_at += len;
00256 output_bytes += len;
00257
00258 if (output())
00259 {
00260 output()->SetSourceBitrate(bitrate);
00261 flush();
00262 }
00263 } else if (len == 0) {
00264 flush(TRUE);
00265
00266 if (output()) {
00267 output()->Drain();
00268 }
00269
00270 done = TRUE;
00271 if (! user_stop) {
00272 finish = TRUE;
00273 }
00274 } else {
00275
00276 error("DecoderOgg: Error while decoding stream, File appears to be "
00277 "corrupted");
00278
00279 finish = TRUE;
00280 }
00281
00282 unlock();
00283 }
00284
00285 lock();
00286
00287 if (finish)
00288 stat = DecoderEvent::Finished;
00289 else if (user_stop)
00290 stat = DecoderEvent::Stopped;
00291
00292 unlock();
00293
00294 {
00295 DecoderEvent e((DecoderEvent::Type) stat);
00296 dispatch(e);
00297 }
00298
00299 deinit();
00300 }
00301
00302 MetaIO *VorbisDecoder::doCreateTagger(void)
00303 {
00304 return new MetaIOOggVorbisComment();
00305 }
00306
00307 bool VorbisDecoderFactory::supports(const QString &source) const
00308 {
00309 return (source.right(extension().length()).lower() == extension());
00310 }
00311
00312 const QString &VorbisDecoderFactory::extension() const
00313 {
00314 static QString ext(".ogg");
00315 return ext;
00316 }
00317
00318 const QString &VorbisDecoderFactory::description() const
00319 {
00320 static QString desc(QObject::tr("Ogg Vorbis Audio"));
00321 return desc;
00322 }
00323
00324 Decoder *VorbisDecoderFactory::create(const QString &file, QIODevice *input,
00325 AudioOutput *output, bool deletable)
00326 {
00327 if (deletable)
00328 return new VorbisDecoder(file, this, input, output);
00329
00330 static VorbisDecoder *decoder = 0;
00331 if (! decoder) {
00332 decoder = new VorbisDecoder(file, this, input, output);
00333 } else {
00334 decoder->setInput(input);
00335 decoder->setFilename(file);
00336 decoder->setOutput(output);
00337 }
00338
00339 return decoder;
00340 }
00341