mmappcomponents/harvester/metadataextractor/src/mpxmetadataextractor.cpp
changeset 0 a2952bb97e68
child 8 bee149131e4b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmappcomponents/harvester/metadataextractor/src/mpxmetadataextractor.cpp	Thu Dec 17 08:55:47 2009 +0200
@@ -0,0 +1,828 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Extracts metadata from a file
+*  Version     : %version: da1mmcf#38.1.4.2.6.1.5 % << Don't touch! Updated by Synergy at check-out.
+*
+*/
+
+
+#include <e32base.h>
+#include <badesca.h>
+#include <apgcli.h>
+#include <MetaDataUtility.h>
+#include <MetaDataFieldContainer.h>
+
+#ifdef RD_MPX_TNM_INTEGRATION
+#include <hash.h>
+#include <f32file.h>
+#include <sysutil.h>
+#include <thumbnailmanager.h>
+#endif //RD_MPX_TNM_INTEGRATION
+
+
+#include <mpxlog.h>
+#include <mpxmedia.h>
+#include <mpxcollectionpath.h>
+#include <mpxcollectiontype.h>
+#include <mpxdrmmediautility.h>
+
+#include <mpxmediamusicdefs.h>
+#include <mpxmediageneraldefs.h>
+#include <mpxmediaaudiodefs.h>
+#include <mpxmediadrmdefs.h>
+#include <mpxmediamtpdefs.h>
+
+#include "mpxmetadataextractor.h"
+#include "mpxfileinfoutility.h"
+#ifdef RD_MPX_TNM_INTEGRATION
+_LIT( KImageFileType, "image/jpeg" );
+const TInt KMPXTimeoutTimer = 3000000; // 3 seconds
+const TInt KMPXMaxThumbnailRequest = 5; 
+#endif //RD_MPX_TNM_INTEGRATION
+
+//Helper functions
+static void FindAndReplaceForbiddenChars(TDes& aString, TInt aLen)
+    {
+    MPX_ASSERT(aLen == aString.Length());
+
+    for (TInt i = 0; i < aLen; ++i)
+        {
+        if (aString[i] == TText('\t'))
+            {
+            aString[i] = TText(' ');
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------
+//
+CMPXMetadataExtractor::CMPXMetadataExtractor(
+                                  RFs& aFs,
+                                  RApaLsSession& aAppArc,
+                                  RPointerArray<CMPXCollectionType>& aTypes  )
+                                  : iFs( aFs ),
+                                    iAppArc( aAppArc ),
+                                    iSupportedTypes( aTypes ),
+                                    iOutstandingThumbnailRequest(0),
+                                    iTNMBlockCount(0)
+    {
+
+    }
+
+
+// ---------------------------------------------------------------------------
+// 2nd Phase Constructor
+// ---------------------------------------------------------------------------
+//
+void CMPXMetadataExtractor::ConstructL()
+    {
+    iMetadataUtility = CMetaDataUtility::NewL();
+    iDrmMediaUtility = CMPXDrmMediaUtility::NewL();
+    iFileInfoUtil    = CMPXFileInfoUtility::NewL();
+
+#ifdef RD_MPX_TNM_INTEGRATION
+    // Create Thumbnail Manager instance. This object is the observer.
+    iTNManager = CThumbnailManager::NewL( *this );
+    iTNManager->SetFlagsL( CThumbnailManager::EDefaultFlags );
+    iTNManager->SetQualityPreferenceL( CThumbnailManager::EOptimizeForQuality);
+    // create wait loop
+    iTNSyncWait = new (ELeave) CActiveSchedulerWait;
+    iTimer = CPeriodic::NewL( CActive::EPriorityIdle );
+#endif //RD_MPX_TNM_INTEGRATION
+    }
+
+// ---------------------------------------------------------------------------
+// Two-Phased Constructor
+// ---------------------------------------------------------------------------
+//
+EXPORT_C CMPXMetadataExtractor* CMPXMetadataExtractor::NewL(
+                                  RFs& aFs,
+                                  RApaLsSession& aAppArc,
+                                  RPointerArray<CMPXCollectionType>& aTypes  )
+    {
+    CMPXMetadataExtractor* self = new( ELeave ) CMPXMetadataExtractor( aFs,
+                                                                       aAppArc,
+                                                                       aTypes );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CMPXMetadataExtractor::~CMPXMetadataExtractor()
+    {
+    delete iMetadataUtility;
+    delete iFileInfoUtil;
+    delete iDrmMediaUtility;
+#ifdef RD_MPX_TNM_INTEGRATION
+    delete iTNManager;
+    if (iTNSyncWait && iTNSyncWait->IsStarted() )
+        {
+        iTNSyncWait->AsyncStop();
+        }
+    delete iTNSyncWait;
+    delete iTimer;
+#endif //RD_MPX_TNM_INTEGRATION
+    
+    MPX_DEBUG2("CMPXMetadataExtractor: TNM Block Count: %d ", iTNMBlockCount );
+    }
+
+// ---------------------------------------------------------------------------
+// Constructs a media properties object
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CMPXMetadataExtractor::CreateMediaL( const TDesC& aFile,
+                                                   CMPXMedia*& aNewProperty,
+                                                   TBool aMetadataOnly )
+    {
+    // make a copy of aFile
+    HBufC* fileName = HBufC::NewL(KMaxFileName);
+    CleanupStack::PushL( fileName );
+    fileName->Des().Append( aFile );
+    MPX_DEBUG2("CMPXMetadataExtractor::CreateMediaL %S <---", fileName );
+
+    RArray<TInt> contentIDs;
+    contentIDs.AppendL( KMPXMediaIdGeneral );
+    contentIDs.AppendL( KMPXMediaIdAudio );
+    contentIDs.AppendL( KMPXMediaIdMusic );
+    contentIDs.AppendL( KMPXMediaIdDrm );
+    contentIDs.AppendL( KMPXMediaIdMTP );
+    aNewProperty = NULL;
+    CMPXMedia* media = CMPXMedia::NewL( contentIDs.Array() );
+    CleanupStack::PushL( media );
+    contentIDs.Close();
+
+    // CMPXMedia default types
+
+    media->SetTObjectValueL<TMPXGeneralType>( KMPXMediaGeneralType,
+                                              EMPXItem );
+    media->SetTObjectValueL<TMPXGeneralCategory>( KMPXMediaGeneralCategory,
+                                                  EMPXSong );
+
+    TParsePtrC parse( *fileName );
+
+    // Title, default is file name
+    media->SetTextValueL( KMPXMediaGeneralTitle,
+                          parse.Name() );
+
+    // Default album track
+    media->SetTextValueL( KMPXMediaMusicAlbumTrack,
+                          KNullDesC );
+
+    // Set the Mime Type and collection UID
+    //
+    if( !aMetadataOnly )
+        {
+        TInt index(KErrNotFound);
+        TInt count( iSupportedTypes.Count() );
+        for (TInt i=0; i <count; ++i)
+            {
+            TInt index2(KErrNotFound);
+            const CDesCArray& exts = iSupportedTypes[i]->Extensions();
+            const TDesC& ext = parse.Ext();
+            if (!exts.FindIsq(ext, index2))
+                { // found
+                index = i;
+                break;
+                }
+            }
+        if( KErrNotFound != index )
+            {
+            MPX_DEBUG1("CMPXMetadataExtractor::CreateMediaPropertiesL apparc <---" );
+            TInt mimeIndex = SupportedContainerTypeL( *fileName, index );
+            User::LeaveIfError( mimeIndex );
+            MPX_DEBUG1("CMPXMetadataExtractor::CreateMediaPropertiesL apparc --->" );
+
+            media->SetTextValueL( KMPXMediaGeneralMimeType,
+                                  iSupportedTypes[index]->Mimetypes()[mimeIndex] );
+
+            media->SetTObjectValueL( KMPXMediaGeneralCollectionId,
+                                     iSupportedTypes[index]->Uid() );
+            }
+        else
+            {
+            User::Leave(KErrNotSupported);
+            }
+        }
+    else // other case use apparc to fetch and set mimetype
+        {
+        TDataType dataType;
+        TUid dummyUid(KNullUid);
+        iAppArc.AppForDocument(*fileName, dummyUid, dataType);
+        media->SetTextValueL( KMPXMediaGeneralMimeType,dataType.Des() );
+        }
+        
+    // Use file handle here
+    //
+    RFile file;
+    TInt err = file.Open( iFs, *fileName, EFileRead | EFileShareReadersOrWriters );
+    CleanupClosePushL(file);
+    
+    // Metadata related
+    //
+    if( err == KErrNone )
+        {
+        const TDesC& mimeType = media->ValueText( KMPXMediaGeneralMimeType );
+        HBufC8* mimeType8 = HBufC8::NewLC( mimeType.Length() );
+        mimeType8->Des().Append( mimeType );
+        TRAPD( metadataerror, iMetadataUtility->OpenFileL( file, *mimeType8 ) );
+        CleanupStack::PopAndDestroy( mimeType8 );
+
+        // No problem
+        if( KErrNone == metadataerror )
+            {
+            // Add TRAPD to capture exception KErrNoMemory.
+            //If album art size is too large, trap this exception and SetDefaultL.
+            //Fix EYLU-7ESE5L
+            TRAPD( err, SetMediaPropertiesL( *media, *fileName ) );
+            if ( KErrNoMemory == err )
+                {
+                SetDefaultL( *media );
+                }
+            }
+        else  // Error, Set defaults
+            {
+            SetDefaultL( *media );
+            }
+
+        // Reset the utility
+        iMetadataUtility->ResetL();
+        }
+    else // Error, Set defaults
+        {
+        SetDefaultL( *media );
+        }
+    
+    // Common properties that we can extract
+    //
+    SetExtMediaPropertiesL( *media, *fileName, aMetadataOnly, file, err );
+    CleanupStack::PopAndDestroy(&file);
+
+    // Set the pointers now that the object is ready
+    //
+    CleanupStack::Pop( media );
+    aNewProperty = media;
+
+    CleanupStack::PopAndDestroy( fileName );
+    MPX_DEBUG1("CMPXMetadataExtractor::CreateMediaPropertiesL --->");
+    }
+
+// ---------------------------------------------------------------------------
+// Sets all of the default media properties
+// ---------------------------------------------------------------------------
+//
+void CMPXMetadataExtractor::SetDefaultL( CMPXMedia& aMediaProp )
+    {
+    // Comment
+    aMediaProp.SetTextValueL( KMPXMediaGeneralComment,
+                              KNullDesC );
+    // Artist
+    aMediaProp.SetTextValueL( KMPXMediaMusicArtist,
+                              KNullDesC );
+    // Album
+    aMediaProp.SetTextValueL( KMPXMediaMusicAlbum,
+                              KNullDesC );
+    // Year
+    aMediaProp.SetTObjectValueL<TInt64>( KMPXMediaMusicYear,
+                                         (TInt64) 0 );
+    // Track
+    aMediaProp.SetTextValueL( KMPXMediaMusicAlbumTrack,
+                              KNullDesC );
+    // Genre
+    aMediaProp.SetTextValueL( KMPXMediaMusicGenre,
+                              KNullDesC );
+    // Composer
+    aMediaProp.SetTextValueL( KMPXMediaMusicComposer,
+                              KNullDesC );
+    // Album artFilename
+    aMediaProp.SetTextValueL( KMPXMediaMusicAlbumArtFileName,
+                              KNullDesC );
+    // URL
+    aMediaProp.SetTextValueL( KMPXMediaMusicURL,
+                              KNullDesC );
+    }
+
+// ---------------------------------------------------------------------------
+// Sets media object attributes from metadata utilities
+// ---------------------------------------------------------------------------
+//
+void CMPXMetadataExtractor::SetMediaPropertiesL( CMPXMedia& aMedia,
+                                                 const TDesC& aFile )
+    {
+    MPX_DEBUG1("CMPXMetadataExtractor::SetMediaPropertiesL <---" );
+
+    const CMetaDataFieldContainer& metaCont =
+                                          iMetadataUtility->MetaDataFieldsL();
+    TInt count( metaCont.Count() );
+    for( TInt i=0; i<count; ++i )
+        {
+        TMetaDataFieldId fieldType;
+
+        HBufC* value = NULL;
+        TRAPD( err, value = metaCont.At( i, fieldType ).AllocL() );
+        CleanupStack::PushL(value);
+        if ( KErrNone != err )
+        {
+            CleanupStack::PopAndDestroy(value);
+            continue;
+        }
+
+        switch( fieldType )
+            {
+            case EMetaDataSongTitle:
+                {
+                TPtr valptr = value->Des();
+                valptr.Trim();
+                TInt vallen = value->Length();
+                if (vallen>0)
+                    {
+                    FindAndReplaceForbiddenChars(valptr, vallen);
+                    aMedia.SetTextValueL(KMPXMediaGeneralTitle, *value);
+                    }
+                break;
+                }
+            case EMetaDataArtist:
+                {
+                TPtr valptr = value->Des();
+                valptr.Trim();
+                TInt vallen = value->Length();
+                if (vallen>0)
+                    {
+                    FindAndReplaceForbiddenChars(valptr, vallen);
+                    aMedia.SetTextValueL(KMPXMediaMusicArtist, *value);
+                    }
+                break;
+                }
+            case EMetaDataAlbum:
+                {
+                TPtr valptr = value->Des();
+                valptr.Trim();
+                TInt vallen = value->Length();
+                if (vallen>0)
+                    {
+                    FindAndReplaceForbiddenChars(valptr, vallen);
+                    aMedia.SetTextValueL(KMPXMediaMusicAlbum, *value );
+                    }
+                break;
+                }
+            case EMetaDataYear:
+                {
+                // Perform the date time conversion
+                TLex lexer( *value );
+                TInt year( 0 );
+                lexer.Val( year );
+
+                // Convert from TInt -> TDateTime -> TTime -> TInt64
+                TDateTime dt;
+                dt.SetYear( year );
+                TTime time( dt );
+                aMedia.SetTObjectValueL<TInt64>( KMPXMediaMusicYear,
+                                                 time.Int64() );
+                break;
+                }
+            case EMetaDataComment:
+                {
+                aMedia.SetTextValueL( KMPXMediaGeneralComment,
+                                      *value );
+                break;
+                }
+            case EMetaDataAlbumTrack:
+                {
+                aMedia.SetTextValueL( KMPXMediaMusicAlbumTrack,
+                                      *value );
+                break;
+                }
+            case EMetaDataGenre:
+                {
+                TPtr valptr = value->Des();
+                valptr.Trim();
+                TInt vallen = value->Length();
+                if (vallen>0)
+                    {
+                    FindAndReplaceForbiddenChars(valptr, vallen);
+                    aMedia.SetTextValueL(KMPXMediaMusicGenre, *value);
+                    }
+                break;
+                }
+            case EMetaDataComposer:
+                {
+                TPtr valptr = value->Des();
+                valptr.Trim();
+                TInt vallen = value->Length();
+                if (vallen>0)
+                    {
+                    FindAndReplaceForbiddenChars(valptr, vallen);
+                    aMedia.SetTextValueL(KMPXMediaMusicComposer, *value);
+                    }
+                break;
+                }
+            case EMetaDataUrl:
+            case EMetaDataUserUrl:  // fall through
+                {
+                aMedia.SetTextValueL( KMPXMediaMusicURL,
+                                      *value );
+                break;
+                }
+            case EMetaDataJpeg:
+                {
+#ifdef RD_MPX_TNM_INTEGRATION
+                MPX_PERF_START(CMPXMetadataExtractor_SetMediaPropertiesL_JPEG_TNM);
+                HBufC8* value8 = MPXUser::Alloc8L(metaCont.At( i, fieldType ));
+                CleanupStack::PushL( value8 );
+                AddMediaAlbumArtL( aMedia, aFile, *value8 );
+                CleanupStack::Pop(value8);
+                MPX_PERF_END(CMPXMetadataExtractor_SetMediaPropertiesL_JPEG_TNM);
+#else //RD_MPX_TNM_INTEGRATION
+                aMedia.SetTextValueL( KMPXMediaMusicAlbumArtFileName,
+                                      aFile );
+#endif //RD_MPX_TNM_INTEGRATION
+                break;
+                }
+            case EMetaDataCopyright:
+                {
+                aMedia.SetTextValueL( KMPXMediaGeneralCopyright,
+                                      *value );
+                break;
+                }
+            case EMetaDataOriginalArtist:  // fall through
+            case EMetaDataVendor:          // fall through
+            case EMetaDataRating:          // fall through
+            case EMetaDataUniqueFileIdentifier:  // fall through
+            case EMetaDataDuration:        // fall through
+            case EMetaDataDate:            // fall through
+                {
+                // not used
+                break;
+                }
+            default:
+                {
+                //ASSERT(0);
+                break;
+                }
+            }
+        CleanupStack::PopAndDestroy(value);
+        }
+
+    MPX_DEBUG1("CMPXMetadataExtractor::SetMediaPropertiesL --->" );
+    }
+
+// ---------------------------------------------------------------------------
+// Sets extra media properties not returned by metadata utilities
+// ---------------------------------------------------------------------------
+//
+void CMPXMetadataExtractor::SetExtMediaPropertiesL( CMPXMedia& aProp, 
+                                                    const TDesC& aFile,
+                                                    TBool aMetadataOnly,
+                                                    RFile& aFileHandle,
+                                                    TInt aFileErr )
+    {
+    MPX_DEBUG1("CMPXMetadataExtractor::SetExtMediaPropertiesL <---");
+
+    // DB Flags to set
+    //
+    TUint dbFlags(KMPXMediaGeneralFlagsSetOrUnsetBit);
+
+    // File Path
+    //
+    TParsePtrC parse( aFile );
+    aProp.SetTextValueL( KMPXMediaGeneralUri,
+                         aFile );
+    aProp.SetTextValueL( KMPXMediaGeneralDrive,
+                         parse.Drive() );
+
+    // DRM Rights
+    //
+    CMPXMedia* drm = NULL;
+    TRAPD( drmError, iDrmMediaUtility->InitL( aFile );
+                     drm = CMPXMedia::NewL( *iDrmMediaUtility->GetMediaL( KMPXMediaDrmProtected.iAttributeId |
+                                                                          KMPXMediaDrmRightsStatus.iAttributeId ) );
+         );
+
+    TBool prot(EFalse);
+    if( drm )
+        {
+        CleanupStack::PushL( drm );
+        MPX_DEBUG1("CMPXMetadataExtractor::SetExtMediaPropertiesL -- is a drm file");
+        if( drm->IsSupported( KMPXMediaDrmProtected ) )
+            {
+            prot = drm->ValueTObjectL<TBool>( KMPXMediaDrmProtected );
+            MPX_DEBUG2("CMPXMetadataExtractor::SetExtMediaPropertiesL protected %i", prot);
+            }
+
+        TMPXMediaDrmRightsStatus status(EMPXDrmRightsFull);
+        if( drm->IsSupported( KMPXMediaDrmRightsStatus ) )
+            {
+            status = drm->ValueTObjectL<TMPXMediaDrmRightsStatus>(KMPXMediaDrmRightsStatus);
+            aProp.SetTObjectValueL<TInt>(KMPXMediaDrmRightsStatus, status );
+            MPX_DEBUG2("CMPXMetadataExtractor::SetExtMediaPropertiesL -- status %i", status);
+            }
+
+        // Set DB flags
+        dbFlags |= KMPXMediaGeneralFlagsIsDrmProtected;
+        if( status != EMPXDrmRightsFull && status != EMPXDrmRightsRestricted && status != EMPXDrmRightsPreview )
+            {
+            dbFlags |= KMPXMediaGeneralFlagsIsDrmLicenceInvalid;
+            }
+        CleanupStack::PopAndDestroy( drm );
+        }
+
+    // Trapped PV DRM error. If -46, we know the file has no rights
+    //
+    if( drmError == KErrPermissionDenied )
+        {
+        dbFlags |= KMPXMediaGeneralFlagsIsDrmLicenceInvalid;
+        }
+    else
+        {
+        User::LeaveIfError( drmError );
+        }
+
+    aProp.SetTObjectValueL<TBool>( KMPXMediaDrmProtected, prot );
+    aProp.SetTObjectValueL<TUint16>( KMPXMediaMTPDrmStatus, (TUint16)prot );
+    
+    iDrmMediaUtility->Close();
+    
+    // File Size
+    //
+    TInt size( 0 );
+    if( aFileErr == KErrNone )
+        {
+        aFileHandle.Size( size );
+        aProp.SetTObjectValueL<TInt>( KMPXMediaGeneralSize,
+                                      size );
+
+        // Duration, bitrate, samplerate, etc
+        //
+        if( !aMetadataOnly )
+            {
+            TRAPD(err2, iFileInfoUtil->OpenFileL(
+                          aFileHandle, 
+                          aProp.ValueText(KMPXMediaGeneralMimeType)));
+            MPX_DEBUG2("CMPXMetadataExtractor::SetExtMediaPropertiesL, file info util error %i", err2);
+            if( KErrNone == err2 )
+                {
+                aProp.SetTObjectValueL<TUint>( KMPXMediaAudioBitrate,
+                                               iFileInfoUtil->BitRate() );
+                aProp.SetTObjectValueL<TUint>( KMPXMediaAudioSamplerate,
+                                               iFileInfoUtil->SampleRate() );
+                TInt64 duration = (TInt64) iFileInfoUtil->Duration().Int64() / 1000; // ms
+                aProp.SetTObjectValueL<TInt32>( KMPXMediaGeneralDuration,
+                                              duration );
+                MPX_DEBUG2("CMPXMetadataExtractor::SetExtMediaPropertiesL -- duration %i", duration);
+                }
+            }
+        }
+    else if( aFileErr == KErrNotFound || aFileErr == KErrPathNotFound )
+        {
+        dbFlags |= KMPXMediaGeneralFlagsIsInvalid;
+        }
+    // Finally set the db flag
+    //
+    aProp.SetTObjectValueL( KMPXMediaGeneralFlags,
+                            dbFlags );
+
+    iFileInfoUtil->Reset();
+    
+    MPX_DEBUG1("CMPXMetadataExtractor::SetExtMediaPropertiesL --->");
+    }
+
+// ---------------------------------------------------------------------------
+// Check to see if this file is a supported container
+// ---------------------------------------------------------------------------
+//
+TInt CMPXMetadataExtractor::SupportedContainerTypeL( const TDesC& aFile,
+                                                     TInt aIndex )
+    {
+    TInt index(KErrNotFound);
+
+    TDataType dataType;
+    TUid dummyUid(KNullUid);
+    iAppArc.AppForDocument(aFile, dummyUid, dataType);
+
+    TInt index2(KErrNotFound);
+    const CDesCArray& mimeTypes = iSupportedTypes[aIndex]->Mimetypes();
+    if (!mimeTypes.FindIsq(dataType.Des(), index2))
+        { // found
+        index = index2;
+        }
+
+    return ( index == KErrNotFound ? KErrNotSupported : index );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CMPXMetadataExtractor::ThumbnailPreviewReady
+// Callback but not used here
+// ---------------------------------------------------------------------------
+void CMPXMetadataExtractor::ThumbnailPreviewReady( 
+        MThumbnailData& /*aThumbnail*/, TThumbnailRequestId /*aId*/ )
+    {
+    MPX_FUNC("CMPXMetadataExtractor::ThumbnailPreviewReady()");
+    }
+        
+
+// ---------------------------------------------------------------------------
+// CMPXMetadataExtractor::ThumbnailReady
+// Callback but not used here
+// ---------------------------------------------------------------------------
+void CMPXMetadataExtractor::ThumbnailReady( TInt /*aError*/, 
+        MThumbnailData& /*aThumbnail*/, TThumbnailRequestId /*aId*/ )
+    {
+    MPX_FUNC("CMPXMetadataExtractor::ThumbnailReady()");
+    iOutstandingThumbnailRequest--;
+    if ( iOutstandingThumbnailRequest <= KMPXMaxThumbnailRequest )
+        {
+        StopWaitLoop();
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Callback for timer.
+// ----------------------------------------------------------------------------
+TInt CMPXMetadataExtractor::TimeoutTimerCallback(TAny* aPtr)
+    {
+    MPX_FUNC("CMPXMetadataExtractor::TimeoutTimerCallback()");
+
+    CMPXMetadataExtractor* ptr =
+        static_cast<CMPXMetadataExtractor*>(aPtr);
+        
+    // Timer expired before thumbnail callback occurred. Stop wait loop to unblock. 
+    ptr->StopWaitLoop();
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// Stop the wait loop.
+// ----------------------------------------------------------------------------
+void CMPXMetadataExtractor::StopWaitLoop()
+    {
+    MPX_FUNC("CMPXMetadataExtractor::StopWaitLoop()");
+    // Cancel timer
+    CancelTimeoutTimer();
+    
+    // Stop wait loop to unblock.
+    if ( iTNSyncWait->IsStarted() )
+        {
+        MPX_DEBUG1("CMPXMetadataExtractor::StopWaitLoop(): Stopping the wait loop.");
+        iTNSyncWait->AsyncStop();
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Cancel timer. 
+// ----------------------------------------------------------------------------
+void CMPXMetadataExtractor::CancelTimeoutTimer()
+    {
+    MPX_FUNC("CMPXMetadataExtractor::CancelTimeoutTimer()");
+    
+    // Cancel timer.
+    if ( iTimer && iTimer->IsActive() )
+        {
+        MPX_DEBUG1("CMPXMetadataExtractor::CancelTimeoutTimer(): Timer active, cancelling");
+        iTimer->Cancel();
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Extract album art from a file and add to thumbnail manager.
+// ----------------------------------------------------------------------------
+EXPORT_C TInt CMPXMetadataExtractor::ExtractAlbumArtL( CMPXMedia* aMedia )
+    {
+    MPX_FUNC("CMPXMetadataExtractor::ExtractAlbumArtL()");
+    TInt err = KErrNone; 
+    
+    if ( !aMedia->IsSupported(KMPXMediaGeneralUri) )
+        {
+        return KErrArgument;
+        }
+    
+    // Get full file name.
+    const TDesC& path = aMedia->ValueText(KMPXMediaGeneralUri);
+    MPX_DEBUG2("CMPXMetadataExtractor::ExtractAlbumArtL Filename:%S ", &path );
+    
+    // create wanted fields array
+    RArray<TMetaDataFieldId> wantedFields;
+    CleanupClosePushL( wantedFields );
+    wantedFields.Append(EMetaDataJpeg);
+    
+    // Open file
+    if ( aMedia->IsSupported(KMPXMediaGeneralMimeType) )
+        {
+        const TDesC& mimeType = aMedia->ValueText( KMPXMediaGeneralMimeType );
+        MPX_DEBUG2("CMPXMetadataExtractor::ExtractAlbumArtL MimeType:%S ", &mimeType );
+        HBufC8* mimeType8 = HBufC8::NewLC( mimeType.Length() );
+        mimeType8->Des().Append( mimeType );
+        TRAP( err, iMetadataUtility->OpenFileL( path, wantedFields, *mimeType8 ) );
+        CleanupStack::PopAndDestroy( mimeType8 );
+        }
+    else
+        {
+        TRAP( err, iMetadataUtility->OpenFileL( path, wantedFields ) );
+        }
+    CleanupStack::PopAndDestroy( &wantedFields );
+    
+    if ( !err )
+        {
+        TRAP( err, GetMediaAlbumArtL( *aMedia, path ));
+        }
+
+    // Reset the utility
+    iMetadataUtility->ResetL();
+    
+    return err;
+    }
+
+// ----------------------------------------------------------------------------
+// Set album art.
+// ----------------------------------------------------------------------------
+TInt CMPXMetadataExtractor::GetMediaAlbumArtL( CMPXMedia& aMedia, 
+                                               const TDesC& aFile )
+    {
+    MPX_FUNC("CMPXMetadataExtractor::GetMediaAlbumArtL()");
+    TInt err = KErrNone;
+    // get metadata container.
+    const CMetaDataFieldContainer& metaCont = iMetadataUtility->MetaDataFieldsL();
+
+    TPtrC data = metaCont.Field( EMetaDataJpeg );
+    
+    if ( data.Length() )
+        {
+        MPX_DEBUG1("CMPXMetadataExtractor::GetMediaAlbumArtL(): Album art exist.");
+#ifdef RD_MPX_TNM_INTEGRATION
+        HBufC8* value8 = MPXUser::Alloc8L( data );       
+        CleanupStack::PushL( value8 );
+        AddMediaAlbumArtL( aMedia, aFile, *value8 );
+        CleanupStack::Pop(value8);
+#else // RD_MPX_TNM_INTEGRATION
+        aMedia.SetTextValueL( KMPXMediaMusicAlbumArtFileName, aFile );
+#endif // RD_MPX_TNM_INTEGRATION          
+        }
+    else
+        {
+        err = KErrNotFound;
+        }
+    
+    return err;
+    }
+
+// ----------------------------------------------------------------------------
+// Add album art to media object.
+// ----------------------------------------------------------------------------
+void CMPXMetadataExtractor::AddMediaAlbumArtL( CMPXMedia& aMedia, 
+                                               const TDesC& aFile,
+                                               TDesC8& aValue )
+    {
+    MPX_FUNC("CMPXMetadataExtractor::AddMediaAlbumArtL()");
+#ifdef RD_MPX_TNM_INTEGRATION
+    
+    // If thumbnail creation is ongoing, wait til it is done
+    if ( iOutstandingThumbnailRequest > KMPXMaxThumbnailRequest )
+        {
+        MPX_DEBUG1("CMPXMetadataExtractor::AddMediaAlbumArtL(): Thumbnail creation ongoing!");
+        iTNMBlockCount++;
+        // Cancel timer.
+        CancelTimeoutTimer();
+        // Start timer in case there is no callback from ThumbNail Manager. 
+        iTimer->Start(
+            KMPXTimeoutTimer,
+            KMPXTimeoutTimer,
+            TCallBack(TimeoutTimerCallback, this ));
+        
+        // Start wait loop until we get a callback from ThumbNail Manager.
+        if ( !iTNSyncWait->IsStarted() )
+            {
+            iTNSyncWait->Start();
+            }
+        }
+    
+    aMedia.SetTextValueL( KMPXMediaMusicAlbumArtFileName, aFile );
+    
+    TBuf<256> mimeType;
+    mimeType.Copy( KImageFileType );
+    CThumbnailObjectSource* source = CThumbnailObjectSource::NewLC(
+        &aValue, mimeType, aFile );
+    iTNManager->CreateThumbnails( *source );
+    CleanupStack::PopAndDestroy( source );
+    aMedia.SetTextValueL( KMPXMediaMusicOriginalAlbumArtFileName, aFile );
+    iOutstandingThumbnailRequest++;
+    
+#endif // RD_MPX_TNM_INTEGRATION          
+    }