我使用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
答案 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。