| /* 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; |
| |
| if (!SkEncodeImage(stream, *bitmap, SkEncodedImageFormat::kJPEG, qFactor)) { |
| ALOGE(" SkEncodeImage failed\n"); |
| 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; |
| } |