videoeditorengine/h263decoder/src/VedVolReader.cpp
changeset 0 951a5db380a0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/videoeditorengine/h263decoder/src/VedVolReader.cpp	Fri Jan 29 14:08:33 2010 +0200
@@ -0,0 +1,889 @@
+/*
+* Copyright (c) 2010 Ixonos Plc.
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - Initial contribution
+*
+* Contributors:
+* Ixonos Plc
+*
+* Description:  
+* MPEG-4 VOL header parsing.
+*
+*/
+
+
+// INCLUDE FILES
+#include "mpegcons.h"
+#include "VedVolReader.h"
+
+
+
+// MACROS
+#ifdef _DEBUG
+#include <e32svr.h>
+#define PRINT(x) RDebug::Print x;
+#else
+#define PRINT(x)
+#endif
+
+
+
+// CONSTANTS
+const TUint8 CVedVolReader::KMsbMask[] = {1, 3, 7, 15, 31, 63, 127, 255};
+const TUint8 CVedVolReader::KLsbMask[] = {255, 254, 252, 248, 240, 224, 192, 128, 0};
+
+const TInt CVedVolReader::KMaxUserDataLength = 512;
+
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+// Two-phased constructor
+EXPORT_C CVedVolReader* CVedVolReader::NewL()
+    {
+    CVedVolReader* self = new (ELeave) CVedVolReader();
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+
+// C++ default constructor
+CVedVolReader::CVedVolReader() : iBitstreamMode(EVedVideoBitstreamModeUnknown)
+    {
+    // Reset the header data to zeroes
+    Mem::FillZ(&iHeader, sizeof(TVolHeader));
+    }
+
+// Symbian OS default constructor can leave
+void CVedVolReader::ConstructL()
+    {
+    }
+
+// Destructor
+CVedVolReader::~CVedVolReader()
+    {
+    if (iHeader.iUserData != 0)
+        {
+        delete iHeader.iUserData;
+        }
+    }
+    
+// ---------------------------------------------------------
+// CVedVolReader::ParseVolHeaderL
+// Parses given Video Object Layer header
+// ---------------------------------------------------------
+//
+EXPORT_C TInt CVedVolReader::ParseVolHeaderL(TDesC8& aData)
+    {
+    TInt useDefaultVBVParams = 0;
+    TInt numBits;
+    TUint32 bits;
+    
+    // Reset the header data
+    if (iHeader.iUserData != 0)
+        {
+        delete iHeader.iUserData;
+        iHeader.iUserData = 0;
+        }
+    Mem::FillZ(&iHeader, sizeof(TVolHeader));
+    iBitstreamMode = EVedVideoBitstreamModeUnknown;
+    iHeaderSize = 0;
+    
+    // Check that we have something to parse
+    if (aData.Length() == 0)
+        {
+        User::Leave(KErrNotFound);
+        }
+    
+    TSeqHeaderBuffer buffer(aData, 0, 7);   // Bit 7 is the first bit in a byte   
+    
+    // if H.263 PSC is present
+    bits = ReadSeqHeaderBits(buffer, 22, EFalse);
+    if (bits == 32)
+        {
+        // This is H.263 so there are no VOL headers
+        iBitstreamMode = EVedVideoBitstreamModeH263;
+        return KErrNone;
+        }
+
+    // if Visual Object Sequence Start Code is present 
+    bits = ReadSeqHeaderBits(buffer, MP4_VOS_START_CODE_LENGTH, EFalse);
+    if (bits == MP4_VOS_START_CODE)
+        {
+        // vos_start_code
+        ReadSeqHeaderBits(buffer, MP4_VOS_START_CODE_LENGTH, ETrue);
+
+        // profile_and_level_indication (8 bits) 
+        bits = ReadSeqHeaderBits(buffer, 8, ETrue);      
+        //   8: Simple Profile Level 0 (from ISO/IEC 14496-2:1999/FPDAM4 [N3670] October 2000)
+        //   9: Simple Profile Level 0b
+        //   1: Simple Profile Level 1
+        //   2: Simple Profile Level 2
+        //   3: Simple Profile Level 3
+        //   4: Simple Profile Level 4a
+        if (bits != 1 && bits != 2 && bits != 3 && bits != 4 && bits != 8 && bits != 9)
+            {
+            // Profile level id was not recognized so take a guess
+            // This is changed later if resolution does not match
+            bits = 9;
+            }
+            
+        iHeader.iProfileLevelId = (TInt) bits;
+            
+        ReadUserDataL(buffer);
+        }
+
+    // if Visual Object Start Code is present 
+    bits = ReadSeqHeaderBits(buffer, MP4_VO_START_CODE_LENGTH, EFalse);
+    if (bits == MP4_VO_START_CODE)
+        {
+        // visual_object_start_code
+        ReadSeqHeaderBits(buffer, MP4_VO_START_CODE_LENGTH, ETrue);
+
+        // is_visual_object_identifier (1 bit)
+        bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+        if (bits)
+            {
+            // visual_object_ver_id (4 bits)
+            bits = ReadSeqHeaderBits(buffer, 4, ETrue);
+            if (bits != 1 && bits != 2)
+                {
+                // this is not an MPEG-4 version 1 or 2 stream
+                PRINT((_L("CVedVolReader: ERROR - This is not an MPEG-4 version 1 or 2 stream")))
+                User::Leave(KErrNotSupported);
+                }
+
+            // visual_object_priority (3 bits) 
+            bits = ReadSeqHeaderBits(buffer, 3, ETrue);
+            iHeader.iVoPriority = (TInt) bits;
+            } 
+        else
+            {
+            iHeader.iVoPriority = 0;
+            }
+
+        // visual_object_type (4 bits)
+        bits = ReadSeqHeaderBits(buffer, 4, ETrue);
+        if (bits != 1)
+            {
+            // this is not a video object
+            PRINT((_L("CVedVolReader: ERROR - This is not a video object")))
+            User::Leave(KErrNotSupported);
+            }
+
+        // is_video_signal_type (1 bit)
+        bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+        if (bits)
+            {
+            /* Note: The following fields in the bitstream give information about the 
+               video signal type before encoding. These parameters don't influence the 
+               decoding algorithm, but the composition at the output of the video decoder.
+               Until a way to utilize them is found, these fields are just dummyly read,
+               but not interpreted.
+               For interpretation see the MPEG-4 Visual standard page 66-70. */
+
+            // video_format (3 bits)
+            bits = ReadSeqHeaderBits(buffer, 3, ETrue);
+            iHeader.iVideoFormat = (TInt) bits;
+
+            // video_range (1 bit)
+            bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+            iHeader.iVideoRange = (TInt) bits;
+
+            // colour_description (1 bit)
+            bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+            if (bits)
+                {          
+                // colour_primaries (8 bits)
+                bits = ReadSeqHeaderBits(buffer, 8, ETrue);
+                iHeader.iColourPrimaries = (TInt) bits;
+
+                // transfer_characteristics (8 bits)
+                bits = ReadSeqHeaderBits(buffer, 8, ETrue);
+                iHeader.iTransferCharacteristics = (TInt) bits;
+
+                // matrix_coefficients (8 bits)
+                bits = ReadSeqHeaderBits(buffer, 8, ETrue);
+                iHeader.iMatrixCoefficients = (TInt) bits;
+                }
+            else
+                {
+                iHeader.iColourPrimaries = 1;         // default: ITU-R BT.709 
+                iHeader.iTransferCharacteristics = 1; // default: ITU-R BT.709 
+                iHeader.iMatrixCoefficients = 1;      // default: ITU-R BT.709 
+                }
+            } 
+        else
+            {
+            // default values
+            iHeader.iVideoFormat = 5;             // Unspecified video format 
+            iHeader.iVideoRange = 0;              // Y range 16-235 pixel values 
+            iHeader.iColourPrimaries = 1;         // ITU-R BT.709 
+            iHeader.iTransferCharacteristics = 1; // ITU-R BT.709 
+            iHeader.iMatrixCoefficients = 1;      // ITU-R BT.709 
+            }
+
+        // check the next start code
+        ReadSeqHeaderBits(buffer, 1, ETrue);
+        if (buffer.iBitInOctet != 7)
+            {
+            numBits = buffer.iBitInOctet + 1;
+
+            bits = ReadSeqHeaderBits(buffer, numBits, ETrue);
+            if (bits != (TUint32) ((1 << numBits)-1))
+                {
+                // stuffing error in VO
+                PRINT((_L("CVedVolReader: ERROR - Stuffing error")))
+                User::Leave(KErrNotSupported);
+                }
+            }
+
+        ReadUserDataL(buffer);
+        }
+   
+    // if Video Object Start Code is present
+    bits = ReadSeqHeaderBits(buffer, MP4_VID_START_CODE_LENGTH, EFalse);
+    if (bits == MP4_VID_START_CODE)
+        {
+        // video_object_start_code 
+        ReadSeqHeaderBits(buffer, MP4_VID_START_CODE_LENGTH, ETrue);
+
+        // video_object_id
+        bits = ReadSeqHeaderBits(buffer, MP4_VID_ID_CODE_LENGTH, ETrue);
+        iHeader.iVoId = (TInt) bits;
+        }
+        
+    // Check if H.263 PSC follows the VO header, in which case this is MPEG-4 with short header
+    bits = ReadSeqHeaderBits(buffer, 22, EFalse);
+    if (bits == 32 || buffer.iData.Length() <= buffer.iGetIndex)
+        {
+        iBitstreamMode = EVedVideoBitstreamModeMPEG4ShortHeader;
+        
+        // Calculate the header size in bytes
+        if (buffer.iBitInOctet == 7)
+            {
+            // The size is a multiple of 8 bits so the size is the number of bytes we've read so far
+            iHeaderSize = buffer.iGetIndex;
+            }
+        else
+            {
+            // Round up to the next full byte
+            iHeaderSize = buffer.iGetIndex + 1;
+            }
+        
+        // We no longer support short header clips    
+        User::Leave(KErrNotSupported);
+        }
+
+    // vol_start_code 
+    bits = ReadSeqHeaderBits(buffer, MP4_VOL_START_CODE_LENGTH, ETrue);
+    if(bits != MP4_VOL_START_CODE)
+    {
+        PRINT((_L("CVedVolReader: ERROR - Bitstream does not start with MP4_VOL_START_CODE")))
+        User::Leave(KErrCorrupt);
+    }
+
+    // vol_id
+    bits = ReadSeqHeaderBits(buffer, MP4_VOL_ID_CODE_LENGTH, ETrue);
+    iHeader.iVolId = (TInt) bits;
+
+    // random_accessible_vol (1 bit)
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    iHeader.iRandomAccessibleVol = (TUint8) bits;
+
+    // video_object_type_indication (8 bits)
+    bits = ReadSeqHeaderBits(buffer, 8, ETrue);
+    if (bits != 1)
+        {
+        // this is not a simple video object stream 
+        PRINT((_L("CVedVolReader: ERROR - This is not a simple video object stream")))
+        User::Leave(KErrNotSupported);
+        }
+
+    // is_object_layer_identifier (1 bit)
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    if (bits)
+        {
+        // visual_object_ver_id (4 bits)
+        bits = ReadSeqHeaderBits(buffer, 4, ETrue);
+        if (bits != 1 && bits != 2)
+            {
+            // this is not an MPEG-4 version 1 or 2 stream
+            PRINT((_L("CVedVolReader: ERROR - This is not an MPEG-4 version 1 or 2 stream")))
+            User::Leave(KErrNotSupported);
+            }
+
+        // video_object_layer_priority (3 bits)
+        bits = ReadSeqHeaderBits(buffer, 3, ETrue);
+        iHeader.iVoPriority = (TInt) bits;
+        } 
+
+    // aspect_ratio_info: `0010`- 12:11 (625-type for 4:3 picture)
+    bits = ReadSeqHeaderBits(buffer, 4, ETrue);
+    iHeader.iPixelAspectRatio = (TInt) bits;
+
+    // extended par 
+    if (bits == 15)
+        { 
+        // par_width 
+        bits = ReadSeqHeaderBits(buffer, 8, ETrue);
+        // par_height 
+        bits = ReadSeqHeaderBits(buffer, 8, ETrue);
+        }
+   
+    // vol_control_parameters flag 
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    if (bits)
+        {
+        // chroma_format (2 bits)
+        bits = ReadSeqHeaderBits(buffer, 2, ETrue);
+        if (bits != 1)
+            {
+            PRINT((_L("CVedVolReader: ERROR - Not supported chroma format")))
+            User::Leave(KErrNotSupported);
+            }
+
+        // low_delay (1 bits)
+        bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+
+        // vbv_parameters (1 bits)
+        bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+        if (bits)
+            {
+            // first_half_bitrate (15 bits) 
+            bits = ReadSeqHeaderBits(buffer, 15, ETrue);
+            iHeader.iBitRate = (bits << 15);
+          
+            // marker_bit
+            if (!ReadSeqHeaderBits(buffer, 1, ETrue))
+                {
+                User::Leave(KErrCorrupt);
+                }
+           
+            // latter_half_bitrate (15 bits)
+            bits = ReadSeqHeaderBits(buffer, 15, ETrue);
+            iHeader.iBitRate += bits;
+            iHeader.iBitRate *= 400;
+           
+            // marker_bit
+            if (!ReadSeqHeaderBits(buffer, 1, ETrue))
+                {
+                User::Leave(KErrCorrupt);
+                }
+           
+            // first_half_vbv_buffer_size (15 bits)
+            bits = ReadSeqHeaderBits(buffer, 15, ETrue);
+            iHeader.iVbvBufferSize = (bits << 3);
+           
+            // marker_bit
+            if (!ReadSeqHeaderBits(buffer, 1, ETrue))
+                {
+                User::Leave(KErrCorrupt);
+                }
+           
+            // latter_half_vbv_buffer_size (3 bits)
+            bits = ReadSeqHeaderBits(buffer, 3, ETrue);
+            iHeader.iVbvBufferSize += bits;
+            iHeader.iVbvBufferSize *= 16384;
+           
+            // first_half_vbv_occupancy (11 bits)
+            bits = ReadSeqHeaderBits(buffer, 11, ETrue);
+            iHeader.iVbvOccupancy = (bits << 15);
+           
+            // marker_bit
+            if (!ReadSeqHeaderBits(buffer, 1, ETrue))
+                {
+                User::Leave(KErrCorrupt);
+                }
+           
+            // latter_half_vbv_occupancy (15 bits) 
+            bits = ReadSeqHeaderBits(buffer, 15, ETrue);
+            iHeader.iVbvOccupancy += bits;
+            iHeader.iVbvOccupancy *= 64;
+           
+            // marker_bit
+            if (!ReadSeqHeaderBits(buffer, 1, ETrue))
+                {
+                User::Leave(KErrCorrupt);
+                }
+            }
+        else
+            {
+            useDefaultVBVParams = 1;
+            }
+        }     
+    else
+        {
+        useDefaultVBVParams = 1;
+        }
+
+    // vol_shape (2 bits) 
+    bits = ReadSeqHeaderBits(buffer, 2, ETrue);
+    // rectangular_shape = '00'
+    if (bits != 0)
+        {
+        PRINT((_L("CVedVolReader: ERROR - Not rectangular shape is not supported")))
+        User::Leave(KErrNotSupported);
+        }
+
+    // marker_bit
+    if (!ReadSeqHeaderBits(buffer, 1, ETrue))
+        {
+        User::Leave(KErrCorrupt);
+        }
+    
+    // time_increment_resolution 
+    bits = ReadSeqHeaderBits(buffer, 16, ETrue);
+    iHeader.iTimeIncrementResolution = (TInt) bits;
+ 
+    // marker_bit
+    if (!ReadSeqHeaderBits(buffer, 1, ETrue))
+        {
+        User::Leave(KErrCorrupt);
+        }
+    
+    // fixed_vop_rate 
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+
+    // fixed_vop_time_increment (1-15 bits)
+    if (bits)
+        {
+        for (numBits = 1; ((iHeader.iTimeIncrementResolution-1) >> numBits) != 0; numBits++) 
+            {
+            }
+
+        bits = ReadSeqHeaderBits(buffer, numBits, ETrue);
+        }
+
+    // marker_bit
+    if (!ReadSeqHeaderBits(buffer, 1, ETrue))
+        {
+        User::Leave(KErrCorrupt);
+        }
+    
+    // vol_width (13 bits) 
+    bits = ReadSeqHeaderBits(buffer, 13, ETrue);
+    iHeader.iLumWidth = (TInt) bits;
+
+    // marker_bit
+    if (!ReadSeqHeaderBits(buffer, 1, ETrue))
+        {
+        User::Leave(KErrCorrupt);
+        }
+    
+    // vol_height (13 bits) 
+    bits = ReadSeqHeaderBits(buffer, 13, ETrue);
+    iHeader.iLumHeight = (TInt) bits;
+    
+    // Accept only resolutions that are divisible by 16
+    if ( ((iHeader.iLumWidth & 0x0000000f) != 0) ||
+        ((iHeader.iLumHeight & 0x0000000f) != 0) )
+        {
+        PRINT((_L("CVedVolReader: ERROR - Unsupported resolution")))
+        User::Leave(KErrNotSupported);
+        }
+        
+    TInt macroBlocks = iHeader.iLumWidth * iHeader.iLumHeight / (16 * 16);
+    
+    // Check that we don't have too many macro blocks (ie resolution is not too big)
+    if( macroBlocks > 1200 )
+        {
+        PRINT((_L("CVedVolReader: ERROR - Unsupported resolution")))
+        User::Leave(KErrNotSupported);
+        }
+        
+    // Check that profile level id matches with the number of macro blocks
+    if( macroBlocks > 396 )
+        {
+        // Resolution is higher than CIF => level must be 4a
+        if( iHeader.iProfileLevelId != 4 )
+            {
+            iHeader.iProfileLevelId = 4;
+            useDefaultVBVParams = 1;
+            }
+        }
+    else if( macroBlocks > 99 )
+        {
+        // Resolution is higher than QCIF => level must be atleast 2
+        if( iHeader.iProfileLevelId < 2 || iHeader.iProfileLevelId > 4 )
+            {
+            iHeader.iProfileLevelId = 3;    // QVGA/CIF @ 30fps
+            useDefaultVBVParams = 1;
+            }
+        }
+    
+    // Set default VBV params if not set already  
+    if (useDefaultVBVParams)
+        {
+        switch (iHeader.iProfileLevelId)
+            {
+            case 1:
+                iHeader.iVbvBufferSize = 10;
+                iHeader.iBitRate = 64;
+                break;
+            case 2:
+                iHeader.iVbvBufferSize = 20;
+                iHeader.iBitRate = 128;
+                break;
+            case 4:
+                iHeader.iVbvBufferSize = 80;
+                iHeader.iBitRate = 4000;
+                break;
+            case 8:
+                iHeader.iVbvBufferSize = 10;
+                iHeader.iBitRate = 64;
+                break;
+            case 9:
+                iHeader.iVbvBufferSize = 20;
+                iHeader.iBitRate = 128;
+                break;
+            default:
+                iHeader.iVbvBufferSize = 20;
+                iHeader.iBitRate = 384;
+                break;
+            }
+        
+        iHeader.iVbvOccupancy = iHeader.iVbvBufferSize * 170;
+       
+        iHeader.iVbvOccupancy *= 64;
+        iHeader.iVbvBufferSize *= 16384;
+        iHeader.iBitRate *= 1024;
+        }
+    
+    // marker_bit
+    if (!ReadSeqHeaderBits(buffer, 1, ETrue))
+        {
+        User::Leave(KErrCorrupt);
+        }
+    
+    // interlaced (1 bit)
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    if (bits)
+        {
+        PRINT((_L("CVedVolReader: ERROR - Interlaced VOP not supported")))
+        User::Leave(KErrNotSupported);
+        }
+
+    // OBMC_disable
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    if (!bits)
+        {
+        PRINT((_L("CVedVolReader: ERROR - Overlapped motion compensation not supported")))
+        User::Leave(KErrNotSupported);
+        }
+
+    // sprite_enable (1 bit) 
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    if (bits)
+        {
+        PRINT((_L("CVedVolReader: ERROR - Sprites not supported")))
+        User::Leave(KErrNotSupported);
+        }
+
+    // not_8_bit (1 bit) 
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    if (bits)
+        {
+        PRINT((_L("CVedVolReader: ERROR - Not 8 bits/pixel not supported")))
+        User::Leave(KErrNotSupported);
+        }
+
+    // quant_type (1 bit) 
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    if (bits)
+        {
+        PRINT((_L("CVedVolReader: ERROR - H.263/MPEG-2 Quant Table switch not supported")))
+        User::Leave(KErrNotSupported);
+        }
+
+    // complexity_estimation_disable (1 bit) 
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    if (!bits)
+        {
+        PRINT((_L("CVedVolReader: ERROR - Complexity estimation header not supported")))
+        User::Leave(KErrNotSupported);
+        }
+  
+    // resync_marker_disable (1 bit)
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    iHeader.iErrorResDisable = (TUint8) bits;
+
+    // data_partitioned (1 bit) 
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    iHeader.iDataPartitioned = (TUint8) bits;
+
+    if (iHeader.iDataPartitioned)
+        {
+        // reversible_vlc (1 bit)
+        bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+        iHeader.iReversibleVlc = (TUint8) bits;
+        }
+
+    // scalability (1 bit)
+    bits = ReadSeqHeaderBits(buffer, 1, ETrue);
+    if (bits)
+        {
+        PRINT((_L("CVedVolReader: ERROR - Scalability not supported")))
+        User::Leave(KErrNotSupported);
+        }
+
+    // check the next start code
+    ReadSeqHeaderBits(buffer, 1, ETrue);
+    if (buffer.iBitInOctet != 7)
+        {
+        numBits = buffer.iBitInOctet + 1;
+       
+        bits = ReadSeqHeaderBits(buffer, numBits, ETrue);
+        
+        /* Removed temporarily
+        if (bits != (TUint32) ((1 << numBits)-1))
+            {
+            // this is not a video object
+            PRINT((_L("CVedVolReader: ERROR - Stuffing error")))
+            User::Leave(KErrNotSupported);
+            }*/
+        }
+
+    ReadUserDataL(buffer);
+        
+    // Calculate the header size in bytes
+    if (buffer.iBitInOctet == 7)
+        {
+        // The size is a multiple of 8 bits so the size is the number of bytes we've read so far
+        iHeaderSize = buffer.iGetIndex;
+        }
+    else
+        {
+        // Round up to the next full byte
+        iHeaderSize = buffer.iGetIndex + 1;
+        }
+     
+    // Determine the bitstream mode  
+    iBitstreamMode = CheckBitstreamMode(iHeader.iErrorResDisable, iHeader.iDataPartitioned, iHeader.iReversibleVlc);
+
+    // If no error in bit buffer functions
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------
+// CVedVolReader::ReadSeqHeaderBits
+// Reads requested bits from given buffer
+// ---------------------------------------------------------
+//  
+TUint32 CVedVolReader::ReadSeqHeaderBits(TSeqHeaderBuffer& aBuffer, TInt aNumBits, TBool aFlush)
+    {      
+    TUint startIndex;       // the index of the first byte to read 
+    TUint startMask;        // the mask for the first byte 
+    TUint endIndex;         // the index of the last byte to read 
+    TUint endMask;          // the mask for the last byte 
+    TUint endShift;         // the number of shifts after masking the last byte 
+    TUint endNumberOfBits;  // the number of bits in the last byte 
+    TUint newBitIndex;      // bitIndex after getting the bits 
+    TUint newGetIndex;      // getIndex after getting the bits 
+    
+    TUint32 returnValue = 0;
+
+    startIndex = aBuffer.iGetIndex;
+    startMask = KMsbMask[aBuffer.iBitInOctet];
+
+    // Check that there are enough bits left
+    if (startIndex * 8 + aNumBits > aBuffer.iData.Length() * 8)
+        {
+	    return 0;
+        }
+
+    if (aBuffer.iBitInOctet + 1 >= aNumBits)
+        {
+        // The bits are within one byte. 
+        endShift = aBuffer.iBitInOctet - aNumBits + 1;
+        endMask = KLsbMask[endShift];
+        returnValue = (aBuffer.iData[startIndex] & startMask & endMask) >> endShift;
+        if (endShift > 0)
+            {
+            newBitIndex = aBuffer.iBitInOctet - aNumBits;
+            newGetIndex = aBuffer.iGetIndex;
+            }
+        else
+            {
+            newBitIndex = 7;
+            newGetIndex = aBuffer.iGetIndex + 1;
+            }
+        } 
+    else
+        {
+        // The bits are in multiple bytes. 
+        aNumBits -= aBuffer.iBitInOctet + 1;
+        endNumberOfBits = aNumBits & 7;
+
+        newBitIndex = 7 - endNumberOfBits;
+        newGetIndex = aBuffer.iGetIndex + (aNumBits >> 3) + 1;
+      
+        // Calculate the return value. 
+        endIndex = newGetIndex;
+        endShift = 8 - (aNumBits & 7);
+        endMask = KLsbMask[endShift];
+      
+        returnValue = aBuffer.iData[startIndex] & startMask;
+        startIndex++;
+      
+        while (startIndex != endIndex)
+            {
+            returnValue <<= 8;
+            returnValue += (TUint8) aBuffer.iData[startIndex];
+            startIndex++;
+            }
+        
+        if (endNumberOfBits != 0)
+            {
+            returnValue <<= endNumberOfBits;
+            returnValue += (aBuffer.iData[startIndex] & endMask) >> endShift;
+            }
+        }
+
+    if (aFlush)
+        {
+        // Update indexes. 
+        aBuffer.iGetIndex = newGetIndex;
+        aBuffer.iBitInOctet = newBitIndex;
+        }
+
+    return returnValue;
+    }
+
+// ---------------------------------------------------------
+// CVedVolReader::ReadUserDataL
+// Reads user data from given buffer
+// ---------------------------------------------------------
+//    
+void CVedVolReader::ReadUserDataL(TSeqHeaderBuffer& aBuffer)
+    {
+    TUint32 bits;
+    
+    // Check if User data is available 
+    bits = ReadSeqHeaderBits(aBuffer, 32, EFalse);
+    if (bits == MP4_USER_DATA_START_CODE)
+        {
+        if (iHeader.iUserData == 0)
+            {
+            iHeader.iUserData = HBufC8::NewL(KMaxUserDataLength);
+            }
+            
+        TInt i = iHeader.iUserData->Length();    
+        do 
+            {
+            bits = ReadSeqHeaderBits(aBuffer, 8, ETrue);
+            if (i++ < KMaxUserDataLength)
+                {
+                (iHeader.iUserData->Des()).Append(TChar(bits));
+                }
+            }
+        while (aBuffer.iData.Length() > aBuffer.iGetIndex &&
+               ReadSeqHeaderBits(aBuffer, 24, EFalse) != 0x1);
+        }
+    }
+     
+// ---------------------------------------------------------
+// CVedVolReader::CheckBitstreamMode
+// Checks what is the bit stream mode the video
+// ---------------------------------------------------------
+//
+TVedVideoBitstreamMode CVedVolReader::CheckBitstreamMode(TUint8 aErd, TUint8 aDp, TUint8 aRvlc)
+    {
+    TVedVideoBitstreamMode mode = EVedVideoBitstreamModeUnknown;
+    int combination = ((!aErd) << 2) | (aDp << 1) | aRvlc;
+                      
+    switch (combination)
+        {
+        case 0:
+            mode = EVedVideoBitstreamModeMPEG4Regular;
+            break;
+        case 2:
+            mode = EVedVideoBitstreamModeMPEG4DP;
+            break;
+        case 3:
+            mode = EVedVideoBitstreamModeMPEG4DP_RVLC;
+            break;
+        case 4:
+            mode = EVedVideoBitstreamModeMPEG4Resyn;
+            break;
+        case 6:
+            mode = EVedVideoBitstreamModeMPEG4Resyn_DP;
+            break;
+        case 7:
+            mode = EVedVideoBitstreamModeMPEG4Resyn_DP_RVLC;
+            break;
+        default:
+            break;
+        }
+        
+    return mode;
+    }
+    
+// ---------------------------------------------------------
+// CVedVolReader::TimeIncrementResolution
+// Returns the time increment resolution that was read from the VOL header
+// ---------------------------------------------------------
+//     
+EXPORT_C TInt CVedVolReader::TimeIncrementResolution() const
+    {
+    return iHeader.iTimeIncrementResolution;
+    }
+       
+// ---------------------------------------------------------
+// CVedVolReader::Width
+// Returns the width of the video that was read from the VOL header
+// ---------------------------------------------------------
+// 
+EXPORT_C TInt CVedVolReader::Width() const
+    {
+    return iHeader.iLumWidth;
+    }
+      
+// ---------------------------------------------------------
+// CVedVolReader::Height
+// Returns the height of the video that was read from the VOL header
+// ---------------------------------------------------------
+// 
+EXPORT_C TInt CVedVolReader::Height() const
+    {
+    return iHeader.iLumHeight;
+    }
+    
+// ---------------------------------------------------------
+// CVedVolReader::ProfileLevelId
+// Returns the Level Id of the Simple Profile the Video Object conforms to
+// ---------------------------------------------------------
+// 
+EXPORT_C TInt CVedVolReader::ProfileLevelId() const
+    {
+    return iHeader.iProfileLevelId;
+    }
+    
+// ---------------------------------------------------------
+// CVedVolReader::BitstreamMode
+// Returns the bitstream mode of the video
+// ---------------------------------------------------------
+//  
+EXPORT_C TVedVideoBitstreamMode CVedVolReader::BitstreamMode() const
+    {
+    return iBitstreamMode;
+    }
+    
+// ---------------------------------------------------------
+// CVedVolReader::HeaderSize
+// Returns the bitstream mode of the video
+// ---------------------------------------------------------
+//  
+EXPORT_C TInt CVedVolReader::HeaderSize() const
+    {
+    return iHeaderSize;
+    }
+