Camera : Enable VFE output 2 for video recording
HAL changes required for handling VFE output 2 frames for video recording
diff --git a/QualcommCameraHardware.cpp b/QualcommCameraHardware.cpp
index db04f01..0aadcfa 100644
--- a/QualcommCameraHardware.cpp
+++ b/QualcommCameraHardware.cpp
@@ -28,6 +28,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <fcntl.h>
#include <cutils/properties.h>
#include <math.h>
#if HAVE_ANDROID_OS
@@ -73,6 +74,9 @@
#define MAX_ZOOM_LEVEL 5
#define NOT_FOUND -1
+// Number of video buffers held by kernal (initially 1,2 &3)
+#define ACTIVE_VIDEO_BUFFERS 3
+
#if DLOPEN_LIBMMCAMERA
#include <dlfcn.h>
@@ -86,6 +90,14 @@
common_crop_t *scaling_parms, exif_tags_info_t *exif_data,
int exif_table_numEntries);
int (*LINK_camframe_terminate)(void);
+//for 720p
+// Function to add a video buffer to free Q
+void (*LINK_camframe_free_video)(struct msm_frame *frame);
+// Function pointer , called by camframe when a video frame is available.
+void (**LINK_camframe_video_callback)(struct msm_frame * frame);
+// To flush free Q in cam frame.
+void (*LINK_cam_frame_flush_free_video)(void);
+
int8_t (*LINK_jpeg_encoder_setMainImageQuality)(uint32_t quality);
int8_t (*LINK_jpeg_encoder_setThumbnailQuality)(uint32_t quality);
int8_t (*LINK_jpeg_encoder_setRotation)(uint32_t rotation);
@@ -619,11 +631,121 @@
return str;
}
+extern "C" {
+//------------------------------------------------------------------------
+// : 720p busyQ funcitons
+// --------------------------------------------------------------------
+static struct fifo_queue g_busy_frame_queue =
+ {0, 0, 0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER};
+};
+/*===========================================================================
+ * FUNCTION cam_frame_wait_video
+ *
+ * DESCRIPTION this function waits a video in the busy queue
+ * ===========================================================================*/
+
+static void cam_frame_wait_video (void)
+{
+ LOGV("cam_frame_wait_video E ");
+ if ((g_busy_frame_queue.num_of_frames) <=0){
+ pthread_cond_wait(&(g_busy_frame_queue.wait), &(g_busy_frame_queue.mut));
+ }
+ LOGV("cam_frame_wait_video X");
+ return;
+}
+
+/*===========================================================================
+ * FUNCTION cam_frame_flush_video
+ *
+ * DESCRIPTION this function deletes all the buffers in busy queue
+ * ===========================================================================*/
+void cam_frame_flush_video (void)
+{
+ LOGV("cam_frame_flush_video: in n = %d\n", g_busy_frame_queue.num_of_frames);
+ pthread_mutex_lock(&(g_busy_frame_queue.mut));
+
+ while (g_busy_frame_queue.front)
+ {
+ //dequeue from the busy queue
+ struct fifo_node *node = dequeue (&g_busy_frame_queue);
+ if(node)
+ free(node);
+
+ LOGV("cam_frame_flush_video: node \n");
+ }
+ pthread_mutex_unlock(&(g_busy_frame_queue.mut));
+ LOGV("cam_frame_flush_video: out n = %d\n", g_busy_frame_queue.num_of_frames);
+ return ;
+}
+/*===========================================================================
+ * FUNCTION cam_frame_get_video
+ *
+ * DESCRIPTION this function returns a video frame from the head
+ * ===========================================================================*/
+static struct msm_frame * cam_frame_get_video()
+{
+ struct msm_frame *p = NULL;
+ LOGV("cam_frame_get_video... in\n");
+ LOGV("cam_frame_get_video... got lock\n");
+ if (g_busy_frame_queue.front)
+ {
+ //dequeue
+ struct fifo_node *node = dequeue (&g_busy_frame_queue);
+ if (node)
+ {
+ p = (struct msm_frame *)node->f;
+ free (node);
+ }
+ LOGV("cam_frame_get_video... out = %x\n", p->buffer);
+ }
+ return p;
+}
+
+/*===========================================================================
+ * FUNCTION cam_frame_post_video
+ *
+ * DESCRIPTION this function add a busy video frame to the busy queue tails
+ * ===========================================================================*/
+static void cam_frame_post_video (struct msm_frame *p)
+{
+ if (!p)
+ {
+ LOGE("post video , buffer is null");
+ return;
+ }
+ LOGV("cam_frame_post_video... in = %x\n", (unsigned int)(p->buffer));
+ pthread_mutex_lock(&(g_busy_frame_queue.mut));
+ LOGV("post_video got lock. q count before enQ %d", g_busy_frame_queue.num_of_frames);
+ //enqueue to busy queue
+ struct fifo_node *node = (struct fifo_node *)malloc (sizeof (struct fifo_node));
+ if (node)
+ {
+ LOGV(" post video , enqueing in busy queue");
+ node->f = p;
+ node->next = NULL;
+ enqueue (&g_busy_frame_queue, node);
+ LOGV("post_video got lock. q count after enQ %d", g_busy_frame_queue.num_of_frames);
+ }
+ else
+ {
+ LOGE("cam_frame_post_video error... out of memory\n");
+ }
+
+ pthread_mutex_unlock(&(g_busy_frame_queue.mut));
+ pthread_cond_signal(&(g_busy_frame_queue.wait));
+
+ LOGV("cam_frame_post_video... out = %x\n", p->buffer);
+
+ return;
+}
+
+//-------------------------------------------------------------------------------------
static Mutex singleton_lock;
static bool singleton_releasing;
static Condition singleton_wait;
static void receive_camframe_callback(struct msm_frame *frame);
+static void receive_camframe_video_callback(struct msm_frame *frame); // 720p
static void receive_jpeg_fragment_callback(uint8_t *buff_ptr, uint32_t buff_size);
static void receive_jpeg_callback(jpeg_event_t status);
static void receive_shutter_callback(common_crop_t *crop);
@@ -682,7 +804,10 @@
char value[PROPERTY_VALUE_MAX];
property_get("persist.debug.sf.showfps", value, "0");
mDebugFps = atoi(value);
- kPreviewBufferCountActual = kPreviewBufferCount + NUM_MORE_BUFS;
+ if(!strncmp(mDeviceName,"msm7630", 7))
+ kPreviewBufferCountActual = kPreviewBufferCount;
+ else
+ kPreviewBufferCountActual = kPreviewBufferCount + NUM_MORE_BUFS;
LOGV("constructor EX");
}
@@ -905,6 +1030,13 @@
*LINK_camframe_timeout_callback = receive_camframetimeout_callback;
+ // 720 p new recording functions
+ *(void **)&LINK_cam_frame_flush_free_video = ::dlsym(libmmcamera, "cam_frame_flush_free_video");
+
+ *(void **)&LINK_camframe_free_video = ::dlsym(libmmcamera, "cam_frame_add_free_video");
+
+ *(void **)&LINK_camframe_video_callback = ::dlsym(libmmcamera, "mmcamera_camframe_videocallback");
+ *LINK_camframe_video_callback = receive_camframe_video_callback;
/* Disabling until support is available.
*(void **)&LINK_mmcamera_shutter_callback =
::dlsym(libmmcamera, "mmcamera_shutter_callback");
@@ -1248,6 +1380,115 @@
return true;
}
+/*===========================================================================
+ * FUNCTION - native_start_recording -
+ *
+ * DESCRIPTION:
+ *==========================================================================*/
+static bool native_start_recording(int camfd)
+{
+ int ret;
+ struct msm_ctrl_cmd ctrlCmd;
+
+ ctrlCmd.timeout_ms = 1000;
+ ctrlCmd.type = CAMERA_START_RECORDING;
+ ctrlCmd.length = 0;
+ ctrlCmd.value = NULL;
+ ctrlCmd.resp_fd = camfd;
+
+ if ((ret = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd)) < 0) {
+ LOGE("native_start_recording: ioctl failed. ioctl return value "\
+ "is %d \n", ret);
+ return false;
+ }
+ LOGV("native_start_video: ioctl good. ioctl return value is %d \n",ret);
+
+ /* TODO: Check status of postprocessing if there is any,
+ * PP status should be in ctrlCmd */
+
+ return true;
+}
+
+/*===========================================================================
+ * FUNCTION - native_stop_recording -
+ *
+ * DESCRIPTION:
+ *==========================================================================*/
+static bool native_stop_recording(int camfd)
+{
+ int ret;
+ struct msm_ctrl_cmd ctrlCmd;
+LOGE("in native_stop_recording ");
+ ctrlCmd.timeout_ms = 1000;
+ ctrlCmd.type = CAMERA_STOP_RECORDING;
+ ctrlCmd.length = 0;
+ ctrlCmd.value = NULL;
+ ctrlCmd.resp_fd = camfd;
+
+ if ((ret = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd)) < 0) {
+ LOGE("native_stop_video: ioctl failed. ioctl return value is %d \n",
+ ret);
+ return false;
+ }
+ LOGV("in native_stop_recording returned %d", ret);
+ return true;
+}
+/*===========================================================================
+ * FUNCTION - native_start_video -
+ *
+ * DESCRIPTION:
+ *==========================================================================*/
+static bool native_start_video(int camfd)
+{
+ int ret;
+ struct msm_ctrl_cmd ctrlCmd;
+
+ ctrlCmd.timeout_ms = 1000;
+ ctrlCmd.type = CAMERA_START_VIDEO;
+ ctrlCmd.length = 0;
+ ctrlCmd.value = NULL;
+ ctrlCmd.resp_fd = camfd;
+
+ if ((ret = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd)) < 0) {
+ LOGE("native_start_video: ioctl failed. ioctl return value is %d \n",
+ ret);
+ return false;
+ }
+
+ /* TODO: Check status of postprocessing if there is any,
+ * PP status should be in ctrlCmd */
+
+ return true;
+}
+
+/*===========================================================================
+ * FUNCTION - native_stop_video -
+ *
+ * DESCRIPTION:
+ *==========================================================================*/
+static bool native_stop_video(int camfd)
+{
+ int ret;
+ struct msm_ctrl_cmd ctrlCmd;
+
+ ctrlCmd.timeout_ms = 1000;
+ ctrlCmd.type = CAMERA_STOP_VIDEO;
+ ctrlCmd.length = 0;
+ ctrlCmd.value = NULL;
+ ctrlCmd.resp_fd = camfd;
+
+ if ((ret = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd)) < 0) {
+ LOGE("native_stop_video: ioctl failed. ioctl return value is %d \n",
+ ret);
+ return false;
+ }
+
+ return true;
+}
+/*==========================================================================*/
+
+static cam_frame_start_parms frame_parms;
+static int recordingState = 0;
static rat_t latitude[3];
static rat_t longitude[3];
@@ -1521,6 +1762,9 @@
}
mPreviewHeap.clear();
+ if(!strncmp(mDeviceName,"msm7630", 7))
+ mRecordHeap.clear();
+
#if DLOPEN_LIBMMCAMERA
if (libhandle) {
::dlclose(libhandle);
@@ -1536,6 +1780,109 @@
LOGV("runFrameThread X");
}
+void QualcommCameraHardware::runVideoThread(void *data)
+{
+ LOGD("runVideoThread E");
+ msm_frame* vframe = NULL;
+
+ while(true) {
+ pthread_mutex_lock(&(g_busy_frame_queue.mut));
+
+ LOGE("in video_thread : wait for video frame ");
+ // check if any frames are available in busyQ and give callback to
+ // services/video encoder
+ cam_frame_wait_video();
+ LOGV("video_thread, wait over..");
+
+ // Exit the thread , in case of stop recording..
+ mVideoThreadWaitLock.lock();
+ if(mVideoThreadExit){
+ LOGE("Exiting video thread..");
+ mVideoThreadWaitLock.unlock();
+ pthread_mutex_unlock(&(g_busy_frame_queue.mut));
+ break;
+ }
+ mVideoThreadWaitLock.unlock();
+
+ // Get the video frame to be encoded
+ vframe = cam_frame_get_video ();
+ LOGV("in video_thread : got video frame ");
+
+ if(vframe != NULL) {
+ // Find the offset within the heap of the current buffer.
+ LOGV("Got video frame : buffer %d base %d ", vframe->buffer, mRecordHeap->mHeap->base());
+ ssize_t offset =
+ (ssize_t)vframe->buffer - (ssize_t)mRecordHeap->mHeap->base();
+ LOGV("offset = %d , alignsize = %d , offset later = %d", offset, mRecordHeap->mAlignedBufferSize, (offset / mRecordHeap->mAlignedBufferSize));
+
+ offset /= mRecordHeap->mAlignedBufferSize;
+
+ // dump frames for test purpose
+#ifdef DUMP_VIDEO_FRAMES
+ static int frameCnt = 0;
+ if (frameCnt >= 11 && frameCnt <= 13 ) {
+ char buf[128];
+ sprintf(buf, "/data/%d_v.yuv", frameCnt);
+ int file_fd = open(buf, O_RDWR | O_CREAT, 0777);
+ LOGV("dumping video frame %d", frameCnt);
+ if (file_fd < 0) {
+ LOGE("cannot open file\n");
+ }
+ else
+ {
+ write(file_fd, (const void *)vframe->buffer,
+ vframe->cbcr_off * 3 / 2);
+ }
+ close(file_fd);
+ }
+ frameCnt++;
+#endif
+ // Enable IF block to give frames to encoder , ELSE block for just simulation
+#if 1
+ LOGV("in video_thread : got video frame, before if check giving frame to services/encoder");
+ mCallbackLock.lock();
+ int msgEnabled = mMsgEnabled;
+ data_callback_timestamp rcb = mDataCallbackTimestamp;
+ void *rdata = mCallbackCookie;
+ mCallbackLock.unlock();
+
+ if(rcb != NULL && (msgEnabled & CAMERA_MSG_VIDEO_FRAME) ) {
+ LOGV("in video_thread : got video frame, giving frame to services/encoder");
+ rcb(systemTime(), CAMERA_MSG_VIDEO_FRAME, mRecordHeap->mBuffers[offset], rdata);
+ Mutex::Autolock rLock(&mRecordFrameLock);
+ if (mReleasedRecordingFrame != true) {
+ LOGV("block waiting for frame release");
+ mRecordWait.wait(mRecordFrameLock);
+ LOGV("video frame released, continuing");
+ }
+ mReleasedRecordingFrame = false;
+ }
+#else
+ // 720p output2 : simulate release frame here:
+ LOGE("in video_thread simulation , releasing the video frame");
+ LINK_camframe_free_video(vframe);
+#endif
+
+ } else LOGE("in video_thread get frame returned null");
+
+ pthread_mutex_unlock(&(g_busy_frame_queue.mut));
+
+ } // end of while loop
+ LOGV("runVideoThread X");
+}
+
+void *video_thread(void *user)
+{
+ LOGV("video_thread E");
+ sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance();
+ if (obj != 0) {
+ obj->runVideoThread(user);
+ }
+ else LOGE("not starting video thread: the object went away!");
+ LOGV("video_thread X");
+ return NULL;
+}
+
void *frame_thread(void *user)
{
LOGD("frame_thread E");
@@ -1552,8 +1899,21 @@
{
// See comments in deinitPreview() for why we have to wait for the frame
// thread here, and why we can't use pthread_join().
+ int videoWidth, videoHeight;
mParameters.getPreviewSize(&previewWidth, &previewHeight);
- LOGI("initPreview E: preview size=%dx%d", previewWidth, previewHeight);
+
+ videoWidth = previewWidth; // temporary , should be configurable later
+ videoHeight = previewHeight;
+ LOGV("initPreview E: preview size=%dx%d videosize = %d x %d", previewWidth, previewHeight, videoWidth, videoHeight );
+
+ if(!strncmp(mDeviceName,"msm7630", 7)) {
+ mDimension.video_width = videoWidth;
+ mDimension.video_width = CEILING32(mDimension.video_width);
+ mDimension.video_height = videoHeight;
+ LOGV("initPreview : preview size=%dx%d videosize = %d x %d", previewWidth, previewHeight, mDimension.video_width, mDimension.video_height );
+ }
+
+
mFrameThreadWaitLock.lock();
while (mFrameThreadRunning) {
LOGV("initPreview: waiting for old frame thread to complete.");
@@ -1576,7 +1936,7 @@
mPreviewHeap = new PmemPool("/dev/pmem_adsp",
MemoryHeapBase::READ_ONLY | MemoryHeapBase::NO_CACHING,
mCameraControlFd,
- MSM_PMEM_OUTPUT2,
+ MSM_PMEM_PREVIEW, //MSM_PMEM_OUTPUT2,
mPreviewFrameSize,
kPreviewBufferCountActual,
mPreviewFrameSize,
@@ -1595,7 +1955,7 @@
new PmemPool("/dev/pmem_adsp",
MemoryHeapBase::READ_ONLY | MemoryHeapBase::NO_CACHING,
mCameraControlFd,
- MSM_PMEM_OUTPUT2,
+ MSM_PMEM_PREVIEW, //MSM_PMEM_OUTPUT2,
mPreviewFrameSize,
1,
mPreviewFrameSize,
@@ -1608,6 +1968,10 @@
}
}
}
+ // Allocate video buffers after allocating preview buffers.
+ if( !strncmp(mDeviceName,"msm7630", 7) )
+ initRecord();
+
// mDimension will be filled with thumbnail_width, thumbnail_height,
// orig_picture_dx, and orig_picture_dy after this function call. We need to
// keep it for jpeg_encoder_encode.
@@ -1621,17 +1985,24 @@
(uint32_t)mPreviewHeap->mHeap->base() + mPreviewHeap->mAlignedBufferSize * cnt;
frames[cnt].y_off = 0;
frames[cnt].cbcr_off = previewWidth * previewHeight;
- frames[cnt].path = MSM_FRAME_ENC;
+ frames[cnt].path = OUTPUT_TYPE_P; // MSM_FRAME_ENC;
}
mFrameThreadWaitLock.lock();
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ frame_parms.frame = frames[kPreviewBufferCount - 1];
+ frame_parms.video_frame = recordframes[kPreviewBufferCount - 1];
+
+ LOGV ("initpreview before cam_frame thread carete , video frame buffer=%lu fd=%d y_off=%d cbcr_off=%d \n",
+ (unsigned long)frame_parms.video_frame.buffer, frame_parms.video_frame.fd, frame_parms.video_frame.y_off,
+ frame_parms.video_frame.cbcr_off);
mFrameThreadRunning = !pthread_create(&mFrameThread,
&attr,
frame_thread,
- &frames[kPreviewBufferCount-1]);
+ (void*)&(frame_parms));
ret = mFrameThreadRunning;
mFrameThreadWaitLock.unlock();
}
@@ -1883,6 +2254,16 @@
int cnt, rc;
struct msm_ctrl_cmd ctrlCmd;
+ // exit video thread
+ mVideoThreadWaitLock.lock();
+ LOGV("in release : making mVideoThreadExit 1");
+ mVideoThreadExit = 1;
+ mVideoThreadWaitLock.unlock();
+ // 720p : signal the video thread , and check in video thread if stop is called, if so exit video thread.
+ pthread_mutex_lock(&(g_busy_frame_queue.mut));
+ pthread_cond_signal(&(g_busy_frame_queue.wait));
+ pthread_mutex_unlock(&(g_busy_frame_queue.mut));
+
if (mCameraRunning) {
if(mDataCallbackTimestamp && (mMsgEnabled & CAMERA_MSG_VIDEO_FRAME)) {
mRecordFrameLock.lock();
@@ -1959,6 +2340,7 @@
status_t QualcommCameraHardware::startPreviewInternal()
{
+ LOGV("in startPreviewInternal : E");
if(mCameraRunning) {
LOGV("startPreview X: preview already running.");
return NO_ERROR;
@@ -1972,7 +2354,11 @@
}
}
+ if( strncmp(mDeviceName,"msm7630", 7) )
mCameraRunning = native_start_preview(mCameraControlFd);
+ else
+ mCameraRunning = native_start_video(mCameraControlFd);
+
if(!mCameraRunning) {
deinitPreview();
mPreviewInitialized = false;
@@ -1994,7 +2380,7 @@
}
mParameters.set("max-zoom",mMaxZoom);
- LOGV("startPreview X");
+ LOGV("startPreviewInternal X");
return NO_ERROR;
}
@@ -2018,7 +2404,11 @@
Mutex::Autolock l(&mCamframeTimeoutLock);
if(!camframe_timeout_flag) {
- mCameraRunning = !native_stop_preview(mCameraControlFd);
+ if ( strncmp(mDeviceName,"msm7630", 7) )
+ mCameraRunning = !native_stop_preview(mCameraControlFd);
+ else
+ mCameraRunning = !native_stop_video(mCameraControlFd);
+
} else {
/* This means that the camframetimeout was issued.
* But we did not issue native_stop_preview(), so we
@@ -2441,6 +2831,18 @@
return sp<QualcommCameraHardware>();
}
}
+void QualcommCameraHardware::receiveRecordingFrame(struct msm_frame *frame)
+{
+ LOGV("receiveRecordingFrame E");
+ // post busy frame
+ if (frame)
+ {
+ cam_frame_post_video (frame);
+ }
+ else LOGE("in receiveRecordingFrame frame is NULL");
+ LOGV("receiveRecordingFrame X");
+}
+
bool QualcommCameraHardware::native_zoom_image(int fd, int srcOffset, int dstOffSet, common_crop_t *crop)
{
@@ -2572,27 +2974,104 @@
pcb(CAMERA_MSG_PREVIEW_FRAME, mPreviewHeap->mBuffers[offset],
pdata);
- if(rcb != NULL && (msgEnabled & CAMERA_MSG_VIDEO_FRAME)) {
- rcb(systemTime(), CAMERA_MSG_VIDEO_FRAME, mPreviewHeap->mBuffers[offset], rdata);
- Mutex::Autolock rLock(&mRecordFrameLock);
- if (mReleasedRecordingFrame != true) {
- LOGV("block waiting for frame release");
- mRecordWait.wait(mRecordFrameLock);
- LOGV("frame released, continuing");
+ // If output2 enabled, Start Recording if recording is enabled by Services
+ if(!strncmp(mDeviceName,"msm7630", 7) && recordingEnabled() ) {
+ if(!recordingState){
+ recordingState = 1; // recording started
+ LOGV(" in receivePreviewframe : recording enabled calling startRecording ");
+ startRecording();
}
- mReleasedRecordingFrame = false;
+ }
+
+ // If output is NOT enabled (targets otherthan 7x30 currently..)
+ if(strncmp(mDeviceName,"msm7630", 7)) {
+ if(rcb != NULL && (msgEnabled & CAMERA_MSG_VIDEO_FRAME)) {
+ rcb(systemTime(), CAMERA_MSG_VIDEO_FRAME, mPreviewHeap->mBuffers[offset], rdata);
+ Mutex::Autolock rLock(&mRecordFrameLock);
+ if (mReleasedRecordingFrame != true) {
+ LOGV("block waiting for frame release");
+ mRecordWait.wait(mRecordFrameLock);
+ LOGV("frame released, continuing");
+ }
+ mReleasedRecordingFrame = false;
+ }
}
mInPreviewCallback = false;
// LOGV("receivePreviewFrame X");
}
+
+bool QualcommCameraHardware::initRecord()
+{
+ LOGV("initREcord E");
+
+ mRecordFrameSize = (mDimension.video_width * mDimension.video_height *3)/2;
+ mRecordHeap = new PmemPool("/dev/pmem_adsp",
+ MemoryHeapBase::READ_ONLY | MemoryHeapBase::NO_CACHING,
+ mCameraControlFd,
+ MSM_PMEM_VIDEO,
+ mRecordFrameSize,
+ kRecordBufferCount,
+ mRecordFrameSize,
+ "record");
+ if (!mRecordHeap->initialized()) {
+ mRecordHeap.clear();
+ LOGE("initRecord X: could not initialize record heap.");
+ return false;
+ }
+ for (int cnt = 0; cnt < kRecordBufferCount; cnt++) {
+ recordframes[cnt].fd = mRecordHeap->mHeap->getHeapID();
+ recordframes[cnt].buffer =
+ (uint32_t)mRecordHeap->mHeap->base() + mRecordHeap->mAlignedBufferSize * cnt;
+ recordframes[cnt].y_off = 0;
+ recordframes[cnt].cbcr_off = mDimension.video_width * mDimension.video_height;
+ recordframes[cnt].path = OUTPUT_TYPE_V;
+
+ LOGV ("initRecord : record heap , video buffers buffer=%lu fd=%d y_off=%d cbcr_off=%d \n",
+ (unsigned long)recordframes[cnt].buffer, recordframes[cnt].fd, recordframes[cnt].y_off,
+ recordframes[cnt].cbcr_off);
+ }
+
+ // initial setup : buffers 1,2,3 with kernel , 4 with camframe , 5,6,7,8 in free Q
+ // flush the busy Q
+ cam_frame_flush_video();
+
+ // Start video thread and wait for busy frames to be encoded.
+ mVideoThreadWaitLock.lock();
+ mVideoThreadExit = 0;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create(&mVideoThread,
+ &attr,
+ video_thread,
+ NULL);
+ mVideoThreadWaitLock.unlock();
+ LOGV("initREcord X");
+
+ return true;
+}
+
status_t QualcommCameraHardware::startRecording()
{
LOGV("startRecording E");
+ int ret;
Mutex::Autolock l(&mLock);
mReleasedRecordingFrame = false;
- return startPreviewInternal();
+ if( (ret=startPreviewInternal())== NO_ERROR){
+ if(!strncmp(mDeviceName,"msm7630", 7)) {
+ // flush free queue and add 5,6,7,8 buffers.
+ LINK_cam_frame_flush_free_video();
+ for(int i=ACTIVE_VIDEO_BUFFERS+1;i <kRecordBufferCount; i++)
+ LINK_camframe_free_video(&recordframes[i]);
+
+ LOGV(" in startREcording : calling native_start_recording");
+ native_start_recording(mCameraControlFd);
+ recordingState = 1;
+ }
+ }
+ return ret;
}
void QualcommCameraHardware::stopRecording()
@@ -2610,8 +3089,17 @@
return;
}
}
+ // If output2 enabled, exit video thread, invoke stop recording ioctl
+ if(!strncmp(mDeviceName,"msm7630", 7)) {
+ mVideoThreadWaitLock.lock();
+ mVideoThreadExit = 1;
+ mVideoThreadWaitLock.unlock();
+ native_stop_recording(mCameraControlFd);
+ }
+ else // for other targets where output2 is not enabled
+ stopPreviewInternal();
- stopPreviewInternal();
+ recordingState = 0; // recording not started
LOGV("stopRecording: X");
}
@@ -2622,6 +3110,37 @@
Mutex::Autolock rLock(&mRecordFrameLock);
mReleasedRecordingFrame = true;
mRecordWait.signal();
+
+ // Ff 7x30 : add the frame to the free camframe queue
+ if(!strcmp(mDeviceName,"msm7630_surf")) {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ msm_frame* releaseframe = NULL;
+ LOGV(" in release recording frame : heap base %d offset %d buffer %d ", heap->base(), offset, heap->base() + offset );
+ int cnt;
+ for (cnt = 0; cnt < kRecordBufferCount; cnt++) {
+ if((unsigned int)recordframes[cnt].buffer == (unsigned int)(heap->base()+ offset)){
+ LOGV("in release recording frame found match , releasing buffer %d", (unsigned int)recordframes[cnt].buffer);
+ releaseframe = &recordframes[cnt];
+ break;
+ }
+ }
+ if(cnt < kRecordBufferCount) {
+ // do this only if frame thread is running
+ mFrameThreadWaitLock.lock();
+ if(mFrameThreadRunning )
+ LINK_camframe_free_video(releaseframe);
+
+ mFrameThreadWaitLock.unlock();
+ } else {
+ LOGE("in release recordingframe XXXXX error , buffer not found");
+ for (int i=0; i< kRecordBufferCount; i++) {
+ LOGE(" recordframes[%d].buffer = %d", i, (unsigned int)recordframes[i].buffer);
+ }
+ }
+ }
+
LOGV("releaseRecordingFrame X");
}
@@ -3426,6 +3945,14 @@
if(!strcmp("preview", mName)) num_buf = kPreviewBufferCount;
LOGE("num_buffers = %d", num_buf);
for (int cnt = 0; cnt < num_buf; ++cnt) {
+ int active = 1;
+ if(pmem_type == MSM_PMEM_VIDEO){
+ active = (cnt<ACTIVE_VIDEO_BUFFERS);
+ LOGV(" pmempool creating video buffers : active %d ", active);
+ }
+ else if (pmem_type == MSM_PMEM_PREVIEW){
+ active = (cnt < (num_buf-1));
+ }
register_buf(mCameraControlFd,
mBufferSize,
mFrameSize,
@@ -3433,7 +3960,7 @@
mAlignedBufferSize * cnt,
(uint8_t *)mHeap->base() + mAlignedBufferSize * cnt,
pmem_type,
- !(cnt == num_buf - 1 && pmem_type == MSM_PMEM_OUTPUT2));
+ active);
}
}
@@ -3572,6 +4099,16 @@
}
LOGV("receive_jpeg_callback X");
}
+// 720p : video frame calbback from camframe
+static void receive_camframe_video_callback(struct msm_frame *frame)
+{
+ LOGV("receive_camframe_video_callback E");
+ sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance();
+ if (obj != 0) {
+ obj->receiveRecordingFrame(frame);
+ }
+ LOGV("receive_camframe_video_callback X");
+}
void QualcommCameraHardware::setCallbacks(notify_callback notify_cb,
data_callback data_cb,