content: /*
   * Copyright (C) 2011-2014 GUIGUI Simon, fyhertz@gmail.com
   * 
   * This file is part of Spydroid (http://code.google.com/p/spydroid-ipcamera/)
   * 
   * Spydroid is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 3 of the License, or
   * (at your option) any later version.
   * 
   * This source code is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU General Public License
   * along with this source code; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  package net.majorkernelpanic.streaming.hw;
  
  import java.nio.ByteBuffer;
  
  import android.media.MediaCodecInfo;
  
  /**
   * Converts from NV21 to YUV420 semi planar or planar.
   */		
  public class NV21Convertor {
  
  	private int mSliceHeight, mHeight;
  	private int mStride, mWidth;
  	private int mSize;
  	private boolean mPlanar, mPanesReversed = false;
  	private int mYPadding;
  	private byte[] mBuffer; 
  	ByteBuffer mCopy;
  	
  	public void setSize(int width, int height) {
  		mHeight = height;
  		mWidth = width;
  		mSliceHeight = height;
  		mStride = width;
  		mSize = mWidth*mHeight;
  	}
  	
  	public void setStride(int width) {
  		mStride = width;
  	}
  	
  	public void setSliceHeigth(int height) {
  		mSliceHeight = height;
  	}
  	
  	public void setPlanar(boolean planar) {
  		mPlanar = planar;
  	}
  	
  	public void setYPadding(int padding) {
  		mYPadding = padding;
  	}
  	
  	public int getBufferSize() {
  		return 3*mSize/2;
  	}
  	
  	public void setEncoderColorFormat(int colorFormat) {
  		switch (colorFormat) {
  		case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
  		case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
  		case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:
  			setPlanar(false);
  			break;	
  		case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
  		case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
  			setPlanar(true);
  			break;
  		}
  	}
  	
  	public void setColorPanesReversed(boolean b) {
  		mPanesReversed = b;
  	}
  	
  	public int getStride() {
  		return mStride;
  	}
  
  	public int getSliceHeigth() {
  		return mSliceHeight;
  	}
  
  	public int getYPadding() {
  		return mYPadding;
  	}
  	
  	
  	public boolean getPlanar() {
  		return mPlanar;
  	}
  	
  	public boolean getUVPanesReversed() {
  		return mPanesReversed;
  	}
  	
  	public void convert(byte[] data, ByteBuffer buffer) {
  		byte[] result = convert(data);
  		buffer.put(result, 0, result.length);
  	}
  	
  	public byte[] convert(byte[] data) {
  
  		// A buffer large enough for every case
  		if (mBuffer==null || mBuffer.length != 3*mSliceHeight*mStride/2+mYPadding) {
  			mBuffer = new byte[3*mSliceHeight*mStride/2+mYPadding];
  		}
  		
  		if (!mPlanar) {
  			if (mSliceHeight==mHeight && mStride==mWidth) {
  				// Swaps U and V
  				if (!mPanesReversed) {
  					for (int i = mSize; i < mSize+mSize/2; i += 2) {
  						mBuffer[0] = data[i+1];
  						data[i+1] = data[i];
  						data[i] = mBuffer[0]; 
  					}
  				}
  				if (mYPadding>0) {
  					System.arraycopy(data, 0, mBuffer, 0, mSize);
  					System.arraycopy(data, mSize, mBuffer, mSize+mYPadding, mSize/2);
  					return mBuffer;
  				}
  				return data;
  			}
  		} else {
  			if (mSliceHeight==mHeight && mStride==mWidth) {
  				// De-interleave U and V
  				if (!mPanesReversed) {
  					for (int i = 0; i < mSize/4; i+=1) {
  						mBuffer[i] = data[mSize+2*i+1];
  						mBuffer[mSize/4+i] = data[mSize+2*i];
  					}
  				} else {
  					for (int i = 0; i < mSize/4; i+=1) {
  						mBuffer[i] = data[mSize+2*i];
  						mBuffer[mSize/4+i] = data[mSize+2*i+1];
  					}
  				}
  				if (mYPadding == 0) {
  					System.arraycopy(mBuffer, 0, data, mSize, mSize/2);
  				} else {
  					System.arraycopy(data, 0, mBuffer, 0, mSize);
  					System.arraycopy(mBuffer, 0, mBuffer, mSize+mYPadding, mSize/2);
  					return mBuffer;
  				}
  				return data;
  			}
  		}
  		
  		return data;
  	}	
  	
  }
  