/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <semaphore.h>
#include <pthread.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>

#include <ui/DisplayInfo.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/ISurfaceComposer.h>

#include <system/camera.h>

#include <camera/Camera.h>
#include <camera/ICamera.h>
#include <camera/CameraParameters.h>
#include <media/mediarecorder.h>

#include <utils/RefBase.h>
#include <utils/Mutex.h>
#include <utils/Condition.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <cutils/memory.h>
#include <SkImageDecoder.h>
#include <SkImageEncoder.h>
#include <MediaCodec.h>
#include <OMX_IVCommon.h>
#include <foundation/AMessage.h>
#include <media/ICrypto.h>
#include <MediaMuxer.h>
#include <foundation/ABuffer.h>
#include <MediaErrors.h>
#include <gralloc_priv.h>
#include <math.h>

#include "qcamera_test.h"
#include "cam_types.h"
#include "mm_camera_dbg.h"

#define VIDEO_BUF_ALLIGN(size, allign) \
  (((size) + (allign-1)) & (typeof(size))(~(allign-1)))

namespace qcamera {

using namespace android;

int CameraContext::JpegIdx = 0;
int CameraContext::mPiPIdx = 0;
const char CameraContext::KEY_ZSL[] = "zsl";

/*===========================================================================
 * FUNCTION   : previewCallback
 *
 * DESCRIPTION: preview callback preview mesages are enabled
 *
 * PARAMETERS :
 *   @mem : preview buffer
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::previewCallback(const sp<IMemory>& mem)
{
    printf("PREVIEW Callback %p", mem->pointer());
    uint8_t *ptr = (uint8_t*) mem->pointer();
    if (NULL != ptr) {
        printf("PRV_CB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
                ptr[0],
                ptr[1],
                ptr[2],
                ptr[3],
                ptr[4],
                ptr[5],
                ptr[6],
                ptr[7],
                ptr[8],
                ptr[9]);
    } else {
        ALOGE(" no preview for NULL CB\n");
    }
}

/*===========================================================================
 * FUNCTION   : useLock
 *
 * DESCRIPTION: Mutex lock for CameraContext
 *
 * PARAMETERS : none
 *
 * RETURN     : none
 *==========================================================================*/
void CameraContext::useLock()
{
    Mutex::Autolock l(mLock);
    while (mInUse) {
        mCond.wait(mLock);
    }
    mInUse = true;
}

/*===========================================================================
 * FUNCTION   : signalFinished
 *
 * DESCRIPTION: Mutex unlock CameraContext
 *
 * PARAMETERS : none
 *
 * RETURN     : none
 *==========================================================================*/
void CameraContext::signalFinished()
{
    Mutex::Autolock l(mLock);
    mInUse = false;
    mCond.signal();
}

/*===========================================================================
 * FUNCTION   : saveFile
 *
 * DESCRIPTION: helper function for saving buffers on filesystem
 *
 * PARAMETERS :
 *   @mem : buffer to save to filesystem
 *   @path: File path
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::saveFile(const sp<IMemory>& mem, String8 path)
{
    unsigned char *buff = NULL;
    ssize_t size;
    int fd = -1;

    if (mem == NULL) {
        return BAD_VALUE;
    }

    fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0655);
    if(fd < 0) {
        printf("Unable to open file %s %s\n", path.string(), strerror(fd));
        return -errno;
    }

    size = (ssize_t)mem->size();
    if (size <= 0) {
        printf("IMemory object is of zero size\n");
        close(fd);
        return BAD_VALUE;
    }

    buff = (unsigned char *)mem->pointer();
    if (!buff) {
        printf("Buffer pointer is invalid\n");
        close(fd);
        return BAD_VALUE;
    }

    if (size != write(fd, buff, (size_t)size)) {
        printf("Bad Write error (%d)%s\n", errno, strerror(errno));
        close(fd);
        return INVALID_OPERATION;
    }

    printf("%s: buffer=%p, size=%lld stored at %s\n",
            __FUNCTION__, buff, (long long int) size, path.string());

    if (fd >= 0)
        close(fd);

    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : PiPCopyToOneFile
 *
 * DESCRIPTION: Copy the smaller picture to the bigger one
 *
 * PARAMETERS :
 *   @bitmap0 : Decoded image buffer 0
 *   @bitmap1 : Decoded image buffer 1
 *
 * RETURN     : decoded picture in picture in SkBitmap
 *==========================================================================*/
SkBitmap * CameraContext::PiPCopyToOneFile(
    SkBitmap *bitmap0, SkBitmap *bitmap1)
{
    size_t size0;
    size_t size1;
    SkBitmap *src;
    SkBitmap *dst;
    unsigned int dstOffset;
    unsigned int srcOffset;

    if (bitmap0 == NULL || bitmap1 == NULL) {
        ALOGE(" bitmap0 : %p, bitmap1 : %p\n",  bitmap0, bitmap1);
        return NULL;
    }

    size0 = bitmap0->getSize();
    if (size0 <= 0) {
        printf("Decoded image 0 is of zero size\n");
        return NULL;
    }

    size1 = bitmap1->getSize();
        if (size1 <= 0) {
            printf("Decoded image 1 is of zero size\n");
            return NULL;
        }

    if (size0 > size1) {
        dst = bitmap0;
        src = bitmap1;
    } else if (size1 > size0){
        dst = bitmap1;
        src = bitmap0;
    } else {
        printf("Picture size should be with different size!\n");
        return NULL;
    }

    for (unsigned int i = 0; i < (unsigned int)src->height(); i++) {
        dstOffset = i * (unsigned int)dst->width() * mfmtMultiplier;
        srcOffset = i * (unsigned int)src->width() * mfmtMultiplier;
        memcpy(((unsigned char *)dst->getPixels()) + dstOffset,
                ((unsigned char *)src->getPixels()) + srcOffset,
                (unsigned int)src->width() * mfmtMultiplier);
    }

    return dst;
}

/*===========================================================================
 * FUNCTION   : decodeJPEG
 *
 * DESCRIPTION: decode jpeg input buffer.
 *
 * PARAMETERS :
 *   @mem     : buffer to decode
 *   @skBM    : decoded buffer
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code

 *==========================================================================*/
status_t CameraContext::decodeJPEG(const sp<IMemory>& mem, SkBitmap *skBM)
{
#ifndef USE_SDK_20_OR_HIGHER
    SkBitmap::Config prefConfig = SkBitmap::kARGB_8888_Config;
    const void *buff = NULL;
    size_t size;

    buff = (const void *)mem->pointer();
    size= mem->size();

    switch(prefConfig) {
        case SkBitmap::kARGB_8888_Config:
        {
            mfmtMultiplier = 4;
        }
            break;

        case SkBitmap::kARGB_4444_Config:
        {
            mfmtMultiplier = 2;
        }
        break;

        case SkBitmap::kRGB_565_Config:
        {
            mfmtMultiplier = 2;
        }
        break;

        case SkBitmap::kIndex8_Config:
        {
            mfmtMultiplier = 4;
        }
        break;

        case SkBitmap::kA8_Config:
        {
            mfmtMultiplier = 4;
        }
        break;

        default:
        {
            mfmtMultiplier = 0;
            printf("Decode format is not correct!\n");
        }
        break;
    }

    if (SkImageDecoder::DecodeMemory(buff, size, skBM, prefConfig,
            SkImageDecoder::kDecodePixels_Mode) == false) {
        printf("%s():%d:: Failed during jpeg decode\n",__FUNCTION__,__LINE__);
        return BAD_VALUE;
    }
#else
    SkColorType prefConfig = kRGBA_8888_SkColorType;
    const void *buff = NULL;
    size_t size;

    buff = (const void *)mem->pointer();
    size= mem->size();

    switch(prefConfig) {
        case kRGBA_8888_SkColorType:
        {
            mfmtMultiplier = 4;
        }
        break;

        case kBGRA_8888_SkColorType:
        {
            mfmtMultiplier = 4;
        }
        break;

        case kARGB_4444_SkColorType:
        {
            mfmtMultiplier = 2;
        }
        break;

        case kRGB_565_SkColorType:
        {
            mfmtMultiplier = 2;
        }
        break;

        case kIndex_8_SkColorType:
        {
            mfmtMultiplier = 4;
        }
        break;

        case kAlpha_8_SkColorType:
        {
            mfmtMultiplier = 4;
        }
        break;

        default:
        {
            mfmtMultiplier = 0;
            printf("Decode format is not correct!\n");
        }
        break;
    }

    if (SkImageDecoder::DecodeMemory(buff, size, skBM, prefConfig,
            SkImageDecoder::kDecodePixels_Mode) == false) {
        printf("%s():%d:: Failed during jpeg decode\n",__FUNCTION__,__LINE__);
        return BAD_VALUE;
    }

#endif
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : encodeJPEG
 *
 * DESCRIPTION: encode the decoded input buffer.
 *
 * PARAMETERS :
 *   @stream  : SkWStream
 *   @bitmap  : SkBitmap decoded image to encode
 *   @path    : File path
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code

 *==========================================================================*/
status_t CameraContext::encodeJPEG(SkWStream * stream,
    const SkBitmap *bitmap, String8 path)
{
    int qFactor = 100;

    skJpegEnc = SkImageEncoder::Create(SkImageEncoder::kJPEG_Type);
    if (!skJpegEnc) {
        ALOGE(" skJpegEnc is NULL\n");
        return BAD_VALUE;
    }

    if (skJpegEnc->encodeStream(stream, *bitmap, qFactor) == false) {
        return BAD_VALUE;
    }

    FILE *fh = fopen(path.string(), "r+");
    if ( !fh ) {
        printf("Could not open file %s\n", path.string());
        return BAD_VALUE;
    }

    fseek(fh, 0, SEEK_END);
    size_t len = (size_t)ftell(fh);
    rewind(fh);

    if( !len ) {
        printf("File %s is empty !\n", path.string());
        fclose(fh);
        return BAD_VALUE;
    }

    unsigned char *buff = (unsigned char*)malloc(len);
    if (!buff) {
        printf("Cannot allocate memory for buffer reading!\n");
        return BAD_VALUE;
    }

    size_t readSize = fread(buff, 1, len, fh);
    if (readSize != len) {
        printf("Reading error\n");
        return BAD_VALUE;
    }

    status_t ret = ReadSectionsFromBuffer(buff, len, READ_ALL);
    if (ret != NO_ERROR) {
        printf("Cannot read sections from buffer\n");
        DiscardData();
        DiscardSections();
        return BAD_VALUE;
    }
    free(buff);
    rewind(fh);

    unsigned char temp = 0xff;
    size_t writeSize = fwrite(&temp, sizeof(unsigned char), 1, fh);
    if (1 != writeSize) {
        printf("Writing error\n");
    }
    temp = 0xd8;
    fwrite(&temp, sizeof(unsigned char), 1, fh);

    for (size_t i = 0; i < mSectionsRead; i++) {
        switch((mSections[i].Type)) {

        case 0x123:
            fwrite(mSections[i].Data, sizeof(unsigned char),
                mSections[i].Size, fh);
            break;

        case 0xe0:
            temp = 0xff;
            fwrite(&temp, sizeof(unsigned char), 1, fh);
            temp = 0xe1;
            fwrite(&temp, sizeof(unsigned char), 1, fh);
            fwrite(mJEXIFSection.Data, sizeof(unsigned char),
                mJEXIFSection.Size, fh);
            break;

        default:
            temp = 0xff;
            fwrite(&temp, sizeof(unsigned char), 1, fh);
            fwrite(&mSections[i].Type, sizeof(unsigned char), 1, fh);
            fwrite(mSections[i].Data, sizeof(unsigned char),
                mSections[i].Size, fh);
            break;
        }
    }
    fseek(fh, 0, SEEK_END);
    len = (size_t)ftell(fh);
    rewind(fh);
    printf("%s: buffer=%p, size=%zu stored at %s\n",
            __FUNCTION__, bitmap->getPixels(), len, path.string());

    free(mJEXIFSection.Data);
    DiscardData();
    DiscardSections();
    fclose(fh);
    ret = NO_ERROR;

    return ret;
}

/*===========================================================================
 * FUNCTION   : readSectionsFromBuffer
 *
 * DESCRIPTION: read all jpeg sections of input buffer.
 *
 * PARAMETERS :
 *   @mem : buffer to read from Metadata Sections
 *   @buffer_size: buffer size
 *   @ReadMode: Read mode - all, jpeg or exif
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::ReadSectionsFromBuffer (unsigned char *buffer,
        size_t buffer_size, ReadMode_t ReadMode)
{
    int a;
    size_t pos = 0;
    int HaveCom = 0;
    mSectionsAllocated = 10;

    mSections = (Sections_t *)malloc(sizeof(Sections_t) * mSectionsAllocated);
    if (!mSections) {
        printf(" not enough memory\n");
        return BAD_VALUE;
    }

    if (!buffer) {
        printf("Input buffer is null\n");
        return BAD_VALUE;
    }

    if (buffer_size < 1) {
        printf("Input size is 0\n");
        return BAD_VALUE;
    }

    a = (int) buffer[pos++];

    if (a != 0xff || buffer[pos++] != M_SOI){
        printf("No valid image\n");
        return BAD_VALUE;
    }

    for(;;){
        size_t itemlen;
        int marker = 0;
        size_t ll,lh;
        unsigned char * Data;

        CheckSectionsAllocated();

        // The call to CheckSectionsAllocated() may reallocate mSections
        // so need to check for NULL again.
        if (mSections == NULL) {
            printf(" not enough memory\n");
            return BAD_VALUE;
        }

        for (a = 0; a <= 16; a++){
            marker = buffer[pos++];
            if (marker != 0xff) break;

            if (a >= 16){
                fprintf(stderr,"too many padding bytes\n");
                return BAD_VALUE;
            }
        }

        mSections[mSectionsRead].Type = marker;

        // Read the length of the section.
        lh = buffer[pos++];
        ll = buffer[pos++];

        itemlen = (lh << 8) | ll;

        if (itemlen < 2) {
            ALOGE("invalid marker");
            return BAD_VALUE;
        }

        mSections[mSectionsRead].Size = itemlen;

        Data = (unsigned char *)malloc(itemlen);
        if (Data == NULL) {
            ALOGE("Could not allocate memory");
            return NO_MEMORY;
        }
        mSections[mSectionsRead].Data = Data;

        // Store first two pre-read bytes.
        Data[0] = (unsigned char)lh;
        Data[1] = (unsigned char)ll;

        if (pos+itemlen-2 > buffer_size) {
            ALOGE("Premature end of file?");
            return BAD_VALUE;
        }

        memcpy(Data+2, buffer+pos, itemlen-2); // Read the whole section.
        pos += itemlen-2;

        mSectionsRead += 1;

        switch(marker){

            case M_SOS:   // stop before hitting compressed data
                // If reading entire image is requested, read the rest of the
                // data.
                if (ReadMode & READ_IMAGE){
                    size_t size;
                    // Determine how much file is left.
                    size = buffer_size - pos;

                    if (size < 1) {
                        ALOGE("could not read the rest of the image");
                        return BAD_VALUE;
                    }
                    Data = (unsigned char *)malloc(size);
                    if (Data == NULL) {
                        ALOGE("%d: could not allocate data for entire "
                                "image size: %d", __LINE__, size);
                        return BAD_VALUE;
                    }

                    memcpy(Data, buffer+pos, size);

                    CheckSectionsAllocated();

                    // The call to CheckSectionsAllocated()
                    // may reallocate mSections
                    // so need to check for NULL again.
                    if (mSections == NULL) {
                        printf(" not enough memory\n");
                        return BAD_VALUE;
                    }

                    mSections[mSectionsRead].Data = Data;
                    mSections[mSectionsRead].Size = size;
                    mSections[mSectionsRead].Type = PSEUDO_IMAGE_MARKER;
                    mSectionsRead ++;
                    mHaveAll = 1;
                }
                return NO_ERROR;

            case M_EOI:   // in case it's a tables-only JPEG stream
                ALOGE("No image in jpeg!\n");
                return BAD_VALUE;

            case M_COM: // Comment section
                if (HaveCom || ((ReadMode & READ_METADATA) == 0)){
                    // Discard this section.
                    free(mSections[--mSectionsRead].Data);
                }
                break;

            case M_JFIF:
                // Regular jpegs always have this tag, exif images have the
                // exif marker instead, althogh ACDsee will write images
                // with both markers.
                // this program will re-create this marker on absence of exif
                // marker.
                // hence no need to keep the copy from the file.
                if (ReadMode & READ_METADATA){
                    if (memcmp(Data+2, "JFIF", 4) == 0) {
                        break;
                    }
                    free(mSections[--mSectionsRead].Data);
                }
                break;

            case M_EXIF:
                // There can be different section using the same marker.
                if (ReadMode & READ_METADATA){
                    if (memcmp(Data+2, "Exif", 4) == 0){
                        break;
                    }else if (memcmp(Data+2, "http:", 5) == 0){
                        // Change tag for internal purposes.
                        mSections[mSectionsRead-1].Type = M_XMP;
                        break;
                    }
                }
                // Oterwise, discard this section.
                free(mSections[--mSectionsRead].Data);
                break;

            case M_IPTC:
                if (ReadMode & READ_METADATA){
                    // Note: We just store the IPTC section.
                    // Its relatively straightforward
                    // and we don't act on any part of it,
                    // so just display it at parse time.
                }else{
                    free(mSections[--mSectionsRead].Data);
                }
                break;

            case M_SOF0:
            case M_SOF1:
            case M_SOF2:
            case M_SOF3:
            case M_SOF5:
            case M_SOF6:
            case M_SOF7:
            case M_SOF9:
            case M_SOF10:
            case M_SOF11:
            case M_SOF13:
            case M_SOF14:
            case M_SOF15:
                break;
            default:
                // Skip any other sections.
                break;
        }
    }
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : CheckSectionsAllocated
 *
 * DESCRIPTION: Check allocated jpeg sections.
 *
 * PARAMETERS : none
 *
 * RETURN     : none

 *==========================================================================*/
void CameraContext::CheckSectionsAllocated(void)
{
    if (mSectionsRead > mSectionsAllocated){
        ALOGE("allocation screw up");
    }
    if (mSectionsRead >= mSectionsAllocated){
        mSectionsAllocated += mSectionsAllocated +1;
        mSections = (Sections_t *)realloc(mSections,
            sizeof(Sections_t) * mSectionsAllocated);
        if (mSections == NULL){
            ALOGE("could not allocate data for entire image");
        }
    }
}

/*===========================================================================
 * FUNCTION   : findSection
 *
 * DESCRIPTION: find the desired Section of the JPEG buffer.
 *
 * PARAMETERS :
 *  @SectionType: Section type
 *
 * RETURN     : return the found section

 *==========================================================================*/
CameraContext::Sections_t *CameraContext::FindSection(int SectionType)
{
    for (unsigned int a = 0; a < mSectionsRead; a++) {
        if (mSections[a].Type == SectionType){
            return &mSections[a];
        }
    }
    // Could not be found.
    return NULL;
}


/*===========================================================================
 * FUNCTION   : DiscardData
 *
 * DESCRIPTION: DiscardData
 *
 * PARAMETERS : none
 *
 * RETURN     : none

 *==========================================================================*/
void CameraContext::DiscardData()
{
    for (unsigned int a = 0; a < mSectionsRead; a++) {
        free(mSections[a].Data);
    }

    mSectionsRead = 0;
    mHaveAll = 0;
}

/*===========================================================================
 * FUNCTION   : DiscardSections
 *
 * DESCRIPTION: Discard allocated sections
 *
 * PARAMETERS : none
 *
 * RETURN     : none

 *==========================================================================*/
void CameraContext::DiscardSections()
{
    free(mSections);
    mSectionsAllocated = 0;
    mHaveAll = 0;
}

/*===========================================================================
 * FUNCTION   : notify
 *
 * DESCRIPTION: notify callback
 *
 * PARAMETERS :
 *   @msgType : type of callback
 *   @ext1: extended parameters
 *   @ext2: extended parameters
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2)
{
    printf("Notify cb: %d %d %d\n", msgType, ext1, ext2);

    if (( msgType & CAMERA_MSG_PREVIEW_FRAME)
#ifndef VANILLA_HAL
            && (ext1 == CAMERA_FRAME_DATA_FD)
#endif
       )
    {
        int fd = dup(ext2);
        printf("notify Preview Frame fd: %d dup fd: %d\n", ext2, fd);
        close(fd);
    }

    if ( msgType & CAMERA_MSG_FOCUS ) {
        printf("AutoFocus %s \n",
               (ext1) ? "OK" : "FAIL");
    }

    if ( msgType & CAMERA_MSG_SHUTTER ) {
        printf("Shutter done \n");
    }

    if ( msgType & CAMERA_MSG_ERROR) {
        printf("Camera Test CAMERA_MSG_ERROR\n");
        stopPreview();
        closeCamera();
    }
}

/*===========================================================================
 * FUNCTION   : postData
 *
 * DESCRIPTION: handles data callbacks
 *
 * PARAMETERS :
 *   @msgType : type of callback
 *   @dataPtr: buffer data
 *   @metadata: additional metadata where available
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::postData(int32_t msgType,
                             const sp<IMemory>& dataPtr,
                             camera_frame_metadata_t *metadata)
{
    mInterpr->PiPLock();
    Size currentPictureSize = mSupportedPictureSizes.itemAt(
        mCurrentPictureSizeIdx);
    unsigned char *buff = NULL;
    size_t size;
    status_t ret = 0;

    memset(&mJEXIFSection, 0, sizeof(mJEXIFSection)),

    printf("Data cb: %d\n", msgType);

    if ( msgType & CAMERA_MSG_PREVIEW_FRAME ) {
        previewCallback(dataPtr);
    }

    if ( msgType & CAMERA_MSG_RAW_IMAGE ) {
        printf("RAW done \n");
    }

    if (msgType & CAMERA_MSG_POSTVIEW_FRAME) {
        printf("Postview frame \n");
    }

    if (msgType & CAMERA_MSG_COMPRESSED_IMAGE ) {
        String8 jpegPath;
        jpegPath = jpegPath.format(QCAMERA_DUMP_FRM_LOCATION"img_%d.jpg",
                JpegIdx);
        if (!mPiPCapture) {
            // Normal capture case
            printf("JPEG done\n");
            saveFile(dataPtr, jpegPath);
            JpegIdx++;
        } else {
            // PiP capture case
            SkFILEWStream *wStream;
            ret = decodeJPEG(dataPtr, &skBMtmp);
            if (NO_ERROR != ret) {
                printf("Error in decoding JPEG!\n");
                mInterpr->PiPUnlock();
                return;
            }

            mWidthTmp = currentPictureSize.width;
            mHeightTmp = currentPictureSize.height;
            PiPPtrTmp = dataPtr;
            // If there are two jpeg buffers
            if (mPiPIdx == 1) {
                printf("PiP done\n");

                // Find the the capture with higher width and height and read
                // its jpeg sections
                if ((mInterpr->camera[0]->mWidthTmp * mInterpr->camera[0]->mHeightTmp) >
                        (mInterpr->camera[1]->mWidthTmp * mInterpr->camera[1]->mHeightTmp)) {
                    buff = (unsigned char *)PiPPtrTmp->pointer();
                    size= PiPPtrTmp->size();
                } else if ((mInterpr->camera[0]->mWidthTmp * mInterpr->camera[0]->mHeightTmp) <
                        (mInterpr->camera[1]->mWidthTmp * mInterpr->camera[1]->mHeightTmp)) {
                    buff = (unsigned char *)PiPPtrTmp->pointer();
                    size= PiPPtrTmp->size();
                } else {
                    printf("Cannot take PiP. Images are with the same width"
                            " and height size!!!\n");
                    mInterpr->PiPUnlock();
                    return;
                }

                if (buff != NULL && size != 0) {
                    ret = ReadSectionsFromBuffer(buff, size, READ_ALL);
                    if (ret != NO_ERROR) {
                        printf("Cannot read sections from buffer\n");
                        DiscardData();
                        DiscardSections();
                        mInterpr->PiPUnlock();
                        return;
                    }

                    mJEXIFTmp = FindSection(M_EXIF);
                    if (!mJEXIFTmp) {
                        ALOGE("skBMDec is null\n");
                        DiscardData();
                        DiscardSections();
                        return;
                    }
                    mJEXIFSection = *mJEXIFTmp;
                    mJEXIFSection.Data = (unsigned char*)malloc(mJEXIFTmp->Size);
                    if (!mJEXIFSection.Data) {
                        ALOGE(" Not enough memory\n");
                        DiscardData();
                        DiscardSections();
                        return;
                    }
                    memcpy(mJEXIFSection.Data,
                        mJEXIFTmp->Data, mJEXIFTmp->Size);
                    DiscardData();
                    DiscardSections();

                    wStream = new SkFILEWStream(jpegPath.string());
                    skBMDec = PiPCopyToOneFile(&mInterpr->camera[0]->skBMtmp,
                            &mInterpr->camera[1]->skBMtmp);
                    if (!skBMDec) {
                        ALOGE("skBMDec is null\n");
                        delete wStream;
                        return;
                    }

                    if (encodeJPEG(wStream, skBMDec, jpegPath) != false) {
                        printf("%s():%d:: Failed during jpeg encode\n",
                                __FUNCTION__,__LINE__);
                        mInterpr->PiPUnlock();
                        return;
                    }
                    mPiPIdx = 0;
                    JpegIdx++;
                    delete wStream;
                }
            } else {
                mPiPIdx++;
            }
            disablePiPCapture();
        }
    }

    if ((msgType & CAMERA_MSG_PREVIEW_METADATA) && (NULL != metadata)) {
        printf("Face detected %d \n", metadata->number_of_faces);
    }
    mInterpr->PiPUnlock();

}

/*===========================================================================
 * FUNCTION   : postDataTimestamp
 *
 * DESCRIPTION: handles recording callbacks
 *
 * PARAMETERS :
 *   @timestamp : timestamp of buffer
 *   @msgType : type of buffer
 *   @dataPtr : buffer data
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::postDataTimestamp(nsecs_t timestamp,
                                      int32_t msgType,
                                      const sp<IMemory>& dataPtr)
{
    printf("Recording cb: %d %lld %p\n",
            msgType, (long long int)timestamp, dataPtr.get());
}

/*===========================================================================
 * FUNCTION   : dataCallbackTimestamp
 *
 * DESCRIPTION: handles recording callbacks. Used for ViV recording
 *
 * PARAMETERS :
 *   @timestamp : timestamp of buffer
 *   @msgType : type of buffer
 *   @dataPtr : buffer data
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::dataCallbackTimestamp(nsecs_t timestamp,
        int32_t msgType,
        const sp<IMemory>& dataPtr)
{
    mInterpr->ViVLock();
    // Not needed check. Just avoiding warnings of not used variables.
    if (timestamp > 0)
        timestamp = 0;
    // Not needed check. Just avoiding warnings of not used variables.
    if (msgType > 0)
        msgType = 0;
    size_t i = 0;
    void * srcBuff = NULL;
    void * dstBuff = NULL;

    size_t srcYStride = 0, dstYStride = 0;
    size_t srcUVStride = 0, dstUVStride = 0;
    size_t srcYScanLines = 0, dstYScanLines = 0;
    size_t srcUVScanLines = 0, dstUVScanLines = 0;
    size_t srcOffset = 0, dstOffset = 0;
    size_t srcBaseOffset = 0;
    size_t dstBaseOffset = 0;
    Size currentVideoSize = mSupportedVideoSizes.itemAt(mCurrentVideoSizeIdx);
    status_t err = NO_ERROR;
    ANativeWindowBuffer* anb = NULL;

    dstBuff = (void *) dataPtr->pointer();
    if (NULL == dstBuff) {
        printf("Cannot access destination buffer!!!\n");
        mInterpr->ViVUnlock();
        return;
    }

    if (mCameraIndex == mInterpr->mViVVid.sourceCameraID) {
        srcYStride = calcStride(currentVideoSize.width);
        srcUVStride = calcStride(currentVideoSize.width);
        srcYScanLines = calcYScanLines(currentVideoSize.height);
        srcUVScanLines = calcUVScanLines(currentVideoSize.height);
        mInterpr->mViVBuff.srcWidth = (size_t)currentVideoSize.width;
        mInterpr->mViVBuff.srcHeight = (size_t)currentVideoSize.height;


        mInterpr->mViVBuff.YStride = srcYStride;
        mInterpr->mViVBuff.UVStride = srcUVStride;
        mInterpr->mViVBuff.YScanLines = srcYScanLines;
        mInterpr->mViVBuff.UVScanLines = srcUVScanLines;

        memcpy( mInterpr->mViVBuff.buff, dstBuff,
            mInterpr->mViVBuff.buffSize);

        mInterpr->mViVVid.isBuffValid = true;
    } else if (mCameraIndex == mInterpr->mViVVid.destinationCameraID) {
        if(mInterpr->mViVVid.isBuffValid == true) {
            dstYStride = calcStride(currentVideoSize.width);
            dstUVStride = calcStride(currentVideoSize.width);
            dstYScanLines = calcYScanLines(currentVideoSize.height);
            dstUVScanLines = calcUVScanLines(currentVideoSize.height);

            srcYStride = mInterpr->mViVBuff.YStride;
            srcUVStride = mInterpr->mViVBuff.UVStride;
            srcYScanLines = mInterpr->mViVBuff.YScanLines;
            srcUVScanLines = mInterpr->mViVBuff.UVScanLines;


            for (i = 0; i < mInterpr->mViVBuff.srcHeight; i++) {
                srcOffset = i*srcYStride;
                dstOffset = i*dstYStride;
                memcpy((unsigned char *) dstBuff + dstOffset,
                    (unsigned char *) mInterpr->mViVBuff.buff +
                    srcOffset, mInterpr->mViVBuff.srcWidth);
            }
            srcBaseOffset = srcYStride * srcYScanLines;
            dstBaseOffset = dstYStride * dstYScanLines;
            for (i = 0; i < mInterpr->mViVBuff.srcHeight / 2; i++) {
                srcOffset = i*srcUVStride + srcBaseOffset;
                dstOffset = i*dstUVStride + dstBaseOffset;
                memcpy((unsigned char *) dstBuff + dstOffset,
                    (unsigned char *) mInterpr->mViVBuff.buff +
                    srcOffset, mInterpr->mViVBuff.srcWidth);
            }

            err = native_window_dequeue_buffer_and_wait(
                mInterpr->mViVVid.ANW.get(),&anb);
            if (err != NO_ERROR) {
                printf("Cannot dequeue anb for sensor %d!!!\n", mCameraIndex);
                mInterpr->ViVUnlock();
                return;
            }
            mInterpr->mViVVid.graphBuf = new GraphicBuffer(anb, false);
            if(NULL == mInterpr->mViVVid.graphBuf.get()) {
                printf("Invalid Graphic buffer\n");
                mInterpr->ViVUnlock();
                return;
            }
            err = mInterpr->mViVVid.graphBuf->lock(
                GRALLOC_USAGE_SW_WRITE_OFTEN,
                (void**)(&mInterpr->mViVVid.mappedBuff));
            if (err != NO_ERROR) {
                printf("Graphic buffer could not be locked %d!!!\n", err);
                mInterpr->ViVUnlock();
                return;
            }

            srcYStride = dstYStride;
            srcUVStride = dstUVStride;
            srcYScanLines = dstYScanLines;
            srcUVScanLines = dstUVScanLines;
            srcBuff = dstBuff;

            for (i = 0; i < (size_t)currentVideoSize.height; i++) {
                srcOffset = i*srcYStride;
                dstOffset = i*dstYStride;
                memcpy((unsigned char *) mInterpr->mViVVid.mappedBuff +
                    dstOffset, (unsigned char *) srcBuff +
                    srcOffset, (size_t)currentVideoSize.width);
            }

            srcBaseOffset = srcYStride * srcYScanLines;
            dstBaseOffset = dstUVStride * (size_t)currentVideoSize.height;

            for (i = 0; i < (size_t)currentVideoSize.height / 2; i++) {
                srcOffset = i*srcUVStride + srcBaseOffset;
                dstOffset = i*dstUVStride + dstBaseOffset;
                memcpy((unsigned char *) mInterpr->mViVVid.mappedBuff +
                    dstOffset, (unsigned char *) srcBuff +
                    srcOffset, (size_t)currentVideoSize.width);
            }


            mInterpr->mViVVid.graphBuf->unlock();

            err = mInterpr->mViVVid.ANW->queueBuffer(
                mInterpr->mViVVid.ANW.get(), anb, -1);
            if(err)
                printf("Failed to enqueue buffer to recorder!!!\n");
        }
    }
    mCamera->releaseRecordingFrame(dataPtr);

    mInterpr->ViVUnlock();
}

/*===========================================================================
 * FUNCTION   : ViVEncoderThread
 *
 * DESCRIPTION: Creates a separate thread for ViV recording
 *
 * PARAMETERS : None
 *
 * RETURN     : None
 *==========================================================================*/
status_t Interpreter::ViVEncoderThread()
{
    int ret = NO_ERROR;
    pthread_attr_t attr;
    pthread_attr_init(&attr);

    ret = pthread_create(&mViVEncThread, &attr, ThreadWrapper, this);
    ret = pthread_attr_destroy(&attr);

    return ret;
}

/*===========================================================================
 * FUNCTION   : ThreadWrapper
 *
 * DESCRIPTION: Helper function for for ViV recording thread
 *
 * PARAMETERS : Interpreter context
 *
 * RETURN     : None
 *==========================================================================*/
void *Interpreter::ThreadWrapper(void *context) {
    Interpreter *writer = static_cast<Interpreter *>(context);
    writer->ViVEncode();
    return NULL;
}

/*===========================================================================
 * FUNCTION   : ViVEncode
 *
 * DESCRIPTION: Thread for ViV encode. Buffers from video codec are sent to
 *              muxer and saved in a file.
 *
 * PARAMETERS : Interpreter context
 *
 * RETURN     : None
 *==========================================================================*/
void Interpreter::ViVEncode()
{
    status_t err = NO_ERROR;
    ssize_t trackIdx = -1;
    uint32_t debugNumFrames = 0;

    size_t bufIndex, offset, size;
    int64_t ptsUsec;
    uint32_t flags;
    bool DoRecording = true;


    err = mTestContext->mViVVid.codec->getOutputBuffers(
        &mTestContext->mViVVid.buffers);
    if (err != NO_ERROR) {
        printf("Unable to get output buffers (err=%d)\n", err);
    }

    while (DoRecording) {
        err = mTestContext->mViVVid.codec->dequeueOutputBuffer(
            &bufIndex,
            &offset,
            &size,
            &ptsUsec,
            &flags, -1);

        switch (err) {

        case NO_ERROR:
            // got a buffer
            if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) {
                // ignore this -- we passed the CSD into MediaMuxer when
                // we got the format change notification
                size = 0;
            }
            if (size != 0) {
                // If the virtual display isn't providing us with timestamps,
                // use the current time.
                if (ptsUsec == 0) {
                    ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000;
                }

                // The MediaMuxer docs are unclear, but it appears that we
                // need to pass either the full set of BufferInfo flags, or
                // (flags & BUFFER_FLAG_SYNCFRAME).
                err = mTestContext->mViVVid.muxer->writeSampleData(
                    mTestContext->mViVVid.buffers[bufIndex],
                    (size_t)trackIdx,
                    ptsUsec,
                    flags);
                if (err != NO_ERROR) {
                    fprintf(stderr, "Failed writing data to muxer (err=%d)\n",
                            err);
                }
                debugNumFrames++;
            }
            err = mTestContext->mViVVid.codec->releaseOutputBuffer(bufIndex);
            if (err != NO_ERROR) {
                fprintf(stderr, "Unable to release output buffer (err=%d)\n",
                        err);
            }
            if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) {
                // Not expecting EOS from SurfaceFlinger.  Go with it.
                printf("Received end-of-stream\n");
                //DoRecording = false;
            }
            break;
        case -EAGAIN:                       // INFO_TRY_AGAIN_LATER
            ALOGV("Got -EAGAIN, looping");
            break;
        case INFO_FORMAT_CHANGED:           // INFO_OUTPUT_FORMAT_CHANGED
        {
            // format includes CSD, which we must provide to muxer
            sp<AMessage> newFormat;
            mTestContext->mViVVid.codec->getOutputFormat(&newFormat);
            trackIdx = mTestContext->mViVVid.muxer->addTrack(newFormat);
            err = mTestContext->mViVVid.muxer->start();
            if (err != NO_ERROR) {
                printf("Unable to start muxer (err=%d)\n", err);
            }
        }
        break;
        case INFO_OUTPUT_BUFFERS_CHANGED:   // INFO_OUTPUT_BUFFERS_CHANGED
            // not expected for an encoder; handle it anyway
            ALOGV("Encoder buffers changed");
            err = mTestContext->mViVVid.codec->getOutputBuffers(
                &mTestContext->mViVVid.buffers);
            if (err != NO_ERROR) {
                printf("Unable to get new output buffers (err=%d)\n", err);
            }
        break;
        case INVALID_OPERATION:
            DoRecording = false;
        break;
        default:
            printf("Got weird result %d from dequeueOutputBuffer\n", err);
        break;
        }
    }

    return;
}

/*===========================================================================
 * FUNCTION   : calcBufferSize
 *
 * DESCRIPTION: Temp buffer size calculation. Temp buffer is used to store
 *              the buffer from the camera with smaller resolution. It is
 *              copied to the buffer from camera with higher resolution.
 *
 * PARAMETERS :
 *   @width   : video size width
 *   @height  : video size height
 *
 * RETURN     : size_t
 *==========================================================================*/
size_t CameraContext::calcBufferSize(int width, int height)
{
    size_t size = 0;
    size_t UVAlignment;
    size_t YPlane, UVPlane, YStride, UVStride, YScanlines, UVScanlines;
    if (!width || !height) {
        return size;
    }
    UVAlignment = 4096;
    YStride = calcStride(width);
    UVStride = calcStride(width);
    YScanlines = calcYScanLines(height);
    UVScanlines = calcUVScanLines(height);
    YPlane = YStride * YScanlines;
    UVPlane = UVStride * UVScanlines + UVAlignment;
    size = YPlane + UVPlane;
    size = VIDEO_BUF_ALLIGN(size, 4096);

    return size;
}

/*===========================================================================
 * FUNCTION   : calcStride
 *
 * DESCRIPTION: Temp buffer stride calculation.
 *
 * PARAMETERS :
 *   @width   : video size width
 *
 * RETURN     : size_t
 *==========================================================================*/
size_t CameraContext::calcStride(int width)
{
    size_t alignment, stride = 0;
    if (!width) {
        return stride;
    }
    alignment = 128;
    stride = VIDEO_BUF_ALLIGN((size_t)width, alignment);

    return stride;
}

/*===========================================================================
 * FUNCTION   : calcYScanLines
 *
 * DESCRIPTION: Temp buffer scanlines calculation for Y plane.
 *
 * PARAMETERS :
 *   @width   : video size height
 *
 * RETURN     : size_t
 *==========================================================================*/
size_t CameraContext::calcYScanLines(int height)
{
    size_t alignment, scanlines = 0;
        if (!height) {
            return scanlines;
        }
    alignment = 32;
    scanlines = VIDEO_BUF_ALLIGN((size_t)height, alignment);

    return scanlines;
}

/*===========================================================================
 * FUNCTION   : calcUVScanLines
 *
 * DESCRIPTION: Temp buffer scanlines calculation for UV plane.
 *
 * PARAMETERS :
 *   @width   : video size height
 *
 * RETURN     : size_t
 *==========================================================================*/
size_t CameraContext::calcUVScanLines(int height)
{
    size_t alignment, scanlines = 0;
    if (!height) {
        return scanlines;
    }
    alignment = 16;
    scanlines = VIDEO_BUF_ALLIGN((size_t)((height + 1) >> 1), alignment);

    return scanlines;
}

/*===========================================================================
 * FUNCTION   : printSupportedParams
 *
 * DESCRIPTION: dump common supported parameters
 *
 * PARAMETERS : None
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::printSupportedParams()
{
    const char *camera_ids = mParams.get("camera-indexes");
    const char *pic_sizes = mParams.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
    const char *pic_formats = mParams.get(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS);
    const char *preview_sizes = mParams.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
    const char *video_sizes = mParams.get(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES);
    const char *preview_formats = mParams.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
    const char *frame_rates = mParams.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES);
    const char *thumb_sizes = mParams.get(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES);
    const char *wb_modes = mParams.get(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE);
    const char *effects = mParams.get(CameraParameters::KEY_SUPPORTED_EFFECTS);
    const char *scene_modes = mParams.get(CameraParameters::KEY_SUPPORTED_SCENE_MODES);
    const char *focus_modes = mParams.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES);
    const char *antibanding_modes = mParams.get(CameraParameters::KEY_SUPPORTED_ANTIBANDING);
    const char *flash_modes = mParams.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES);
    int focus_areas = mParams.getInt(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS);
    const char *fps_ranges = mParams.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE);
    const char *focus_distances = mParams.get(CameraParameters::KEY_FOCUS_DISTANCES);

    printf("\n\r\tSupported Cameras: %s",
           (camera_ids != NULL)? camera_ids : "NULL");
    printf("\n\r\tSupported Picture Sizes: %s",
           (pic_sizes != NULL)? pic_sizes : "NULL");
    printf("\n\r\tSupported Picture Formats: %s",
           (pic_formats != NULL)? pic_formats : "NULL");
    printf("\n\r\tSupported Preview Sizes: %s",
           (preview_sizes != NULL)? preview_sizes : "NULL");
    printf("\n\r\tSupported Video Sizes: %s",
            (video_sizes != NULL)? video_sizes : "NULL");
    printf("\n\r\tSupported Preview Formats: %s",
           (preview_formats != NULL)? preview_formats : "NULL");
    printf("\n\r\tSupported Preview Frame Rates: %s",
           (frame_rates != NULL)? frame_rates : "NULL");
    printf("\n\r\tSupported Thumbnail Sizes: %s",
           (thumb_sizes != NULL)? thumb_sizes : "NULL");
    printf("\n\r\tSupported Whitebalance Modes: %s",
           (wb_modes != NULL)? wb_modes : "NULL");
    printf("\n\r\tSupported Effects: %s",
           (effects != NULL)? effects : "NULL");
    printf("\n\r\tSupported Scene Modes: %s",
           (scene_modes != NULL)? scene_modes : "NULL");
    printf("\n\r\tSupported Focus Modes: %s",
           (focus_modes != NULL)? focus_modes : "NULL");
    printf("\n\r\tSupported Antibanding Options: %s",
           (antibanding_modes != NULL)? antibanding_modes : "NULL");
    printf("\n\r\tSupported Flash Modes: %s",
           (flash_modes != NULL)? flash_modes : "NULL");
    printf("\n\r\tSupported Focus Areas: %d", focus_areas);
    printf("\n\r\tSupported FPS ranges : %s",
           (fps_ranges != NULL)? fps_ranges : "NULL");
    printf("\n\r\tFocus Distances: %s \n",
           (focus_distances != NULL)? focus_distances : "NULL");
}

/*===========================================================================
 * FUNCTION   : createPreviewSurface
 *
 * DESCRIPTION: helper function for creating preview surfaces
 *
 * PARAMETERS :
 *   @width : preview width
 *   @height: preview height
 *   @pixFormat : surface pixelformat
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::createPreviewSurface(int width, int height, int32_t pixFormat)
{
    int ret = NO_ERROR;
    DisplayInfo dinfo;
    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
                        ISurfaceComposer::eDisplayIdMain));
    SurfaceComposerClient::getDisplayInfo(display, &dinfo);
    uint32_t previewWidth, previewHeight;

    if ((0 >= width) || (0 >= height)) {
        printf("Bad preview surface size %dx%d\n", width, height);
        return BAD_VALUE;
    }

    if ((int)dinfo.w < width) {
        previewWidth = dinfo.w;
    } else {
        previewWidth = (unsigned int)width;
    }

    if ((int)dinfo.h < height) {
        previewHeight = dinfo.h;
    } else {
        previewHeight = (unsigned int)height;
    }

    mClient = new SurfaceComposerClient();

    if ( NULL == mClient.get() ) {
        printf("Unable to establish connection to Surface Composer \n");
        return NO_INIT;
    }

    mSurfaceControl = mClient->createSurface(String8("QCamera_Test"),
                                             previewWidth,
                                             previewHeight,
                                             pixFormat,
                                             0);
    if ( NULL == mSurfaceControl.get() ) {
        printf("Unable to create preview surface \n");
        return NO_INIT;
    }

    mPreviewSurface = mSurfaceControl->getSurface();
    if ( NULL != mPreviewSurface.get() ) {
        mClient->openGlobalTransaction();
        ret |= mSurfaceControl->setLayer(0x7fffffff);
        if ( mCameraIndex == 0 )
            ret |= mSurfaceControl->setPosition(0, 0);
        else
            ret |= mSurfaceControl->setPosition((float)(dinfo.w - previewWidth),
                    (float)(dinfo.h - previewHeight));

        ret |= mSurfaceControl->setSize(previewWidth, previewHeight);
        ret |= mSurfaceControl->show();
        mClient->closeGlobalTransaction();

        if ( NO_ERROR != ret ) {
            printf("Preview surface configuration failed! \n");
        }
    } else {
        ret = NO_INIT;
    }

    return ret;
}

/*===========================================================================
 * FUNCTION   : destroyPreviewSurface
 *
 * DESCRIPTION: closes previously open preview surface
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::destroyPreviewSurface()
{
    if ( NULL != mPreviewSurface.get() ) {
        mPreviewSurface.clear();
    }

    if ( NULL != mSurfaceControl.get() ) {
        mSurfaceControl->clear();
        mSurfaceControl.clear();
    }

    if ( NULL != mClient.get() ) {
        mClient->dispose();
        mClient.clear();
    }

    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : CameraContext
 *
 * DESCRIPTION: camera context constructor
 *
 * PARAMETERS : None
 *
 * RETURN     : None
 *==========================================================================*/
CameraContext::CameraContext(int cameraIndex) :
    mCameraIndex(cameraIndex),
    mResizePreview(true),
    mHardwareActive(false),
    mPreviewRunning(false),
    mRecordRunning(false),
    mVideoFd(-1),
    mVideoIdx(0),
    mRecordingHint(false),
    mDoPrintMenu(true),
    mPiPCapture(false),
    mfmtMultiplier(1),
    mSectionsRead(false),
    mSectionsAllocated(0),
    mSections(NULL),
    mJEXIFTmp(NULL),
    mHaveAll(false),
    mCamera(NULL),
    mClient(NULL),
    mSurfaceControl(NULL),
    mPreviewSurface(NULL),
    mInUse(false)
{
    mRecorder = new MediaRecorder(String16("camera"));
}

/*===========================================================================
 * FUNCTION     : setTestCtxInstance
 *
 * DESCRIPTION  : Sends TestContext instance to CameraContext
 *
 * PARAMETERS   :
 *    @instance : TestContext instance
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::setTestCtxInstance(TestContext  *instance)
{
    mInterpr = instance;
}

/*===========================================================================
 * FUNCTION     : setTestCtxInst
 *
 * DESCRIPTION  : Sends TestContext instance to Interpreter
 *
 * PARAMETERS   :
 *    @instance : TestContext instance
 *
 * RETURN     : None
 *==========================================================================*/
void Interpreter::setTestCtxInst(TestContext  *instance)
{
    mTestContext = instance;
}

/*===========================================================================
 * FUNCTION   : ~CameraContext
 *
 * DESCRIPTION: camera context destructor
 *
 * PARAMETERS : None
 *
 * RETURN     : None
 *==========================================================================*/
CameraContext::~CameraContext()
{
    stopPreview();
    closeCamera();
}

/*===========================================================================
 * FUNCTION   : openCamera
 *
 * DESCRIPTION: connects to and initializes camera
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t  CameraContext::openCamera()
{
    useLock();
    const char *ZSLStr = NULL;
    size_t ZSLStrSize = 0;

    if ( NULL != mCamera.get() ) {
        printf("Camera already open! \n");
        signalFinished();
        return NO_ERROR;
    }

    printf("openCamera(camera_index=%d)\n", mCameraIndex);

#ifndef USE_JB_MR1

    String16 packageName("CameraTest");

    mCamera = Camera::connect(mCameraIndex,
                              packageName,
                              Camera::USE_CALLING_UID);

#else

    mCamera = Camera::connect(mCameraIndex);

#endif

    if ( NULL == mCamera.get() ) {
        printf("Unable to connect to CameraService\n");
        signalFinished();
        return NO_INIT;
    }

    mParams = mCamera->getParameters();
    mParams.getSupportedPreviewSizes(mSupportedPreviewSizes);
    mParams.getSupportedPictureSizes(mSupportedPictureSizes);
    mParams.getSupportedVideoSizes(mSupportedVideoSizes);

    mCurrentPictureSizeIdx = mSupportedPictureSizes.size() / 2;
    mCurrentPreviewSizeIdx = mSupportedPreviewSizes.size() / 2;
    mCurrentVideoSizeIdx   = mSupportedVideoSizes.size() / 2;

    mCamera->setListener(this);
    mHardwareActive = true;

    mInterpr->setViVSize((Size) mSupportedVideoSizes.itemAt(
        mCurrentVideoSizeIdx),
        mCameraIndex);

    ZSLStr = mParams.get(CameraContext::KEY_ZSL);
    if (NULL != ZSLStr) {
        ZSLStrSize = strlen(ZSLStr);
        if (!strncmp(ZSLStr, "on", ZSLStrSize)) {
            mInterpr->mIsZSLOn = true;
        } else if (!strncmp(ZSLStr, "off", ZSLStrSize)) {
            mInterpr->mIsZSLOn = false;
        } else {
            printf("zsl value is not valid!\n");
        }
    } else {
        printf("zsl is NULL\n");
    }

    signalFinished();

    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : onAsBinder
 *
 * DESCRIPTION: onAsBinder
 *
 * PARAMETERS : None
 *
 * RETURN     : Pointer to IBinder
 *==========================================================================*/
IBinder* CameraContext::onAsBinder() {
    return NULL;
}

/*===========================================================================
 * FUNCTION   : getNumberOfCameras
 *
 * DESCRIPTION: returns the number of supported camera by the system
 *
 * PARAMETERS : None
 *
 * RETURN     : supported camera count
 *==========================================================================*/
int CameraContext::getNumberOfCameras()
{
    int ret = -1;

    if ( NULL != mCamera.get() ) {
        ret = mCamera->getNumberOfCameras();
    }

    return ret;
}

/*===========================================================================
 * FUNCTION   : closeCamera
 *
 * DESCRIPTION: closes a previously the initialized camera reference
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::closeCamera()
{
    useLock();
    if ( NULL == mCamera.get() ) {
        return NO_INIT;
    }

    mCamera->disconnect();
    mCamera.clear();

    mRecorder->init();
    mRecorder->close();
    mRecorder->release();
    mRecorder.clear();

    mHardwareActive = false;
    mPreviewRunning = false;
    mRecordRunning = false;

    signalFinished();
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : startPreview
 *
 * DESCRIPTION: starts camera preview
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::startPreview()
{
    useLock();

    int ret = NO_ERROR;
    int previewWidth, previewHeight;
    Size calculatedPreviewSize;
    Size currentPreviewSize = mSupportedPreviewSizes.itemAt(
        mCurrentPreviewSizeIdx);
    Size currentPictureSize = mSupportedPictureSizes.itemAt(
        mCurrentPictureSizeIdx);
    Size currentVideoSize   = mSupportedVideoSizes.itemAt(
        mCurrentVideoSizeIdx);

#ifndef USE_JB_MR1

    sp<IGraphicBufferProducer> gbp;

#endif

    if (!mHardwareActive ) {
        printf("Camera not active! \n");
        return NO_INIT;
    }

    if (mPreviewRunning) {
        printf("Preview is already running! \n");
        signalFinished();
        return NO_ERROR;
    }

    if (mResizePreview) {
        mPreviewRunning = false;

        if ( mRecordingHint ) {
            calculatedPreviewSize =
                getPreviewSizeFromVideoSizes(currentVideoSize);
            previewWidth = calculatedPreviewSize.width;
            previewHeight = calculatedPreviewSize.height;
        } else {
            previewWidth = currentPreviewSize.width;
            previewHeight = currentPreviewSize.height;
        }

        ret = createPreviewSurface(previewWidth,
                                   previewHeight,
                                   HAL_PIXEL_FORMAT_YCrCb_420_SP);
        if (  NO_ERROR != ret ) {
            printf("Error while creating preview surface\n");
            return ret;
        }

        // set rdi mode if system prop is set for front camera
        if (mCameraIndex == 1) {
            char value[32];
            property_get("persist.camera.rdimode", value, "0");
            int rdimode = atoi(value);
            printf("rdi mode = %d\n", rdimode);
            if (rdimode == 1) {
                mParams.set("rdi-mode", "enable");
            } else {
                mParams.set("rdi-mode", "disable");
            }
        } else {
            mParams.set("rdi-mode", "disable");
        }

        //mParams.set("rdi-mode", "enable");
        mParams.set("recording-hint", "true");
        mParams.setPreviewSize(previewWidth, previewHeight);
        mParams.setPictureSize(currentPictureSize.width,
            currentPictureSize.height);
        mParams.setVideoSize(
            currentVideoSize.width, currentVideoSize.height);

        ret |= mCamera->setParameters(mParams.flatten());

#ifndef USE_JB_MR1

        gbp = mPreviewSurface->getIGraphicBufferProducer();
        ret |= mCamera->setPreviewTarget(gbp);

#else

        ret |= mCamera->setPreviewDisplay(mPreviewSurface);

#endif
        mResizePreview = false;
    }

    if ( !mPreviewRunning ) {
        ret |= mCamera->startPreview();
        if ( NO_ERROR != ret ) {
            printf("Preview start failed! \n");
            return ret;
        }

        mPreviewRunning = true;
    }

    signalFinished();

    return ret;
}

/*===========================================================================
 * FUNCTION   : getPreviewSizeFromVideoSizes
 *
 * DESCRIPTION: Get the preview size from video size. Find all resolutions with
 *              the same aspect ratio and choose the same or the closest
 *              from them.
 *
 * PARAMETERS :
 *   @currentVideoSize: current video size

 *
 * RETURN     : PreviewSize
 *==========================================================================*/
Size CameraContext::getPreviewSizeFromVideoSizes(Size currentVideoSize)
{

    Size tmpPreviewSize;
    Size PreviewSize;
    Size PreviewSizes[mSupportedPreviewSizes.size()];
    double tolerance = 0.00001;
    double videoRatio;
    double previewRatio;
    size_t i = 0;
    size_t j = 0;
    int delta;

    // Find all the resolutions with the same aspect ratio and choose the
    // same or the closest resolution from them. Choose the closest resolution
    // in case same aspect ratio is not found
    if (currentVideoSize.width * currentVideoSize.height > 0 &&
            mSupportedPreviewSizes.size() > 0) {
        videoRatio = (float)currentVideoSize.width /
            (float)currentVideoSize.height;
        for (i=0; i<mSupportedPreviewSizes.size(); i++) {
            tmpPreviewSize = mSupportedPreviewSizes.itemAt(i);
            previewRatio = (float)tmpPreviewSize.width /
                (float)tmpPreviewSize.height;
            if (fabs(videoRatio - previewRatio) < tolerance) {
                PreviewSizes[j] = tmpPreviewSize;
                j++;
            }
        }

        if ( j > 0 ) {
            delta = abs((currentVideoSize.width *currentVideoSize.height)-
                (PreviewSizes[0].width * PreviewSizes[0].height));
            PreviewSize = PreviewSizes[0];
            for (i=0; i<j; i++) {
                if(abs(currentVideoSize.width * currentVideoSize.height) -
                    (PreviewSizes[i].width * PreviewSizes[i].height) <
                    delta) {
                    PreviewSize = PreviewSizes[i];
                    delta = abs((currentVideoSize.width *
                        currentVideoSize.height) -
                        (PreviewSizes[i].width * PreviewSizes[i].height));
                }
            }
        } else {
            // Choose the closest resolution in case same aspect ratio is
            // not found
            tmpPreviewSize = mSupportedPreviewSizes.itemAt(j);
            PreviewSize = tmpPreviewSize;
            delta = abs(
                    (currentVideoSize.width * currentVideoSize.height)-
                    (tmpPreviewSize.width * tmpPreviewSize.height));
            for (i=0; i<mSupportedPreviewSizes.size(); i++) {
                tmpPreviewSize = mSupportedPreviewSizes.itemAt(i);
                if(abs(
                        (currentVideoSize.width * currentVideoSize.height)-
                        (tmpPreviewSize.width * tmpPreviewSize.height)) <
                        delta) {
                    PreviewSize = tmpPreviewSize;
                    delta = abs(
                            (currentVideoSize.width * currentVideoSize.height)-
                            (tmpPreviewSize.width * tmpPreviewSize.height));
                }
            }
        }
    } else {
        memset(&PreviewSize, 0, sizeof(PreviewSize));
    }
    return PreviewSize;
}

/*===========================================================================
 * FUNCTION   : autoFocus
 *
 * DESCRIPTION: Triggers autofocus
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::autoFocus()
{
    useLock();
    status_t ret = NO_ERROR;

    if ( mPreviewRunning ) {
        ret = mCamera->autoFocus();
    }

    signalFinished();
    return ret;
}

/*===========================================================================
 * FUNCTION   : enablePreviewCallbacks
 *
 * DESCRIPTION: Enables preview callback messages
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::enablePreviewCallbacks()
{
    useLock();
    if ( mHardwareActive ) {
        mCamera->setPreviewCallbackFlags(
            CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
    }

    signalFinished();
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : takePicture
 *
 * DESCRIPTION: triggers image capture
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::takePicture()
{
    status_t ret = NO_ERROR;
    useLock();
    if ( mPreviewRunning ) {
        ret = mCamera->takePicture(
            CAMERA_MSG_COMPRESSED_IMAGE|
            CAMERA_MSG_RAW_IMAGE);
        if (!mRecordingHint && !mInterpr->mIsZSLOn) {
            mPreviewRunning = false;
        }
    } else {
        printf("Please resume/start the preview before taking a picture!\n");
    }
    signalFinished();
    return ret;
}

/*===========================================================================
 * FUNCTION   : configureRecorder
 *
 * DESCRIPTION: Configure video recorder
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::configureRecorder()
{
    useLock();
    status_t ret = NO_ERROR;

    mResizePreview = true;
    mParams.set("recording-hint", "true");
    mRecordingHint = true;
    mCamera->setParameters(mParams.flatten());

    Size videoSize = mSupportedVideoSizes.itemAt(mCurrentVideoSizeIdx);
    ret = mRecorder->setParameters(
        String8("video-param-encoding-bitrate=64000"));
    if ( ret != NO_ERROR ) {
        LOGE("Could not configure recorder (%d)", ret);
        return ret;
    }

    ret = mRecorder->setCamera(
        mCamera->remote(), mCamera->getRecordingProxy());
    if ( ret != NO_ERROR ) {
        LOGE("Could not set camera (%d)", ret);
        return ret;
    }
    ret = mRecorder->setVideoSource(VIDEO_SOURCE_CAMERA);
    if ( ret != NO_ERROR ) {
        LOGE("Could not set video soruce (%d)", ret);
        return ret;
    }
    ret = mRecorder->setAudioSource(AUDIO_SOURCE_DEFAULT);
    if ( ret != NO_ERROR ) {
        LOGE("Could not set audio source (%d)", ret);
        return ret;
    }
    ret = mRecorder->setOutputFormat(OUTPUT_FORMAT_DEFAULT);
    if ( ret != NO_ERROR ) {
        LOGE("Could not set output format (%d)", ret);
        return ret;
    }

    ret = mRecorder->setVideoEncoder(VIDEO_ENCODER_DEFAULT);
    if ( ret != NO_ERROR ) {
        LOGE("Could not set video encoder (%d)", ret);
        return ret;
    }

    char fileName[100];

    snprintf(fileName, sizeof(fileName) / sizeof(char),
            "/sdcard/vid_cam%d_%dx%d_%d.mpeg", mCameraIndex,
            videoSize.width, videoSize.height, mVideoIdx++);

    if ( mVideoFd < 0 ) {
        mVideoFd = open(fileName, O_CREAT | O_RDWR );
    }

    if ( mVideoFd < 0 ) {
        LOGE("Could not open video file for writing %s!", fileName);
        return UNKNOWN_ERROR;
    }

    ret = mRecorder->setOutputFile(mVideoFd, 0, 0);
    if ( ret != NO_ERROR ) {
        LOGE("Could not set output file (%d)", ret);
        return ret;
    }

    ret = mRecorder->setVideoSize(videoSize.width, videoSize.height);
    if ( ret  != NO_ERROR ) {
        LOGE("Could not set video size %dx%d", videoSize.width,
            videoSize.height);
        return ret;
    }

    ret = mRecorder->setVideoFrameRate(30);
    if ( ret != NO_ERROR ) {
        LOGE("Could not set video frame rate (%d)", ret);
        return ret;
    }

    ret = mRecorder->setAudioEncoder(AUDIO_ENCODER_DEFAULT);
    if ( ret != NO_ERROR ) {
        LOGE("Could not set audio encoder (%d)", ret);
        return ret;
    }

    signalFinished();
    return ret;
}

/*===========================================================================
 * FUNCTION   : unconfigureViVRecording
 *
 * DESCRIPTION: Unconfigures video in video recording
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::unconfigureRecorder()
{
    useLock();

    if ( !mRecordRunning ) {
        mResizePreview = true;
        mParams.set("recording-hint", "false");
        mRecordingHint = false;
        mCamera->setParameters(mParams.flatten());
    }

    signalFinished();
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : configureViVRecording
 *
 * DESCRIPTION: Configures video in video recording
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::configureViVRecording()
{
    status_t ret = NO_ERROR;

    mResizePreview = true;
    mParams.set("recording-hint", "true");
    mRecordingHint = true;
    mCamera->setParameters(mParams.flatten());
    mCamera->setRecordingProxyListener(this);

    signalFinished();
    return ret;
}

/*===========================================================================
 * FUNCTION   : startRecording
 *
 * DESCRIPTION: triggers start recording
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::startRecording()
{
    useLock();
    status_t ret = NO_ERROR;


    if ( mPreviewRunning ) {

        mCamera->unlock();

        ret = mRecorder->prepare();
        if ( ret != NO_ERROR ) {
            LOGE("Could not prepare recorder");
            return ret;
        }

        ret = mRecorder->start();
        if ( ret != NO_ERROR ) {
            LOGE("Could not start recorder");
            return ret;
        }

        mRecordRunning = true;
    }
    signalFinished();
    return ret;
}

/*===========================================================================
 * FUNCTION   : stopRecording
 *
 * DESCRIPTION: triggers start recording
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::stopRecording()
{
    useLock();
    status_t ret = NO_ERROR;

    if ( mRecordRunning ) {
            mRecorder->stop();
            close(mVideoFd);
            mVideoFd = -1;

        mRecordRunning = false;
    }

    signalFinished();

    return ret;
}

/*===========================================================================
 * FUNCTION   : startViVRecording
 *
 * DESCRIPTION: Starts video in video recording
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::startViVRecording()
{
    useLock();
    status_t ret;

    if (mInterpr->mViVVid.VideoSizes[0].width *
            mInterpr->mViVVid.VideoSizes[0].height >=
            mInterpr->mViVVid.VideoSizes[1].width *
            mInterpr->mViVVid.VideoSizes[1].height) {
        mInterpr->mViVBuff.buffSize = calcBufferSize(
            mInterpr->mViVVid.VideoSizes[1].width,
            mInterpr->mViVVid.VideoSizes[1].height);
        if (mInterpr->mViVBuff.buff == NULL) {
            mInterpr->mViVBuff.buff =
                (void *)malloc(mInterpr->mViVBuff.buffSize);
        }
        mInterpr->mViVVid.sourceCameraID = 1;
        mInterpr->mViVVid.destinationCameraID = 0;

    } else {
        mInterpr->mViVBuff.buffSize = calcBufferSize(
            mInterpr->mViVVid.VideoSizes[0].width,
            mInterpr->mViVVid.VideoSizes[0].height);
        if (mInterpr->mViVBuff.buff == NULL) {
            mInterpr->mViVBuff.buff =
                (void *)malloc(mInterpr->mViVBuff.buffSize);
        }
        mInterpr->mViVVid.sourceCameraID = 0;
        mInterpr->mViVVid.destinationCameraID = 1;
    }

    ret = mCamera->startRecording();

    signalFinished();
    return ret;
}

/*===========================================================================
 * FUNCTION   : stopViVRecording
 *
 * DESCRIPTION: Stops video in video recording
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::stopViVRecording()
{
    useLock();
    status_t ret = NO_ERROR;

    mCamera->stopRecording();

    signalFinished();
    return ret;
}

/*===========================================================================
 * FUNCTION   : stopPreview
 *
 * DESCRIPTION: stops camera preview
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::stopPreview()
{
    useLock();
    status_t ret = NO_ERROR;

    if ( mHardwareActive ) {
        mCamera->stopPreview();
        ret = destroyPreviewSurface();
    }

    mPreviewRunning  = false;
    mResizePreview = true;

    signalFinished();

    return ret;
}

/*===========================================================================
 * FUNCTION   : resumePreview
 *
 * DESCRIPTION: resumes camera preview after image capture
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::resumePreview()
{
    useLock();
    status_t ret = NO_ERROR;

    if ( mHardwareActive ) {
        ret = mCamera->startPreview();
        mPreviewRunning = true;
    } else {
        ret = NO_INIT;
    }

    signalFinished();
    return ret;
}

/*===========================================================================
 * FUNCTION   : nextPreviewSize
 *
 * DESCRIPTION: Iterates through all supported preview sizes.
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::nextPreviewSize()
{
    useLock();
    if ( mHardwareActive ) {
        mCurrentPreviewSizeIdx += 1;
        mCurrentPreviewSizeIdx %= mSupportedPreviewSizes.size();
        Size previewSize = mSupportedPreviewSizes.itemAt(
            mCurrentPreviewSizeIdx);
        mParams.setPreviewSize(previewSize.width,
                               previewSize.height);
        mResizePreview = true;

        if ( mPreviewRunning ) {
            mCamera->stopPreview();
            mCamera->setParameters(mParams.flatten());
            mCamera->startPreview();
        } else {
            mCamera->setParameters(mParams.flatten());
        }
    }

    signalFinished();
    return NO_ERROR;
}


/*===========================================================================
 * FUNCTION   : setPreviewSize
 *
 * DESCRIPTION: Sets exact preview size if supported
 *
 * PARAMETERS : format size in the form of WIDTHxHEIGHT
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::setPreviewSize(const char *format)
{
    useLock();
    if ( mHardwareActive ) {
        int newHeight;
        int newWidth;
        sscanf(format, "%dx%d", &newWidth, &newHeight);

        unsigned int i;
        for (i = 0; i < mSupportedPreviewSizes.size(); ++i) {
            Size previewSize = mSupportedPreviewSizes.itemAt(i);
            if ( newWidth == previewSize.width &&
                 newHeight == previewSize.height )
            {
                break;
            }

        }
        if ( i == mSupportedPreviewSizes.size())
        {
            printf("Preview size %dx%d not supported !\n",
                newWidth, newHeight);
            return INVALID_OPERATION;
        }

        mParams.setPreviewSize(newWidth,
                               newHeight);
        mResizePreview = true;

        if ( mPreviewRunning ) {
            mCamera->stopPreview();
            mCamera->setParameters(mParams.flatten());
            mCamera->startPreview();
        } else {
            mCamera->setParameters(mParams.flatten());
        }
    }

    signalFinished();
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : getCurrentPreviewSize
 *
 * DESCRIPTION: queries the currently configured preview size
 *
 * PARAMETERS :
 *  @previewSize : preview size currently configured
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::getCurrentPreviewSize(Size &previewSize)
{
    useLock();
    if ( mHardwareActive ) {
        previewSize = mSupportedPreviewSizes.itemAt(mCurrentPreviewSizeIdx);
    }
    signalFinished();
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : nextPictureSize
 *
 * DESCRIPTION: Iterates through all supported picture sizes.
 *
 * PARAMETERS : None
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::nextPictureSize()
{
    useLock();
    if ( mHardwareActive ) {
        mCurrentPictureSizeIdx += 1;
        mCurrentPictureSizeIdx %= mSupportedPictureSizes.size();
        Size pictureSize = mSupportedPictureSizes.itemAt(
            mCurrentPictureSizeIdx);
        mParams.setPictureSize(pictureSize.width,
            pictureSize.height);
        mCamera->setParameters(mParams.flatten());
    }
    signalFinished();
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : setPictureSize
 *
 * DESCRIPTION: Sets exact preview size if supported
 *
 * PARAMETERS : format size in the form of WIDTHxHEIGHT
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::setPictureSize(const char *format)
{
    useLock();
    if ( mHardwareActive ) {
        int newHeight;
        int newWidth;
        sscanf(format, "%dx%d", &newWidth, &newHeight);

        unsigned int i;
        for (i = 0; i < mSupportedPictureSizes.size(); ++i) {
            Size PictureSize = mSupportedPictureSizes.itemAt(i);
            if ( newWidth == PictureSize.width &&
                 newHeight == PictureSize.height )
            {
                break;
            }

        }
        if ( i == mSupportedPictureSizes.size())
        {
            printf("Preview size %dx%d not supported !\n",
                newWidth, newHeight);
            return INVALID_OPERATION;
        }

        mParams.setPictureSize(newWidth,
                               newHeight);
        mCamera->setParameters(mParams.flatten());
    }

    signalFinished();
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : nextVideoSize
 *
 * DESCRIPTION: Select the next available video size
 *
 * PARAMETERS : none
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::nextVideoSize()
{
    useLock();
    if ( mHardwareActive ) {
        mCurrentVideoSizeIdx += 1;
        mCurrentVideoSizeIdx %= mSupportedVideoSizes.size();
        Size videoSize = mSupportedVideoSizes.itemAt(mCurrentVideoSizeIdx);
        mParams.setVideoSize(videoSize.width,
                             videoSize.height);
        mCamera->setParameters(mParams.flatten());
        mInterpr->setViVSize((Size) mSupportedVideoSizes.itemAt(
            mCurrentVideoSizeIdx), mCameraIndex);
    }
    signalFinished();
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : setVideoSize
 *
 * DESCRIPTION: Set video size
 *
 * PARAMETERS :
 *   @format  : format
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::setVideoSize(const char *format)
{
    useLock();
    if ( mHardwareActive ) {
        int newHeight;
        int newWidth;
        sscanf(format, "%dx%d", &newWidth, &newHeight);

        unsigned int i;
        for (i = 0; i < mSupportedVideoSizes.size(); ++i) {
            Size PictureSize = mSupportedVideoSizes.itemAt(i);
            if ( newWidth == PictureSize.width &&
                 newHeight == PictureSize.height )
            {
                break;
            }

        }
        if ( i == mSupportedVideoSizes.size())
        {
            printf("Preview size %dx%d not supported !\n",
                newWidth, newHeight);
            return INVALID_OPERATION;
        }

        mParams.setVideoSize(newWidth,
                             newHeight);
        mCamera->setParameters(mParams.flatten());
    }

    signalFinished();
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION    : getCurrentVideoSize
 *
 * DESCRIPTION : Get current video size
 *
 * PARAMETERS  :
 *   @videoSize: video Size
 *
 * RETURN      : status_t type of status
 *               NO_ERROR  -- success
 *               none-zero failure code
 *==========================================================================*/
status_t CameraContext::getCurrentVideoSize(Size &videoSize)
{
    useLock();
    if ( mHardwareActive ) {
        videoSize = mSupportedVideoSizes.itemAt(mCurrentVideoSizeIdx);
    }
    signalFinished();
    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : getCurrentPictureSize
 *
 * DESCRIPTION: queries the currently configured picture size
 *
 * PARAMETERS :
 *  @pictureSize : picture size currently configured
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t CameraContext::getCurrentPictureSize(Size &pictureSize)
{
    useLock();
    if ( mHardwareActive ) {
        pictureSize = mSupportedPictureSizes.itemAt(mCurrentPictureSizeIdx);
    }
    signalFinished();
    return NO_ERROR;
}

}; //namespace qcamera ends here

using namespace qcamera;

/*===========================================================================
 * FUNCTION   : printMenu
 *
 * DESCRIPTION: prints the available camera options
 *
 * PARAMETERS :
 *  @currentCamera : camera context currently being used
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::printMenu(sp<CameraContext> currentCamera)
{
    if ( !mDoPrintMenu ) return;
    Size currentPictureSize, currentPreviewSize, currentVideoSize;
    const char *zsl_mode = mParams.get(CameraContext::KEY_ZSL);

    assert(currentCamera.get());

    currentCamera->getCurrentPictureSize(currentPictureSize);
    currentCamera->getCurrentPreviewSize(currentPreviewSize);
    currentCamera->getCurrentVideoSize(currentVideoSize);

    printf("\n\n=========== FUNCTIONAL TEST MENU ===================\n\n");

    printf(" \n\nSTART / STOP / GENERAL SERVICES \n");
    printf(" -----------------------------\n");
    printf("   %c. Switch camera - Current Index: %d\n",
            Interpreter::SWITCH_CAMERA_CMD,
            currentCamera->getCameraIndex());
    printf("   %c. Resume Preview after capture \n",
            Interpreter::RESUME_PREVIEW_CMD);
    printf("   %c. Quit \n",
            Interpreter::EXIT_CMD);
    printf("   %c. Camera Capability Dump",
            Interpreter::DUMP_CAPS_CMD);

    printf(" \n\n PREVIEW SUB MENU \n");
    printf(" -----------------------------\n");
    printf("   %c. Start Preview\n",
            Interpreter::START_PREVIEW_CMD);
    printf("   %c. Stop Preview\n",
            Interpreter::STOP_PREVIEW_CMD);
    printf("   %c. Preview size:  %dx%d\n",
            Interpreter::CHANGE_PREVIEW_SIZE_CMD,
            currentPreviewSize.width,
            currentPreviewSize.height);
    printf("   %c. Video size:  %dx%d\n",
            Interpreter::CHANGE_VIDEO_SIZE_CMD,
            currentVideoSize.width,
            currentVideoSize.height);
    printf("   %c. Start Recording\n",
            Interpreter::START_RECORD_CMD);
    printf("   %c. Stop Recording\n",
            Interpreter::STOP_RECORD_CMD);
    printf("   %c. Start ViV Recording\n",
            Interpreter::START_VIV_RECORD_CMD);
    printf("   %c. Stop ViV Recording\n",
            Interpreter::STOP_VIV_RECORD_CMD);
    printf("   %c. Enable preview frames\n",
            Interpreter::ENABLE_PRV_CALLBACKS_CMD);
    printf("   %c. Trigger autofocus \n",
            Interpreter::AUTOFOCUS_CMD);

    printf(" \n\n IMAGE CAPTURE SUB MENU \n");
    printf(" -----------------------------\n");
    printf("   %c. Take picture/Full Press\n",
            Interpreter::TAKEPICTURE_CMD);
    printf("   %c. Take picture in picture\n",
            Interpreter::TAKEPICTURE_IN_PICTURE_CMD);
    printf("   %c. Picture size:  %dx%d\n",
            Interpreter::CHANGE_PICTURE_SIZE_CMD,
            currentPictureSize.width,
            currentPictureSize.height);
    printf("   %c. zsl:  %s\n", Interpreter::ZSL_CMD,
        (zsl_mode != NULL) ? zsl_mode : "NULL");

    printf("\n   Choice: ");
}

/*===========================================================================
 * FUNCTION   : enablePrintPreview
 *
 * DESCRIPTION: Enables printing the preview
 *
 * PARAMETERS : None
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::enablePrintPreview()
{
    mDoPrintMenu = true;
}

/*===========================================================================
 * FUNCTION   : disablePrintPreview
 *
 * DESCRIPTION: Disables printing the preview
 *
 * PARAMETERS : None
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::disablePrintPreview()
{
    mDoPrintMenu = false;
}

/*===========================================================================
 * FUNCTION   : enablePiPCapture
 *
 * DESCRIPTION: Enables picture in picture capture
 *
 * PARAMETERS : None
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::enablePiPCapture()
{
    mPiPCapture = true;
}

/*===========================================================================
 * FUNCTION   : disablePiPCapture
 *
 * DESCRIPTION: Disables picture in picture capture
 *
 * PARAMETERS : None
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::disablePiPCapture()
{
    mPiPCapture = false;
}

/*===========================================================================
 * FUNCTION   : getZSL
 *
 * DESCRIPTION: get ZSL value of current camera
 *
 * PARAMETERS : None
 *
 * RETURN     : current zsl value
 *==========================================================================*/
const char *CameraContext::getZSL()
{
    return mParams.get(CameraContext::KEY_ZSL);
}

/*===========================================================================
 * FUNCTION   : setZSL
 *
 * DESCRIPTION: set ZSL value of current camera
 *
 * PARAMETERS : zsl value to be set
 *
 * RETURN     : None
 *==========================================================================*/
void CameraContext::setZSL(const char *value)
{
    mParams.set(CameraContext::KEY_ZSL, value);
    mCamera->setParameters(mParams.flatten());
}

/*===========================================================================
 * FUNCTION   : configureViVCodec
 *
 * DESCRIPTION: Configures video in video codec
 *
 * PARAMETERS : none
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t Interpreter::configureViVCodec()
{
    status_t ret = NO_ERROR;
    char fileName[100];
    sp<AMessage> format = new AMessage;
    sp<ALooper> looper = new ALooper;

    if (mTestContext->mViVVid.VideoSizes[0].width *
            mTestContext->mViVVid.VideoSizes[0].height >=
            mTestContext->mViVVid.VideoSizes[1].width *
            mTestContext->mViVVid.VideoSizes[1].height) {
        snprintf(fileName, sizeof(fileName) / sizeof(char), "/sdcard/ViV_vid_%dx%d_%d.mp4",
            mTestContext->mViVVid.VideoSizes[0].width,
            mTestContext->mViVVid.VideoSizes[0].height,
            mTestContext->mViVVid.ViVIdx++);
        format->setInt32("width", mTestContext->mViVVid.VideoSizes[0].width);
        format->setInt32("height", mTestContext->mViVVid.VideoSizes[0].height);
    } else {
        snprintf(fileName, sizeof(fileName) / sizeof(char), "/sdcard/ViV_vid_%dx%d_%d.mp4",
            mTestContext->mViVVid.VideoSizes[1].width,
            mTestContext->mViVVid.VideoSizes[1].height,
            mTestContext->mViVVid.ViVIdx++);
        format->setInt32("width", mTestContext->mViVVid.VideoSizes[1].width);
        format->setInt32("height", mTestContext->mViVVid.VideoSizes[1].height);
    }
    int fd = open(fileName, O_CREAT | O_RDWR );
    if (fd < 0) {
        LOGE("Error opening file");
        return UNKNOWN_ERROR;
    }
    mTestContext->mViVVid.muxer = new MediaMuxer(
        fd, MediaMuxer::OUTPUT_FORMAT_MPEG_4);

    format->setString("mime", "video/avc");
    format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);

    format->setInt32("bitrate", 1000000);
    format->setFloat("frame-rate", 30);
    format->setInt32("i-frame-interval", 10);

    looper->setName("ViV_recording_looper");
    looper->start();
    ALOGV("Creating codec");
    mTestContext->mViVVid.codec = MediaCodec::CreateByType(
        looper, "video/avc", true);
    if (mTestContext->mViVVid.codec == NULL) {
        fprintf(stderr, "ERROR: unable to create video/avc codec instance\n");
        return UNKNOWN_ERROR;
    }
    ret = mTestContext->mViVVid.codec->configure(format, NULL, NULL,
            MediaCodec::CONFIGURE_FLAG_ENCODE);
    if (ret != NO_ERROR) {
        mTestContext->mViVVid.codec->release();
        mTestContext->mViVVid.codec.clear();

        fprintf(stderr, "ERROR: unable to configure codec (err=%d)\n", ret);
        return ret;
    }

    ALOGV("Creating buffer producer");
    ret = mTestContext->mViVVid.codec->createInputSurface(
        &mTestContext->mViVVid.bufferProducer);
    if (ret != NO_ERROR) {
        mTestContext->mViVVid.codec->release();
        mTestContext->mViVVid.codec.clear();

        fprintf(stderr,
            "ERROR: unable to create encoder input surface (err=%d)\n", ret);
        return ret;
    }

    ret = mTestContext->mViVVid.codec->start();
    if (ret != NO_ERROR) {
        mTestContext->mViVVid.codec->release();
        mTestContext->mViVVid.codec.clear();

        fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", ret);
        return ret;
    }
    ALOGV("Codec prepared");

    mTestContext->mViVVid.surface = new Surface(
        mTestContext->mViVVid.bufferProducer);
    mTestContext->mViVVid.ANW = mTestContext->mViVVid.surface;
    ret = native_window_api_connect(mTestContext->mViVVid.ANW.get(),
        NATIVE_WINDOW_API_CPU);
    if (mTestContext->mViVVid.VideoSizes[0].width *
        mTestContext->mViVVid.VideoSizes[0].height >=
        mTestContext->mViVVid.VideoSizes[1].width *
        mTestContext->mViVVid.VideoSizes[1].height) {
        native_window_set_buffers_format(mTestContext->mViVVid.ANW.get(),
                HAL_PIXEL_FORMAT_NV12_ENCODEABLE);
        native_window_set_buffers_dimensions(mTestContext->mViVVid.ANW.get(),
                mTestContext->mViVVid.VideoSizes[0].width,
                mTestContext->mViVVid.VideoSizes[0].height);
    } else {
        native_window_set_buffers_format(mTestContext->mViVVid.ANW.get(),
                HAL_PIXEL_FORMAT_NV12_ENCODEABLE);
        native_window_set_buffers_dimensions(mTestContext->mViVVid.ANW.get(),
                mTestContext->mViVVid.VideoSizes[1].width,
                mTestContext->mViVVid.VideoSizes[1].height);
    }
    native_window_set_usage(mTestContext->mViVVid.ANW.get(),
        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
    native_window_set_buffer_count(mTestContext->mViVVid.ANW.get(),
        mTestContext->mViVVid.buff_cnt);

    ViVEncoderThread();

    return ret;
}

/*===========================================================================
 * FUNCTION   : unconfigureViVCodec
 *
 * DESCRIPTION: Unconfigures video in video codec
 *
 * PARAMETERS : none
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
status_t Interpreter::unconfigureViVCodec()
{
    status_t ret = NO_ERROR;

    ret = native_window_api_disconnect(mTestContext->mViVVid.ANW.get(),
        NATIVE_WINDOW_API_CPU);
    mTestContext->mViVVid.bufferProducer = NULL;
    mTestContext->mViVVid.codec->stop();
    pthread_join(mViVEncThread, NULL);
    mTestContext->mViVVid.muxer->stop();
    mTestContext->mViVVid.codec->release();
    mTestContext->mViVVid.codec.clear();
    mTestContext->mViVVid.muxer.clear();
    mTestContext->mViVVid.surface.clear();
  return ret;
}

/*===========================================================================
 * FUNCTION   : Interpreter
 *
 * DESCRIPTION: Interpreter constructor
 *
 * PARAMETERS : none
 *
 * RETURN     : none
 *==========================================================================*/
Interpreter::Interpreter(const char *file)
    : mCmdIndex(0)
    , mScript(NULL)
{
    if (!file){
        printf("no File Given\n");
        mUseScript = false;
        return;
    }

    FILE *fh = fopen(file, "r");
    if ( !fh ) {
        printf("Could not open file %s\n", file);
        mUseScript = false;
        return;
    }

    fseek(fh, 0, SEEK_END);
    size_t len = (size_t)ftell(fh);
    rewind(fh);

    if( !len ) {
        printf("Script file %s is empty !\n", file);
        fclose(fh);
        return;
    }

    mScript = new char[len + 1];
    if ( !mScript ) {
        fclose(fh);
        return;
    }

    fread(mScript, sizeof(char), len, fh);
    mScript[len] = '\0'; // ensure null terminated;
    fclose(fh);


    char *p1;
    char *p2;
    p1 = p2 = mScript;

    do {
        switch (*p1) {
        case '\0':
        case '|':
            p1++;
            break;
        case SWITCH_CAMERA_CMD:
        case RESUME_PREVIEW_CMD:
        case START_PREVIEW_CMD:
        case STOP_PREVIEW_CMD:
        case CHANGE_PREVIEW_SIZE_CMD:
        case CHANGE_PICTURE_SIZE_CMD:
        case START_RECORD_CMD:
        case STOP_RECORD_CMD:
        case START_VIV_RECORD_CMD:
        case STOP_VIV_RECORD_CMD:
        case DUMP_CAPS_CMD:
        case AUTOFOCUS_CMD:
        case TAKEPICTURE_CMD:
        case TAKEPICTURE_IN_PICTURE_CMD:
        case ENABLE_PRV_CALLBACKS_CMD:
        case EXIT_CMD:
        case ZSL_CMD:
        case DELAY:
            p2 = p1;
            while( (p2 != (mScript + len)) && (*p2 != '|')) {
                p2++;
            }
            *p2 = '\0';
            if (p2 == (p1 + 1))
                mCommands.push_back(Command(
                    static_cast<Interpreter::Commands_e>(*p1)));
            else
                mCommands.push_back(Command(
                    static_cast<Interpreter::Commands_e>(*p1), (p1 + 1)));
            p1 = p2;
            break;
        default:
            printf("Invalid cmd %c \n", *p1);
            do {
                p1++;

            } while(*p1 != '|' && p1 != (mScript + len));

        }
    } while(p1 != (mScript + len));
    mUseScript = true;
}

/*===========================================================================
 * FUNCTION   : ~Interpreter
 *
 * DESCRIPTION: Interpreter destructor
 *
 * PARAMETERS : none
 *
 * RETURN     : none
 *==========================================================================*/
Interpreter::~Interpreter()
{
    if ( mScript )
        delete[] mScript;

    mCommands.clear();
}

/*===========================================================================
 * FUNCTION        : getCommand
 *
 * DESCRIPTION     : Get a command from interpreter
 *
 * PARAMETERS      :
 *   @currentCamera: Current camera context
 *
 * RETURN          : command
 *==========================================================================*/
Interpreter::Command Interpreter::getCommand(
    sp<CameraContext> currentCamera)
{
    if( mUseScript ) {
        return mCommands[mCmdIndex++];
    } else {
        currentCamera->printMenu(currentCamera);
        return Interpreter::Command(
            static_cast<Interpreter::Commands_e>(getchar()));
    }
}

/*===========================================================================
 * FUNCTION        : TestContext
 *
 * DESCRIPTION     : TestContext constructor
 *
 * PARAMETERS      : None
 *
 * RETURN          : None
 *==========================================================================*/
TestContext::TestContext()
{
    int i = 0;
    mTestRunning = false;
    mInterpreter = NULL;
    mViVVid.ViVIdx = 0;
    mViVVid.buff_cnt = 9;
    mViVVid.graphBuf = 0;
    mViVVid.mappedBuff = NULL;
    mViVVid.isBuffValid = false;
    mViVVid.sourceCameraID = -1;
    mViVVid.destinationCameraID = -1;
    mPiPinUse = false;
    mViVinUse = false;
    mIsZSLOn = false;
    memset(&mViVBuff, 0, sizeof(ViVBuff_t));

    ProcessState::self()->startThreadPool();

    do {
        camera[i] = new CameraContext(i);
        if ( NULL == camera[i].get() ) {
            break;
        }
        camera[i]->setTestCtxInstance(this);

        //by default open only back camera
        if (i==0) {
            status_t stat = camera[i]->openCamera();
            if ( NO_ERROR != stat ) {
                printf("Error encountered Openging camera id : %d\n", i);
                break;
            }
        }
        mAvailableCameras.add(camera[i]);
        i++;
    } while ( i < camera[0]->getNumberOfCameras() ) ;

    if (i < camera[0]->getNumberOfCameras() ) {
        for (size_t j = 0; j < mAvailableCameras.size(); j++) {
            camera[j] = mAvailableCameras.itemAt(j);
            camera[j]->closeCamera();
            camera[j].clear();
        }

        mAvailableCameras.clear();
    }
}

/*===========================================================================
 * FUNCTION        : ~TestContext
 *
 * DESCRIPTION     : TestContext destructor
 *
 * PARAMETERS      : None
 *
 * RETURN          : None
 *==========================================================================*/
TestContext::~TestContext()
{
    delete mInterpreter;

    for (size_t j = 0; j < mAvailableCameras.size(); j++) {
        camera[j] = mAvailableCameras.itemAt(j);
        camera[j]->closeCamera();
        camera[j].clear();
    }

    mAvailableCameras.clear();
}

/*===========================================================================
 * FUNCTION        : GetCamerasNum
 *
 * DESCRIPTION     : Get the number of available cameras
 *
 * PARAMETERS      : None
 *
 * RETURN          : Number of cameras
 *==========================================================================*/
size_t TestContext::GetCamerasNum()
{
    return mAvailableCameras.size();
}

/*===========================================================================
 * FUNCTION        : AddScriptFromFile
 *
 * DESCRIPTION     : Add script from file
 *
 * PARAMETERS      :
 *   @scriptFile   : Script file
 *
 * RETURN          : status_t type of status
 *                   NO_ERROR  -- success
 *                   none-zero failure code
 *==========================================================================*/
status_t TestContext::AddScriptFromFile(const char *scriptFile)
{
    mInterpreter = new Interpreter(scriptFile);
    mInterpreter->setTestCtxInst(this);

    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION        : releasePiPBuff
 *
 * DESCRIPTION     : Release video in video temp buffer
 *
 * PARAMETERS      : None
 *
 * RETURN          : None
 *==========================================================================*/
void Interpreter::releasePiPBuff() {
    free(mTestContext->mViVBuff.buff);
    mTestContext->mViVBuff.buff = NULL;
}

/*===========================================================================
 * FUNCTION   : functionalTest
 *
 * DESCRIPTION: queries and executes client supplied commands for testing a
 *              particular camera.
 *
 * PARAMETERS :
 *  @availableCameras : List with all cameras supported
 *
 * RETURN     : status_t type of status
 *              NO_ERROR  -- continue testing
 *              none-zero -- quit test
 *==========================================================================*/
status_t TestContext::FunctionalTest()
{
    status_t stat = NO_ERROR;
    const char *ZSLStr = NULL;
    size_t ZSLStrSize = 0;

    assert(mAvailableCameras.size());

    if ( !mInterpreter ) {
        mInterpreter = new Interpreter();
        mInterpreter->setTestCtxInst(this);
    }

    if (mAvailableCameras.size() == 0) {
        printf("no cameras supported... exiting test app\n");
    } else {
        mTestRunning = true;
    }

    while (mTestRunning) {
        sp<CameraContext> currentCamera =
            mAvailableCameras.itemAt(mCurrentCameraIndex);
        Interpreter::Command command =
            mInterpreter->getCommand(currentCamera);
        currentCamera->enablePrintPreview();

        switch (command.cmd) {
        case Interpreter::SWITCH_CAMERA_CMD:
        {
            mCurrentCameraIndex++;
            mCurrentCameraIndex %= mAvailableCameras.size();
            currentCamera = mAvailableCameras.itemAt(mCurrentCameraIndex);
            stat = currentCamera->openCamera();
        }
            break;

        case Interpreter::RESUME_PREVIEW_CMD:
        {
            stat = currentCamera->resumePreview();
        }
            break;

        case Interpreter::START_PREVIEW_CMD:
        {
            stat = currentCamera->startPreview();
        }
            break;

        case Interpreter::STOP_PREVIEW_CMD:
        {
            stat = currentCamera->stopPreview();
        }
            break;

        case Interpreter::CHANGE_VIDEO_SIZE_CMD:
        {
            if ( command.arg )
                stat = currentCamera->setVideoSize(command.arg);
            else
                stat = currentCamera->nextVideoSize();
        }
        break;

        case Interpreter::CHANGE_PREVIEW_SIZE_CMD:
        {
            if ( command.arg )
                stat = currentCamera->setPreviewSize(command.arg);
            else
                stat = currentCamera->nextPreviewSize();
        }
            break;

        case Interpreter::CHANGE_PICTURE_SIZE_CMD:
        {
            if ( command.arg )
                stat = currentCamera->setPictureSize(command.arg);
            else
                stat = currentCamera->nextPictureSize();
        }
            break;

        case Interpreter::DUMP_CAPS_CMD:
        {
            currentCamera->printSupportedParams();
        }
            break;

        case Interpreter::AUTOFOCUS_CMD:
        {
            stat = currentCamera->autoFocus();
        }
            break;

        case Interpreter::TAKEPICTURE_CMD:
        {
            stat = currentCamera->takePicture();
        }
            break;

        case Interpreter::TAKEPICTURE_IN_PICTURE_CMD:
        {
            if (mAvailableCameras.size() == 2) {
                mSaveCurrentCameraIndex = mCurrentCameraIndex;
                for (size_t i = 0; i < mAvailableCameras.size(); i++) {
                    mCurrentCameraIndex = i;
                    currentCamera = mAvailableCameras.itemAt(mCurrentCameraIndex);
                    currentCamera->enablePiPCapture();
                    stat = currentCamera->takePicture();
                }
                mCurrentCameraIndex = mSaveCurrentCameraIndex;
            } else {
                printf("Number of available sensors should be 2\n");
            }
        }
        break;

        case Interpreter::ENABLE_PRV_CALLBACKS_CMD:
        {
            stat = currentCamera->enablePreviewCallbacks();
        }
            break;

        case Interpreter::START_RECORD_CMD:
        {
            stat = currentCamera->stopPreview();
            stat = currentCamera->configureRecorder();
            stat = currentCamera->startPreview();
            stat = currentCamera->startRecording();
        }
            break;

        case Interpreter::STOP_RECORD_CMD:
        {
            stat = currentCamera->stopRecording();

            stat = currentCamera->stopPreview();
            stat = currentCamera->unconfigureRecorder();
            stat = currentCamera->startPreview();
        }
            break;

        case Interpreter::START_VIV_RECORD_CMD:
        {

            if (mAvailableCameras.size() == 2) {
                mSaveCurrentCameraIndex = mCurrentCameraIndex;
                stat = mInterpreter->configureViVCodec();
                for ( size_t i = 0; i < mAvailableCameras.size(); i++ ) {
                    mCurrentCameraIndex = i;
                    currentCamera = mAvailableCameras.itemAt(
                        mCurrentCameraIndex);
                    stat = currentCamera->stopPreview();
                    stat = currentCamera->configureViVRecording();
                    stat = currentCamera->startPreview();
                    stat = currentCamera->startViVRecording();
                }
                mCurrentCameraIndex = mSaveCurrentCameraIndex;
            } else {
                printf("Number of available sensors should be 2\n");
            }

        }
            break;

        case Interpreter::STOP_VIV_RECORD_CMD:
        {
            if (mAvailableCameras.size() == 2) {
                mSaveCurrentCameraIndex = mCurrentCameraIndex;
                for ( size_t i = 0; i < mAvailableCameras.size(); i++ ) {
                    mCurrentCameraIndex = i;
                    currentCamera = mAvailableCameras.itemAt(
                        mCurrentCameraIndex);
                    stat = currentCamera->stopViVRecording();
                    stat = currentCamera->stopPreview();
                    stat = currentCamera->unconfigureRecorder();
                    stat = currentCamera->startPreview();
                }
                stat = mInterpreter->unconfigureViVCodec();
                mCurrentCameraIndex = mSaveCurrentCameraIndex;

                mInterpreter->releasePiPBuff();
            } else {
                printf("Number of available sensors should be 2\n");
            }
        }
        break;

        case Interpreter::EXIT_CMD:
        {
            currentCamera->stopPreview();
            mTestRunning = false;
        }
            break;

        case Interpreter::DELAY:
        {
            if ( command.arg ) {
                int delay = atoi(command.arg);
                if (0 < delay) {
                    usleep(1000U * (unsigned int)delay);
                }
            }
        }
            break;

        case Interpreter::ZSL_CMD:
        {
            currentCamera = mAvailableCameras.itemAt(
                    mCurrentCameraIndex);
            ZSLStr = currentCamera->getZSL();

            if (NULL != ZSLStr) {
                ZSLStrSize = strlen(ZSLStr);
                if (!strncmp(ZSLStr, "off", ZSLStrSize)) {
                    currentCamera->setZSL("on");
                    mIsZSLOn = true;
                } else if (!strncmp(ZSLStr, "on", ZSLStrSize)) {
                    currentCamera->setZSL("off");
                    mIsZSLOn = false;
                } else {
                    printf("Set zsl failed!\n");
                }
            } else {
                printf("zsl is NULL\n");
            }
        }
            break;

        default:
        {
            currentCamera->disablePrintPreview();
        }
            break;
        }
        printf("Command status 0x%x \n", stat);
    }

    return NO_ERROR;
}

/*===========================================================================
 * FUNCTION   : PiPLock
 *
 * DESCRIPTION: Mutex lock for PiP capture
 *
 * PARAMETERS : none
 *
 * RETURN     : none
 *==========================================================================*/
void TestContext::PiPLock()
{
    Mutex::Autolock l(mPiPLock);
    while (mPiPinUse) {
        mPiPCond.wait(mPiPLock);
    }
    mPiPinUse = true;
}

/*===========================================================================
 * FUNCTION   : PiPUnLock
 *
 * DESCRIPTION: Mutex unlock for PiP capture
 *
 * PARAMETERS : none
 *
 * RETURN     : none
 *==========================================================================*/
void TestContext::PiPUnlock()
{
    Mutex::Autolock l(mPiPLock);
    mPiPinUse = false;
    mPiPCond.signal();
}

/*===========================================================================
 * FUNCTION   : ViVLock
 *
 * DESCRIPTION: Mutex lock for ViV Video
 *
 * PARAMETERS : none
 *
 * RETURN     : none
 *==========================================================================*/
void TestContext::ViVLock()
{
    Mutex::Autolock l(mViVLock);
    while (mViVinUse) {
        mViVCond.wait(mViVLock);
    }
    mViVinUse = true;
}

/*===========================================================================
 * FUNCTION   : ViVUnlock
 *
 * DESCRIPTION: Mutex unlock for ViV Video
 *
 * PARAMETERS : none
 *
 * RETURN     : none
 *==========================================================================*/
void TestContext::ViVUnlock()
{
    Mutex::Autolock l(mViVLock);
    mViVinUse = false;
    mViVCond.signal();
}

/*===========================================================================
 * FUNCTION     : setViVSize
 *
 * DESCRIPTION  : Set video in video size
 *
 * PARAMETERS   :
 *   @VideoSize : video size
 *   @camIndex  : camera index
 *
 * RETURN       : none
 *==========================================================================*/
void TestContext::setViVSize(Size VideoSize, int camIndex)
{
    mViVVid.VideoSizes[camIndex] = VideoSize;
}

/*===========================================================================
 * FUNCTION     : main
 *
 * DESCRIPTION  : main function
 *
 * PARAMETERS   :
 *   @argc      : argc
 *   @argv      : argv
 *
 * RETURN       : int status
 *==========================================================================*/
int main(int argc, char *argv[])
{
    TestContext ctx;

    if (argc > 1) {
        if ( ctx.AddScriptFromFile((const char *)argv[1]) ) {
            printf("Could not add script file... "
                "continuing in normal menu mode! \n");
        }
    }

    ctx.FunctionalTest();

    return 0;
}