【问题标题】:QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka color formatQOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka 颜色格式
【发布时间】:2012-04-08 01:33:56
【问题描述】:

全部

有人知道QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka格式的详细信息,它是qcom 7x30 h/w解码器的输出格式,这种颜色格式的数据是如何存储的?谢谢

【问题讨论】:

    标签: colors yuv


    【解决方案1】:

    这是我对此的研究,关于 QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka 转换为 YUV420Planar (I420)。至于QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka格式,可以参考($your_android_native_sdk_dir)/WORKING_DIRECTORY/hardware/qcom/media/mm-core/inc/QOMX_IVCommonExtensions.h源码。此函数可能理想地支持通用分辨率,但是我只测试 CIF 大小,因为给定源输入不可用。当然,您可以将其他尺寸数据伪造为给定的输入。如果您正在处理此问题,希望对您有所帮助。 根据我的 CIF 测试,我看到颜色是正确的。代码很长,大约 390 行,很重。包括步骤:构造yTileToMb、uvTileToMb,然后按如下方式转换y和u/v。

    ///////////////////////////////////////////////////////////////////////
    /**
    * Enumeration defining the extended uncompressed image/video
    * formats.
    *
    * ENUMS:
    *  YVU420PackedSemiPlanar       : Buffer containing all Y, and then V and U 
    *                                 interleaved.
    *  YVU420PackedSemiPlanar32m4ka : YUV planar format, similar to the 
    *                                 YVU420PackedSemiPlanar format, but with the
    *                                 following restrictions:
    *
    *                                 1. The width and height of both plane must 
    *                                 be a multiple of 32 texels.
    *
    *                                 2. The base address of both planes must be 
    *                                 aligned to a 4kB boundary.
    * 
    *  YUV420PackedSemiPlanar16m2ka : YUV planar format, similar to the
    *                                 YUV420PackedSemiPlanar format, but with the
    *                                 following restrictions:
    *
    *                                 1. The width of the luma plane must be a
    *                                 multiple of 16 pixels.
    *
    *                                 2. The address of both planes must be 
    *                                 aligned to a 2kB boundary.
    * 
    *  YUV420PackedSemiPlanar64x32Tile2m8ka : YUV planar format, similar to the 
    *                                 YUV420PackedSemiPlanar format, but with the
    *                                 following restrictions:
    *
    *                                 1. The data is laid out in a 4x2 MB tiling 
    *                                 memory structure
    *
    *                                 2. The width of each plane is a multiple of
    *                                 2 4x2 MB tiles.
    *
    *                                 3. The height of each plan is a multiple of
    *                                 a 4x2 MB tile.
    *
    *                                 4. The base address of both planes must be 
    *                                 aligned to an 8kB boundary.
    *
    *                                 5. The tiles are scanned in the order 
    *                                 defined in the MFCV5.1 User's Manual.
    *
    *                                                                       i.e, CIF size in pysical location
    *
    *                                                                       Luma order(4x2 MB = 64x32 pix): 54 tiles:
    *                                                                       0  1  6  7  8  9
    *                                                                       2  3  4  5  10 11
    *                                                                       12 13 18 19 20 21
    *                                                                       14 15 16 17 22 23
    *                                                                       24 25 30 31 32 33
    *                                                                       26 27 28 29 34 35
    *                                                                       36 37 42 43 44 45
    *                                                                       38 39 40 41 46 47
    *                                                                       48 49 50 51 52 53
    *                                                                       MBs in a y tile:
    *                                                                       0  1  2  3
    *                                                                       22 23 24 25
    *                                                                       Chromas order(64x32 pix):
    *                                                                       0  1  6  7  8  9
    *                                                                       2  3  4  5  10 11
    *                                                                       12 13 18 19 20 21
    *                                                                       14 15 16 17 22 23
    *                                                                       24 25 26 27 28 29
    *                                                                       MBs in a uv tile:
    *                                                                       0  1  2  3
    *                                                                       22 23 24 25
    *                                                                       44 45 46 47
    *                                                                       66 67 68 69
    *
    */
    
    // YUV420PackedSemiPlanar64x32Tile2m8ka,    // 12 bit, yyyyyyyy vuvu
    // YUV420Planar, 12 bit, yyyyyyyy uu vv
    #pragma pack(1)
    typedef enum {
        Scan_Init       = 0,
        Scan_Hor,
        Scan_VerDown,
        Scan_VerUp
    } ScanMode;
    typedef struct{
        uint16_t    startMbIndex;
        uint8_t     numMBs;
    //  bool        lastTileInHor;
        bool        lastTileInVer;
    } MbGroup;
    #pragma pack()
    
    #define ALIGN_B(x,a)        (((x)+(a)-1) &(~((a)-1)))
    #define MAX_RESOLUTION_X    1920    // 4096
    #define MAX_RESOLUTION_Y    1088    // 3072
    #define MAX_TILES_NUM       (((MAX_RESOLUTION_X+63)>>6) * ((MAX_RESOLUTION_Y+31)>>5))
    
    int32_t ToI420::YUV420PackedSemiPlanar64x32Tile2m8kaToYUV420Planar( uint8_t* src, uint8_t* dst_y, uint8_t* dst_u, uint8_t* dst_v,
                const int32_t width, const int32_t height,
                const int32_t stride_y, const int32_t stride_u, const int32_t stride_v )
    {
        const int32_t srcStrideY    = ALIGN_B( width, 128 );
        const int32_t srcHeightY    = ALIGN_B( height, 32 );
        const int32_t srcStrideUV   = srcStrideY;   // v/u interlaced
        const int32_t srcHeightUV   = ALIGN_B( (height>>1), 32 );
        const int32_t srcSizeY      = ALIGN_B( (srcStrideY * srcHeightY), 8192 );
        const int32_t srcSizeUV     = ALIGN_B( (srcStrideUV * srcHeightUV), 8192 );
        uint8_t* src_y              = src;
        uint8_t* src_uv             = src_y + srcSizeY;
    
        const int32_t wTiles        = (width+63)>>6;
        const int32_t hTilesY       = (height+31)>>5;
        const int32_t hTilesUV      = (height/2+31)>>5;
        const int32_t numTilesY     = wTiles*hTilesY;
        const int32_t numTilesUV    = wTiles*hTilesUV; 
        const int32_t wMacroblocks  = (width+15)>>4;
        const int32_t hMacroblocks  = (height+15)>>4;
        int32_t numMbInTile         = 4*2;  // y: 4*2; uv: 4*4
        const int32_t mbOffsetTileHor       = 4;
        int32_t mbOffsetTileVer             = (wMacroblocks<<1);    // y: (wMacroblocks<<1); uv: (wMacroblocks<<2)  
        MbGroup yTileToMb[MAX_TILES_NUM]    = {0};  // each Tile index storing according MB index
        MbGroup uvTileToMb[MAX_TILES_NUM]   = {0};  // each Tile index storing according MB index
        assert( numTilesY <= MAX_TILES_NUM && numTilesUV <= MAX_TILES_NUM );
        int32_t availableTilesY             = numTilesY;
        int32_t availableTilesUV            = numTilesUV;
        const int32_t numTilesYPerScanUnit  = (wTiles<<1);
        int32_t tileIndex                   = 0;
        ScanMode preMode                    = Scan_Init;
        ScanMode curMode                    = Scan_Hor;
        int32_t scanedTiles                 = 0;
        int32_t hMbMultiple                 = 0;
        int32_t cntScanTimesInPeriod        = 0;    // maximal scan times is up to 4
        int32_t cnt1stLineTiles             = 0;
        int32_t cnt2ndLineTiles             = 0;
        uint16_t mbPosition                 = 0;
        uint16_t lastMbIdx                  = mbPosition;
        uint16_t firstMbIdxUnit             = mbPosition;
        bool noEnoughMbInTile               = false;    
    
        // construct yTileToMb table
        while( availableTilesY > 0 ){       
            if ( availableTilesY >= numTilesYPerScanUnit ){         
                preMode                 = Scan_Init;
                curMode                 = Scan_Hor;
                lastMbIdx               = mbPosition;
                firstMbIdxUnit          = mbPosition;
                cntScanTimesInPeriod    = 0;    // maximal scan times is up to 4
                cnt1stLineTiles         = 0;
                cnt2ndLineTiles         = 0;
                noEnoughMbInTile        = false;
                scanedTiles             = 0;
    
                while ( scanedTiles < numTilesYPerScanUnit ){               
                    if ( (tileIndex & 3) == 0 ){
                        firstMbIdxUnit = mbPosition;
                    }
                    noEnoughMbInTile = false;
                    if ( curMode == Scan_Hor ){
                        if ( (preMode == Scan_VerUp && cnt1stLineTiles+1>= wTiles) || 
                             (preMode == Scan_VerDown && cnt2ndLineTiles+1>= wTiles) ){
                                 noEnoughMbInTile = (ALIGN_B(width, 16) < srcStrideY);
    //                           yTileToMb[tileIndex].lastTileInHor = true;
                        }
                        yTileToMb[tileIndex].startMbIndex   = mbPosition;
                        yTileToMb[tileIndex].numMBs         = noEnoughMbInTile ? ((4-((srcStrideY-ALIGN_B(width,16))>>4))<<1) : numMbInTile;
                        ++ tileIndex;                   
                        ++ cntScanTimesInPeriod;
                        if ( noEnoughMbInTile && cntScanTimesInPeriod  == 1){
                            if ( preMode == Scan_VerDown ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerUp;
                                ++ cnt2ndLineTiles;
                                mbPosition = firstMbIdxUnit - mbOffsetTileVer;
                            }else if ( preMode == Scan_VerUp ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerDown;
                                ++ cnt1stLineTiles;
                                mbPosition = firstMbIdxUnit + mbOffsetTileVer;
                            }
                        }else if ( cntScanTimesInPeriod == 2 ){
                            if ( preMode == Scan_Init || preMode == Scan_VerUp ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerDown;
                                ++ cnt1stLineTiles;
                                mbPosition = firstMbIdxUnit + mbOffsetTileVer;
                            }else if ( preMode == Scan_VerDown ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerUp;
                                ++ cnt2ndLineTiles;
                                mbPosition = firstMbIdxUnit - mbOffsetTileVer;
                            }
                        }else if ( cntScanTimesInPeriod == 4 ){                     
                            if ( preMode == Scan_VerDown ){
                                ++ cnt2ndLineTiles;
                                mbPosition += mbOffsetTileHor;
                            }else if ( preMode == Scan_VerUp ){
                                ++ cnt1stLineTiles;
                                mbPosition += mbOffsetTileHor;
                            }
                        }else{
                            if ( preMode == Scan_Init ){
                                ++ cnt1stLineTiles;
                            }else if ( preMode == Scan_VerDown ){
                                ++ cnt2ndLineTiles;
                            }else if ( preMode == Scan_VerUp ){
                                ++ cnt1stLineTiles;
                            }
                            if ( cnt2ndLineTiles >= wTiles && preMode == Scan_VerDown ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerUp;                           
                                mbPosition = firstMbIdxUnit - mbOffsetTileVer;
                            }else if ( cnt1stLineTiles >= wTiles && preMode == Scan_VerUp ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerDown;                         
                                mbPosition = firstMbIdxUnit + mbOffsetTileVer;
                            }else{
                                mbPosition += mbOffsetTileHor;
                            }
                        }
                    }else if ( curMode == Scan_VerUp ){
                        if ( cnt1stLineTiles+1 >= wTiles ){
                            noEnoughMbInTile = (ALIGN_B(width, 16) < srcStrideY);
    //                      yTileToMb[tileIndex].lastTileInHor  = true;
                        }
                        yTileToMb[tileIndex].startMbIndex= mbPosition;
                        yTileToMb[tileIndex].numMBs     = noEnoughMbInTile ? ((4-((srcStrideY-ALIGN_B(width,16))>>4))<<1) : numMbInTile;
                        ++ tileIndex;
                        mbPosition += mbOffsetTileHor;
                        ++ cntScanTimesInPeriod;
                        ++ cnt1stLineTiles;
                        preMode = curMode;  // scan mode change need upate preMode
                        curMode = Scan_Hor;
                    }else if ( curMode == Scan_VerDown ){
                        if ( cnt2ndLineTiles+1 >= wTiles ){
                            noEnoughMbInTile = (ALIGN_B(width, 16) < srcStrideY);
    //                      yTileToMb[tileIndex].lastTileInHor  = true;
                        }
                        yTileToMb[tileIndex].startMbIndex= mbPosition;
                        yTileToMb[tileIndex].numMBs     = noEnoughMbInTile ? ((4-((srcStrideY-ALIGN_B(width,16))>>4))<<1) : numMbInTile;
                        ++ tileIndex;
                        mbPosition += mbOffsetTileHor;
                        ++ cntScanTimesInPeriod;
                        ++ cnt2ndLineTiles;
                        preMode = curMode;  // scan mode change need upate preMode
                        curMode = Scan_Hor;
                    }
                    cntScanTimesInPeriod &= 0x03;
                    ++ scanedTiles;
                }
                mbPosition = lastMbIdx + (mbOffsetTileVer<<1);
                availableTilesY -= numTilesYPerScanUnit;
            }else{
                scanedTiles = 0;
                hMbMultiple = hMacroblocks - (tileIndex/wTiles)*2;
                noEnoughMbInTile = false;
                while ( scanedTiles < wTiles ){
                    yTileToMb[tileIndex].startMbIndex = mbPosition;
                    yTileToMb[tileIndex].lastTileInVer= true;
                    if ( scanedTiles+1 == wTiles ){
                        noEnoughMbInTile = (ALIGN_B(width, 16) < srcStrideY);
    //                  yTileToMb[tileIndex].lastTileInHor  = true;
                    }
                    yTileToMb[tileIndex].numMBs = noEnoughMbInTile ? ((4-((srcStrideY-ALIGN_B(width,16))>>4))*hMbMultiple) : (4*hMbMultiple);
                    ++ tileIndex;
                    mbPosition += mbOffsetTileHor;
                    ++ scanedTiles;
                }
                availableTilesY -= wTiles;
            }
        }
    
        numMbInTile = 4*4;  
        mbOffsetTileVer = (wMacroblocks<<2);
        mbPosition = 0;
        tileIndex = 0;
        // construct uvTileToMb table
        while( availableTilesUV > 0 ){      
            if ( availableTilesUV >= numTilesYPerScanUnit ){            
                preMode             = Scan_Init;
                curMode             = Scan_Hor;
                lastMbIdx           = mbPosition;
                firstMbIdxUnit      = mbPosition;
                cntScanTimesInPeriod= 0;    // maximal scan times is up to 4
                cnt1stLineTiles     = 0;
                cnt2ndLineTiles     = 0;
                noEnoughMbInTile    = false;
                scanedTiles         = 0;
    
                while ( scanedTiles < numTilesYPerScanUnit ){               
                    if ( (tileIndex & 3) == 0 ){
                        firstMbIdxUnit = mbPosition;
                    }
                    noEnoughMbInTile = false;
                    if ( curMode == Scan_Hor ){
                        if ( (preMode == Scan_VerUp && cnt1stLineTiles+1>= wTiles) || 
                             (preMode == Scan_VerDown && cnt2ndLineTiles+1>= wTiles) ){
                                 noEnoughMbInTile = (ALIGN_B(width, 16) < srcStrideY);
    //                           uvTileToMb[tileIndex].lastTileInHor    = true;
                        }
                        uvTileToMb[tileIndex].startMbIndex  = mbPosition;
                        uvTileToMb[tileIndex].numMBs        = noEnoughMbInTile ? ((4-((srcStrideY-ALIGN_B(width,16))>>4))<<2) : numMbInTile;
                        ++ tileIndex;                   
                        ++ cntScanTimesInPeriod;
                        if ( noEnoughMbInTile && cntScanTimesInPeriod  == 1){
                            if ( preMode == Scan_VerDown ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerUp;
                                ++ cnt2ndLineTiles;
                                mbPosition = firstMbIdxUnit - mbOffsetTileVer;
                            }else if ( preMode == Scan_VerUp ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerDown;
                                ++ cnt1stLineTiles;
                                mbPosition = firstMbIdxUnit + mbOffsetTileVer;
                            }
                        }else if ( cntScanTimesInPeriod == 2 ){
                            if ( preMode == Scan_Init || preMode == Scan_VerUp ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerDown;
                                ++ cnt1stLineTiles;
                                mbPosition = firstMbIdxUnit + mbOffsetTileVer;
                            }else if ( preMode == Scan_VerDown ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerUp;
                                ++ cnt2ndLineTiles;
                                mbPosition = firstMbIdxUnit - mbOffsetTileVer;
                            }
                        }else if ( cntScanTimesInPeriod == 4 ){                     
                            if ( preMode == Scan_VerDown ){
                                ++ cnt2ndLineTiles;
                                mbPosition += mbOffsetTileHor;
                            }else if ( preMode == Scan_VerUp ){
                                ++ cnt1stLineTiles;
                                mbPosition += mbOffsetTileHor;
                            }
                        }else{
                            if ( preMode == Scan_Init ){
                                ++ cnt1stLineTiles;
                            }else if ( preMode == Scan_VerDown ){
                                ++ cnt2ndLineTiles;
                            }else if ( preMode == Scan_VerUp ){
                                ++ cnt1stLineTiles;
                            }
                            if ( cnt2ndLineTiles >= wTiles && preMode == Scan_VerDown ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerUp;                           
                                mbPosition = firstMbIdxUnit - mbOffsetTileVer;
                            }else if ( cnt1stLineTiles >= wTiles && preMode == Scan_VerUp ){
                                preMode = curMode;  // scan mode change need upate preMode
                                curMode = Scan_VerDown;                         
                                mbPosition = firstMbIdxUnit + mbOffsetTileVer;
                            }else{
                                mbPosition += mbOffsetTileHor;
                            }
                        }
                    }else if ( curMode == Scan_VerUp ){
                        if ( cnt1stLineTiles+1 >= wTiles ){
                            noEnoughMbInTile = (ALIGN_B(width, 16) < srcStrideY);
    //                      uvTileToMb[tileIndex].lastTileInHor = true;
                        }
                        uvTileToMb[tileIndex].startMbIndex  = mbPosition;
                        uvTileToMb[tileIndex].numMBs        = noEnoughMbInTile ? ((4-((srcStrideY-ALIGN_B(width,16))>>4))<<2) : numMbInTile;
                        ++ tileIndex;
                        mbPosition += mbOffsetTileHor;
                        ++ cntScanTimesInPeriod;
                        ++ cnt1stLineTiles;
                        preMode = curMode;  // scan mode change need upate preMode
                        curMode = Scan_Hor;
                    }else if ( curMode == Scan_VerDown ){
                        if ( cnt2ndLineTiles+1 >= wTiles ){
                            noEnoughMbInTile = (ALIGN_B(width, 16) < srcStrideY);
    //                      uvTileToMb[tileIndex].lastTileInHor = true;
                        }
                        uvTileToMb[tileIndex].startMbIndex  = mbPosition;
                        uvTileToMb[tileIndex].numMBs        = noEnoughMbInTile ? ((4-((srcStrideY-ALIGN_B(width,16))>>4))<<2) : numMbInTile;
                        ++ tileIndex;
                        mbPosition += mbOffsetTileHor;
                        ++ cntScanTimesInPeriod;
                        ++ cnt2ndLineTiles;
                        preMode = curMode;  // scan mode change need upate preMode
                        curMode = Scan_Hor;
                    }
                    cntScanTimesInPeriod &= 0x03;
                    ++ scanedTiles;
                }
                mbPosition = lastMbIdx + (mbOffsetTileVer<<1);
                availableTilesUV -= numTilesYPerScanUnit;
            }else{
                scanedTiles = 0;
                hMbMultiple = hMacroblocks - (tileIndex/wTiles)*4;
                noEnoughMbInTile = false;
                while ( scanedTiles < wTiles ){
                    uvTileToMb[tileIndex].startMbIndex = mbPosition;
                    uvTileToMb[tileIndex].lastTileInVer = true;
                    if ( scanedTiles+1 == wTiles ){
                        noEnoughMbInTile = (ALIGN_B(width, 16) < srcStrideY);
    //                  uvTileToMb[tileIndex].lastTileInHor = true;
                    }
                    uvTileToMb[tileIndex].numMBs    = noEnoughMbInTile ? ((4-((srcStrideY-ALIGN_B(width,16))>>4))*hMbMultiple) : (4*hMbMultiple);
                    ++ tileIndex;
                    mbPosition += mbOffsetTileHor;
                    ++ scanedTiles;
                }
                availableTilesUV -= wTiles;
            }
        }
    
        uint8_t* py     = src_y;    
        tileIndex = 0;
        // converting luma componet with yTileToMb
        while ( tileIndex < numTilesY ){
            uint16_t startMbIndex = yTileToMb[tileIndex].startMbIndex;
            const int32_t startMbX = (startMbIndex % wMacroblocks);
            const int32_t startMbY = (startMbIndex / wMacroblocks);
    
            int32_t mb_x = startMbX;
            int32_t mb_y = startMbY;
            const int32_t cntMbLines = yTileToMb[tileIndex].lastTileInVer ? (hMacroblocks - (tileIndex/wTiles)*2) : 2;      
            const int32_t numMbPerLine = yTileToMb[tileIndex].numMBs / cntMbLines;
            const int32_t sizePixelLine = (numMbPerLine << 4);
            int32_t mbLine = 0;
            while ( mbLine < cntMbLines ){
                assert( mb_y < hMacroblocks && mb_x < wMacroblocks );
                const int32_t dstOffsetY = (mb_y * stride_y + mb_x)<<4;
                int32_t _l = 0;
                // luma
                while( _l < 16 ){
                    memcpy( dst_y + dstOffsetY + _l * stride_y, py, sizePixelLine );
                    py += 64; // eliminate padding (64-sizePixelLine)
                    ++ _l;
                }
                mb_x = startMbX;
                ++ mb_y;
                ++ mbLine;
            }       
            ++ tileIndex;
        }
    
        uint8_t* puv    = src_uv;
        tileIndex = 0;
        // convering cb/cr componets with uvTileToMb
        while ( tileIndex < numTilesUV ){
            uint16_t startMbIndex = uvTileToMb[tileIndex].startMbIndex;
            const int32_t startMbX = (startMbIndex % wMacroblocks);
            const int32_t startMbY = (startMbIndex / wMacroblocks);
    
            int32_t mb_x = startMbX;
            int32_t mb_y = startMbY;
            const int32_t cntMbLines = uvTileToMb[tileIndex].lastTileInVer ? (hMacroblocks - (tileIndex/wTiles)*4) : 4;
            const int32_t numMbPerLine = uvTileToMb[tileIndex].numMBs / cntMbLines;     
            int32_t mbLine = 0;
            while ( mbLine < cntMbLines ){
                assert( mb_y < hMacroblocks && mb_x < wMacroblocks );           
                // cb/cr
                int32_t mbIndex = 0;
                while ( mbIndex < numMbPerLine ){
                    assert( mb_y < hMacroblocks && mb_x < wMacroblocks );
                    const int32_t dstOffsetUV = (mb_y * stride_u + mb_x)<<3;            
                    int32_t _l = 0;
                    while( _l < 8 ){
                        const int32_t _offset = dstOffsetUV + _l * stride_u;
                        uint8_t* _u = dst_u + _offset;
                        uint8_t* _v = dst_v + _offset;
                        uint8_t* _src_vu = puv+(mbIndex<<4)+(_l<<6);
                        int32_t _interlace = 0;
                        for ( int32_t ichroma = 0; ichroma < 8; ++ichroma ){
                            _u[ichroma] = _src_vu[_interlace++];
                            _v[ichroma] = _src_vu[_interlace++];
                        }
                        ++ _l;
                    }
                    ++ mb_x;
                    ++ mbIndex;
                }
                puv += 64*8;
                mb_x = startMbX;
                ++ mb_y;
                ++ mbLine;
            }
            if ( cntMbLines < 4 ){
                puv += 64*(4-cntMbLines)*8;
            }
            ++ tileIndex;
        }
    
        return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////
    

    【讨论】:

    • 请编辑您的答案并格式化代码以使其可读
    • 这个函数有问题。我正在解码 720p,它在交错 uv 瓦片的最后一个循环中崩溃(行 _v[ichroma] = _src_vu[_interlace++]; 崩溃)。顺便说一句,uv是交错的,不是交错的,错误的措辞只会令人困惑。
    • 它几乎完成了这项工作。当我在最后一个循环中添加手动检查以防止无效的内存访问 (if(_u + 8 &lt;= dst_u + width * height / 4){ ... }) 时,它停止崩溃,正如预期的那样,解码图像的最后 16 行像素不正确。其中一些看起来像错误的图块放置在错误的位置,另一些看起来像黑色方块(这些图块没有被解码)。
    • 看起来最后一行UV-tiles仍然以这种zig-zag顺序解码,而它们实际上是一个接一个地定位,就像函数前的注释提到最后一个UV的布局一样一排瓷砖。
    • @Pavel,感谢您的评论。我们确实需要准确地关注图片/平铺边界,正如我声明的那样,它可能不支持其他尺寸,并且仅使用 CIF 尺寸进行了测试。所以关于其他大小的转换,不能保证它的正确性,但至少基本的程序逻辑是有的。那么你有关于其他分辨率大小支持的任何更新吗?我几乎无法弄清楚交错和交错之间的区别,“int _interlace = 0;”只是一个变量,对吧?
    【解决方案2】:

    顾名思义,数据被打包成 64x32 像素的“图块”。

    如果将解码后的图片写入兼容的硬件表面,则无需知道像素格式。

    至少对于某些视频宽度,我已经对格式进行了逆向工程(目前仅适用于 Luma)。 但是,我(尚)不知道色度样本的布局方式,而且下面的代码仍然存在问题。

    void CopyOmxPicture( decoder_t *p_dec, picture_t *p_pic,
                     OMX_BUFFERHEADERTYPE *p_header, int i_slice_height )
    {
    decoder_sys_t *p_sys = p_dec->p_sys;
    int i_src_stride;
    int i_plane, i_width, i_line;
    uint8_t *p_dst, *p_src, *p_dst2;
    
    i_src_stride  = p_sys->out.i_frame_stride;
    p_src = p_header->pBuffer + p_header->nOffset;
    
    if( p_dec->p_sys->out.definition.format.video.eColorFormat == QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka )
    {
        uint8_t *to = p_pic->p[0].p_pixels;
        int w = p_pic->p[0].i_visible_pitch;
        int h = p_pic->p[0].i_visible_lines;
        int pitch = p_pic->p[0].i_pitch;
    
        msg_Dbg(p_dec, "stride %d pitch %d w %d h %d", i_src_stride, pitch, w, h);
    
        //copy luma plane
        const int tsz = 64*32;
        int wtiles = (w + 63) / 64; // number of tiles in horizontal direction
        int htiles = (h + 31) / 32; // number of tiles in   vertical direction
    
        int tile = 0; // FIXME : order differs for other streams
    
        int tiles_max = 2 * wtiles;
        uint8_t order[tiles_max];
        order[0] = 0;
        order[1] = 1;
    
        uint8_t done[tiles_max];
        memset(done, 0, tiles_max);
        done[0] = done[1] = 1;
    
        int j = 2 + 4;
        for (int i = 2; i < tiles_max;) {
            while(done[j]) { j++; j%=tiles_max; }
            done[j] = 1;
            order[i++] = j++; j%= tiles_max;
            while(done[j]) { j++; j%=tiles_max; }
            done[j] = 1;
            order[i++] = j++; j%= tiles_max;
            if (j == 0)
                continue;
            if (i == tiles_max)
                break;
            while(done[j]) { j++; j%=tiles_max; }
            done[j] = 1;
            order[i++] = j++; j%= tiles_max;
            while(done[j]) { j++; j%=tiles_max; }
            done[j] = 1;
            order[i++] = j++;
            j += 4;
            j%= tiles_max;
        }
    #if 0
        static const uint8_t order[] = { 0, 1, 6, 7, 2, 3, 4, 5 };
        static const uint8_t order[] = { 0, 1,
            6,  7,  8,  9,
            14, 15, 16, 17,
            22, 23, 24, 25,
            2,  3,  4,  5 ,
            10, 11, 12, 13,
            18, 19, 20, 21,
            26, 27,
        };
    #endif
        i_src_stride += 127; i_src_stride &= ~127;
        //int width_align = tsz * (wtiles & 1); // width is aligned on 128 pixels
        int width_align = i_src_stride - ((wtiles + 1) & ~1) * 64;
        int soff = 0;
        for (int i = 0; i < htiles; i++) { // top to bottom
            int lines = 32;
            if ((i == htiles - 1) && (h & 31))
                lines = h & 31;
            for (int j = 0; j < wtiles; j++) { // left to right
                //copy one tile
                int tile_pitch = 64;
                if ((j == wtiles-1) && (w & 63))
                    tile_pitch = w & 63;
                int doff = pitch * i * 32 + j * 64;
                for (int l = 0; l < lines; l++) {
                    memcpy(&to[doff + l * pitch],
                        &p_src[soff + 64 * 32 * order[tile % tiles_max] + l * 64],
                        tile_pitch);
                }
                if ((++tile % tiles_max) == 0) {
                    soff += tiles_max * 64 * 32;
                }
            }
            p_src += width_align;
        }
    
        // black out chroma
        for (int i = 1; i < p_pic->i_planes; i++)
            memset(p_pic->p[i].p_pixels, 0x80,
                    p_pic->p[i].i_pitch * p_pic->p[i].i_visible_lines);
    
    #if 1 //dump
    char mask[32];
    static int x = 0;
    sprintf(mask, "/sdcard/yuv/out%dx%dxp%d-%.3d.yuv", w, h, pitch, ++x);
    if ((x & 15) == 0) {
        FILE *f = fopen(mask, "w");
        if ((f = fopen(mask, "w"))) {
    #if 1
            //int w = (p_pic->format.i_width + 127) & ~127;
            //int h = (p_pic->format.i_height + 31) & ~31;
            //size_t s = (w * h + 8191) & ~8191;
            size_t s = p_header->nFilledLen;
            fwrite(p_src, s, 1, f);
    #else
            fwrite(to, pitch*h*3 / 2, 1, f);
    #endif
            fclose(f);
        }
    }
    #endif
    
    }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-07-24
      • 1970-01-01
      • 1970-01-01
      • 2013-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-08
      相关资源
      最近更新 更多