yuyv(yuv422)轉換爲yuv420p

今天遇到一個問題,我的攝像頭採集到的數據是yuyv格式(屬於yuv422),而X264在進行編碼的時候需要標準的YUV(4:2:0)。所以有一個yuv422toyuv420的轉換。在網上找了半天找到的方法拿過來轉換了查看都很花。於是自己看了一下yuv格式的解釋,準備寫一個轉換代碼。以下許多解釋都是按我的理解:
一、yuv
yuv格式通常有兩大類:打包(packed)和平面(planar)格式。前者在碼流裏是yuv挨一起,比如我的yuyv就是 Y0 U0 Y1 V1 Y2 U2 …. 每一個 Y對應一組UV分量。後者存儲y u v分量是分開存儲的,這種方式一般後面帶P, 比如y uv420p就是Y0 Y1 Y2 … U0 U1 U2 … V0 V1 V2 … uv分量的多少根據格式來,yuv420也就是每四個 Y共用一組UV分量。
二、轉換
理解了yuyv即yuv422與yuv420p中分量的排布,就要進行轉換了。網上查到的資料說yuv422->yuv420p時 丟棄偶數行的uv分量。
三、編碼

定義:

unsignedchar *y = out;
unsignedchar *u = out + width*height;
unsigned char*v = out + width*height + width*height/4;

y u v分別指向yuv420buf中存儲y u v分量的數組,這裏out的類型爲char型數組,按yuv420p的定義,4個y共用一對uv,那麼一個y對應1/4個uv,一個分量佔一個byte,out的大小爲:總共的y分量(width*height) + 總共的u分量(width*height/4) + 總共的v分量(width*height/4) = width*height*3/2。通過上面的轉換也可以得到yuyv(yuv422)一個像素佔用2個字節,yuv420p一個像素佔1.5個字節,rgb24的話佔用3個字節,還是節約了一點點空間的。。。

獲取y分量並存儲到yuv420buf中:
         for(i=0; i<yuv422_length; i+=2){
               *(y+y_index) = *(in+i);
               y_index++;
         }
這裏的yuv422_length爲width*height*2;y_index初始爲0,存儲一個y就自加一次。

獲取uv分量並存儲到yuv420buf中:
         for(i=0; i<height; i+=2){
               base_h = i*width*2;
               for(j=base_h+1;j<base_h+width*2; j+=2){
                        if(is_u){
                                 *(u+u_index)= *(in+j);
                                 u_index++;
                                 is_u = 0;
                        }
                        else{
                                 *(v+v_index)= *(in+j);
                                 v_index++;
                                 is_u = 1;
                        }
               }
          }

總結:初入視頻圖像,我還是一個菜鳥,對於很多理解也不深,這個代碼應該還有很多沒考慮,對於我可用了。當然以上都是廢話,直接貼代碼

int yuv422toyuv420(unsigned char *out, const unsigned char *in, unsigned int width, unsigned int height)
    {
    unsigned char *y = out;
    unsigned char *u = out + width*height;
    unsigned char *v = out + width*height + width*height/4;

    unsigned int i,j;
    unsigned int base_h;
    unsigned int is_y = 1, is_u = 1;
    unsigned int y_index = 0, u_index = 0, v_index = 0;

    unsigned long yuv422_length = 2 * width * height;

    //序列爲YU YV YU YV,一個yuv422幀的長度 width * height * 2 個字節
    //丟棄偶數行 u v

    for(i=0; i<yuv422_length; i+=2){
        *(y+y_index) = *(in+i);
        y_index++;
    }

    for(i=0; i<height; i+=2){
        base_h = i*width*2;
        for(j=base_h+1; j<base_h+width*2; j+=2){
            if(is_u){
                *(u+u_index) = *(in+j);
                u_index++;
                is_u = 0;
            }
            else{
                *(v+v_index) = *(in+j);
                v_index++;
                is_u = 1;
            }
        }
    }

    return 1;
    }
發佈了38 篇原創文章 · 獲贊 9 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章