我正在使用ffmpeg C库,并尝试将AVFrame转换为具有YUV *组件的2d像素数组,以进行分析。我想出了如何转换每个像素的Y分量:

uint8_t y_val = pFrame->data[0][pFrame->linesize[0] * y + x];


由于所有帧都具有Y分量,因此这很容易。但是,大多数数字视频都没有4:4:4色度二次采样,因此获取UV分量让我很困惑。

我正在为这个项目使用C语言。没有C ++。有想法吗?

*注意:是的,我知道从技术上讲它是YCbCr而不是YUV。

编辑:

我对C相当陌生,因此它可能不是那里最漂亮的代码。

当我尝试:

VisYUVFrame *VisCreateYUVFrame(const AVFrame *pFrame){
    VisYUVFrame *tmp = (VisYUVFrame*)malloc(sizeof(VisYUVFrame));
    if(tmp == NULL){ return NULL;}
    tmp->height = pFrame->height;
    tmp->width = pFrame->width;

    tmp->data = (PixelYUV***)malloc(sizeof(PixelYUV**) * pFrame->height);
    if(tmp->data == NULL) { return NULL;};

    for(int y = 0; y < pFrame->height; y++){
        tmp->data[y] = (PixelYUV**)malloc(sizeof(PixelYUV*) * pFrame->width);
        if(tmp->data[y] == NULL) { return NULL;}

        for(int x = 0; x < pFrame->width; x++){
            tmp->data[y][x] = (PixelYUV*)malloc(sizeof(PixelYUV*));
            if(tmp->data[y][x] == NULL){ return NULL;};
            tmp->data[y][x]->Y = pFrame->data[0][pFrame->linesize[0] * y + x];
            tmp->data[y][x]->U = pFrame->data[1][pFrame->linesize[1] * y + x];
            tmp->data[y][x]->V = pFrame->data[2][pFrame->linesize[2] * y + x];

        }
    }

    return tmp;


Luma工作,但是当我运行Valgrind时,我得到了


  
   0x26
   1个
    无效读取
    大小为1的读取无效
    
      
        0x100003699
        /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2
        VisCreateYUVFrame
        /用户/ hborcher / ClionProjects / borcherscope / lib
        可视化
        145
      
      
        0x100006B5B
        /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2
        渲染
        /用户/ hborcher / ClionProjects / borcherscope / lib / decoder
        simpleDecoder2.c
        253
      
      
        0x100002D24
        /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2
        主要
        /用户/ hborcher / ClionProjects / borcherscope / src
        createvisual2.c
        93
      
    
    在分配了大小为92,207的块之后,地址0x10e9f91ef为0字节
    
      
        0x100013EEA
        / usr / local /地窖/valgrind/3.11.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so
        malloc_zone_memalign
      
      
        0x1084B5416
        /usr/lib/system/libsystem_malloc.dylib
        posix_memalign
      
      
        0x10135D317
        /usr/local/Cellar/ffmpeg/3.0.2/lib/libavutil.55.17.103.dylib
        av_malloc
      
    
  
  
  
    0x27
    1个
    无效读取
    大小为1的读取无效
    
      
        0x1000036BA
        /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2
        VisCreateYUVFrame
        /用户/ hborcher / ClionProjects / borcherscope / lib
        可视化
        147
      
      
        0x100006B5B
        /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2
        渲染
        /用户/ hborcher / ClionProjects / borcherscope / lib / decoder
        simpleDecoder2.c
        253
      
      
        0x100002D24
        /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2
        主要
        /用户/ hborcher / ClionProjects / borcherscope / src
        createvisual2.c
        93
      
    
    在分配了大小为92,207的块之后,地址0x10e9f91ef为0字节
    
      
        0x100013EEA
        / usr / local /地窖/valgrind/3.11.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so
        malloc_zone_memalign
      
      
        0x1084B5416
        /usr/lib/system/libsystem_malloc.dylib
        posix_memalign
      
      
        0x10135D317
        /usr/local/Cellar/ffmpeg/3.0.2/lib/libavutil.55.17.103.dylib
        av_malloc

最佳答案

如果您可以对色度子采样进行硬编码,例如您知道帧数据格式为4:2:0,这很简单:

int uvy = y >> 1, uvx = x >> 1;
uint8_t u_val = pFrame->data[1][pFrame->linesize[1] * uvy + uvx];
uint8_t v_val = pFrame->data[2][pFrame->linesize[2] * uvy + uvx];


如果您希望它更通用,请使用以下命令:

AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pFrame->format);
int uvy = y >> desc->log2_chroma_h, uvx = x >> desc->log2_chroma_w;
uint8_t u_val = pFrame->data[1][pFrame->linesize[1] * uvy + uvx];
uint8_t v_val = pFrame->data[2][pFrame->linesize[2] * uvy + uvx];


在所有情况下,在任何x,y位置获取像素均应如此。但是,请勿使用此方法将任何色度子采样的缓冲区转换为4:4:4数组,否则会有视觉瑕疵。为了在屏幕上显示,请使用原始数据并在例如您的openGL着色器可将屏幕上的原始数组转换为所需的目标分辨率。要转换为其他用例的4:4:4,请使用libswscale

10-08 06:35