--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/connectivitymodules/SeCon/services/pcd/src/sconmetadata.cpp Wed Sep 01 12:20:56 2010 +0100
@@ -0,0 +1,1362 @@
+/*
+* Copyright (c) 2007-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: SConMetadata implementation
+*
+*/
+
+
+// INCLUDE FILES
+
+#include <utf.h> // for CnvUtfConverter
+#include <MetaDataUtility.h>
+#include <MetaDataFieldContainer.h>
+#include <MetaDataField.hrh>
+#include <caf/content.h>
+#include <caf/data.h>
+#include <ExifRead.h>
+#include <ExifTag.h>
+
+#include "sconmetadata.h"
+#include "sconconmltask.h"
+#include "sconpcdconsts.h"
+#include "sconvideoparser.h"
+#include "debug.h"
+#include "sconmetadatafielddefs.h"
+
+
+
+const TInt KBufferSize(1024);
+// Size of buffer to load from file start to get EXIF thumbnail
+const TInt KJpegLoadBufferSize = 65536; // 64k
+
+
+const TUint32 KFieldMaxLength = 0xFFFFFFFF; // four bytes reserved for "length" information
+
+// GPS related Exif IDs
+const TUint16 KGPSLatitudeRef = 0x01;
+const TUint16 KGPSLatitude = 0x02;
+const TUint16 KGPSLongitudeRef = 0x03;
+const TUint16 KGPSLongitude = 0x04;
+const TUint16 KGPSAltitudeRef = 0x05;
+const TUint16 KGPSAltitude = 0x06;
+
+
+// extensions for exif parser
+_LIT(KJpgExt, ".jpg");
+_LIT(KJpegExt, ".jpeg");
+// extensions for audio metadata parser
+_LIT(KAacExt, ".aac");
+_LIT(KMp3Ext, ".mp3");
+_LIT(KMp4Ext, ".mp4");
+_LIT(KWmaExt, ".wma");
+// extensions for video metadata parser
+_LIT(KM4aExt, ".m4a");
+_LIT(K3gpExt, ".3gp");
+
+
+// ============================= MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// SConMetadata::ProcessTask()
+// ProcessTask
+// -----------------------------------------------------------------------------
+//
+void SConMetadata::ProcessTask( CSConTask& aTask, RFs& aFs )
+ {
+ TRACE_FUNC_ENTRY;
+ TInt err(KErrNone);
+ if ( aTask.GetServiceId() == EGetMetadata )
+ {
+ LOGGER_WRITE_1( "SConMetadata::ProcessTask() : file %S",
+ &aTask.iGetMetadataParams->iFilename );
+
+#ifdef _DEBUG
+ LOGGER_WRITE( "start.. " );
+ TTimeIntervalMicroSeconds sec;
+ TTime start;
+ TTime end;
+ start.HomeTime();
+#endif
+
+ TParsePtrC filename( aTask.iGetMetadataParams->iFilename );
+
+ if ( filename.Ext().CompareF( KJpgExt ) == 0
+ || filename.Ext().CompareF( KJpegExt ) == 0 )
+ {
+ // jpg file, try to read exif
+ LOGGER_WRITE( "jpg file, Try to read exif" );
+ TRAP( err, ReadExifDataL( aTask, aFs ) );
+ }
+ else if ( filename.Ext().CompareF( KMp4Ext ) == 0
+ || filename.Ext().CompareF( K3gpExt ) == 0 )
+ {
+ LOGGER_WRITE( "Try to read video" );
+ TRAP( err, GetVideoMetadataL( aTask, aFs ) );
+ }
+ else if ( filename.Ext().CompareF( KAacExt ) == 0
+ || filename.Ext().CompareF( KM4aExt ) == 0
+ || filename.Ext().CompareF( KMp3Ext ) == 0
+ || filename.Ext().CompareF( KWmaExt ) == 0 )
+ {
+
+ // audio file, try to read audio
+ LOGGER_WRITE( "Try to read audio" );
+ TRAP( err, GetAudioMetadataL( aTask ) );
+ }
+ else
+ {
+ LOGGER_WRITE( "File extension not supported" );
+ err = KErrNotSupported;
+ }
+
+#ifdef _DEBUG
+ end.HomeTime();
+ sec = end.MicroSecondsFrom( start );
+
+ LOGGER_WRITE_1( "trapErr %d", err );
+ LOGGER_WRITE_1( "duration: %Ld", sec.Int64() );
+#endif
+ }
+ else
+ {
+ LOGGER_WRITE( "SConMetadata::ProcessTask() : not supported" );
+ err = KErrNotSupported;
+ }
+
+ LOGGER_WRITE( "SConMetadata::ProcessTask() : CompleteTask" );
+
+ TInt progress( KSConCodeTaskCompleted );
+ TBool complete ( ETrue );
+ switch( err )
+ {
+ case KErrNone :
+ progress = KSConCodeTaskCompleted;
+ break;
+ case KErrNotFound :
+ case KErrBadName :
+ progress = KSConCodeNotFound;
+ break;
+ default :
+ progress = KSConCodeConflict;
+ break;
+ }
+
+ aTask.SetCompleteValue( complete );
+ aTask.SetProgressValue( progress );
+ TRACE_FUNC_EXIT;
+ }
+
+// -----------------------------------------------------------------------------
+// SConMetadata::GetAudioMetadataL()
+// Read audio metadata
+// -----------------------------------------------------------------------------
+//
+void SConMetadata::GetAudioMetadataL( CSConTask& aTask )
+ {
+ TRACE_FUNC_ENTRY;
+ CMetaDataUtility* metadataUtil = CMetaDataUtility::NewL();
+ CleanupStack::PushL( metadataUtil );
+
+ LOGGER_WRITE( "SConMetadata::GetAudioMetadataL() : OpenFileL" );
+ metadataUtil->OpenFileL( aTask.iGetMetadataParams->iFilename );
+
+ TInt count = metadataUtil->MetaDataCount();
+ LOGGER_WRITE_1( "SConMetadata::GetAudioMetadataL() : MetaDataCount %d", count );
+ if ( count > 0 )
+ {
+ const CMetaDataFieldContainer& fields = metadataUtil->MetaDataFieldsL();
+ count = fields.Count();
+
+ CBufFlat* buffer = CBufFlat::NewL( KBufferSize );
+ CleanupStack::PushL( buffer );
+ buffer->Reset();
+
+
+ TInt offset(0);
+ // write object header
+ // Item type (1 byte) + Version (1 byte) = 2 bytes
+ buffer->ExpandL( offset, 2 );
+
+ // header id
+ TUint8 value( KSconMetadataHeaderAudio );
+ buffer->Write( offset, TPtrC8(&value, 1) );
+ offset++;
+
+ // header version
+ value = KSconMetadataHeaderVersion;
+ buffer->Write( offset, TPtrC8(&value, 1) );
+ offset++;
+
+ // Add ID3 field
+ value = metadataUtil->ID3Version();
+ AppendTUintDataFieldL( buffer, value, KSconAudioID3Version );
+
+ TMetaDataFieldId fieldId;
+ TPtrC fieldData;
+
+ for ( TInt i = 0; i < count; i++ )
+ {
+ // get field id
+ fields.FieldIdAt( i , fieldId );
+ LOGGER_WRITE_2( "AudioFieldId( %d ): 0x%02x", i, fieldId );
+ TUint8 sconFieldId = AudioFieldId( fieldId );
+ if ( sconFieldId == KSconAudioJpeg )
+ {
+ TPtrC8 field8( fields.Field8( fieldId ) );
+ AppendByteDataFieldL(
+ buffer,
+ field8,
+ AudioFieldId( fieldId ) );
+ }
+ else if ( sconFieldId > 0 )
+ {
+ // get field data and add UTF-8 formatted text to buffer
+ fieldData.Set( fields.At( i , fieldId ) );
+ AppendUtf8DataFieldL( buffer, fieldData, sconFieldId );
+ }
+ else
+ {
+ LOGGER_WRITE("Unknown field skipped");
+ }
+ }
+
+ if ( buffer->Size() > 0 )
+ {
+ LOGGER_WRITE_1( "SConMetadata::GetAudioMetadataL() : buffer->Size() %d", buffer->Size() );
+ if ( aTask.iGetMetadataParams->iData )
+ {
+ delete aTask.iGetMetadataParams->iData;
+ aTask.iGetMetadataParams->iData = NULL;
+ }
+ //Initialize the task data buffer
+ aTask.iGetMetadataParams->iData = HBufC8::NewL( buffer->Size() );
+ TPtr8 dataPtr = aTask.iGetMetadataParams->iData->Des();
+
+ buffer->Read( 0, dataPtr, buffer->Size() );
+ LOGGER_WRITE_1( "SConMetadata::GetAudioMetadataL() dataPtr len: %d", dataPtr.Length());
+ }
+ CleanupStack::PopAndDestroy( buffer );
+ }
+
+ CleanupStack::PopAndDestroy( metadataUtil );
+
+ TRACE_FUNC_EXIT;
+ }
+
+// -----------------------------------------------------------------------------
+// SConMetadata::GetVideoMetadataL()
+// Read video metadata
+// -----------------------------------------------------------------------------
+//
+void SConMetadata::GetVideoMetadataL( CSConTask& aTask, RFs& aFs )
+ {
+ TRACE_FUNC_ENTRY;
+ CBufFlat* buffer = CBufFlat::NewL( KBufferSize );
+ CleanupStack::PushL( buffer );
+ buffer->Reset();
+
+ TInt offset(0);
+ // write object header
+ // Item type (1 byte) + Version (1 byte) = 2 bytes
+ buffer->ExpandL( offset, 2 );
+
+ // header id
+ TUint8 value( KSconMetadataHeaderVideo );
+ buffer->Write( offset, TPtrC8(&value, 1) );
+ offset++;
+
+ // header version
+ value = KSconMetadataHeaderVersion;
+ buffer->Write( offset, TPtrC8(&value, 1) );
+ offset++;
+
+
+ CSConVideoParser* videoParser = CSConVideoParser::NewLC();
+
+ videoParser->OpenFileL( aFs, aTask.iGetMetadataParams->iFilename );
+ LOGGER_WRITE( "Open completed" );
+
+ const TUint KFormatMaxLength = 100;
+ TBuf<KFormatMaxLength> formatMimeType;
+ formatMimeType.Copy( videoParser->VideoFormatMimeTypeL() );
+ LOGGER_WRITE_1( "formatMimeType: %S", &formatMimeType);
+ AppendUtf8DataFieldL( buffer, formatMimeType, KSconVideoFormat );
+
+ // we can't use TReal format, so convert frame rate to frames/ms (or 1000 frames/s)
+ TReal32 frameRate = videoParser->VideoFrameRateL();
+ const TUint KFrameRateMultiplier = 1000;
+ TInt frm = frameRate * KFrameRateMultiplier;
+ LOGGER_WRITE_1( "frameRate: %f", frameRate );
+ LOGGER_WRITE_1( "frm: %d", frm );
+ AppendTUintDataFieldL( buffer, frm, KSconVideoFrameRate );
+
+ TSize size;
+ videoParser->VideoFrameSizeL( size );
+ LOGGER_WRITE_2( "VideoFrameSizeL: %d, %d", size.iWidth, size.iHeight);
+ AppendTUintDataFieldL( buffer, size.iWidth, KSconVideoFrameSizeWidth );
+ AppendTUintDataFieldL( buffer, size.iHeight, KSconVideoFrameSizeHeight );
+
+
+
+ const TUint8 KSconVideoAudioStreamMimetype ( 0x09 );
+ const TUint8 KSconVideoVideoStreamMimetype ( 0x0a );
+
+ TInt videoBitRate = videoParser->VideoBitRateL();
+ LOGGER_WRITE_1( "videoBitRate: %d", videoBitRate);
+ AppendTUintDataFieldL( buffer, videoBitRate, KSconVideoVideoBitRate );
+
+ TInt audioBitRate = videoParser->AudioBitRateL();
+ LOGGER_WRITE_1( "audioBitRate: %d", audioBitRate);
+ AppendTUintDataFieldL( buffer, audioBitRate, KSconVideoAudioBitRate );
+
+ TInt durationMs = videoParser->DurationL();
+ LOGGER_WRITE_1( "duration ms: %d", durationMs);
+ AppendTUintDataFieldL( buffer, durationMs, KSconVideoDuration );
+
+ TPtrC8 thumbnail = videoParser->Thumbnail();
+ if ( thumbnail.Length() > 0 )
+ {
+ AppendByteDataFieldL( buffer, thumbnail, KSconVideoThumbnail );
+ }
+
+ TPtrC audioMimeType = videoParser->AudioMimeTypeL();
+ if ( audioMimeType.Length() > 0 )
+ {
+ AppendUtf8DataFieldL( buffer, audioMimeType, KSconVideoAudioStreamMimetype );
+ }
+
+ TPtrC videoMimeType = videoParser->VideoMimeTypeL();
+ if ( videoMimeType.Length() > 0 )
+ {
+ AppendUtf8DataFieldL( buffer, formatMimeType, KSconVideoVideoStreamMimetype );
+ }
+
+ CleanupStack::PopAndDestroy( videoParser );
+ LOGGER_WRITE( "videoParser deleted" );
+
+
+ if ( buffer->Size() > 0 )
+ {
+ if ( aTask.iGetMetadataParams->iData )
+ {
+ delete aTask.iGetMetadataParams->iData;
+ aTask.iGetMetadataParams->iData = NULL;
+ }
+ //Initialize the task data buffer
+ aTask.iGetMetadataParams->iData = HBufC8::NewL( buffer->Size() );
+ TPtr8 dataPtr = aTask.iGetMetadataParams->iData->Des();
+
+ buffer->Read( 0, dataPtr, buffer->Size() );
+ }
+ CleanupStack::PopAndDestroy( buffer );
+
+
+ TRACE_FUNC_EXIT;
+ }
+
+// -----------------------------------------------------------------------------
+// SConMetadata::AudioFieldId()
+// Map TMetaDataFieldId to KSconAudio field id
+// -----------------------------------------------------------------------------
+//
+TUint8 SConMetadata::AudioFieldId( const TMetaDataFieldId fieldId )
+ {
+ TUint8 ret(NULL);
+ switch( fieldId )
+ {
+ case EMetaDataSongTitle :
+ ret = KSconAudioTitle;
+ break;
+ case EMetaDataArtist :
+ ret = KSconAudioArtist;
+ break;
+ case EMetaDataAlbum :
+ ret = KSconAudioAlbum;
+ break;
+ case EMetaDataYear :
+ ret = KSconAudioYear;
+ break;
+ case EMetaDataComment :
+ ret = KSconAudioComment;
+ break;
+ case EMetaDataAlbumTrack :
+ ret = KSconAudioAlbumTrack;
+ break;
+ case EMetaDataGenre :
+ ret = KSconAudioGenre;
+ break;
+ case EMetaDataComposer :
+ ret = KSconAudioComposer;
+ break;
+ case EMetaDataCopyright :
+ ret = KSconAudioCopyright;
+ break;
+ case EMetaDataOriginalArtist :
+ ret = KSconAudioOriginalArtist;
+ break;
+ case EMetaDataUrl :
+ ret = KSconAudioUrl;
+ break;
+ case EMetaDataUserUrl :
+ ret = KSconAudioUserUrl;
+ break;
+ case EMetaDataJpeg :
+ ret = KSconAudioJpeg;
+ break;
+ case EMetaDataVendor :
+ ret = KSconAudioVendor;
+ break;
+ case EMetaDataRating :
+ ret = KSconAudioRating;
+ break;
+ case EMetaDataUniqueFileIdentifier :
+ ret = KSconAudioUniqueFileIdentifier;
+ break;
+ case EMetaDataDuration :
+ ret = KSconAudioDuration;
+ break;
+ case EMetaDataDate :
+ ret = KSconAudioDate;
+ break;
+ case EMetaDataUnsyncLyrics:
+ ret = KSconAudioUnsyncLyrics;
+ break;
+ case EMetaDataProtected:
+ ret = KSconAudioProtected;
+ break;
+ default :
+ LOGGER_WRITE( "SConMetadata::AudioFieldId : ERR field not defined!" );
+ break;
+ }
+ return ret;
+ }
+
+
+// -----------------------------------------------------------------------------
+// SConMetadata::GetExifTagL( CExifRead* aReader, const TUint8 aTagID )
+// This function is used to read exif data that might leave.
+// -----------------------------------------------------------------------------
+//
+HBufC8* SConMetadata::GetExifTagL( CExifRead* aReader, const TUint8 aTagID )
+ {
+ TRACE_FUNC_ENTRY;
+ LOGGER_WRITE_1( " aTagID: 0x%02x", aTagID );
+ HBufC8* tempBuf( NULL );
+
+ switch( aTagID )
+ {
+ case KSconExifThumbnail:
+ tempBuf = aReader->GetThumbnailL();
+ break;
+ case KSconExifDescription:
+ tempBuf = aReader->GetImageDescriptionL();
+ break;
+ case KSconExifMake:
+ tempBuf = aReader->GetMakeL();
+ break;
+ case KSconExifModel:
+ tempBuf = aReader->GetModelL();
+ break;
+ case KSconExifDateTime:
+ tempBuf = aReader->GetDateTimeL();
+ break;
+ case KSconExifSoftware:
+ tempBuf = aReader->GetSoftwareL();
+ break;
+ case KSconExifCopyright:
+ tempBuf = aReader->GetCopyrightL();
+ break;
+ case KSconExifIsoSpeedRatings:
+ tempBuf = aReader->GetIsoSpeedRatingsL();
+ if ( tempBuf )
+ {
+ TInt isoSpeed = ReadTUint32( tempBuf->Des() );
+ LOGGER_WRITE_1(" isoSpeed: %d", isoSpeed);
+ delete tempBuf;
+
+ const TInt maxLength(5);
+ // no need to push on cleanupstack as leave cannot
+ // happen before returning tempBuf.
+ tempBuf = HBufC8::NewL(maxLength);
+ TPtr8 temp = tempBuf->Des();
+ temp.Num( isoSpeed );
+ }
+ break;
+ case KSconExifDateTimeOriginal:
+ tempBuf = aReader->GetDateTimeOriginalL();
+ break;
+ case KSconExifDateTimeDigitized:
+ tempBuf = aReader->GetDateTimeDigitizedL();
+ break;
+ case KSconExifMakerNote:
+ // makernote contents are up to the manufacturer
+ // not needed.
+ User::Leave( KErrNotSupported );
+ break;
+ case KSconExifUserComment:
+ tempBuf = aReader->GetUserCommentL();
+ break;
+ case KSconExifRelatedSoundFile:
+ tempBuf = aReader->GetRelatedSoundFileL();
+ break;
+ default:
+ User::Leave( KErrNotSupported );
+ }
+ TRACE_FUNC_EXIT;
+ return tempBuf;
+ }
+
+// -----------------------------------------------------------------------------
+// SConMetadata::ReadTUint32()
+// Convert 8-bit binary data to unsigned integer
+// -----------------------------------------------------------------------------
+//
+TUint32 SConMetadata::ReadTUint32( const TDesC8& aData )
+ {
+ TRACE_FUNC_ENTRY;
+ TUint32 result = 0;
+ TUint8 c;
+
+ for (TInt i=aData.Length()-1; i>=0; i--)
+ {
+ c = aData[i];
+ result = (result << 8) | c;
+ }
+
+ LOGGER_WRITE_1( "SConMetadata::ReadTUint32() : returned %d ", result );
+ return result;
+ }
+
+// -----------------------------------------------------------------------------
+// SConMetadata::GetFileDataLC()
+// Read data from file
+// -----------------------------------------------------------------------------
+//
+HBufC8* SConMetadata::GetFileDataLC( const TDesC& aFilename, RFs& aFs )
+ {
+ TRACE_FUNC_ENTRY;
+ RFile file;
+
+ User::LeaveIfError( file.Open( aFs, aFilename,
+ EFileRead | EFileShareReadersOnly ) );
+ CleanupClosePushL( file );
+
+ LOGGER_WRITE( "SConMetadata::GetFileDataLC() : file opened" );
+
+ TInt dataSize(0);
+ ContentAccess::CContent* content;
+ content = ContentAccess::CContent::NewLC( file );
+ ContentAccess::CData* data = content->OpenContentLC( ContentAccess::EPeek );
+ data->DataSizeL(dataSize);
+
+ LOGGER_WRITE( "SConMetadata::GetFileDataLC() : content opened" );
+ // Read 64k from the beginning of the file
+ if ( dataSize > KJpegLoadBufferSize )
+ {
+ dataSize = KJpegLoadBufferSize;
+ }
+ HBufC8* readBuffer = HBufC8::NewLC( dataSize );
+ TPtr8 readPtr = readBuffer->Des();
+ User::LeaveIfError( data->Read( readPtr, dataSize ) );
+
+ LOGGER_WRITE( "SConMetadata::GetFileDataLC() : data readed" );
+ CleanupStack::Pop( readBuffer );
+ CleanupStack::PopAndDestroy( data );
+ CleanupStack::PopAndDestroy( content );
+ CleanupStack::PopAndDestroy( &file );
+
+ CleanupStack::PushL( readBuffer );
+ TRACE_FUNC_EXIT;
+ return readBuffer;
+ }
+
+// -----------------------------------------------------------------------------
+// SConMetadata::ReadExifDataL()
+// Read Exif data
+// -----------------------------------------------------------------------------
+//
+void SConMetadata::ReadExifDataL( CSConTask& aTask, RFs& aFs )
+ {
+ TRACE_FUNC_ENTRY;
+
+ // read data from file
+ HBufC8* jpegReadBuffer = GetFileDataLC( aTask.iGetMetadataParams->iFilename, aFs );
+
+ CExifRead* reader = CExifRead::NewL(
+ *jpegReadBuffer, CExifRead::ENoJpeg | CExifRead::ENoTagChecking );
+
+ LOGGER_WRITE( "SConMetadata::ReadExifDataL() : reader created" );
+ CleanupStack::PopAndDestroy( jpegReadBuffer );
+ CleanupStack::PushL( reader );
+
+
+ CBufFlat* buffer = CBufFlat::NewL( KBufferSize );
+ CleanupStack::PushL( buffer );
+ buffer->Reset();
+
+
+ TInt offset(0);
+ // header id (1 byte) + head.version (1 byte) = 2 bytes
+
+ buffer->ExpandL( offset, 2 );
+
+ // header id
+ TUint8 value( KSconMetadataHeaderExif );
+ buffer->Write( offset, TPtrC8(&value, 1) );
+ offset++;
+
+ // header version
+ value = KSconMetadataHeaderVersion;
+ buffer->Write( offset, TPtrC8(&value, 1) );
+ offset++;
+
+
+ HBufC8* tempBuf(NULL);
+
+ TInt err;
+
+ for ( TInt tagID = KSconExifThumbnail; tagID < KSconExifGpsVersion; tagID++ )
+ {
+ // GetExifTagL function is used only to tags that leaves if data is not found
+ TRAP( err, tempBuf = GetExifTagL( reader, tagID ) );
+ if ( !err )
+ {
+ LOGGER_WRITE("write to buffer");
+ CleanupStack::PushL( tempBuf );
+ AppendByteDataFieldL( buffer, tempBuf->Des(), tagID );
+ CleanupStack::PopAndDestroy( tempBuf );
+ tempBuf = NULL;
+ }
+ else
+ {
+ LOGGER_WRITE_1( "GetExifTagL Leave code %d", err );
+ }
+ }
+
+
+ TUint16 value16a;
+ TUint32 value32a;
+ TUint32 value32b;
+ TInt32 val32a;
+ TInt32 val32b;
+
+ // Orientation
+ err = reader->GetOrientation( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifOrientation );
+ }
+
+ // XResolution
+ err = reader->GetXResolution( value32a, value32b );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifXResolution1 );
+ AppendTUintDataFieldL( buffer, value32b, KSconExifXResolution2 );
+ }
+
+ // YResolution
+ err = reader->GetYResolution( value32a, value32b );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifYResolution1 );
+ AppendTUintDataFieldL( buffer, value32b, KSconExifYResolution2 );
+ }
+
+ // ResolutionUnit
+ err = reader->GetResolutionUnit( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifResolutionUnit );
+ }
+
+ // YCbCrPositioning
+ err = reader->GetYCbCrPositioning( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifYCbCrPositioning );
+ }
+
+ // YCbCrPositioning
+ err = reader->GetYCbCrPositioning( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifYCbCrPositioning );
+ }
+
+
+ // ExposureTime
+ err = reader->GetExposureTime( value32a, value32b );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifExposureTime1 );
+ AppendTUintDataFieldL( buffer, value32b, KSconExifExposureTime2 );
+ }
+
+ // ComponentsConfiguration
+ TUint8 value8a;
+ TUint8 value8b;
+ TUint8 value8c;
+ TUint8 value8d;
+ err = reader->GetComponentsConfiguration( value8a, value8b, value8c, value8d );
+ if ( !err )
+ {
+ TInt offset;
+ offset = buffer->Size();
+
+ // field ID (1 byte) + field lenght (4 bytes) + field data (4bytes) = 9 bytes
+ buffer->ExpandL( offset, 9 );
+
+ // field id (one byte)
+ TUint8 fieldId( KSconExifComponentsConfiguration );
+ buffer->Write( offset, TPtrC8( &fieldId, 1 ) );
+ offset++;
+
+ // field lenght
+ WriteTUint32( buffer, offset, 4);
+ offset += 4;
+
+ buffer->Write( offset, TPtrC8(&value8a, 1) );
+ offset++;
+ buffer->Write( offset, TPtrC8(&value8b, 1) );
+ offset++;
+ buffer->Write( offset, TPtrC8(&value8c, 1) );
+ offset++;
+ buffer->Write( offset, TPtrC8(&value8d, 1) );
+ offset++;
+ }
+
+ // Flash
+ err = reader->GetFlash( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifFlash );
+ }
+
+ // ColorSpace
+ err = reader->GetColorSpace( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifColorSpace );
+ }
+
+ // PixelXDimension
+ err = reader->GetPixelXDimension( value32a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifPixelXDimension );
+ }
+
+ // PixelYDimension
+ err = reader->GetPixelYDimension( value32a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifPixelYDimension );
+ }
+
+ // ExposureMode
+ err = reader->GetExposureMode( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifExposureMode );
+ }
+
+ // WhiteBalance
+ err = reader->GetWhiteBalance( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifWhiteBalance );
+ }
+
+ // SceneCaptureType
+ err = reader->GetSceneCaptureType( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifSceneCaptureType );
+ }
+
+ // ExposureProgram
+ err = reader->GetExposureProgram( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifExposureProgram );
+ }
+
+ // GetApertureValue
+ err = reader->GetApertureValue( value32a, value32b );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifApertureValue1 );
+ AppendTUintDataFieldL( buffer, value32b, KSconExifApertureValue2 );
+ }
+
+ // GetExposureBiasValue
+ err = reader->GetExposureBiasValue( val32a, val32b );
+ if ( !err )
+ {
+ value32a = val32a;
+ value32b = val32b;
+ AppendTUintDataFieldL( buffer, value32a, KSconExifExposureBiasValue1 );
+ AppendTUintDataFieldL( buffer, value32b, KSconExifExposureBiasValue2 );
+ }
+
+ // GetMeteringMode
+ err = reader->GetMeteringMode( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifMeteringMode );
+ }
+
+ // GetLightSource
+ err = reader->GetLightSource( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifLightSource );
+ }
+
+ // GetFileSource
+ TInt8 val8;
+ err = reader->GetFileSource( val8 );
+ if ( !err )
+ {
+ value8a = val8;
+ AppendTUintDataFieldL( buffer, value8a, KSconExifFileSource );
+ }
+
+ // GetDigitalZoomRatio
+ err = reader->GetDigitalZoomRatio( value32a, value32b );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifDigitalZoomRatio1 );
+ AppendTUintDataFieldL( buffer, value32b, KSconExifDigitalZoomRatio2 );
+ }
+
+ // GetContrast
+ err = reader->GetContrast( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifContrast );
+ }
+
+ // GetSaturation
+ err = reader->GetSaturation( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifSaturation );
+ }
+
+ // GetSharpness
+ err = reader->GetSharpness( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifSharpness );
+ }
+
+ // GetExifVersion
+ err = reader->GetExifVersion( value32a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifExifVersion );
+ }
+
+ // GetFlashPixVersion
+ err = reader->GetFlashPixVersion( value32a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifFlashPixVersion );
+ }
+
+ // GetThumbnailXResolution
+ err = reader->GetThumbnailXResolution( value32a, value32b );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifThumbXResolution1 );
+ AppendTUintDataFieldL( buffer, value32b, KSconExifThumbXResolution2 );
+ }
+
+ // GetThumbnailYResolution
+ err = reader->GetThumbnailYResolution( value32a, value32b );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifThumbYResolution1 );
+ AppendTUintDataFieldL( buffer, value32b, KSconExifThumbYResolution2 );
+ }
+
+ // GetThumbnailResolutionUnit
+ err = reader->GetThumbnailResolutionUnit( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifThumbResolutionUnit );
+ }
+
+ // GetThumbnailCompression
+ err = reader->GetThumbnailCompression( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifThumbCompression );
+ }
+
+ // GetJpegInterchangeFormat
+ err = reader->GetJpegInterchangeFormat( value32a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifThumbJpegInterchangeFormat );
+ }
+
+ // GetJpegInterchangeFormatLength
+ err = reader->GetJpegInterchangeFormatLength( value32a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifThumbJpegInterchangeFormatLength );
+ }
+
+ // GetShutterSpeedValue
+ err = reader->GetShutterSpeedValue( val32a, val32b );
+ if ( !err )
+ {
+ value32a = val32a;
+ value32b = val32b;
+ AppendTUintDataFieldL( buffer, value32a, KSconExifShutterSpeedValue1 );
+ AppendTUintDataFieldL( buffer, value32b, KSconExifShutterSpeedValue2 );
+ }
+
+ // GetBrightnessValue
+ err = reader->GetBrightnessValue( val32a, val32b );
+ if ( !err )
+ {
+ value32a = val32a;
+ value32b = val32b;
+ AppendTUintDataFieldL( buffer, value32a, KSconExifBrightnessValue1 );
+ AppendTUintDataFieldL( buffer, value32b, KSconExifBrightnessValue2 );
+ }
+
+ // GetCustomRendered
+ err = reader->GetCustomRendered( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifCustomRendered );
+ }
+
+ // GetGainControl
+ err = reader->GetGainControl( value16a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value16a, KSconExifGainControl );
+ }
+
+ // GetGpsVersion
+ err = reader->GetGpsVersion( value32a );
+ if ( !err )
+ {
+ AppendTUintDataFieldL( buffer, value32a, KSconExifGpsVersion );
+ }
+
+ // Get GPS coordinates
+ const TUint KCoordinatesMaxLength = 50;
+ TBuf<KCoordinatesMaxLength> gpsInfo;
+ // Latidute
+ err = GetExifGPSLatitudeL( *reader, gpsInfo );
+ if ( !err )
+ {
+ AppendUtf8DataFieldL( buffer, gpsInfo ,KSconExifGPSLatitude );
+ }
+
+ // Longitude
+ err = GetExifGPSLongitudeL( *reader, gpsInfo );
+ if ( !err )
+ {
+ AppendUtf8DataFieldL( buffer, gpsInfo ,KSconExifGPSLongitude );
+ }
+
+ // Altidute
+ err = GetExifGPSAltiduteL( *reader, gpsInfo );
+ if ( !err )
+ {
+ AppendUtf8DataFieldL( buffer, gpsInfo ,KSconExifGPSAltitude );
+ }
+
+ LOGGER_WRITE( "SConMetadata::ReadExifDataL() : All data collected" );
+
+ if ( buffer->Size() > 0 )
+ {
+ LOGGER_WRITE_1( "SConMetadata::ReadExifDataL() : buffer->Size() %d", buffer->Size() );
+ if ( aTask.iGetMetadataParams->iData )
+ {
+ delete aTask.iGetMetadataParams->iData;
+ aTask.iGetMetadataParams->iData = NULL;
+ }
+ //Initialize the task data buffer
+ aTask.iGetMetadataParams->iData = HBufC8::NewL( buffer->Size() );
+ TPtr8 dataPtr = aTask.iGetMetadataParams->iData->Des();
+
+ buffer->Read( 0, dataPtr, buffer->Size() );
+ LOGGER_WRITE_1( "SConMetadata::ReadExifDataL() dataPtr len: %d", dataPtr.Length());
+ }
+ CleanupStack::PopAndDestroy( buffer );
+
+ LOGGER_WRITE( "SConMetadata::ReadExifDataL() : task updated" );
+
+ CleanupStack::PopAndDestroy( reader );
+ TRACE_FUNC_EXIT;
+ }
+
+// -----------------------------------------------------------------------------
+// void SConMetadata::ConvertRationalTag( const CExifTag& aTag, TDes& aPosDegrees )
+// parses degrees, minutes and seconds from CExifTag and converts it to string format
+// -----------------------------------------------------------------------------
+//
+TInt SConMetadata::ConvertRationalTag( const CExifTag& aTag, TDes& aPosDegrees )
+ {
+ TRACE_FUNC_ENTRY;
+ TInt numer(0);
+ TInt denom(0);
+ TReal64 degrees(0);
+ TReal64 minutes(0);
+ TReal64 seconds(0);
+
+ const TUint8* ratData = aTag.Data().Ptr();
+ for ( TUint y=0; y < aTag.TagInfo().iDataCount; y++ )
+ {
+ numer = 0;
+ denom = 0;
+ Mem::Copy(&numer, ratData + ((y * 2) * sizeof(numer)), sizeof(numer));
+ Mem::Copy(&denom, ratData + (((y * 2) + 1) * sizeof(numer)), sizeof(denom));
+ if (denom != 0)
+ {
+ if ( y == 0 )// degrees
+ {
+ degrees = numer/denom;
+ }
+ else if ( y == 1 )// minutes
+ {
+ minutes = numer/denom;
+ }
+ else if ( y == 2 )// seconds
+ {
+ seconds = numer/denom;
+ }
+ }
+ }
+ _LIT(KFormat, "%.0f°%.0f'%.2f\"" );
+ aPosDegrees.Format( KFormat, degrees, minutes, seconds );
+ TRACE_FUNC_EXIT;
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// void SConMetadata::GetExifGPSLatitudeL( CExifRead& aExifRead, TDes& aLatitude )
+// Read latidute from ExifReader
+// -----------------------------------------------------------------------------
+//
+TInt SConMetadata::GetExifGPSLatitudeL( CExifRead& aExifRead, TDes& aLatitude )
+ {
+ TRACE_FUNC_ENTRY;
+ TInt ret(KErrNone);
+ if ( aExifRead.TagExists( KGPSLatitudeRef, EIfdGps )
+ && aExifRead.TagExists( KGPSLatitude, EIfdGps) )
+ {
+ // get latidute
+ const CExifTag* lat = aExifRead.GetTagL(
+ EIfdGps,
+ KGPSLatitude );
+ User::LeaveIfError( ConvertRationalTag( *lat, aLatitude ) );
+ if ( aLatitude.Length()+2 > aLatitude.MaxLength() )
+ {
+ User::Leave( KErrTooBig );
+ }
+
+ // south or north
+ const CExifTag* latRef = aExifRead.GetTagL(
+ EIfdGps,
+ KGPSLatitudeRef );
+ _LIT8( KNorthTagDef8, "N" );
+ _LIT( KNorth, "N " );
+ _LIT( KSouth, "S " );
+ if ( latRef->Data().Find( KNorthTagDef8 ) != KErrNotFound )
+ {
+ aLatitude.Insert( 0, KNorth );
+ }
+ else
+ {
+ aLatitude.Insert( 0, KSouth );
+ }
+ }
+ else
+ {
+ ret=KErrNotFound;
+ }
+ TRACE_FUNC_EXIT;
+ return ret;
+ }
+
+// -----------------------------------------------------------------------------
+// void SConMetadata::GetExifGPSLongitudeL( CExifRead& aExifRead, TDes& aLongitude )
+// Read longitude from ExifReader
+// -----------------------------------------------------------------------------
+//
+TInt SConMetadata::GetExifGPSLongitudeL( CExifRead& aExifRead, TDes& aLongitude )
+ {
+ TRACE_FUNC_ENTRY;
+ TInt ret(KErrNone);
+ if ( aExifRead.TagExists( KGPSLongitudeRef, EIfdGps )
+ && aExifRead.TagExists( KGPSLongitude, EIfdGps) )
+ {
+ // get longitude
+ const CExifTag* lon = aExifRead.GetTagL(
+ EIfdGps,
+ KGPSLongitude );
+ User::LeaveIfError( ConvertRationalTag( *lon, aLongitude ) );
+ if ( aLongitude.Length()+2 > aLongitude.MaxLength() )
+ {
+ User::Leave( KErrTooBig );
+ }
+
+ // east or west
+ const CExifTag* lonref = aExifRead.GetTagL(
+ EIfdGps,
+ KGPSLongitudeRef );
+ _LIT8( KEastTagDef8, "E" );
+ _LIT( KEast, "E " );
+ _LIT( KWest, "W " );
+ if ( lonref->Data().Find( KEastTagDef8 ) != KErrNotFound )
+ {
+ aLongitude.Insert( 0, KEast );
+ }
+ else
+ {
+ aLongitude.Insert( 0, KWest );
+ }
+ }
+ else
+ {
+ ret = KErrNotFound;
+ }
+ TRACE_FUNC_EXIT;
+ return ret;
+ }
+
+// -----------------------------------------------------------------------------
+// void SConMetadata::GetExifGPSAltiduteL( CExifRead& aExifRead, TDes& aAltidute )
+// Read altidute from ExifReader
+// -----------------------------------------------------------------------------
+//
+TInt SConMetadata::GetExifGPSAltiduteL( CExifRead& aExifRead, TDes& aAltidute )
+ {
+ TRACE_FUNC_ENTRY;
+
+ TInt ret(KErrNone);
+ if ( aExifRead.TagExists( KGPSAltitudeRef, EIfdGps )
+ && aExifRead.TagExists( KGPSAltitude, EIfdGps) )
+ {
+ if ( aAltidute.MaxLength() < 5 )
+ {
+ User::Leave( KErrTooBig );
+ }
+
+ // get altidute
+ const CExifTag* alt = aExifRead.GetTagL(
+ EIfdGps,
+ KGPSAltitude );
+ const TUint8* ratData = alt->Data().Ptr();
+
+ TInt numer;
+ TInt denom;
+ Mem::Copy(&numer, ratData , sizeof(numer));
+ Mem::Copy(&denom, ratData + (sizeof(numer)), sizeof(denom));
+
+ TReal32 tmp = numer / denom;
+
+ // sea level
+ const CExifTag* altref = aExifRead.GetTagL(
+ EIfdGps,
+ KGPSAltitudeRef );
+ _LIT8( KAltSealevelDef8, "1" );
+ if ( altref->Data().Find( KAltSealevelDef8 ) != KErrNotFound )
+ {
+ // seaLevelReference -> negative value
+ tmp *= -1;
+ }
+ TRealFormat format;
+ format.iType = KRealFormatFixed;
+ format.iPlaces=1;
+ User::LeaveIfError( aAltidute.Num( tmp, format ) );
+ }
+ else
+ {
+ ret = KErrNotFound;
+ }
+ TRACE_FUNC_EXIT;
+ return ret;
+ }
+
+// -----------------------------------------------------------------------------
+// void SConMetadata::AppendUtf8DataFieldL( CBufFlat* aBuffer,
+// const TPtrC aAppendData, const TUint8 aFieldId )
+// Write 8bit field id value, data length (32bit) and UTF8 data to buffer
+// -----------------------------------------------------------------------------
+//
+void SConMetadata::AppendUtf8DataFieldL( CBufFlat* aBuffer,
+ const TPtrC aAppendData, const TUint8 aFieldId )
+ {
+ TRACE_FUNC_ENTRY;
+ LOGGER_WRITE_1( "aFieldId: 0x%02x", aFieldId);
+ HBufC8* tempBuf = HBufC8::NewLC( aAppendData.Size() );
+ TPtr8 temp = tempBuf->Des();
+
+ CnvUtfConverter::ConvertFromUnicodeToUtf8( temp, aAppendData );
+ LOGGER_WRITE_1( "lenght: %d", temp.Length() );
+
+ if ( temp.Length() > KFieldMaxLength )
+ {
+ LOGGER_WRITE("Data length is too big, field skipped");
+ CleanupStack::PopAndDestroy( tempBuf );
+ return;
+ }
+
+ TInt offset;
+ offset = aBuffer->Size();
+ // field ID (1 byte) + field lenght (4 bytes) + field data
+ aBuffer->ExpandL( offset, temp.Length() + 5 );
+
+ // field id (one byte)
+ aBuffer->Write( offset, TPtrC8(&aFieldId, 1) );
+ offset++;
+
+ WriteTUint32( aBuffer, offset, temp.Length());
+ offset += 4;
+
+ // field data
+ aBuffer->Write( offset, temp, temp.Length() );
+ offset += temp.Length();
+
+ CleanupStack::PopAndDestroy( tempBuf );
+
+ TRACE_FUNC_EXIT;
+ }
+
+// -----------------------------------------------------------------------------
+// void SConMetadata::AppendByteDataFieldL( CBufFlat* aBuffer,
+// const TPtrC8 aAppendData, const TUint8 aFieldId )
+// Write 8bit field id value, data length (32bit) and n*8bit data to buffer
+// -----------------------------------------------------------------------------
+//
+void SConMetadata::AppendByteDataFieldL( CBufFlat* aBuffer,
+ const TPtrC8 aAppendData, const TUint8 aFieldId )
+ {
+ TRACE_FUNC_ENTRY;
+ LOGGER_WRITE_1( "aFieldId: 0x%02x", aFieldId);
+ LOGGER_WRITE_1( "lenght: %d", aAppendData.Length() );
+ if ( aAppendData.Length() > KFieldMaxLength )
+ {
+ LOGGER_WRITE("Data length is too big, field skipped");
+ return;
+ }
+ TInt offset;
+ offset = aBuffer->Size();
+
+ // field id (1) + field len (4) + datalen = 5 + datalen
+ aBuffer->ExpandL( offset, aAppendData.Length() + 5 );
+
+ // field id (one byte)
+ aBuffer->Write( offset, TPtrC8(&aFieldId, 1) );
+ offset++;
+
+ // field data length (32bit unsigned integer, two byte)
+ WriteTUint32( aBuffer, offset, aAppendData.Length() );
+ offset += 4;
+
+ // field data
+ aBuffer->Write( offset, aAppendData );
+ offset += aAppendData.Length();
+
+ TRACE_FUNC_EXIT;
+ }
+
+// -----------------------------------------------------------------------------
+// void SConMetadata::AppendTUintDataFieldL( CBufFlat* aBuffer,
+// const TUint32 aValue, const TUint8 aFieldId )
+// Write 8bit field id value, data length (16bit) and n*8bit data to buffer
+// -----------------------------------------------------------------------------
+//
+void SConMetadata::AppendTUintDataFieldL( CBufFlat* aBuffer,
+ TUint32 aValue, const TUint8 aFieldId )
+ {
+ TRACE_FUNC_ENTRY;
+ LOGGER_WRITE_1( "aFieldId: 0x%02x", aFieldId);
+ LOGGER_WRITE_1( "aValue dec: %u", aValue);
+ TInt offset;
+ offset = aBuffer->Size();
+ TInt dataLen(1);
+ TUint8 temp[4];
+ TInt i(0);
+
+ temp[i] = aValue & 0xFF;
+
+ aValue >>= 8;
+ while( aValue > 0 )
+ {
+ i++;
+ temp[i] = aValue & 0xFF;
+ aValue >>= 8;
+ dataLen++;
+ }
+ // field id (1) + field len (4) + datalen = 5 + datalen
+ aBuffer->ExpandL( offset, 5 + dataLen );
+
+ // field id (one byte)
+ aBuffer->Write( offset, TPtrC8(&aFieldId, 1) );
+ offset++;
+
+ // field data length (32bit unsigned integer, two byte)
+ WriteTUint32( aBuffer, offset, dataLen );
+ offset += 4;
+
+ // field data
+ for( TInt i = dataLen-1; i>=0; i-- )
+ {
+ aBuffer->Write( offset, TPtrC8(&temp[i], 1) );
+ offset++;
+ }
+
+ TRACE_FUNC_EXIT;
+ }
+
+// -----------------------------------------------------------------------------
+// void SConMetadata::WriteTUint32( CBufFlat* aBuffer, TInt offset, TUint32 aValue )
+// Write 32bit unsigned integer value to buffer.
+// -----------------------------------------------------------------------------
+//
+void SConMetadata::WriteTUint32( CBufFlat* aBuffer, TInt offset, TUint32 aValue )
+ {
+ TUint8 temp[4];
+ TInt i(0);
+
+ temp[i] = aValue & 0xFF;
+
+ aValue >>= 8;
+ for ( TInt i=1; i<4; i++ )
+ {
+ temp[i] = aValue & 0xFF;
+ aValue >>= 8;
+ }
+
+ // high to low
+ for ( TInt i=3; i>=0; i-- )
+ {
+ aBuffer->Write( offset, TPtrC8(&temp[i], 1) );
+ offset++;
+ }
+ }
+
+// End of file