[mythtv] [PATCH] MythMusic On Demand Loading

John Hurliman jhurliman at myrealbox.com
Mon Apr 21 00:08:58 EDT 2003


(Hey I got the subject right this time). This is the beginning of my 
attempts to speed up the load time for mythmusic when using large audio 
archives and/or CD-based media. I'm submitting it because I'm stuck 
right now and need a little help. I wrote a new function 
AllMusic::checkFilesInTree() which calls MusicNode::checkYourself() 
which calls the existing CheckFile function. CheckFile was modified to 
run in two modes, just update the database with an id, filename, minimal 
info, and the second runs a full CheckFile (actually opens the file and 
gets things like length or id3 tag). The problem is I'm calling 
all_music->checkFilesInTree() from startPlayback() and it's checking the 
entire tree each time you go to the PlaybackBox screen. I need to make 
it only check the files which will show up in the PlaybackBox or take a 
completely different approach. I think I'm way off base here but it's a 
start.

John Hurliman
-------------- next part --------------
Index: cddecoder.cpp
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/cddecoder.cpp,v
retrieving revision 1.12
diff -u -r1.12 cddecoder.cpp
--- cddecoder.cpp	25 Mar 2003 20:12:06 -0000	1.12
+++ cddecoder.cpp	21 Apr 2003 05:50:14 -0000
@@ -315,8 +315,9 @@
     return getMetadata();
 }
 
-Metadata* CdDecoder::getMetadata(QSqlDatabase *x)
+Metadata* CdDecoder::getMetadata(QSqlDatabase *x, bool readFile)
 {
+    readFile = false;
     x = x ;
     return getMetadata();
 }
Index: cddecoder.h
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/cddecoder.h,v
retrieving revision 1.7
diff -u -r1.7 cddecoder.h
--- cddecoder.h	25 Mar 2003 20:12:06 -0000	1.7
+++ cddecoder.h	21 Apr 2003 05:50:14 -0000
@@ -25,7 +25,7 @@
     int getNumTracks(void);
 
     Metadata *getMetadata(QSqlDatabase *db, int track);
-    Metadata *getMetadata(QSqlDatabase *db);
+    Metadata *getMetadata(QSqlDatabase *db, bool readFile);
     Metadata *getMetadata(int track);
     Metadata *getMetadata();
     void commitMetadata(Metadata *mdata);
Index: decoder.h
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/decoder.h,v
retrieving revision 1.4
diff -u -r1.4 decoder.h
--- decoder.h	5 Feb 2003 19:47:54 -0000	1.4
+++ decoder.h	21 Apr 2003 05:50:15 -0000
@@ -78,7 +78,7 @@
     static Decoder *create(const QString &, QIODevice *, Output *, 
                            bool = FALSE);
 
-    virtual Metadata *getMetadata(QSqlDatabase *db) = 0;
+    virtual Metadata *getMetadata(QSqlDatabase *db, bool readFile) = 0;
     virtual void commitMetadata(Metadata *mdata) = 0;
 
   protected:
Index: flacdecoder.cpp
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/flacdecoder.cpp,v
retrieving revision 1.5
diff -u -r1.5 flacdecoder.cpp
--- flacdecoder.cpp	5 Feb 2003 19:47:54 -0000	1.5
+++ flacdecoder.cpp	21 Apr 2003 05:50:17 -0000
@@ -408,75 +408,81 @@
         char *field_value;
 } Argument_VcField;
 
-Metadata *FlacDecoder::getMetadata(QSqlDatabase *db)
+Metadata *FlacDecoder::getMetadata(QSqlDatabase *db, bool readFile)
 {
     Metadata *testdb = new Metadata(filename);
-    if (testdb->isInDatabase(db))
-        return testdb;
-
+    if(!readFile)
+    {
+        if (testdb->isInDatabase(db))
+            return testdb;
+    }
+    
     delete testdb;
 
     QString artist = "", album = "", title = "", genre = "";
     int year = 0, tracknum = 0, length = 0;
 
-    FILE *input = fopen(filename.ascii(), "r");
-
-    if (!input)
-        return NULL;
-
-    FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
-    if (!FLAC__metadata_chain_read(chain, filename.ascii()))
+    if(readFile)
     {
-        FLAC__metadata_chain_delete(chain); 
-        return NULL;
-    }
-
-    bool found_vc_block = false;
-    FLAC__StreamMetadata *block = 0;
-    FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
+        FILE *input = fopen(filename.ascii(), "r");
 
-    FLAC__metadata_iterator_init(iterator, chain);
+        if (!input)
+            return NULL;
 
-    block = FLAC__metadata_iterator_get_block(iterator);
+        FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
+        if (!FLAC__metadata_chain_read(chain, filename.ascii()))
+        {
+            FLAC__metadata_chain_delete(chain); 
+            return NULL;
+        }
+
+        bool found_vc_block = false;
+        FLAC__StreamMetadata *block = 0;
+        FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
 
-    FLAC__ASSERT(0 != block);
-    FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
+        FLAC__metadata_iterator_init(iterator, chain);
 
-    int samplerate = block->data.stream_info.sample_rate;
-    int totalsamples = block->data.stream_info.total_samples;
-    int bytesperms = (samplerate) / 1000;
+        block = FLAC__metadata_iterator_get_block(iterator);
 
-    length = totalsamples / bytesperms;
+        FLAC__ASSERT(0 != block);
+        FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
 
-    do {
-        block = FLAC__metadata_iterator_get_block(iterator);
-        if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
-            found_vc_block = true;
-    } while (!found_vc_block && FLAC__metadata_iterator_next(iterator));
+        int samplerate = block->data.stream_info.sample_rate;
+        int totalsamples = block->data.stream_info.total_samples;
+        int bytesperms = (samplerate) / 1000;
+
+        length = totalsamples / bytesperms;
+
+        do {
+          block = FLAC__metadata_iterator_get_block(iterator);
+          if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+              found_vc_block = true;
+        } while (!found_vc_block && FLAC__metadata_iterator_next(iterator));
+
+        if (!found_vc_block)
+        {
+          FLAC__metadata_chain_delete(chain);
+          FLAC__metadata_iterator_delete(iterator);
+          return NULL;
+        }
+
+        FLAC__ASSERT(0 != block);
+        FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+        artist = getComment(block, "artist");
+        album = getComment(block, "album");
+        title = getComment(block, "title");
+        genre = getComment(block, "genre");
+        tracknum = getComment(block, "tracknumber").toInt(); 
+        year = getComment(block, "date").toInt();
 
-    if (!found_vc_block)
-    {
         FLAC__metadata_chain_delete(chain);
         FLAC__metadata_iterator_delete(iterator);
-        return NULL;
     }
 
-    FLAC__ASSERT(0 != block);
-    FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
-    artist = getComment(block, "artist");
-    album = getComment(block, "album");
-    title = getComment(block, "title");
-    genre = getComment(block, "genre");
-    tracknum = getComment(block, "tracknumber").toInt(); 
-    year = getComment(block, "date").toInt();
-
     Metadata *retdata = new Metadata(filename, artist, album, title, genre,
                                      year, tracknum, length);
-
-    FLAC__metadata_chain_delete(chain);
-    FLAC__metadata_iterator_delete(iterator);
-
+    
     retdata->dumpToDatabase(db);
 
     return retdata;
Index: flacdecoder.h
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/flacdecoder.h,v
retrieving revision 1.4
diff -u -r1.4 flacdecoder.h
--- flacdecoder.h	5 Feb 2003 19:47:54 -0000	1.4
+++ flacdecoder.h	21 Apr 2003 05:50:17 -0000
@@ -21,7 +21,7 @@
     void doWrite(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
     void setFlacMetadata(const FLAC__StreamMetadata *metadata);
 
-    Metadata *getMetadata(QSqlDatabase *db);
+    Metadata *getMetadata(QSqlDatabase *db, bool readFile);
     void commitMetadata(Metadata *mdata);
 
   private:
Index: maddecoder.cpp
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/maddecoder.cpp,v
retrieving revision 1.8
diff -u -r1.8 maddecoder.cpp
--- maddecoder.cpp	15 Apr 2003 21:38:58 -0000	1.8
+++ maddecoder.cpp	21 Apr 2003 05:50:20 -0000
@@ -529,11 +529,14 @@
     return MAD_FLOW_STOP;
 }
 
-Metadata *MadDecoder::getMetadata(QSqlDatabase *db)
+Metadata *MadDecoder::getMetadata(QSqlDatabase *db, bool readFile)
 {
     Metadata *testdb = new Metadata(filename);
-    if (testdb->isInDatabase(db))
-        return testdb;
+    if(!readFile)
+    {
+        if (testdb->isInDatabase(db))
+            return testdb;
+    }
 
     delete testdb;
 
@@ -650,66 +653,69 @@
             }
         }
     }
-
+    
     struct mad_stream stream;
     struct mad_header header;
     mad_timer_t timer;
 
-    unsigned char buffer[8192];
-    unsigned int buflen = 0;
+    if (readFile)
+    {
+        unsigned char buffer[8192];
+        unsigned int buflen = 0;
 
-    mad_stream_init(&stream);
-    mad_header_init(&header);
+        mad_stream_init(&stream);
+        mad_header_init(&header);
    
-    timer = mad_timer_zero;
+        timer = mad_timer_zero;
 
-    FILE *input = fopen(filename.ascii(), "r");
+        FILE *input = fopen(filename.ascii(), "r");
 
-    while (1) 
-    {
-        if (buflen < sizeof(buffer)) 
+        while (1) 
         {
-            int bytes;
-            bytes = fread(buffer + buflen, 1, sizeof(buffer) - buflen, input);
-            if (bytes <= 0)
-                break;
-            buflen += bytes;
-        }
+            if (buflen < sizeof(buffer)) 
+            {
+                int bytes;
+                bytes = fread(buffer + buflen, 1, sizeof(buffer) - buflen, input);
+                if (bytes <= 0)
+                    break;
+                buflen += bytes;
+            }
 
-        mad_stream_buffer(&stream, buffer, buflen);
+            mad_stream_buffer(&stream, buffer, buflen);
 
-        while (1)
-        {
-            if (mad_header_decode(&header, &stream) == -1)
+            while (1)
             {
-                if (!MAD_RECOVERABLE(stream.error))
-                    break;
-                if (stream.error == MAD_ERROR_LOSTSYNC)
+                if (mad_header_decode(&header, &stream) == -1)
                 {
-                    int tagsize = id3_tag_query(stream.this_frame,
-                                                stream.bufend - 
-                                                stream.this_frame);
-                    if (tagsize > 0)
-                        mad_stream_skip(&stream, tagsize);
+                    if (!MAD_RECOVERABLE(stream.error))
+                       break;
+                    if (stream.error == MAD_ERROR_LOSTSYNC)
+                    {
+                        int tagsize = id3_tag_query(stream.this_frame,
+                                                    stream.bufend - 
+                                                    stream.this_frame);
+                        if (tagsize > 0)
+                            mad_stream_skip(&stream, tagsize);
+                    }
                 }
+                mad_timer_add(&timer, header.duration);
             }
-            mad_timer_add(&timer, header.duration);
-        }
         
-        if (stream.error != MAD_ERROR_BUFLEN)
-            break;
-
-        memmove(buffer, stream.next_frame, &buffer[buflen] - stream.next_frame);
-        buflen -= stream.next_frame - &buffer[0];
-    }
+            if (stream.error != MAD_ERROR_BUFLEN)
+                break;
 
-    mad_header_finish(&header);
-    mad_stream_finish(&stream);
+            memmove(buffer, stream.next_frame, &buffer[buflen] - stream.next_frame);
+            buflen -= stream.next_frame - &buffer[0];
+        }
 
-    fclose(input);
+        mad_header_finish(&header);
+        mad_stream_finish(&stream);
 
-    length = mad_timer_count(timer, MAD_UNITS_MILLISECONDS);
+        fclose(input);
 
+        length = mad_timer_count(timer, MAD_UNITS_MILLISECONDS);
+    }
+    
     Metadata *retdata = new Metadata(filename, artist, album, title, genre,
                                      year, tracknum, length);
 
Index: maddecoder.h
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/maddecoder.h,v
retrieving revision 1.5
diff -u -r1.5 maddecoder.h
--- maddecoder.h	5 Feb 2003 19:47:54 -0000	1.5
+++ maddecoder.h	21 Apr 2003 05:50:20 -0000
@@ -24,7 +24,7 @@
     static const int maxFrameCheck;
     static const int initialFrameSize;
 
-    Metadata *getMetadata(QSqlDatabase *db);
+    Metadata *getMetadata(QSqlDatabase *db, bool readFile);
     void commitMetadata(Metadata *mdata);
 
 private:
Index: main.cpp
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/main.cpp,v
retrieving revision 1.39
diff -u -r1.39 main.cpp
--- main.cpp	18 Apr 2003 18:19:31 -0000	1.39
+++ main.cpp	21 Apr 2003 05:50:21 -0000
@@ -23,6 +23,8 @@
 #include <mythtv/themedmenu.h>
 #include <mythtv/mythcontext.h>
 
+#include "main.h"
+
 MythContext *gContext;
 
 void CheckFreeDBServerFile(void)
@@ -59,7 +61,7 @@
     return decoder;
 }
 
-void CheckFile(const QString &filename)
+void CheckFile(const QString &filename, bool readFile)
 {
     Decoder *decoder = getDecoder(filename);
 
@@ -67,7 +69,7 @@
     {
         QSqlDatabase *db = QSqlDatabase::database();
 
-        Metadata *data = decoder->getMetadata(db);
+        Metadata *data = decoder->getMetadata(db, readFile);
         if (data)
             delete data;
 
@@ -211,7 +213,7 @@
     {
         if (*iter == kFileSystem)
         {
-            CheckFile(iter.key());
+            CheckFile(iter.key(), false);
         }
         else if (*iter == kDatabase)
         {
@@ -231,6 +233,14 @@
 
 void startPlayback(PlaylistsContainer *all_playlists, AllMusic *all_music)
 {
+    if(!all_music)
+    {
+        cerr << "main.o: We are not going to get very far with a null pointer to metadata" << endl;
+        return;
+    }
+    
+    all_music->checkFilesInTree();
+    
     PlaybackBox *pbb = new PlaybackBox(all_playlists, all_music);
     pbb->Show();
 
Index: metadata.cpp
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/metadata.cpp,v
retrieving revision 1.22
diff -u -r1.22 metadata.cpp
--- metadata.cpp	12 Apr 2003 16:01:06 -0000	1.22
+++ metadata.cpp	21 Apr 2003 05:50:25 -0000
@@ -10,6 +10,7 @@
 #include <mythtv/mythwidgets.h>
 
 #include "metadata.h"
+#include "main.h"
 
 bool operator==(const Metadata& a, const Metadata& b)
 {
@@ -124,16 +125,28 @@
     QString sqlfilename = filename;
     sqlfilename.replace(QRegExp("\""), QString("\\\""));
 
-    QString thequery = QString("INSERT INTO musicmetadata (artist,album,title,"
-                               "genre,year,tracknum,length,filename) VALUES "
-                               "(\"%1\",\"%2\",\"%3\",\"%4\",%5,%6,%7,\"%8\");")
-                              .arg(artist.latin1()).arg(album.latin1())
-                              .arg(title.latin1()).arg(genre).arg(year)
-                              .arg(tracknum).arg(length).arg(sqlfilename);
-    db->exec(thequery);
+    QString updatequery = QString("UPDATE musicmetadata SET artist = \"%1\", "
+                                  "album = \"%2\", title = \"%3\", genre = \"%4\", "
+                                  "year = \"%5\", tracknum = \"%6\", "
+                                  "length = \"%7\" WHERE filename = \"%8\" LIMIT 1;")
+                                 .arg(artist.latin1()).arg(album.latin1())
+                                 .arg(title.latin1()).arg(genre).arg(year)
+                                 .arg(tracknum).arg(length).arg(sqlfilename);
+    QSqlQuery query = db->exec(updatequery);
+    
+    if (query.numRowsAffected() == 0)
+    {
+        QString thequery = QString("INSERT INTO musicmetadata (artist,album,title,"
+                                   "genre,year,tracknum,length,filename) VALUES "
+                                   "(\"%1\",\"%2\",\"%3\",\"%4\",%5,%6,%7,\"%8\");")
+                                  .arg(artist.latin1()).arg(album.latin1())
+                                  .arg(title.latin1()).arg(genre).arg(year)
+                                  .arg(tracknum).arg(length).arg(sqlfilename);
+        db->exec(thequery);
 
-    // easiest way to ensure we've got 'id' filled.
-    fillData(db);
+        // easiest way to ensure we've got 'id' filled.
+        fillData(db);
+    }
 }
 
 void Metadata::setField(const QString &field, const QString &data)
@@ -542,6 +555,22 @@
     }
 }
 
+void AllMusic::checkFilesInTree()
+{
+    //FIXME: Display a progress dialog
+    
+    root_node->checkYourself();
+    QPtrListIterator<MusicNode> iter( top_nodes );
+    MusicNode *checker;
+    while ( (checker = iter.current()) != 0 )
+    {
+        checker->checkYourself();
+        ++iter;
+    }
+
+    resync();
+}
+
 void AllMusic::buildTree()
 {
     //
@@ -953,3 +982,22 @@
     }
 }
 
+void MusicNode::checkYourself()
+{
+    QPtrListIterator<Metadata>  anit(my_tracks);
+    Metadata *a_track;
+    while( (a_track = anit.current() ) != 0)
+    {
+        QString filename = a_track->Filename();
+        CheckFile(filename, true);
+        ++anit;
+    }
+
+    QPtrListIterator<MusicNode> iter(my_subnodes);
+    MusicNode *check;
+    while( (check = iter.current() ) != 0)
+    {
+        check->checkYourself();
+        ++iter;
+    }
+}
Index: metadata.h
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/metadata.h,v
retrieving revision 1.12
diff -u -r1.12 metadata.h
--- metadata.h	12 Apr 2003 04:31:18 -0000	1.12
+++ metadata.h	21 Apr 2003 05:50:26 -0000
@@ -141,6 +141,7 @@
     QString     getTitle(){return my_title;}
     MusicNode*  findRightNode(QStringList tree_levels, Metadata *inserter, uint depth);
     void        printYourself(int indent_amount);   // debugging
+    void        checkYourself();
     void        clearTracks(){my_tracks.clear();}
     void        putYourselfOnTheListView(TreeCheckItem *parent, bool show_node);
     void        sort();
@@ -190,6 +191,7 @@
     void        setCDTitle(const QString &a_title){cd_title = a_title;}
     void        buildTree();
     void        printTree();    // debugging
+    void        checkFilesInTree();
     void        sortTree();
     void        intoTree(Metadata* inserter);
     MusicNode*  findRightNode(Metadata* inserter, uint depth);
Index: vorbisdecoder.cpp
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/vorbisdecoder.cpp,v
retrieving revision 1.5
diff -u -r1.5 vorbisdecoder.cpp
--- vorbisdecoder.cpp	15 Apr 2003 21:38:58 -0000	1.5
+++ vorbisdecoder.cpp	21 Apr 2003 05:50:27 -0000
@@ -316,46 +316,52 @@
     deinit();
 }
 
-Metadata *VorbisDecoder::getMetadata(QSqlDatabase *db)
+Metadata *VorbisDecoder::getMetadata(QSqlDatabase *db, bool readFile)
 {
     Metadata *testdb = new Metadata(filename);
-    if (testdb->isInDatabase(db))
-        return testdb;
+    if(!readFile)
+    {
+        if (testdb->isInDatabase(db))
+            return testdb;
+    }
 
     delete testdb;
 
     QString artist = "", album = "", title = "", genre = "";
     int year = 0, tracknum = 0, length = 0;
-
-    FILE *input = fopen(filename.ascii(), "r");
-
-    if (!input)
-        return NULL;
-
-    OggVorbis_File vf;
-    vorbis_comment *comment = NULL;
-
-    if (ov_open(input, &vf, NULL, 0))
+    
+    if(readFile)
     {
-        fclose(input);
-        return NULL;
-    }
+        FILE *input = fopen(filename.ascii(), "r");
 
-    comment = ov_comment(&vf, -1);
-    length = (int)ov_time_total(&vf, -1) * 1000;
+        if (!input)
+            return NULL;
 
-    artist = getComment(comment, "artist");
-    album = getComment(comment, "album");
-    title = getComment(comment, "title");
-    genre = getComment(comment, "genre");
-    tracknum = atoi(getComment(comment, "tracknumber").ascii()); 
-    year = atoi(getComment(comment, "date").ascii());
+        OggVorbis_File vf;
+        vorbis_comment *comment = NULL;
 
-    ov_clear(&vf);
+        if (ov_open(input, &vf, NULL, 0))
+        {
+           fclose(input);
+            return NULL;
+        }
+
+        comment = ov_comment(&vf, -1);
+        length = (int)ov_time_total(&vf, -1) * 1000;
+
+        artist = getComment(comment, "artist");
+        album = getComment(comment, "album");
+        title = getComment(comment, "title");
+        genre = getComment(comment, "genre");
+        tracknum = atoi(getComment(comment, "tracknumber").ascii()); 
+        year = atoi(getComment(comment, "date").ascii());
 
+        ov_clear(&vf);
+    }
+    
     Metadata *retdata = new Metadata(filename, artist, album, title, genre,
                                      year, tracknum, length);
-
+    
     retdata->dumpToDatabase(db);
 
     return retdata;
Index: vorbisdecoder.h
===================================================================
RCS file: /var/lib/cvs/mythmusic/mythmusic/vorbisdecoder.h,v
retrieving revision 1.4
diff -u -r1.4 vorbisdecoder.h
--- vorbisdecoder.h	5 Feb 2003 19:47:54 -0000	1.4
+++ vorbisdecoder.h	21 Apr 2003 05:50:27 -0000
@@ -18,7 +18,7 @@
     void seek(double);
     void stop();
 
-    Metadata *getMetadata(QSqlDatabase *db);
+    Metadata *getMetadata(QSqlDatabase *db, bool readFile);
     void commitMetadata(Metadata *mdata);
 
   private:
-------------- next part --------------
void CheckFile(const QString &filename, bool readFile);


More information about the mythtv-dev mailing list