androidandroid-cameralibyuv

Issue with libyuv::ConvertToI420 on Android?


I have an onPreviewFrame callback set up. This gets a byte[] with NV21 data in it. I have set the preview size to 176*144. When device is held in landscape mode, byte[] with 176*144 dimensions is perfect but when device is held in portrait mode I still get byte[] with the same dimensions.

I want to rotate the byte[] by 90 degrees and obtain byte[] with dimensions 144*176.

So the question is, how to rotate the data, not just the preview image? Camera.Parameters.setRotation only affects taking the picture, not video. Camera.setDisplayOrientation specifically says it only affects the displaying preview, not the frame bytes:

This does not affect the order of byte array passed in      
onPreviewFrame(byte[], Camera), JPEG pictures, or recorded videos.

After checking out various posts I have found this one stating to use ConvertToI420 from libyuv.

Now the deal is I have compiled libyuv and able to call libyuv::ConvertToI420 method but the resulting I420 that I get is all messed up in terms of color and showing lines and all..... however the dimensions that I get are now 144*176, can check the image here.

The code snippet that i've used is as follows.

    //sourceWidth = 176 and sourceHeight = 144  
    unsigned char I420M = new unsigned char[(int)(sourceWidth*sourceHeight*1.5)];

    unsigned int YSize = sourceWidth * sourceHeight;
    // yuvPtr is the NV21 data passed from onPreviewCallback (from JAVA layer)
    const uint8* src_frame = const_cast<const uint8*>(yuvPtr);
    size_t src_size = YSize;

    uint8* pDstY = I420M;
    uint8* pDstU = I420M + YSize;
    uint8* pDstV = I420M + (YSize/4);

    libyuv::RotationMode mode;
    if(landscapeLeft){
        mode = libyuv::kRotate90;
    }else{
        mode = libyuv::kRotate270;
    }


    uint32 format = libyuv::FOURCC_NV21;
    int retVal = libyuv::ConvertToI420(src_frame, src_size,
              pDstY, sourceHeight,
              pDstU, (sourceHeight/2),
              pDstV, (sourceHeight/2),
              0, 0,
              sourceWidth, sourceHeight,
              sourceWidth, sourceHeight,
              mode,
              format);

I don't wish to crop the image, just rotate it by 90 (clockwise/anticlockwise) the attached image is for kRotate90.

Could anyone please point me where am going wrong, I strongly doubt it has o do something with the parameters am passing to the ConvertToI420 method.

Any help appreciated.


Solution

  • I have figured out what was going wrong. The above code snippet works perfectly well and I420M contains the rotated YUV with 144*176 dimensions.

    The problem was the in the way I was converting the I420M to jbyte[] while passing it back to Java Layer.