/* Copyright (c) 2012-2014, The Linux Foundataion. 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"
#define ERROR(format, ...) printf( \
"%s[%d] : ERROR: "format"\n", __func__, __LINE__, ##__VA_ARGS__)
#define VIDEO_BUF_ALLIGN(size, allign) (((size) + (allign-1)) & (~(allign-1)))
namespace qcamera {
using namespace android;
int CameraContext::JpegIdx = 0;
int CameraContext::mPiPIdx = 0;
SkBitmap *CameraContext::skBMtmp[2];
sp<IMemory> CameraContext::PiPPtrTmp[2];
/*===========================================================================
* 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 0x%x", ( unsigned int ) mem->pointer());
uint8_t *ptr = (uint8_t*) mem->pointer();
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]);
}
/*===========================================================================
* FUNCTION : useLock
*
* DESCRIPTION: Mutex lock for CameraContext
*
* PARAMETERS : none
*
* RETURN : none
*==========================================================================*/
void CameraContext::useLock()
{
Mutex::Autolock l(mLock);
if ( mInUse ) {
mCond.wait(mLock);
} else {
mInUse = true;
}
}
/*===========================================================================
* FUNCTION : signalFinished
*
* DESCRIPTION: Mutex unlock CameraContext
*
* PARAMETERS : none
*
* RETURN : none
*==========================================================================*/
void CameraContext::signalFinished()
{
Mutex::Autolock l(mLock);
mInUse = false;
mCond.signal();
}
/*===========================================================================
* FUNCTION : mutexLock
*
* DESCRIPTION: Mutex lock for ViV Video
*
* PARAMETERS : none
*
* RETURN : none
*==========================================================================*/
void CameraContext::mutexLock()
{
Mutex::Autolock l(mViVLock);
if (mViVinUse ) {
mViVCond.wait(mViVLock);
} else {
mViVinUse = true;
}
}
/*===========================================================================
* FUNCTION : mutexUnLock
*
* DESCRIPTION: Mutex unlock for ViV Video
*
* PARAMETERS : none
*
* RETURN : none
*==========================================================================*/
void CameraContext::mutexUnlock()
{
Mutex::Autolock l(mViVLock);
mViVinUse = false;
mViVCond.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;
int 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 = 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) ) {
printf("Bad Write error (%d)%s\n",
errno,
strerror(errno));
close(fd);
return INVALID_OPERATION;
}
printf("%s: buffer=%08X, size=%d stored at %s\n",
__FUNCTION__, (int)buff, 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)
{
int size0;
int size1;
SkBitmap *src;
SkBitmap *dst;
unsigned int dstOffset;
unsigned int srcOffset;
if (bitmap0 == NULL && bitmap1 == NULL) {
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(int i=0; i<src->height(); i++) {
dstOffset = i*(dst->width())*mfmtMultiplier;
srcOffset = i*(src->width())*mfmtMultiplier;
memcpy(((unsigned char *) dst->getPixels())+dstOffset,
((unsigned char *) src->getPixels())+srcOffset,
src->width()*mfmtMultiplier);
}
return dst;
}
/*===========================================================================
* FUNCTION : decodeJPEG
*
* DESCRIPTION: decode jpeg input buffer.
*
* PARAMETERS :
* @mem : buffer to decode
*
* RETURN : decoded picture in SkBitmap
*==========================================================================*/
SkBitmap *CameraContext::decodeJPEG(const sp<IMemory>& mem)
{
SkBitmap *skBM;
skBM = new SkBitmap; //Deleted in encodeJPEG (skBMtmp[0] and skBMtmp[1])
SkBitmap::Config prefConfig = SkBitmap::kARGB_8888_Config;
const void *buff = NULL;
int 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 NULL;
}
return skBM;
}
/*===========================================================================
* 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;
long len;
status_t ret;
unsigned char *buff;
unsigned char temp;
skJpegEnc = SkImageEncoder::Create(SkImageEncoder::kJPEG_Type);
if (skJpegEnc->encodeStream(stream, *bitmap, qFactor) == false) {
return BAD_VALUE;
}
printf("%s: buffer=%08X, size=%d stored at %s\n",
__FUNCTION__, (int)bitmap->getPixels(),
bitmap->getSize(), path.string());
delete skBMtmp[0];
delete skBMtmp[1];
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);
len = ftell(fh);
rewind(fh);
if( !len ) {
printf("File %s is empty !\n", path.string());
fclose(fh);
return BAD_VALUE;
}
buff = (unsigned char*)malloc(len);
if (!buff) {
printf("Cannot allocate memory for buffer reading!\n");
return BAD_VALUE;
}
ret = fread(buff, 1, len, fh);
if (ret != len) {
printf("Reading error\n");
return BAD_VALUE;
}
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);
temp = 0xff;
ret = fwrite(&temp, sizeof(unsigned char), 1, fh);
if (ret != 1) {
printf("Writing error\n");
}
temp = 0xd8;
fwrite(&temp, sizeof(unsigned char), 1, fh);
for (int 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;
}
}
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,
unsigned int buffer_size, ReadMode_t ReadMode)
{
int a;
unsigned int pos = 0;
int HaveCom = 0;
mSectionsAllocated = 10;
mSections = (Sections_t *)malloc(sizeof(Sections_t) * mSectionsAllocated);
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(;;){
int itemlen;
int marker = 0;
int ll,lh;
unsigned char * Data;
CheckSectionsAllocated();
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){
int 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();
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)
{
int a;
for (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()
{
int a;
for (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) && (ext1 == CAMERA_FRAME_DATA_FD)) {
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)
{
Size currentPictureSize = mSupportedPictureSizes.itemAt(
mCurrentPictureSizeIdx);
unsigned char *buff = NULL;
int 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("/sdcard/img_%d.jpg", JpegIdx);
if (!mPiPCapture) {
// Normal capture case
printf("JPEG done\n");
saveFile(dataPtr, jpegPath);
JpegIdx++;
} else {
// PiP capture case
SkFILEWStream *wStream;
skBMtmp[mPiPIdx] = decodeJPEG(dataPtr);
mWidthTmp[mPiPIdx] = currentPictureSize.width;
mHeightTmp[mPiPIdx] = currentPictureSize.height;
PiPPtrTmp[mPiPIdx] = 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 ((mWidthTmp[0]*mHeightTmp[0]) >
(mWidthTmp[1]*mHeightTmp[1])) {
buff = (unsigned char *)PiPPtrTmp[0]->pointer();
size = PiPPtrTmp[0]->size();
} else if ((mWidthTmp[0]*mHeightTmp[0]) <
(mWidthTmp[1]*mHeightTmp[1])) {
buff = (unsigned char *)PiPPtrTmp[1]->pointer();
size = PiPPtrTmp[1]->size();
} else {
printf("Cannot take PiP. Images are with the same width"
" and height size!!!\n");
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();
return;
}
mJEXIFTmp = FindSection(M_EXIF);
mJEXIFSection = *mJEXIFTmp;
mJEXIFSection.Data =
(unsigned char*)malloc(mJEXIFTmp->Size);
memcpy(mJEXIFSection.Data,
mJEXIFTmp->Data, mJEXIFTmp->Size);
DiscardData();
DiscardSections();
wStream = new SkFILEWStream(jpegPath.string());
skBMDec = PiPCopyToOneFile(skBMtmp[0], skBMtmp[1]);
if (encodeJPEG(wStream, skBMDec, jpegPath) != false) {
printf("%s():%d:: Failed during jpeg encode\n",
__FUNCTION__,__LINE__);
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);
}
signalFinished();
}
/*===========================================================================
* 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, 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)
{
mutexLock();
// 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;
int 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 (mCameraIndex == mInterpr->mViVVid.sourceCameraID) {
srcYStride = calcStride(currentVideoSize.width);
srcUVStride = calcStride(currentVideoSize.width);
srcYScanLines = calcYScanLines(currentVideoSize.height);
srcUVScanLines = calcUVScanLines(currentVideoSize.height);
mInterpr->mViVBuff.srcWidth = currentVideoSize.width;
mInterpr->mViVBuff.srcHeight = currentVideoSize.height;
mInterpr->mViVBuff.YStride = srcYStride;
mInterpr->mViVBuff.UVStride = srcUVStride;
mInterpr->mViVBuff.YScanLines = srcYScanLines;
mInterpr->mViVBuff.UVScanLines = srcUVScanLines;
memcpy( mInterpr->mViVBuff.buff, (void *) dataPtr->pointer(),
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<(int) 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<(int) 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);
return;
}
mInterpr->mViVVid.graphBuf = new GraphicBuffer(anb, false);
if(NULL == mInterpr->mViVVid.graphBuf.get()) {
printf("Invalid Graphic buffer\n");
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);
return;
}
srcYStride = dstYStride;
srcUVStride = dstUVStride;
srcYScanLines = dstYScanLines;
srcUVScanLines = dstUVScanLines;
srcBuff = dstBuff;
for (i=0; i<(int) currentVideoSize.height; i++) {
srcOffset = i*srcYStride;
dstOffset = i*dstYStride;
memcpy((unsigned char *) mInterpr->mViVVid.mappedBuff +
dstOffset, (unsigned char *) srcBuff +
srcOffset, currentVideoSize.width);
}
srcBaseOffset = srcYStride * srcYScanLines;
dstBaseOffset = dstUVStride * currentVideoSize.height;
for (i=0;i<(int) currentVideoSize.height/2;i++) {
srcOffset = i*srcUVStride + srcBaseOffset;
dstOffset = i*dstUVStride + dstBaseOffset;
memcpy((unsigned char *) mInterpr->mViVVid.mappedBuff +
dstOffset, (unsigned char *) srcBuff +
srcOffset, 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);
mutexUnlock();
}
/*===========================================================================
* 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],
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(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(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(((height + 1) >> 1), alignment);
return scanlines;
}
/*===========================================================================
* FUNCTION : printSupportedParams
*
* DESCRIPTION: dump common supported parameters
*
* PARAMETERS : None
*
* RETURN : None
*==========================================================================*/
void CameraContext::printSupportedParams()
{
printf("\n\r\tSupported Cameras: %s",
mParams.get("camera-indexes")?
mParams.get("camera-indexes") : "NULL");
printf("\n\r\tSupported Picture Sizes: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES)?
mParams.get(
CameraParameters::KEY_SUPPORTED_PICTURE_SIZES) : "NULL");
printf("\n\r\tSupported Picture Formats: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS)?
mParams.get(
CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS) : "NULL");
printf("\n\r\tSupported Preview Sizes: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES)?
mParams.get(
CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES) : "NULL");
printf("\n\r\tSupported Video Sizes: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES)?
mParams.get(
CameraParameters::KEY_SUPPORTED_VIDEO_SIZES) : "NULL");
printf("\n\r\tSupported Preview Formats: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS)?
mParams.get(
CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS) : "NULL");
printf("\n\r\tSupported Preview Frame Rates: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES)?
mParams.get(
CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES) : "NULL");
printf("\n\r\tSupported Thumbnail Sizes: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES)?
mParams.get(
CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES) : "NULL");
printf("\n\r\tSupported Whitebalance Modes: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE)?
mParams.get(
CameraParameters::KEY_SUPPORTED_WHITE_BALANCE) : "NULL");
printf("\n\r\tSupported Effects: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_EFFECTS)?
mParams.get(CameraParameters::KEY_SUPPORTED_EFFECTS) : "NULL");
printf("\n\r\tSupported Scene Modes: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_SCENE_MODES)?
mParams.get(CameraParameters::KEY_SUPPORTED_SCENE_MODES) : "NULL");
printf("\n\r\tSupported Focus Modes: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES)?
mParams.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES) : "NULL");
printf("\n\r\tSupported Antibanding Options: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_ANTIBANDING)?
mParams.get(CameraParameters::KEY_SUPPORTED_ANTIBANDING) : "NULL");
printf("\n\r\tSupported Flash Modes: %s",
mParams.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES)?
mParams.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES) : "NULL");
printf("\n\r\tSupported Focus Areas: %d",
mParams.getInt(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS));
printf("\n\r\tSupported FPS ranges : %s",
mParams.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE)?
mParams.get(
CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE) : "NULL");
printf("\n\r\tFocus Distances: %s \n",
mParams.get(CameraParameters::KEY_FOCUS_DISTANCES)?
mParams.get(CameraParameters::KEY_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(unsigned int width,
unsigned int height,
int32_t pixFormat)
{
int ret = NO_ERROR;
DisplayInfo dinfo;
sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
ISurfaceComposer::eDisplayIdMain));
SurfaceComposerClient::getDisplayInfo(display, &dinfo);
unsigned int previewWidth, previewHeight;
if ( dinfo.w < width ) {
previewWidth = dinfo.w;
} else {
previewWidth = width;
}
if ( dinfo.h < height ) {
previewHeight = dinfo.h;
} else {
previewHeight = 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(
dinfo.w - previewWidth, 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(false),
mSections(NULL),
mJEXIFTmp(NULL),
mHaveAll(false),
mViVinUse(false),
mCamera(NULL),
mClient(NULL),
mSurfaceControl(NULL),
mPreviewSurface(NULL),
mInUse(false)
{
mRecorder = new MediaRecorder();
}
/*===========================================================================
* 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();
if ( NULL != mCamera.get() ) {
printf("Camera already open! \n");
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");
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);
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()];
float tolerance = 0.00001;
float videoRatio;
float 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(); // Unlocked in jpeg callback
if ( mPreviewRunning ) {
ret = mCamera->takePicture(
CAMERA_MSG_COMPRESSED_IMAGE|
CAMERA_MSG_RAW_IMAGE);
if (!mRecordingHint) {
mPreviewRunning = false;
}
} else {
printf("Please resume/start the preview before taking a picture!\n");
signalFinished(); //Unlock in case preview is not running
}
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 ) {
ERROR("Could not configure recorder (%d)", ret);
return ret;
}
ret = mRecorder->setCamera(
mCamera->remote(), mCamera->getRecordingProxy());
if ( ret != NO_ERROR ) {
ERROR("Could not set camera (%d)", ret);
return ret;
}
ret = mRecorder->setVideoSource(VIDEO_SOURCE_CAMERA);
if ( ret != NO_ERROR ) {
ERROR("Could not set video soruce (%d)", ret);
return ret;
}
ret = mRecorder->setAudioSource(AUDIO_SOURCE_DEFAULT);
if ( ret != NO_ERROR ) {
ERROR("Could not set audio source (%d)", ret);
return ret;
}
ret = mRecorder->setOutputFormat(OUTPUT_FORMAT_DEFAULT);
if ( ret != NO_ERROR ) {
ERROR("Could not set output format (%d)", ret);
return ret;
}
ret = mRecorder->setVideoEncoder(VIDEO_ENCODER_DEFAULT);
if ( ret != NO_ERROR ) {
ERROR("Could not set video encoder (%d)", ret);
return ret;
}
char fileName[100];
sprintf(fileName, "/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 ) {
ERROR("Could not open video file for writing %s!", fileName);
return UNKNOWN_ERROR;
}
ret = mRecorder->setOutputFile(mVideoFd, 0, 0);
if ( ret != NO_ERROR ) {
ERROR("Could not set output file (%d)", ret);
return ret;
}
ret = mRecorder->setVideoSize(videoSize.width, videoSize.height);
if ( ret != NO_ERROR ) {
ERROR("Could not set video size %dx%d", videoSize.width,
videoSize.height);
return ret;
}
ret = mRecorder->setVideoFrameRate(30);
if ( ret != NO_ERROR ) {
ERROR("Could not set video frame rate (%d)", ret);
return ret;
}
ret = mRecorder->setAudioEncoder(AUDIO_ENCODER_DEFAULT);
if ( ret != NO_ERROR ) {
ERROR("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 ) {
ERROR("Could not prepare recorder");
return ret;
}
ret = mRecorder->start();
if ( ret != NO_ERROR ) {
ERROR("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;
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("\n");
printf(" 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 : 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) {
sprintf(fileName, "/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 {
sprintf(fileName, "/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);
}
mTestContext->mViVVid.muxer = new MediaMuxer(
fileName, 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_geometry(mTestContext->mViVVid.ANW.get(),
mTestContext->mViVVid.VideoSizes[0].width,
mTestContext->mViVVid.VideoSizes[0].height,
HAL_PIXEL_FORMAT_NV12_ENCODEABLE);
} else {
native_window_set_buffers_geometry(mTestContext->mViVVid.ANW.get(),
mTestContext->mViVVid.VideoSizes[1].width,
mTestContext->mViVVid.VideoSizes[1].height,
HAL_PIXEL_FORMAT_NV12_ENCODEABLE);
}
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);
int len = 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 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()
{
sp<CameraContext> camera;
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;
memset(&mViVBuff, 0, sizeof(ViVBuff_t));
ProcessState::self()->startThreadPool();
do {
camera = new CameraContext(i);
if ( NULL == camera.get() ) {
break;
}
camera->setTestCtxInstance(this);
status_t stat = camera->openCamera();
if ( NO_ERROR != stat ) {
printf("Error encountered Openging camera id : %d\n", i);
break;
}
mAvailableCameras.add(camera);
i++;
} while ( i < camera->getNumberOfCameras() ) ;
if (i < camera->getNumberOfCameras() ) {
for (size_t j = 0; j < mAvailableCameras.size(); j++) {
camera = mAvailableCameras.itemAt(j);
camera->closeCamera();
camera.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++) {
sp<CameraContext> camera = mAvailableCameras.itemAt(j);
camera->closeCamera();
camera.clear();
}
mAvailableCameras.clear();
}
/*===========================================================================
* FUNCTION : GetCamerasNum
*
* DESCRIPTION : Get the number of available cameras
*
* PARAMETERS : None
*
* RETURN : Number of cameras
*==========================================================================*/
int32_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;
assert(mAvailableCameras.size());
if ( !mInterpreter ) {
mInterpreter = new Interpreter();
mInterpreter->setTestCtxInst(this);
}
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);
}
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 )
usleep(1000 * atoi(command.arg));
}
break;
default:
{
currentCamera->disablePrintPreview();
}
break;
}
printf("Command status 0x%x \n", stat);
}
return NO_ERROR;
}
/*===========================================================================
* 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;
}