当前位置: 首页 > >

DX播放YUV的问题-frame->linesize[0]

发布时间:

问题现象:
播放一个飞常规设备的视频,解码出来视频的宽度为1056,高度为1792,播放花屏,如下图所示:



问题排查过程:
这种现象一眼就觉得是视频的宽高不对,然后就各种怼FFmpeg,甚至直接保存裸h264视频,用h264播放器解码播放,居然是可以播放的,说明视频本身没有问题,根据解码器输出视频宽高,分别是1056和1792。说明FFmpeg解码出来的视频宽高没有问题。
因为我这里绘图采用的是DX绘图,难道是DX的问题?于是将绘图模式改成GDI,FFmpeg解码输出BGR视频。结果能正常播放。由于这里视频高度大于宽度,于是猜想DX是不是不支持这种宽度小于高度的视频,但是最终没有查到任何资料,为了测试,我居然直接在初始化DX的时候,将高度和宽度对调,结果还是不行,同样的花屏。
之后说将解码之后的YUV数据保存起来,用YUV播放器播放试试。因为之前写YUV数据都是直接用的视频的宽高,代码如下所示:


FILE* file = fopen("e:\test.yuv", "ab+");
if (file) {
fwrite(outY, 1, framePara[0] * framePara[1], file);
fwrite(outU, 1, framePara[0] * framePara[1] / 4, file);
fwrite(outV, 1, framePara[0] * framePara[1] / 4, file);
fclose(file);
}

其中framePara[0]是视频的宽度,framePara[1]是视频的高度,这样保存下来的YUV数据,找了很多个播放器都是花屏,录制一个常规的设备视频,播放器都是可以播放的。
然后说只保存Y分量,结果测试YUV播放器上能看到一部分图像(这里不方便截图,就不发出来了)。虽然是绿色的图像,但是也能看到图像里面的物体场景等。再次证明FFmpeg解码出来的YUV应该是没有问题的。
最后实在没办法了,找到FFmpeg的示例代码,找到它保存YUV视频数据的代码,如下所示:


static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize, char *filename){
FILE *f;
int i;
f = fopen(filename,"w");
fprintf(f, "P5
%d %d
%d
", xsize, ysize, 255);
for (i = 0; i < ysize; i++)
fwrite(buf + i * wrap, 1, xsize, f);
fclose(f);
}

pgm_save(frame->data[0], frame->linesize[0], frame->width, frame->height, buf);
在这里发现保存用的wrap不是视频的宽度,而是FFmpeg解码后输出的一个参数,抱着侥幸的心理,查看了一下正常视频和这个花屏的视频的这个输出参数,如下所示:



这个是一个1920*1080的视频的解码出来的参数,framePara[2]就是frame->linesize[0]。



这个就是播放花屏的解码参数,结果发现frame->linesize[0]并不等于视频宽度,网上说的frame->linesize[0]>=video_width。
于是抱着侥幸心理,继续尝试修改代码,下面是改之前的复制YUV数据到DX缓冲区的代码


for (i = 0; i < video_height; i++) {
memcpy(pDest + i * stride, outY + i * video_width, video_width);
}
for (i = 0; i < video_height / 2; i++) {
memcpy(pDest + stride * video_height + i * stride / 2, outV + i * video_width / 2, video_width / 2);
}
for (i = 0; i < video_height / 2; i++) {
memcpy(pDest + stride * video_height + stride * video_height / 4 + i * stride / 2, outU + i * video_width / 2, video_width / 2);
}

下面是改之后的代码,其中video_stride就是frame->linesize[0]。


for (i = 0; i < video_height; i++) {
memcpy(pDest + i * stride, outY + i * video_stride, video_width);
}
for (i = 0; i < video_height / 2; i++) {
memcpy(pDest + stride * video_height + i * stride / 2, outV + i * video_stride / 2, video_width / 2);
}
for (i = 0; i < video_height / 2; i++) {
memcpy(pDest + stride * video_height + stride * video_height / 4 + i * stride / 2, outU + i * video_stride / 2, video_width / 2);
}

编译播放,视频完美绘制,没有花屏。



友情链接: hackchn文档网 营销文档网 爱linux网 爱行业网 时尚网