Symbian
Symbian OS Library

SYMBIAN OS V9.3

[Index] [Spacer] [Previous] [Next]



MmfExSinkSource: Multimedia Framework sink/source plug-ins example

Found in: Examples\MultiMedia\MmfExSinkSource\

These are the main files contained in the examples. Some extra files may be needed to run the examples, and these will be found in the appropriate examples directory.

//
// main.cpp
// Copyright 1997-2005 Symbian Software Ltd.  All rights reserved.
//

// __________________________________________________________________________
// Exported proxy for instantiation method resolution
// Define the interface UIDs

#include <ImplementationProxy.h>
#include "mmfexdes.h"
#include "MmfExSinkSourceUIDs.hrh"

const TImplementationProxy ImplementationTable[] = 
    {
        IMPLEMENTATION_PROXY_ENTRY(KDescriptorSourceUID,    CMMFExDescriptor::NewSourceL),
        IMPLEMENTATION_PROXY_ENTRY(KDescriptorSinkUID,  CMMFExDescriptor::NewSinkL)
    };

EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
    {
    aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);

    return ImplementationTable;
    }

// mmfdes.cpp
//
// Copyright 1997-2005 Symbian Software Ltd.  All rights reserved.
//


#include <f32file.h>
#include <E32Std.h>
#include <mmfdatabuffer.h>

#include "mmfexdes.h"
#include "MmfExSinkSourceUIDs.hrh"

// Panic function
void Panic(TMMFExDescriptorPanicCode aPanicCode)
    {
    _LIT(KMMFExDescriptorPanicCategory, "MMFExDescriptor");
    User::Panic(KMMFExDescriptorPanicCategory, aPanicCode);
    }

//
// CMMFExDescriptor
//

// Plugin implementation UIDs
const TUid KDescriptorSourceUIDObject = {KDescriptorSourceUID};
const TUid KDescriptorSinkUIDObject   = {KDescriptorSinkUID};

// Constructor
CMMFExDescriptor::CMMFExDescriptor( ) : CMMFClip( TUid(KDescriptorSourceUIDObject), TUid(KDescriptorSinkUIDObject )) 
    {
    iOffset = 0 ;
    }

// Destructor
CMMFExDescriptor::~CMMFExDescriptor()
    {
    iDesThread.Close() ;
    }

// Factory function for source plug-in
MDataSource* CMMFExDescriptor::NewSourceL( )
    {
    CMMFExDescriptor* self = new (ELeave) CMMFExDescriptor( ) ;
    return STATIC_CAST( MDataSource*, self ) ;
    }
    
// Factory function for sink plug-in
MDataSink* CMMFExDescriptor::NewSinkL( )
    {
    CMMFExDescriptor* self = new (ELeave) CMMFExDescriptor( ) ;
    return STATIC_CAST( MDataSink*, self ) ;
    }

// MDataSource factory
// aInitData is a packaged TMMFExDescriptorParams
void CMMFExDescriptor::ConstructSourceL( const TDesC8& aInitData )
    {
    ConstructL( aInitData ) ;
    }

// MDataSink factory
// aInitData is a packaged TMMFExDescriptorParams
void CMMFExDescriptor::ConstructSinkL( const TDesC8& aInitData )
    {
    ConstructL( aInitData ) ;
    }

// Construction helper
// aInitData is a packaged TMMFExDescriptorParams
void CMMFExDescriptor::ConstructL( const TDesC8& aInitData ) 
    {
    // get descriptor to which to read/write, and the thread 
    // to which it belongs
    TMMFExDescriptorParams params;
    TPckgC<TMMFExDescriptorParams> config(params);
    config.Set(aInitData);
    iDes = STATIC_CAST( TDes8*, config().iDes);
    User::LeaveIfError( iDesThread.Open( config().iDesThreadId ) );
    }


// From MDataSource

TFourCC CMMFExDescriptor::SourceDataTypeCode(TMediaId /*aMediaId*/) 
    {
    return iSourceFourCC ;
    }

// Fills a buffer from the source descriptor
void CMMFExDescriptor::FillBufferL( CMMFBuffer* aBuffer, MDataSink* aConsumer, TMediaId /*aMediaId*/  ) 
    {
    // Current position in Descriptor is iOffset.

    // Read from iDes in iDesThread into Des in aBuffer.

    // Assume that the amount to be read is the size of the buffer descriptor
    // Should check that there is sufficient data in the source buffer
    // If there is not enough to fill the target then copy what there is

    // Use of a single iOffset will preclude use by more than one client (use ReadBufferL())
    if ( aBuffer->Type() == KUidMmfDataBuffer  ) 
        {
        TDes8& bufferDes = STATIC_CAST(CMMFDataBuffer*, aBuffer)->Data();
        TInt targetMaxLength = bufferDes.MaxLength();
        TInt sourceLength = iDes->Length();
        
        if ( ( sourceLength - iOffset - targetMaxLength ) > 0 )
            {
            bufferDes = iDes->Mid(iOffset,targetMaxLength);
            iOffset += targetMaxLength;
            }
        else
            bufferDes.SetLength(0);

        // Check if the buffer is the last buffer and if so set the last buffer flag on the CMMFDataBuffer
        TInt requestSize = aBuffer->RequestSize();
        if (requestSize)
            { // The buffer has a request size  - so assume last buffer if length is less than the request size
            if (bufferDes.Length() < requestSize)    
                aBuffer->SetLastBuffer(ETrue);
            }
        else
            { // There is no request size so assume last buffer if length is less than the max length
            if (bufferDes.Length() < bufferDes.MaxLength()) 
                aBuffer->SetLastBuffer(ETrue);
            }

        aConsumer->BufferFilledL( aBuffer ) ;
        }
    else
        User::Leave(KErrNotSupported);
    }

// called by MDataSink to pass back emptied buffer to the source
void CMMFExDescriptor::BufferEmptiedL( CMMFBuffer* /*aBuffer*/ )
    {
    // not supported in this plug-in
    __ASSERT_DEBUG(EFalse, Panic(EMMFDescriptorPanicBufferEmptiedLNotSupported));
    }

// tests if the plug-in can create a source buffer
TBool CMMFExDescriptor::CanCreateSourceBuffer()
    {
    // this can't: it needs a descriptor from another thread
    return EFalse ;
    }

// creates a source buffer
CMMFBuffer* CMMFExDescriptor::CreateSourceBufferL(  TMediaId /*aMediaId*/, TBool& /*aReference*/ )
    {
    // is not supported in this plug-in
    User::Leave(KErrNotSupported);
    return NULL;
    }


// from MDataSink

// gets sink codec type
TFourCC CMMFExDescriptor::SinkDataTypeCode(TMediaId /*aMediaId*/) 
    {
    return iSinkFourCC ;
    }

// Empties supplied buffer into the sink descriptor 
void CMMFExDescriptor::EmptyBufferL( CMMFBuffer* aBuffer, MDataSource* aSupplier, TMediaId /*aMediaId*/ )
    {
    // Current position in Descriptor is iOffset.

    // Assume that the amount to be read is the size of the buffer descriptor
    // Should check that there is sufficient data in the source buffer
    // If there is not enough to fill the target then copy what there is

    // Use of a single iOffset will preclude use by more than one client (use ReadBufferL())

    if ( aBuffer->Type() == KUidMmfDataBuffer  ) 
        {
        TDes8& bufferDes = STATIC_CAST(CMMFDataBuffer*, aBuffer)->Data();

        TInt sourceLength = bufferDes.Length() ;    
        TInt targetLength = iDes->MaxLength() - iOffset;
        if ( targetLength>0 )
            {
            if (sourceLength>targetLength)
                {
                sourceLength = targetLength;
                bufferDes.SetLength(targetLength);
                }

            iDes->Append(bufferDes) ;

            iOffset += sourceLength ;
            }
        else
            bufferDes.SetLength(0);

        aSupplier->BufferEmptiedL( aBuffer ) ;
        }
    }

// called by MDataSource to pass back full buffer to the sink
void CMMFExDescriptor::BufferFilledL( CMMFBuffer* /*aBuffer*/ )
    {
    // not supported in this plug-in
    __ASSERT_DEBUG(EFalse, Panic(EMMFDescriptorPanicBufferFilledLNotSupported));
    }

// tests if the plug-in can create a sink buffer
TBool CMMFExDescriptor::CanCreateSinkBuffer()
    {
    // this can't: it needs a descriptor from another thread   
    return EFalse ;
    }

// creates a sink buffer
CMMFBuffer* CMMFExDescriptor::CreateSinkBufferL( TMediaId /*aMediaId*/ , TBool& /*aReference*/)
    {
    // not supported in this plug-in
    User::Leave(KErrNotSupported);
    return NULL;
    }

// from CMMFClip

// Loads aBuffer with specified amount of data from a specified point in the source descriptor 
void CMMFExDescriptor::ReadBufferL(TInt aLength, CMMFBuffer* aBuffer, TInt aPosition, MDataSink* aConsumer)
    {
    if (aBuffer->Type() == KUidMmfDataBuffer) 
        {
        TDes8& bufferDes = STATIC_CAST(CMMFDataBuffer*, aBuffer)->Data();

        if (aLength>bufferDes.MaxLength())
            User::Leave(KErrOverflow);

        if ((aLength<0) || (aPosition<0))
            User::Leave(KErrArgument);

        ReadBufferL(aBuffer, aPosition, aConsumer);
        }
    else
        User::Leave(KErrNotSupported);
    }

// Loads aBuffer from a specified point in the source descriptor  
void CMMFExDescriptor::ReadBufferL(CMMFBuffer* aBuffer, TInt aPosition, MDataSink* aConsumer)
    {
    if (aBuffer->Type() == KUidMmfDataBuffer) 
        {
        TDes8& bufferDes = STATIC_CAST(CMMFDataBuffer*, aBuffer)->Data();

        TInt sourceLength = iDes->Length() ;
        TInt destinationMaxLength = bufferDes.MaxLength();
        TInt len = sourceLength - aPosition;
        if (len > destinationMaxLength)
            len = destinationMaxLength;

        if (len>0)
            {
            TPtrC8 srcPtr(iDes->Mid(aPosition,len));
            bufferDes.Copy(srcPtr);
            }
        else
            bufferDes.SetLength(0);

        // Check if the buffer is the last buffer and if so set the last buffer flag on the CMMFDataBuffer
        TInt requestSize = aBuffer->RequestSize();
        if (requestSize)
            { // The buffer has a request size  - so assume last buffer if length is less than the request size
            if (bufferDes.Length() < requestSize)    
                aBuffer->SetLastBuffer(ETrue);
            }
        else
            { // There is no request size so assume last buffer if length is less than the max length
            if (bufferDes.Length() < bufferDes.MaxLength()) 
                aBuffer->SetLastBuffer(ETrue);
            }

        if (aConsumer)
            aConsumer->BufferFilledL(aBuffer);
        }
    else
        User::Leave(KErrNotSupported);
    }

// Loads aBuffer from a specified point in the source descriptor 
// This is intended for synchronous usage
void CMMFExDescriptor::ReadBufferL(CMMFBuffer* aBuffer, TInt aPosition)
    {
    ReadBufferL(aBuffer, aPosition, NULL);
    }

// Writes aBuffer at specified location into the sink descriptor
void CMMFExDescriptor::WriteBufferL(CMMFBuffer* aBuffer, TInt aPosition, MDataSource* aSupplier) 
    {
    if (aBuffer->Type() == KUidMmfDataBuffer)
        {
        TDes8& bufferDes = STATIC_CAST(CMMFDataBuffer*, aBuffer)->Data();

        WriteBufferL(bufferDes.Length(), aBuffer, aPosition, aSupplier);
        }
    else
        User::Leave(KErrNotSupported);
    }

// Writes specified length of aBuffer at specified location into the sink descriptor
void CMMFExDescriptor::WriteBufferL(TInt aLength, CMMFBuffer* aBuffer, TInt aPosition, MDataSource* aSupplier)
    {
    if (aBuffer->Type() == KUidMmfDataBuffer) 
        {
        TDes8& bufferDes = STATIC_CAST(CMMFDataBuffer*, aBuffer)->Data();

        if (aLength>bufferDes.Length() || (aLength<0) || (aPosition<0))
            User::Leave(KErrArgument);

        TInt sourceLength = aLength;
        TPtr8 bufferPtr(((sourceLength) ? &bufferDes[0] : NULL), sourceLength, sourceLength);
        TInt targetLength = iDes->MaxLength() - aPosition;
        if (targetLength>0 && sourceLength > 0)
            {
            if (sourceLength>targetLength)
                User::Leave(KErrOverflow);

            if ((iDes->Length() - aPosition) > 0)
                {
                TInt bytesToReplace = iDes->Length() - aPosition;
                if (sourceLength > bytesToReplace) 
                    {
                    TPtrC8 replaceBuf = bufferPtr.Left(bytesToReplace);
                    TPtrC8 appendBuf = bufferPtr.Right(sourceLength-bytesToReplace);
                    iDes->Replace(aPosition, bytesToReplace, replaceBuf);
                    iDes->Append(appendBuf);
                    } 
                else
                    iDes->Replace(aPosition, sourceLength, bufferPtr);

                } 
            else if (aPosition == iDes->Length())
                iDes->Append(bufferPtr.Ptr(),sourceLength);
            else
                {
                iDes->AppendFill(0,aPosition - iDes->Length());
                iDes->Append(bufferPtr.Ptr(),sourceLength);
                }
            }
        else if (targetLength<0)
            User::Leave(KErrArgument);
        else if (aLength != 0)
            User::Leave(KErrOverflow);

        if (aSupplier)
            aSupplier->BufferEmptiedL(aBuffer);
        }
    else
        User::Leave(KErrNotSupported);
    }

// Writes aBuffer at specified location into the sink descriptor
void CMMFExDescriptor::WriteBufferL( CMMFBuffer* aBuffer, TInt aPosition)
    {
    WriteBufferL( aBuffer, aPosition, NULL );
    }

// Gets the space available in the clip
TInt64 CMMFExDescriptor::BytesFree() 
    {
    // get difference between length and maxlength
    TInt64 length = iDes->Length() ;
    TInt64 maxLength =  iDes->MaxLength() ;
    return( maxLength - length ) ;
    }

// Gets the size of the clip
TInt CMMFExDescriptor::Size() 
    {
    // Length (not max length) of descriptor
    TInt length = iDes->Length();
    return(length);
    }

// MMFDes.h
//
// Copyright (c) 2001-2002 Symbian Ltd.  All rights reserved.
//

#ifndef __MMFDES_H_
#define __MMFDES_H_


#include <mmf\server\mmfclip.h>
#include <mmf\common\mmfutilities.h>

//Panic codes for MMFDescriptor
enum TMMFExDescriptorPanicCode
    {
    EMMFDescriptorPanicBufferEmptiedLNotSupported = 1,
    EMMFDescriptorPanicBufferFilledLNotSupported
    };
    
class TMMFExDescriptorParams
    {
public:
    TAny* iDes ; // Address of TPtr8 describing source Descriptor
    TThreadId iDesThreadId ;
    } ;

typedef TPckgBuf<TMMFExDescriptorParams>  TMMFDescriptorConfig ;

// Defines a MMF sink and source plug-in that can write and read media data
// to a descriptor
// Implements CMMFClip, which itself derives from MDataSource and MDataSink
class CMMFExDescriptor : public CMMFClip
    {
public:
    // Data source factory
    static MDataSource* NewSourceL() ; 
    // Data sink factory
    static MDataSink* NewSinkL() ; 
    ~CMMFExDescriptor() ;
    
private:
    // From MDataSource
    TFourCC SourceDataTypeCode( TMediaId /*aMediaId*/) ;
    void FillBufferL(CMMFBuffer* aBuffer, MDataSink* aConsumer,TMediaId /*aMediaId*/) ;//called by a MDataSink to request buffer fill
    void BufferEmptiedL( CMMFBuffer* aBuffer ) ;
    TBool CanCreateSourceBuffer() ;
    CMMFBuffer* CreateSourceBufferL(TMediaId /*aMediaId*/, TBool &aReference) ;
    void ConstructSourceL(  const TDesC8& aInitData ) ;

    // From MDataSink
    TFourCC SinkDataTypeCode(TMediaId /*aMediaId*/) ; //used by data path MDataSource/Sink for codec matching
    void EmptyBufferL( CMMFBuffer* aBuffer, MDataSource* aSupplier, TMediaId /*aMediaId*/ ) ; 
    void BufferFilledL( CMMFBuffer* aBuffer ) ;
    TBool CanCreateSinkBuffer() ;
    CMMFBuffer* CreateSinkBufferL( TMediaId /*aMediaId*/ , TBool &aReference) ;
    void ConstructSinkL( const TDesC8& aInitData ) ;

    // From CMMFClip
    void ReadBufferL( TInt aLength, CMMFBuffer* aBuffer, TInt aPosition, MDataSink* aConsumer);
    void WriteBufferL( TInt aLength, CMMFBuffer* aBuffer, TInt aPosition, MDataSource* aSupplier);
    void ReadBufferL( CMMFBuffer* aBuffer, TInt aPosition, MDataSink* aConsumer) ;
    void WriteBufferL( CMMFBuffer* aBuffer, TInt aPosition, MDataSource* aSupplier) ;
    void ReadBufferL( CMMFBuffer* aBuffer, TInt aPosition) ;
    void WriteBufferL( CMMFBuffer* aBuffer, TInt aPosition) ;
    TInt64 BytesFree() ;  // amount of space available for the clip
    TInt Size() ;  // length of clip

    // Construction
    void ConstructL( const TDesC8& aInitData ) ;
    CMMFExDescriptor();
    // Helpers
    void Reset() { iOffset = 0 ; };

private:
    // Need to know about the thread that the descriptor is in
    RThread iDesThread;
    TDes8* iDes ;
    TInt iOffset;
    TFourCC iSinkFourCC;
    TFourCC iSourceFourCC;
    TBool iUseTransferBuffer;
    } ;


#endif

#ifndef _MmfSinkSourceUIDS_H_
#define _MmfSinkSourceUIDS_H_

#define KPluginDLLUID 0x101F81D3
#define KDescriptorSourceUID 0x101F81D4
#define KDescriptorSinkUID 0x101F81D5

#endif

bld.inf
PRJ_MMPFILES
MmfExSinkSource.mmp

// MmfExSinkSource.mmp
//
// Copyright (c) 2002-2005 Symbian Software Ltd.  All rights reserved.
//

TARGET MmfExSinkSource.dll
TARGETTYPE PLUGIN

// Ecom Dll recognition UID followed by the unique UID for this dll
UID 0x10009D8D 0x101F81D3
VENDORID 0x70000001
CAPABILITY ALL -TCB

SOURCEPATH  .
SOURCE  main.cpp
SOURCE  mmfdes.cpp    

SYSTEMINCLUDE  \epoc32\include
SYSTEMINCLUDE   \epoc32\include\mmf\common
SYSTEMINCLUDE   \epoc32\include\mmf\server
SYSTEMINCLUDE   \epoc32\include\ecom

START RESOURCE 101F81D3.rss
TARGETPATH     \resource\Plugins
HEADER
END

LIBRARY euser.lib
LIBRARY ECom.lib
LIBRARY efsrv.lib
LIBRARY mmfcontrollerframework.lib

// 101F81D3.RSS
// Copyright (c) Symbian Ltd.  All rights reserved.
//
//

#include "RegistryInfo.rh"
#include <mmfPluginInterfaceUIDs.hrh>
#include "MmfExSinkSourceUIDs.hrh"

RESOURCE REGISTRY_INFO theInfo
    {
    dll_uid = KPluginDLLUID;
    interfaces = 
        {
        INTERFACE_INFO
            {
            interface_uid = KMmfUidPluginInterfaceDataSource; // MdataSource
            implementations = 
                {
                IMPLEMENTATION_INFO
                    {
                    implementation_uid = KDescriptorSourceUID;
                    version_no = 1;
                    display_name = "CMMFExDescriptor";
                    default_data = "" ; // n/a
                    opaque_data = "";  // n/a
                    }

                };
            } ,
        INTERFACE_INFO
            {
            interface_uid = KMmfUidPluginInterfaceDataSink; 
            implementations = 
                {
                IMPLEMENTATION_INFO
                    {
                    implementation_uid = KDescriptorSinkUID;
                    version_no = 1;
                    display_name = "CMMFExDescriptor";
                    default_data = "" ; // n/a
                    opaque_data = "";  // n/a
                    }
                };
            }

        };
    }


Description

MmfExSinkSource demonstrates how to implement sink and source plug-ins for the Multimedia Framework. A sink is an object that can receive multimedia data; a source is an object that can supply it. This example implements a sink and a source as descriptor objects.

Both the sink and source are implemented in a single class, CMMFExDescriptor, that derives from CMMFClip. CMMFClip represents a multimedia clip (i.e. not a stream or hardware device), which, in turn, derives from the ECom sink interface MDataSink, and the source interface MDataSource.

Both the example source and sink are passed on creation a packaged TMMFExDescriptorParams object, which specifies the descriptor to read/write, and the thread to which the descriptor belongs.

Note that the default audio controller only uses the default sink/sources, and returns "not supported" if you attempt to use other sink/sources with it.