轉換dvd 字幕縮小改進(thinkvd開發日誌)

先看視頻轉換320x240的效果比較圖:


採用的是:Two Pass Scaling using Filters圖片縮放算法
http://www.codeproject.com/KB/graphics/2_pass_scaling.aspx
把它改到mingw c語言下,用gcc編譯時遇到了許多問題,開始總出現異常,儘管在vc下測試是正常的。
目前還存在字幕顯示有點模糊,縮小情況下不能調整字幕顏色了,這個與視頻合併時有關,合併前字幕截圖是正常的。
由於字幕顏色格式採用的是rgba,而轉換出來的視頻顏色格式採用的可能是其它格式,如YUV420P, YV12等,
如何有效地轉換成一致,這個暫時不太清楚,儘管可用sws_scale轉換,但效果如何有待確認。
編譯異常主要遇到的情況:
1。聲明變量類型分配空間大小問題。由於原來用的是c++中的new,不用考慮int8, int32等大小,但用malloc則需要。
2。由於vc下有采用的變量類型在c語言下可能沒有,需要自己定義並替換原來的。
3。語法問題,如for (int i=0; i<10; i++){....}, i在後面就不能直接用了等。


有關Pass Scaling源代碼,裏面函數Filter,其實就是它原來的CBilinearFilter, 把原來的class全部改成了function
Pass Scaling的設計思路還是相當不錯的.
#ifndef _2_PASS_SCALE_H_
#define _2_PASS_SCALE_H_

#include <math.h>

typedef struct
{
   double *Weights;  // Normalized weights of neighboring pixels
   int Left,Right;   // Bounds of source pixels window
} ContributionType;  // Contirbution information for a single pixel

typedef struct
{
   ContributionType *ContribRow; // Row (or column) of contribution weights
   UINT WindowSize,              // Filter window size (of affecting source pixels)
        LineLength;              // Length of line (no. or rows / cols)
} LineContribType;               // Contribution information for an entire line (row or column)

COLORREF * AllocAndScale ( 
    COLORREF   *pOrigImage,
    UINT        uOrigWidth,
    UINT        uOrigHeight,
    UINT        uNewWidth,
    UINT        uNewHeight);

COLORREF * Scale ( 
    COLORREF   *pOrigImage,
    UINT        uOrigWidth,
    UINT        uOrigHeight,
    COLORREF   *pDstImage,
    UINT        uNewWidth,
    UINT        uNewHeight);

LineContribType *AllocContributions (UINT uLineLength, UINT uWindowSize)
{
    LineContribType *res = (LineContribType *) malloc(sizeof(LineContribType));
        // Init structure header
    res->WindowSize = uWindowSize;
    res->LineLength = uLineLength;
        // Allocate list of contributions
    res->ContribRow = (ContributionType *) malloc(uLineLength * sizeof(ContributionType));
    for (UINT u = 0 ; u < uLineLength ; u++)
    {
        // Allocate contributions for every pixel
        res->ContribRow[u].Weights = (double *)malloc(uWindowSize * sizeof(double));
    }
    return res;
}
 
void FreeContributions (LineContribType * p)
{
    for (UINT u = 0; u < p->LineLength; u++)
    {
        // Free contribs for every pixel
        free(p->ContribRow[u].Weights);
    }
    free(p->ContribRow);    // Free list of pixels contribs
    free(p);                   // Free contribs header
}
 
double Filter (double dVal)
{
 dVal = fabs(dVal);
 return (dVal < 1.0 ? 1.0 - dVal : 0.0);
}

LineContribType *CalcContributions (UINT uLineSize, UINT uSrcSize, double dScale)
{
    double dWidth;
    double dFScale = 1.0;
    double dFilterWidth = 1.0;

    if (dScale < 1.0)
    {    // Minification
        dWidth = dFilterWidth / dScale;
        dFScale = dScale;
    }
    else
    {    // Magnification
        dWidth= dFilterWidth;
    }
 
    // Window size is the number of sampled pixels
    int iWindowSize = 2 * (int)ceil(dWidth) + 1;
 
    // Allocate a new line contributions strucutre
    LineContribType *res = AllocContributions (uLineSize, iWindowSize);
 
    for (UINT u = 0; u < uLineSize; u++)
    {   // Scan through line of contributions
        double dCenter = (double)u / dScale;   // Reverse mapping
        // Find the significant edge points that affect the pixel
        int iLeft = max (0, (int)floor (dCenter - dWidth));
        res->ContribRow[u].Left = iLeft;
        int iRight = min (ceil (dCenter + dWidth), uSrcSize - 1);
        res->ContribRow[u].Right = iRight;
 
        // Cut edge points to fit in filter window in case of spill-off
        if (iRight - iLeft + 1 > iWindowSize)
        {
            if (iLeft < (uSrcSize - 1 / 2))
            {
                iLeft++;
            }
            else
            {
                iRight--;
            }
        }
  int iSrc;
        double dTotalWeight = 0.0;  // Zero sum of weights
        for (iSrc = iLeft; iSrc <= iRight; iSrc++)
        {   // Calculate weights
            dTotalWeight += (res->ContribRow[u].Weights[iSrc-iLeft] = 
                                dFScale * Filter (dFScale * (dCenter - (double)iSrc)));
        }
        //assert (dTotalWeight >= 0.0);   // An error in the filter function can cause this
        if (dTotalWeight > 0.0)
        {   // Normalize weight of neighbouring points
            for (iSrc = iLeft; iSrc <= iRight; iSrc++)
            {   // Normalize point
                res->ContribRow[u].Weights[iSrc-iLeft] /= dTotalWeight;
            }
        }
   }
   return res;
}
 
void ScaleRow(COLORREF           *pSrc,
            UINT                uSrcWidth,
            COLORREF           *pRes,
            UINT                uResWidth,
            UINT                uRow,
            LineContribType    *Contrib)
{
    COLORREF *pSrcRow = &(pSrc[uRow * uSrcWidth]);
    COLORREF *pDstRow = &(pRes[uRow * uResWidth]);
    for (UINT x = 0; x < uResWidth; x++)
    {   // Loop through row
        BYTE r = 0;
        BYTE g = 0;
        BYTE b = 0;
        int iLeft = Contrib->ContribRow[x].Left;    // Retrieve left boundries
        int iRight = Contrib->ContribRow[x].Right;  // Retrieve right boundries
  //printf("%d, left=%d, right=%d/n", x,iLeft, iRight);
  if (iRight - iLeft >= 5) {
  // printf("%d, left=%d, right=%d===============================/n", x,iLeft, iRight); 
  }
        for (int i = iLeft; i <= iRight; i++)
        {   // Scan between boundries
            // Accumulate weighted effect of each neighboring pixel
            r += (BYTE)(Contrib->ContribRow[x].Weights[i-iLeft] * (double)(GetRValue(pSrcRow[i])));
            g += (BYTE)(Contrib->ContribRow[x].Weights[i-iLeft] * (double)(GetGValue(pSrcRow[i])));
            b += (BYTE)(Contrib->ContribRow[x].Weights[i-iLeft] * (double)(GetBValue(pSrcRow[i])));
        }
        pDstRow[x] = RGB(r,g,b); // Place result in destination pixel
    }
}

void HorizScale (COLORREF           *pSrc,
                UINT                uSrcWidth,
                UINT                uSrcHeight,
                COLORREF           *pDst,
                UINT                uResWidth,
                UINT                uResHeight)
{
    if (uResWidth == uSrcWidth)
    {   // No scaling required, just copy
        memcpy (pDst, pSrc, sizeof (COLORREF) * uSrcHeight * uSrcWidth);
    }
    // Allocate and calculate the contributions
    LineContribType * Contrib = CalcContributions (uResWidth, uSrcWidth, (double)uResWidth/uSrcWidth);
    for (UINT u = 0; u < uResHeight; u++)
    {          
  printf("noRow=%d, w=%d/n", u, uResWidth);
        ScaleRow (  pSrc,
                    uSrcWidth,
                    pDst,
                    uResWidth,
                    u,
                    Contrib);    // Scale each row
    }
    FreeContributions (Contrib);  // Free contributions structure
}
 
void ScaleCol (COLORREF           *pSrc,
            UINT                uSrcWidth,
            COLORREF           *pRes,
            UINT                uResWidth,
            UINT                uResHeight,
            UINT                uCol,
            LineContribType    *Contrib)
{
    for (UINT y = 0; y < uResHeight; y++)
    {    // Loop through column
        BYTE r = 0;
        BYTE g = 0;
        BYTE b = 0;
        int iLeft = Contrib->ContribRow[y].Left;    // Retrieve left boundries
        int iRight = Contrib->ContribRow[y].Right;  // Retrieve right boundries
  //printf("%d, left=%d, right=%d/n", y,iLeft, iRight);
        for (int i = iLeft; i <= iRight; i++)
        {   // Scan between boundries
            // Accumulate weighted effect of each neighboring pixel
            COLORREF pCurSrc = pSrc[i * uSrcWidth + uCol];
            r += BYTE(Contrib->ContribRow[y].Weights[i-iLeft] * (double)(GetRValue(pCurSrc)));
            g += BYTE(Contrib->ContribRow[y].Weights[i-iLeft] * (double)(GetGValue(pCurSrc)));
            b += BYTE(Contrib->ContribRow[y].Weights[i-iLeft] * (double)(GetBValue(pCurSrc)));
        }
        pRes[(uResHeight-1-y) * uResWidth + uCol] = RGB (r,g,b);   // Place result in destination pixel
    }
}
 
void VertScale (COLORREF           *pSrc,
            UINT                uSrcWidth,
            UINT                uSrcHeight,
            COLORREF           *pDst,
            UINT                uResWidth,
            UINT                uResHeight)
{
    if (uSrcHeight == uResHeight)
    {   // No scaling required, just copy
        memcpy (pDst, pSrc, sizeof (COLORREF) * uSrcHeight * uSrcWidth);
    }
    // Allocate and calculate the contributions
    LineContribType * Contrib = CalcContributions (uResHeight, uSrcHeight, (double)uResHeight/uSrcHeight);
    for (UINT u = 0; u < uResWidth; u++)
    {   // Step through columns
  printf("noCol=%d, w=%d/n", u, uResWidth);
        ScaleCol (  pSrc,
                    uSrcWidth,
                    pDst,
                    uResWidth,
                    uResHeight,
                    u,
                    Contrib);   // Scale each column
    }
    FreeContributions (Contrib);     // Free contributions structure
}

COLORREF *AllocAndScale (
    COLORREF   *pOrigImage,
    UINT        uOrigWidth,
    UINT        uOrigHeight,
    UINT        uNewWidth,
    UINT        uNewHeight)
{
    // Scale source image horizontally into temporary image
    COLORREF *pTemp = (COLORREF*)malloc(uNewWidth * uOrigHeight * sizeof(COLORREF));
    HorizScale (pOrigImage,
                uOrigWidth,
                uOrigHeight,
                pTemp,
                uNewWidth,
                uOrigHeight);

    // Scale temporary image vertically into result image   
    COLORREF *pRes = (COLORREF*)malloc(uNewWidth * uNewHeight * sizeof(COLORREF));
    VertScale ( pTemp,
                uNewWidth,
                uOrigHeight,
                pRes,
                uNewWidth,
                uNewHeight);
    free(pTemp);
    return pRes;
}

COLORREF *Scale (
    COLORREF   *pOrigImage,
    UINT        uOrigWidth,
    UINT        uOrigHeight,
    COLORREF   *pDstImage,
    UINT        uNewWidth,
    UINT        uNewHeight)
{
    // Scale source image horizontally into temporary image
    COLORREF *pTemp = (COLORREF*)malloc(uNewWidth * uOrigHeight * sizeof(COLORREF));
    HorizScale (pOrigImage,
                uOrigWidth,
                uOrigHeight,
                pTemp,
                uNewWidth,
                uOrigHeight);
    // Scale temporary image vertically into result image   
    VertScale ( pTemp,
                uNewWidth,
                uOrigHeight,
                pDstImage,
                uNewWidth,
                uNewHeight);
    free(pTemp);
    return pDstImage;
}

#endif //   _2_PASS_SCALE_H_

參考文檔:
http://www.compuphase.com/graphic/scale2.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章