YUV格式互转

#ifndef __COLORTRANSFORM_H__
#define __COLORTRANSFORM_H__

#ifdef __cplusplus
extern "C" {
#endif

#define PERROR 1
#define IMAGE_MAX_WIDTH (4*1024)
#define IMAGE_MAX_HEIGHT (4*1024)
#define MAX_FILE_NAME_LENGTH 256
#define LOGP printf("FUNCTION:%s,LINE:%d\n",__FUNCTION__,__LINE__);
#define LINE_BYTES(Width)	(((long)(Width) * 8 + 31) / 32 * 4)

typedef unsigned char COLOR_BYTE;
typedef unsigned short COLOR_WORD;
typedef unsigned int COLOR_DWORD;
typedef long COLOR_LONG;

//Definition of bitmap header, in which file type info is not included as
//it is determined by the memory layout of bitmap header.
//If added,file info may be wrongly readed.
typedef struct  __tag_BIT_MAP_FILE_HEADER{
//  COLOR_WORD wType;//file type,must be0x424D(BM)
    COLOR_DWORD dwSize;//file size
    COLOR_WORD wReserved1;//reserved word
    COLOR_WORD wReserved2;//reserved word
    COLOR_DWORD dwOffBits;//offsets from header of file
}BITMAPFILEHEADER, *LPBITMAPFILEHEADER;

typedef struct __tag_BIT_MAP_INFO_HEADER{
    COLOR_DWORD dwSize;//size of info header
    COLOR_LONG lWidth;//width of image
    COLOR_LONG lHeight;//height of image
    COLOR_WORD wPlanes;//count of bit plane,must be 1
    COLOR_WORD wBitCount;//bits for every pix
    COLOR_DWORD dwCompression; //compression type
    COLOR_DWORD dwSizeImage; //size in byte of compressed file
    COLOR_LONG lXPelsPerMeter; //horizontal resolution
    COLOR_LONG lYPelsPerMeter; //vertical resolution
    COLOR_DWORD dwClrUsed; //count of color actually used by bitmap
    COLOR_DWORD dwClrImportant; //count of important color in bitmap
}BITMAPINFOHEADER, *LPBITMAPINFOHEADER; //definition of bitmap info header

typedef struct __tag_RGB_QUAD{
    COLOR_BYTE byRGBBlue; //blue component of the color
    COLOR_BYTE byRGBGreen; //green component of the color
    COLOR_BYTE byRGBRed; //red component of the color
    COLOR_BYTE byRGBReserved; //reserverd value
}RGBQUAD, *LPRGBQUAD;//definition of palette

typedef struct __tag_IMAGE_DATA
{
    COLOR_BYTE byBlue;
    COLOR_BYTE byGreen;
    COLOR_BYTE byRed;
}IMAGEDATA, *LPIMAGEDATA;//pixel information

MRESULT SaveBMPFromYUV(const char* pFilePath, const char *pFileName, const MUInt8 * pSource, int iWidth, int iHeight);
MRESULT ReadYUVFromBMP(const char* pFilePath, const char *pFileName, MUInt8 **ppDest, long *pWidth, long *pHeight);
MRESULT ConvertYuv420pToNV21(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight);
MRESULT ConvertYuv420pToNV12(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight);
MRESULT ConvertYuv420pToYUYV(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight);
MRESULT ConvertYuv420pToI422H(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight);
MRESULT ConvertYuv420pToLPI422H(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight);

#ifdef __cplusplus
}
#endif

#endif //__COLORTRANSFORM_H__

#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include "turbojpeg.h"
#include "ColorTransform.h"

MRESULT SaveBMPFromYUV(const char* pFilePath, const char *pFileName, const MUInt8 * pSource, int iWidth, int iHeight)
{
    if (NULL == pFilePath || NULL == pFileName || NULL == pSource)
    {
        return PERROR;
    }
    if (iWidth <= 0 || iHeight <= 0)
    {
        return PERROR;
    }

    MRESULT res = MOK;
    const COLOR_WORD wType = 0x4d42;

    BITMAPFILEHEADER strHead; //head of bitmap
    BITMAPINFOHEADER strInfo; //info head of bitmap
    IMAGEDATA *pBMPImageData = NULL; //store pixel info of bitmap
    FILE *pFileOut = NULL;
    memset(&strHead, 0, sizeof(BITMAPFILEHEADER));
    memset(&strInfo, 0, sizeof(BITMAPINFOHEADER));
    pBMPImageData = (IMAGEDATA*)malloc(iWidth * iHeight * sizeof(IMAGEDATA));
    if (NULL == pBMPImageData)
    {
        printf("failed to allocate %d size of memory for pBMPImageData\n", iWidth * iHeight * sizeof(IMAGEDATA));
        res = PERROR;
        goto __EXIT;
    }
    memset(pBMPImageData, 0, iWidth * iHeight * sizeof(IMAGEDATA));

    int y;
    int r, g, b;
    int i, j;
    for(i = 0; i < iHeight; i++)
    {
        for(j = 0; j < iWidth; j++)
        {
            y  = pSource[j + i * iWidth];

            /*
            yuv<-->rgb
            Y'= 0.299*R' + 0.587*G' + 0.114*B'
            U'= -0.147*R' - 0.289*G' + 0.436*B' = 0.492*(B'- Y')
            V'= 0.615*R' - 0.515*G' - 0.100*B' = 0.877*(R'- Y')
            R' = Y' + 1.140*V'
            G' = Y' - 0.394*U' - 0.581*V'
            B' = Y' + 2.032*U'
            yCbCr<-->rgb
            Y’ = 0.257*R' + 0.504*G' + 0.098*B' + 16
            Cb' = -0.148*R' - 0.291*G' + 0.439*B' + 128
            Cr' = 0.439*R' - 0.368*G' - 0.071*B' + 128
            R' = 1.164*(Y’-16) + 1.596*(Cr'-128)
            G' = 1.164*(Y’-16) - 0.813*(Cr'-128) - 0.392*(Cb'-128)
            B' = 1.164*(Y’-16) + 2.017*(Cb'-128)*/
            r = y;
            g = y;
            b = y;

            r = r > 255 ? 255 : r;
            g = g > 255 ? 255 : g;
            b = b > 255 ? 255 : b;

            r = r < 0 ? 0 : r;
            g = g < 0 ? 0 : g;
            b = b < 0 ? 0 : b;

            (*(pBMPImageData + i * iWidth + j)).byBlue = (COLOR_BYTE)b;
            (*(pBMPImageData + i * iWidth + j)).byGreen = (COLOR_BYTE)g;
            (*(pBMPImageData + i * iWidth + j)).byRed = (COLOR_BYTE)r;
        }
    }


    ///save BMP image
    char arrFilePathName[MAX_FILE_NAME_LENGTH];
    strcpy(arrFilePathName, pFilePath);
    strcat(arrFilePathName, pFileName);
    sprintf(arrFilePathName, "%s_%dX%d%s" , arrFilePathName, iWidth, iHeight, ".bmp");

    if(NULL == (pFileOut = fopen(arrFilePathName, "wb")))
    {
        printf("create the bmp file:%s failed!\n", arrFilePathName);
        res = PERROR;
        goto __EXIT;
    }

    printf("Save bmp file:%s\n", arrFilePathName);

    fwrite(&wType, 1, sizeof(COLOR_WORD), pFileOut);

    strHead.dwSize = iWidth * iHeight * 3 + 54; //size of bitmap in byte
    strHead.wReserved2 = 0;
    strHead.dwOffBits = 54; //actual offsets from the header in byte(14 + 40),no palette
    fwrite(&strHead, 1, sizeof(BITMAPFILEHEADER), pFileOut);


    strInfo.lWidth = iWidth;
    strInfo.lHeight = iHeight;
    strInfo.wBitCount = 24; //specify the count of bits used in rendering colors,common value are:1(Black and white two-color image), 4(16-color image), 8(256-color image), 24(true-color image)
    strInfo.dwClrImportant = 0; //specify the count of important colors,all colors are identified to be important if it is zero.
    strInfo.dwClrUsed = 0; //specify the count of colors actually used in image.If it is 0,count of colors used is identified as 2*2*....*2(total count of wBitCount)
    strInfo.dwCompression = 0; //specify if the image is compressed
    strInfo.wPlanes = 1; ///count of planes and must be 1
    strInfo.dwSize = 40; ///length of struct and must be 40
    strInfo.dwSizeImage = 3 * iWidth * iHeight;

    fwrite(&strInfo, 1, sizeof(BITMAPINFOHEADER), pFileOut);

    //save pixel data
    for(i = iHeight - 1; i >= 0; --i) //from top the bottom
    {
        for(j = 0; j < iWidth; ++j)
            //for(int j = iWidth;j > 0;--j)
        {
            fwrite( &((*(pBMPImageData + i * iWidth + j)).byBlue), 1, sizeof(COLOR_BYTE), pFileOut);
            fwrite( &((*(pBMPImageData + i * iWidth + j)).byGreen), 1, sizeof(COLOR_BYTE), pFileOut);
            fwrite( &((*(pBMPImageData + i * iWidth + j)).byRed), 1, sizeof(COLOR_BYTE), pFileOut);
        }
    }
__EXIT:
    if (pFileOut != NULL)
    {
        fclose(pFileOut);
        pFileOut = NULL;
    }
    if (pBMPImageData != NULL)
    {
        free(pBMPImageData);
        pBMPImageData = NULL;
    }

    return res;
}

MRESULT ReadYUVFromBMP(const char* pFilePath, const char *pFileName, MUInt8 **ppDest, long *pWidth, long *pHeight)
{
    if (NULL == pFilePath || NULL == pFileName || NULL == ppDest || NULL == pWidth || NULL == pHeight)
    {
        printf("parameters invalid\n");
        return PERROR;
    }

    MRESULT res = MOK;

    MUInt8 *pData = NULL;
    FILE *pFile = NULL;
    char arrFileNameFull[MAX_FILE_NAME_LENGTH]; //file name
    size_t lReadSize = 0; //return value of fread
    size_t lWantReadSize = 0; //acutal value want to read
    size_t lActualFileSize = 0; //actula file size in byte
    COLOR_DWORD dwFileSize = 0; //file size got from file head
    COLOR_DWORD dwOffset = 0; //  offset of rgb data from header of file
    int iHeight = 0; // height of bmp file
    int iWidth = 0; // width of bmp file
    MUInt8 * pRGBDataLine = NULL;
    sprintf(arrFileNameFull, "%s%s", pFilePath, pFileName);
    printf("mask bmp file is:%s\n", arrFileNameFull);
    pFile = fopen(arrFileNameFull, "rb");
    if (NULL == pFile)
    {
        printf("can not open file %s\n", arrFileNameFull);
        res = PERROR;
        goto __EXIT;
    }

    pData = malloc(sizeof(MUInt8) * (sizeof(BITMAPFILEHEADER) > sizeof(BITMAPINFOHEADER) ? sizeof(BITMAPFILEHEADER) : sizeof(BITMAPINFOHEADER)));
    if (NULL == pData)
    {
        res = PERROR;
        goto __EXIT;
    }

    // get file size in byte
    fseek(pFile, 0L, SEEK_END);
    lActualFileSize = ftell(pFile);
    fseek(pFile, 0L, SEEK_SET);

    //check file type
    lWantReadSize = 2;
    lReadSize = fread(pData, 1, lWantReadSize, pFile);
    if (lReadSize != lWantReadSize)
    {
        printf("fread from %s failed and return %u\n", arrFileNameFull, lReadSize);
        res = PERROR;
        goto __EXIT;
    }
    if (pData[0] != 0x42 || pData[1] != 0x4d)
    {
        printf("file type is:%0x%0x,not a bmp file\n", pData[1], pData[0]);
        res = PERROR;
        goto __EXIT;
    }

    // get file size from file head
    lWantReadSize = sizeof(BITMAPFILEHEADER);
    lReadSize = fread(pData, 1, lWantReadSize, pFile);
    if (lReadSize != lWantReadSize)
    {
        printf("read head from %s failed and return %u\n", arrFileNameFull, lReadSize);
        res = PERROR;
        goto __EXIT;
    }
    dwFileSize =
        (((COLOR_DWORD)pData[3]) << 24) |
        (((COLOR_DWORD)pData[2]) << 16) |
        (((COLOR_DWORD)pData[1]) << 8) |
        (((COLOR_DWORD)pData[0]) << 0);
    if ( dwFileSize != lActualFileSize)
    {
        printf("file is broken,size in head:%u,actual size:%u\n", dwFileSize, lActualFileSize);
        res = PERROR;
        goto __EXIT;
    }

    // get rgb offset from file head
    dwOffset =
        (((COLOR_DWORD)pData[11]) << 24) |
        (((COLOR_DWORD)pData[10]) << 16) |
        (((COLOR_DWORD)pData[9]) << 8) |
        (((COLOR_DWORD)pData[8]) << 0);

    // get info head
    lWantReadSize = sizeof(BITMAPINFOHEADER);
    lReadSize = fread(pData, 1, lWantReadSize, pFile);
    if (lReadSize != lWantReadSize)
    {
        printf("read info head from %s failed and return %u\n", arrFileNameFull, lReadSize);
        res = PERROR;
        goto __EXIT;
    }

    iWidth =
        (((COLOR_LONG)pData[7]) << 24) |
        (((COLOR_LONG)pData[6]) << 16) |
        (((COLOR_LONG)pData[5]) << 8) |
        (((COLOR_LONG)pData[4]) << 0) ;
    iHeight =
        (((COLOR_LONG)pData[11]) << 24) |
        (((COLOR_LONG)pData[10]) << 16) |
        (((COLOR_LONG)pData[9]) << 8) |
        (((COLOR_LONG)pData[8]) << 0) ;
    *pWidth = iWidth;
    *pHeight = iHeight;

    // read RGB data and trasform it into YUV Grey format
    *ppDest = (MUInt8 *)malloc(sizeof(MUInt8) * iWidth * iHeight * 2);
    if (NULL == *ppDest)
    {
        printf("failed to malloc size of %ld memory for *ppDest\n", (long)(sizeof(MUInt8) * (*pWidth) * (*pHeight)));
        res = PERROR;
        goto __EXIT;

    }

    fseek(pFile, dwOffset, SEEK_SET);
    int iChannel = 3;
    int iStep = iChannel * iWidth;
    int iOffSet = iStep % 4;
    int i, j;
    if (iOffSet != 0)
    {
        iOffSet = 4 - iOffSet;
    }
    pRGBDataLine = (MUInt8 *) malloc(sizeof(MUInt8) * (iStep + iOffSet));
    if (NULL == pRGBDataLine)
    {
        printf("failed to allocate size of %d memory for pRGBDataLine\n", sizeof(MUInt8) * (iStep + iOffSet));
        res = PERROR;
        goto __EXIT;
    }
    for (i = 0; i < iHeight; i++)
    {
        fread(pRGBDataLine, 1, iStep + iOffSet, pFile);
        for (j = 0; j < iWidth; j++)
        {
            //if (pRGBDataLine[j * iChannel] != 0 && pRGBDataLine[j * iChannel] != 255)
            if (255 == pRGBDataLine[j * iChannel])
            {
                (*ppDest)[(iHeight - 1 - i) * iWidth + j] = 0;
            }
            else if (0 == pRGBDataLine[j * iChannel])
            {
                (*ppDest)[(iHeight - 1 - i) * iWidth + j] = 255;
            }
            else
            {
                //printf("pRGBDataLine[%d]:%d invalid\n", j * iChannel, pRGBDataLine[j * iChannel]);
                (*ppDest)[(iHeight - 1 - i) * iWidth + j] = 255;
            }

        }
    }

__EXIT:
    if (pRGBDataLine != NULL)
    {
        free(pRGBDataLine);
        pRGBDataLine = NULL;
    }
    if (pFile != NULL)
    {
        fclose(pFile);
        pFile = NULL;
    }
    if (pData != NULL)
    {
        free(pData);
        pData = NULL;
    }
    return res;
}

MRESULT ConvertYuv420pToNV21(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight)
{
    if (NULL == pDest || NULL == pSource)
    {
        return PERROR;
    }
    if (iWidth <= 0 || iHeight <= 0)
    {
        return PERROR;
    }

    int iArea = iHeight * iWidth;
    int iSqarea = iArea >> 3;
    int iQarea = iArea >> 2;
    int iCount = iSqarea;
    const unsigned short * pU = (const unsigned short *) (pSource + iArea);
    const unsigned short * pV = (const unsigned short *) (pSource + iArea + iQarea);
    unsigned int * pUV = (unsigned int *)(pDest + iArea);
    memcpy(pDest, pSource, iArea);
    do
    {
        unsigned int uiU = *pU++;
        unsigned int uiV = *pV++;
        *pUV++ = ( ( (uiU & 0x00FF) << 8 ) |
                   ( (uiU & 0xFF00) << 16) |
                   ( (uiV & 0x00FF) )      |
                   ( (uiV & 0xFF00) << 8) );
    }
    while (--iCount);
    return MOK;
}

MRESULT ConvertYuv420pToNV12(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight)
{
    if (NULL == pDest || NULL == pSource)
    {
        return PERROR;
    }
    if (iWidth <= 0 || iHeight <= 0)
    {
        return PERROR;
    }

    int iArea = iHeight * iWidth;
    int iSqarea = iArea >> 3;
    int iQarea = iArea >> 2;
    int iCount = iSqarea;
    const unsigned short * pU = (const unsigned short *) (pSource + iArea);
    const unsigned short * pV = (const unsigned short *) (pSource + iArea + iQarea);
    unsigned int * pUV = (unsigned int *)(pDest + iArea);
    memcpy(pDest, pSource, iArea);
    do
    {
        unsigned int uiU = *pU++;
        unsigned int uiV = *pV++;
        *pUV++ = ( ( (uiV & 0x00FF) << 8 ) |
                   ( (uiV & 0xFF00) << 16) |
                   ( (uiU & 0x00FF) )      |
                   ( (uiU & 0xFF00) << 8) );
    }
    while (--iCount);
    return MOK;
}

MRESULT ConvertYuv420pToYUYV(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight)
{
    if (NULL == pDest || NULL == pSource)
    {
        return PERROR;
    }
    if (iWidth <= 0 || iHeight <= 0)
    {
        return PERROR;
    }

    int iStride = iWidth * iHeight;
    unsigned int x, y;
    for (y = 0; y < iHeight; ++y)
    {
        const MUInt8 *pY = pSource + y * iWidth;
        const MUInt8 *pU = pSource + iStride + (y / 2) * (iWidth / 2);
        const MUInt8 *pV = pSource + (iStride * 5) / 4 + (y / 2) * (iWidth / 2);
        for (x = 0; x < iWidth; x += 2)
        {
            *(pDest + 0) = pY[0];
            *(pDest + 1) = pU[0];
            *(pDest + 2) = pY[1];
            *(pDest + 3) = pV[0];
            pDest += 4;
            pY += 2;
            ++pU;
            ++pV;
        }
    }

    return MOK;
}

MRESULT ConvertYuv420pToI422H(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight)
{
    if (NULL == pDest || NULL == pSource)
    {
        return PERROR;
    }
    if (iWidth <= 0 || iHeight <= 0)
    {
        return PERROR;
    }

    int iStride = iWidth * iHeight;
    unsigned int x, y;
    MUInt8 * pDestU = pDest + iStride;
    MUInt8 * pDestV = pDestU + iStride / 2;
    memcpy(pDest, pSource, iStride);
    for (y = 0; y < iHeight; ++y)
    {
        const MUInt8 *pU = pSource + iStride + (y / 2) * (iWidth / 2);
        const MUInt8 *pV = pSource + (iStride * 5) / 4 + (y / 2) * (iWidth / 2);
        for (x = 0; x < iWidth; x += 2)
        {
            *pDestU++ = *pU++;
            *pDestV++ = *pV++;
        }
    }

    return MOK;
}

MRESULT ConvertYuv420pToLPI422H(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight)
{
    if (NULL == pDest || NULL == pSource)
    {
        return PERROR;
    }
    if (iWidth <= 0 || iHeight <= 0)
    {
        return PERROR;
    }

    int iStride = iWidth * iHeight;
    unsigned int x, y;
    MUInt8 * pDestUV = pDest + iStride;
    memcpy(pDest, pSource, iStride);
    for (y = 0; y < iHeight; ++y)
    {
        const MUInt8 *pU = pSource + iStride + (y / 2) * (iWidth / 2);
        const MUInt8 *pV = pSource + (iStride * 5) / 4 + (y / 2) * (iWidth / 2);
        for (x = 0; x < iWidth; x += 2)
        {
            *pDestUV++ = *pU++;
            *pDestUV++ = *pV++;
        }
    }

    return MOK;
}
//conver yuv422 to yuv420
int i;
for(i = 0; i < iHeight / 2; i++)
{
    memcpy(*ppImgData + iStride + i * iWidth / 2, pYuvRaw + iStride + i * iWidth, iWidth / 2);
    memcpy(*ppImgData + iStride * 5 / 4 + i * iWidth / 2, pYuvRaw + iStride * 3 / 2 + i * iWidth, iWidth / 2);
}




你可能感兴趣的:(YUV格式互转)