sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: sl@0: /** sl@0: Creates an instance of a 3GP Parser for reading 3GP/3G2/MP4 data using default buffer size. sl@0: sl@0: The default value for read buffer size is 8k. sl@0: sl@0: @return A pointer to the newly created 3gp parse object. sl@0: sl@0: @leave KErrNoMemory Out of memory. sl@0: */ sl@0: EXPORT_C C3GPParse* C3GPParse::NewL() sl@0: { sl@0: C3GPParse* self = new (ELeave) C3GPParse(); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: Creates an instance of a 3GP Parser for reading 3GP/3G2/MP4 data, and sets the sl@0: internal file read buffer size. sl@0: sl@0: @param aReadBufferSize Size of file read buffer. sl@0: sl@0: @return A pointer to the newly created 3gp parse object. sl@0: sl@0: @leave KErrNoMemory Out of memory. sl@0: @leave KErrGeneral General error. sl@0: sl@0: @panic C3GPParse KErrArgument if size of file read buffer is not greater than 0. sl@0: */ sl@0: EXPORT_C C3GPParse* C3GPParse::NewL(TInt aReadBufferSize) sl@0: { sl@0: __ASSERT_ALWAYS((aReadBufferSize > 0), Panic(KErrArgument)); sl@0: C3GPParse* self = new (ELeave) C3GPParse(aReadBufferSize); sl@0: return self; sl@0: } sl@0: sl@0: // First phase constructor sl@0: C3GPParse::C3GPParse(TInt aReadBufferSize) : sl@0: iReadBufferSize(aReadBufferSize), sl@0: iDuplicateFileHandleCreated(EFalse), sl@0: iVideoType(E3GPNoVideo), sl@0: iAudioType(E3GPNoAudio) sl@0: { sl@0: } sl@0: sl@0: /** sl@0: This function initialises the 3GP Parser for reading 3GP/3G2/MP4 data from a buffer and expects data sl@0: to be inserted through subsequent calls to C3GPParse::InsertData. sl@0: sl@0: @see C3GPParse::InsertData sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNoMemory if an attempt to allocate memory has failed; sl@0: KErrInUse if the parser is currently engaged; C3GPParse::Complete must be called to sl@0: finish the parsing activities before the parser can be re-initialised again. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::Open() sl@0: { sl@0: if (iHandler) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: sl@0: return SymbianOSError(MP4ParseOpen(&iHandler, NULL)); sl@0: } sl@0: sl@0: /** sl@0: This function initialises the 3GP Parser for reading 3GP/3G2/MP4 data from a file. sl@0: sl@0: @param aFilename A full path name of the file containing the data. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNoMemory if an attempt to allocate memory has failed; sl@0: KErrAccessDenied if opening file has failed; sl@0: KErrUnderflow if the file name length is not greater than 0; sl@0: KErrInUse if the parser is currently engaged; C3GPParse::Complete must be called to sl@0: finish the parsing activities before the parser can be re-initialised again. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::Open(const TDesC& aFilename) sl@0: { sl@0: if (iHandler) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: if (aFilename.Length() <= 0) sl@0: { sl@0: return KErrUnderflow; sl@0: } sl@0: sl@0: // Create a zero terminated version of the file name sl@0: RBuf fileName; sl@0: TInt err = fileName.Create(aFilename.Length() + 1); sl@0: if (err == KErrNone) sl@0: { sl@0: fileName.Copy(aFilename); sl@0: mp4_u16* mp4FileName = const_cast(fileName.PtrZ()); sl@0: MP4Err mp4Err = MP4ParseOpen(&iHandler, reinterpret_cast(mp4FileName)); sl@0: sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: // Set composing related values to 0. sl@0: mp4Err = MP4SetCustomFileBufferSizes(iHandler, 0, 0, iReadBufferSize); sl@0: if (mp4Err != MP4_OK) sl@0: { sl@0: // Ignore the error sl@0: Complete(); sl@0: } sl@0: } sl@0: err = SymbianOSError(mp4Err); sl@0: } sl@0: fileName.Close(); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: This function initialises the 3GP Parser for reading 3GP/3G2/MP4 data from a file. sl@0: sl@0: @param aFile File handle of the file containing the data. It is expected to be a valid file handle, sl@0: opened and will be closed outside of the library. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrNoMemory if an attempt to allocate memory has failed; sl@0: KErrInUse if the parser is currently engaged; C3GPParse::Complete must be called to sl@0: finish the parsing activities before the parser can be re-initialised again. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::Open(const RFile& aFile) sl@0: { sl@0: TInt err = KErrNone; sl@0: if (!iDuplicateFileHandleCreated) sl@0: { sl@0: iDuplicateFileHandleCreated = ETrue; sl@0: iFile.Close(); sl@0: err = iFile.Duplicate(aFile); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: } sl@0: sl@0: return Open(iFile); sl@0: } sl@0: /** sl@0: This function initialises the 3GP Parser for reading 3GP/3G2/MP4 data from a file. sl@0: sl@0: @param aFile File handle of the file containing the data. It is expected to be a valid file handle, sl@0: opened and will be closed outside of the library. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrNoMemory if an attempt to allocate memory has failed; sl@0: KErrInUse if the parser is currently engaged; C3GPParse::Complete must be called to sl@0: finish the parsing activities before the parser can be re-initialised again. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::Open(const RFile64& aFile) sl@0: { sl@0: if (iHandler) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: sl@0: const RFile64* file = &aFile; sl@0: MP4Err mp4Err = MP4ParseOpenFileHandle64(&iHandler, (const_cast(file))); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: // Set composing related values to 0. sl@0: mp4Err = MP4SetCustomFileBufferSizes(iHandler, 0, 0, iReadBufferSize); sl@0: if (mp4Err != MP4_OK) sl@0: { sl@0: // Ignore the error sl@0: Complete(); sl@0: } sl@0: } sl@0: sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function initialises the 3GP Parser for reading 3GP/3G2/MP4 data from a CAF object. sl@0: sl@0: @param aData A CData object pointing to a CAF object. It is expected to be opened and will be sl@0: closed outside of the library. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrNoMemory if an attempt to allocate memory has failed; sl@0: KErrInUse if the parser is currently engaged; C3GPParse::Complete must be called to sl@0: finish the parsing activities before the parser can be re-initialised again. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::Open(const ContentAccess::CData& aData) sl@0: { sl@0: if (iHandler) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: sl@0: MP4Err mp4Err = MP4ParseOpenCAF(&iHandler, const_cast(&aData)); sl@0: sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: // Set composing related values to 0. sl@0: mp4Err = MP4SetCustomFileBufferSizes(iHandler, 0, 0, iReadBufferSize); sl@0: if (mp4Err != MP4_OK) sl@0: { sl@0: // Ignore the error sl@0: Complete(); sl@0: } sl@0: } sl@0: sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: Destructor. Deletes all objects. sl@0: */ sl@0: EXPORT_C C3GPParse::~C3GPParse() sl@0: { sl@0: Complete(); // Ignore the error sl@0: } sl@0: sl@0: /** sl@0: This function completes the parsing operation. sl@0: sl@0: If C3GPParse::Complete is called before the parse is initialised, it will be ignored and KErrNone is sl@0: returned. sl@0: sl@0: The parser can be reused again after this call, following another call to C3GPParse::Open to sl@0: re-initialise the parser. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: */ sl@0: EXPORT_C TInt C3GPParse::Complete() sl@0: { sl@0: MP4Err mp4Err = MP4_OK; sl@0: if (iHandler) sl@0: { sl@0: mp4Err = MP4ParseClose(iHandler); sl@0: } sl@0: sl@0: if (iAsyncReadBuffer) sl@0: { sl@0: CancelReadFrame(); sl@0: } sl@0: sl@0: // Always reset the class member data even MP4ParseClose returns error sl@0: Reset(); sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: // Helper function to reset class member data. sl@0: void C3GPParse::Reset() sl@0: { sl@0: iVideoType = E3GPNoVideo; sl@0: iAudioType = E3GPNoAudio; sl@0: iAsyncReadBuffer = NULL; sl@0: iCallback = NULL; // Parse doesn't own the callback. Set it to NULL. sl@0: iAudioAvgBitRate = 0; sl@0: iStreamAvgBitRate = 0; sl@0: iVideoPropertiesSaved = EFalse; sl@0: iAudioPropertiesSaved = EFalse; sl@0: iStreamPropertiesSaved = EFalse; sl@0: iVideoError = KErrNone; sl@0: iAudioError = KErrNone; sl@0: iStreamError = KErrNone; sl@0: iHandler = NULL; sl@0: iDuplicateFileHandleCreated = EFalse; sl@0: iFile.Close(); sl@0: } sl@0: sl@0: /** sl@0: This function inserts MP4/3GP/3G2 data into the parser. sl@0: sl@0: It is only necessary to call this function if no parameter has been supplied when sl@0: C3GPParse::Open is called. Several functions can return KErr3gpLibMoreDataRequired if the library sl@0: does not have enough data to return the information that the caller requests. In this case, more data sl@0: needs to be inserted to the library before calling those functions again. sl@0: sl@0: This function makes a copy of the data inserted into the library so the caller can use the input buffer sl@0: for other purposes. If the function returns KErrNoMemory, the buffer contents have not been copied into sl@0: the library and the caller needs to reduce the buffer content before calling again. sl@0: sl@0: If an empty string is supplied for the argument aBuffer, it indicates that there is be no more data sl@0: to feed through this function. Such a function call must be done to indicate that all 3GP/MP4/3G2 sl@0: data has been written to the library's internal memory. sl@0: sl@0: @param aBuffer The descriptor containing the data to be inserted. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNoMemory if parser cannot allocate enough memory for the data; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::InsertData(const TDesC8& aBuffer) sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: return SymbianOSError(MP4ParseWriteData(iHandler, const_cast(aBuffer.Ptr()), aBuffer.Length())); sl@0: } sl@0: sl@0: /** sl@0: This function returns the parameters describing the video stream. sl@0: sl@0: If no file or CAF object is supplied during parser initialisation, this should be called after sl@0: enough data has been inserted into the library buffers so that the 3GP headers containing the sl@0: information can be read. sl@0: sl@0: The aFrameRate parameter refers to the frame rate of the original video material. sl@0: sl@0: @param aType The type of video stream. Refer to T3GPVideoType for supported video type. sl@0: @param aLength Duration of video in milliseconds. sl@0: @param aFrameRate Average frame rate of video (in Hz). sl@0: @param aAvgBitRate Average bit rate of video. sl@0: @param aSize Width and height of video image measured in pixels. sl@0: @param aTimeScale Timescale of video track. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain video; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if more data is required before the requested information can be sl@0: retrieved; See C3GPParse::InsertData. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetVideoProperties(T3GPVideoType& aType, TUint& aLength, TReal& aFrameRate, sl@0: TUint& aAvgBitRate, TSize& aSize, TUint& aTimeScale) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: TInt err = DoGetVideoProperties(); sl@0: sl@0: if (err == KErrNone) sl@0: { sl@0: aLength = iVideoLength; sl@0: aType = iVideoType; sl@0: aFrameRate = iVideoFrameRate; sl@0: aSize.iWidth = iVideoSize.iWidth; sl@0: aSize.iHeight = iVideoSize.iHeight; sl@0: aTimeScale = iVideoTimeScale; sl@0: } sl@0: else sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: // Get average bit rate of the stream in bps sl@0: err = DoGetStreamProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: // Video average bit rate is calculated from GetStreamDescription’s aAvgBitRate substructs Audio’s aAvgBitRate sl@0: // GetAudioProperties has not been called sl@0: err = DoGetAudioProperties(); sl@0: if (err == KErrNone) sl@0: { sl@0: aAvgBitRate = iStreamAvgBitRate - iAudioAvgBitRate; sl@0: } sl@0: else sl@0: { sl@0: // if the audio stream is not usable, ignore the error since the stream sl@0: // in concern is video stream. The audio stream error can be dealt with by sl@0: // users when it asks for audio properties. sl@0: aAvgBitRate = iStreamAvgBitRate; sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: This function returns the parameters describing the audio stream. sl@0: sl@0: If no file or CAF object is supplied during parser initialisation, this should be called after sl@0: enough data has been inserted into the library so that the 3GP headers containing the information sl@0: can be read. sl@0: sl@0: @param aType The type of audio stream. Refer to T3GPFrameType for supported audio type values. sl@0: @param aLength Duration of audio in milliseconds. sl@0: @param aFramesPerSample Number of audio frames in each sample. sl@0: @param aAvgBitRate Average bit rate of audio. sl@0: @param aTimeScale Timescale of audio track. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if input does not contain audio; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if more data is required before the requested information can be sl@0: retrieved. See C3GPParse::InsertData. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetAudioProperties(T3GPAudioType& aType, TUint& aLength, TInt& aFramesPerSample, sl@0: TUint& aAvgBitRate, TUint& aTimeScale) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: TInt err = DoGetAudioProperties(); sl@0: sl@0: if (err == KErrNone) sl@0: { sl@0: aLength = iAudioLength; sl@0: aType = iAudioType; sl@0: aFramesPerSample = iAudioFramesPerSample; sl@0: aAvgBitRate = iAudioAvgBitRate; sl@0: aTimeScale = iAudioTimeScale; sl@0: iAudioPropertiesSaved = ETrue; sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: This function returns the parameters that describe the contents of the input file or buffer. sl@0: sl@0: If no file or CAF object is supplied during parser initialisation, this should be called after sl@0: enough data has been inserted into the library so that the headers containing the information can sl@0: be read. sl@0: sl@0: @param aSize Length of the stream in bytes. sl@0: @param aAvgBitRate Average bit rate of the stream in bps. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if more data is required before the requested information can be sl@0: retrieved. See C3GPParse::InsertData. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetContainerProperties(TUint& aSize, TUint& aAvgBitRate) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: TInt err = DoGetStreamProperties(); sl@0: if (err == KErrNone) sl@0: { sl@0: aSize = iStreamSize; sl@0: aAvgBitRate = iStreamAvgBitRate; sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: This function returns the number of bytes that the library instance has in its allocated buffers. sl@0: sl@0: The function is only valid when the parser is initialized without any parameters. Zero is sl@0: returned when in file mode, that is, the parser has been initialized with a valid filename, file handle sl@0: or a CAF object. sl@0: sl@0: @see C3GPParse::InsertData. sl@0: sl@0: @param aNum Number of allocated bytes in the library. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the parser has been initialised with a file name or file handle; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetNumBufferedBytes(TInt& aNum) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: mp4_u32 numBytes = 0; sl@0: MP4Err mp4Err = MP4ParseGetBufferedBytes(iHandler, &numBytes); sl@0: aNum = numBytes; sl@0: sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function returns the type of the next audio/video frame in the stream. sl@0: sl@0: This function has no effect on the parser’s current position. sl@0: sl@0: @param aType Type of the next frame. Refer to the definition of T3GPFrameType for all possible values. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotFound if frame does not exist (the previous frame was the last one); sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetFrameType(T3GPFrameType& aType) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: mp4_u32 frameType = 0; sl@0: MP4Err mp4Err = MP4ParseNextFrameType(iHandler, &frameType); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: if ( sl@0: frameType == MP4_TYPE_MPEG4_VIDEO || sl@0: frameType == MP4_TYPE_H263_PROFILE_0 || sl@0: frameType == MP4_TYPE_H263_PROFILE_3 || sl@0: frameType == MP4_TYPE_AVC_PROFILE_BASELINE || sl@0: frameType == MP4_TYPE_AVC_PROFILE_MAIN || sl@0: frameType == MP4_TYPE_AVC_PROFILE_EXTENDED || sl@0: frameType == MP4_TYPE_AVC_PROFILE_HIGH sl@0: ) sl@0: { sl@0: aType = E3GPVideo; sl@0: } sl@0: else if (frameType == MP4_TYPE_MPEG4_AUDIO || frameType == MP4_TYPE_AMR_NB || sl@0: frameType == MP4_TYPE_AMR_WB || frameType == MP4_TYPE_QCELP_13K) sl@0: { sl@0: aType = E3GPAudio; sl@0: } sl@0: else sl@0: { sl@0: // This should not happen sl@0: Panic(KErrCorrupt); sl@0: } sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function returns the size of the immediate next video frame based on the current sl@0: position of the parser. sl@0: sl@0: Calling this function does not change the current position of the parser. sl@0: sl@0: @param aSize Size of the next video frame in bytes. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain video; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetVideoFrameSize(TUint& aSize) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: // video type from 3GP file header has been saved sl@0: mp4_u32 frameSize = 0; sl@0: MP4Err mp4Err = MP4ParseNextFrameSize(iHandler, iVideoMp4Type, &frameSize); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aSize = frameSize; sl@0: } sl@0: sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function returns the total size of the audio frames in the immediate audio sample based on the sl@0: current position of the parser. sl@0: sl@0: This function has no effect on the parser’s current position. sl@0: sl@0: @param aSize Size of the next audio sample in bytes. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain audio; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetAudioFramesSize(TUint& aSize) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains audio stream sl@0: TInt err = DoGetAudioProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: // audio type from 3GP file header has been saved. Directely use iAudioMp4Type as input sl@0: mp4_u32 frameSize = 0; sl@0: sl@0: MP4Err mp4Err = MP4ParseNextFrameSize(iHandler, iAudioMp4Type, &frameSize); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aSize = frameSize; sl@0: } sl@0: sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function reads the next video frame from the 3GP file/stream and returns it to the caller. sl@0: The current position of video stream will be moved forward. sl@0: sl@0: The next frame depends on the position in the input 3GP file. C3GPParse::Seek can be used to change sl@0: the current position in the 3GP file. sl@0: sl@0: If the function returns KErr3gpLibMoreDataRequired, the caller needs to call C3GPParse::InsertData sl@0: to insert more data before calling the function again. sl@0: sl@0: Since there are separate cursors for storing current positions of video and audio streams, calling this sl@0: function does not affect the position of the next audio stream. sl@0: sl@0: @param aBuffer Video frame is returned here. sl@0: @param aKeyFrame Returns ETrue if the current frame is a key frame (intra), otherwise the value is EFalse. sl@0: @param aTimeStampInMs Video frame presentation time in milliseconds from the beginning of the video sequence. sl@0: @param aTimeStampInTimescale Video frame presentation time in timescale from the beginning of the video sequence. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the 3GP input data contains no video stream; sl@0: KErrNotFound if frame does not exist (the previous frame was the last one); sl@0: KErrOverflow if requested frame does not fit into the given buffer; Caller can use sl@0: C3GPParse::GetVideoFrameSize to retrieve the minimum buffer size needed sl@0: to fit this video frame; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::ReadVideoFrame(TDes8& aBuffer, TBool& aKeyFrame, TUint& aTimeStampInMs, sl@0: TUint& aTimeStampInTimescale) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: if (aBuffer.MaxLength() <= 0) sl@0: { sl@0: return KErrOverflow; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 frameSize = 0; sl@0: mp4_u32 timeStamp = 0; sl@0: mp4_bool keyFrame = EFalse; sl@0: mp4_u32 timestamp2 = 0; sl@0: sl@0: MP4Err mp4Err = MP4ParseReadVideoFrame(iHandler, const_cast(aBuffer.Ptr()), aBuffer.MaxLength(), sl@0: &frameSize, &timeStamp, &keyFrame, ×tamp2); sl@0: sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aBuffer.SetLength(frameSize); sl@0: aKeyFrame = keyFrame; sl@0: aTimeStampInMs = timeStamp; sl@0: aTimeStampInTimescale = timestamp2; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: Return size of video DecoderSpecificInfo. sl@0: For files with MPEG-4 video this data is read from the esds atom. For files with AVC video sl@0: this data is read from the avcC atom. sl@0: sl@0: Note: Only MPEG-4 video and H.264/AVC video streams contain DecoderSpecificInfo. sl@0: sl@0: @param aSize Size of video DecoderSpecificInfo. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the 3GP input data contains no MPEG-4 / AVC video stream; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetVideoDecoderSpecificInfoSize(TInt& aSize) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream and the video type is either sl@0: // MPEG-4 or H.264/AVC sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err == KErrNone) sl@0: { sl@0: if (!( sl@0: iVideoType == E3GPMpeg4Video || sl@0: iVideoType == E3GPAvcProfileBaseline || sl@0: iVideoType == E3GPAvcProfileMain || sl@0: iVideoType == E3GPAvcProfileExtended || sl@0: iVideoType == E3GPAvcProfileHigh sl@0: )) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 decspecinfosize = 0; sl@0: MP4Err mp4Err = MP4ParseReadVideoDecoderSpecificInfo(iHandler, NULL, 0, &decspecinfosize); sl@0: sl@0: if ( mp4Err == MP4_OK || mp4Err == MP4_BUFFER_TOO_SMALL) sl@0: { sl@0: aSize = decspecinfosize; sl@0: mp4Err = MP4_OK; sl@0: } sl@0: sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function reads DecoderSpecificInfo data from 3GP metadata and returns it to the caller. sl@0: For files with MPEG-4 video this data is read from the esds atom. For files with AVC video sl@0: this data is read from the avcC atom. sl@0: sl@0: Note: Only MPEG-4 video and H.264/AVC video streams contain DecoderSpecificInfo. sl@0: sl@0: @see C3GPParse::GetVideoDecoderSpecificInfoSize sl@0: sl@0: @param aInfo The descriptor to store the video decoder information. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the 3GP input data contains no MPEG-4 / AVC video stream; sl@0: KErrOverflow if requested frame does not fit into the given buffer; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetVideoDecoderSpecificInfo(TDes8& aInfo) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: if (aInfo.MaxLength() <= 0) sl@0: { sl@0: return KErrOverflow; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream and the video type is either sl@0: // MPEG-4 or H.264/AVC sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err == KErrNone) sl@0: { sl@0: if (!( sl@0: iVideoType == E3GPMpeg4Video || sl@0: iVideoType == E3GPAvcProfileBaseline || sl@0: iVideoType == E3GPAvcProfileMain || sl@0: iVideoType == E3GPAvcProfileExtended || sl@0: iVideoType == E3GPAvcProfileHigh sl@0: )) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 decspecinfosize = 0; sl@0: MP4Err mp4Err = MP4ParseReadVideoDecoderSpecificInfo(iHandler, const_cast(aInfo.Ptr()), sl@0: aInfo.MaxLength(),&decspecinfosize); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aInfo.SetLength(decspecinfosize); sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function reads the audio frames that are stored in the current audio sample from the sl@0: 3GP file/stream and returns them to the caller. The current position of audio stream will be moved forward. sl@0: sl@0: Note: The next frame depends on the position in the input 3GP file. C3GPParse::Seek can sl@0: be used to change the current position in the 3GP file. sl@0: sl@0: If the function returns KErr3gpLibMoreDataRequired, the caller needs to call C3GPParse::InsertData sl@0: to insert more data before calling the function again. sl@0: sl@0: Note: aReturnedFrames may differ from the correct value when accessing the last audio sample. sl@0: sl@0: Note: Since there are separate cursors for storing current positions for video and audio streams, calling sl@0: this function does not change current position of the parser for video stream. sl@0: sl@0: @param aBuffer Audio frames are returned here. sl@0: @param aReturnedFrames Number of the returned frames or 0 if not known. sl@0: @param aTimeStampInMs Audio frame presentation time in milliseconds from the beginning of the sl@0: audio sequence. sl@0: @param aTimeStampInTimescale Audio frame presentation time in timescale from the beginning sl@0: of the audio sequence. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the 3GP input data contains no audio stream; sl@0: KErrOverflow if requested frame does not fit into the given buffer; Caller can use sl@0: C3GPParse::GetAudioFrameSize to retrieve the minimum size needed to sl@0: fit this audio frame; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotFound if no more frames available; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::ReadAudioFrames(TDes8& aBuffer, TInt& aReturnedFrames, TUint& aTimeStampInMs, sl@0: TUint& aTimeStampInTimescale) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: if (aBuffer.MaxLength() <= 0) sl@0: { sl@0: return KErrOverflow; sl@0: } sl@0: sl@0: // Check if 3GP input data contains audio stream sl@0: TInt err = DoGetAudioProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 numOfFrames = 0; sl@0: mp4_u32 timeStampInMs = 0; sl@0: mp4_u32 timeStampInTimescale = 0; sl@0: mp4_u32 audioSize = 0; sl@0: MP4Err mp4Err = MP4ParseReadAudioFrames(iHandler, const_cast(aBuffer.Ptr()), aBuffer.MaxLength(), sl@0: &audioSize, &timeStampInMs, &numOfFrames, &timeStampInTimescale); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aBuffer.SetLength(audioSize); sl@0: aReturnedFrames = numOfFrames; sl@0: aTimeStampInMs = timeStampInMs; sl@0: aTimeStampInTimescale = timeStampInTimescale; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: Returns size of audio DecoderSpecificInfo data from 3GP metadata. sl@0: sl@0: @param aSize Size of DecoderSpecificInfo to be returned (in bytes). sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the stream does not contain audio stream stored in MPEG-4 audio sample boxes. sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetAudioDecoderSpecificInfoSize(TInt& aSize) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains audio stream sl@0: TInt err = DoGetAudioProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 decspecinfosize = 0; sl@0: MP4Err mp4Err = MP4ParseReadAudioDecoderSpecificInfo(iHandler, NULL, 0, &decspecinfosize); sl@0: if ( mp4Err == MP4_OK || mp4Err == MP4_BUFFER_TOO_SMALL) sl@0: { sl@0: aSize = decspecinfosize; sl@0: mp4Err = MP4_OK; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function reads DecoderSpecificInfo data from 3GP metadata and returns it to the caller. sl@0: sl@0: Note: AMR DecoderSpecificInfo data structure is returned in runtime in an architecture-specific sl@0: Endian format, that is, no Endian conversion is necessary for the data. sl@0: sl@0: @see C3GPParse::GetAudioDecoderSpecificInfoSize sl@0: sl@0: @param aBuffer DecoderSpecificInfo is returned here. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the stream does not contain audio stream stored in MPEG-4 audio sample boxes. sl@0: KErrOverflow if requested frame does not fit into the given buffer; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetAudioDecoderSpecificInfo(TDes8& aBuffer) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: if (aBuffer.MaxLength() <= 0) sl@0: { sl@0: return KErrOverflow; sl@0: } sl@0: sl@0: // Check if 3GP input data contains audio stream sl@0: TInt err = DoGetAudioProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 decspecinfosize = 0; sl@0: MP4Err mp4Err = MP4ParseReadAudioDecoderSpecificInfo(iHandler, const_cast(aBuffer.Ptr()), sl@0: aBuffer.MaxLength(),&decspecinfosize); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aBuffer.SetLength(decspecinfosize); sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: Returns the timestamp of the next video frame. The current position of the video stream will be moved forward. sl@0: sl@0: The function can be used to find out which frames have been coded to optimize the input frame selection sl@0: if video frame rate needs to be modified. sl@0: sl@0: When this function call returns KErrEof, there are no more video frames left in the 3GP file and sl@0: the timestamp returned with the previous call was the timestamp of the last video frame. sl@0: sl@0: Note: C3GPParse::Seek can be used to change the current position in the 3GP file. sl@0: sl@0: @param aTimeStampInMs Timestamp in milliseconds is returned here. sl@0: @param aTimeStampInTimescale Timestamp in timescale is returned here. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain video; sl@0: KErrEof if no more video frames left; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetVideoTimestamp(TUint& aTimeStampInMs, TUint& aTimeStampInTimescale) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 timeStampInMs = 0; sl@0: mp4_u32 timeStampInTimescale = 0; sl@0: MP4Err mp4Err = MP4ParseGetNextVideoTimestamp(iHandler, &timeStampInMs, &timeStampInTimescale); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aTimeStampInMs = timeStampInMs; sl@0: aTimeStampInTimescale = timeStampInTimescale; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function determines whether the input 3GP stream is streamable, that is, whether the media data is arranged sl@0: in such a manner that playback can be started without downloading the entire stream. sl@0: sl@0: @param aStreamable Returns ETrue if the file is streamable. Otherwise, returns EFalse. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetStreamable(TBool& aStreamable) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: MP4Err mp4Err = MP4ParseIsStreamable(iHandler); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aStreamable = ETrue; sl@0: } sl@0: else sl@0: { sl@0: aStreamable = EFalse; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function seeks the position specified by the aPosition parameter in the input 3GP file/stream. sl@0: sl@0: The position is considered to start from the beginning of the presentation time line in the 3GP file. sl@0: Thus audio and video positions cannot be given separately. sl@0: sl@0: The function will set the current audio and video positions in the following manner: sl@0: sl@0: If there is only audio data in the file, the current position is set to the audio frame at or just sl@0: before the given position. sl@0: sl@0: If there is only video in the file and the key frame is EFalse, the current position is set to the sl@0: video frame at or just before the given position. If the key frame is set to ETrue, the current sl@0: position is set to the first key frame at or before the current position. sl@0: sl@0: If there are both audio and video in the file, video is first positioned as explained above and then sl@0: audio is sought to the closest position in relation to video. sl@0: sl@0: If the position to seek is greater than the duration of video or audio, the video or audio position is sl@0: set to the position of the last video or audio frame as explained above. sl@0: sl@0: If the function returns KErr3gpLibMoreDataRequired, the caller needs to call C3GPParse::InsertData sl@0: to insert more data before calling the function again. sl@0: sl@0: @param aPosition Position to seek in milliseconds in the 3GP presentation time line. sl@0: @param aKeyFrame If set to ETrue, the first video key frame before a given point is sought. If sl@0: set to EFalse, the first video frame before a given point is sought. sl@0: @param aAudioPosition Position of audio after seeking (in milliseconds). sl@0: @param aVideoPosition Position of video after seeking (in milliseconds). sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotFound if cannot seek the requested position; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: */ sl@0: EXPORT_C TInt C3GPParse::Seek(TUint aPosition, TBool aKeyFrame, TUint& aAudioPosition, TUint& aVideoPosition) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: mp4_u32 audioPosition = 0; sl@0: mp4_u32 videoPosition = 0; sl@0: mp4_bool keyFrame = aKeyFrame; sl@0: MP4Err mp4Err = MP4ParseSeek(iHandler, aPosition, &audioPosition, &videoPosition, keyFrame); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aAudioPosition = audioPosition; sl@0: aVideoPosition = videoPosition; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function determines whether the next frame of the type aType is available. sl@0: sl@0: This function has no effect on the parser’s current position. sl@0: sl@0: @param aType The type of frame to check for. Refer to T3GPFrameType for supported types. sl@0: @param aAvailable Return ETrue if the type of frame specified by aType is available. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotFound if frame of the requested type is not available; sl@0: KErrCorrupt if 3GP stream is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetFrameAvailability(T3GPFrameType aType, TBool& aAvailable) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: aAvailable = EFalse; sl@0: TInt err = KErrNone; sl@0: MP4Err mp4Err = MP4_OK; sl@0: if (aType == E3GPAudio) sl@0: { sl@0: // Check if 3GP input data contains audio stream sl@0: err = DoGetAudioProperties(); sl@0: if (err == KErrNotSupported) sl@0: { sl@0: // If there is no requested type, err will be KErrNotSupported. But in here, KErrNotFound is sl@0: // more proper. sl@0: err = KErrNotFound; sl@0: } sl@0: else if (err == KErrNone) sl@0: { sl@0: mp4Err = MP4ParseIsFrameAvailable(iHandler, iAudioMp4Type); sl@0: err = SymbianOSError(mp4Err); sl@0: } sl@0: } sl@0: else if (aType == E3GPVideo) sl@0: { sl@0: // Check if 3GP input data contains video stream sl@0: err = DoGetVideoProperties(); sl@0: if (err == KErrNotSupported) sl@0: { sl@0: // If there is no requested type, err will be KErrNotSupported. But in here, KErrNotFound is sl@0: // more proper. sl@0: err = KErrNotFound; sl@0: } sl@0: else if (err == KErrNone) sl@0: { sl@0: mp4Err = MP4ParseIsFrameAvailable(iHandler, iVideoMp4Type); sl@0: err = SymbianOSError(mp4Err); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: Panic(KErrArgument); // This should not happen. sl@0: } sl@0: sl@0: if (err == KErrNone) sl@0: { sl@0: aAvailable = ETrue; sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Returns the number of video frames. sl@0: sl@0: @param aNum Number of video frames. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain video; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetNumberOfVideoFrames(TUint& aNum) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 numVideoFrame = 0; sl@0: MP4Err mp4Err = MP4ParseGetNumberOfVideoFrames(iHandler, &numVideoFrame); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aNum = numVideoFrame; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function gives the video sample entry index of the next video frame to be read. sl@0: sl@0: The smallest index value is 1. sl@0: sl@0: @param aIndex Returns the Visual Sample Entry index of the next video frame to be read. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain video; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetVideoSampleEntryIndex(TUint& aIndex) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 index = 0; sl@0: MP4Err mp4Err = MP4ParseGetVideoSampleEntryIndex(iHandler, &index); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aIndex = index; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: Returns video frame size. sl@0: sl@0: @param aIndex Index of video frame. sl@0: @param aSize Return the size of the video frame. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain video; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetVideoFrameSize(TUint aIndex, TUint& aSize) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 videoFrameSize = 0; sl@0: MP4Err mp4Err = MP4ParseGetVideoFrameSize(iHandler, aIndex, &videoFrameSize); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aSize = videoFrameSize; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: Returns video frame start time. sl@0: sl@0: @param aIndex Index of video frame. sl@0: @param aTimeStampInMs Result in milliseconds. sl@0: @param aTimeStampInTimescale Result is returned here. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain video; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetVideoFrameStartTime(TUint aIndex, TUint& aTimeStampInMs, TUint& aTimeStampInTimescale) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 timeStampInMs = 0; sl@0: mp4_u32 timeStampInTimescale = 0; sl@0: MP4Err mp4Err = MP4ParseGetVideoFrameStartTime(iHandler, aIndex, &timeStampInTimescale, &timeStampInMs); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aTimeStampInMs = timeStampInMs; sl@0: aTimeStampInTimescale = timeStampInTimescale; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: Checks if a video frame of with index aIndex exists. sl@0: sl@0: @param aIndex Index of video frame. sl@0: @param aKeyFrame Return ETrue if the video frame is a key frame. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain video; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetVideoFrameKeyType(TUint aIndex, TBool& aKeyFrame) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_bool keyFrame = EFalse; sl@0: MP4Err mp4Err = MP4ParseGetVideoFrameType(iHandler, aIndex, &keyFrame); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aKeyFrame = keyFrame; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function gives the audio sample entry index of the next audio frame to be read. sl@0: sl@0: The smallest index value is 1. sl@0: sl@0: @param aIndex Returns the Audio Sample Entry index of the next video frame to be read. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain audio; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetAudioSampleEntryIndex(TUint& aIndex) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains audio stream sl@0: TInt err = DoGetAudioProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u32 audioSampleEntryIndex = 0; sl@0: MP4Err mp4Err = MP4ParseGetAudioSampleEntryIndex(iHandler, &audioSampleEntryIndex); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aIndex = audioSampleEntryIndex; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function provides the storage mode of 13K QCELP in 3G2 file. sl@0: sl@0: In 3G2 files, QCELP can be registered to be stored in two ways: sl@0: using the QCELP Sample Entry ('sqcp') Box or sl@0: using the MPEG4 Audio Sample Description ('esds') Box. sl@0: sl@0: @param aMode Returns the QCELP storage mode. See T3GPQcelpStorageMode. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the 3GP input data does not contain any QCELP audio stream; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetQcelpStorageMode(T3GPQcelpStorageMode& aMode) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains any QCELP audio stream sl@0: TInt err = DoGetAudioProperties(); sl@0: if (err == KErrNone) sl@0: { sl@0: if (iAudioType != E3GPQcelp13K) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u8 audioQcelpStorageMode = 0; sl@0: MP4Err mp4Err = MP4ParseGetQCELPStorageMode(iHandler, &audioQcelpStorageMode); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: if (audioQcelpStorageMode == 1) sl@0: { sl@0: aMode = E3GPMP4AudioDescriptionBox; sl@0: } sl@0: else sl@0: { sl@0: aMode = E3GPQcelpSampleEntryBox; sl@0: } sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function provides the video level of the H263 video stream contained in the 3GP data. sl@0: sl@0: @param aLevel Returns the H263 video level. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the 3GP input data does not contain any H263 video stream; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetH263VideoLevel(TInt& aLevel) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains any H263 video stream sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err == KErrNone) sl@0: { sl@0: if (!(iVideoType == E3GPH263Profile0 || iVideoType == E3GPH263Profile3)) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: TVideoClipProperties videoClipProperties; sl@0: MP4Err mp4Err = MP4ParseGetVideoClipProperties(iHandler, videoClipProperties); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: aLevel = videoClipProperties.iH263Level; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: Returns the needed size for memory buffer to store an atom of given type from user data atom (UDTA). sl@0: sl@0: @param aType Type of atom to be read from UDTA. Hex value of 4 chars representing atom type sl@0: defined in standard. For example, 0x7469746c is 'titl', title for the media atom. sl@0: @param aLocation Specifies the location of user information to be retrieved. Refer to sl@0: T3GPUdtaLocation for supported values. sl@0: @param aAtomIndex Specifies the index of atom if UDTA contains multiple sub-atoms of the same sl@0: aUdtaAtomType to retrieve when supplied as input parameter. Returns the sl@0: highest index of the matching sub-atom found in the specified location as sl@0: output parameter. sl@0: @param aSize This contains the needed size for memory buffer. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotFound if UDTA or wanted sub-atom is not available in asked location; sl@0: KErrAccessDenied if cannot seek to UDTA atom location; sl@0: KErrArgument if asked aLocation is invalid; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: sl@0: @panic C3GPParse KErrArgument if the location of user information is not in the range of T3GPUdtaLocation sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetUserDataAtomSize(TUint32 aType, T3GPUdtaLocation aLocation, sl@0: TUint& aAtomIndex, TInt& aSize) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: mp4_u32 userDataAtomSize = 0; sl@0: mp4_u32 atomIndex = aAtomIndex; sl@0: mp4_u32 type = aType; sl@0: mp4_u8 location = UdtaLocation(aLocation); sl@0: MP4Err mp4Err = MP4ParseGetUserDataAtom(iHandler, location, type, sl@0: NULL, userDataAtomSize, atomIndex); sl@0: if ( mp4Err == MP4_OK || mp4Err == MP4_OUTPUT_BUFFER_TOO_SMALL) sl@0: { sl@0: aSize = userDataAtomSize; sl@0: aAtomIndex = atomIndex; sl@0: mp4Err = MP4_OK; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: Retrieves an atom of given type from user data atom (UDTA) to the given buffer. sl@0: sl@0: The buffer returned stores an atom of structure that conforms to the definition of sl@0: a "full box" as specified in ISO/IEC 14496-12:2003: "Information technology – Coding sl@0: of audio-visual objects – Part 12: ISO base media file format." sl@0: sl@0: For more information on user data atoms, see Section 8 – Asset Information of "3GPP sl@0: TS 26.244 version 6.1.0 – 3GP file format (Rel 6)." sl@0: sl@0: @param aType Type of atom to be read from UDTA. Hex value of 4 chars representing atom type sl@0: defined in standard. For example, 0x7469746c is 'titl', title for the media atom. sl@0: @param aLocation Specifies the location of user information to be retrieved. Refer to sl@0: T3GPUdtaLocation for supported values. sl@0: @param aBuffer The descriptor to store the requested user data atom. sl@0: @param aAtomIndex Specifies the index of atom if UDTA contains multiple sub-atoms of the same sl@0: aUdtaAtomType to retrieve when supplied as input parameter. Returns the sl@0: highest index of the matching sub-atom found in the specified location as sl@0: output parameter. Only matching sub-atoms are counted when calculating the highest sl@0: index. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotFound if UDTA or wanted sub-atom is not available in asked location; sl@0: KErrAccessDenied if cannot seek to UDTA atom location; sl@0: KErrArgument if asked aUdtaLocation is invalid; sl@0: KErrOverflow if the buffer to write atom to is too small. Use C3GPParse::GetUserDataAtomSize sl@0: to retrieve the proper size. sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: sl@0: @panic C3GPParse KErrArgument if the location of user information is not in the range of T3GPUdtaLocation sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetUserDataAtom(TUint32 aType, T3GPUdtaLocation aLocation, TDes8& aBuffer, TUint& aAtomIndex) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: if (aBuffer.MaxLength() <= 0) sl@0: { sl@0: return KErrOverflow; sl@0: } sl@0: sl@0: mp4_u32 userDataAtomSize = aBuffer.MaxLength(); sl@0: mp4_u32 atomIndex = aAtomIndex; sl@0: mp4_u32 type = aType; sl@0: mp4_u8 location = UdtaLocation(aLocation); sl@0: MP4Err mp4Err = MP4ParseGetUserDataAtom(iHandler, location, type, sl@0: const_cast(aBuffer.Ptr()), userDataAtomSize, atomIndex); sl@0: if ( mp4Err == MP4_OK ) sl@0: { sl@0: aType = type; sl@0: aBuffer.SetLength(userDataAtomSize); sl@0: aAtomIndex = atomIndex; sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function gets the next frame's dependency information from SDTP box. sl@0: sl@0: @param aDependencies Returns the next frame's dependency information. See T3GPFrameDependencies. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain video stream; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open; sl@0: KErr3gpLibMoreDataRequired if if 3GP library needs more data before the requested sl@0: information can be returned. sl@0: */ sl@0: EXPORT_C TInt C3GPParse::GetVideoFrameDependencies(T3GPFrameDependencies& aDependencies) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: mp4_u8 dependsOn; sl@0: mp4_u8 isDependedOn; sl@0: mp4_u8 hasRedundancy; sl@0: MP4Err mp4Err = MP4ParseNextVideoFrameDependencies(iHandler, &dependsOn, &isDependedOn, &hasRedundancy); sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: switch (dependsOn) sl@0: { sl@0: case 1: sl@0: aDependencies.iDependsOn = E3GPDependencyExists; sl@0: break; sl@0: case 2: sl@0: aDependencies.iDependsOn = E3GPDependencyNone; sl@0: break; sl@0: case 0: sl@0: aDependencies.iDependsOn = E3GPDependencyUnknown; sl@0: break; sl@0: default: sl@0: Panic(KErrCorrupt); sl@0: } sl@0: sl@0: switch (isDependedOn) sl@0: { sl@0: case 1: sl@0: aDependencies.iIsDependedOn = E3GPDependencyExists; sl@0: break; sl@0: case 2: sl@0: aDependencies.iIsDependedOn = E3GPDependencyNone; sl@0: break; sl@0: case 0: sl@0: aDependencies.iIsDependedOn = E3GPDependencyUnknown; sl@0: break; sl@0: default: sl@0: Panic(KErrCorrupt); sl@0: } sl@0: sl@0: switch (hasRedundancy) sl@0: { sl@0: case 1: sl@0: aDependencies.iHasRedundancy = E3GPRedundancyExists; sl@0: break; sl@0: case 2: sl@0: aDependencies.iHasRedundancy = E3GPRedundancyNone; sl@0: break; sl@0: case 0: sl@0: aDependencies.iHasRedundancy = E3GPRedundancyUnknown; sl@0: break; sl@0: default: sl@0: Panic(KErrCorrupt); sl@0: } sl@0: } sl@0: return SymbianOSError(mp4Err); sl@0: } sl@0: sl@0: /** sl@0: This function gets frame properties, from aStartIndex for a count of aNumberOfFrames frames. sl@0: sl@0: Properties obtained are start time, frame type, and frame size, stored in the T3GPFrameInfoParameters sl@0: struct. sl@0: sl@0: @param aStartIndex Index to start getting info for the array. sl@0: @param aNumberOfFrames Number of frames to retrieve frame info. sl@0: @param aArray An array of T3GPFrameInfoParameters struct to store video frame properties. sl@0: The input array will be flushed of all existing elements before use. sl@0: sl@0: @return KErrNone if successful. Otherwise, returns one of the system wide error codes. sl@0: KErrGeneral if an error has no specific categorisation; sl@0: KErrNotSupported if the input does not contain video stream; sl@0: KErrNoMemory if an attempt to allocate memory has failed; sl@0: KErrAccessDenied if opening file has failed; sl@0: KErrNotReady if the parser has not yet been initialised; See C3GPParse::Open. sl@0: */ sl@0: EXPORT_C TInt C3GPParse:: GetVideoFrameProperties(TUint aStartIndex, TUint aNumberOfFrames, sl@0: RArray& aArray) const sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // Check if 3GP input data contains video stream sl@0: TInt err = DoGetVideoProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: // Check if the input parameters are valid before retrieving video frame properties. sl@0: TUint totalNumOfVideoFrames; sl@0: err = GetNumberOfVideoFrames(totalNumOfVideoFrames); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: if (aStartIndex >= totalNumOfVideoFrames || aNumberOfFrames > totalNumOfVideoFrames) sl@0: { sl@0: return KErrGeneral; sl@0: } sl@0: sl@0: TFrameInfoParameters* infoArray = new TFrameInfoParameters[aNumberOfFrames]; sl@0: sl@0: if (!infoArray) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: mp4_u32 startIndex = aStartIndex; sl@0: mp4_u32 numberOfFrames = aNumberOfFrames; sl@0: MP4Err mp4Err = MP4GetVideoFrameProperties(iHandler, startIndex, numberOfFrames, infoArray); sl@0: sl@0: if ( mp4Err == MP4_OK ) sl@0: { sl@0: aArray.Reset(); sl@0: T3GPFrameInfoParameters infoParams; sl@0: sl@0: for (TInt i=0; i(aBuffer.Ptr()), &bufferSize); sl@0: if (mp4Err != MP4_OK) sl@0: { sl@0: aCallback.VideoFrameAvailable(SymbianOSError(mp4Err), EFalse, 0, 0); sl@0: } sl@0: else sl@0: { sl@0: // MP4ParseReadVideoFrameAsync success. Store aBuffer since its length has sl@0: // not been set. sl@0: iAsyncReadBuffer = &aBuffer; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function reads the audio frames that are stored in the current audio sample from the input sl@0: file and returns them to the caller asynchronously. The current position of audio stream sl@0: will be moved forward. sl@0: sl@0: This function is not supported when the parser is in buffer mode. sl@0: sl@0: C3GPParse::CancelReadFrame can be used to cancel an outstanding asynchronous frame read request. sl@0: sl@0: Note: Only one asynchronous parse audio or video frame(s) operation can be ongoing at any given time. sl@0: sl@0: Upon completion, successfully or otherwise, the callback function M3GPParseCallback::AudioFramesAvailable is called. sl@0: sl@0: @param aCallback Reference to class derived from M3GPAsyncObserver designed to receive notification of sl@0: asynchronous event completion. sl@0: @param aBuffer The descriptor to store the audio frames. sl@0: */ sl@0: EXPORT_C void C3GPParse::ReadAudioFrames(M3GPParseCallback& aCallback, TDes8& aBuffer) sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: aCallback.AudioFramesAvailable(KErrNotReady, 0, 0, 0); sl@0: return; sl@0: } sl@0: if (aBuffer.MaxLength() <= 0) sl@0: { sl@0: aCallback.AudioFramesAvailable(KErrOverflow, 0, 0, 0); sl@0: return; sl@0: } sl@0: if (iAsyncReadBuffer) sl@0: { sl@0: aCallback.AudioFramesAvailable(KErrInUse, 0, 0, 0); sl@0: return; sl@0: } sl@0: sl@0: // Check if 3GP input data contains audio stream sl@0: TInt err = DoGetAudioProperties(); sl@0: if (err != KErrNone) sl@0: { sl@0: aCallback.AudioFramesAvailable(err, 0, 0, 0); sl@0: return; sl@0: } sl@0: sl@0: iCallback = &aCallback; sl@0: mp4_u32 bufferSize = aBuffer.MaxLength(); sl@0: MP4Err mp4Err = MP4ParseReadAudioFramesAsync(iHandler, this, sl@0: const_cast(aBuffer.Ptr()), &bufferSize); sl@0: if (mp4Err != MP4_OK) sl@0: { sl@0: aCallback.AudioFramesAvailable(SymbianOSError(mp4Err), 0, 0, 0); sl@0: } sl@0: else sl@0: { sl@0: // MP4ParseReadAudioFramesAsync success. Store aBuffer since its length has sl@0: // not been set. sl@0: iAsyncReadBuffer = &aBuffer; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function cancels the outstanding asynchronous read audio/video frame request. sl@0: sl@0: No callback function will be called. sl@0: sl@0: Note: As only one asynchronous parse audio or video frame(s) operation can be ongoing at any given time, sl@0: this function can be used to cancel audio or video read request. sl@0: */ sl@0: EXPORT_C void C3GPParse::CancelReadFrame() sl@0: { sl@0: if (!iHandler) sl@0: { sl@0: return; sl@0: } sl@0: if (iAsyncReadBuffer) sl@0: { sl@0: MP4CancelReadFrame(iHandler); sl@0: iAsyncReadBuffer = NULL; sl@0: iCallback = NULL; sl@0: } sl@0: } sl@0: sl@0: // Receive asynchronous parse video frames operation completion notification. sl@0: void C3GPParse::M3GPMP4LibVideoFrameAvailable(MP4Err aError, mp4_u32 aFrameSize, mp4_u32 aTimeStamp, sl@0: mp4_bool aKeyFrame, mp4_u32 aTimestamp2) sl@0: { sl@0: // Check if there is an outstanding asynchronous request sl@0: if (iAsyncReadBuffer) sl@0: { sl@0: if (aError == MP4_OK) sl@0: { sl@0: // Set the buffer length for the asynchronous read video frame sl@0: iAsyncReadBuffer->SetLength(aFrameSize); sl@0: } sl@0: iAsyncReadBuffer = NULL; sl@0: // Parser can send out the callback to the client sl@0: TBool keyFrame = aKeyFrame; sl@0: TUint timeStampInMs = aTimeStamp; sl@0: TUint timeStampInTimescale = aTimestamp2; sl@0: iCallback->VideoFrameAvailable(SymbianOSError(aError), keyFrame, timeStampInMs, timeStampInTimescale); sl@0: } sl@0: sl@0: iCallback = NULL; sl@0: } sl@0: sl@0: // Receive asyncronous parse audio frames operation completion notification. sl@0: void C3GPParse::M3GPMP4LibAudioFramesAvailable(MP4Err aError, mp4_u32 aAudioSize, mp4_u32 aTimeStamp, sl@0: mp4_u32 aReturnedFrames, mp4_u32 aTimestamp2) sl@0: { sl@0: // Check if there is an outstanding asynchronous request sl@0: if (iAsyncReadBuffer) sl@0: { sl@0: if (aError == MP4_OK) sl@0: { sl@0: // Set the buffer length for the asynchronous read audio frame sl@0: iAsyncReadBuffer->SetLength(aAudioSize); sl@0: } sl@0: iAsyncReadBuffer = NULL; sl@0: // Parser can send out the callback to the client sl@0: TUint returnedFrames = aReturnedFrames; sl@0: TUint timeStampInMs = aTimeStamp; sl@0: TUint timeStampInTimescale = aTimestamp2; sl@0: iCallback->AudioFramesAvailable(SymbianOSError(aError), returnedFrames, timeStampInMs, timeStampInTimescale); sl@0: } sl@0: sl@0: iCallback = NULL; sl@0: } sl@0: sl@0: // Helper function to convert c style error code to Symbian OS standard error code sl@0: TInt C3GPParse::SymbianOSError(MP4Err aError) const sl@0: { sl@0: TInt error = KErrNone; sl@0: sl@0: switch (aError) sl@0: { sl@0: case (MP4_OK): sl@0: break; sl@0: case (MP4_ERROR): sl@0: error = KErrGeneral; sl@0: break; sl@0: case (MP4_OUT_OF_MEMORY): sl@0: error = KErrNoMemory; sl@0: break; sl@0: case (MP4_NOT_AVAILABLE): sl@0: error = KErr3gpLibMoreDataRequired; sl@0: break; sl@0: case (MP4_FILE_MODE): sl@0: case (MP4_NOT_STREAMABLE): sl@0: case (MP4_NO_VIDEO): sl@0: case (MP4_NO_AUDIO): sl@0: error = KErrNotSupported; sl@0: break; sl@0: case (MP4_BUFFER_TOO_SMALL): sl@0: case (MP4_OUTPUT_BUFFER_TOO_SMALL): sl@0: error = KErrOverflow; sl@0: break; sl@0: case (MP4_END_OF_VIDEO): sl@0: error = KErrEof; sl@0: break; sl@0: case (MP4_CANT_SEEK): sl@0: case (MP4_NO_FRAME): sl@0: case (MP4_NO_REQUESTED_FRAME): sl@0: case (MP4_UDTA_NOT_FOUND): sl@0: error = KErrNotFound; sl@0: break; sl@0: case (MP4_FILE_ERROR): sl@0: error = KErrAccessDenied; sl@0: break; sl@0: case (MP4_INVALID_INPUT_STREAM): sl@0: error = KErrCorrupt; sl@0: break; sl@0: case (MP4_INVALID_TYPE): sl@0: error = KErrArgument; sl@0: break; sl@0: default: sl@0: // Mapped all possible errors returned by the MP4_library. Anything else should NOT happen sl@0: Panic(KErrArgument); sl@0: } sl@0: return error; sl@0: } sl@0: sl@0: // Help function to get video properties sl@0: TInt C3GPParse::DoGetVideoProperties() const sl@0: { sl@0: if (!iVideoPropertiesSaved || iVideoError == KErr3gpLibMoreDataRequired) sl@0: { sl@0: MP4Err mp4Err = MP4_OK; sl@0: mp4_u32 length = 0; sl@0: mp4_u32 type = 0; sl@0: mp4_u32 width = 0; sl@0: mp4_u32 height = 0; sl@0: mp4_u32 timeScale = 0; sl@0: mp4_double frameRate = 0; sl@0: sl@0: mp4Err = MP4ParseRequestVideoDescription(iHandler, &length, &frameRate, &type, &width, &height, &timeScale); sl@0: iVideoPropertiesSaved = ETrue; sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: iVideoType = WrapperVideoType(type); sl@0: if (iVideoType == E3GPNoVideo) sl@0: { sl@0: iVideoError = KErrNotSupported; sl@0: return KErrNotSupported; sl@0: } sl@0: iVideoLength = length; sl@0: iVideoMp4Type = type; // Type of video stream sl@0: iVideoSize.iWidth = width; sl@0: iVideoSize.iHeight = height; sl@0: iVideoTimeScale = timeScale; sl@0: iVideoFrameRate = frameRate; sl@0: } sl@0: iVideoError = SymbianOSError(mp4Err); sl@0: } sl@0: return iVideoError; sl@0: } sl@0: sl@0: // Help function to get audio properties sl@0: TInt C3GPParse::DoGetAudioProperties() const sl@0: { sl@0: if (!iAudioPropertiesSaved || iAudioError == KErr3gpLibMoreDataRequired) sl@0: { sl@0: MP4Err mp4Err = MP4_OK; sl@0: mp4_u32 audioLength = 0; sl@0: mp4_u32 audioType = 0; sl@0: mp4_u32 averateBitRate = 0; sl@0: mp4_u32 timeScale = 0; sl@0: mp4_u8 framesPerSample = 0; sl@0: sl@0: mp4Err = MP4ParseRequestAudioDescription(iHandler, &audioLength, &audioType, sl@0: &framesPerSample, &timeScale, &averateBitRate); sl@0: iAudioPropertiesSaved = ETrue; sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: iAudioLength = audioLength; sl@0: iAudioMp4Type = audioType; // Type of audio stream sl@0: iAudioType = WrapperAudioType(audioType); sl@0: iAudioFramesPerSample = framesPerSample; sl@0: iAudioAvgBitRate = averateBitRate; sl@0: iAudioTimeScale = timeScale; sl@0: } sl@0: iAudioError = SymbianOSError(mp4Err); sl@0: } sl@0: return iAudioError; sl@0: } sl@0: sl@0: // Help function to get stream properties sl@0: TInt C3GPParse::DoGetStreamProperties() const sl@0: { sl@0: if (!iStreamPropertiesSaved || iStreamError == KErr3gpLibMoreDataRequired) sl@0: { sl@0: MP4Err mp4Err = MP4_OK; sl@0: mp4_u32 streamSize = 0; sl@0: mp4_u32 streamAvgBitRate; sl@0: mp4Err = MP4ParseRequestStreamDescription(iHandler,&streamSize, &streamAvgBitRate); sl@0: iStreamPropertiesSaved = ETrue; sl@0: if (mp4Err == MP4_OK) sl@0: { sl@0: iStreamSize = streamSize; sl@0: iStreamAvgBitRate = streamAvgBitRate; sl@0: } sl@0: iStreamError = SymbianOSError(mp4Err); sl@0: } sl@0: return iStreamError; sl@0: } sl@0: sl@0: // Helper function to map Mp4 enum type to T3GPVideoType for video sl@0: T3GPVideoType C3GPParse::WrapperVideoType(TUint aType) const sl@0: { sl@0: T3GPVideoType videoType = E3GPNoVideo; sl@0: switch (aType) sl@0: { sl@0: case (MP4_TYPE_MPEG4_VIDEO): sl@0: videoType = E3GPMpeg4Video; sl@0: break; sl@0: case (MP4_TYPE_H263_PROFILE_0): sl@0: videoType = E3GPH263Profile0; sl@0: break; sl@0: case (MP4_TYPE_H263_PROFILE_3): sl@0: videoType = E3GPH263Profile3; sl@0: break; sl@0: case (MP4_TYPE_AVC_PROFILE_BASELINE): sl@0: videoType = E3GPAvcProfileBaseline; sl@0: break; sl@0: case (MP4_TYPE_AVC_PROFILE_MAIN): sl@0: videoType = E3GPAvcProfileMain; sl@0: break; sl@0: case (MP4_TYPE_AVC_PROFILE_EXTENDED): sl@0: videoType = E3GPAvcProfileExtended; sl@0: break; sl@0: sl@0: case (MP4_TYPE_AVC_PROFILE_HIGH): sl@0: videoType = E3GPAvcProfileHigh; sl@0: break; sl@0: case MP4_TYPE_NONE: sl@0: break; sl@0: default: sl@0: Panic(KErrCorrupt); // This should not happen. sl@0: break; sl@0: } sl@0: return videoType; sl@0: } sl@0: sl@0: // Helper function to map Mp4 enum type to T3GPAudioType for audio sl@0: T3GPAudioType C3GPParse::WrapperAudioType(TUint aType) const sl@0: { sl@0: T3GPAudioType audioType = E3GPNoAudio; sl@0: switch (aType) sl@0: { sl@0: case (MP4_TYPE_MPEG4_AUDIO): sl@0: audioType = E3GPMpeg4Audio; sl@0: break; sl@0: case (MP4_TYPE_AMR_NB): sl@0: audioType = E3GPAmrNB; sl@0: break; sl@0: case (MP4_TYPE_AMR_WB): sl@0: audioType = E3GPAmrWB; sl@0: break; sl@0: case (MP4_TYPE_QCELP_13K): sl@0: audioType = E3GPQcelp13K; sl@0: break; sl@0: default: sl@0: Panic(KErrCorrupt); // This should not happen. sl@0: } sl@0: return audioType; sl@0: } sl@0: sl@0: // Helper function to map enum type of the location of the user data in the file sl@0: mp4_u8 C3GPParse::UdtaLocation(T3GPUdtaLocation aLocation) const sl@0: { sl@0: mp4_u8 location = MP4_UDTA_NONE; sl@0: sl@0: switch (aLocation ) sl@0: { sl@0: case (E3GPUdtaMoov): sl@0: location = MP4_UDTA_MOOV; sl@0: break; sl@0: case (E3GPUdtaVideoTrak): sl@0: location = MP4_UDTA_VIDEOTRAK; sl@0: break; sl@0: case (E3GPUdtaAudioTrak): sl@0: location = MP4_UDTA_AUDIOTRAK; sl@0: break; sl@0: default: sl@0: Panic(KErrArgument); sl@0: } sl@0: return location; sl@0: } sl@0: sl@0: sl@0: void C3GPParse::Panic(TInt aPanic) sl@0: // Panic client sl@0: { sl@0: _LIT(K3GPParsePanicName, "C3GPParse"); sl@0: User::Panic(K3GPParsePanicName, aPanic); sl@0: } sl@0: sl@0: