Fixed AVController, it was accidentally set to search only for renderers. Now also servers are added to device list. Also some minor changes in package definition xml and platform API xml definition files.
/*
* 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