-rw-r--r-- | core/multimedia/opieplayer/libmad/libmadplugin.cpp | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/core/multimedia/opieplayer/libmad/libmadplugin.cpp b/core/multimedia/opieplayer/libmad/libmadplugin.cpp index 9a1ab2a..9d1ff8c 100644 --- a/core/multimedia/opieplayer/libmad/libmadplugin.cpp +++ b/core/multimedia/opieplayer/libmad/libmadplugin.cpp @@ -14,129 +14,130 @@ ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ // largly modified by Maximilian Reiss <max.reiss@gmx.de> #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <time.h> #include <locale.h> #include <math.h> #include <assert.h> #include <qapplication.h> #include <qmessagebox.h> #include <qregexp.h> #include <qpe/config.h> // for network handling #include <netinet/in.h> #include <netdb.h> #include <linux/limits.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> //#define HAVE_MMAP #if defined(HAVE_MMAP) # include <sys/mman.h> #endif #include "libmadplugin.h" extern "C" { #include "mad.h" } #define MPEG_BUFFER_SIZE 65536 //#define MPEG_BUFFER_SIZE 32768 //16384 // 8192 //#define debugMsg(a) qDebug(a) #define debugMsg(a) class Input { public: char const *path; int fd; #if defined(HAVE_MMAP) void *fdm; #endif - unsigned char *data; + unsigned long fileLength; + unsigned char *data; unsigned long length; int eof; }; class Output { public: mad_fixed_t attenuate; struct filter *filters; unsigned int channels_in; unsigned int channels_out; unsigned int speed_in; unsigned int speed_out; const char *path; }; # if defined(HAVE_MMAP) static void *map_file(int fd, unsigned long *length) { void *fdm; *length += MAD_BUFFER_GUARD; fdm = mmap(0, *length, PROT_READ, MAP_SHARED, fd, 0); if (fdm == MAP_FAILED) return 0; # if defined(HAVE_MADVISE) madvise(fdm, *length, MADV_SEQUENTIAL); # endif return fdm; } static int unmap_file(void *fdm, unsigned long length) { if (munmap(fdm, length) == -1) return -1; return 0; } # endif static inline QString tr( const char *str ) { // Apparently this is okay from a plugin as it runs in the process space of the owner of the plugin return qApp->translate( "OpiePlayer", str, "libmad strings for mp3 file info" ); } class LibMadPluginData { public: Input input; Output output; int bad_last_frame; struct mad_stream stream; struct mad_frame frame; struct mad_synth synth; bool flush; }; @@ -392,243 +393,276 @@ int LibMadPlugin::http_open(const QString& path ) { return http_open(&http_request[10]); } if (QString(http_request).left(4) == "ICY ") { /* This is shoutcast/icecast streaming */ if (strncmp(http_request + 4, "200 ", 4)) { qDebug("http_open: " + QString(http_request) + "\n"); return 0; } } else if (QString(http_request).left(4) == "icy-") { /* we can have: icy-noticeX, icy-name, icy-genre, icy-url, icy-pub, icy-metaint, icy-br */ if ( QString( http_request ).left( 8 ) == "icy-name" ) { name = tr("Name: ") + QString(http_request).mid(9, (QString(http_request).length())- 9 ); } else if ( QString( http_request ).left( 9 ) == "icy-genre" ) { genre = tr("Genre: ") + QString(http_request).mid(10, (QString(http_request).length())-10 ); } else if ( QString( http_request ).left( 6 ) == "icy-br" ) { bitrate = tr("Bitrate: ") + QString(http_request).mid(7, (QString(http_request).length())- 7 ); } else if ( QString( http_request ).left( 7 ) == "icy-url" ) { url = tr("URL: ") + QString(http_request).mid(8, (QString(http_request).length())- 8 ); } else if ( QString( http_request ).left( 10 ) == "icy-notice" ) { message += QString(http_request).mid(11, QString(http_request).length()-11 ) ; } } } while (strcmp(http_request, "\n") != 0); info = QString(name + genre + url + bitrate + message).replace( QRegExp("\n"), " : " ); qDebug("Stream info: " + info); return (tcp_sock); } bool LibMadPlugin::open( const QString& path ) { debugMsg( "LibMadPlugin::open" ); Config cfg("OpiePlayer"); cfg.setGroup("Options"); bufferSize = cfg.readNumEntry("MPeg_BufferSize",MPEG_BUFFER_SIZE); qDebug("buffer size is %d", bufferSize); d->bad_last_frame = 0; d->flush = TRUE; info = QString( "" ); //qDebug( "Opening %s", path.latin1() ); if (path.left( 4 ) == "http" ) { // in case of any error we get 0 here if ( !(http_open(path) == 0) ) { d->input.fd = http_open(path); } else { return FALSE; } } else { d->input.path = path.latin1(); d->input.fd = ::open( d->input.path, O_RDONLY ); // thats a better place, since it should only seek for ID3 tags on mp3 files, not streams printID3Tags(); } if (d->input.fd == -1) { qDebug("error opening %s", d->input.path ); return FALSE; } -#if defined(HAVE_MMAP) struct stat stat; if (fstat(d->input.fd, &stat) == -1) { - //qDebug("error calling fstat"); return FALSE; + qDebug("error calling fstat"); return FALSE; } + if (S_ISREG(stat.st_mode) && stat.st_size > 0) + d->input.fileLength = stat.st_size; + else + d->input.fileLength = 0; + +#if defined(HAVE_MMAP) if (S_ISREG(stat.st_mode) && stat.st_size > 0) { d->input.length = stat.st_size; d->input.fdm = map_file(d->input.fd, &d->input.length); if (d->input.fdm == 0) { qDebug("error mmapping file"); return FALSE; } d->input.data = (unsigned char *)d->input.fdm; } #endif if (d->input.data == 0) { d->input.data = (unsigned char *)malloc( bufferSize /*MPEG_BUFFER_SIZE*/); if (d->input.data == 0) { qDebug("error allocating input buffer"); return FALSE; } d->input.length = 0; } d->input.eof = 0; mad_stream_init(&d->stream); mad_frame_init(&d->frame); mad_synth_init(&d->synth); return TRUE; } bool LibMadPlugin::close() { debugMsg( "LibMadPlugin::close" ); int result = TRUE; mad_synth_finish(&d->synth); mad_frame_finish(&d->frame); mad_stream_finish(&d->stream); #if defined(HAVE_MMAP) if (d->input.fdm) { if (unmap_file(d->input.fdm, d->input.length) == -1) { qDebug("error munmapping file"); result = FALSE; } d->input.fdm = 0; d->input.data = 0; } #endif if (d->input.data) { free(d->input.data); d->input.data = 0; } if (::close(d->input.fd) == -1) { qDebug("error closing file %s", d->input.path); result = FALSE; } d->input.fd = 0; return result; } bool LibMadPlugin::isOpen() { debugMsg( "LibMadPlugin::isOpen" ); return ( d->input.fd != 0 ); } int LibMadPlugin::audioStreams() { debugMsg( "LibMadPlugin::audioStreams" ); return 1; } int LibMadPlugin::audioChannels( int ) { debugMsg( "LibMadPlugin::audioChannels" ); /* long t; short t1[5]; audioReadSamples( t1, 2, 1, t, 0 ); qDebug( "LibMadPlugin::audioChannels: %i", d->frame.header.mode > 0 ? 2 : 1 ); return d->frame.header.mode > 0 ? 2 : 1; */ return 2; } int LibMadPlugin::audioFrequency( int ) { debugMsg( "LibMadPlugin::audioFrequency" ); long t; short t1[5]; audioReadSamples( t1, 2, 1, t, 0 ); qDebug( "LibMadPlugin::audioFrequency: %i", d->frame.header.samplerate ); return d->frame.header.samplerate; } int LibMadPlugin::audioSamples( int ) { - debugMsg( "LibMadPlugin::audioSamples" ); + debugMsg( "LibMadPlugin::audioSamples" ); + + long t; short t1[5]; audioReadSamples( t1, 2, 1, t, 0 ); + mad_header_decode( (struct mad_header *)&d->frame.header, &d->stream ); +/* + qDebug( "LibMadPlugin::audioSamples: %i*%i", d->frame.header.duration.seconds, + d->frame.header.samplerate ); + return d->frame.header.duration.seconds * d->frame.header.samplerate; +*/ + if ( d->frame.header.bitrate == 0 ) + return 0; + int samples = (d->input.fileLength / (d->frame.header.bitrate/8)) * d->frame.header.samplerate; + + qDebug( "LibMadPlugin::audioSamples: %i * %i * 8 / %i", (int)d->input.fileLength, + (int)d->frame.header.samplerate, (int)d->frame.header.bitrate ); + qDebug( "LibMadPlugin::audioSamples: %i", samples ); - // long t; short t1[5]; audioReadSamples( t1, 2, 1, t, 0 ); -// mad_header_decode( (struct mad_header *)&d->frame.header, &d->stream ); -// qDebug( "LibMadPlugin::audioSamples: %i*%i", d->frame.header.duration.seconds, d->frame.header.samplerate ); -// return d->frame.header.duration.seconds * d->frame.header.samplerate; + return samples; - return 10000000; +// return 10000000; } bool LibMadPlugin::audioSetSample( long, int ) { debugMsg( "LibMadPlugin::audioSetSample" ); + +// long totalSamples = audioSamples(0); +// if ( totalSamples <= 1 ) +// return FALSE; + +// // Seek to requested position +// qDebug( "seek pos: %i", (int)((double)pos * d->input.fileLength / totalSamples) ); +// ::lseek( d->input.fd, (long)((double)pos * d->input.fileLength / totalSamples), SEEK_SET ); +// mad_stream_sync(&d->stream); + +// mad_stream_init(&d->stream); +// mad_frame_init(&d->frame); +// mad_synth_init(&d->synth); + +// return TRUE; + debugMsg( "LibMadPlugin::audioSetSample" ); return FALSE; } long LibMadPlugin::audioGetSample( int ) { debugMsg( "LibMadPlugin::audioGetSample" ); return 0; } /* bool LibMadPlugin::audioReadSamples( short *, int, long, int ) { debugMsg( "LibMadPlugin::audioReadSamples" ); return FALSE; } bool LibMadPlugin::audioReReadSamples( short *, int, long, int ) { debugMsg( "LibMadPlugin::audioReReadSamples" ); return FALSE; } */ bool LibMadPlugin::read() { debugMsg( "LibMadPlugin::read" ); int len; if (d->input.eof) return FALSE; #if defined(HAVE_MMAP) if (d->input.fdm) { unsigned long skip = 0; if (d->stream.next_frame) { struct stat stat; if (fstat(d->input.fd, &stat) == -1) return FALSE; if (stat.st_size + MAD_BUFFER_GUARD <= (signed)d->input.length) return FALSE; // file size changed; update memory map skip = d->stream.next_frame - d->input.data; if (unmap_file(d->input.fdm, d->input.length) == -1) { d->input.fdm = 0; d->input.data = 0; return FALSE; } d->input.length = stat.st_size; d->input.fdm = map_file(d->input.fd, &d->input.length); if (d->input.fdm == 0) { d->input.data = 0; return FALSE; } d->input.data = (unsigned char *)d->input.fdm; } mad_stream_buffer(&d->stream, d->input.data + skip, d->input.length - skip); |