upnpavcontroller/upnpavcontrollerhelper/src/upnptranscodehelper.cpp
branchIOP_Improvements
changeset 40 08b5eae9f9ff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/upnpavcontroller/upnpavcontrollerhelper/src/upnptranscodehelper.cpp	Wed Nov 03 11:45:09 2010 +0200
@@ -0,0 +1,426 @@
+/*
+* Copyright (c) 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:  Implementation of UPnP transcode helper
+*
+*/
+#include <bautils.h> //hack
+
+#include <upnpitem.h>
+#include <upnpstring.h>
+#include <upnpdlnaprotocolinfo.h>
+
+#include <upnpgstwrapper.h>
+#include <upnprenderercfg.h>
+#include <upnprenderercfgparser.h>
+
+#include "upnpitemutility.h"
+#include "upnpavdevice.h"
+
+#include "upnptranscodehelper.h"
+
+_LIT( KComponentLogfile, "upnptranscodehelper.txt");
+#include "upnplog.h"
+
+#define __FUNC_LOG __LOG8_1( "%s", __PRETTY_FUNCTION__ );
+
+_LIT( KRendererCfgFile, "C:\\data\\UpnpCfgs.xml" );
+
+_LIT( KTranscodedFlag, "?transcoded=true" );
+
+_LIT8( KSymbianDirDelimiter, "\\" );
+_LIT8( KLinuxDirDelimiter, "/" );
+_LIT8( KProtocolInfo, "protocolInfo" );
+_LIT8( KRes, "res" );
+
+// These are for Transport Stream muxer checking (from pipeline)
+_LIT8( KMpegTsMux, "mpegtsmux" );
+_LIT8( KFFMuxMpegTs, "ffmux_mpegts" );
+
+// These are for Transport Stream support checking
+_LIT8( KTsProtocolInfoIdentifier, "_TS_" );
+_LIT8( KAllMpegMimeTypes, "video/mpeg:*" );
+
+// This is for MP4 support checking 
+_LIT8( KMp4MimeType, "video/mp4" );
+
+// The pipeline is currently hardcoded (except input file)
+_LIT8( KDefaultPipelineFmt, 
+"mpegtsmux output-buf-size=0x7FCCC name=mux ! appsink max-buffers=10 name=sinkbuffer filesrc \
+location=%S ! qtdemux name=demux ! queue max-size-bytes=0xAAAA ! mux. demux. ! \
+queue max-size-bytes=0xAAAA ! mux.");
+
+const TInt KLocationFmtTagLen = 2;
+
+CUpnpTranscodeHelper* CUpnpTranscodeHelper::NewL()
+    {
+    __FUNC_LOG;
+    
+    CUpnpTranscodeHelper* self = new ( ELeave ) CUpnpTranscodeHelper();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+CUpnpTranscodeHelper::~CUpnpTranscodeHelper()
+    {
+    __FUNC_LOG;
+    
+    iGstWrapper->RemoveObserver( *this );
+    iGstWrapper->Close();
+    iFs.Close();
+    }
+
+void CUpnpTranscodeHelper::PreDefinedCfgL( const CUpnpAVDevice& aRenderer, 
+        CUpnpItem& aUpnpItem, HBufC8*& aPipeline,
+        HBufC8*& aProtocolInfo )
+    {
+    __FUNC_LOG;
+    
+    //fetch mimetype and filename from original resource
+    RUPnPElementsArray resources;
+    CleanupClosePushL( resources );
+    UPnPItemUtility::GetResElements( aUpnpItem, resources );
+    TInt resourcesCount = resources.Count();
+    if ( resourcesCount == 0 )
+        {
+        User::Leave( KErrNotFound );
+        }         
+
+    const CUpnpAttribute& originalProtocolInfoDesc = 
+             UPnPItemUtility::FindAttributeByNameL( 
+             *resources[0], KProtocolInfo ); 
+    
+    CUpnpDlnaProtocolInfo* originalProtocolInfo = 
+            CUpnpDlnaProtocolInfo::NewL( originalProtocolInfoDesc.Value() );
+    CleanupStack::PushL( originalProtocolInfo );            
+    
+    //create config for renderer
+    CUpnpRendererCfg* config = CUpnpRendererCfg::NewLC( KRendererCfgFile, 
+            aRenderer.ModelName(), originalProtocolInfo->ThirdField() );    
+    
+    CUpnpRendererCfgParser* parser = CUpnpRendererCfgParser::NewLC();   
+        
+    parser->ParseRendererCfgL( *config );
+    
+    HBufC8* srcFileName8 = PathToLinuxSyntaxL( resources[0]->FilePath() );
+    CleanupStack::PushL( srcFileName8 );
+    
+    HBufC8* pipeline = HBufC8::NewLC( config->Pipeline().Length() + 
+            srcFileName8->Length() - KLocationFmtTagLen );    
+    pipeline->Des().AppendFormat( config->Pipeline(), srcFileName8 );
+      
+    HBufC8* protocolInfo = config->ProtocolInfo().AllocL();
+
+    RFile file;
+    User::LeaveIfError( file.Open(iFs,resources[0]->FilePath(),EFileRead) );
+    CleanupClosePushL(file);
+    TInt size(KErrNotFound);
+    User::LeaveIfError( file.Size(size) );
+    iGstWrapper->SetTranscodedFileSize( config->SizeMultiplier()*size );
+    CleanupStack::PopAndDestroy(&file);
+    
+    CleanupStack::Pop( pipeline );
+    CleanupStack::PopAndDestroy( srcFileName8 );
+    CleanupStack::PopAndDestroy( parser );
+    CleanupStack::PopAndDestroy( config );
+    CleanupStack::PopAndDestroy( originalProtocolInfo );
+    CleanupStack::PopAndDestroy( &resources );
+    
+    aPipeline = pipeline;
+    aProtocolInfo = protocolInfo;
+    }
+
+HBufC8* CUpnpTranscodeHelper::PipelineL( CUpnpItem& aUpnpItem, 
+        const CDesC8Array& aRendererProtocolInfos )
+    {
+    __FUNC_LOG;
+    
+    HBufC8* pipeline = NULL;
+    TBool protocolMatch = EFalse;
+    TContainerType srcContainerType = EUnknownContainer;
+    TContainerType destContainerType = EUnknownContainer;
+
+    //Get resources from the current upnp item
+    RUPnPElementsArray resources;
+    CleanupClosePushL( resources );
+    UPnPItemUtility::GetResElements( aUpnpItem, resources );
+    TInt resourcesCount = resources.Count();
+    if ( resourcesCount == 0 )
+        {
+        User::Leave( KErrNotFound );
+        }    
+
+    //Check if suitable source container is found from 1st resource
+    const CUpnpAttribute& originalProtocolInfo = 
+            UPnPItemUtility::FindAttributeByNameL( 
+            *resources[0], KProtocolInfo ); 
+            
+    if( originalProtocolInfo.Value().Find( KMp4MimeType ) )
+        {
+        srcContainerType = EMp4Container; 
+        }
+    else
+        {
+        User::Leave( KErrNotSupported );
+        }        
+
+    //Loop through all protocol infos from renderer and try to find suitable        
+    TInt rendererProtocolInfoCount = aRendererProtocolInfos.Count(); 
+    for( TInt i = 0; i < rendererProtocolInfoCount && !protocolMatch; i++ )
+        {
+        for( TInt j = 0; j < resourcesCount && !protocolMatch; j++ )
+            {
+            const TDesC8& protocolInfo = 
+            UPnPItemUtility::FindAttributeByNameL( 
+                    *resources[j], KProtocolInfo ).Value();        
+
+            const TDesC8& rendererProtocolInfo = 
+            aRendererProtocolInfos.MdcaPoint(i);
+
+            if( rendererProtocolInfo.Find( protocolInfo ) != KErrNotFound )
+                {                                
+                protocolMatch = ETrue;
+                //breaks both 'for' loops here    
+                }
+
+            //Check if protocol info is supported 
+            if( destContainerType == EUnknownContainer &&
+                ( rendererProtocolInfo.Find( 
+                      KTsProtocolInfoIdentifier ) != KErrNotFound || 
+                  rendererProtocolInfo.Find(
+                      KAllMpegMimeTypes ) != KErrNotFound ) ) 
+                {
+                destContainerType = ETsContainer; 
+                }
+            //TODO: add here other supported containers (muxers) as well
+
+            }        
+        }
+
+    if( !protocolMatch )
+        {               
+        HBufC8* filePath = PathToLinuxSyntaxL( resources[0]->FilePath() );     
+        CleanupStack::PushL( filePath );            
+        pipeline = GeneratePipelineL( *filePath, destContainerType );        
+        CleanupStack::PopAndDestroy( filePath );                
+        }
+
+    CleanupStack::PopAndDestroy( &resources );
+
+    return pipeline;
+    }
+
+void CUpnpTranscodeHelper::ReplaceResourceL( CUpnpItem& aUpnpItem, 
+                                             const TDesC8& aProtocolInfo )
+    {
+    RUPnPElementsArray& elements = const_cast<RUPnPElementsArray&>(
+                    aUpnpItem.GetElements());
+
+    for( TInt resIndex(0); resIndex < elements.Count(); ++resIndex )
+        {
+        if( elements[resIndex]->Name() == KRes )
+            {
+            HBufC* tmp = HBufC::NewLC( 
+                    elements[resIndex]->FilePath().Length() +
+                    KTranscodedFlag().Length() );
+            tmp->Des().Append( elements[resIndex]->FilePath() );
+            tmp->Des().Append( KTranscodedFlag() );
+            elements.Remove( resIndex );
+            aUpnpItem.AddResourceL( *tmp, aProtocolInfo );
+            CleanupStack::PopAndDestroy( tmp );
+            break;
+            }
+        }
+    }
+
+void CUpnpTranscodeHelper::TranscodeL( const TDesC8& aPipeline )
+    {
+    __FUNC_LOG;
+    
+    //iGstWrapper->StartL( aPipeline ); 
+    iGstWrapper->SetPipelineL( aPipeline );
+    
+    //should we wait here until we get pipeline playing state notification
+    //or error ;)
+    }
+
+
+void CUpnpTranscodeHelper::AddValidResElementL( 
+        CUpnpItem& aUpnpItem, const TDesC8& aPipeline, 
+        const CDesC8Array& aRendererProtocolInfos )
+    {
+    __FUNC_LOG;
+    
+    TBool suitableFound = EFalse;
+    const TDesC8* protocolInfoIdentifier = NULL;
+
+    //TODO: Add also other supported containers (muxers)
+    if( aPipeline.Find( KMpegTsMux ) != KErrNotFound || 
+        aPipeline.Find( KFFMuxMpegTs ) != KErrNotFound )        
+        {
+        protocolInfoIdentifier = &KTsProtocolInfoIdentifier(); 
+        }
+    else
+        {
+        User::Leave( KErrNotSupported );
+        }
+
+    TInt rendererProtocolInfoCount = aRendererProtocolInfos.Count();
+
+    if( rendererProtocolInfoCount == 0 )
+        {
+        User::Leave(KErrNotFound);
+        }
+
+    //Get resources from the current upnp item
+    RUPnPElementsArray resources;
+    CleanupClosePushL( resources );
+    UPnPItemUtility::GetResElements( aUpnpItem, resources );
+    TInt resourcesCount = resources.Count();
+    if ( resourcesCount == 0 )
+        {
+        User::Leave( KErrNotFound );
+        }  
+    
+    for( TInt i = 0; i < rendererProtocolInfoCount && !suitableFound; i++ )
+        {           
+        TPtrC8 rendererProtocolInfo = aRendererProtocolInfos.MdcaPoint(i);
+        if( rendererProtocolInfo.Find( *protocolInfoIdentifier ) )
+            {
+            //TODO: Add only suitable ones -- now adds all protocol infos
+            //      from renderer, which contains _TS_ sub-string
+            const TDesC& originalFilePath = resources[0]->FilePath();
+            HBufC* transcodedFilePath = HBufC::NewL( 
+                    originalFilePath.Length() + KTranscodedFlag().Length() );
+            CleanupStack::PushL( transcodedFilePath );
+            
+            
+            transcodedFilePath->Des().Append( originalFilePath );
+            transcodedFilePath->Des().Append( KTranscodedFlag );
+        
+            aUpnpItem.AddResourceL( *transcodedFilePath, 
+                    rendererProtocolInfo );
+            
+            CleanupStack::PopAndDestroy( transcodedFilePath );
+            
+            suitableFound = ETrue;
+            }                
+        }
+
+    CleanupStack::PopAndDestroy( &resources );
+    
+    if( !suitableFound )
+        {
+        User::Leave( KErrNotFound );
+        }    
+    else
+        {
+        // delete orig.
+        RUPnPElementsArray& elements = const_cast<RUPnPElementsArray&>(
+                aUpnpItem.GetElements());
+
+        for( TInt resIndex(0); resIndex < elements.Count(); ++resIndex )
+            {
+            if( elements[resIndex]->Name() == KRes )
+                {
+                elements.Remove(resIndex);
+                break;
+                }
+            }
+        }
+    }
+
+CUpnpTranscodeHelper::CUpnpTranscodeHelper()
+    {
+    __FUNC_LOG;    
+    }
+
+void CUpnpTranscodeHelper::ConstructL()
+    {
+    __FUNC_LOG;    
+    
+    iGstWrapper = CUpnpGstWrapper::GetInstanceL();    
+    iGstWrapper->SetObserverL( *this );
+    User::LeaveIfError( iFs.Connect() );
+    }
+
+HBufC8* CUpnpTranscodeHelper::GeneratePipelineL( 
+        const TDesC8& aOriginalFilePath, 
+        TContainerType aDestContainerType )
+    {    
+    __FUNC_LOG;
+    
+    if( aDestContainerType == EUnknownContainer )
+        {
+        User::Leave( KErrNotSupported );
+        }    
+
+    HBufC8* pipeline = NULL;     
+    
+    switch( aDestContainerType )
+        {
+        case ETsContainer:
+            {
+            //TODO ??
+            pipeline = HBufC8::NewL( KDefaultPipelineFmt().Length() - 
+                    KLocationFmtTagLen + aOriginalFilePath.Length() );            
+            pipeline->Des().AppendFormat( KDefaultPipelineFmt, 
+                    &aOriginalFilePath );
+            break;
+            }
+        default:
+            {
+            __ASSERT_ALWAYS( 0, User::Invariant() );
+            }
+        }
+    
+    return pipeline; 
+    }
+
+HBufC8* CUpnpTranscodeHelper::PathToLinuxSyntaxL( 
+        const TDesC& aOriginalPath )
+    {
+    __FUNC_LOG;
+    
+    HBufC8* newFilePath = UpnpString::FromUnicodeL( aOriginalPath );
+     
+    TInt index = 0;
+    while( index >= 0 )
+        {
+        index = newFilePath->Find( KSymbianDirDelimiter );
+        if( index >= 0 )
+            {
+            newFilePath->Des().Replace( index, 
+                    KSymbianDirDelimiter().Length(), KLinuxDirDelimiter );
+            }
+        }    
+    
+    return newFilePath;
+    }
+
+void CUpnpTranscodeHelper::HandleGstEvent( Gst::TEvent aEvent )
+    {
+    __FUNC_LOG;
+    
+    if( aEvent == Gst::EError )
+        {
+        __LOG1( "CUpnpTranscodeHelper::HandleGstEvent ErrorMsg: %S",
+                iGstWrapper->ErrorMsg() );
+        __ASSERT( EFalse, __FILE__, __LINE__ );
+        }
+    }
+
+
+// end of file