Cover Art

Help
kilbert
2009-01-27
2013-08-13
  •  kilbert
    kilbert
    2009-01-27

    I know I read somewhere mediatomb supports cover art, can someone point me to the reading of how it is done.
    (linux/ps3)
    thansk
    kilbert

     
    • Jin
      Jin
      2009-01-29

      Just make sure that your mp3 files have cover art embedded in the id3 tags, SVN version with libmp4v2 also supports MP4 cover art.

      And for the PS3 you will have to enable the protocolInfo option. Also, if the cover art is too big the PS3 will not show it (I think 160x160 is maximum for a thumbnail/cover art image).

       
  • Jared Kidd
    Jared Kidd
    2010-04-09

    I have cover art showing from one mediatomb box but it is not showing from the other one which I compiled from svn. What would effect it?

     
  • Jared Kidd
    Jared Kidd
    2010-04-09

    Nevermind, it works now. I had to blow out the database and re-import everything.

     
  • Cover art in a folder as an option to embedded in the mp3 would be a nice feature.  

     
  • Jin
    Jin
    2010-04-12

    I know :) Had no time for it yet.

     
  • Peter Asplund
    Peter Asplund
    2011-04-07

    Cover art in a folder is really a killer feature, I'm very sad to see that mediatomb doesn't support it :(

    I've bought a Linn Sneaky DS, and it really takes away the feeling of browsing through albums when there are no covers. I +1 the request for the feature! =)

     
  • cojms1
    cojms1
    2011-04-11

    Should cover art also work for mp4 video files?  I have some embedded into my mp4 files and have built from SVN with libmp4v2 support compiled.  I have shrunk the covert art files to be smaller than 160x160 but still no luck with seeing the art on the PS3.  protocolInfo is also set to yes.  I can see when I turn debug on that the mp4tags are being read.  Using mp4art or mp4info it shows that cover art is embedded.

     
  • Nigel Gilbert
    Nigel Gilbert
    2011-04-13

    cojms1,

    I managed to get cover art to work the way you describe (embedded in mp4 files), but I needed to build the software with taglib support as well as libmp4v2.

    I believe this works because without taglib, the

    #ifdef HAVE_ID3_ALBUMART
    

    block in cds_resource_manager.cc:371 will not be compiled in, preventing processing the resource content

    ID3_ALBUM_ART
    

    which is returned by

    metadata/libmp4v2_handler.cc:223
    

    . Though, I don't know why this extra dependency is required!

    Also, I didn't need to resize the cover art images, some of my cover art images are larger than 160x160 and they worked fine.

    Hope this helps.

     
  • cojms1
    cojms1
    2011-04-13

    Hi norbini,

    I thought you may have hit the nail on the head, but it appears that I did compile with taglib support.  My MP3 tags are being read correctly.  Compile info below…

    <code>
    MediaTomb UPnP Server version 0.12.1 - http://mediatomb.cc/

    ===============================================================================
    Copyright 2005-2010 Gena Batsyan, Sergey Bostandzhyan, Leonhard Wimmer.
    MediaTomb is free software, covered by the GNU General Public License version 2

    Compile info:

            host:                   armv5tel-unknown-linux-gnueabi
            sqlite3:                yes
            mysql:                  missing
            libjs:                  yes
            libmagic:               yes
            inotify:                yes
            libexif:                yes
            id3lib:                 disabled
            taglib:                 yes
            ffmpeg                  missing
            libmp4v2:               yes
            external transcoding:   yes
            curl:                   yes
            YouTube:                yes
            libextractor            disabled
            db-autocreate:          yes
            debug log:              yes
            protocol info extension:yes
            ffmpegthumbnailer:      missing
            lastfmlib:              missing
            data directory:         /usr/local/share/mediatomb
    </code>

    I'm not sure if the platform is causing an issue (NSLU2, Debian Squeeze).

     
  • Nigel Gilbert
    Nigel Gilbert
    2011-04-13

    Hi cojms1,

      Hmmm. That's strange. I've upgraded to 0.12.1 and it still seems to work with taglib (or id3lib) and fail without, so could you provide some more information to try and work out how our versions differ?

      To try and simplify things, I've been removing all of my database entries and adding them back in each time I try a new build (all via the web interface). I've also been limiting myself to only putting one file that I think should work in the database (to try and simplify my efforts when running in the debugger). If possible, I'd suggest you do the same.

      Just to check, you are talking about trying to get a thumbnail to appear for an mp4 video (rather than audio)? I think it should work either way, but I've only tested it with video so far.

      1. If you remove, then re-add the file whilst running with -D, you should see some logging in the console. There should be a bunch of lines like:

    [../src/metadata/libmp4v2_handler.cc:129] addMetaField(): mp4 handler: setting metadata on item: ...
    

         Underneath that, there should be:

    [../src/storage/sql_storage.cc:494] addObject(): insert_query: INSERT INTO "mt_cds_object" ...
    

         If libmp4v2 has managed to locate album artwork, there should be a couple of 'protocolInfo=' pieces of text in that massive INSERT statement.
         On my working version, the last one reads:

    5~protocolInfo=http-get%3A%2A%3Aimage%2Fjpeg%3A%2A~rct=aa~
    

    I believe that this is the MIME type of the thumbnail that will be treated as album artwork (rct=aa) according to libmp4v2. Basically, you're looking for something ending 'rct=aa'. Do you have one, if so, what does it say?

      2. If you got something, then we should check that your build is including the right bit to serve the thumbnail; If you didn't, try point 3 for a possible solution.

    grep "HAVE_ID3_ALBUMART" whereever/the/build/is/autoconfig.h
    

    Should show:

    #define HAVE_ID3_ALBUMART 1
    

      3. Check you have:

      <treat mimetype="video/mp4" as="mp4"/>
      <treat mimetype="audio/mp4" as="mp4"/>
    

      in the <mimetype-contenttype> section of the config file.

      You might also check that there were no enabled transcode profiles for the video/mp4 mime type that have <thumbnail>yes</thumbnail>.

      Hope this is of some use, let me know how you get on,
        Cheers,
          -Norbini

    PS. Here are my -compile-info output for reference:

    MediaTomb UPnP Server version 0.12.1 - http://mediatomb.cc/
    ===============================================================================
    Copyright 2005-2010 Gena Batsyan, Sergey Bostandzhyan, Leonhard Wimmer.
    MediaTomb is free software, covered by the GNU General Public License version 2
    Compile info:
    -------------
        host:           x86_64-unknown-linux-gnu
        sqlite3:        yes
        mysql:          missing
        libjs:          missing
        libmagic:       yes
        inotify:        yes
        libexif:        missing
        id3lib:         disabled
        taglib:         yes
        ffmpeg          missing
        libmp4v2:       yes
        external transcoding:   yes
        curl:           yes
        YouTube:        yes
        libextractor        disabled
        db-autocreate:      yes
        debug log:      yes
        protocol info extension:yes
        ffmpegthumbnailer:  disabled
        lastfmlib:      missing
    

    In case it helps anyone, I'm using Ubuntu 10.10, using the following packages:

    libmp4v2-dev   1:1.6dfsg-0.2ubuntu9
    libmagic-dev   5.03-5ubuntu1
    libtag1-dev    1.6.3-1
    libsqlite3-dev 3.7.2-1ubuntu0.1

     
  • cojms1
    cojms1
    2011-04-14

    Hi norbini,

    Thanks for the pointers.  I've turned debugging on and it looks like libmp4v2 is not being used to gather the metadata of the file.  I see a number of lines referring to

    ../src/metadata/ffmpeg_handler.cc
    

    Below is the config I am using

    <?xml version="1.0" encoding="UTF-8"?>
    <config version="1" xmlns="http://mediatomb.cc/config/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://mediatomb.cc/config/1 http://mediatomb.cc/config/1.xsd">
      <server>
        <pc-directory upnp-hide="yes"/>
        <port>50500</port>
        <ui enabled="yes" poll-when-idle="no">
          <accounts enabled="no" session-timeout="30">
            <account user="mediatomb" password="mediatomb"/>
          </accounts>
        </ui>
        <name>MediaTomb</name>
        <udn>uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</udn>
        <home>/var/lib/mediatomb</home>
        <webroot>/usr/share/mediatomb/web</webroot>
        <storage>
          <sqlite3 enabled="yes">
            <database-file>mediatomb.db</database-file>
          </sqlite3>
          <mysql enabled="no">
            <host>localhost</host>
            <username>mediatomb</username>
            <database>mediatomb</database>
          </mysql>
        </storage>
        <protocolInfo extend="yes"/>
      </server>
      <import hidden-files="no">
        <filesystem-charset>ISO-8859-1</filesystem-charset>
        <metadata-charset>ISO-8859-1</metadata-charset>
        <playlist-charset>ISO-8859-1</playlist-charset>
        <scripting script-charset="UTF-8">
          <common-script>/usr/share/mediatomb/js/common.js</common-script>
          <playlist-script>/usr/share/mediatomb/js/playlists.js</playlist-script>
          <virtual-layout type="js">
            <import-script>/usr/share/mediatomb/js/js-import.js</import-script>
          </virtual-layout>
        </scripting>
        <mappings>
          <extension-mimetype ignore-unknown="yes">
            <map from="mp3" to="audio/mpeg"/>
            <map from="jpg" to="image/jpeg"/>
            <map from="m4v" to="video/mp4"/>
            <map from="mp4" to="video/mp4"/>
            <map from="avi" to="video/divx"/>
          </extension-mimetype>
          <mimetype-upnpclass>
            <map from="audio/*" to="object.item.audioItem.musicTrack"/>
            <map from="video/*" to="object.item.videoItem"/>
            <map from="image/*" to="object.item.imageItem"/>
          </mimetype-upnpclass>
          <mimetype-contenttype>
            <treat mimetype="audio/mpeg" as="mp3"/>
            <treat mimetype="image/jpeg" as="jpg"/>
            <treat mimetype="video/x-msvideo" as="avi"/>
            <treat mimetype="video/mp4" as="mp4"/>
          </mimetype-contenttype>
        </mappings>
      </import>
      <transcoding enabled="no">
        <mimetype-profile-mappings>
          <transcode mimetype="video/x-flv" using="vlcmpeg"/>
          <transcode mimetype="application/ogg" using="vlcmpeg"/>
          <transcode mimetype="application/ogg" using="oggflac2raw"/>
          <transcode mimetype="audio/x-flac" using="oggflac2raw"/>
        </mimetype-profile-mappings>
        <profiles>
          <profile name="oggflac2raw" enabled="no" type="external">
            <mimetype>audio/L16</mimetype>
            <accept-url>no</accept-url>
            <first-resource>yes</first-resource>
            <accept-ogg-theora>no</accept-ogg-theora>
            <agent command="ogg123" arguments="-d raw -f %out %in"/>
            <buffer size="1048576" chunk-size="131072" fill-size="262144"/>
          </profile>
          <profile name="vlcmpeg" enabled="no" type="external">
            <mimetype>video/mpeg</mimetype>
            <accept-url>yes</accept-url>
            <first-resource>yes</first-resource>
            <accept-ogg-theora>yes</accept-ogg-theora>
            <agent command="vlc" arguments="-I dummy %in --sout #transcode{venc=ffmpeg,vcodec=mp2v,vb=4096,fps=25,aenc=ffmpeg,acodec=mpga,ab=192,samplerate=44100,channels=2}:standard{access=file,mux=ps,dst=%out} vlc:quit"/>
            <buffer size="14400000" chunk-size="512000" fill-size="120000"/>
          </profile>
        </profiles>
      </transcoding>
    </config>
    

    Packages in use are:

    libmp4v2-dev - 2:1.9.1-0.1
    libmagic-dev - 5.04-5
    libtag1-dev - 1.6.3-1
    libsqlite3-dev - 3.7.3-1

    I don't suppose you can see anything that stands out that means that libmp4v2 isn't grabbing the metadata can you?

     
  • cojms1
    cojms1
    2011-04-14

    Ok, I now get libmp4v2 reading the tags (I was pointing to the wrong executable in the init script).
    Debug logs now show the

    DEBUG: [../src/metadata/libmp4v2_handler.cc:129] addMetaField(): mp4 handler: setting metadata on item:
    

    lines but don't seem to find any album art.  The art has been added using the mp4art command line tool.  mp4info sees the art.

    mp4info version 1.9.1
    /test.mp4:
    Track   Type    Info
    1       video   H264 High@3, 7076.513 secs, 1097 kbps, 720x432 @ 25.000025 fps
    2       audio   ac-3, 7076.512 secs, 448 kbps, 48000 Hz
    3       text
     Name: Test
     Encoded with: HandBrake 0.9.5 2011010300
     Genre: Test
     Cover Art pieces: 1
    

    but my insert line does not show any lines with

    rct=aa
    

    Any ideas?  I'm not at the PS3 at the moment so can't test anything but am assuming that without that part the art won't be parsed along with the file.

     
  • Nigel Gilbert
    Nigel Gilbert
    2011-04-15

    The config file in your previous post looked good to me.

    Here is a patch to add more debugging to the reading mp4 metadata part of the code. Save it somewhere like src/metadata/libmp4v2_handler.add_debug.patch

    --- libmp4v2_handler.cc.bkp 2011-04-15 20:39:13.000000000 +0100
    +++ libmp4v2_handler.cc 2011-04-15 20:52:45.000000000 +0100
    @@ -193,6 +193,7 @@
             u_int8_t *art_data;
             u_int32_t art_data_len;
             String art_mimetype;
    +        log_debug("mp4 handler: looking for cover art\n");
     #ifdef HAVE_MP4_GET_METADATA_COVER_ART_COUNT
             if (MP4GetMetadataCoverArtCount(mp4) && 
                 MP4GetMetadataCoverArt(mp4, &art_data, &art_data_len))
    @@ -200,14 +201,21 @@
                 MP4GetMetadataCoverArt(mp4, &art_data, &art_data_len);
     #endif
             {
    +            log_debug("mp4 handler: checking for cover art data\n");
    +
                 if (art_data)
                 {
                     try
                     {
                         art_mimetype = ContentManager::getInstance()->getMimeTypeFromBuffer((void *)art_data, art_data_len);
                         if (!string_ok(art_mimetype))
    +                    {
    +                        log_debug("mp4 handler: cover art mime type unspecified,, unable to use\n");
                             art_mimetype = _(MIMETYPE_DEFAULT);
    +                    }
    
    +                    Ref<StringConverter> sc = StringConverter::i2i();
    +                    log_debug("mp4 handler: found cover art, mime type=%s\n", sc->convert(art_mimetype).c_str());
                     }
                     catch (Exception ex)
                     {
    @@ -218,10 +226,17 @@
                     free(art_data);
                     if (art_mimetype != _(MIMETYPE_DEFAULT))
                     {
    +                    log_debug("mp4 handler: adding cover art resource\n");
    +
                         Ref<CdsResource> resource(new CdsResource(CH_MP4));
                         resource->addAttribute(MetadataHandler::getResAttrName(R_PROTOCOLINFO), renderProtocolInfo(art_mimetype));
                         resource->addParameter(_(RESOURCE_CONTENT_TYPE), _(ID3_ALBUM_ART));
                         item->addResource(resource);
    +                    log_debug("mp4 handler: cover art added\n");
    +                }
    +                else
    +                {
    +                    log_debug("mp4 handler: unable to use cover art\n");
                     }
                 }
             }
    

    Then cd into src/metadata and type:

    patch < libmp4v2_handler.add_debug.patch
    

    Rebuild, rerun (with debugging), then remove and re-add the file that you expect should have cover art.
    The debug log shows some stuff about 'cover art' just after the 'setting metadata on item' bits from before. Ideally, you should get the line 'cover art added'. If that doesn't happen, then let me know what you do get. It should tell you the mime-type of the cover art. Mine works with 'image/jpeg'.

    You could sanity-check you can extract the thumbnail with mp4art and checked it's mime type:

    mkdir tmp
    mp4art the_file.mp4 tmp/the_file
    # Check the mime-type of the extracted file
    file -i tmp/the_file.*
    

    Let me know how it goes,
      -Norbini

     
  • cojms1
    cojms1
    2011-04-16

    All patched and tested now.  Results as follows: -

    2011-04-16 09:33:49   DEBUG: [../src/metadata/libmp4v2_handler.cc:129] addMetaField(): mp4 handler: setting metadata on item: 0, Test
    2011-04-16 09:33:49   DEBUG: [../src/metadata/libmp4v2_handler.cc:129] addMetaField(): mp4 handler: setting metadata on item: 4, Test
    2011-04-16 09:33:49   DEBUG: [../src/metadata/libmp4v2_handler.cc:196] fillMetadata(): mp4 handler: looking for cover art
    2011-04-16 09:33:49   DEBUG: [../src/metadata/libmp4v2_handler.cc:204] fillMetadata(): mp4 handler: checking for cover art data
    2011-04-16 09:33:49   DEBUG: [../src/metadata/libmp4v2_handler.cc:213] fillMetadata(): mp4 handler: cover art mime type unspecified,, unable to use
    2011-04-16 09:33:49   DEBUG: [../src/metadata/libmp4v2_handler.cc:218] fillMetadata(): mp4 handler: found cover art, mime type=application/octet-stream
    2011-04-16 09:33:49   DEBUG: [../src/metadata/libmp4v2_handler.cc:239] fillMetadata(): mp4 handler: unable to use cover art
    

    So it looks from this as though the mimetype cannot be found correctly.

    mp4art shows the following: -

    IDX     BYTES  CRC32     TYPE       FILE
    ----------------------------------------------------------------------
      0     19285  1d6dd7b1  jpeg       /Films/Crime/Test.mp4
    

    file -i shows: -

    /Films/Crime/Test.art[0].jpg: image/jpeg; charset=binary
    

    Interestingly I did spot the following whilst rebuilding…

     
  • Nigel Gilbert
    Nigel Gilbert
    2011-04-17

    It looks like, due to a quirk with how libmagic is used by mediatomb, if you have: ignore-unknown="yes" set on the extension-mimetype tag in the config file, it will not look up the mime-type of the cover art and will always fail to use it.

    Try setting your config to:

    <extension-mimetype ignore-unknown="no">
    

    and run through the procedure from before. Hopefully, you'll get the magic log message 'cover art added' this time! :-)

    The deprecation warnings you get with MP4GetMetadataCoverArt() and MP4GetMetadataCoverArtCount() is because you have the newest version of libmp4v2 (1.9.1), I am only using 1.6 and these haven't been deprecated yet. It might become an issue if they remove these functions in a later release of the library, but I think that's it's ok for the moment.

    Hope this helps,
      -Norbini

     
  • Manu
    Manu
    2011-04-17

    You may try to remove the warnings with :

    void LibMP4V2Handler::fillMetadata(Ref<CdsItem> item)
    {
        // the location has already been checked by the setMetadata function
        MP4FileHandle mp4 = MP4Read(item->getLocation().c_str(), 0); 
        if (mp4 == MP4_INVALID_FILE_HANDLE)
        {
            log_error("Skipping metadata extraction for file %s\n", 
                      item->getLocation().c_str());
            return;
        }
        /* allocate */
        const MP4Tags* tags = MP4TagsAlloc();
    
        /* fetch data from MP4 file and populate structure */
        MP4TagsFetch( tags, mp4 );
    
        try
        {
            for (int i = 0; i < M_MAX; i++)
                addMetaField((metadata_fields_t) i, tags, item);
         //   Ref<ConfigManager> cm = ConfigManager::getInstance();
            //  MP4GetTimeScale returns the time scale in units of ticks per 
            //  second for the mp4 file. Caveat: tracks may use the same time 
            //  scale as  the  movie or may use their own time scale.
            u_int32_t timescale = MP4GetTimeScale(mp4);
            //  MP4GetDuration  returns the maximum duration of all the tracks in 
            //  the specified mp4 file.
            //
            //  Caveat: the duration is the movie (file) time scale units.
            MP4Duration duration = MP4GetDuration(mp4);
            duration = duration / timescale;
            if (duration > 0)
                item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_DURATION),
                        secondsToHMS(duration));
            MP4TrackId tid = MP4FindTrackId(mp4, 0, MP4_AUDIO_TRACK_TYPE);
            if (tid != MP4_INVALID_TRACK_ID)
            {
    #ifdef HAVE_MP4_GET_TRACK_AUDIO_CHANNELS
                int temp = MP4GetTrackAudioChannels(mp4, tid);
                if (temp > 0)
                {
                    item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_NRAUDIOCHANNELS), String::from(temp));
                    timescale =  MP4GetTrackTimeScale(mp4, tid);
                    if (timescale > 0)
                        item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_SAMPLEFREQUENCY), String::from((unsigned int)timescale));
                }
    #endif
                // note: UPnP requres bytes/second
                timescale = MP4GetTrackBitRate(mp4, tid);
                if (timescale > 0)
                {
                    timescale = timescale / 8;
                    item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_BITRATE), String::from(timescale));
                }
            }
    #if defined(HAVE_MAGIC)
            String art_mimetype;
            const MP4TagArtwork* art = tags->artwork;
    #ifdef HAVE_MP4_GET_METADATA_COVER_ART_COUNT
            if ( tags->artworkCount )
    #endif
            {
                if (art->data)
                {
                    try
                    {
                            art_mimetype = ContentManager::getInstance()->getMimeTypeFromBuffer((void *)art->data, art->size);
                            if (!string_ok(art_mimetype))
                                    art_mimetype = _(MIMETYPE_DEFAULT);
                    }
                    catch (Exception ex)
                    {
                            MP4TagsFree( tags );
                    MP4Close(mp4);
                            throw ex;
                    }
                    if (art_mimetype != _(MIMETYPE_DEFAULT))
                    {
                        Ref<CdsResource> resource(new CdsResource(CH_MP4));
                        resource->addAttribute(MetadataHandler::getResAttrName(R_PROTOCOLINFO), renderProtocolInfo(art_mimetype));
                        resource->addParameter(_(RESOURCE_CONTENT_TYPE), _(ID3_ALBUM_ART));
                        item->addResource(resource);
                    }
                }
            }
    #endif
            MP4TagsFree( tags );    
            MP4Close(mp4);
        }
        catch (Exception ex)
        {
        MP4TagsFree( tags );
            MP4Close(mp4);
            throw ex;
        }
    }
    

    Emmanuel

     
  • cojms1
    cojms1
    2011-04-19

    @norbini - thanks heaps.  All seems to be working now.

    @emmanuelr1 - everything is working despite the warnings so I'm happy to keep as is for now.  thanks for the code mind you.

     
  • Nigel Gilbert
    Nigel Gilbert
    2011-04-19

    Hi cojms1,

      No problem. Glad it's working now. Happy mediatombing!

      -Norbini

     
  • paddler247
    paddler247
    2011-11-14

    Hello,

    here is a patch which provides folder cover art support. The code is looking for each music track if there is a file named 'folder.jpg' or 'cover.jpg' in the same directory. This is then used as albumArtURI for albums and music tracks. If both folder.jpg and cover.jpg are present it takes folder.jpg, allowing you to put that to a lower size than cover.jpg.

    diff -uNr src_orig/storage/sql_storage.cc src/storage/sql_storage.cc
    --- src_orig/storage/sql_storage.cc     2010-03-25 16:28:10.000000000 +0100
    +++ src/storage/sql_storage.cc  2011-11-11 05:08:46.000000000 +0100
    @@ -1301,6 +1301,40 @@
         return buf->toString(1);
     }
    
    +String SQLStorage::findFolderImage(int id)
    +{
    +    Ref<StringBuffer> q(new StringBuffer());
    +    // folder.jpg or cover.jpg
    +    *q << "SELECT " << TQ("id") << " FROM " << TQ(CDS_OBJECT_TABLE) << " WHERE ";
    +    *q << "( " << TQ("dc_title") << '=' << TQ("folder.jpg") << " OR ";
    +    *q << TQ("dc_title") << '=' << TQ("cover.jpg") << " ) AND ";
    +    *q << TQ("upnp_class") << '=' << TQ(UPNP_DEFAULT_CLASS_IMAGE_ITEM) << " AND ";
    +    *q << TQ("parent_id") << " IN ";
    +    *q << "(";
    +    *q << "SELECT " << TQ("parent_id") << " FROM " << TQ(CDS_OBJECT_TABLE) << " WHERE ";
    +    *q << TQ("upnp_class") << '=' << TQ(UPNP_DEFAULT_CLASS_MUSIC_TRACK) << " AND ";
    +    *q << TQ("id") << " IN ";
    +    *q << "(";
    +    *q << "SELECT " << TQ("ref_id") << " FROM " << TQ(CDS_OBJECT_TABLE) << " WHERE ";
    +    *q << TQ("parent_id") << '=' << TQ(String::from(id)) << " AND ";
    +    *q << TQ("object_type") << '=' << TQ(OBJECT_TYPE_ITEM);
    +    *q << ")";
    +    *q << ")";
    +    *q << " ORDER BY " << TQ("dc_title") << " DESC";
    +
    +    log_debug("findFolderImage %d, %s\n", id, q->c_str());
    +    Ref<SQLResult> res = select(q);
    +    if (res == nil)
    +        throw _Exception(_("db error"));
    +    Ref<SQLRow> row;
    +    if ((row = res->nextRow()) != nil)  // we only care about the first result
    +    {
    +        log_debug("findFolderImage result: %s\n", row->col(0).c_str());
    +        return row->col(0);
    +    }
    +    return nil;
    +}
    +
     /*
     Ref<Array<CdsObject> > SQLStorage::selectObjects(Ref<SelectParam> param)
     {
    diff -uNr src_orig/storage/sql_storage.h src/storage/sql_storage.h
    --- src_orig/storage/sql_storage.h      2010-03-25 15:58:06.000000000 +0100
    +++ src/storage/sql_storage.h   2011-11-11 05:07:47.000000000 +0100
    @@ -107,6 +107,8 @@
         
         virtual zmm::Ref<CdsObject> loadObjectByServiceID(zmm::String serviceID);
         virtual zmm::Ref<zmm::IntArray> getServiceObjectIDs(char servicePrefix);
    +
    +    virtual zmm::String findFolderImage(int id);
         
         /* accounting methods */
         virtual int getTotalFiles();
    diff -uNr src_orig/storage.h src/storage.h
    --- src_orig/storage.h  2010-03-25 15:58:11.000000000 +0100
    +++ src/storage.h       2011-11-11 05:04:59.000000000 +0100
    @@ -165,6 +165,9 @@
         /* utility methods */
         virtual zmm::Ref<CdsObject> loadObject(int objectID) = 0;
         virtual int getChildCount(int contId, bool containers = true, bool items = true, bool hideFsRoot = false) = 0;
    +
    +    virtual zmm::String findFolderImage(int id) = 0;
    +
         
         class ChangedContainers : public Object
         {
    diff -uNr src_orig/upnp_xml.cc src/upnp_xml.cc
    --- src_orig/upnp_xml.cc        2010-03-25 15:58:11.000000000 +0100
    +++ src/upnp_xml.cc     2011-11-14 13:40:08.000000000 +0100
    @@ -39,6 +39,8 @@
     #include "common.h"
     #include "config_manager.h"
     #include "metadata_handler.h"
    +#include "storage.h"
    +#include "dictionary.h"
    
     using namespace zmm;
     using namespace mxml;
    @@ -115,6 +117,27 @@
             
             CdsResourceManager::addResources(item, result);
             
    +        if (upnp_class == UPNP_DEFAULT_CLASS_MUSIC_TRACK)
    +        {
    +          Ref<Storage> storage = Storage::getInstance();
    +          String aa_id = storage->findFolderImage(item->getParentID());
    +          if (aa_id != nil)
    +          {
    +             String url;
    +             Ref<Dictionary> dict(new Dictionary());
    +             dict->put(_(URL_OBJECT_ID), aa_id);
    +
    +             url = Server::getInstance()->getVirtualURL() +
    +                       _(_URL_PARAM_SEPARATOR) +
    +                       CONTENT_MEDIA_HANDLER + _(_URL_PARAM_SEPARATOR) +
    +                       dict->encodeSimple() + _(_URL_PARAM_SEPARATOR) +
    +                       _(URL_RESOURCE_ID) + _(_URL_PARAM_SEPARATOR) + "0";
    +             log_debug("UpnpXML_DIDLRenderObject: url: %s\n", url.c_str());
    +             Ref<Element> aa(new Element(MetadataHandler::getMetaFieldName(M_ALBUMARTURI)));
    +             aa->setText(url);
    +             result->appendElementChild(aa);
    +          }
    +        }
             result->setName(_("item"));
         }
         else if (IS_CDS_CONTAINER(objectType))
    @@ -125,9 +148,31 @@
             int childCount = cont->getChildCount();
             if (childCount >= 0)
                 result->setAttribute(_("childCount"), String::from(childCount));
    -        
    +
    +        String upnp_class = obj->getClass();
    +        if (upnp_class == UPNP_DEFAULT_CLASS_MUSIC_ALBUM)
    +        {
    +          Ref<Storage> storage = Storage::getInstance();
    +          String aa_id = storage->findFolderImage(cont->getID());
    +          if (aa_id != nil)
    +          {
    +             String url;
    +             Ref<Dictionary> dict(new Dictionary());
    +             dict->put(_(URL_OBJECT_ID), aa_id);
    +
    +             url = Server::getInstance()->getVirtualURL() +
    +                       _(_URL_PARAM_SEPARATOR) +
    +                       CONTENT_MEDIA_HANDLER + _(_URL_PARAM_SEPARATOR) +
    +                       dict->encodeSimple() + _(_URL_PARAM_SEPARATOR) +
    +                       _(URL_RESOURCE_ID) + _(_URL_PARAM_SEPARATOR) + "0";
    +             log_debug("UpnpXML_DIDLRenderObject: url: %s\n", url.c_str());
    +             Ref<Element> aa(new Element(MetadataHandler::getMetaFieldName(M_ALBUMARTURI)));
    +             aa->setText(url);
    +             result->appendElementChild(aa);
    +          }
    +        }
         }
    -    
    +
         if (renderActions && IS_CDS_ACTIVE_ITEM(objectType))
         {
             Ref<CdsActiveItem> aitem = RefCast(obj, CdsActiveItem);
    

    I don't have a chance to do much testing, all I can tell is that it works fine for me. For some upnp clients album art should not be larger than 600x600.

    Any feedback appreciated!

    Paddler

     
  • Peter Asplund
    Peter Asplund
    2011-11-14

    Cool! I hope this gets pulled/merged into the next release. I'm sorry I don't have the possibility of testing it for you.

     
  • blueicehaller
    blueicehaller
    2013-08-13

    Hello,
    I have added Album Art to my MP3s with the Software Mp3tag (http://mp3tag.de/en/index.html).
    I was wondering that neither WMP, VLC nor foobar2000 shows the pictures.
    If I use foobar2000 UPnP Media Server I can see the pictures with WMP, with VLC I can't see them.

    Here is the compile info (not from me) (I don't understand the code highlighting on SF):
    ./configure --build=mipsel-oe-linux --host=mipsel-oe-linux --prefix=/usr --enable-iconv-lib -
    -disable-ffmpeg --disable-debug-log

    CONFIGURATION SUMMARY ----

    sqlite3 : yes
    mysql : yes
    libjs : missing
    libmagic : yes
    inotify : yes
    libexif : yes
    id3lib : yes
    taglib : yes
    libmp4v2 : yes
    ffmpeg : disabled
    ffmpegthumbnailer : missing
    lastfmlib : yes
    external transcoding : yes
    curl : yes
    YouTube : yes
    libextractor :
    db-autocreate : yes

    And here is the output on shell:
    root@dm7025:~# mediatomb

    MediaTomb UPnP Server version 0.12.1 - http://mediatomb.cc/

    ===============================================================================
    Copyright 2005-2010 Gena Batsyan, Sergey Bostandzhyan, Leonhard Wimmer.
    MediaTomb is free software, covered by the GNU General Public License version 2

    2013-08-13 13:58:36 INFO: Loading configuration from: /home/root/.mediatomb/config.xml
    2013-08-13 13:58:36 INFO: Checking configuration...
    2013-08-13 13:58:36 INFO: Setting filesystem import charset to UTF-8
    2013-08-13 13:58:36 INFO: Setting metadata import charset to ISO-8859-1
    2013-08-13 13:58:36 INFO: Setting playlist charset to UTF-8
    2013-08-13 13:58:36 INFO: Configuration check succeeded.
    2013-08-13 13:58:36 INFO: Initialized port: 49153
    2013-08-13 13:58:36 INFO: Server bound to: 192.168.123.8
    2013-08-13 13:58:36 INFO: Adding HTTP header "transferMode.dlna.org: Streaming"
    2013-08-13 13:58:36 INFO: Adding HTTP header "contentFeatures.dlna.org: DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"
    2013-08-13 13:58:38 INFO: MediaTomb Web UI can be reached by following this link:
    2013-08-13 13:58:38 INFO: http://192.168.123.8:49153/
    2013-08-13 13:58:41 INFO: MediaTomb shutting down. Please wait...
    2013-08-13 13:58:42 INFO: Server terminating

    The configuration and debug log is in the attachement.

     
    Last edit: blueicehaller 2013-08-13