将ffmpeg帧转换为C

时间:2016-06-08 15:33:14

标签: c ffmpeg

我使用ffmpeg C库并尝试将一个AVFrame转换为带有YUV *组件的二维像素数组进行分析。我想出了如何为每个像素转换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时,我得到了

  

   0×26    1     InvalidRead     读取大小为1无效                     0x100003699         /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2         VisCreateYUVFrame         /用户/ hborcher / ClionProjects / borcherscope / lib中         visualization.c         145                       0x100006B5B         /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2         给予         /用户/ hborcher / ClionProjects / borcherscope / LIB /解码器         simpleDecoder2.c         253                       0x100002D24         /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2         主要         /用户/ hborcher / ClionProjects / borcherscope / SRC         createvisual2.c         93                 地址0x10e9f91ef是大小为92,207 alloc&#d; d的块后的0字节                     0x100013EEA         /usr/local/Cellar/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               

     

    0×27     1     InvalidRead     读取大小为1无效                     0x1000036BA         /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2         VisCreateYUVFrame         /用户/ hborcher / ClionProjects / borcherscope / lib中         visualization.c         147                       0x100006B5B         /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2         给予         /用户/ hborcher / ClionProjects / borcherscope / LIB /解码器         simpleDecoder2.c         253                       0x100002D24         /Users/hborcher/Library/Caches/CLion2016.2/cmake/generated/borcherscope-8e83e7dd/8e83e7dd/Debug/VisCreator2         主要         /用户/ hborcher / ClionProjects / borcherscope / SRC         createvisual2.c         93                 地址0x10e9f91ef是大小为92,207 alloc&#d; d的块后的0字节                     0x100013EEA         /usr/local/Cellar/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               

1 个答案:

答案 0 :(得分:1)

如果您可以对色度子采样进行硬编码,例如你知道帧数据格式是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