accessoryservices/pluggeddisplay/edidparser/src/cea861edidparser.cpp
changeset 0 4e1aa6a622a0
child 5 1a73e8f1b64d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/accessoryservices/pluggeddisplay/edidparser/src/cea861edidparser.cpp	Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,1921 @@
+/*
+ * Copyright (c) 2008,2009 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of "Eclipse Public License v1.0"
+ * which accompanies this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ *
+ * Initial Contributors:
+ * Nokia Corporation - initial contribution.
+ *
+ * Contributors:
+ *
+ * Description:
+ * Implementation of CCea861EdidParser class.
+ *
+ */
+
+#include "cea861edidparser.h"
+#include "trace.h"
+
+// ======== LOCAL FUNCTIONS ========
+
+
+// ======== MEMBER FUNCTIONS ========
+
+
+// ---------------------------------------------------------------------------
+// CCea861EdidParser::CCea861EdidParser
+// ---------------------------------------------------------------------------
+//
+CCea861EdidParser::CCea861EdidParser() :
+    iParsed( EFalse ),
+    iAudioDataBlockSupported( EFalse ),
+    iVideoDataBlockSupported( EFalse ),
+    iVendorSpecificDataBlockSupported( EFalse ),
+    iSpeakerAllocationDataBlockSupported( EFalse )
+    {
+    FUNC_LOG;
+    }
+
+// ---------------------------------------------------------------------------
+// CEdidParserBase::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CCea861EdidParser::ConstructL( const TExtDataBlock& aData )
+    {
+    FUNC_LOG;
+
+    iParsedInfo = CCea861ExtEdidInformation::NewL();
+    ParseExtensionBlockL( aData );
+    }
+
+// ---------------------------------------------------------------------------
+// CEdidParserBase::NewL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C CCea861EdidParser* CCea861EdidParser::NewL( const TExtDataBlock& aData )
+    {
+    FUNC_LOG;
+
+    CCea861EdidParser* self = CCea861EdidParser::NewLC( aData );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CEdidParserBase::NewLC
+// ---------------------------------------------------------------------------
+//
+EXPORT_C CCea861EdidParser* CCea861EdidParser::NewLC( const TExtDataBlock& aData )
+    {
+    FUNC_LOG;
+
+    CCea861EdidParser* self = new ( ELeave ) CCea861EdidParser();
+    CleanupStack::PushL( self );
+    self->ConstructL( aData );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CCea861EdidParser::~CCea861EdidParser
+// ---------------------------------------------------------------------------
+//
+CCea861EdidParser::~CCea861EdidParser()
+    {
+    FUNC_LOG;
+
+    delete iParsedInfo;
+    }
+
+// ---------------------------------------------------------------------------
+// CCea861EdidParser::ParseExtensionBlockL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TInt CCea861EdidParser::ParseExtensionBlockL( const TExtDataBlock& aData )
+    {
+    FUNC_LOG;
+
+    TInt err( KErrNone );
+    TInt index( 0 );
+
+    // Check first byte to see if tag is 0x2.
+    // If not return error.
+    if( aData[index] != KBit1 )
+        {
+        return KErrNotSupported;
+        }
+
+    iParsedInfo->iExtensionTag = aData[index];
+    index++;
+
+    // Check revision
+    iParsedInfo->iRevision = aData[index];
+    index++;
+    switch( iParsedInfo->iRevision )
+        {
+        case 1:
+            err = ReadCeaVersion1L( aData, index );
+            break;
+        case 2:
+            err = ReadCeaVersion2L( aData, index );
+            break;
+        case 3:
+            err = ReadCeaVersion3L( aData, index );
+            break;
+        default:
+            err = KErrNotSupported;
+            break;
+        }
+
+    if( err == KErrNone )
+        {
+        iParsed = ETrue;
+        }
+
+    return err;
+    }
+
+// ---------------------------------------------------------------------------
+// CCea861EdidParser::isExtensionBlockParsed
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TBool CCea861EdidParser::IsExtensionBlockParsed()
+    {
+    FUNC_LOG;
+
+    return iParsed;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetVIC
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TInt8 CCea861EdidParser::GetVIC( TUint8 aNumber )
+    {
+    FUNC_LOG;
+
+    if( !iParsed )
+        {
+        return KErrNotFound;
+        }
+
+    if( IsVideoDataBlockSupported() )
+        {
+        return KErrNotFound;
+        }
+
+    if( iParsedInfo->iShortVideoDescriptors )
+        {
+        TCEA861VideoDataBlock* cur = iParsedInfo->iShortVideoDescriptors;
+        TUint8 count = 0;
+        while( cur )
+            {
+            if( cur->iNative )
+                {
+                if( count == aNumber )
+                    {
+                    return cur->iVIC;
+                    }
+                count++;
+                }
+            cur = cur->iNext;
+            }
+        }
+
+    return KErrNotFound;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::Underscan
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CCea861EdidParser::Underscan()
+    {
+    FUNC_LOG;
+
+    if( iParsedInfo->UnderscanDataSupported() )
+        {
+        return iParsedInfo->iUnderscan;
+        }
+    return EFalse;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::BasicAudio
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CCea861EdidParser::BasicAudio()
+    {
+    FUNC_LOG;
+
+    if( iParsedInfo->AudioDataSupported() )
+        {
+        return iParsedInfo->iAudio;
+        }
+    return EFalse;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::YCbCr444
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CCea861EdidParser::YCbCr444()
+    {
+    FUNC_LOG;
+
+    if( iParsedInfo->YCbCr444DataSupported() )
+        {
+        return iParsedInfo->iYCbCr444;
+        }
+    return EFalse;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::YCbCr422
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CCea861EdidParser::YCbCr422()
+    {
+    FUNC_LOG;
+
+    if( iParsedInfo->YCbCr422DataSupported() )
+        {
+        return iParsedInfo->iYCbCr422;
+        }
+    return EFalse;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::TotalNumberOfNativeFormats
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TUint8 CCea861EdidParser::TotalNumberOfNativeFormats()
+    {
+    FUNC_LOG;
+    
+    return iParsedInfo->TotalNumberOfNativeFormats();
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::IsAudioDataBlockSupported
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CCea861EdidParser::IsAudioDataBlockSupported()
+    {
+    FUNC_LOG;
+
+    return iAudioDataBlockSupported;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::IsVideoDataBlockSupported
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CCea861EdidParser::IsVideoDataBlockSupported()
+    {
+    FUNC_LOG;
+
+    return iVideoDataBlockSupported;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::IsVideoDataBlockSupported
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CCea861EdidParser::IsVendorSpecificDataBlockSupported()
+    {
+    FUNC_LOG;
+
+    return iVendorSpecificDataBlockSupported;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetParsedInformation
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CCea861ExtEdidInformation* CCea861EdidParser::GetParsedInformation()
+    {
+    FUNC_LOG;
+
+    return iParsedInfo;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::IsSpeakerAllocationDataBlockSupported
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CCea861EdidParser::IsSpeakerAllocationDataBlockSupported()
+    {
+    FUNC_LOG;
+
+    return iSpeakerAllocationDataBlockSupported;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetVideoLatency
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TUint8 CCea861EdidParser::GetVideoLatency()
+    {
+    FUNC_LOG;
+
+    // Video latency is kept in Vendor Specific Data Block according to
+    // HDMISpecification13a.pdf, table 8-6
+    TUint8 latency = 0;
+    TCEA861VendorSpecificDataBlock* data = iParsedInfo->iVendorSpecificData;
+    if( ( !data ) || ( !IsVendorSpecificDataBlockSupported() ) )
+        {
+        return latency;
+        }
+
+    TCEA861VendorSpecificDataBlockPayload* cur = data->iVendorSpecificPayloadStart;
+
+    // According to HDMI spec table 8-6,  index of video latency is 9
+    // Start counting from index 4 
+    for( TInt ii = 0; ii < 6; ii++ )
+        {
+        if( !cur )
+            {
+            break;
+            }
+        
+        // Byte 8
+        else if( ii == 4 )
+            {
+            // Check if latency field bits are present
+            if( !LatencyFieldsPresent( cur->iData ) )
+                {
+                // Latency fields are not present
+                break;
+                }
+            }
+
+        // Byte 9
+        else if( ii == 5 )
+            {
+            // Get Video_latency byte
+            latency = cur->iData;
+            }
+
+        cur = cur->iNext;
+        }
+    
+    // Convert latency in to ms
+    latency = LatencyInMs( latency );
+
+    return latency;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetAudioLatency
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TUint8 CCea861EdidParser::GetAudioLatency()
+    {
+    FUNC_LOG;
+
+    // Audio latency is kept in Vendor Specific Data Block according to
+    // HDMISpecification13a.pdf, table 8-6
+    TUint8 latency = 0;
+    TCEA861VendorSpecificDataBlock* data = iParsedInfo->iVendorSpecificData;
+    if( ( !data ) || ( !IsVendorSpecificDataBlockSupported() ) )
+        {
+        return latency;
+        }
+
+    TCEA861VendorSpecificDataBlockPayload* cur = data->iVendorSpecificPayloadStart;
+
+    // According to HDMI spec table 8-6,  index of audio latency is 10
+    // Start counting from index 4 
+    for( TInt ii = 0; ii < 7; ii++ )
+        {
+        if( !cur )
+            {
+            break;
+            }
+
+        // Byte 8
+        else if( ii == 4 )
+            {
+            // Check if latency field bits are present
+            if( !LatencyFieldsPresent( cur->iData ) )
+                {
+                // Latency fields are not present
+                break;
+                }
+            }
+        
+        // Byte 10
+        else if( ii == 6 )
+            {
+            latency = cur->iData;
+            }
+
+        cur = cur->iNext;
+        }
+
+    // Convert latency in to ms
+    latency = LatencyInMs( latency );
+
+    return latency;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetInterlacedVideoLatency
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TUint8 CCea861EdidParser::GetInterlacedVideoLatency()
+    {
+    // Video latency is kept in Vendor Specific Data Block according to
+    // HDMISpecification13a.pdf, table 8-6
+    TUint8 latency = 0;
+    TCEA861VendorSpecificDataBlock* data = iParsedInfo->iVendorSpecificData;
+    if( ( !data ) || ( !IsVendorSpecificDataBlockSupported() ) )
+        {
+        return latency;
+        }
+
+    TCEA861VendorSpecificDataBlockPayload* cur = data->iVendorSpecificPayloadStart;
+
+    // According to HDMI spec table 8-6,  index of video latency is 9 or 11
+    // Start counting from index 4
+    
+    // Start index == 4, video latency == 9 (4 + 5)
+    TInt videoLatencyByte = 5;
+    for( TInt ii = 0; ii < 8; ii++ )
+        {
+        if( !cur )
+            {
+            break;
+            }
+        
+        // Byte 8
+        else if( ii == 4 )
+            {
+            // Check if latency field bits are present
+            TUint8 byte8 = cur->iData;
+            if( InterlacedLatencyFieldsPresent( byte8 ) )
+                {
+                // Interlaced latency fields are present
+                // Start index == 4, interlaced video latency == 11 (4 + 7)
+                videoLatencyByte = 7;
+                }
+            else if( !LatencyFieldsPresent( byte8 ) )
+                {
+                // Latency fields are not present
+                break;
+                }
+            }
+
+        // Byte 9 or Byte 11
+        else if( ii == videoLatencyByte )
+            {
+            // Get Video_latency byte
+            latency = cur->iData;
+            }
+
+        cur = cur->iNext;
+        }
+
+    // Convert latency in to ms
+    latency = LatencyInMs( latency );
+
+    return latency;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetInterlacedAudioLatency
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TUint8 CCea861EdidParser::GetInterlacedAudioLatency()
+    {
+    FUNC_LOG;
+
+    // Audio latency is kept in Vendor Specific Data Block according to
+    // HDMISpecification13a.pdf, table 8-6
+    TUint8 latency = 0;
+    TCEA861VendorSpecificDataBlock* data = iParsedInfo->iVendorSpecificData;
+    if( ( !data ) || ( !IsVendorSpecificDataBlockSupported() ) )
+        {
+        return latency;
+        }
+
+    TCEA861VendorSpecificDataBlockPayload* cur = data->iVendorSpecificPayloadStart;
+
+    // According to HDMI spec table 8-6,  index of audio latency is 10 or 12
+    // Start counting from index 4
+    
+    // Start index == 4, audio latency == 10 (4 + 6)
+    TInt audioLatencyByte = 6;
+    for( TInt ii = 0; ii < 9; ii++ )
+        {
+        if( !cur )
+            {
+            break;
+            }
+
+        // Byte 8
+        else if( ii == 4 )
+            {
+            // Check if interlaced latency field bits are present
+            TUint8 byte8 = cur->iData;
+            if( InterlacedLatencyFieldsPresent( byte8 ) )
+                {
+                // Start index == 4, interlaced audio latency == 12 (4 + 8)
+                audioLatencyByte = 8;
+                }
+            
+            // Check if latency field bits are present
+            else if( !LatencyFieldsPresent( byte8 ) )
+                {
+                // Latency fields are not present
+                break;
+                }
+            }
+        
+        // Byte 10 or Byte 12
+        else if( ii == audioLatencyByte )
+            {
+            latency = cur->iData;
+            }
+
+        cur = cur->iNext;
+        }
+
+    // Convert latency in to ms
+    latency = LatencyInMs( latency );
+
+    return latency;
+    }
+
+// ---------------------------------------------------------------------------
+// CCea861EdidParser::ReadCeaVersion1L
+// ---------------------------------------------------------------------------
+//
+TInt CCea861EdidParser::ReadCeaVersion1L( const TExtDataBlock& aData,
+    TInt aIndex )
+    {
+    FUNC_LOG;
+
+    if( aIndex > KEdidParserSizeOfEdidBlock )
+        {
+        return KErrOverflow;
+        }
+
+    for( TInt index = aIndex; index < KEdidParserSizeOfEdidBlock; index++ )
+        {
+        // Offset. If this is a newer version of CEA-861,
+        // then this is skipped (we are already past the offset)
+        if( index == 2 )
+            {
+            iParsedInfo->iOffset = aData[index];
+            // Skip over the offset
+            while( index < iParsedInfo->iOffset )
+                {
+                index++;
+                }
+            }
+
+        if( aData[index] != KEdidPaddingByte ) // padding = 0x00
+            {
+            // start of 18-byte descriptors: See section 3.10.2 of VESA E-EDID Standard [10]
+
+            TBool first = ETrue;
+            if( iParsedInfo->iDescriptorBlocks == 0 )
+                {
+                iParsedInfo->iDescriptorBlocks
+                    = new ( ELeave ) TCEA861TEdidDescriptorBlockList();
+                }
+
+            // read the descriptors here
+            TEdidDescriptorBlock tmp = GetDescriptorBlock( aData, index );
+            if( first )
+                {
+                first = EFalse;
+                iParsedInfo->iDescriptorBlocks->iData = tmp;
+                continue;
+                }
+            TCEA861TEdidDescriptorBlockList* last =
+                iParsedInfo->iDescriptorBlocks;
+            while( last->iNext != 0 ) // go to last block
+                {
+                last = last->iNext;
+                }
+            last->iNext = new ( ELeave ) TCEA861TEdidDescriptorBlockList();
+            last = last->iNext;
+            last->iData = tmp;
+            }
+        else
+            {
+            // this is only padding, no need to do anything
+            }
+
+        // after the descriptors there is padding to fill Extension block to 128 bytes.
+        // beginning of padding               | End of padding  | Checksum
+        // d+(18*n) ..........................| 126             | 127
+        if( index == 0x7F )
+            {
+            iParsedInfo->iChecksum = aData[index];
+            // Finished reading
+            return KErrNone;
+            }
+        }
+
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// CCea861EdidParser::ReadCeaVersion2L
+// ---------------------------------------------------------------------------
+//
+TInt CCea861EdidParser::ReadCeaVersion2L( const TExtDataBlock& aData,
+    TInt aIndex )
+    {
+    FUNC_LOG;
+
+    ReadCeaVersion2and3Common( aData, aIndex );
+
+    return ReadCeaVersion1L( aData, aIndex );
+    }
+
+// ---------------------------------------------------------------------------
+// CCea861EdidParser::ReadCeaVersion3L
+// ---------------------------------------------------------------------------
+//
+TInt CCea861EdidParser::ReadCeaVersion3L( const TExtDataBlock& aData,
+    TInt aIndex )
+    {
+    FUNC_LOG;
+
+    // first read the common information in versions 2 and 3
+    ReadCeaVersion2and3Common( aData, aIndex );
+
+    if( aIndex == 4 ) // start of the Data block collection (see table 39)
+        {
+        while( aIndex < iParsedInfo->iOffset ) // it is possible to have more than one DataBlockCollection
+            {
+            TInt ret = ReadCeaDataBlockCollectionL( aData, aIndex );
+            if( ret != KErrNone )
+                {
+                return ret;
+                }
+            if( aIndex > KEdidParserSizeOfEdidBlock )
+                {
+                return KErrOverflow;
+                }
+            }
+        // after reading the CEADataBlockCollections, we can read all the descriptors
+        }
+    else
+        {
+        // error
+        if( aIndex < 4 )
+            {
+            return KErrNotFound;
+            }
+        else
+            {
+            return KErrOverflow;
+            }
+        }
+    return ReadCeaVersion1L( aData, aIndex );
+    }
+
+// ---------------------------------------------------------------------------
+// CCea861EdidParser::ReadCeaVersion2L
+// ---------------------------------------------------------------------------
+//
+TInt CCea861EdidParser::ReadCeaVersion2and3Common( const TExtDataBlock& aData,
+    TInt& aIndex )
+    {
+    FUNC_LOG;
+
+    for( TInt i = aIndex; i < KEdidParserSizeOfEdidBlock; i++ )
+        {
+        if( aIndex == 2 ) // offset
+            {
+            iParsedInfo->iOffset = aData[i];
+            // don't skip over the offset
+            }
+        if( aIndex == 3 )
+            {
+            // bit 7 = underscan: 1 if sink underscans IT video formats by default
+            // bit 6 = audio    : 1 if sink supports basic audio
+            // bit 5 = YCbCr 4:4:4 = 1 if sink supports YCbCr 4:4:4 in addition to RGB
+            // bit 4 = YCbCr 4:2:2 = 1 if sink supports YCbCr 4:2:2 in addition to RGB
+            // lower 4 bits = total number of native DTDs (detailed timing descriptors) (see section 2.2 for definition of "native format")
+            iParsedInfo->iUnderscan = ( KBit7 & aData[i] ? ETrue : EFalse );
+            iParsedInfo->iAudio = ( KBit6 & aData[i] ? ETrue : EFalse );
+            iParsedInfo->iYCbCr444 = ( KBit5 & aData[i] ? ETrue : EFalse );
+            iParsedInfo->iYCbCr422 = ( KBit4 & aData[i] ? ETrue : EFalse );
+            iParsedInfo->iTotalNumberOfNativeFormats = 0x0F & aData[i];
+            aIndex++;
+            return KErrNone; // end of common data
+            }
+        aIndex++;
+        }
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetDescriptorBlock
+//
+// ----------------------------------------------------------------------------
+//
+TEdidDescriptorBlock CCea861EdidParser::GetDescriptorBlock( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    TEdidDescriptorBlock descBlock;
+
+    descBlock.iPixelClock = GetPixelClock( aData, aIndex );
+
+    descBlock.iHorizontalAddressableVideoPixels
+        = GetHorizontalAddressableVideoPixels( aData, aIndex );
+
+    descBlock.iHorizontalBlanking = GetHorizontalBlanking( aData, aIndex );
+
+    descBlock.iVerticalAddressableVideoPixels
+        = GetVerticalAddressableVideoPixels( aData, aIndex );
+
+    descBlock.iVerticalBlanking = GetVerticalBlanking( aData, aIndex );
+
+    descBlock.iHorizontalFrontPorch = GetHorizontalFrontPorch( aData, aIndex );
+
+    descBlock.iHorizontalSyncPulse
+        = GetHorizontalSyncPulseWidth( aData, aIndex );
+
+    descBlock.iVerticalFrontPorch = GetVerticalFrontPorch( aData, aIndex );
+
+    descBlock.iVerticalSyncPulse = GetVerticalSyncPulseWidth( aData, aIndex );
+
+    descBlock.iHorizontalAddressableImageSize
+        = GetHorizontalAddressableImageSizeInMm( aData, aIndex );
+
+    descBlock.iVerticalAddressableImageSize
+        = GetVerticalAddressableImageSizeInMm( aData, aIndex );
+
+    descBlock.iHorizontalBorder = GetHorizontalBorderSize( aData, aIndex );
+
+    descBlock.iVerticalBorder = GetVerticalBorderSize( aData, aIndex );
+
+    descBlock.iInterlacedVideo = GetVideoIsInterlaced( aData, aIndex );
+
+    descBlock.iStereoSupport = GetStereoViewingSupport( aData, aIndex );
+
+    descBlock.iSyncs = GetSyncSignalDefinitions( aData, aIndex );
+
+    return descBlock;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetPixelClock
+//
+// ----------------------------------------------------------------------------
+//
+TUint16 CCea861EdidParser::GetPixelClock( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // Stored Value = Pixel clock ÷ 10,000
+    // LSB stored in byte 0 and MSB stored in byte 1
+    // 0, 1 2 Range: 10 kHz to 655.35 MHz in 10 kHz steps
+    // (00 00)h Reserved: Do not use for Detailed Timing Descriptor
+    TUint16 word1 = aData[aIndex];
+    TUint16 word2 = aData[aIndex + 1];
+
+    TUint16 pixelClock = word2; // xxxx xxxx 1010 1010
+    pixelClock = pixelClock << 8; // 1010 1010 xxxx xxxx shifted to left (MSB)
+    pixelClock += word1; // 1010 1010 0101 0101 add the LSB
+
+    aIndex += 2;
+
+    return pixelClock;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetHorizontalAddressableVideoPixels
+//
+// ----------------------------------------------------------------------------
+//
+TUint16 CCea861EdidParser::GetHorizontalAddressableVideoPixels( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #2
+    TUint16 word1 = aData[aIndex];
+    TUint16 word2 = aData[aIndex + 2];
+
+    // 12bits long, defined in 8 bits of byte 2 and upper nibble of byte 4 (4bits), range 0-4095
+    TUint16 horAddrVideo = 0;
+
+    // nullify the 4 lsb
+    // ---- ---- xxxx yyyy >> 4  = ---- ---- ---- xxxx
+    horAddrVideo = word1 >> 4;
+    // return back to original position (4)+4
+    // ---- ---- ---- xxxx << 4  = ---- xxxx 0000 0000
+    horAddrVideo = horAddrVideo << ( 4 + 4 );
+    // ---- xxxx zzzz zzzz = correct values for the 12-bit-long var
+    horAddrVideo += word2;
+
+    aIndex++; // to byte #3
+
+    return horAddrVideo;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetHorizontalBlanking
+//
+// ----------------------------------------------------------------------------
+//
+TUint16 CCea861EdidParser::GetHorizontalBlanking( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #3
+    TUint16 word1 = aData[aIndex];
+    TUint16 word2 = aData[aIndex + 1];
+
+    TUint16 horBlanking = 0;
+
+    // nullify the 4 msb
+    // ---- ---- xxxx yyyy << 12 = yyyy ---- ---- ----
+    horBlanking = word1 << 12;
+    // nullify the 4 msb
+    // yyyy ---- ---- ---- >> 4  = ---- yyyy ---- ----
+    horBlanking = horBlanking >> 4;
+    // ---- yyyy zzzz zzzz = correct values for the 12-bit-long var
+    horBlanking += word2;
+
+    aIndex += 2; // to byte #5
+
+    return horBlanking;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetVerticalAddressableVideoPixels
+// Vertical Addressable Video in lines
+//
+// ----------------------------------------------------------------------------
+//
+TUint16 CCea861EdidParser::GetVerticalAddressableVideoPixels( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #5
+    TUint16 word1 = aData[aIndex + 2];
+    TUint16 word2 = aData[aIndex];
+
+    //Upper nibble of byte 7 and the 8 bits of byte 5) - Range is 0 lines to 4095 lines
+    TUint16 vertAddrVideo = 0;
+    vertAddrVideo = word1 >> 4;
+    vertAddrVideo = vertAddrVideo << ( 4 + 4 );
+    vertAddrVideo += word2; // like before with HorAddrVideo
+
+    aIndex++; // to byte #6
+    return vertAddrVideo;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetVerticalBlanking
+//
+// ----------------------------------------------------------------------------
+//
+TUint16 CCea861EdidParser::GetVerticalBlanking( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #6
+    TUint16 word1 = aData[aIndex + 1];
+    TUint16 word2 = aData[aIndex];
+
+    // 12bits long, defined in 8 bits of byte 2 and upper nibble of byte 4 (4bits), range 0-4095
+    TUint16 vertBlanking = 0;
+
+    // nullify the 4 msb
+    // ---- ---- xxxx yyyy << 12 = yyyy ---- ---- ----
+    vertBlanking = word1 << 12;
+    // nullify the 4 msb
+    // yyyy ---- ---- ---- >> 4  = 0000 yyyy ---- ----
+    vertBlanking = vertBlanking >> 4;
+    // ---- yyyy zzzz zzzz = correct values for the 12-bit-long var
+    vertBlanking += word2;
+
+    aIndex += 2; // to byte #8
+    return vertBlanking;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetHorizontalFrontPorch
+//
+// ----------------------------------------------------------------------------
+//
+TUint16 CCea861EdidParser::GetHorizontalFrontPorch( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #8
+
+    TUint16 word1 = aData[aIndex];
+    TUint16 word2 = aData[aIndex + 3]; // 2 bits from #11
+
+    // Horizontal Front Porch in Pixels (from blanking start to start of sync) is represented by a 10 bit
+    // number (Bits 7 & 6 of byte 11 and the 8 bits of byte 8) - Range is 0 pixels to 1023 pixels.
+
+    TUint16 horFrontPorch = 0;
+
+    TUint8 bit67 = word1;
+    bit67 = ( bit67 & KBit7 ) | ( bit67 & KBit6 ); // bits 6 and 7 remain
+
+    horFrontPorch = bit67 << 2;
+    horFrontPorch += word2;
+
+    aIndex++; // to byte #9
+    return horFrontPorch;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetHorizontalSyncPulseWidth
+//
+// ----------------------------------------------------------------------------
+//
+TUint16 CCea861EdidParser::GetHorizontalSyncPulseWidth( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #9
+    TUint16 word1 = aData[aIndex];
+    TUint16 word2 = aData[aIndex + 2]; // 2 bits from #11
+
+    //Horizontal Sync Pulse Width in Pixels (from the end of the front porch to the start of the back
+    //porch) is represented by a 10 bit number (Bits 5 & 4 of byte 11 and the 8 bits of byte 9) - Range
+    //is 0 pixels to 1023 pixels.
+
+    TUint16 horSyncPulseWidth = word1;
+    horSyncPulseWidth = ( horSyncPulseWidth & KBit5 ) | ( horSyncPulseWidth
+        & KBit4 ); // only bits 5 and 4 remain
+    horSyncPulseWidth = horSyncPulseWidth << 4;
+    horSyncPulseWidth += word2;
+
+    aIndex++; // aIndex at byte #10
+
+    return horSyncPulseWidth;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetVerticalFrontPorch
+//
+// ----------------------------------------------------------------------------
+//
+TUint16 CCea861EdidParser::GetVerticalFrontPorch( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // Vertical Front Porch in Lines (from blanking start to start of sync) is represented by a 6 bit
+    // number (Bits 3 & 2 of byte 11 and the upper nibble of byte 10) - Range is 0 lines to 63 lines.
+
+    // aIndex at byte #10
+    TUint16 word1 = aData[aIndex + 1];
+    TUint16 word2 = aData[aIndex]; // 2 bits from #11
+
+    TUint16 vertFrontPorch = 0;
+
+    TUint8 bit23 = word1;
+    // bits 2 and 3 remain  0000 xx00
+    bit23 = ( bit23 & KBit3 ) | ( bit23 & KBit2 );
+
+    // 00xx 0000
+    vertFrontPorch = bit23 << 2;
+    // 00xx yyyy
+    vertFrontPorch += ( word2 >> 4 );
+
+    //Index remains at byte #10
+
+    return vertFrontPorch;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetVerticalSyncPulseWidth
+//
+// ----------------------------------------------------------------------------
+//
+TUint8 CCea861EdidParser::GetVerticalSyncPulseWidth( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // Vertical Sync Pulse Width in Lines (from the end of the front porch to the start of the back
+    // porch) is represented by a 6 bit number (Bits 1 & 0 of byte 11 and the lower nibble of byte 10 -
+    // Range is 0 lines to 63 lines.
+
+    // aIndex at byte #10
+    TUint16 word1 = aData[aIndex];
+    TUint16 word2 = aData[aIndex + 1]; // 2 bits from #11
+
+    // Vertical Sync Pulse Width in Lines (from the end of the front porch to the start of the back
+    // porch) is represented by a 6 bit number (Bits 1 & 0 of byte 11 and the lower nibble of byte 10 -
+    // Range is 0 lines to 63 lines.
+    TUint8 vertSyncPulse = 0;
+
+    // bits 1 and 0 remain   0000 00xx
+    word2 = ( word2 & KBit1 ) | ( word2 & KBit0 );
+
+    // 00xx 0000
+    vertSyncPulse = word2 << 4;
+    // only the lower nibble, %16 removes the upper nibble
+    word1 = word1 % 16;
+    // 00xx yyyy
+    vertSyncPulse += word1;
+
+    aIndex += 2; // to byte #12
+
+    return vertSyncPulse;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetHorizontalAddressableImageSizeInMm
+// Horizontal Addressable Video Image Size in mm
+//
+// ----------------------------------------------------------------------------
+//
+TUint16 CCea861EdidParser::GetHorizontalAddressableImageSizeInMm( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #12
+    TUint16 word1 = aData[aIndex + 2];
+    TUint16 word2 = aData[aIndex];
+
+    //Horizontal Addressable Video Image Size in mm is represented by a 12 bit number (Upper
+    //nibble of byte 14 and the 8 bits of byte 12) - Range is 0 mm to 4095 mm.
+
+    // first nullify 4 lsb
+    TUint16 hais = word1 >> 4;
+    // and then move back the first 4 and then again 4
+    hais = hais << ( 4 + 4 );
+    hais += word2;
+
+    aIndex++; // to byte #13
+
+    return hais;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetVerticalAddressableImageSizeInMm
+//
+// ----------------------------------------------------------------------------
+//
+TUint16 CCea861EdidParser::GetVerticalAddressableImageSizeInMm( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #13
+    TUint16 word1 = aData[aIndex + 1];
+    TUint16 word2 = aData[aIndex];
+
+    //Vertical Addressable Video Image Size in mm is represented by a 12 bit number (Lower nibble
+    //of byte 14 and the 8 bits of byte 13) - Range is 0 mm to 4095 mm.
+
+    TUint16 vais = word1;
+    // first nullify 4 msb and then move back 1 nibble
+    vais = vais << 12;
+    vais = vais >> 4;
+    vais += word2;
+
+    aIndex += 2; // to byte #15
+
+    return vais;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetHorizontalBorderSize
+//
+// ----------------------------------------------------------------------------
+//
+TUint8 CCea861EdidParser::GetHorizontalBorderSize( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #15
+    TUint16 word1 = aData[aIndex];
+
+    //Right Horizontal Border or Left Horizontal Border in Pixels is represented by an 8 bit number
+    //(the 8 bits of byte 15) - Range is 0 pixels to 255 pixels.
+
+    // the same value is used for (left and right) / (top and bottom)
+    aIndex++; // to byte #16
+    return word1;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetVerticalBorderSize
+// Top Vertical Border or Bottom Vertical Border in Lines
+//
+// ----------------------------------------------------------------------------
+//
+TUint8 CCea861EdidParser::GetVerticalBorderSize( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #16
+    TUint16 word1 = aData[aIndex];
+
+    //Top Vertical Border or Bottom Vertical Border in Lines is represented by an 8 bit number (the
+    //8 bits of byte 16) - Range is 0 lines to 255 lines.
+
+    aIndex++; // to byte #17
+    return word1;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetVideoIsInterlaced
+//
+// ----------------------------------------------------------------------------
+//
+TBool CCea861EdidParser::GetVideoIsInterlaced( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #17
+    TUint16 word1 = aData[aIndex];
+
+    // byte 17
+    //Bytes Bit Definitions Detailed Timing Definitions
+    //7 6 5 4 3 2 1 0 Signal Interface Type:
+    //0 _ _ _ _ _ _ _ Non-Interlaced (1 frame = 1 field)
+    //1 _ _ _ _ _ _ _ Interlaced (1 frame = 2 fields)
+
+    // Index remains at byte #17
+
+    return KBit7 & word1;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetStereoViewingSupport
+//
+// ----------------------------------------------------------------------------
+//
+TEdidStereoViewingSupport CCea861EdidParser::GetStereoViewingSupport( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #17
+    TUint16 word1 = aData[aIndex];
+
+    // See TEdidStereoViewingSupport enum declaration
+
+    // byte 17
+    //Bytes Bit Definitions Detailed Timing Definitions
+    //_ 6 5 _ _ _ _ 0 Stereo Viewing Support:
+    //  0 0 _ _ _ _ x Normal Display – No Stereo. The value of bit 0 is "don't care"
+    //  0 1 _ _ _ _ 0 Field sequential stereo, right image when stereo sync signal = 1
+    //  1 0 _ _ _ _ 0 Field sequential stereo, left image when stereo sync signal = 1
+    //  0 1 _ _ _ _ 1 2-way interleaved stereo, right image on even lines
+    //  1 0 _ _ _ _ 1 2-way interleaved stereo, left image on even lines
+    //  1 1 _ _ _ _ 0 4-way interleaved stereo
+    //  1 1 _ _ _ _ 1 Side-by-Side interleaved stereo
+    TUint8 bit17 = word1;
+
+    // Index remains at byte #17
+
+    if( !( ( KBit6 & bit17 ) | ( KBit5 & bit17 ) ) ) //  0 0 _ _ _ _ x Normal Display – No Stereo.
+        { //                The value of bit 0 is "don't care"
+        return ENormalDisplay;
+        }
+    else
+        {
+        if( !( KBit6 & bit17 ) && ( KBit5 & bit17 ) && !( KBit0 & bit17 ) ) //  0 1 _ _ _ _ 0 Field sequential stereo,
+            { //                right image when stereo sync signal=1
+            return EFieldSequentialStereoRightWhenStereoSyncSignal1;
+            }
+        else
+            {
+            if( ( KBit6 & bit17 ) && !( KBit5 & bit17 ) && !( KBit0 & bit17 ) ) //  1 0 _ _ _ _ 0 Field sequential stereo,
+                { //                left image when stereo sync signal=1
+                return EFieldSequentialStereoLeftWhenStereoSyncSignal1;
+                }
+            else
+                {
+                if( !( KBit6 & bit17 ) && ( KBit5 & bit17 ) && ( KBit0 & bit17 ) ) //  0 1 _ _ _ _ 1 2-way interleaved stereo,
+                    { //                right image on even lines
+                    return ETwoWayInterleavedStereoRightImageOnEvenLines;
+                    }
+                else
+                    {
+                    if( ( KBit6 & bit17 ) && !( KBit5 & bit17 ) && ( KBit0
+                        & bit17 ) )//  1 0 _ _ _ _ 1 2-way interleaved stereo,
+                        { //                left image on even lines
+                        return ETwoWayInterleavedStereoLeftImageOnEvenLines;
+                        }
+                    else
+                        {
+                        if( ( KBit6 & bit17 ) && ( KBit5 & bit17 ) && !( KBit0
+                            & bit17 ) ) //  1 1 _ _ _ _ 0 4-way interleaved stereo
+                            {
+                            return EFourWayInterleaverStereo;
+                            }
+                        else
+                            {
+                            if( ( KBit6 & bit17 ) && ( KBit5 & bit17 )
+                                && ( KBit0 & bit17 ) ) //  1 1 _ _ _ _ 1 Side-by-Side interleaved stereo
+                                {
+                                return ESideBySideInterleavedStere;
+                                }
+                            else
+                                {
+                                return EUnknownStereoViewingSupport;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetAnalogSyncSignalDefinitions
+//
+// ----------------------------------------------------------------------------
+//
+TEdidSyncSignalDefinitions CCea861EdidParser::GetSyncSignalDefinitions( const TExtDataBlock& aData,
+    TInt& aIndex ) const
+    {
+    FUNC_LOG;
+
+    // aIndex at byte #18
+    TUint8 byte17 = aData[aIndex];
+
+    // byte 17
+    // 4 3 2 1 _ Analog Sync Signal Definitions:
+    //------------------------------------------
+    // 0 0 _ _ _ Analog Composite Sync:
+    // 0 1 _ _ _ Bipolar Analog Composite Sync:
+
+    aIndex++; // advance to byte #18 finally -> this descriptor block is now finished
+
+    if( !( KBit4 & byte17 ) ) // if bit4 == 0 then this is analog display
+        {
+        return GetAnalogSyncSignalDefinitions( byte17 );
+        }
+
+    return GetDigitalSyncSignalDefinitions( byte17 );
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetAnalogSyncSignalDefinitions
+//
+// ----------------------------------------------------------------------------
+//
+TEdidSyncSignalDefinitions CCea861EdidParser::GetAnalogSyncSignalDefinitions( const TUint8 aByte17 )
+    {
+    FUNC_LOG;
+
+    // byte 17
+    // 4 3 2 1 _ Analog Sync Signal Definitions:
+    //------------------------------------------
+    // 0 0 _ _ _ Analog Composite Sync:
+    // 0 1 _ _ _ Bipolar Analog Composite Sync:
+    // 0 _ 0 _ _ ---------- Without Serrations;
+    // 0 _ 1 _ _ ---------- With Serrations (H-sync during V-sync);
+    // 0 _ _ 0 _ -------------------- Sync On Green Signal only
+    // 0 _ _ 1 _ -------------------- Sync On all three (RGB) video signals
+
+    TBool ACS = !( KBit3 & aByte17 ); // if true -> bipolar analog composite sync
+    TBool serrations = KBit2 & aByte17;
+    TBool syncOnGreen = !( KBit1 & aByte17 );
+
+    if( ACS )
+        {
+        if( !serrations )
+            {
+            if( syncOnGreen )
+                {
+                return EAnalogCompositeSyncWithoutSerrationsSyncSyncOnGreenSignalOnly;
+                }
+            else
+                {
+                return EAnalogCompositeSyncWithoutSerrationsSyncOnAllThreeVideoSignals;
+                }
+            }
+        else
+            {
+            if( syncOnGreen )
+                {
+                return EAnalogCompositeSyncWithoutSerrationsSyncSyncOnGreenSignalOnly;
+                }
+            else
+                {
+                return EAnalogCompositeSyncWithoutSerrationsSyncOnAllThreeVideoSignals;
+                }
+            }
+        }
+    else
+        {
+        if( !serrations )
+            {
+            if( syncOnGreen )
+                {
+                return EAnalogBipolarAnalogCompositeSyncWithoutSerrationsSyncSyncOnGreenSignalOnly;
+                }
+            else
+                {
+                return EAnalogBipolarAnalogCompositeSyncWithoutSerrationsSyncOnAllThreeVideoSignals;
+                }
+            }
+        else
+            {
+            if( syncOnGreen )
+                {
+                return EAnalogBipolarAnalogCompositeSyncWithSerrationsSyncSyncOnGreenSignalOnly;
+                }
+            else
+                {
+                return EAnalogBipolarAnalogCompositeSyncWithSerrationsSyncOnAllThreeVideoSignals;
+                }
+            }
+        }
+    // unreachable
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::GetDigitalSyncSignalDefinitions
+//
+// ----------------------------------------------------------------------------
+//
+TEdidSyncSignalDefinitions CCea861EdidParser::GetDigitalSyncSignalDefinitions( const TUint8 aByte17 )
+    {
+    FUNC_LOG;
+
+    //        4 3 2 1 0 bit
+    //        --------------
+    //        1 0 _ _ _ Digital Composite Sync:
+    //        1 0 0 _ _ ---------- Without Serrations;
+    //        1 0 1 _ _ ---------- With Serrations (H-sync during V-sync);
+    //        1 1 _ _ _ Digital Separate Sync:
+    //        1 1 0 _ _ ---------- Vertical Sync is Negative;
+    //        1 1 1 _ _ ---------- Vertical Sync is Positive;
+    //        1 _ _ 0 _ -------------------- Horizontal Sync is Negative (outside of V-sync)
+    //        1 _ _ 1 _ -------------------- Horizontal Sync is Positive (outside of V-sync)
+
+    TBool digComp = !( KBit3 & aByte17 ); // ETrue == digital separate sync
+    TBool bit2 = KBit2 & aByte17;
+
+    if( digComp ) // digital composite sync
+        {
+        if( !bit2 ) // without serrations
+            {
+            return EDigitalCompositeSyncWithoutSerrations;
+            }
+        else // with serrations
+            {
+            return EDigitalCompositeSyncWithSerrations;
+            }
+        } // endif  digital composite sync
+    else //        digital separate sync
+        {
+        TBool bit1 = KBit1 & aByte17;
+
+        if( !bit2 ) // vertical = neg
+            {
+            if( !bit1 )
+                { // vertical = neg, horizontal = neg
+                return EDigitalSeparateSyncVerticalSyncIsNegativeHorizontalSyncIsNegative;
+                }
+            else
+                { // vertical = neg, horizontal = pos
+                return EDigitalSeparateSyncVerticalSyncIsNegativeHorizontalSyncIsPositive;
+                }
+            }
+        else // vertical = pos
+            {
+            if( !bit1 )
+                { // vertical = pos, horizontal = neg
+                return EDigitalSeparateSyncVerticalSyncIsPositiveHorizontalSyncIsNegative;
+                }
+            else
+                { // vertical = pos, horizontal = pos
+                return EDigitalSeparateSyncVerticalSyncIsPositiveHorizontalSyncIsPositive;
+                }
+            }
+        }
+    // unreachable
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::ReadCeaDataBlockCollectionL
+//
+// ----------------------------------------------------------------------------
+//
+TInt CCea861EdidParser::ReadCeaDataBlockCollectionL( const TExtDataBlock& aData,
+    TInt& aIndex )
+    {
+    FUNC_LOG;
+
+    // bits 5-7         | bits 0-4
+    // Tag Code         | Length = total number of video bytes following this byte (L1)
+    TInt tag = 0; // video tag code
+    TInt L1 = 0; // lenght (L1)
+    if( KBit7 & aData[aIndex] )
+        {
+        tag += 4;
+        }
+    if( KBit6 & aData[aIndex] )
+        {
+        tag += 2;
+        }
+    if( KBit5 & aData[aIndex] )
+        {
+        tag += 1;
+        }
+    L1 = aData[aIndex] & 0x1F; // clear the 3 MSBits
+
+    aIndex++; // jump over the first byte
+
+    TInt auxTag = 0;
+    switch( tag )
+        {
+        case 0:
+            //reserved
+            break;
+        case 1:
+            ReadCea861ShortAudioDataBlockL( aData, aIndex, L1 );
+            break;
+        case 2:
+            ReadCea861ShortVideoDataBlockL( aData, aIndex, L1 );
+            break;
+        case 3:
+            ReadCea861VendorSpecificDataBlockL( aData, aIndex, L1 );
+            break;
+        case 4:
+            ReadCea861SpeakerAllocationDataBlock( aData, aIndex, L1 );
+            break;
+        case 5:
+            //VESA DTC Data Block
+            ReadUnknownTagCode( aData, aIndex, L1 );
+            break;
+        case 6:
+            //reserved
+            ReadUnknownTagCode( aData, aIndex, L1 );
+            break;
+        case 7:
+            //use extended tag (second byte holds the extended tag-code)
+            // (see table 43 in CEA-861 spec) (if using repeater, then these information must be re-transmitted)
+            auxTag = aData[aIndex + 1];
+            if( auxTag == 5 ) // colorimetry, see table 51, table 52 and table 53 in CEA-861-E.pdf
+                {
+                }
+            else if( auxTag == 0x07 ) // video Capability Data Block, see table 54
+                {
+                ReadVideoCapabilityDataBlockL( aData, aIndex, L1 );
+                }
+            else if( auxTag == 0x01 ) // Vendor-Specific Video Data Block, see table 56
+                {
+                }
+            else if( auxTag == 0x11 ) // Vendor-Specific Audio Data Block, see table 57
+                {
+                }
+            // TODO: these should be read as well, not just as unknown
+            ReadUnknownTagCode( aData, aIndex, L1 );
+            break;
+        default:
+            // if tag-code is unknown, we still must read through it
+            ReadUnknownTagCode( aData, aIndex, L1 );
+            break;
+        }
+
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::ReadCea861ShortAudioDataBlockL
+//
+// ----------------------------------------------------------------------------
+//
+void CCea861EdidParser::ReadCea861ShortAudioDataBlockL( const TExtDataBlock& aData,
+    TInt& aIndex,
+    const TInt8 aLen )
+    {
+    FUNC_LOG;
+
+    iAudioDataBlockSupported = ETrue;
+
+    if( !iParsedInfo->iShortAudioDescriptors ) // linked list
+        {
+        iParsedInfo->iShortAudioDescriptors
+            = new ( ELeave ) TCEA861AudioDataBlock();
+        }
+    TCEA861AudioDataBlock* cur = iParsedInfo->iShortAudioDescriptors;
+
+    while( cur->iNext != 0 )
+        {
+        cur = cur->iNext; // jump to the end
+        }
+
+    TBool first = ETrue;
+    for( int i = 0; i < aLen; i++ )
+        {
+        // read aLen-amount of short video descriptors
+
+        // first link is a special case
+        if( ( iParsedInfo->iShortAudioDescriptors == cur ) && first )
+            {
+            first = EFalse;
+            cur->iByte1 = aData[aIndex];
+            cur->iByte2 = aData[aIndex + 1];
+            cur->iByte3 = aData[aIndex + 2];
+            DetermineAudioBlockInformation( cur );
+            aIndex += 3;
+            i += 3;
+            continue;
+            }
+
+        // create new data blocks
+        cur->iNext = new ( ELeave ) TCEA861AudioDataBlock();
+        cur = cur->iNext;
+        cur->iByte1 = aData[aIndex];
+        cur->iByte2 = aData[aIndex + 1];
+        cur->iByte3 = aData[aIndex + 2];
+        cur->iNext = 0;
+
+        DetermineAudioBlockInformation( cur );
+
+        aIndex += 3;
+        i += 3;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::ReadCea861ShortVideoDataBlockL
+//
+// ----------------------------------------------------------------------------
+//
+void CCea861EdidParser::ReadCea861ShortVideoDataBlockL( const TExtDataBlock& aData,
+    TInt& aIndex,
+    const TInt8 aLen )
+    {
+    FUNC_LOG;
+
+    TBool first = ETrue;
+    iVideoDataBlockSupported = ETrue;
+    if( !iParsedInfo->iShortVideoDescriptors ) // linked list
+        {
+        iParsedInfo->iShortVideoDescriptors
+            = new ( ELeave ) TCEA861VideoDataBlock();
+        iParsedInfo->iShortVideoDescriptors->iNext = 0; // make sure there are no stray pointers
+        }
+
+    TCEA861VideoDataBlock* cur = iParsedInfo->iShortVideoDescriptors;
+    while( cur->iNext != 0 )
+        {
+        cur = cur->iNext; // jump to the end
+        first = EFalse; // there is already some links, so set first to false
+        }
+
+    for( int i = 0; i < aLen; i++ )
+        {
+
+        // read aLen-amount of short video descriptors
+
+        // first link is a special case
+        if( ( iParsedInfo->iShortVideoDescriptors == cur ) && first )
+            {
+            first = EFalse;
+            cur->iNative = KBit7 & aData[aIndex];
+            cur->iVIC = ( ~KBit7 ) & aData[aIndex]; // nullify the most signicant bit
+            cur->iNext = 0;
+            aIndex++;
+            continue;
+            }
+
+        // create new data blocks
+        cur->iNext = new ( ELeave ) TCEA861VideoDataBlock();
+        cur = cur->iNext;
+        cur->iNative = KBit7 & aData[aIndex];
+        cur->iVIC = ( ~KBit7 ) & aData[aIndex]; // nullify the most signicant bit
+        cur->iNext = 0;
+        aIndex++;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::ReadCea861VendorSpecificDataBlockL
+//
+// ----------------------------------------------------------------------------
+//
+void CCea861EdidParser::ReadCea861VendorSpecificDataBlockL( const TExtDataBlock& aData,
+    TInt& aIndex,
+    TInt8 aLen )
+    {
+    FUNC_LOG;
+
+    iVendorSpecificDataBlockSupported = ETrue;
+
+    if( !iParsedInfo->iVendorSpecificData )
+        {
+        iParsedInfo->iVendorSpecificData = new ( ELeave ) TCEA861VendorSpecificDataBlock();
+        }
+
+
+    TUint8 data1 = aData[aIndex]; // least significant byte first
+    TUint8 data2 = aData[aIndex + 1];
+    TUint8 data3 = aData[aIndex + 2];
+    aIndex += 3; // three bytes of IEEE registration identifier
+
+    iParsedInfo->iVendorSpecificData->iIEEE24bitRegistrationIdentifier = 0; // convert from LSB -> MSB
+    iParsedInfo->iVendorSpecificData->iIEEE24bitRegistrationIdentifier += data3;
+    iParsedInfo->iVendorSpecificData->iIEEE24bitRegistrationIdentifier
+        = iParsedInfo->iVendorSpecificData->iIEEE24bitRegistrationIdentifier
+            << 8;
+    iParsedInfo->iVendorSpecificData->iIEEE24bitRegistrationIdentifier += data2;
+    iParsedInfo->iVendorSpecificData->iIEEE24bitRegistrationIdentifier
+        = iParsedInfo->iVendorSpecificData->iIEEE24bitRegistrationIdentifier
+            << 8;
+    iParsedInfo->iVendorSpecificData->iIEEE24bitRegistrationIdentifier += data1;
+
+    aLen -= 3; // this is needed: Vendor specific payload length = L4-3bytes
+
+    TBool first = ETrue;
+    if( iParsedInfo->iVendorSpecificData->iVendorSpecificPayloadStart == 0 )
+        {
+        iParsedInfo->iVendorSpecificData->iVendorSpecificPayloadStart
+            = new ( ELeave ) TCEA861VendorSpecificDataBlockPayload();
+        }
+    TCEA861VendorSpecificDataBlockPayload* cur =
+        iParsedInfo->iVendorSpecificData->iVendorSpecificPayloadStart;
+    // traverse to the end of the list
+    while( cur->iNext != 0 )
+        {
+        cur = cur->iNext;
+        }
+
+    for( int i = 0; i < aLen; i++ )
+        {
+        if( ( cur == iParsedInfo->iVendorSpecificData->iVendorSpecificPayloadStart )
+            && first ) // first byte is special case
+            {
+            first = EFalse;
+            cur->iData = aData[aIndex];
+            cur->iNext = NULL;
+            aIndex++;
+            continue;
+            }
+        cur->iNext = new ( ELeave ) TCEA861VendorSpecificDataBlockPayload();
+        cur = cur->iNext;
+        cur->iData = aData[aIndex];
+        cur->iNext = 0;
+        aIndex++;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::ReadCea861SpeakerAllocationDataBlock
+//
+// ----------------------------------------------------------------------------
+//
+void CCea861EdidParser::ReadCea861SpeakerAllocationDataBlock( const TExtDataBlock& aData,
+    TInt& aIndex,
+    const TInt8 aLen )
+    {
+    FUNC_LOG;
+
+    // read the 3 bytes
+    if( aLen != 3 )
+        {
+        return;
+        }
+
+    iSpeakerAllocationDataBlockSupported = ETrue;
+
+    for( TInt i = 0; i < aLen; i++ )
+        {
+        switch( i )
+            {
+            case 0:
+                iParsedInfo->iSpeakerAllocationData.iByte1 = aData[aIndex];
+                break;
+            case 1:
+                iParsedInfo->iSpeakerAllocationData.iByte2 = aData[aIndex];
+                break;
+            case 2:
+                iParsedInfo->iSpeakerAllocationData.iByte3 = aData[aIndex];
+                break;
+            default:
+                // error
+                break;
+            }
+        aIndex++;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::ReadVideoCapabilityDataBlockL
+//
+// ----------------------------------------------------------------------------
+//
+void CCea861EdidParser::ReadVideoCapabilityDataBlockL( const TExtDataBlock& aData,
+    TInt& aIndex,
+    const TInt8 aLen )
+    {
+    FUNC_LOG;
+
+    aIndex++; // jump to the extended tag code (aLen is the length from extended tag to the end)
+
+    if( iParsedInfo->iVideoCapabilityDataBlock == 0 )
+        {
+        iParsedInfo->iVideoCapabilityDataBlock
+            = new ( ELeave ) TCEA861VideoCapabilityDataBlock();
+        }
+    TCEA861VideoCapabilityDataBlock* cur =
+        iParsedInfo->iVideoCapabilityDataBlock;
+    TBool first = ETrue;
+    while( cur->iNext != 0 )
+        {
+        first = EFalse;
+        cur = cur->iNext;
+        }
+
+    // Payload currently only contains a single byte in addition to the extended tag code. The Source should ignore such additional bytes when present.
+    for( int i = 0; i < aLen; i++ )
+        {
+        if( i == 1 )
+            {
+            if( !first ) // if this wasn't the first time we are reading to this
+                {
+                cur->iNext = new ( ELeave ) TCEA861VideoCapabilityDataBlock(); // sets Next to 0
+                cur = cur->iNext;
+                }
+            cur->iInitialized = ETrue;
+            cur->iQuantizationRange = aData[aIndex] & KBit7;
+            cur->iQuantizationRangeSelectable = aData[aIndex] & KBit6;
+            cur->iS_PT1 = aData[aIndex] & KBit5;
+            cur->iS_PT0 = aData[aIndex] & KBit4;
+            cur->iS_IT1 = aData[aIndex] & KBit3;
+            cur->iS_IT0 = aData[aIndex] & KBit2;
+            cur->iS_CE1 = aData[aIndex] & KBit1;
+            cur->iS_CE0 = aData[aIndex] & KBit0;
+            cur->iNext = 0;
+            }
+        aIndex++;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::readUnknownTagCode
+//
+// ----------------------------------------------------------------------------
+//
+void CCea861EdidParser::ReadUnknownTagCode( const TExtDataBlock& /*aData*/,
+    TInt& aIndex,
+    const TInt8 aLen )
+    {
+    FUNC_LOG;
+
+    // Skip the data. This must be done if the tag is unknown
+    aIndex += aLen;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::DetermineAudioBlockInformation
+//
+// ----------------------------------------------------------------------------
+//
+void CCea861EdidParser::DetermineAudioBlockInformation( TCEA861AudioDataBlock* aAudioBlock )
+    {
+    FUNC_LOG;
+
+    // x6543xxx we need the information in the bytes 6543
+    aAudioBlock->iAudioFormatCode = ( KBit3 | KBit2 | KBit1 | KBit0 )
+        & ( aAudioBlock->iByte1 >> 3 );
+    aAudioBlock->iSupport192kHz = ( aAudioBlock->iByte2 & KBit6 ? ETrue : EFalse );
+    aAudioBlock->iSupport176kHz = ( aAudioBlock->iByte2 & KBit5 ? ETrue : EFalse );
+    aAudioBlock->iSupport96kHz = ( aAudioBlock->iByte2 & KBit4 ? ETrue : EFalse );
+    aAudioBlock->iSupport88kHz = ( aAudioBlock->iByte2 & KBit3 ? ETrue: EFalse );
+    aAudioBlock->iSupport48kHz = ( aAudioBlock->iByte2 & KBit2 ? ETrue : EFalse );
+    aAudioBlock->iSupport44kHz = ( aAudioBlock->iByte2 & KBit1 ? ETrue : EFalse );
+    aAudioBlock->iSupport32kHz = ( aAudioBlock->iByte2 & KBit0 ? ETrue : EFalse );
+    aAudioBlock->iMaxChannels = aAudioBlock->iByte1 & 0x07; // only the 3 LSB is used
+    //TODO: 3rd byte shall be read according to the audioformatcode (see table 45 in CEA-861-E.pdf)
+    switch( aAudioBlock->iAudioFormatCode )
+        {
+        case 1:
+            aAudioBlock->iSupport24Bit = ( aAudioBlock->iByte3 & KBit2 ? ETrue : EFalse );
+            aAudioBlock->iSupport20Bit = ( aAudioBlock->iByte3 & KBit1 ? ETrue : EFalse );
+            aAudioBlock->iSupport16Bit = ( aAudioBlock->iByte3 & KBit0 ? ETrue : EFalse );
+            break;
+        case 2: //cases 2-8
+        case 3:
+        case 4:
+        case 5:
+        case 6:
+        case 7:
+        case 8:
+            aAudioBlock->iMaxBitrate = aAudioBlock->iByte3 * 8;
+            break;
+        case 9: // cases 9-13
+        case 10:
+        case 11:
+        case 12:
+        case 13:
+            // byte3 is Audio format code dependent value
+            break;
+        case 14:
+            // byte3 bits 0,1,2 is profile. bits 3-7 are reserved.
+            break;
+        case 15: // bits 7-3 = audio format code extension, bits 2-0
+            aAudioBlock->iAudioFormatCodeExtension = aAudioBlock->iByte3 >> 3;
+            break;
+        default:
+            // error
+            break;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::LatencyFieldsPresent
+//
+// ----------------------------------------------------------------------------
+//
+TBool CCea861EdidParser::LatencyFieldsPresent( TUint8 aByte ) const
+    {
+    FUNC_LOG;
+    
+    TBool present = EFalse;
+    
+    // Latency_Fields_Preset bit is bit6 (01000000) in the aByte
+    if( aByte & 0x40 )
+        {
+        present = ETrue;
+        }
+    return present;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::InterlacedLatencyFieldsPresent
+//
+// ----------------------------------------------------------------------------
+//
+TBool CCea861EdidParser::InterlacedLatencyFieldsPresent( TUint8 aByte ) const
+    {
+    FUNC_LOG;
+
+    TBool present = EFalse;
+    
+    // Latency_Fields_Preset bit is bit7 (10000000) in the aByte
+    if( aByte & 0x80 )
+        {
+        present = ETrue;
+        }
+    return present;
+    }
+
+// ----------------------------------------------------------------------------
+// CCea861EdidParser::InterlacedLatencyFieldsPresent
+//
+// ----------------------------------------------------------------------------
+//
+TUint8 CCea861EdidParser::LatencyInMs( TUint8 aByte ) const
+    {
+    FUNC_LOG;
+    
+    TUint8 latency = 0;
+    if( aByte > 0 && aByte <= 251 )
+        {
+        latency = ( aByte - 1 ) * 2;
+        }
+    
+    return latency;
+    }
+
+// End of file