<五> S5PV210 H264视频解码后显示

    上一章写了如何通过SPPV210芯片H264硬件解码生存yuv格式视频文件,yuv格式是由一帧帧的图像组成,做一下格式转换写到framebuffer上即可实现显示了。

    首先看上一章中关于解码后获得YUV帧数据的处理方法,下面是解码部分代码。

if(status==MFC_GETOUTBUF_DISPLAY_DECODING || status==MFC_GETOUTBUF_DISPLAY_ONLY) {
            if(!ylin)
                ylin = (uint8_t *)malloc(oinfo.img_width*oinfo.img_height);
            if(!ylin) {
                fprintf(stderr,"Out of memory.\n");
                break;
            }
            // converted tiled to linear nv12 format - Y plane
            csc_tiled_to_linear(ylin, (uint8_t *)oinfo.YVirAddr, oinfo.img_width, oinfo.img_height);
            fwrite(ylin,1, oinfo.img_width*oinfo.img_height, fpo);
            
            if(!clin)
                clin = (uint8_t *)malloc(oinfo.img_width*oinfo.img_height/2);
            if(!clin) {
                fprintf(stderr,"Out of memory.\n");
                break;
            }

            p_U = (uint8_t *)clin;
            p_V = (uint8_t *)clin;
            p_V += ((oinfo.img_width * oinfo.img_height) >> 2);
            // converted tiled to linear uv format - C plane
            csc_tiled_to_linear_deinterleave(p_U, p_V, (uint8_t *)oinfo.CVirAddr, oinfo.img_width, oinfo.img_height/2);

            fwrite(clin,1,oinfo.img_width*oinfo.img_height/2,fpo);
            show_cnt++;
        }

    解码完成时,获得到一帧YUV格式数据后,会将status设置为MFC_GETOUTBUF_DISPLAY_DECODING ,从而进入下面的程序。ylin、clin分别是存储Y分量数据和UV分量数据的地址,主要到为其申请到的地址空间长度分别为img_width*img_height和img_width*img_height/2,由于解码器输出数据为tiled格式,需要将其转为line格式,这里分别调用了csc_tiled_to_linear()函数和csc_tiled_to_linear_deinterleave()函数对其进行格式转换,转换后通过fwrite()函数将其写入到输出文件即可。

    这里要对解码后的数据进行显示,由于液晶屏幕显示的数据格式为rgb格式的,所以就要多一次格式转换。这次解码后输出的YUV数据与之前写的一篇显示摄像头画面程序中的NV12格式数据类似,很多函数直接使用即可。

    首先看屏幕的初始化,代码如下。

    Fb *fb;
    char *fb_dev = "/dev/fb0";
    unsigned char* yuv420p = NULL;
    unsigned char* rgb = NULL;
    // 屏幕初始化
    fb = new Fb(fb_dev,  80, 0, 640, 480);
    if(!fb->OpenDevice()){
       printf("Fb Open error\n");
       return -1;
    }
    fb->Trans(&rgb);


    这里定义了液晶屏控制类,在其构造函数中定义了显示图像的位置(80,0),显示图像的大小(640,480),这里图像的大小要与解码的h264文件的图像格式大小一致,不然会显示图像不正常。然后调用Trans()函数来取到显示区buff 的地址,需要显示图像时,往这个地址写rgb图像格式数据就行。

    接下来看显示部分,代码如下。

if(status==MFC_GETOUTBUF_DISPLAY_DECODING || status==MFC_GETOUTBUF_DISPLAY_ONLY) {
            if(!ylin)
                ylin = (uint8_t *)malloc(oinfo.img_width*oinfo.img_height);
            if(!ylin) {
                fprintf(stderr,"Out of memory.\n");
                break;
            }
            if(!yuv420p)
		yuv420p = (uint8_t *)malloc(oinfo.img_width*oinfo.img_height*3/2);
	    if(!yuv420p) {
		fprintf(stderr,"Out of memory.\n");
		break;
	    }
            // converted tiled to linear nv12 format - Y plane
            csc_tiled_to_linear(ylin, (uint8_t *)oinfo.YVirAddr, oinfo.img_width, oinfo.img_height);
            memcpy(yuv420p, ylin, oinfo.img_width*oinfo.img_height);
            
            if(!clin)
                clin = (uint8_t *)malloc(oinfo.img_width*oinfo.img_height/2);
            if(!clin) {
                fprintf(stderr,"Out of memory.\n");
                break;
            }

            // converted tiled to linear uv format - C plane
            csc_tiled_to_linear(clin, (uint8_t *)oinfo.CVirAddr, oinfo.img_width, oinfo.img_height/2);
            memcpy(yuv420p+oinfo.img_width*oinfo.img_height, clin, oinfo.img_width*oinfo.img_height/2);

            decodeYUV420SP((unsigned int*)rgb, yuv420p, oinfo.img_width, oinfo.img_height);
	    fb->Draw();
            show_cnt++;
        }

     这里多了申请了一个地址yuv420p,用来存放完整的一帧yuv格式数据,之前是通过ylin,clin两个地址存放。注意到这里UV分量数据转换时时调用的是csc_tiled_to_linear()函数,输出的是NV12格式数据。YUV与NV12格式数据的区别在于,UV分量排列时,YUV是先存放U分量,然后存放V分量,而NV12是UV交叉排列。调用decodeYUV420SP()函数来完成NV12格式数据到rgb格式数据的转换,然后调用Draw()函数就完成了一帧图像的显示。

    具体程序我上传到了http://download.csdn.net/detail/westlor/9403775,欢迎下载查看。






你可能感兴趣的:(解码,显示,h264,yuv)