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,歡迎下載查看。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章