--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/lib3gp/wrapper/src/c3gpcompose.cpp Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,1026 @@
+// Copyright (c) 2008-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:
+//
+
+#include <e32debug.h>
+#include <c3gplibrary.h>
+
+#if defined (COMPOSE_DEBUG)
+#define DEBUG_PRINT RDebug::Print
+#else
+#define DEBUG_PRINT
+#endif
+
+const TInt KMinWriteBufferMaxCount = 6;
+_LIT(K3GPComposePanicName, "C3GPCompose");
+
+// This is video base class containing common video properties.
+T3GPVideoPropertiesBase::T3GPVideoPropertiesBase(T3GPVideoType aType,
+ TUint aTimescale, const TSize& aSize) :
+ iType(aType), iTimescale(aTimescale), iSize(aSize)
+ {
+ }
+
+/**
+This structure stores the common and MPEG-4 video specific properties of video data.
+
+@param aTimescale Timescale of the video data. This is the number of time units that
+ pass in one second.
+@param aSize Video width and height in pixels.
+@param aMaxBitRate Maximum video bit rate.
+@param aAvgBitRate Average video bit rate.
+@param aDecoderSpecificInfo MPEG-4 video DecoderSpecificInfo data stored in an ESDS atom.
+*/
+EXPORT_C T3GPVideoPropertiesMpeg4Video::T3GPVideoPropertiesMpeg4Video(TUint aTimescale,
+ const TSize& aSize, TUint aMaxBitRate, TUint aAvgBitRate, const TDesC8& aDecoderSpecificInfo) :
+ T3GPVideoPropertiesBase(E3GPMpeg4Video, aTimescale, aSize),
+ iMaxBitRate(aMaxBitRate),
+ iAvgBitRate(aAvgBitRate),
+ iDecoderSpecificInfo(aDecoderSpecificInfo)
+ {
+ }
+
+/**
+This structure stores the common and H.263 specific properties of video data.
+
+@param aTimescale Timescale of the video data. This is the number of time units that
+ pass in one second.
+@param aSize Video width and height in pixels.
+@param aVideoLevel Indicates the H263 video level.
+@param aProfile Indicates the H263 profile.
+*/
+EXPORT_C T3GPVideoPropertiesH263::T3GPVideoPropertiesH263(TUint aTimescale, const TSize& aSize,
+ TInt aVideoLevel, TProfile aProfile) :
+T3GPVideoPropertiesBase((aProfile == EProfile0) ? E3GPH263Profile0 : E3GPH263Profile3,
+ aTimescale, aSize), iVideoLevel(aVideoLevel)
+ {
+ }
+
+/**
+This structure stores the common and AVC specific properties of video data.
+
+@param aTimescale Timescale of the video data. This is the number of time units that
+ pass in one second.
+@param aSize Video width and height in pixels.
+@param aDecoderSpecificInfo AVCDecoderConfigurationRecord data that will be stored in the avcC atom.
+*/
+EXPORT_C T3GPVideoPropertiesAvc::T3GPVideoPropertiesAvc(TUint aTimescale, const TSize& aSize,
+ const TDesC8& aDecoderSpecificInfo) :
+T3GPVideoPropertiesBase(E3GPAvcProfileBaseline, aTimescale, aSize),
+iDecoderSpecificInfo(aDecoderSpecificInfo)
+ {
+ /*
+ NOTE: Although Baseline profile is being set here, it's just used to indicate
+ the fact that we have AVC data. The underlying 3GP lib does not differentiate
+ between profiles when composing a file. It simply writes the contents of
+ iDecoderSpecificInfo (which contains the profile amongst other things)
+ verbatim into the "avcC" box.
+ */
+ }
+
+// This is audio base class containing common audio properties.
+T3GPAudioPropertiesBase::T3GPAudioPropertiesBase(T3GPAudioType aType,
+ TUint aTimescale, TInt aFramesPerSample) :
+ iType(aType), iTimescale(aTimescale), iFramesPerSample(aFramesPerSample)
+ {
+ __ASSERT_ALWAYS((aTimescale > 0) && (aTimescale <= KMaxTUint16), User::Panic(K3GPComposePanicName, KErrOverflow));
+ }
+
+/**
+This structure stores the common and MPEG-4 audio-specific properties of audio data.
+
+@param aTimescale Timescale of the audio data. This is the number of time units that pass in one
+ second. It must be smaller than 65536.
+@param aDecoderSpecificInfo MPEG-4 audio DecoderSpecificInfo data stored in an ESDS atom.
+*/
+EXPORT_C T3GPAudioPropertiesMpeg4Audio::T3GPAudioPropertiesMpeg4Audio(TUint aTimescale,
+ const TDesC8& aDecoderSpecificInfo) :
+ T3GPAudioPropertiesBase(E3GPMpeg4Audio, aTimescale, 0),
+ iDecoderSpecificInfo(aDecoderSpecificInfo)
+ {
+ }
+
+/**
+This structure stores the common and AMR-specific properties of audio data.
+
+@param aTimescale Timescale of the audio data. This is the number of time units that pass in one
+ second. It must be smaller than 65536.
+@param aFramesPerSample Frames per sample. It must be smaller than 256.
+ MPEG-4 audio has a fixed value of 1.
+@param aModeSet AMR mode set.
+@param aCodec AMR Speech Codec.
+*/
+EXPORT_C T3GPAudioPropertiesAmr::T3GPAudioPropertiesAmr(TUint aTimescale, TInt aFramesPerSample,
+ TInt aModeSet, TSpeechCodec aCodec) :
+ T3GPAudioPropertiesBase((aCodec == EAmrNB) ? E3GPAmrNB : E3GPAmrWB,
+ aTimescale, aFramesPerSample), iModeSet(aModeSet)
+ {
+ __ASSERT_ALWAYS((aFramesPerSample > 0) && (aFramesPerSample <= KMaxTUint8),
+ User::Panic(K3GPComposePanicName, KErrOverflow));
+ }
+
+/**
+This structure stores the common and QCELP-specific properties of MPEG4 audio data. The storage mode is
+automatically set to MPEG4 Audio Sample Description Box mode.
+
+@param aTimescale Timescale of the audio data. This is the number of time units that pass in one
+ second. It must be smaller than 65536.
+@param aFramesPerSample Frames per sample. It must be smaller than 512.
+ MPEG-4 audio has a fixed value of 1.
+@param aDecoderSpecificInfo MPEG-4 audio decoder specific information data stored in an ESDS atom.
+*/
+EXPORT_C T3GPAudioPropertiesQcelp::T3GPAudioPropertiesQcelp(TUint aTimescale, TInt aFramesPerSample,
+ const TDesC8& aDecoderSpecificInfo) :
+ T3GPAudioPropertiesBase(E3GPQcelp13K, aTimescale, aFramesPerSample),
+ iMode(E3GPMP4AudioDescriptionBox),
+ iDecoderSpecificInfo(aDecoderSpecificInfo)
+ {
+ __ASSERT_ALWAYS((aFramesPerSample > 0) && (aFramesPerSample <= KMaxTUint8),
+ User::Panic(K3GPComposePanicName, KErrOverflow));
+ }
+
+/**
+This structure stores the common and QCELP-specific properties of audio data.
+
+@param aTimescale Timescale of the audio data. This is the number of time units that pass in one
+ second. It must be smaller than 65536.
+@param aFramesPerSample Frames per sample. It must be smaller than 512.
+ MPEG-4 audio has a fixed value of 1.
+*/
+
+EXPORT_C T3GPAudioPropertiesQcelp::T3GPAudioPropertiesQcelp(TUint aTimescale, TInt aFramesPerSample) :
+ T3GPAudioPropertiesBase(E3GPQcelp13K, aTimescale, aFramesPerSample),
+ iMode(E3GPQcelpSampleEntryBox),
+ iDecoderSpecificInfo(KNullDesC8)
+ {
+ __ASSERT_ALWAYS((aFramesPerSample > 0) && (aFramesPerSample <= KMaxTUint8),
+ User::Panic(K3GPComposePanicName, KErrOverflow));
+ }
+
+/**
+Create an instance of 3GP composer using default buffer count and size.
+
+The default values for buffer count and size are as follow:
+Write Buffer Size is 2048
+Write Buffer Max Count is 15
+
+@return A pointer to the newly created 3gp compose object.
+
+@leave KErrGeneral General error.
+@leave KErrNoMemory Out of memory.
+
+@panic C3GPCompose KErrAbort if clients do not a CActiveScheduler installed already.
+*/
+EXPORT_C C3GPCompose* C3GPCompose::NewL()
+ {
+ // Leave if no scheduler exists
+ __ASSERT_ALWAYS ((CActiveScheduler::Current() != NULL), Panic(KErrAbort));
+ C3GPCompose* self = new (ELeave) C3GPCompose();
+ return self;
+ }
+
+/**
+Create an instance of 3GP composer, and let the user set a count limit and size of
+internal buffer for composition.
+
+The default values for buffer count and size are as follow:
+ Write Buffer Size is 2048
+ Write Buffer Max Count is 15
+
+An increase of the buffer count and size will lead to a decrease of file I/O activities, thereby,
+improves the performance of the 3GP Composer at the expense of higher memory usage.
+
+@param aMediaWriteBufferSize Size of media data file output buffer (in bytes).
+@param aWriteBufferMaxCount Maximum number of buffers (both media and meta) allowed before file
+ output changes to synchronous (by default file writing is asynchronous
+ operation). A minimum value of 6 is enforced.
+
+@return A pointer to the newly created 3gp compose object.
+
+@leave KErrGeneral General error.
+@leave KErrNoMemory Out of memory.
+
+@panic C3GPCompose KErrAbort if clients do not a CActiveScheduler installed already.
+@panic C3GPCompose KErrArgument if Write Buffer Size is less or equal to 0 or Write Buffer Max Count is
+ less than 6.
+ */
+EXPORT_C C3GPCompose* C3GPCompose::NewL(TInt aMediaWriteBufferSize, TInt aWriteBufferMaxCount)
+ {
+ __ASSERT_ALWAYS ((aMediaWriteBufferSize > 0 && aWriteBufferMaxCount >= KMinWriteBufferMaxCount),
+ Panic(KErrArgument));
+ // Leave if no scheduler exists
+ __ASSERT_ALWAYS ((CActiveScheduler::Current() != NULL), Panic(KErrAbort));
+
+ C3GPCompose* self = new (ELeave) C3GPCompose(aMediaWriteBufferSize, aWriteBufferMaxCount);
+ return self;
+ }
+
+// First phase constructor
+C3GPCompose::C3GPCompose(TInt aMediaWriteBufferSize, TInt aWriteBufferMaxCount) :
+ iMediaWriteBufferSize(aMediaWriteBufferSize),
+ iWriteBufferMaxCount(aWriteBufferMaxCount),
+ iDuplicateFileHandleCreated(EFalse)
+ {
+ }
+
+/**
+This function initialises the 3GP composer for writing 3GP/3G2/MP4 data into a file.
+Any combination of one video and one audio type is acceptable.
+
+Note: Ownership of aVideo and aAudio remains with the caller. Both aVideo and aAudio are ready for
+deletion after C3GPCompose::Open returns.
+
+@param aFileFormat Specifies the file format in which the data will be created. Refer to
+ T3GPFileFormatType for supported file format types.
+@param aVideo Specifies the video stream to be used for video data. The input data given will
+ be inserted into 3GP file headers and is ready to be disposed when
+ C3GPCompose::Open returns. See Video Properties Classes.
+ If aVideo is NULL, audio-only file will be composed.
+@param aAudio Specifies the audio stream to be used for audio data. The input data given will
+ be inserted into 3GP file headers and is ready to be disposed when
+ C3GPCompose::Open returns. See Audio Properties Classes.
+ If aAudio is NULL, video-only file will be composed.
+@param aFilename A full path name of the file to save the data to. An empty path is not allowed.
+@param aFlags Optional flags for composing preferences. Refer to T3GPComposeFlag for supported flags.
+ The combined use of flags is acceptable. For example:
+ E3GPLongClip | E3GPMetaDataLast
+
+@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
+ KErrGeneral if an error has no specific categorisation;
+ KErrNoMemory if an attempt to allocate memory has failed;
+ KErrArgument if neither video nor audio stream is specified;
+ KErrAccessDenied if opening file has failed;
+ KErrUnderflow if the file name length is not greater than 0;
+ KErrInUse if the composer is currently engaged; C3GPCompose::Complete must be called to
+ finish the current composition before the composer can be re-initialised again.
+*/
+EXPORT_C TInt C3GPCompose::Open(T3GPFileFormatType aFileFormat,
+ const T3GPVideoPropertiesBase* aVideo,
+ const T3GPAudioPropertiesBase* aAudio,
+ const TDesC& aFilename,
+ TUint aFlags)
+ {
+ if (iHandler)
+ {
+ return KErrInUse;
+ }
+ if (aFilename.Length() <= 0)
+ {
+ return KErrUnderflow;
+ }
+ if (!aVideo && !aAudio)
+ {
+ // if neither video nor audio is supplied
+ return KErrArgument;
+ }
+
+ // Create a zero terminated version of the file name
+ RBuf fileName;
+ TInt err = fileName.Create(aFilename.Length() + 1);
+ if (err == KErrNone)
+ {
+ fileName.Copy(aFilename);
+ mp4_u16* mp4FileName = const_cast<mp4_u16*>(fileName.PtrZ());
+ MP4Err mp4Err = MP4ComposeOpen(&iHandler, reinterpret_cast<MP4FileName>(mp4FileName), Mp4Type(aVideo, aAudio));
+
+ if (mp4Err == MP4_OK)
+ {
+ // Write audio and video properties to the 3GP file
+ err = SetComposeProperties(aVideo, aAudio, aFileFormat, aFlags);
+ if (err != KErrNone)
+ {
+ Complete(); // Ingore the error
+ }
+ }
+ else
+ {
+ err = SymbianOSError(mp4Err);
+ }
+ }
+ fileName.Close();
+ return err;
+ }
+
+/**
+This function initialises the 3GP composer for writing 3GP/3G2/MP4 data into a file.
+Any combination of one video and one audio type is acceptable.
+
+Note: E3GPMetaDataLast will be defaulted in aFlags if file handle is used for the initialisation
+of the 3GP composer.
+
+Note: Ownership of aVideo and aAudio remains with the caller. Both aVideo and aAudio are ready for
+deletion after C3GPCompose::Open returns.
+
+@param aFileFormat Specifies the file format in which the data will be created. Refer to
+ T3GPFileFormatType for supported file format types.
+@param aVideo Specifies the video stream to be used for video data. The input data given will
+ be inserted into 3GP file headers and is ready to be disposed when
+ C3GPCompose::Open returns. See Video Properties Classes.
+ If aVideo is NULL, audio-only file will be composed.
+@param aAudio Specifies the audio stream to be used for audio data. The input data given will
+ be inserted into 3GP file headers and is ready to be disposed when
+ C3GPCompose::Open returns. See Audio Properties Classes.
+ If aAudio is NULL, video-only file will be composed.
+@param aFile File handle of the file to save the data to. E3GPMetaDataLast needs to be set for
+ aFlags when this is used.
+@param aFlags Optional flags for composing preferences. Refer to T3GPComposeFlag for supported flags.
+ The combined use of flags is acceptable. For example:
+ E3GPLongClip | E3GPMetaDataLast
+
+@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
+ KErrGeneral if an error has no specific categorisation;
+ KErrNoMemory if an attempt to allocate memory has failed;
+ KErrArgument if neither video nor audio stream is specified;
+ KErrAccessDenied if opening file has failed;
+ KErrInUse if the composer is currently engaged; C3GPCompose::Complete must be called to
+ finish the current composition before the composer can be re-initialised again.
+*/
+
+EXPORT_C TInt C3GPCompose::Open(T3GPFileFormatType aFileFormat,
+ const T3GPVideoPropertiesBase* aVideo,
+ const T3GPAudioPropertiesBase* aAudio,
+ RFile& aFile,
+ TUint aFlags)
+ {
+ TInt err = KErrNone;
+ if (!iDuplicateFileHandleCreated)
+ {
+ iDuplicateFileHandleCreated = ETrue;
+ iFile.Close();
+ err = iFile.Duplicate(aFile);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ }
+
+ return Open(aFileFormat, aVideo, aAudio, iFile, aFlags);
+ }
+
+/**
+This function initialises the 3GP composer for writing 3GP/3G2/MP4 data into a file.
+Any combination of one video and one audio type is acceptable.
+
+Note: E3GPMetaDataLast will be defaulted in aFlags if file handle is used for the initialisation
+of the 3GP composer.
+
+Note: Ownership of aVideo and aAudio remains with the caller. Both aVideo and aAudio are ready for
+deletion after C3GPCompose::Open returns.
+
+@param aFileFormat Specifies the file format in which the data will be created. Refer to
+ T3GPFileFormatType for supported file format types.
+@param aVideo Specifies the video stream to be used for video data. The input data given will
+ be inserted into 3GP file headers and is ready to be disposed when
+ C3GPCompose::Open returns. See Video Properties Classes.
+ If aVideo is NULL, audio-only file will be composed.
+@param aAudio Specifies the audio stream to be used for audio data. The input data given will
+ be inserted into 3GP file headers and is ready to be disposed when
+ C3GPCompose::Open returns. See Audio Properties Classes.
+ If aAudio is NULL, video-only file will be composed.
+@param aFile File handle of the file to save the data to. E3GPMetaDataLast needs to be set for
+ aFlags when this is used.
+@param aFlags Optional flags for composing preferences. Refer to T3GPComposeFlag for supported flags.
+ The combined use of flags is acceptable. For example:
+ E3GPLongClip | E3GPMetaDataLast
+
+@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
+ KErrGeneral if an error has no specific categorisation;
+ KErrNoMemory if an attempt to allocate memory has failed;
+ KErrArgument if neither video nor audio stream is specified;
+ KErrAccessDenied if opening file has failed;
+ KErrInUse if the composer is currently engaged; C3GPCompose::Complete must be called to
+ finish the current composition before the composer can be re-initialised again.
+*/
+EXPORT_C TInt C3GPCompose::Open(T3GPFileFormatType aFileFormat,
+ const T3GPVideoPropertiesBase* aVideo,
+ const T3GPAudioPropertiesBase* aAudio,
+ RFile64& aFile,
+ TUint aFlags)
+ {
+ if (iHandler)
+ {
+ return KErrInUse;
+ }
+ if (!aVideo && !aAudio)
+ {
+ // if neither video nor audio is supplied
+ return KErrArgument;
+ }
+
+ TInt driveNumber = EDriveA;
+ TDriveInfo driveInfo;
+ TInt err = aFile.Drive(driveNumber, driveInfo);
+ if (err == KErrNone)
+ {
+ MP4Err mp4Err = MP4ComposeOpenFileHandle64(&iHandler, &aFile, static_cast<TDriveNumber>(driveNumber), Mp4Type(aVideo, aAudio));
+ if (mp4Err == MP4_OK)
+ {
+ // Write audio and video properties to the 3GP file
+ err = SetComposeProperties(aVideo, aAudio, aFileFormat, aFlags);
+ if (err != KErrNone)
+ {
+ Complete(); // Ingore the error
+ }
+ }
+ else
+ {
+ err = SymbianOSError(mp4Err);
+ }
+ }
+
+ return err;
+ }
+
+/**
+Destructor
+Deletes all objects and releases all resource owned by this instance.
+*/
+EXPORT_C C3GPCompose::~C3GPCompose()
+ {
+ Complete(); // Ignore the error
+ }
+
+/**
+This function completes the composing operation. It frees the memory allocated by the library instance
+and closes the output file.
+
+It is necessary to call this function before the output file is guaranteed to be a valid output file
+even though the file may exist prior to the call.
+
+The composer can be reused again after this call, following another call to C3GPCompose::Open to
+re-initialise the composer.
+
+If C3GPCompose::Complete is called before the composer is initialised, it will be ignored and KErrNone
+is returned.
+
+Although during destruction of C3GPCompose, this function will be automatically called, and no error
+code will be returned. Therefore, when destroying the Composer object that you have used to compose a
+file, you should ensure that data is committed to the file by invoking C3GPCompose::Complete before
+destroying the Composer object.
+
+@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
+ KErrGeneral if an error has no specific categorisation;
+ KErrWrite if metadata could not be written.
+*/
+EXPORT_C TInt C3GPCompose::Complete()
+ {
+ MP4Err mp4Err = MP4_OK;
+ if (iHandler)
+ {
+ mp4Err = MP4ComposeClose(iHandler);
+ }
+ // Always reset the class member data even this function returns error
+ Reset();
+ return SymbianOSError(mp4Err);
+ }
+
+// Helper function to reset class member data.
+void C3GPCompose::Reset()
+ {
+ iHasVideo = EFalse;
+ iHasAudio = EFalse;
+ iHandler = NULL;
+ iFile.Close();
+ }
+
+/**
+This function writes one video frame to the output file or buffer.
+
+The frames must be inserted according to their causal sequence. Because the library doesn't analyze
+the video bit stream, frames are inserted into the 3GP file in the same order as they are entered
+with this function. Therefore, the frames will not be retrieved from the resulting 3GP file or
+buffer correctly if they are not in proper order.
+
+A frame inserted with this function call will result in one 3GP sample and one 3GP chunk.
+
+The current frame's dependency information which is using default values (E3GPDependencyUnknown &
+E3GPRedundancyUnknown) is inserted.
+
+The data is available in the output file only after calling C3GPCompose::Complete. C3GPCompose::Complete
+should be called exactly once when all audio and video data has been inserted into the library.
+
+@param aBuffer The descriptor containing the video frame data to be written.
+@param aDuration Duration of video frame in timescale, see T3GPVideoPropertiesBase.
+@param aKeyFrame ETrue to indicate whether this frame is a key frame. EFalse otherwise.
+
+@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
+ KErrGeneral if an error has no specific categorisation;
+ KErrNotSupported if the composer is setup for an audio-only file;
+ KErrUnderflow if the supplied video frame buffer data is empty;
+ KErrNotReady if the composer has not yet been initialised; See C3GPCompose::Open.
+*/
+EXPORT_C TInt C3GPCompose::WriteVideoFrame(const TDesC8& aBuffer, TUint aDuration, TBool aKeyFrame)
+ {
+ if (!iHandler)
+ {
+ return KErrNotReady;
+ }
+ if (aBuffer.Length() <= 0)
+ {
+ return KErrUnderflow;
+ }
+ if (!iHasVideo)
+ {
+ return KErrNotSupported;
+ }
+
+ // Insert video frame data
+ mp4_bool keyFrame = aKeyFrame;
+ mp4_u32 duration = aDuration;
+ MP4Err mp4Err = MP4ComposeWriteVideoFrame(iHandler, const_cast<mp4_u8*>(aBuffer.Ptr()), aBuffer.Length(), duration, keyFrame);
+
+ return SymbianOSError(mp4Err);
+ }
+
+/**
+This function sets the current frame's dependency information to SDTP box and writes one video frame
+to the output file.
+
+The frames must be inserted according to their causal sequence. Because the library doesn't analyze
+the video bit stream, frames are inserted into the 3GP file in the same order as they are entered
+with this function. Therefore, the frames will not be retrieved from the resulting 3GP file or
+buffer correctly if they are not in proper order.
+
+A frame inserted with this function call will result in one 3GP sample and one 3GP chunk.
+
+The data is available in the output file only after calling C3GPCompose::Complete. C3GPCompose::Complete
+should be called exactly once when all audio and video data has been inserted into the library.
+
+@param aBuffer The descriptor containing the video frame data to be written.
+@param aDuration Duration of video frame in timescale, see T3GPVideoPropertiesBase.
+@param aKeyFrame ETrue to indicate whether this frame is a key frame. EFalse otherwise.
+@param aDependencies This specifies the current frame's dependency information.
+ The information will be supplied into the SDTP box.
+ See T3GPFrameDependencies.
+
+@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
+ KErrGeneral if an error has no specific categorisation;
+ KErrNotSupported if the composer is setup for an audio-only file;
+ KErrUnderflow if the supplied video frame buffer data is empty;
+ KErrNotReady if the composer has not yet been initialised; See C3GPCompose::Open.
+*/
+EXPORT_C TInt C3GPCompose::WriteVideoFrame(const TDesC8& aBuffer, TUint aDuration, TBool aKeyFrame,
+ const T3GPFrameDependencies& aDependencies)
+ {
+ if (!iHandler)
+ {
+ return KErrNotReady;
+ }
+ if (aBuffer.Length() <= 0)
+ {
+ return KErrUnderflow;
+ }
+ if (!iHasVideo)
+ {
+ return KErrNotSupported;
+ }
+
+ // Insert the current frame's dependency information
+ MP4Err mp4Err = MP4ComposeWriteNextVideoFrameDependencies(iHandler, aDependencies.iDependsOn,
+ aDependencies.iIsDependedOn, aDependencies.iHasRedundancy);
+
+ if (mp4Err == MP4_OK)
+ {
+ // Insert video frame data
+ mp4_bool keyFrame = aKeyFrame;
+ mp4_u32 duration = aDuration;
+ mp4Err = MP4ComposeWriteVideoFrame(iHandler, const_cast<mp4_u8*>(aBuffer.Ptr()),
+ aBuffer.Length(), duration, keyFrame);
+ }
+
+ return SymbianOSError(mp4Err);
+ }
+
+/**
+This function writes audio frames into the output file or buffer. The data is available in the
+3GP output file only after calling C3GPCompose::Complete. C3GPCompose::Complete should be called exactly
+once when all audio and video data has been inserted into the library.
+
+For MPEG-4 audio:
+This function writes one MPEG audio frame to the 3GP file.
+
+For other audio types:
+This function writes a number of audio frames to the 3GP file specified during composer setup
+in the input parameter aAudio when calling C3GPCompose::Open. All audio frames inserted with
+one function call will be placed inside one sample in the resulting file.
+
+Note: Only the last call can have a different number of frames if the number is less than
+the number of frames per sample specified during composer setup.
+
+@see T3GPAudioPropertiesAmr
+@see T3GPAudioPropertiesQcelp
+
+@param aBuffer The descriptor containing the audio data to be written.
+@param aDuration Duration of audio frames in timescale, see T3GPAudioPropertiesBase
+
+@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
+ KErrGeneral if an error has no specific categorisation;
+ KErrNotSupported if the composer is setup for a video-only file;
+ KErrUnderflow if the supplied audio frames buffer data is empty;
+ KErrNotReady if the composer has not yet been initialised; See C3GPCompose::Open.
+*/
+EXPORT_C TInt C3GPCompose::WriteAudioFrames(const TDesC8& aBuffer, TUint aDuration)
+ {
+ if (!iHandler)
+ {
+ return KErrNotReady;
+ }
+ if (aBuffer.Length() <= 0)
+ {
+ return KErrUnderflow;
+ }
+ if (!iHasAudio)
+ {
+ return KErrNotSupported;
+ }
+
+ mp4_u32 duration = aDuration;
+ // use 0 for the number of frames since it is being ignored within the mp4 library implementation
+ MP4Err mp4Err = MP4ComposeWriteAudioFrames(iHandler, const_cast<mp4_u8*>(aBuffer.Ptr()),
+ aBuffer.Length(), 0, duration);
+
+ return SymbianOSError(mp4Err);
+ }
+
+/**
+Writes a buffer containing whole atom to inside of user data atom (UDTA) defined in aLocation.
+
+The buffer should contain an atom of structure that conforms to the definition of a "full box"
+as specified in ISO/IEC 14496-12:2003: "Information technology – Coding of audio-visual objects
+ – Part 12: ISO base media file format."
+
+For more information on user data atoms, see Section 8 – Asset Information of "3GPP TS 26.244
+version 6.1.0 – 3GP file format (Rel 6)."
+
+@param aLocation Specifies the location of user information to be written. Refer to
+ T3GPUdtaLocation for possible values.
+@param aBuffer The descriptor containing the user information to write into file.
+
+@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
+ KErrGeneral if an error has no specific categorisation;
+ KErrArgument if asked aLocation is invalid;
+ KErrUnderflow if the supplied buffer data is empty;
+ KErrNotSupported if specify video track user data but no video type is specified,
+ or specify audio track user data but no audio type is specified
+ KErrNoMemory if an attempt to allocate memory has failed;
+ KErrNotReady if the composer has not yet been initialised; See C3GPCompose::Open.
+
+@panic C3GPCompose KErrArgument if the location of user information is not of T3GPUdtaLocation.
+*/
+EXPORT_C TInt C3GPCompose::SetUserData(T3GPUdtaLocation aLocation, const TDesC8& aBuffer)
+ {
+ if (!iHandler)
+ {
+ return KErrNotReady;
+ }
+ if (aBuffer.Length() <= 0)
+ {
+ return KErrUnderflow;
+ }
+ if ((!iHasAudio && aLocation == E3GPUdtaAudioTrak) || (!iHasVideo && aLocation == E3GPUdtaVideoTrak))
+ {
+ return KErrNotSupported;
+ }
+
+ mp4_u8 location;
+ switch (aLocation)
+ {
+ case (E3GPUdtaMoov):
+ location = MP4_UDTA_MOOV;
+ break;
+ case (E3GPUdtaVideoTrak):
+ location = MP4_UDTA_VIDEOTRAK;
+ break;
+ case (E3GPUdtaAudioTrak):
+ location = MP4_UDTA_AUDIOTRAK;
+ break;
+ default:
+ Panic(KErrArgument);
+ break;
+ }
+
+ mp4_u32 bufferSize = aBuffer.Length();
+ MP4Err mp4Err = MP4ComposeSetUserDataAtom(iHandler, location, const_cast<mp4_u8*>(aBuffer.Ptr()), bufferSize);
+ return SymbianOSError(mp4Err);
+ }
+
+// Helper function to convert 3GP/MP4 library specific error codes to system wide error codes
+TInt C3GPCompose::SymbianOSError(MP4Err aError)
+ {
+ TInt error = KErrNone;
+
+ switch (aError)
+ {
+ case (MP4_OK):
+ break;
+ case (MP4_ERROR):
+ error = KErrGeneral;
+ break;
+ case (MP4_OUT_OF_MEMORY):
+ error = KErrNoMemory;
+ break;
+ case (MP4_FILE_ERROR):
+ error = KErrAccessDenied;
+ break;
+ case (MP4_INVALID_TYPE):
+ error = KErrArgument;
+ break;
+ case (MP4_METADATA_ERROR):
+ error = KErrWrite;
+ break;
+ default:
+ Panic(KErrArgument);
+ }
+ return error;
+ }
+
+// Helper function to map 3GP enum type to MP4 audio and video type
+mp4_u32 C3GPCompose::Mp4Type(const T3GPVideoPropertiesBase* aVideo, const T3GPAudioPropertiesBase* aAudio)
+ {
+ mp4_u32 videoType = MP4_TYPE_NONE;
+ mp4_u32 audioType = MP4_TYPE_NONE;
+
+ if (aVideo)
+ {
+ iHasVideo = ETrue;
+ switch (aVideo->iType)
+ {
+ case (E3GPMpeg4Video):
+ videoType = MP4_TYPE_MPEG4_VIDEO;
+ break;
+ case (E3GPH263Profile0):
+ videoType = MP4_TYPE_H263_PROFILE_0;
+ break;
+ case (E3GPH263Profile3):
+ videoType = MP4_TYPE_H263_PROFILE_3;
+ break;
+
+ /*
+ * NOTE: The underlying 3GP library does
+ * not differentiate between the various AVC
+ * profiles when composing.
+ *
+ * In all cases it will simply copy the data
+ * from the iDecoderSpecificInfo member of
+ * T3GPVideoPropertiesAvc into the 'avcC' atom.
+ * It does not do any checking of that data, so
+ * it is the API user's responsibility to ensure
+ * that it contains a valid AVCDecoderConfigurationRecord
+ * with the correct AVC profile and level.
+ *
+ * An interesting side-effect of this is that you can
+ * compose AVC data with arbitrary profiles even if they
+ * are not "supported" by this API. For example, as long
+ * as the AVCDecoderConfigurationRecord says there is
+ * High 10 profile data and the AVC data is of that profile
+ * then you will still end up with a valid file.
+ */
+ case (E3GPAvcProfileBaseline):
+ videoType = MP4_TYPE_AVC_PROFILE_BASELINE;
+ break;
+ case (E3GPAvcProfileMain):
+ videoType = MP4_TYPE_AVC_PROFILE_MAIN;
+ break;
+ case (E3GPAvcProfileExtended):
+ videoType = MP4_TYPE_AVC_PROFILE_EXTENDED;
+ break;
+ case (E3GPAvcProfileHigh):
+ videoType = MP4_TYPE_AVC_PROFILE_HIGH;
+ break;
+ default:
+ Panic(KErrArgument);
+ }
+ }
+
+ if(aAudio)
+ {
+ iHasAudio = ETrue;
+ switch (aAudio->iType)
+ {
+ case (E3GPMpeg4Audio):
+ audioType = MP4_TYPE_MPEG4_AUDIO;
+ break;
+ case (E3GPAmrNB):
+ audioType = MP4_TYPE_AMR_NB;
+ break;
+ case (E3GPAmrWB):
+ audioType = MP4_TYPE_AMR_WB;
+ break;
+ case (E3GPQcelp13K):
+ audioType = MP4_TYPE_QCELP_13K;
+ break;
+ default:
+ Panic(KErrArgument);
+ }
+ }
+ return (videoType | audioType);
+ }
+
+// Helper function to set compose properties
+TInt C3GPCompose::SetComposeProperties(const T3GPVideoPropertiesBase* aVideo,
+ const T3GPAudioPropertiesBase* aAudio, T3GPFileFormatType aFileFormat, TUint aFlag)
+ {
+ mp4_u32 writeBufferSize = iMediaWriteBufferSize;
+ mp4_u32 writeBufferMaxCount = iWriteBufferMaxCount;
+ MP4Err mp4Err = MP4SetCustomFileBufferSizes(iHandler, writeBufferSize, writeBufferMaxCount, 0);
+ if ( mp4Err != MP4_OK)
+ {
+ return SymbianOSError(mp4Err);
+ }
+
+ // Set compose flag before other MP4Compose functions
+ TInt err = SetComposeFlag(aFileFormat, aFlag);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+
+ if (aVideo)
+ {
+ switch (aVideo->iType)
+ {
+ case (E3GPMpeg4Video):
+ err = SetMPeg4VideoProperties(aVideo);
+ break;
+ case (E3GPAvcProfileBaseline):
+ case (E3GPAvcProfileMain):
+ case (E3GPAvcProfileExtended):
+ case (E3GPAvcProfileHigh):
+ err = SetAvcVideoProperties(aVideo);
+ break;
+ case (E3GPH263Profile0):
+ case (E3GPH263Profile3):
+ err = SetH263VideoProperties(aVideo);
+ break;
+ default:
+ Panic(KErrArgument);
+ }
+ }
+ if (err != KErrNone)
+ {
+ return err;
+ }
+
+ if (aAudio)
+ {
+ switch (aAudio->iType)
+ {
+ case (E3GPMpeg4Audio):
+ err = SetMpeg4AudioProperties(aAudio);
+ break;
+ case (E3GPQcelp13K):
+ err = SetQcelpAudioProperties(aAudio);
+ break;
+ case (E3GPAmrNB):
+ case (E3GPAmrWB):
+ err = SetAmrAudioProperties(aAudio);
+ break;
+ default:
+ Panic(KErrArgument);
+ }
+ }
+ return err;
+ }
+
+// Inform the 3GP library about the MPeg4 video data
+TInt C3GPCompose::SetMPeg4VideoProperties(const T3GPVideoPropertiesBase* aVideo)
+ {
+ const T3GPVideoPropertiesMpeg4Video* mpeg4Video = static_cast<const T3GPVideoPropertiesMpeg4Video*>(aVideo);
+
+ MP4Err err = MP4ComposeWriteVideoDecoderSpecificInfo(iHandler, const_cast<mp4_u8*>(mpeg4Video->iDecoderSpecificInfo.Ptr()),
+ mpeg4Video->iDecoderSpecificInfo.Length());
+
+ if ( err == MP4_OK)
+ {
+ err = MP4ComposeAddVideoDescription(iHandler, mpeg4Video->iTimescale,
+ mpeg4Video->iSize.iWidth, mpeg4Video->iSize.iHeight,
+ mpeg4Video->iMaxBitRate, mpeg4Video->iAvgBitRate);
+ }
+
+ return SymbianOSError(err);
+ }
+
+// Inform the 3GP library about the AVC video data
+TInt C3GPCompose::SetAvcVideoProperties(const T3GPVideoPropertiesBase* aVideo)
+ {
+ const T3GPVideoPropertiesAvc* avcVideo = static_cast<const T3GPVideoPropertiesAvc*>(aVideo);
+
+ MP4Err err = MP4ComposeWriteVideoDecoderSpecificInfo(iHandler, const_cast<mp4_u8*>(avcVideo->iDecoderSpecificInfo.Ptr()),
+ avcVideo->iDecoderSpecificInfo.Length ());
+
+ if ( err == MP4_OK)
+ {
+ // aMaxBitRate and aAvgBitRate are MPEG-4 video specific values. Set 0 for them
+ err = MP4ComposeAddVideoDescription(iHandler, avcVideo->iTimescale,
+ avcVideo->iSize.iWidth, avcVideo->iSize.iHeight, 0, 0);
+ }
+
+ return SymbianOSError(err);
+ }
+
+// Inform the 3GP library about the H263 video data
+TInt C3GPCompose::SetH263VideoProperties(const T3GPVideoPropertiesBase* aVideo)
+ {
+ // aMaxBitRate and aAvgBitRate are MPEG-4 video specific values. Set 0 for H263 video
+ MP4Err err = MP4ComposeAddVideoDescription(iHandler, aVideo->iTimescale,
+ aVideo->iSize.iWidth, aVideo->iSize.iHeight, 0, 0);
+
+ if ( err == MP4_OK)
+ {
+ const T3GPVideoPropertiesH263* h263Video = static_cast<const T3GPVideoPropertiesH263*>(aVideo);
+ TVideoClipProperties properties;
+ properties.iH263Level = h263Video->iVideoLevel;
+ err = MP4ComposeSetVideoClipProperties(iHandler, properties);
+ }
+
+ return SymbianOSError(err);
+ }
+
+// Inform the 3GP library about the MPeg4 audio data
+TInt C3GPCompose::SetMpeg4AudioProperties(const T3GPAudioPropertiesBase* aAudio)
+ {
+ const T3GPAudioPropertiesMpeg4Audio* mpeg4Audio = static_cast<const T3GPAudioPropertiesMpeg4Audio*>(aAudio);
+
+ MP4Err err = MP4ComposeWriteAudioDecoderSpecificInfo(iHandler, const_cast<mp4_u8*>(mpeg4Audio->iDecoderSpecificInfo.Ptr()),
+ mpeg4Audio->iDecoderSpecificInfo.Length ());
+
+ if ( err == MP4_OK)
+ {
+ //modeSet is needed only for AMR audio. Set it to 0 for Mpeg4 audio.
+ err = MP4ComposeAddAudioDescription(iHandler, mpeg4Audio->iTimescale, mpeg4Audio->iFramesPerSample, 0);
+ }
+
+ return SymbianOSError(err);
+ }
+
+// Inform the 3GP library about the Amr audio data
+TInt C3GPCompose::SetAmrAudioProperties(const T3GPAudioPropertiesBase* aAudio)
+ {
+ const T3GPAudioPropertiesAmr* amrAudio = static_cast<const T3GPAudioPropertiesAmr*>(aAudio);
+ //modeSet is needed only for AMR audio.
+ MP4Err err = MP4ComposeAddAudioDescription(iHandler, amrAudio->iTimescale,
+ amrAudio->iFramesPerSample, amrAudio->iModeSet);
+ return SymbianOSError(err);
+ }
+
+// Sets the storage mode of storing 13K QCELP data in a 3G2 file
+TInt C3GPCompose::SetQcelpAudioProperties(const T3GPAudioPropertiesBase* aAudio)
+ {
+ const T3GPAudioPropertiesQcelp* qcelpAudio = static_cast<const T3GPAudioPropertiesQcelp*>(aAudio);
+ MP4Err err = MP4ComposeSetQCELPStorageMode(iHandler, qcelpAudio->iMode);
+ if ( err == MP4_OK)
+ {
+ if ( qcelpAudio->iMode == E3GPMP4AudioDescriptionBox)
+ {
+ err = MP4ComposeWriteAudioDecoderSpecificInfo(iHandler, const_cast<mp4_u8*>(qcelpAudio->iDecoderSpecificInfo.Ptr()), qcelpAudio->iDecoderSpecificInfo.Length ());
+ }
+ if ( err == MP4_OK)
+ {
+ //modeSet is needed only for AMR audio. Set it to 0 for Qcelp audio.
+ err = MP4ComposeAddAudioDescription(iHandler, qcelpAudio->iTimescale, qcelpAudio->iFramesPerSample, 0);
+ }
+ }
+
+ return SymbianOSError(err);
+ }
+
+// Set compose flag
+TInt C3GPCompose::SetComposeFlag(T3GPFileFormatType aFileFormat, TUint aFlag)
+ {
+ mp4_u32 fileFormat = 0;
+ switch (aFileFormat)
+ {
+ case (E3GPMP4):
+ fileFormat = MP4_FLAG_GENERATE_MP4;
+ break;
+ case (E3GP3G2):
+ fileFormat = MP4_FLAG_GENERATE_3G2;
+ break;
+ case (E3GP3GP):
+ fileFormat = MP4_FLAG_NONE;
+ break;
+ default:
+ Panic(KErrArgument);
+ }
+
+ MP4Err err = MP4ComposeSetFlags(iHandler, aFlag | fileFormat);
+ return SymbianOSError(err);
+ }
+
+
+void C3GPCompose::Panic(TInt aPanic)
+// Panic client
+ {
+ User::Panic(K3GPComposePanicName, aPanic);
+ }