--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/harvester/harvesterplugins/VideoPlugin/src/harvestervideoplugin.cpp Mon Jan 18 20:34:07 2010 +0200
@@ -0,0 +1,1066 @@
+/*
+* Copyright (c) 2006-2009 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: Harvests meta data from video file.*
+*/
+
+
+#include <e32base.h>
+#include <e32std.h>
+#include <3gplibrary/mp4lib.h>
+#include <hxmetadatautil.h>
+#include <hxmetadatakeys.h>
+
+#include "mdsutils.h"
+#include "harvestervideoplugin.h"
+#include "harvesterlog.h"
+#include "harvesterblacklist.h"
+#include "mdeobjectwrapper.h"
+
+#include <mdenamespacedef.h>
+#include <mdeobjectdef.h>
+#include <mdepropertydef.h>
+#include <mdeobject.h>
+#include <harvesterdata.h>
+#include <mdeconstants.h>
+
+using namespace MdeConstants;
+
+_LIT( KMimeTypeVideoMp4, "video/mp4" );
+_LIT( KMimeTypeAudioMp4, "audio/mp4" );
+_LIT( KMimeTypeVideo3gpp, "video/3gpp" );
+_LIT( KMimeTypeAudio3gpp, "audio/3gpp" );
+_LIT( KMimeTypeRm, "application/vnd.rn-realmedia" ); // can be audio or video
+_LIT( KMimeTypeRmvb, "application/vnd.rn-realmedia-vbr" ); // can be audio or video
+_LIT( KMimeTypeRv, "video/vnd.rn-realvideo" );
+_LIT( KMimeTypeRa, "audio/vnd.rn-realaudio" );
+_LIT( KMimeTypeAvi, "video/avi");
+_LIT( KMimeTypeVideoMatroska, "video/x-matroska");
+_LIT( KMimeTypeAudioMatroska, "audio/x-matroska");
+
+_LIT( KExtensionMp4, "mp4" );
+_LIT( KExtensionMpg4, "mpg4" );
+_LIT( KExtensionMpeg4, "mpeg4" );
+_LIT( KExtensionM4v, "m4v" );
+_LIT( KExtensionM4a, "m4a" );
+_LIT( KExtension3gp, "3gp" );
+_LIT( KExtension3gpp, "3gpp" );
+_LIT( KExtension3g2, "3g2" );
+_LIT( KExtensionRm, "rm" );
+_LIT( KExtensionRmvb, "rmvb" );
+_LIT( KExtensionRv, "rv" );
+_LIT( KExtensionAvi, "avi" );
+_LIT( KExtensionMkv, "mkv" );
+_LIT( KExtensionRa, "ra" );
+
+_LIT(KVideo, "Video");
+_LIT(KAudio, "Audio");
+
+_LIT(KAudioAC3, "audio/AC3");
+_LIT(KAudioEAC3, "audio/EAC3");
+const TUint32 KMDSFourCCCodeAC3 = 0x33434120; //{' ', 'A', 'C', '3'}
+const TUint32 KMDSFourCCCodeEAC3 = 0x33434145; //{'E', 'A', 'C', '3'}
+
+_LIT(KInUse, "InUse");
+
+const TInt KKiloBytes = 1024;
+const TReal32 KThousandReal = 1000.0;
+
+CHarvesterVideoPluginPropertyDefs::CHarvesterVideoPluginPropertyDefs() : CBase()
+ {
+ }
+
+void CHarvesterVideoPluginPropertyDefs::ConstructL(CMdEObjectDef& aObjectDef)
+ {
+ CMdENamespaceDef& nsDef = aObjectDef.NamespaceDef();
+
+ // Common property definitions
+ CMdEObjectDef& objectDef = nsDef.GetObjectDefL( Object::KBaseObject );
+ iCreationDatePropertyDef = &objectDef.GetPropertyDefL( Object::KCreationDateProperty );
+ iLastModifiedDatePropertyDef = &objectDef.GetPropertyDefL( Object::KLastModifiedDateProperty );
+ iSizePropertyDef = &objectDef.GetPropertyDefL( Object::KSizeProperty );
+ iTimeOffsetPropertyDef = &objectDef.GetPropertyDefL( Object::KTimeOffsetProperty );
+ iItemTypePropertyDef = &objectDef.GetPropertyDefL( Object::KItemTypeProperty );
+
+ CMdEObjectDef& mediaDef = nsDef.GetObjectDefL( MediaObject::KMediaObject );
+ iReleaseDatePropertyDef = &mediaDef.GetPropertyDefL( MediaObject::KReleaseDateProperty );
+ iCaptureDatePropertyDef = &mediaDef.GetPropertyDefL( MediaObject::KCaptureDateProperty );
+ iDurationPropertyDef = &mediaDef.GetPropertyDefL( MediaObject::KDurationProperty );
+ iWidthPropertyDef = &mediaDef.GetPropertyDefL( MediaObject::KWidthProperty );
+ iHeightPropertyDef = &mediaDef.GetPropertyDefL( MediaObject::KHeightProperty );
+ iBitratePropertyDef = &mediaDef.GetPropertyDefL( MediaObject::KBitrateProperty );
+ iCopyrightPropertyDef = &mediaDef.GetPropertyDefL( MediaObject::KCopyrightProperty );
+ iAuthorPropertyDef = &mediaDef.GetPropertyDefL( MediaObject::KAuthorProperty );
+ iGenrePropertyDef = &mediaDef.GetPropertyDefL( MediaObject::KGenreProperty );
+ iArtistPropertyDef = &mediaDef.GetPropertyDefL( MediaObject::KArtistProperty );
+ iDescriptionPropertyDef = &mediaDef.GetPropertyDefL( MediaObject::KDescriptionProperty );
+
+ iAudioFourCCDef = &mediaDef.GetPropertyDefL( MediaObject::KAudioFourCCProperty );
+
+ // Video property definitions
+ CMdEObjectDef& videoDef = nsDef.GetObjectDefL( Video::KVideoObject );
+ iFrameratePropertyDef = &videoDef.GetPropertyDefL( Video::KFramerateProperty );
+
+ // Audio property definitions
+ CMdEObjectDef& audioDef = nsDef.GetObjectDefL( Audio::KAudioObject );
+ iSamplingFrequencyPropertyDef = &audioDef.GetPropertyDefL( Audio::KSamplingFrequencyProperty );
+ }
+
+CHarvesterVideoPluginPropertyDefs* CHarvesterVideoPluginPropertyDefs::NewL(CMdEObjectDef& aObjectDef)
+ {
+ CHarvesterVideoPluginPropertyDefs* self =
+ new (ELeave) CHarvesterVideoPluginPropertyDefs();
+ CleanupStack::PushL( self );
+ self->ConstructL( aObjectDef );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+/**
+* Default constructor
+*/
+CHarvesterVideoPlugin::CHarvesterVideoPlugin() : CHarvesterPlugin(), iPropDefs( NULL )
+ {
+ }
+
+/**
+* Construction
+* @return Harvester image plugin
+*/
+CHarvesterVideoPlugin* CHarvesterVideoPlugin::NewL()
+ {
+ WRITELOG("CHarvesterVideoPlugin::NewL()");
+ CHarvesterVideoPlugin* self = new(ELeave) CHarvesterVideoPlugin();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+* Destruction
+*/
+CHarvesterVideoPlugin::~CHarvesterVideoPlugin()
+ {
+ delete iPropDefs;
+
+ WRITELOG("CHarvesterVideoPlugin::CHarvesterVideoPlugin()");
+ }
+
+/**
+* 2nd phase constructor
+*/
+void CHarvesterVideoPlugin::ConstructL()
+ {
+ WRITELOG( "CHarvesterVideoPlugin::ConstructL() - begin" );
+
+ TLinearOrder< THarvestingHandling > cmp( THarvestingHandling::CompareFunction );
+
+ // MPEG4
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtensionMp4(), KNullDesC(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EMp4LibHandling, KNullDesC(),
+ KMimeTypeVideoMp4(), KMimeTypeAudioMp4() ) ),
+ cmp ) );
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtensionMpg4(), KNullDesC(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EMp4LibHandling, KNullDesC(),
+ KMimeTypeVideoMp4(), KMimeTypeAudioMp4() ) ),
+ cmp ) );
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtensionMpeg4(), KNullDesC(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EMp4LibHandling, KNullDesC(),
+ KMimeTypeVideoMp4(), KMimeTypeAudioMp4() ) ),
+ cmp ) );
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtensionM4v(), KMimeTypeVideoMp4(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EMp4LibHandling, KVideo(),
+ KMimeTypeVideoMp4(), KMimeTypeAudioMp4() ) ),
+ cmp ) );
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtensionM4a(), KMimeTypeAudioMp4(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EMp4LibHandling, KAudio(),
+ KMimeTypeVideoMp4(), KMimeTypeAudioMp4() ) ),
+ cmp ) );
+
+ // 3GP
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtension3gp(), KNullDesC(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EMp4LibHandling, KNullDesC(),
+ KMimeTypeVideo3gpp(), KMimeTypeAudio3gpp() ) ),
+ cmp ) );
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtension3gpp(), KNullDesC(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EMp4LibHandling, KNullDesC(),
+ KMimeTypeVideo3gpp(), KMimeTypeAudio3gpp() ) ),
+ cmp ) );
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtension3g2(), KNullDesC(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EMp4LibHandling, KNullDesC(),
+ KMimeTypeVideo3gpp(), KMimeTypeAudio3gpp() ) ),
+ cmp ) );
+
+ // RealMedia
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtensionRm(), KNullDesC(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EHexilMetadataHandling, KNullDesC(),
+ KMimeTypeRm(), KMimeTypeRm() ) ),
+ cmp ) );
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtensionRmvb(), KNullDesC(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EHexilMetadataHandling, KNullDesC(),
+ KMimeTypeRmvb(), KMimeTypeRmvb() ) ),
+ cmp ) );
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtensionRv(), KMimeTypeRv(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EHexilMetadataHandling, KVideo(),
+ KMimeTypeRv(), KMimeTypeRa() ) ),
+ cmp ) );
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtensionRa(), KMimeTypeRa(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EHexilMetadataHandling, KAudio(),
+ KMimeTypeRv(), KMimeTypeRa() ) ),
+ cmp ) );
+
+ // Avi
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtensionAvi(), KMimeTypeAvi(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EHexilMetadataHandling, KVideo(),
+ KMimeTypeAvi(), KMimeTypeAvi() ) ),
+ cmp ) );
+
+ // Matroska
+ User::LeaveIfError( iMimeTypeMappings.InsertInOrder( THarvestingHandling(
+ KExtensionMkv(), KNullDesC(),
+ TVideoMetadataHandling( TVideoMetadataHandling::EHexilMetadataHandling, KNullDesC(),
+ KMimeTypeVideoMatroska(), KMimeTypeAudioMatroska() ) ),
+ cmp ) );
+ }
+
+
+// ---------------------------------------------------------------------------
+// GetObjectType
+// ---------------------------------------------------------------------------
+//
+void CHarvesterVideoPlugin::GetObjectType( const TDesC& aUri, TDes& aObjectType )
+ {
+ aObjectType.Zero();
+
+ const THarvestingHandling* mapping = FindHandler( aUri );
+
+ // no matching extension found
+ if( !mapping )
+ {
+ return;
+ }
+
+ const TVideoMetadataHandling& handler = mapping->iHandler;
+
+ // object def is defined by extension
+ if( handler.iObjectDef.Length() > 0 )
+ {
+ aObjectType.Copy( handler.iObjectDef );
+ return;
+ }
+
+ RFile64 file;
+ // File must not be allowed to be written to here. If file passes through
+ // here while it is still open for writing, it will fail in actual harvesting
+ // and will not be processed again until the file is modified
+ const TInt error = file.Open( iFs, aUri, EFileRead | EFileShareReadersOnly );
+ if ( error != KErrNone )
+ {
+ WRITELOG1( "CHarvesterVideoPlugin::GetObjectType - File open error: %d", error );
+ if( error == KErrInUse )
+ {
+ aObjectType.Copy( KInUse() );
+ }
+ return;
+ }
+
+ if( handler.iLibrary == TVideoMetadataHandling::EMp4LibHandling )
+ {
+ GetMp4Type( file, aObjectType );
+ }
+ else if( handler.iLibrary == TVideoMetadataHandling::EHexilMetadataHandling )
+ {
+ TRAP_IGNORE( GetRmTypeL( file, aObjectType ) );
+ }
+ else
+ {
+ WRITELOG1( "CHarvesterVideoPlugin::GetObjectType - ERROR: %S. No handling library found", &aUri );
+ }
+
+ file.Close();
+ }
+
+void CHarvesterVideoPlugin::HarvestL( CHarvesterData* aHD )
+ {
+ CMdEObject& mdeObject = aHD->MdeObject();
+ CVideoHarvestData* fileData = new (ELeave) CVideoHarvestData;
+ CleanupStack::PushL( fileData );
+
+#ifdef _DEBUG
+ WRITELOG1("CHarvesterVideoPlugin::HarvestL - aHD->Uri() %S", &aHD->Uri() );
+ WRITELOG1("CHarvesterVideoPlugin::HarvestL - mdeObject.Uri() %S", &mdeObject.Uri() );
+#endif
+
+ TRAPD( error, GatherDataL( mdeObject, *fileData ) );
+ if ( error == KErrNone || error == KErrCompletion )
+ {
+ TBool isNewObject( mdeObject.Id() == 0 );
+
+ if ( isNewObject || mdeObject.Placeholder() )
+ {
+ TRAP( error, HandleObjectPropertiesL( *aHD, *fileData, ETrue ) );
+ mdeObject.SetPlaceholder( EFalse );
+ }
+ else
+ {
+ TRAP( error, HandleObjectPropertiesL( *aHD, *fileData, EFalse ) );
+ }
+
+ if ( error != KErrNone )
+ {
+ WRITELOG1( "CHarvesterVideoPlugin::HarvestSingleFileL() - Handling object failed: ", error );
+ }
+ }
+ else
+ {
+ WRITELOG1( "CHarvesterVideoPlugin::HarvestSingleFileL() - TRAP error: %d", error );
+ TInt convertedError = KErrNone;
+ MdsUtils::ConvertTrapError( error, convertedError );
+ aHD->SetErrorCode( convertedError );
+ }
+
+ CleanupStack::PopAndDestroy( fileData );
+ }
+
+// ---------------------------------------------------------------------------
+// GatherDataL
+// ---------------------------------------------------------------------------
+//
+void CHarvesterVideoPlugin::GatherDataL( CMdEObject& aMetadataObject,
+ CVideoHarvestData& aVHD )
+ {
+ const TDesC& uri = aMetadataObject.Uri();
+
+ WRITELOG1( "CHarvesterVideoPlugin - Gather data from file %S", &uri );
+
+ RFile64 file;
+ TInt error = file.Open( iFs, uri, EFileRead | EFileShareReadersOnly );
+ CleanupClosePushL( file );
+ if ( error == KErrInUse ||
+ error == KErrLocked )
+ {
+ WRITELOG( "CHarvesterVideoPlugin - File is open!" );
+ CleanupStack::PopAndDestroy( &file );
+ User::Leave( KErrInUse );
+ }
+ else if( error == KErrNotFound ||
+ error == KErrPathNotFound ||
+ error == KErrDisMounted ||
+ error == KErrBadDescriptor )
+ {
+ WRITELOG1( "CHarvesterVideoPlugin - File open error: %d", error );
+ CleanupStack::PopAndDestroy( &file );
+ User::Leave( error );
+ }
+
+ TBool dataExtracted( aMetadataObject.Id() == 0 || aMetadataObject.Placeholder() );
+
+ if( dataExtracted )
+ {
+ CMdEProperty* prop = NULL;
+ CMdEObjectDef& objectDef = aMetadataObject.Def();
+ CMdEPropertyDef& sizeDef = objectDef.GetPropertyDefL( MdeConstants::Object::KSizeProperty );
+ aMetadataObject.Property( sizeDef, prop );
+ if( prop )
+ {
+ aVHD.iFileSize = prop->Uint32ValueL();
+ }
+ else
+ {
+ dataExtracted = EFalse;
+ }
+ CMdEPropertyDef& modifiedDef = objectDef.GetPropertyDefL( MdeConstants::Object::KLastModifiedDateProperty );
+ aMetadataObject.Property( modifiedDef, prop );
+ if( prop )
+ {
+ aVHD.iModified = prop->TimeValueL();
+ }
+ else
+ {
+ dataExtracted = EFalse;
+ }
+ }
+
+ if( !dataExtracted )
+ {
+ TEntry entry;
+ const TInt errorcode = iFs.Entry( uri, entry );
+
+ if ( errorcode != KErrNone )
+ {
+ WRITELOG1( "CHarvesterVideoPlugin - Error getting entry: %d", errorcode );
+ CleanupStack::PopAndDestroy( &file );
+ User::Leave( errorcode );
+ }
+
+ aVHD.iModified = entry.iModified;
+ aVHD.iFileSize = (TUint)entry.iSize;
+ }
+
+ WRITELOG1( "CHarvesterVideoPlugin - File size: %d", aVHD.iFileSize );
+
+ // now the minimum information has been harvested
+ // from now on the harvested data should always be stored
+
+ const THarvestingHandling* mapping = FindHandler( uri );
+
+ if( !mapping )
+ {
+ CleanupStack::PopAndDestroy( &file );
+ User::Leave( KErrNotFound );
+ }
+
+ aVHD.iVideoObject = aMetadataObject.Def().Name().Compare( KVideo ) == 0;
+
+ if( error != KErrNone )
+ {
+ WRITELOG1( "CHarvesterVideoPlugin - File open error: %d", error );
+ CleanupStack::PopAndDestroy( &file );
+ User::Leave( KErrCompletion );
+ }
+
+ if ( mapping->iHandler.iLibrary == TVideoMetadataHandling::EHexilMetadataHandling )
+ {
+ // doesn't own pointers to MIME types
+ RPointerArray<HBufC> mimes;
+ CleanupClosePushL( mimes );
+
+ CHXMetaDataUtility* helixMetadata = CHXMetaDataUtility::NewL();
+ CleanupStack::PushL( helixMetadata );
+
+ TRAP( error, helixMetadata->OpenFileL( file ) );
+
+ if ( error == KErrNone )
+ {
+ HBufC *buf = NULL;
+ HXMetaDataKeys::EHXMetaDataId metaid;
+ TUint metacount = 0;
+ helixMetadata->GetMetaDataCount( metacount );
+ TLex lex;
+ for ( TUint i = 0; i < metacount; i++ )
+ {
+ helixMetadata->GetMetaDataAt( i, metaid, buf );
+ switch (metaid)
+ {
+ case HXMetaDataKeys::EHXVideoBitRate:
+ {
+ WRITELOG( "CHarvesterVideoPlugin - found videobitrate" );
+ if( aVHD.iVideoObject )
+ {
+ lex.Assign( *buf );
+ if( KErrNone == lex.Val( aVHD.iVideoBitrate ) )
+ {
+ aVHD.iVideoBitrate /= KKiloBytes;
+ }
+ }
+ break;
+ }
+ case HXMetaDataKeys::EHXAudioBitRate:
+ {
+ WRITELOG( "CHarvesterVideoPlugin - found audiobitrate" );
+ lex.Assign( *buf );
+ if( KErrNone == lex.Val( aVHD.iAudioBitrate ) )
+ {
+ aVHD.iAudioBitrate /= KKiloBytes;
+ }
+ break;
+ }
+ case HXMetaDataKeys::EHXClipBitRate:
+ {
+ WRITELOG( "CHarvesterVideoPlugin - found clipbitrate" );
+ lex.Assign( *buf );
+ if( KErrNone == lex.Val( aVHD.iClipBitrate ) )
+ {
+ aVHD.iClipBitrate /= KKiloBytes;
+ }
+ break;
+ }
+ case HXMetaDataKeys::EHXDuration:
+ {
+ WRITELOG( "CHarvesterVideoPlugin - found duration" );
+ lex.Assign(*buf);
+ if( KErrNone == lex.Val( aVHD.iDuration ) )
+ {
+ aVHD.iDuration /= KThousandReal;
+ }
+ break;
+ }
+ case HXMetaDataKeys::EHXFramesPerSecond:
+ {
+ WRITELOG( "CHarvesterVideoPlugin - found framerate" );
+ lex.Assign( *buf );
+ lex.Val( aVHD.iFrameRate );
+ break;
+ }
+ case HXMetaDataKeys::EHXCopyright:
+ {
+ aVHD.iCopyright = buf->Alloc();
+ break;
+ }
+ case HXMetaDataKeys::EHXAuthor:
+ {
+ aVHD.iAuthor = buf->Alloc();
+ break;
+ }
+ case HXMetaDataKeys::EHXGenre:
+ {
+ aVHD.iGenre = buf->Alloc();
+ break;
+ }
+ case HXMetaDataKeys::EHXPerformer:
+ {
+ aVHD.iPerformer = buf->Alloc();
+ break;
+ }
+ case HXMetaDataKeys::EHXDescription:
+ {
+ aVHD.iDescription = buf->Alloc();
+ break;
+ }
+ case HXMetaDataKeys::EHXMimeType:
+ {
+ mimes.AppendL( buf );
+ if( aVHD.iCodec == 0 )
+ {
+ CheckForCodecSupport( buf, aVHD );
+ }
+ break;
+ }
+ case HXMetaDataKeys::EHXFrameSize:
+ {
+ const TChar separator = 'x'; // as in e.g."177x144"
+ const TInt separatorLocation = buf->Locate( separator );
+ TLex input( buf->Left( separatorLocation ) );
+
+ input.Val( aVHD.iFrameWidth );
+ input = buf->Right(buf->Length() - separatorLocation - 1);
+ input.Val( aVHD.iFrameHeight );
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ const TInt mimeCount = mimes.Count();
+
+ TPtrC mime( NULL, 0 );
+
+ // if metadata didn't contain MIME, get it from extension mapping
+ if( mimeCount == 0 )
+ {
+ if( aVHD.iVideoObject )
+ {
+ mime.Set( mapping->iHandler.iVideoMime.Ptr(),
+ mapping->iHandler.iVideoMime.Length() );
+ }
+ else
+ {
+ mime.Set( mapping->iHandler.iAudioMime.Ptr(),
+ mapping->iHandler.iAudioMime.Length() );
+ }
+ }
+ // otherwise search from MIME type array
+ else
+ {
+ for( TInt i = 0; i < mimeCount; i++ )
+ {
+ HBufC* mimeTmp = mimes[i];
+
+ if( !mimeTmp )
+ {
+ continue;
+ }
+
+ mime.Set( mimeTmp->Des().Ptr(), mimeTmp->Des().Length() );
+
+ // MIME contains substring "application/vnd.rn-realmedia".
+ // That case MIME matches also with
+ // string "application/vnd.rn-realmedia-vbr".
+ if( MdsUtils::Find( mime, KMimeTypeRm() ) != KErrNotFound )
+ {
+ break;
+ }
+ // Match MIME type, for video object with "video" substring
+ else if( aVHD.iVideoObject )
+ {
+ if( MdsUtils::Find( mime, KVideo() ) != KErrNotFound )
+ {
+ break;
+ }
+ }
+ // Match MIME type for audio object with "audio" substring
+ else if( MdsUtils::Find( mime, KAudio() ) != KErrNotFound )
+ {
+ break;
+ }
+ }
+ }
+
+ if( mime.Ptr() && ( mime.Length() > 0 ) )
+ {
+ aVHD.iMimeBuf = mime.Alloc();
+ }
+
+ CleanupStack::PopAndDestroy( helixMetadata );
+
+ // don't destory mime type pointers just clean array
+ CleanupStack::PopAndDestroy( &mimes );
+ }
+ else if( mapping->iHandler.iLibrary == TVideoMetadataHandling::EMp4LibHandling )
+ {
+ MP4Handle handle( 0 );
+ MP4Err mp4err = MP4_OK;
+
+ WRITELOG( "CHarvesterVideoPlugin - Before open file handle to parse" );
+
+ WRITELOG( "CHarvesterVideoPlugin - GatherDataL - MP4ParseOpenFileHandle - start" );
+
+ mp4err = MP4ParseOpenFileHandle64( &handle, &file );
+
+ WRITELOG( "CHarvesterVideoPlugin - GatherDataL - MP4ParseOpenFileHandle - ready" );
+
+ if ( mp4err != MP4_OK )
+ {
+ WRITELOG( "CHarvesterVideoPlugin - Error opening file handle" );
+
+ CleanupStack::PopAndDestroy( &file );
+ User::Leave( KErrCompletion );
+ }
+
+ WRITELOG( "CHarvesterVideoPlugin - Start gathering" );
+
+ if( aVHD.iVideoObject )
+ {
+ mp4_u32 videolength( 0 );
+ mp4_double framerate( 0 );
+ mp4_u32 videotype( 0 );
+ mp4_u32 videowidth( 0 );
+ mp4_u32 videoheight( 0 );
+ mp4_u32 timescale( 0 );
+
+ WRITELOG( "CHarvesterVideoPlugin - GatherDataL - MP4ParseRequestVideoDescription - start" );
+ mp4err = MP4ParseRequestVideoDescription( handle, &videolength, &framerate,
+ &videotype, &videowidth, &videoheight, ×cale );
+ WRITELOG( "CHarvesterVideoPlugin - GatherDataL - MP4ParseRequestVideoDescription - ready" );
+
+ if ( mp4err == MP4_OK )
+ {
+ aVHD.iDuration = videolength / KThousandReal;
+ aVHD.iFrameRate = framerate;
+ aVHD.iFrameWidth = videowidth;
+ aVHD.iFrameHeight = videoheight;
+ }
+
+ mp4_u32 streamSize( 0 );
+ mp4_u32 avgBitrate( 0 );
+
+ WRITELOG( "CHarvesterVideoPlugin - GatherDataL - MP4ParseRequestStreamDescription - start" );
+ mp4err = MP4ParseRequestStreamDescription( handle, &streamSize, &avgBitrate );
+ WRITELOG( "CHarvesterVideoPlugin - GatherDataL - MP4ParseRequestStreamDescription - ready" );
+
+ if ( mp4err == MP4_OK )
+ {
+ aVHD.iClipBitrate = avgBitrate / KKiloBytes;
+ }
+
+ aVHD.iMimeBuf = mapping->iHandler.iVideoMime.Alloc();
+ }
+ else
+ {
+ mp4_u32 audiolength;
+ mp4_u32 audiotype;
+ mp4_u8 framespersample;
+ mp4_u32 timescale;
+ mp4_u32 averagebitrate;
+
+ WRITELOG( "CHarvesterVideoPlugin - GatherDataL - MP4ParseRequestVideoDescription - start" );
+ mp4err = MP4ParseRequestAudioDescription( handle, &audiolength, &audiotype,
+ &framespersample, ×cale, &averagebitrate );
+ WRITELOG( "CHarvesterVideoPlugin - GatherDataL - MP4ParseRequestAudioDescription - ready" );
+
+ if ( mp4err == MP4_OK )
+ {
+ aVHD.iDuration = audiolength / KThousandReal;
+ aVHD.iSamplingFrequency = timescale;
+ aVHD.iAudioBitrate = averagebitrate / KKiloBytes;
+ }
+
+ aVHD.iMimeBuf = mapping->iHandler.iAudioMime.Alloc();
+ }
+
+ WRITELOG( "CHarvesterVideoPlugin - Stop gathering" );
+
+ WRITELOG( "CHarvesterVideoPlugin - GatherDataL - MP4ParseClose - start" );
+ mp4err = MP4ParseClose( handle );
+ WRITELOG( "CHarvesterVideoPlugin - GatherDataL - MP4ParseClose - ready" );
+ if ( mp4err != MP4_OK )
+ {
+ WRITELOG( "CHarvesterVideoPlugin - Error closing file handle" );
+ }
+ }
+ WRITELOG( "CHarvesterVideoPlugin - Closing file" );
+ CleanupStack::PopAndDestroy( &file );
+
+ WRITELOG( "CHarvesterVideoPlugin - Start adding data to object" );
+ }
+
+// ---------------------------------------------------------------------------
+// HandleNewObjectL
+// ---------------------------------------------------------------------------
+//
+void CHarvesterVideoPlugin::HandleObjectPropertiesL(
+ CHarvesterData& aHD,
+ CVideoHarvestData& aVHD,
+ TBool aIsAdd )
+ {
+ WRITELOG("CHarvesterVideoPlugin::HandleObjectPropertiesL ");
+
+ CMdEObject& mdeObject = aHD.MdeObject();
+
+ if( !iPropDefs )
+ {
+ CMdEObjectDef& objectDef = mdeObject.Def();
+ iPropDefs = CHarvesterVideoPluginPropertyDefs::NewL( objectDef );
+ }
+
+ TTimeIntervalSeconds timeOffsetSeconds = User::UTCOffset();
+ TTime localModifiedDate = aVHD.iModified + timeOffsetSeconds;
+
+ if( !mdeObject.Placeholder() )
+ {
+ // Creation date
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iCreationDatePropertyDef, &localModifiedDate, aIsAdd );
+
+ // Last modified date
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iLastModifiedDatePropertyDef, &aVHD.iModified, aIsAdd );
+
+ // File size
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iSizePropertyDef, &aVHD.iFileSize, aIsAdd );
+ }
+
+ // Release date
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iReleaseDatePropertyDef, &localModifiedDate, aIsAdd );
+
+ // Capture date
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iCaptureDatePropertyDef, &localModifiedDate, aIsAdd );
+
+ // Time offset
+ TInt16 timeOffsetMinutes = timeOffsetSeconds.Int() / 60;
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iTimeOffsetPropertyDef, &timeOffsetMinutes, aIsAdd );
+
+ // Item Type
+ if( aVHD.iMimeBuf )
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iItemTypePropertyDef, aVHD.iMimeBuf, aIsAdd );
+ }
+
+ // Duration
+ if( aVHD.iDuration != 0.0f )
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iDurationPropertyDef, &aVHD.iDuration, aIsAdd );
+ }
+
+ if( aVHD.iVideoObject )
+ {
+ // Width
+ if (aVHD.iFrameWidth != 0)
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iWidthPropertyDef, &aVHD.iFrameWidth, aIsAdd );
+ }
+
+ // Height
+ if (aVHD.iFrameHeight != 0)
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iHeightPropertyDef, &aVHD.iFrameHeight, aIsAdd );
+ }
+
+ // Framerate
+ if (aVHD.iFrameRate != 0)
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iFrameratePropertyDef, &aVHD.iFrameRate, aIsAdd );
+ }
+ }
+ else // audio object
+ {
+ // Sampling frequency
+ if (aVHD.iSamplingFrequency != 0.0f)
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iSamplingFrequencyPropertyDef, &aVHD.iSamplingFrequency, aIsAdd );
+ }
+ }
+
+ // Bitrate
+ if (aVHD.iClipBitrate != 0)
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iBitratePropertyDef, &aVHD.iClipBitrate, aIsAdd );
+ }
+ else
+ {
+ if( aVHD.iVideoObject )
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iBitratePropertyDef, &aVHD.iVideoBitrate, aIsAdd );
+ }
+ else // audio object
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iBitratePropertyDef, &aVHD.iAudioBitrate, aIsAdd );
+ }
+ }
+
+ // Copyright
+ if( aVHD.iCopyright )
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iCopyrightPropertyDef, aVHD.iCopyright, aIsAdd );
+ }
+
+ // Author
+ if( aVHD.iAuthor )
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iAuthorPropertyDef, aVHD.iAuthor, aIsAdd );
+ }
+
+ // Genre
+ if( aVHD.iGenre )
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iGenrePropertyDef, aVHD.iGenre, aIsAdd );
+ }
+
+ // Artist
+ if( aVHD.iPerformer )
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iArtistPropertyDef, aVHD.iPerformer, aIsAdd );
+ }
+
+ // Description
+ if( aVHD.iDescription )
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iDescriptionPropertyDef, aVHD.iDescription, aIsAdd );
+ }
+
+ // Codec
+ if( aVHD.iCodec != 0 )
+ {
+ CMdeObjectWrapper::HandleObjectPropertyL(mdeObject, *iPropDefs->iAudioFourCCDef, &aVHD.iCodec, aIsAdd );
+ }
+ }
+
+void CHarvesterVideoPlugin::GetMp4Type( RFile64& aFile, TDes& aType )
+ {
+ WRITELOG( "CHarvesterVideoPlugin::GetMp4Mime - MP4ParseOpenFileHandle - start" );
+ MP4Handle handle;
+
+ MP4Err mp4err = MP4ParseOpenFileHandle64( &handle, &aFile );
+
+ WRITELOG( "CHarvesterVideoPlugin::GetMp4Mime - MP4ParseOpenFileHandle - ready" );
+
+ if ( mp4err != MP4_OK )
+ {
+ WRITELOG( "CHarvesterVideoPlugin::GetMp4Mime - Error opening file handle" );
+ return;
+ }
+
+ WRITELOG( "CHarvesterVideoPlugin::GetMp4Mime - MP4ParseRequestVideoDescription - start" );
+ mp4_u32 videolength;
+ mp4_double framerate;
+ mp4_u32 videowidth;
+ mp4_u32 videoheight;
+ mp4_u32 timescale;
+ mp4_u32 videotype;
+ mp4err = MP4ParseRequestVideoDescription( handle, &videolength,
+ &framerate, &videotype, &videowidth, &videoheight, ×cale );
+ WRITELOG( "CHarvesterVideoPlugin::GetMp4Mime - MP4ParseRequestVideoDescription - ready" );
+
+ // If no video stream found, set to Audio
+ if ( mp4err == MP4_NO_VIDEO )
+ {
+ WRITELOG( "CHarvesterVideoPlugin::GetMp4Mime - No video stream found, set to Audio" );
+ aType.Copy( KAudio() );
+ }
+ // Otherwise set to Video, regardless how badly file is corrupted
+ else
+ {
+ aType.Copy( KVideo() );
+ }
+
+ MP4ParseClose( handle );
+ }
+
+void CHarvesterVideoPlugin::GetRmTypeL( RFile64& aFile, TDes& aType )
+ {
+ TBool possibleVideo = EFalse;
+
+ CHXMetaDataUtility* helixMetadata = CHXMetaDataUtility::NewL();
+ CleanupStack::PushL( helixMetadata );
+
+ TRAPD( err, helixMetadata->OpenFileL( aFile ) );
+
+ if( err == KErrNone )
+ {
+ // doesn't own pointers to MIME types
+ RPointerArray<HBufC> mimes;
+ CleanupClosePushL( mimes );
+
+ TUint metacount = 0;
+ helixMetadata->GetMetaDataCount(metacount);
+ for (TUint i = 0; i < metacount; i++)
+ {
+ HBufC *buf = NULL;
+ HXMetaDataKeys::EHXMetaDataId metaid;
+ helixMetadata->GetMetaDataAt( i, metaid, buf );
+ if( metaid == HXMetaDataKeys::EHXMimeType )
+ {
+ mimes.AppendL( buf );
+ }
+ else if( metaid == HXMetaDataKeys::EHXVideoBitRate )
+ {
+ possibleVideo = ETrue;
+ }
+ }
+
+ const TInt mimeCount = mimes.Count();
+
+ // at least one MIME type must be found
+ if( mimeCount == 0 )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ for( TInt i = 0; i < mimeCount; i++ )
+ {
+ HBufC* mime = mimes[i];
+
+ // "application/vnd.rn-realmedia" or "application/vnd.rn-realmedia-vbr"
+ if( MdsUtils::Find( *mime, KMimeTypeRm() ) != KErrNotFound )
+ {
+ WRITELOG1( "CHarvesterVideoPlugin::GetObjectType - mimetype %S. Object type Rm", mime );
+ if( possibleVideo )
+ {
+ aType.Copy( KVideo );
+ }
+ else
+ {
+ aType.Copy( KAudio );
+ }
+
+ break;
+ }
+ else if( MdsUtils::Find( *mime, KVideo() ) != KErrNotFound )
+ {
+ WRITELOG1( "CHarvesterVideoPlugin::GetObjectType - mimetype %S. Object type Video", mime );
+ aType.Copy( KVideo );
+
+ // use MIME with "video" substring, if file might be video
+ if( possibleVideo )
+ {
+ break;
+ }
+ }
+ else if( MdsUtils::Find( *mime, KAudio() ) != KErrNotFound )
+ {
+ WRITELOG1( "CHarvesterVideoPlugin::GetObjectType - mimetype %S. Object type Audio", mime );
+ aType.Copy( KAudio );
+ }
+ // Set to Video, regardless how badly file is corrupted
+ else
+ {
+ aType.Copy( KVideo );
+ }
+ }
+
+ // don't destory mime type pointers just clean array
+ CleanupStack::PopAndDestroy( &mimes );
+ }
+ // Set to Video, regardless how badly file is corrupted
+ else
+ {
+ aType.Copy( KVideo );
+ }
+
+ CleanupStack::PopAndDestroy( helixMetadata );
+ }
+
+const THarvestingHandling* CHarvesterVideoPlugin::FindHandler( const TDesC& aUri )
+ {
+ TParsePtrC parse( aUri );
+ TPtrC ext = parse.Ext();
+
+ // remove '.' from extension
+ if ( ext.Length() > 1 )
+ {
+ ext.Set( ext.Mid( 1 ) );
+ }
+ else
+ {
+ WRITELOG1( "CHarvesterVideoPlugin::GetObjectType - ERROR: %S. No any extension found", &aUri );
+ return NULL;
+ }
+
+ THarvestingHandling finder( ext );
+
+ TLinearOrder<THarvestingHandling> cmp(THarvestingHandling::CompareFunction);
+
+ TInt pos = iMimeTypeMappings.FindInOrder( finder, cmp );
+
+ // no matching extension found or extension is missing from filename
+ if( KErrNotFound == pos || ext.Length() <= 0 )
+ {
+ WRITELOG1( "CHarvesterVideoPlugin::GetObjectType - ERROR: %S. No extension found", &aUri );
+ return NULL;
+ }
+
+ const THarvestingHandling* mapping = &iMimeTypeMappings[pos];
+
+ return mapping;
+ }
+
+void CHarvesterVideoPlugin::CheckForCodecSupport( HBufC* aMimeBuffer, CVideoHarvestData& aVHD )
+ {
+ if( !aMimeBuffer )
+ {
+ return;
+ }
+
+ TPtrC mime( NULL, 0 );
+ mime.Set( aMimeBuffer->Des().Ptr(), aMimeBuffer->Des().Length() );
+
+ if( MdsUtils::Find( mime, KAudioAC3() ) != KErrNotFound )
+ {
+ aVHD.iCodec = KMDSFourCCCodeAC3;
+ return;
+ }
+
+ if( MdsUtils::Find( mime, KAudioEAC3() ) != KErrNotFound )
+ {
+ aVHD.iCodec = KMDSFourCCCodeEAC3;
+ return;
+ }
+ return;
+ }
+
+// End of file
+