簡體   English   中英

使用 libav/ffmpeg 將 RGB8 轉換為 NV12

[英]Converting RGB8 to to NV12 with libav/ffmpeg

我正在嘗試使用 libav 將輸入的 RGB8 圖像轉換為 NV12,但 sws_scale 引發了讀取訪問沖突。 我一定是飛機或步幅不對,但我不明白為什么。

在這一點上,我相信我會從一雙新鮮的眼睛中受益。 我錯過了什么?


void convertRGB2NV12(unsigned char *rgb_in, width, height) {
 struct SwsContext* sws_context = nullptr;
 const int in_linesize[1] = {3 * width}; // RGB stride
 int out_linesize[2] = {width, width}; // NV12 stride

 // NV12 data is separated in two
 // planes, one for the intensity (Y) and another one for
 // the colours(UV) interleaved, both with
 // the same width as the frame but the UV plane with
 // half of its height.
 uint8_t* out_planes[2];
 out_planes[0] = new uint8_t[width * height];
 out_planes[1] = new uint8_t[width * height/2];

 sws_context = sws_getCachedContext(sws_context, width, height,
                                    AV_PIX_FMT_RGB8, width, height,
                                    AV_PIX_FMT_NV12, 0, 0, 0, 0);
 sws_scale(sws_context, (const uint8_t* const*)rgb_in, in_linesize,
           0, height, out_planes, out_linesize);
// (.....)
}

正如Rotem在原始帖子的第一條評論中所注意到的,輸入格式平面必須采用指針數組格式。

主要有兩個問題:

  • AV_PIX_FMT_RGB8替換AV_PIX_FMT_RGB24

  • rgb_in應該用指針數組“包裝”:

     const uint8_t* in_planes[1] = {rgb_in}; sws_scale(sws_context, in_planes, ...)

測試:

使用 FFmpeg 命令行工具創建 RGB24 像素格式的二進制輸入:

ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1 -vcodec rawvideo -pix_fmt rgb24 -frames 1 -f rawvideo rgb_image.bin

使用 C 代碼讀取輸入圖像:

const int width = 192;
const int height = 108;
unsigned char* rgb_in = new uint8_t[width * height * 3];

FILE* f = fopen("rgb_image.bin", "rb");
fread(rgb_in, 1, width * height * 3, f);
fclose(f);

執行convertRGB2NV12(rgb_in, width, height); .

在函數結束前,添加將輸出寫入二進制文件的臨時代碼:

FILE* f = fopen("nv12_image.bin", "wb");
fwrite(out_planes[0], 1, width * height, f);
fwrite(out_planes[1], 1, width * height/2, f);
fclose(f);

將 nv12_image.bin 作為灰度輸入轉換為 PNG 圖像文件(用於查看結果):

ffmpeg -y -f rawvideo -s 192x162 -pix_fmt gray -i nv12_image.bin -pix_fmt rgb24 nv12_image.png

完整的代碼示例:

#include <stdio.h>
#include <string.h>
#include <stdint.h>

extern "C"
{
#include <libswscale/swscale.h>
}


void convertRGB2NV12(const unsigned char *rgb_in, int width, int height)
{
    struct SwsContext* sws_context = nullptr;
    const int in_linesize[1] = {3 * width}; // RGB stride
    const int out_linesize[2] = {width, width}; // NV12 stride

    // NV12 data is separated in two
    // planes, one for the intensity (Y) and another one for
    // the colours(UV) interleaved, both with
    // the same width as the frame but the UV plane with
    // half of its height.
    uint8_t* out_planes[2];
    out_planes[0] = new uint8_t[width * height];
    out_planes[1] = new uint8_t[width * height/2];

    sws_context = sws_getCachedContext(sws_context, width, height,
                                    AV_PIX_FMT_RGB24, width, height,
                                    AV_PIX_FMT_NV12, SWS_BILINEAR, nullptr, nullptr, nullptr);

    const uint8_t* in_planes[1] = {rgb_in};

    int response = sws_scale(sws_context, in_planes, in_linesize,
                             0, height, out_planes, out_linesize);

    if (response < 0)
    {
        printf("Error: sws_scale response = %d\n", response);
        return;
    }

// (.....)

    //Write NV12 output image to binary file (for testing)
    ////////////////////////////////////////////////////////////////////////////
    FILE* f = fopen("nv12_image.bin", "wb");
    fwrite(out_planes[0], 1, width * height, f);
    fwrite(out_planes[1], 1, width * height/2, f);
    fclose(f);
    ////////////////////////////////////////////////////////////////////////////


    delete[] out_planes[0];
    delete[] out_planes[1];

    sws_freeContext(sws_context);
}



int main()
{
    //Use ffmpeg for building raw RGB image (used as input).
    //ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1 -vcodec rawvideo -pix_fmt rgb24 -frames 1 -f rawvideo rgb_image.bin
    
    const int width = 192;
    const int height = 108;
    unsigned char* rgb_in = new uint8_t[width * height * 3];

    //Read input image for binary file (for testing)
    ////////////////////////////////////////////////////////////////////////////
    FILE* f = fopen("rgb_image.bin", "rb");
    fread(rgb_in, 1, width * height * 3, f);
    fclose(f);
    ////////////////////////////////////////////////////////////////////////////


    convertRGB2NV12(rgb_in, width, height);

    delete[] rgb_in;

    return 0;
}

輸入(RGB):
在此處輸入圖片說明

輸出(NV12 顯示為灰度):
在此處輸入圖片說明


將 NV12 轉換為 RGB:

ffmpeg -y -f rawvideo -s 192x108 -pix_fmt nv12 -i nv12_image.bin -pix_fmt rgb24 rgb_output_image.png

結果:
在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM