[FFMpeg] 非標准分辨率視頻Dump YUV注意事項


背景

做視頻編解碼相關開發的過程中我們經常會遇到要把視頻原始YUV數據保存下來查看的情況。
使用FFMpeg對視頻解碼之后原始圖片數據都是保存在AVFrame這一結構中,很多時候我們都按照圖像的長寬來對數據進行保存,這在絕大部分標准分辨率中都是可行的,因為圖像的寬度在內存中能剛好滿足CPU的字節對齊。
而對於非標准分辨率的視頻來說,應該注意AVFramelinesize可能比實際的圖像寬度要大。
如我在解碼一個858x360分辨率的視頻成YUV420P的時候,其解碼出來的幀的linesize分別為{896,448,448},可以看到linesize[0]大於858,相關解釋可以見AVFrame結構體定義的備注:

/**
 * For video, size in bytes of each picture line.
 * For audio, size in bytes of each plane.
 *
 * For audio, only linesize[0] may be set. For planar audio, each channel
 * plane must be the same size.
 *
 * For video the linesizes should be multiples of the CPUs alignment
 * preference, this is 16 or 32 for modern desktop CPUs.                    // <-- Suiyek: Ref Here
 * Some code requires such alignment other code can be slower without
 * correct alignment, for yet other it makes no difference.
 *
 * @note The linesize may be larger than the size of usable data -- there
 * may be extra padding present for performance reasons.
 */
int linesize[AV_NUM_DATA_POINTERS];

不難看出,AVFrame.data的數據存放格式是這樣的:

data[i]:
[ (width >> component-shift) data | padding data ]
|<- -                linesize[i]             - ->|

所以我們在dump YUV的時候不能僅僅使用寬高來計算數據大小,應該去掉linesize的對齊長度(以YUV420P為例):

void DumpYUV420P(const AVFrame* frame, const char* name) {
    if (!frame->width || !frame->height)
        return;

    int ws, hs;
    // 取得當前像素格式的U/V分量(若有)的右移系數(其實就是除以多少..)
    av_pix_fmt_get_chroma_sub_sample(static_cast<AVPixelFormat>(frame->format), &ws, &hs);

    int offset = 0;
    std::ofstream ofs(name, std::ios::binary | std::ios::app);
    for (int i = 0; i < frame->height; i++)
    {
        ofs.write((char*)(frame->data[0] + offset), frame->width);
        offset += frame->linesize[0];
    }

    offset = 0;
    for (int i = 0; i < frame->height >> hs; i++)
    {
        ofs.write((char*)(frame->data[1] + offset), frame->width >> ws);
        offset += frame->linesize[1];
    }

    offset = 0;
    for (int i = 0; i < frame->height >> hs; i++)
    {
        ofs.write((char*)(frame->data[2] + offset), frame->width >> ws);
        offset += frame->linesize[2];
    }

    ofs.close();
}

參考

FFMpeg在很多地方都有做數據字節對齊的優化,字節對齊是很常見的計算機軟件優化手段,可以參考:Data structure alignment


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM