Sujith Ks
Sujith Ks

Reputation: 360

Decoding NV21 image from android camera but it's color is not proper for the image

this is the code I used to rotate the image. I need to send it through the network.Image is rotating properly but the image i am getting is not having proper color. I have written this code as native in cpp. DecodeNV21() having 3 parameters width,height,rotation.The width and height I am getting is 640,480.If the rotation is portrait variable rotation is 1 and the height and width will be 640,480.and the rotation is 0 which is landscape then the width and height 640 and 480. please any one knows about it please help me to solve this issue.Portrait mode rotation is correct.but the landscape mode having the issue.

void DecodeNV21(int SrcHeight,int SrcWidth,int rotation)
 /* decodes NV21-encoded image data, which is the default camera preview image format. */
 {
  //int SrcWidth = encoderContext.m_width;
  //int SrcHeight = encoderContext.m_height;
  int Rotate = rotation;
  int Alpha = 0xFF;
   int AlphaMask = Alpha << 24;
 /* Rotation involves accessing either the source or destination pixels in a
   non-sequential fashion. Since the source is smaller, I figure it's less
   cache-unfriendly to go jumping around that. */
    int DstWidth = (Rotate & 1) != 0 ? SrcHeight : SrcWidth;
    int DstHeight = (Rotate & 1) != 0 ? SrcWidth : SrcHeight;
    bool DecrementRow = Rotate > 1;
    bool DecrementCol = Rotate == 1 || Rotate == 2;
    int LumaRowStride = (Rotate & 1) != 0 ? 1 : SrcWidth;
    int LumaColStride = (Rotate & 1) != 0 ? SrcWidth : 1;
    int ChromaRowStride = (Rotate & 1) != 0 ? 2 : SrcWidth;
    int ChromaColStride = (Rotate & 1) != 0 ? SrcWidth : 2;
  //  LOGME("DecodeNV21 decoding w:%d,h:%d,DecrementRow:%d,ChromaRowStride:%d, DecrementCol:%d,ChromaColStride:%d,LumaRowStride%d,LumaColStride:%d",DstWidth,DstHeight,DecrementRow,ChromaRowStride, DecrementCol,ChromaColStride,LumaRowStride,LumaColStride);
   int dst = 0;
   int i=0;
   for (int row = DecrementRow ? DstHeight : 0;;)
     {
       if (row == (DecrementRow ? 0 : DstHeight))
           break;
       if (DecrementRow)
         {
           --row;
         } /*if*/
       for (int col = DecrementCol ? DstWidth : 0;;)
         {
           if (col == (DecrementCol ? 0 : DstWidth))
               break;
           if (DecrementCol)
             {
               --col;
             } /*if*/
            int Y = 0xff & (int)byte_array[row * LumaRowStride + col * LumaColStride]; /* [0 .. 255] */
         /* U/V data follows entire luminance block, downsampled to half luminance
           resolution both horizontally and vertically */
         /* decoding follows algorithm shown at
           <http://www.mail-archive.com/[email protected]/msg14558.html>,
           except it gets red and blue the wrong way round */
            int Cr =
               (0xff & (int)byte_array[SrcHeight * SrcWidth + row / 2 * ChromaRowStride + col / 2 * ChromaColStride]) - 128;
                 /* [-128 .. +127] */
            int Cb =
               (0xff & (int)byte_array[SrcHeight * SrcWidth + row / 2 * ChromaRowStride + col / 2 * ChromaColStride + 1]) - 128;
                 /* [-128 .. +127] */
                   int r,g,b;
           int color =
                   AlphaMask
               |
                       (r=max(
                           min(
                               (int)(
                                       Y
                                   +
                                       Cr
                                   +
                                       (Cr >> 1)
                                   +
                                       (Cr >> 2)
                                   +
                                       (Cr >> 6)
                               ),
                               255
                             ),
                             0
                         ))
                   <<
                       16 /* red */
               |
                       (g=max(
                           min(
                               (int)(
                                       Y
                                   -
                                       (Cr >> 2)
                                   +
                                       (Cr >> 4)
                                   +
                                       (Cr >> 5)
                                   -
                                       (Cb >> 1)
                                   +
                                       (Cb >> 3)
                                   +
                                       (Cb >> 4)
                                   +
                                       (Cb >> 5)
                               ),
                               255
                             ),
                           0
                         ))
                   <<
                       8 /* green */
               |  (b=max(
                       min(
                           (int)(
                                   Y
                               +
                                   Cb
                               +
                                   (Cb >> 2)
                               +
                                   (Cb >> 3)
                               +
                                   (Cb >> 5)
                           ),
                           255
                         ),
                       0
                     )); /* blue */
                        //color = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
             TypeConvert::udwordToBytes(color, encoderContext.m_in_Array_Encode,i * 4);
      i++;
           if (!DecrementCol)
             {
               ++col;
             } /*if*/
         } /*for*/
       if (!DecrementRow)
         {
           ++row;
         } /*if*/
     } /*for*/
 } /*DecodeNV21*/

Upvotes: 1

Views: 733

Answers (1)

JasonYang
JasonYang

Reputation: 786

Don't really want to sort through your old code, but just let me paste my adopted solution (got it from somewhere I forgot...) to rotate the image 90, 180, 270 degree and return by a byte array. So for instance, you are in portrait mode, you can rotate 90 degree for the back camera, and 270 degree to the front camera. Other rotation modes can be implemented according to similar patterns. I think it should be enough for you to continue the path.

private byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight)
{

    byte [] yuv = new byte[imageWidth*imageHeight*3/2];
    // Rotate the Y luma
    int i = 0;
    for(int x = 0;x < imageWidth;x++)
    {
        for(int y = imageHeight-1;y >= 0;y--)                               
        {
            yuv[i] = data[y*imageWidth+x];
            i++;
        }

    }
    // Rotate the U and V color components 
    i = imageWidth*imageHeight*3/2-1;
    for(int x = imageWidth-1;x > 0;x=x-2)
    {
        for(int y = 0;y < imageHeight/2;y++)                                
        {
            yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+x];
            i--;
            yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+(x-1)];
            i--;
        }
    }
    return yuv;
}

private byte[] rotateYUV420Degree180(byte[] data, int imageWidth, int imageHeight) 
{
    byte [] yuv = new byte[imageWidth*imageHeight*3/2];
    int i = 0;
    int count = 0;

    for (i = imageWidth * imageHeight - 1; i >= 0; i--) {
        yuv[count] = data[i];
        count++;
    }

    i = imageWidth * imageHeight * 3 / 2 - 1;
    for (i = imageWidth * imageHeight * 3 / 2 - 1; i >= imageWidth
            * imageHeight; i -= 2) {
        yuv[count++] = data[i - 1];
        yuv[count++] = data[i];
    }
    return yuv;
}

private byte[] rotateYUV420Degree270(byte[] data, int imageWidth, int imageHeight) 
{
    byte [] yuv = new byte[imageWidth*imageHeight*3/2];
    int nWidth = 0, nHeight = 0;
    int wh = 0;
    int uvHeight = 0;
    if(imageWidth != nWidth || imageHeight != nHeight)
    {
        nWidth = imageWidth;
        nHeight = imageHeight;
        wh = imageWidth * imageHeight;
        uvHeight = imageHeight >> 1;//uvHeight = height / 2
    }

    //–˝◊™Y
    int k = 0;
    for(int i = 0; i < imageWidth; i++) {
        int nPos = 0;
        for(int j = 0; j < imageHeight; j++) {
            yuv[k] = data[nPos + i];
            k++;
            nPos += imageWidth;
        }
    }

    for(int i = 0; i < imageWidth; i+=2){
        int nPos = wh;
        for(int j = 0; j < uvHeight; j++) {
            yuv[k] = data[nPos + i];
            yuv[k + 1] = data[nPos + i + 1];
            k += 2;
            nPos += imageWidth;
        }
    }
    return rotateYUV420Degree180(yuv,imageWidth,imageHeight);
}

Upvotes: 1

Related Questions