我正在使用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。