1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/mmplugins/lib3gp/wrapper/src/c3gpcompose.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1026 @@
1.4 +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <e32debug.h>
1.20 +#include <c3gplibrary.h>
1.21 +
1.22 +#if defined (COMPOSE_DEBUG)
1.23 +#define DEBUG_PRINT RDebug::Print
1.24 +#else
1.25 +#define DEBUG_PRINT
1.26 +#endif
1.27 +
1.28 +const TInt KMinWriteBufferMaxCount = 6;
1.29 +_LIT(K3GPComposePanicName, "C3GPCompose");
1.30 +
1.31 +// This is video base class containing common video properties.
1.32 +T3GPVideoPropertiesBase::T3GPVideoPropertiesBase(T3GPVideoType aType,
1.33 + TUint aTimescale, const TSize& aSize) :
1.34 + iType(aType), iTimescale(aTimescale), iSize(aSize)
1.35 + {
1.36 + }
1.37 +
1.38 +/**
1.39 +This structure stores the common and MPEG-4 video specific properties of video data.
1.40 +
1.41 +@param aTimescale Timescale of the video data. This is the number of time units that
1.42 + pass in one second.
1.43 +@param aSize Video width and height in pixels.
1.44 +@param aMaxBitRate Maximum video bit rate.
1.45 +@param aAvgBitRate Average video bit rate.
1.46 +@param aDecoderSpecificInfo MPEG-4 video DecoderSpecificInfo data stored in an ESDS atom.
1.47 +*/
1.48 +EXPORT_C T3GPVideoPropertiesMpeg4Video::T3GPVideoPropertiesMpeg4Video(TUint aTimescale,
1.49 + const TSize& aSize, TUint aMaxBitRate, TUint aAvgBitRate, const TDesC8& aDecoderSpecificInfo) :
1.50 + T3GPVideoPropertiesBase(E3GPMpeg4Video, aTimescale, aSize),
1.51 + iMaxBitRate(aMaxBitRate),
1.52 + iAvgBitRate(aAvgBitRate),
1.53 + iDecoderSpecificInfo(aDecoderSpecificInfo)
1.54 + {
1.55 + }
1.56 +
1.57 +/**
1.58 +This structure stores the common and H.263 specific properties of video data.
1.59 +
1.60 +@param aTimescale Timescale of the video data. This is the number of time units that
1.61 + pass in one second.
1.62 +@param aSize Video width and height in pixels.
1.63 +@param aVideoLevel Indicates the H263 video level.
1.64 +@param aProfile Indicates the H263 profile.
1.65 +*/
1.66 +EXPORT_C T3GPVideoPropertiesH263::T3GPVideoPropertiesH263(TUint aTimescale, const TSize& aSize,
1.67 + TInt aVideoLevel, TProfile aProfile) :
1.68 +T3GPVideoPropertiesBase((aProfile == EProfile0) ? E3GPH263Profile0 : E3GPH263Profile3,
1.69 + aTimescale, aSize), iVideoLevel(aVideoLevel)
1.70 + {
1.71 + }
1.72 +
1.73 +/**
1.74 +This structure stores the common and AVC specific properties of video data.
1.75 +
1.76 +@param aTimescale Timescale of the video data. This is the number of time units that
1.77 + pass in one second.
1.78 +@param aSize Video width and height in pixels.
1.79 +@param aDecoderSpecificInfo AVCDecoderConfigurationRecord data that will be stored in the avcC atom.
1.80 +*/
1.81 +EXPORT_C T3GPVideoPropertiesAvc::T3GPVideoPropertiesAvc(TUint aTimescale, const TSize& aSize,
1.82 + const TDesC8& aDecoderSpecificInfo) :
1.83 +T3GPVideoPropertiesBase(E3GPAvcProfileBaseline, aTimescale, aSize),
1.84 +iDecoderSpecificInfo(aDecoderSpecificInfo)
1.85 + {
1.86 + /*
1.87 + NOTE: Although Baseline profile is being set here, it's just used to indicate
1.88 + the fact that we have AVC data. The underlying 3GP lib does not differentiate
1.89 + between profiles when composing a file. It simply writes the contents of
1.90 + iDecoderSpecificInfo (which contains the profile amongst other things)
1.91 + verbatim into the "avcC" box.
1.92 + */
1.93 + }
1.94 +
1.95 +// This is audio base class containing common audio properties.
1.96 +T3GPAudioPropertiesBase::T3GPAudioPropertiesBase(T3GPAudioType aType,
1.97 + TUint aTimescale, TInt aFramesPerSample) :
1.98 + iType(aType), iTimescale(aTimescale), iFramesPerSample(aFramesPerSample)
1.99 + {
1.100 + __ASSERT_ALWAYS((aTimescale > 0) && (aTimescale <= KMaxTUint16), User::Panic(K3GPComposePanicName, KErrOverflow));
1.101 + }
1.102 +
1.103 +/**
1.104 +This structure stores the common and MPEG-4 audio-specific properties of audio data.
1.105 +
1.106 +@param aTimescale Timescale of the audio data. This is the number of time units that pass in one
1.107 + second. It must be smaller than 65536.
1.108 +@param aDecoderSpecificInfo MPEG-4 audio DecoderSpecificInfo data stored in an ESDS atom.
1.109 +*/
1.110 +EXPORT_C T3GPAudioPropertiesMpeg4Audio::T3GPAudioPropertiesMpeg4Audio(TUint aTimescale,
1.111 + const TDesC8& aDecoderSpecificInfo) :
1.112 + T3GPAudioPropertiesBase(E3GPMpeg4Audio, aTimescale, 0),
1.113 + iDecoderSpecificInfo(aDecoderSpecificInfo)
1.114 + {
1.115 + }
1.116 +
1.117 +/**
1.118 +This structure stores the common and AMR-specific properties of audio data.
1.119 +
1.120 +@param aTimescale Timescale of the audio data. This is the number of time units that pass in one
1.121 + second. It must be smaller than 65536.
1.122 +@param aFramesPerSample Frames per sample. It must be smaller than 256.
1.123 + MPEG-4 audio has a fixed value of 1.
1.124 +@param aModeSet AMR mode set.
1.125 +@param aCodec AMR Speech Codec.
1.126 +*/
1.127 +EXPORT_C T3GPAudioPropertiesAmr::T3GPAudioPropertiesAmr(TUint aTimescale, TInt aFramesPerSample,
1.128 + TInt aModeSet, TSpeechCodec aCodec) :
1.129 + T3GPAudioPropertiesBase((aCodec == EAmrNB) ? E3GPAmrNB : E3GPAmrWB,
1.130 + aTimescale, aFramesPerSample), iModeSet(aModeSet)
1.131 + {
1.132 + __ASSERT_ALWAYS((aFramesPerSample > 0) && (aFramesPerSample <= KMaxTUint8),
1.133 + User::Panic(K3GPComposePanicName, KErrOverflow));
1.134 + }
1.135 +
1.136 +/**
1.137 +This structure stores the common and QCELP-specific properties of MPEG4 audio data. The storage mode is
1.138 +automatically set to MPEG4 Audio Sample Description Box mode.
1.139 +
1.140 +@param aTimescale Timescale of the audio data. This is the number of time units that pass in one
1.141 + second. It must be smaller than 65536.
1.142 +@param aFramesPerSample Frames per sample. It must be smaller than 512.
1.143 + MPEG-4 audio has a fixed value of 1.
1.144 +@param aDecoderSpecificInfo MPEG-4 audio decoder specific information data stored in an ESDS atom.
1.145 +*/
1.146 +EXPORT_C T3GPAudioPropertiesQcelp::T3GPAudioPropertiesQcelp(TUint aTimescale, TInt aFramesPerSample,
1.147 + const TDesC8& aDecoderSpecificInfo) :
1.148 + T3GPAudioPropertiesBase(E3GPQcelp13K, aTimescale, aFramesPerSample),
1.149 + iMode(E3GPMP4AudioDescriptionBox),
1.150 + iDecoderSpecificInfo(aDecoderSpecificInfo)
1.151 + {
1.152 + __ASSERT_ALWAYS((aFramesPerSample > 0) && (aFramesPerSample <= KMaxTUint8),
1.153 + User::Panic(K3GPComposePanicName, KErrOverflow));
1.154 + }
1.155 +
1.156 +/**
1.157 +This structure stores the common and QCELP-specific properties of audio data.
1.158 +
1.159 +@param aTimescale Timescale of the audio data. This is the number of time units that pass in one
1.160 + second. It must be smaller than 65536.
1.161 +@param aFramesPerSample Frames per sample. It must be smaller than 512.
1.162 + MPEG-4 audio has a fixed value of 1.
1.163 +*/
1.164 +
1.165 +EXPORT_C T3GPAudioPropertiesQcelp::T3GPAudioPropertiesQcelp(TUint aTimescale, TInt aFramesPerSample) :
1.166 + T3GPAudioPropertiesBase(E3GPQcelp13K, aTimescale, aFramesPerSample),
1.167 + iMode(E3GPQcelpSampleEntryBox),
1.168 + iDecoderSpecificInfo(KNullDesC8)
1.169 + {
1.170 + __ASSERT_ALWAYS((aFramesPerSample > 0) && (aFramesPerSample <= KMaxTUint8),
1.171 + User::Panic(K3GPComposePanicName, KErrOverflow));
1.172 + }
1.173 +
1.174 +/**
1.175 +Create an instance of 3GP composer using default buffer count and size.
1.176 +
1.177 +The default values for buffer count and size are as follow:
1.178 +Write Buffer Size is 2048
1.179 +Write Buffer Max Count is 15
1.180 +
1.181 +@return A pointer to the newly created 3gp compose object.
1.182 +
1.183 +@leave KErrGeneral General error.
1.184 +@leave KErrNoMemory Out of memory.
1.185 +
1.186 +@panic C3GPCompose KErrAbort if clients do not a CActiveScheduler installed already.
1.187 +*/
1.188 +EXPORT_C C3GPCompose* C3GPCompose::NewL()
1.189 + {
1.190 + // Leave if no scheduler exists
1.191 + __ASSERT_ALWAYS ((CActiveScheduler::Current() != NULL), Panic(KErrAbort));
1.192 + C3GPCompose* self = new (ELeave) C3GPCompose();
1.193 + return self;
1.194 + }
1.195 +
1.196 +/**
1.197 +Create an instance of 3GP composer, and let the user set a count limit and size of
1.198 +internal buffer for composition.
1.199 +
1.200 +The default values for buffer count and size are as follow:
1.201 + Write Buffer Size is 2048
1.202 + Write Buffer Max Count is 15
1.203 +
1.204 +An increase of the buffer count and size will lead to a decrease of file I/O activities, thereby,
1.205 +improves the performance of the 3GP Composer at the expense of higher memory usage.
1.206 +
1.207 +@param aMediaWriteBufferSize Size of media data file output buffer (in bytes).
1.208 +@param aWriteBufferMaxCount Maximum number of buffers (both media and meta) allowed before file
1.209 + output changes to synchronous (by default file writing is asynchronous
1.210 + operation). A minimum value of 6 is enforced.
1.211 +
1.212 +@return A pointer to the newly created 3gp compose object.
1.213 +
1.214 +@leave KErrGeneral General error.
1.215 +@leave KErrNoMemory Out of memory.
1.216 +
1.217 +@panic C3GPCompose KErrAbort if clients do not a CActiveScheduler installed already.
1.218 +@panic C3GPCompose KErrArgument if Write Buffer Size is less or equal to 0 or Write Buffer Max Count is
1.219 + less than 6.
1.220 + */
1.221 +EXPORT_C C3GPCompose* C3GPCompose::NewL(TInt aMediaWriteBufferSize, TInt aWriteBufferMaxCount)
1.222 + {
1.223 + __ASSERT_ALWAYS ((aMediaWriteBufferSize > 0 && aWriteBufferMaxCount >= KMinWriteBufferMaxCount),
1.224 + Panic(KErrArgument));
1.225 + // Leave if no scheduler exists
1.226 + __ASSERT_ALWAYS ((CActiveScheduler::Current() != NULL), Panic(KErrAbort));
1.227 +
1.228 + C3GPCompose* self = new (ELeave) C3GPCompose(aMediaWriteBufferSize, aWriteBufferMaxCount);
1.229 + return self;
1.230 + }
1.231 +
1.232 +// First phase constructor
1.233 +C3GPCompose::C3GPCompose(TInt aMediaWriteBufferSize, TInt aWriteBufferMaxCount) :
1.234 + iMediaWriteBufferSize(aMediaWriteBufferSize),
1.235 + iWriteBufferMaxCount(aWriteBufferMaxCount),
1.236 + iDuplicateFileHandleCreated(EFalse)
1.237 + {
1.238 + }
1.239 +
1.240 +/**
1.241 +This function initialises the 3GP composer for writing 3GP/3G2/MP4 data into a file.
1.242 +Any combination of one video and one audio type is acceptable.
1.243 +
1.244 +Note: Ownership of aVideo and aAudio remains with the caller. Both aVideo and aAudio are ready for
1.245 +deletion after C3GPCompose::Open returns.
1.246 +
1.247 +@param aFileFormat Specifies the file format in which the data will be created. Refer to
1.248 + T3GPFileFormatType for supported file format types.
1.249 +@param aVideo Specifies the video stream to be used for video data. The input data given will
1.250 + be inserted into 3GP file headers and is ready to be disposed when
1.251 + C3GPCompose::Open returns. See Video Properties Classes.
1.252 + If aVideo is NULL, audio-only file will be composed.
1.253 +@param aAudio Specifies the audio stream to be used for audio data. The input data given will
1.254 + be inserted into 3GP file headers and is ready to be disposed when
1.255 + C3GPCompose::Open returns. See Audio Properties Classes.
1.256 + If aAudio is NULL, video-only file will be composed.
1.257 +@param aFilename A full path name of the file to save the data to. An empty path is not allowed.
1.258 +@param aFlags Optional flags for composing preferences. Refer to T3GPComposeFlag for supported flags.
1.259 + The combined use of flags is acceptable. For example:
1.260 + E3GPLongClip | E3GPMetaDataLast
1.261 +
1.262 +@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
1.263 + KErrGeneral if an error has no specific categorisation;
1.264 + KErrNoMemory if an attempt to allocate memory has failed;
1.265 + KErrArgument if neither video nor audio stream is specified;
1.266 + KErrAccessDenied if opening file has failed;
1.267 + KErrUnderflow if the file name length is not greater than 0;
1.268 + KErrInUse if the composer is currently engaged; C3GPCompose::Complete must be called to
1.269 + finish the current composition before the composer can be re-initialised again.
1.270 +*/
1.271 +EXPORT_C TInt C3GPCompose::Open(T3GPFileFormatType aFileFormat,
1.272 + const T3GPVideoPropertiesBase* aVideo,
1.273 + const T3GPAudioPropertiesBase* aAudio,
1.274 + const TDesC& aFilename,
1.275 + TUint aFlags)
1.276 + {
1.277 + if (iHandler)
1.278 + {
1.279 + return KErrInUse;
1.280 + }
1.281 + if (aFilename.Length() <= 0)
1.282 + {
1.283 + return KErrUnderflow;
1.284 + }
1.285 + if (!aVideo && !aAudio)
1.286 + {
1.287 + // if neither video nor audio is supplied
1.288 + return KErrArgument;
1.289 + }
1.290 +
1.291 + // Create a zero terminated version of the file name
1.292 + RBuf fileName;
1.293 + TInt err = fileName.Create(aFilename.Length() + 1);
1.294 + if (err == KErrNone)
1.295 + {
1.296 + fileName.Copy(aFilename);
1.297 + mp4_u16* mp4FileName = const_cast<mp4_u16*>(fileName.PtrZ());
1.298 + MP4Err mp4Err = MP4ComposeOpen(&iHandler, reinterpret_cast<MP4FileName>(mp4FileName), Mp4Type(aVideo, aAudio));
1.299 +
1.300 + if (mp4Err == MP4_OK)
1.301 + {
1.302 + // Write audio and video properties to the 3GP file
1.303 + err = SetComposeProperties(aVideo, aAudio, aFileFormat, aFlags);
1.304 + if (err != KErrNone)
1.305 + {
1.306 + Complete(); // Ingore the error
1.307 + }
1.308 + }
1.309 + else
1.310 + {
1.311 + err = SymbianOSError(mp4Err);
1.312 + }
1.313 + }
1.314 + fileName.Close();
1.315 + return err;
1.316 + }
1.317 +
1.318 +/**
1.319 +This function initialises the 3GP composer for writing 3GP/3G2/MP4 data into a file.
1.320 +Any combination of one video and one audio type is acceptable.
1.321 +
1.322 +Note: E3GPMetaDataLast will be defaulted in aFlags if file handle is used for the initialisation
1.323 +of the 3GP composer.
1.324 +
1.325 +Note: Ownership of aVideo and aAudio remains with the caller. Both aVideo and aAudio are ready for
1.326 +deletion after C3GPCompose::Open returns.
1.327 +
1.328 +@param aFileFormat Specifies the file format in which the data will be created. Refer to
1.329 + T3GPFileFormatType for supported file format types.
1.330 +@param aVideo Specifies the video stream to be used for video data. The input data given will
1.331 + be inserted into 3GP file headers and is ready to be disposed when
1.332 + C3GPCompose::Open returns. See Video Properties Classes.
1.333 + If aVideo is NULL, audio-only file will be composed.
1.334 +@param aAudio Specifies the audio stream to be used for audio data. The input data given will
1.335 + be inserted into 3GP file headers and is ready to be disposed when
1.336 + C3GPCompose::Open returns. See Audio Properties Classes.
1.337 + If aAudio is NULL, video-only file will be composed.
1.338 +@param aFile File handle of the file to save the data to. E3GPMetaDataLast needs to be set for
1.339 + aFlags when this is used.
1.340 +@param aFlags Optional flags for composing preferences. Refer to T3GPComposeFlag for supported flags.
1.341 + The combined use of flags is acceptable. For example:
1.342 + E3GPLongClip | E3GPMetaDataLast
1.343 +
1.344 +@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
1.345 + KErrGeneral if an error has no specific categorisation;
1.346 + KErrNoMemory if an attempt to allocate memory has failed;
1.347 + KErrArgument if neither video nor audio stream is specified;
1.348 + KErrAccessDenied if opening file has failed;
1.349 + KErrInUse if the composer is currently engaged; C3GPCompose::Complete must be called to
1.350 + finish the current composition before the composer can be re-initialised again.
1.351 +*/
1.352 +
1.353 +EXPORT_C TInt C3GPCompose::Open(T3GPFileFormatType aFileFormat,
1.354 + const T3GPVideoPropertiesBase* aVideo,
1.355 + const T3GPAudioPropertiesBase* aAudio,
1.356 + RFile& aFile,
1.357 + TUint aFlags)
1.358 + {
1.359 + TInt err = KErrNone;
1.360 + if (!iDuplicateFileHandleCreated)
1.361 + {
1.362 + iDuplicateFileHandleCreated = ETrue;
1.363 + iFile.Close();
1.364 + err = iFile.Duplicate(aFile);
1.365 + if (err != KErrNone)
1.366 + {
1.367 + return err;
1.368 + }
1.369 + }
1.370 +
1.371 + return Open(aFileFormat, aVideo, aAudio, iFile, aFlags);
1.372 + }
1.373 +
1.374 +/**
1.375 +This function initialises the 3GP composer for writing 3GP/3G2/MP4 data into a file.
1.376 +Any combination of one video and one audio type is acceptable.
1.377 +
1.378 +Note: E3GPMetaDataLast will be defaulted in aFlags if file handle is used for the initialisation
1.379 +of the 3GP composer.
1.380 +
1.381 +Note: Ownership of aVideo and aAudio remains with the caller. Both aVideo and aAudio are ready for
1.382 +deletion after C3GPCompose::Open returns.
1.383 +
1.384 +@param aFileFormat Specifies the file format in which the data will be created. Refer to
1.385 + T3GPFileFormatType for supported file format types.
1.386 +@param aVideo Specifies the video stream to be used for video data. The input data given will
1.387 + be inserted into 3GP file headers and is ready to be disposed when
1.388 + C3GPCompose::Open returns. See Video Properties Classes.
1.389 + If aVideo is NULL, audio-only file will be composed.
1.390 +@param aAudio Specifies the audio stream to be used for audio data. The input data given will
1.391 + be inserted into 3GP file headers and is ready to be disposed when
1.392 + C3GPCompose::Open returns. See Audio Properties Classes.
1.393 + If aAudio is NULL, video-only file will be composed.
1.394 +@param aFile File handle of the file to save the data to. E3GPMetaDataLast needs to be set for
1.395 + aFlags when this is used.
1.396 +@param aFlags Optional flags for composing preferences. Refer to T3GPComposeFlag for supported flags.
1.397 + The combined use of flags is acceptable. For example:
1.398 + E3GPLongClip | E3GPMetaDataLast
1.399 +
1.400 +@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
1.401 + KErrGeneral if an error has no specific categorisation;
1.402 + KErrNoMemory if an attempt to allocate memory has failed;
1.403 + KErrArgument if neither video nor audio stream is specified;
1.404 + KErrAccessDenied if opening file has failed;
1.405 + KErrInUse if the composer is currently engaged; C3GPCompose::Complete must be called to
1.406 + finish the current composition before the composer can be re-initialised again.
1.407 +*/
1.408 +EXPORT_C TInt C3GPCompose::Open(T3GPFileFormatType aFileFormat,
1.409 + const T3GPVideoPropertiesBase* aVideo,
1.410 + const T3GPAudioPropertiesBase* aAudio,
1.411 + RFile64& aFile,
1.412 + TUint aFlags)
1.413 + {
1.414 + if (iHandler)
1.415 + {
1.416 + return KErrInUse;
1.417 + }
1.418 + if (!aVideo && !aAudio)
1.419 + {
1.420 + // if neither video nor audio is supplied
1.421 + return KErrArgument;
1.422 + }
1.423 +
1.424 + TInt driveNumber = EDriveA;
1.425 + TDriveInfo driveInfo;
1.426 + TInt err = aFile.Drive(driveNumber, driveInfo);
1.427 + if (err == KErrNone)
1.428 + {
1.429 + MP4Err mp4Err = MP4ComposeOpenFileHandle64(&iHandler, &aFile, static_cast<TDriveNumber>(driveNumber), Mp4Type(aVideo, aAudio));
1.430 + if (mp4Err == MP4_OK)
1.431 + {
1.432 + // Write audio and video properties to the 3GP file
1.433 + err = SetComposeProperties(aVideo, aAudio, aFileFormat, aFlags);
1.434 + if (err != KErrNone)
1.435 + {
1.436 + Complete(); // Ingore the error
1.437 + }
1.438 + }
1.439 + else
1.440 + {
1.441 + err = SymbianOSError(mp4Err);
1.442 + }
1.443 + }
1.444 +
1.445 + return err;
1.446 + }
1.447 +
1.448 +/**
1.449 +Destructor
1.450 +Deletes all objects and releases all resource owned by this instance.
1.451 +*/
1.452 +EXPORT_C C3GPCompose::~C3GPCompose()
1.453 + {
1.454 + Complete(); // Ignore the error
1.455 + }
1.456 +
1.457 +/**
1.458 +This function completes the composing operation. It frees the memory allocated by the library instance
1.459 +and closes the output file.
1.460 +
1.461 +It is necessary to call this function before the output file is guaranteed to be a valid output file
1.462 +even though the file may exist prior to the call.
1.463 +
1.464 +The composer can be reused again after this call, following another call to C3GPCompose::Open to
1.465 +re-initialise the composer.
1.466 +
1.467 +If C3GPCompose::Complete is called before the composer is initialised, it will be ignored and KErrNone
1.468 +is returned.
1.469 +
1.470 +Although during destruction of C3GPCompose, this function will be automatically called, and no error
1.471 +code will be returned. Therefore, when destroying the Composer object that you have used to compose a
1.472 +file, you should ensure that data is committed to the file by invoking C3GPCompose::Complete before
1.473 +destroying the Composer object.
1.474 +
1.475 +@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
1.476 + KErrGeneral if an error has no specific categorisation;
1.477 + KErrWrite if metadata could not be written.
1.478 +*/
1.479 +EXPORT_C TInt C3GPCompose::Complete()
1.480 + {
1.481 + MP4Err mp4Err = MP4_OK;
1.482 + if (iHandler)
1.483 + {
1.484 + mp4Err = MP4ComposeClose(iHandler);
1.485 + }
1.486 + // Always reset the class member data even this function returns error
1.487 + Reset();
1.488 + return SymbianOSError(mp4Err);
1.489 + }
1.490 +
1.491 +// Helper function to reset class member data.
1.492 +void C3GPCompose::Reset()
1.493 + {
1.494 + iHasVideo = EFalse;
1.495 + iHasAudio = EFalse;
1.496 + iHandler = NULL;
1.497 + iFile.Close();
1.498 + }
1.499 +
1.500 +/**
1.501 +This function writes one video frame to the output file or buffer.
1.502 +
1.503 +The frames must be inserted according to their causal sequence. Because the library doesn't analyze
1.504 +the video bit stream, frames are inserted into the 3GP file in the same order as they are entered
1.505 +with this function. Therefore, the frames will not be retrieved from the resulting 3GP file or
1.506 +buffer correctly if they are not in proper order.
1.507 +
1.508 +A frame inserted with this function call will result in one 3GP sample and one 3GP chunk.
1.509 +
1.510 +The current frame's dependency information which is using default values (E3GPDependencyUnknown &
1.511 +E3GPRedundancyUnknown) is inserted.
1.512 +
1.513 +The data is available in the output file only after calling C3GPCompose::Complete. C3GPCompose::Complete
1.514 +should be called exactly once when all audio and video data has been inserted into the library.
1.515 +
1.516 +@param aBuffer The descriptor containing the video frame data to be written.
1.517 +@param aDuration Duration of video frame in timescale, see T3GPVideoPropertiesBase.
1.518 +@param aKeyFrame ETrue to indicate whether this frame is a key frame. EFalse otherwise.
1.519 +
1.520 +@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
1.521 + KErrGeneral if an error has no specific categorisation;
1.522 + KErrNotSupported if the composer is setup for an audio-only file;
1.523 + KErrUnderflow if the supplied video frame buffer data is empty;
1.524 + KErrNotReady if the composer has not yet been initialised; See C3GPCompose::Open.
1.525 +*/
1.526 +EXPORT_C TInt C3GPCompose::WriteVideoFrame(const TDesC8& aBuffer, TUint aDuration, TBool aKeyFrame)
1.527 + {
1.528 + if (!iHandler)
1.529 + {
1.530 + return KErrNotReady;
1.531 + }
1.532 + if (aBuffer.Length() <= 0)
1.533 + {
1.534 + return KErrUnderflow;
1.535 + }
1.536 + if (!iHasVideo)
1.537 + {
1.538 + return KErrNotSupported;
1.539 + }
1.540 +
1.541 + // Insert video frame data
1.542 + mp4_bool keyFrame = aKeyFrame;
1.543 + mp4_u32 duration = aDuration;
1.544 + MP4Err mp4Err = MP4ComposeWriteVideoFrame(iHandler, const_cast<mp4_u8*>(aBuffer.Ptr()), aBuffer.Length(), duration, keyFrame);
1.545 +
1.546 + return SymbianOSError(mp4Err);
1.547 + }
1.548 +
1.549 +/**
1.550 +This function sets the current frame's dependency information to SDTP box and writes one video frame
1.551 +to the output file.
1.552 +
1.553 +The frames must be inserted according to their causal sequence. Because the library doesn't analyze
1.554 +the video bit stream, frames are inserted into the 3GP file in the same order as they are entered
1.555 +with this function. Therefore, the frames will not be retrieved from the resulting 3GP file or
1.556 +buffer correctly if they are not in proper order.
1.557 +
1.558 +A frame inserted with this function call will result in one 3GP sample and one 3GP chunk.
1.559 +
1.560 +The data is available in the output file only after calling C3GPCompose::Complete. C3GPCompose::Complete
1.561 +should be called exactly once when all audio and video data has been inserted into the library.
1.562 +
1.563 +@param aBuffer The descriptor containing the video frame data to be written.
1.564 +@param aDuration Duration of video frame in timescale, see T3GPVideoPropertiesBase.
1.565 +@param aKeyFrame ETrue to indicate whether this frame is a key frame. EFalse otherwise.
1.566 +@param aDependencies This specifies the current frame's dependency information.
1.567 + The information will be supplied into the SDTP box.
1.568 + See T3GPFrameDependencies.
1.569 +
1.570 +@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
1.571 + KErrGeneral if an error has no specific categorisation;
1.572 + KErrNotSupported if the composer is setup for an audio-only file;
1.573 + KErrUnderflow if the supplied video frame buffer data is empty;
1.574 + KErrNotReady if the composer has not yet been initialised; See C3GPCompose::Open.
1.575 +*/
1.576 +EXPORT_C TInt C3GPCompose::WriteVideoFrame(const TDesC8& aBuffer, TUint aDuration, TBool aKeyFrame,
1.577 + const T3GPFrameDependencies& aDependencies)
1.578 + {
1.579 + if (!iHandler)
1.580 + {
1.581 + return KErrNotReady;
1.582 + }
1.583 + if (aBuffer.Length() <= 0)
1.584 + {
1.585 + return KErrUnderflow;
1.586 + }
1.587 + if (!iHasVideo)
1.588 + {
1.589 + return KErrNotSupported;
1.590 + }
1.591 +
1.592 + // Insert the current frame's dependency information
1.593 + MP4Err mp4Err = MP4ComposeWriteNextVideoFrameDependencies(iHandler, aDependencies.iDependsOn,
1.594 + aDependencies.iIsDependedOn, aDependencies.iHasRedundancy);
1.595 +
1.596 + if (mp4Err == MP4_OK)
1.597 + {
1.598 + // Insert video frame data
1.599 + mp4_bool keyFrame = aKeyFrame;
1.600 + mp4_u32 duration = aDuration;
1.601 + mp4Err = MP4ComposeWriteVideoFrame(iHandler, const_cast<mp4_u8*>(aBuffer.Ptr()),
1.602 + aBuffer.Length(), duration, keyFrame);
1.603 + }
1.604 +
1.605 + return SymbianOSError(mp4Err);
1.606 + }
1.607 +
1.608 +/**
1.609 +This function writes audio frames into the output file or buffer. The data is available in the
1.610 +3GP output file only after calling C3GPCompose::Complete. C3GPCompose::Complete should be called exactly
1.611 +once when all audio and video data has been inserted into the library.
1.612 +
1.613 +For MPEG-4 audio:
1.614 +This function writes one MPEG audio frame to the 3GP file.
1.615 +
1.616 +For other audio types:
1.617 +This function writes a number of audio frames to the 3GP file specified during composer setup
1.618 +in the input parameter aAudio when calling C3GPCompose::Open. All audio frames inserted with
1.619 +one function call will be placed inside one sample in the resulting file.
1.620 +
1.621 +Note: Only the last call can have a different number of frames if the number is less than
1.622 +the number of frames per sample specified during composer setup.
1.623 +
1.624 +@see T3GPAudioPropertiesAmr
1.625 +@see T3GPAudioPropertiesQcelp
1.626 +
1.627 +@param aBuffer The descriptor containing the audio data to be written.
1.628 +@param aDuration Duration of audio frames in timescale, see T3GPAudioPropertiesBase
1.629 +
1.630 +@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
1.631 + KErrGeneral if an error has no specific categorisation;
1.632 + KErrNotSupported if the composer is setup for a video-only file;
1.633 + KErrUnderflow if the supplied audio frames buffer data is empty;
1.634 + KErrNotReady if the composer has not yet been initialised; See C3GPCompose::Open.
1.635 +*/
1.636 +EXPORT_C TInt C3GPCompose::WriteAudioFrames(const TDesC8& aBuffer, TUint aDuration)
1.637 + {
1.638 + if (!iHandler)
1.639 + {
1.640 + return KErrNotReady;
1.641 + }
1.642 + if (aBuffer.Length() <= 0)
1.643 + {
1.644 + return KErrUnderflow;
1.645 + }
1.646 + if (!iHasAudio)
1.647 + {
1.648 + return KErrNotSupported;
1.649 + }
1.650 +
1.651 + mp4_u32 duration = aDuration;
1.652 + // use 0 for the number of frames since it is being ignored within the mp4 library implementation
1.653 + MP4Err mp4Err = MP4ComposeWriteAudioFrames(iHandler, const_cast<mp4_u8*>(aBuffer.Ptr()),
1.654 + aBuffer.Length(), 0, duration);
1.655 +
1.656 + return SymbianOSError(mp4Err);
1.657 + }
1.658 +
1.659 +/**
1.660 +Writes a buffer containing whole atom to inside of user data atom (UDTA) defined in aLocation.
1.661 +
1.662 +The buffer should contain an atom of structure that conforms to the definition of a "full box"
1.663 +as specified in ISO/IEC 14496-12:2003: "Information technology – Coding of audio-visual objects
1.664 + – Part 12: ISO base media file format."
1.665 +
1.666 +For more information on user data atoms, see Section 8 – Asset Information of "3GPP TS 26.244
1.667 +version 6.1.0 – 3GP file format (Rel 6)."
1.668 +
1.669 +@param aLocation Specifies the location of user information to be written. Refer to
1.670 + T3GPUdtaLocation for possible values.
1.671 +@param aBuffer The descriptor containing the user information to write into file.
1.672 +
1.673 +@return KErrNone if successful. Otherwise, returns one of the system wide error codes.
1.674 + KErrGeneral if an error has no specific categorisation;
1.675 + KErrArgument if asked aLocation is invalid;
1.676 + KErrUnderflow if the supplied buffer data is empty;
1.677 + KErrNotSupported if specify video track user data but no video type is specified,
1.678 + or specify audio track user data but no audio type is specified
1.679 + KErrNoMemory if an attempt to allocate memory has failed;
1.680 + KErrNotReady if the composer has not yet been initialised; See C3GPCompose::Open.
1.681 +
1.682 +@panic C3GPCompose KErrArgument if the location of user information is not of T3GPUdtaLocation.
1.683 +*/
1.684 +EXPORT_C TInt C3GPCompose::SetUserData(T3GPUdtaLocation aLocation, const TDesC8& aBuffer)
1.685 + {
1.686 + if (!iHandler)
1.687 + {
1.688 + return KErrNotReady;
1.689 + }
1.690 + if (aBuffer.Length() <= 0)
1.691 + {
1.692 + return KErrUnderflow;
1.693 + }
1.694 + if ((!iHasAudio && aLocation == E3GPUdtaAudioTrak) || (!iHasVideo && aLocation == E3GPUdtaVideoTrak))
1.695 + {
1.696 + return KErrNotSupported;
1.697 + }
1.698 +
1.699 + mp4_u8 location;
1.700 + switch (aLocation)
1.701 + {
1.702 + case (E3GPUdtaMoov):
1.703 + location = MP4_UDTA_MOOV;
1.704 + break;
1.705 + case (E3GPUdtaVideoTrak):
1.706 + location = MP4_UDTA_VIDEOTRAK;
1.707 + break;
1.708 + case (E3GPUdtaAudioTrak):
1.709 + location = MP4_UDTA_AUDIOTRAK;
1.710 + break;
1.711 + default:
1.712 + Panic(KErrArgument);
1.713 + break;
1.714 + }
1.715 +
1.716 + mp4_u32 bufferSize = aBuffer.Length();
1.717 + MP4Err mp4Err = MP4ComposeSetUserDataAtom(iHandler, location, const_cast<mp4_u8*>(aBuffer.Ptr()), bufferSize);
1.718 + return SymbianOSError(mp4Err);
1.719 + }
1.720 +
1.721 +// Helper function to convert 3GP/MP4 library specific error codes to system wide error codes
1.722 +TInt C3GPCompose::SymbianOSError(MP4Err aError)
1.723 + {
1.724 + TInt error = KErrNone;
1.725 +
1.726 + switch (aError)
1.727 + {
1.728 + case (MP4_OK):
1.729 + break;
1.730 + case (MP4_ERROR):
1.731 + error = KErrGeneral;
1.732 + break;
1.733 + case (MP4_OUT_OF_MEMORY):
1.734 + error = KErrNoMemory;
1.735 + break;
1.736 + case (MP4_FILE_ERROR):
1.737 + error = KErrAccessDenied;
1.738 + break;
1.739 + case (MP4_INVALID_TYPE):
1.740 + error = KErrArgument;
1.741 + break;
1.742 + case (MP4_METADATA_ERROR):
1.743 + error = KErrWrite;
1.744 + break;
1.745 + default:
1.746 + Panic(KErrArgument);
1.747 + }
1.748 + return error;
1.749 + }
1.750 +
1.751 +// Helper function to map 3GP enum type to MP4 audio and video type
1.752 +mp4_u32 C3GPCompose::Mp4Type(const T3GPVideoPropertiesBase* aVideo, const T3GPAudioPropertiesBase* aAudio)
1.753 + {
1.754 + mp4_u32 videoType = MP4_TYPE_NONE;
1.755 + mp4_u32 audioType = MP4_TYPE_NONE;
1.756 +
1.757 + if (aVideo)
1.758 + {
1.759 + iHasVideo = ETrue;
1.760 + switch (aVideo->iType)
1.761 + {
1.762 + case (E3GPMpeg4Video):
1.763 + videoType = MP4_TYPE_MPEG4_VIDEO;
1.764 + break;
1.765 + case (E3GPH263Profile0):
1.766 + videoType = MP4_TYPE_H263_PROFILE_0;
1.767 + break;
1.768 + case (E3GPH263Profile3):
1.769 + videoType = MP4_TYPE_H263_PROFILE_3;
1.770 + break;
1.771 +
1.772 + /*
1.773 + * NOTE: The underlying 3GP library does
1.774 + * not differentiate between the various AVC
1.775 + * profiles when composing.
1.776 + *
1.777 + * In all cases it will simply copy the data
1.778 + * from the iDecoderSpecificInfo member of
1.779 + * T3GPVideoPropertiesAvc into the 'avcC' atom.
1.780 + * It does not do any checking of that data, so
1.781 + * it is the API user's responsibility to ensure
1.782 + * that it contains a valid AVCDecoderConfigurationRecord
1.783 + * with the correct AVC profile and level.
1.784 + *
1.785 + * An interesting side-effect of this is that you can
1.786 + * compose AVC data with arbitrary profiles even if they
1.787 + * are not "supported" by this API. For example, as long
1.788 + * as the AVCDecoderConfigurationRecord says there is
1.789 + * High 10 profile data and the AVC data is of that profile
1.790 + * then you will still end up with a valid file.
1.791 + */
1.792 + case (E3GPAvcProfileBaseline):
1.793 + videoType = MP4_TYPE_AVC_PROFILE_BASELINE;
1.794 + break;
1.795 + case (E3GPAvcProfileMain):
1.796 + videoType = MP4_TYPE_AVC_PROFILE_MAIN;
1.797 + break;
1.798 + case (E3GPAvcProfileExtended):
1.799 + videoType = MP4_TYPE_AVC_PROFILE_EXTENDED;
1.800 + break;
1.801 + case (E3GPAvcProfileHigh):
1.802 + videoType = MP4_TYPE_AVC_PROFILE_HIGH;
1.803 + break;
1.804 + default:
1.805 + Panic(KErrArgument);
1.806 + }
1.807 + }
1.808 +
1.809 + if(aAudio)
1.810 + {
1.811 + iHasAudio = ETrue;
1.812 + switch (aAudio->iType)
1.813 + {
1.814 + case (E3GPMpeg4Audio):
1.815 + audioType = MP4_TYPE_MPEG4_AUDIO;
1.816 + break;
1.817 + case (E3GPAmrNB):
1.818 + audioType = MP4_TYPE_AMR_NB;
1.819 + break;
1.820 + case (E3GPAmrWB):
1.821 + audioType = MP4_TYPE_AMR_WB;
1.822 + break;
1.823 + case (E3GPQcelp13K):
1.824 + audioType = MP4_TYPE_QCELP_13K;
1.825 + break;
1.826 + default:
1.827 + Panic(KErrArgument);
1.828 + }
1.829 + }
1.830 + return (videoType | audioType);
1.831 + }
1.832 +
1.833 +// Helper function to set compose properties
1.834 +TInt C3GPCompose::SetComposeProperties(const T3GPVideoPropertiesBase* aVideo,
1.835 + const T3GPAudioPropertiesBase* aAudio, T3GPFileFormatType aFileFormat, TUint aFlag)
1.836 + {
1.837 + mp4_u32 writeBufferSize = iMediaWriteBufferSize;
1.838 + mp4_u32 writeBufferMaxCount = iWriteBufferMaxCount;
1.839 + MP4Err mp4Err = MP4SetCustomFileBufferSizes(iHandler, writeBufferSize, writeBufferMaxCount, 0);
1.840 + if ( mp4Err != MP4_OK)
1.841 + {
1.842 + return SymbianOSError(mp4Err);
1.843 + }
1.844 +
1.845 + // Set compose flag before other MP4Compose functions
1.846 + TInt err = SetComposeFlag(aFileFormat, aFlag);
1.847 + if (err != KErrNone)
1.848 + {
1.849 + return err;
1.850 + }
1.851 +
1.852 + if (aVideo)
1.853 + {
1.854 + switch (aVideo->iType)
1.855 + {
1.856 + case (E3GPMpeg4Video):
1.857 + err = SetMPeg4VideoProperties(aVideo);
1.858 + break;
1.859 + case (E3GPAvcProfileBaseline):
1.860 + case (E3GPAvcProfileMain):
1.861 + case (E3GPAvcProfileExtended):
1.862 + case (E3GPAvcProfileHigh):
1.863 + err = SetAvcVideoProperties(aVideo);
1.864 + break;
1.865 + case (E3GPH263Profile0):
1.866 + case (E3GPH263Profile3):
1.867 + err = SetH263VideoProperties(aVideo);
1.868 + break;
1.869 + default:
1.870 + Panic(KErrArgument);
1.871 + }
1.872 + }
1.873 + if (err != KErrNone)
1.874 + {
1.875 + return err;
1.876 + }
1.877 +
1.878 + if (aAudio)
1.879 + {
1.880 + switch (aAudio->iType)
1.881 + {
1.882 + case (E3GPMpeg4Audio):
1.883 + err = SetMpeg4AudioProperties(aAudio);
1.884 + break;
1.885 + case (E3GPQcelp13K):
1.886 + err = SetQcelpAudioProperties(aAudio);
1.887 + break;
1.888 + case (E3GPAmrNB):
1.889 + case (E3GPAmrWB):
1.890 + err = SetAmrAudioProperties(aAudio);
1.891 + break;
1.892 + default:
1.893 + Panic(KErrArgument);
1.894 + }
1.895 + }
1.896 + return err;
1.897 + }
1.898 +
1.899 +// Inform the 3GP library about the MPeg4 video data
1.900 +TInt C3GPCompose::SetMPeg4VideoProperties(const T3GPVideoPropertiesBase* aVideo)
1.901 + {
1.902 + const T3GPVideoPropertiesMpeg4Video* mpeg4Video = static_cast<const T3GPVideoPropertiesMpeg4Video*>(aVideo);
1.903 +
1.904 + MP4Err err = MP4ComposeWriteVideoDecoderSpecificInfo(iHandler, const_cast<mp4_u8*>(mpeg4Video->iDecoderSpecificInfo.Ptr()),
1.905 + mpeg4Video->iDecoderSpecificInfo.Length());
1.906 +
1.907 + if ( err == MP4_OK)
1.908 + {
1.909 + err = MP4ComposeAddVideoDescription(iHandler, mpeg4Video->iTimescale,
1.910 + mpeg4Video->iSize.iWidth, mpeg4Video->iSize.iHeight,
1.911 + mpeg4Video->iMaxBitRate, mpeg4Video->iAvgBitRate);
1.912 + }
1.913 +
1.914 + return SymbianOSError(err);
1.915 + }
1.916 +
1.917 +// Inform the 3GP library about the AVC video data
1.918 +TInt C3GPCompose::SetAvcVideoProperties(const T3GPVideoPropertiesBase* aVideo)
1.919 + {
1.920 + const T3GPVideoPropertiesAvc* avcVideo = static_cast<const T3GPVideoPropertiesAvc*>(aVideo);
1.921 +
1.922 + MP4Err err = MP4ComposeWriteVideoDecoderSpecificInfo(iHandler, const_cast<mp4_u8*>(avcVideo->iDecoderSpecificInfo.Ptr()),
1.923 + avcVideo->iDecoderSpecificInfo.Length ());
1.924 +
1.925 + if ( err == MP4_OK)
1.926 + {
1.927 + // aMaxBitRate and aAvgBitRate are MPEG-4 video specific values. Set 0 for them
1.928 + err = MP4ComposeAddVideoDescription(iHandler, avcVideo->iTimescale,
1.929 + avcVideo->iSize.iWidth, avcVideo->iSize.iHeight, 0, 0);
1.930 + }
1.931 +
1.932 + return SymbianOSError(err);
1.933 + }
1.934 +
1.935 +// Inform the 3GP library about the H263 video data
1.936 +TInt C3GPCompose::SetH263VideoProperties(const T3GPVideoPropertiesBase* aVideo)
1.937 + {
1.938 + // aMaxBitRate and aAvgBitRate are MPEG-4 video specific values. Set 0 for H263 video
1.939 + MP4Err err = MP4ComposeAddVideoDescription(iHandler, aVideo->iTimescale,
1.940 + aVideo->iSize.iWidth, aVideo->iSize.iHeight, 0, 0);
1.941 +
1.942 + if ( err == MP4_OK)
1.943 + {
1.944 + const T3GPVideoPropertiesH263* h263Video = static_cast<const T3GPVideoPropertiesH263*>(aVideo);
1.945 + TVideoClipProperties properties;
1.946 + properties.iH263Level = h263Video->iVideoLevel;
1.947 + err = MP4ComposeSetVideoClipProperties(iHandler, properties);
1.948 + }
1.949 +
1.950 + return SymbianOSError(err);
1.951 + }
1.952 +
1.953 +// Inform the 3GP library about the MPeg4 audio data
1.954 +TInt C3GPCompose::SetMpeg4AudioProperties(const T3GPAudioPropertiesBase* aAudio)
1.955 + {
1.956 + const T3GPAudioPropertiesMpeg4Audio* mpeg4Audio = static_cast<const T3GPAudioPropertiesMpeg4Audio*>(aAudio);
1.957 +
1.958 + MP4Err err = MP4ComposeWriteAudioDecoderSpecificInfo(iHandler, const_cast<mp4_u8*>(mpeg4Audio->iDecoderSpecificInfo.Ptr()),
1.959 + mpeg4Audio->iDecoderSpecificInfo.Length ());
1.960 +
1.961 + if ( err == MP4_OK)
1.962 + {
1.963 + //modeSet is needed only for AMR audio. Set it to 0 for Mpeg4 audio.
1.964 + err = MP4ComposeAddAudioDescription(iHandler, mpeg4Audio->iTimescale, mpeg4Audio->iFramesPerSample, 0);
1.965 + }
1.966 +
1.967 + return SymbianOSError(err);
1.968 + }
1.969 +
1.970 +// Inform the 3GP library about the Amr audio data
1.971 +TInt C3GPCompose::SetAmrAudioProperties(const T3GPAudioPropertiesBase* aAudio)
1.972 + {
1.973 + const T3GPAudioPropertiesAmr* amrAudio = static_cast<const T3GPAudioPropertiesAmr*>(aAudio);
1.974 + //modeSet is needed only for AMR audio.
1.975 + MP4Err err = MP4ComposeAddAudioDescription(iHandler, amrAudio->iTimescale,
1.976 + amrAudio->iFramesPerSample, amrAudio->iModeSet);
1.977 + return SymbianOSError(err);
1.978 + }
1.979 +
1.980 +// Sets the storage mode of storing 13K QCELP data in a 3G2 file
1.981 +TInt C3GPCompose::SetQcelpAudioProperties(const T3GPAudioPropertiesBase* aAudio)
1.982 + {
1.983 + const T3GPAudioPropertiesQcelp* qcelpAudio = static_cast<const T3GPAudioPropertiesQcelp*>(aAudio);
1.984 + MP4Err err = MP4ComposeSetQCELPStorageMode(iHandler, qcelpAudio->iMode);
1.985 + if ( err == MP4_OK)
1.986 + {
1.987 + if ( qcelpAudio->iMode == E3GPMP4AudioDescriptionBox)
1.988 + {
1.989 + err = MP4ComposeWriteAudioDecoderSpecificInfo(iHandler, const_cast<mp4_u8*>(qcelpAudio->iDecoderSpecificInfo.Ptr()), qcelpAudio->iDecoderSpecificInfo.Length ());
1.990 + }
1.991 + if ( err == MP4_OK)
1.992 + {
1.993 + //modeSet is needed only for AMR audio. Set it to 0 for Qcelp audio.
1.994 + err = MP4ComposeAddAudioDescription(iHandler, qcelpAudio->iTimescale, qcelpAudio->iFramesPerSample, 0);
1.995 + }
1.996 + }
1.997 +
1.998 + return SymbianOSError(err);
1.999 + }
1.1000 +
1.1001 +// Set compose flag
1.1002 +TInt C3GPCompose::SetComposeFlag(T3GPFileFormatType aFileFormat, TUint aFlag)
1.1003 + {
1.1004 + mp4_u32 fileFormat = 0;
1.1005 + switch (aFileFormat)
1.1006 + {
1.1007 + case (E3GPMP4):
1.1008 + fileFormat = MP4_FLAG_GENERATE_MP4;
1.1009 + break;
1.1010 + case (E3GP3G2):
1.1011 + fileFormat = MP4_FLAG_GENERATE_3G2;
1.1012 + break;
1.1013 + case (E3GP3GP):
1.1014 + fileFormat = MP4_FLAG_NONE;
1.1015 + break;
1.1016 + default:
1.1017 + Panic(KErrArgument);
1.1018 + }
1.1019 +
1.1020 + MP4Err err = MP4ComposeSetFlags(iHandler, aFlag | fileFormat);
1.1021 + return SymbianOSError(err);
1.1022 + }
1.1023 +
1.1024 +
1.1025 +void C3GPCompose::Panic(TInt aPanic)
1.1026 +// Panic client
1.1027 + {
1.1028 + User::Panic(K3GPComposePanicName, aPanic);
1.1029 + }