summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnu Sundararajan <sanuradha@ti.com>2012-07-26 14:02:03 -0500
committerJason Simmons <jsimmons@google.com>2012-11-07 14:36:32 -0800
commit4a9915838f134a3b5e05cd21bb7c2435cf6d9a2d (patch)
treede20ab4897f55a5d6774f530092f1ecbcc993c3f
parente2f0f7e6ccd237ff8b521d2ab8851911a4637cd5 (diff)
downloadomap4-aah-4a9915838f134a3b5e05cd21bb7c2435cf6d9a2d.tar.gz
CameraHal: V4LCameraAdapter: Add support for MJPEG
USBCameras support higher resolutions(above VGA) in MJPEG format only. V4LCameraAdapter has been modified to use MJPEG as the default pixel format. The incoming jpeg frames are decoded(into NV12) using libjpeg and then sent for rendering. Change-Id: Ie7f62abd7a7fad3bc1f01e048fe8f17f67890301 Signed-off-by: Saravanan Solaiyappan <saravanan.s@ti.com> Signed-off-by: Andriy Chepurnyy <x0155536@ti.com> Signed-off-by: Anu Sundararajan <sanuradha@ti.com>
-rwxr-xr-x[-rw-r--r--]camera/V4LCameraAdapter/V4LCameraAdapter.cpp137
-rwxr-xr-x[-rw-r--r--]camera/V4LCameraAdapter/V4LCapabilities.cpp4
-rwxr-xr-x[-rw-r--r--]camera/inc/V4LCameraAdapter/V4LCameraAdapter.h12
3 files changed, 106 insertions, 47 deletions
diff --git a/camera/V4LCameraAdapter/V4LCameraAdapter.cpp b/camera/V4LCameraAdapter/V4LCameraAdapter.cpp
index c703ecb..d87a72a 100644..100755
--- a/camera/V4LCameraAdapter/V4LCameraAdapter.cpp
+++ b/camera/V4LCameraAdapter/V4LCameraAdapter.cpp
@@ -86,6 +86,10 @@ status_t V4LCameraAdapter::v4lIoctl (int fd, int req, void* argp) {
status_t V4LCameraAdapter::v4lInitMmap(int& count) {
status_t ret = NO_ERROR;
+ int width, height;
+ mParams.getPreviewSize(&width, &height);
+ jpeg_with_dht_buffer_size = (width * height / 2) + jpgdecoder.readDHTSize();
+
//First allocate adapter internal buffers at V4L level for USB Cam
//These are the buffers from which we will copy the data into overlay buffers
/* Check if camera can handle NB_BUFFER buffers */
@@ -126,6 +130,12 @@ status_t V4LCameraAdapter::v4lInitMmap(int& count) {
CAMHAL_LOGEB("Unable to map buffer [%d]. (%s)", i, strerror(errno));
return -1;
}
+
+ if (jpeg_with_dht_buffer[i] != NULL){
+ free(jpeg_with_dht_buffer[i]);
+ jpeg_with_dht_buffer[i] = NULL;
+ }
+ jpeg_with_dht_buffer[i] = (unsigned char *)malloc(jpeg_with_dht_buffer_size);
}
return ret;
}
@@ -214,7 +224,7 @@ status_t V4LCameraAdapter::v4lSetFormat (int width, int height, uint32_t pix_for
mVideoInfo->width = width;
mVideoInfo->height = height;
mVideoInfo->framesizeIn = (width * height << 1);
- mVideoInfo->formatIn = DEFAULT_PIXEL_FORMAT;
+ mVideoInfo->formatIn = pix_format;
mVideoInfo->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
mVideoInfo->format.fmt.pix.width = width;
@@ -267,11 +277,12 @@ status_t V4LCameraAdapter::restartPreview ()
for (int i = 0; i < mPreviewBufferCountQueueable; i++) {
- mVideoInfo->buf.index = i;
- mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
+ v4l2_buffer buf;
+ buf.index = i;
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
- ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
+ ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &buf);
if (ret < 0) {
CAMHAL_LOGEA("VIDIOC_QBUF Failed");
goto EXIT;
@@ -356,17 +367,27 @@ status_t V4LCameraAdapter::fillThisBuffer(CameraBuffer *frameBuf, CameraFrame::F
goto EXIT;
}
- idx = mPreviewBufs.valueFor(frameBuf);
+ for (int xx = 0; xx < NB_BUFFER; xx++){
+ if (mPreviewBufs[xx] == frameBuf){
+ idx = xx;
+ break;
+ }
+ }
+ if (idx == NB_BUFFER){
+ CAMHAL_LOGEB("Wrong index = %d. What do i do? What do i do?",idx);
+ goto EXIT;
+ }
if(idx < 0) {
CAMHAL_LOGEB("Wrong index = %d",idx);
goto EXIT;
}
- mVideoInfo->buf.index = idx;
- mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
+ v4l2_buffer buf;
+ buf.index = idx;
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
- ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
+ ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &buf);
if (ret < 0) {
CAMHAL_LOGEA("VIDIOC_QBUF Failed");
goto EXIT;
@@ -507,8 +528,8 @@ status_t V4LCameraAdapter::UseBuffersPreview(CameraBuffer *bufArr, int num)
if (ret == NO_ERROR) {
for (int i = 0; i < num; i++) {
//Associate each Camera internal buffer with the one from Overlay
- mPreviewBufs.add(&bufArr[i], i);
- CAMHAL_LOGDB("Preview- buff [%d] = 0x%x ",i, mPreviewBufs.keyAt(i));
+ mPreviewBufs[i] = &bufArr[i];
+ CAMHAL_LOGDB("Preview- buff [%d] = 0x%x ",i, mPreviewBufs[i]);
}
// Update the preview buffer count
@@ -554,7 +575,7 @@ status_t V4LCameraAdapter::takePicture() {
CAMHAL_LOGDB("Image Capture Size WxH = %dx%d",width,height);
yuv422i_buff_size = width * height * 2;
- ret = v4lSetFormat (width, height, DEFAULT_PIXEL_FORMAT);
+ ret = v4lSetFormat (width, height, DEFAULT_CAPTURE_FORMAT);
if (ret < 0) {
CAMHAL_LOGEB("v4lSetFormat Failed: %s", strerror(errno));
goto EXIT;
@@ -568,11 +589,12 @@ status_t V4LCameraAdapter::takePicture() {
for (int i = 0; i < mCaptureBufferCountQueueable; i++) {
- mVideoInfo->buf.index = i;
- mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
+ v4l2_buffer buf;
+ buf.index = i;
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
- ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
+ ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &buf);
if (ret < 0) {
CAMHAL_LOGEA("VIDIOC_QBUF Failed");
ret = BAD_VALUE;
@@ -590,7 +612,8 @@ status_t V4LCameraAdapter::takePicture() {
CAMHAL_LOGDA("Streaming started for Image Capture");
//get the frame and send to encode as JPG
- fp = this->GetFrame(index);
+ int filledLen;
+ fp = this->GetFrame(index, filledLen);
if(!fp) {
CAMHAL_LOGEA("!!! Captured frame is NULL !!!!");
ret = BAD_VALUE;
@@ -695,11 +718,12 @@ status_t V4LCameraAdapter::startPreview()
for (int i = 0; i < mPreviewBufferCountQueueable; i++) {
- mVideoInfo->buf.index = i;
- mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
+ v4l2_buffer buf;
+ buf.index = i;
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
- ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
+ ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &buf);
if (ret < 0) {
CAMHAL_LOGEA("VIDIOC_QBUF Failed");
goto EXIT;
@@ -746,8 +770,6 @@ status_t V4LCameraAdapter::stopPreview()
nDequeued = 0;
mFramesWithEncoder = 0;
- mPreviewBufs.clear();
-
mPreviewThread->requestExitAndWait();
mPreviewThread.clear();
@@ -755,13 +777,14 @@ status_t V4LCameraAdapter::stopPreview()
return ret;
}
-char * V4LCameraAdapter::GetFrame(int &index)
+char * V4LCameraAdapter::GetFrame(int &index, int &filledLen)
{
int ret = NO_ERROR;
LOG_FUNCTION_NAME;
- mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
+ v4l2_buffer buf;
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
/* DQ */
// Some V4L drivers, notably uvc, protect each incoming call with
@@ -772,7 +795,7 @@ char * V4LCameraAdapter::GetFrame(int &index)
return NULL;
}
- ret = v4lIoctl(mCameraHandle, VIDIOC_DQBUF, &mVideoInfo->buf);
+ ret = v4lIoctl(mCameraHandle, VIDIOC_DQBUF, &buf);
if((ret == 0) || (errno != EAGAIN)) {
break;
}
@@ -784,10 +807,11 @@ char * V4LCameraAdapter::GetFrame(int &index)
}
nDequeued++;
- index = mVideoInfo->buf.index;
+ index = buf.index;
+ filledLen = buf.bytesused;
LOG_FUNCTION_NAME_EXIT;
- return (char *)mVideoInfo->mem[mVideoInfo->buf.index];
+ return (char *)mVideoInfo->mem[buf.index];
}
//API to get the frame size required to be allocated. This size is used to override the size passed
@@ -896,6 +920,8 @@ V4LCameraAdapter::V4LCameraAdapter(size_t sensor_index)
// Nothing useful to do in the constructor
mFramesWithEncoder = 0;
+ jpeg_with_dht_buffer_size = 0;
+ for (int i = 0; i < NB_BUFFER; i++) jpeg_with_dht_buffer[i] = NULL;
LOG_FUNCTION_NAME_EXIT;
}
@@ -913,6 +939,13 @@ V4LCameraAdapter::~V4LCameraAdapter()
mVideoInfo = NULL;
}
+ for (int i = 0; i < NB_BUFFER; i++) {
+ if (jpeg_with_dht_buffer[i] != NULL){
+ free(jpeg_with_dht_buffer[i]);
+ jpeg_with_dht_buffer[i] = NULL;
+ }
+ }
+
LOG_FUNCTION_NAME_EXIT;
}
@@ -1122,19 +1155,22 @@ int V4LCameraAdapter::previewThread()
CameraFrame frame;
void *y_uv[2];
int index = 0;
+ int filledLen = 0;
int stride = 4096;
char *fp = NULL;
mParams.getPreviewSize(&width, &height);
+ android::Mutex::Autolock lock(mSubscriberLock);
if (mPreviewing) {
- fp = this->GetFrame(index);
+ fp = this->GetFrame(index, filledLen);
if(!fp) {
ret = BAD_VALUE;
goto EXIT;
}
- CameraBuffer *buffer = mPreviewBufs.keyAt(index);
+
+ CameraBuffer *buffer = mPreviewBufs[index];
CameraFrame *lframe = (CameraFrame *)mFrameQueue.valueFor(buffer);
if (!lframe) {
ret = BAD_VALUE;
@@ -1147,19 +1183,36 @@ int V4LCameraAdapter::previewThread()
ret = BAD_VALUE;
goto EXIT;
}
- y_uv[0] = (void*) lframe->mYuv[0];
- //y_uv[1] = (void*) lframe->mYuv[1];
- //y_uv[1] = (void*) (lframe->mYuv[0] + height*stride);
- convertYUV422ToNV12Tiler ( (unsigned char*)fp, (unsigned char*)y_uv[0], width, height);
- CAMHAL_LOGVB("##...index= %d.;camera buffer= 0x%x; y= 0x%x; UV= 0x%x.",index, buffer, y_uv[0], y_uv[1] );
+
+ if ( DEFAULT_PIXEL_FORMAT == V4L2_PIX_FMT_MJPEG ) {
+ /*
+ MJPEG frames do not include the Huffman tables. MJPEG compressors use standard tables,
+ and they are not included in the stream to decrease the bandwidth. Therefore, the
+ Huffman table must be concatenated onto the start of a motion JPEG image to form a
+ valid still JPEG image.
+ */
+ int final_jpg_sz = jpgdecoder.appendDHT((unsigned char*)fp, filledLen,
+ jpeg_with_dht_buffer[index], jpeg_with_dht_buffer_size);
+ if (!jpgdecoder.decode(jpeg_with_dht_buffer[index], final_jpg_sz, (unsigned char*)lframe->mYuv[0], 4096)) {
+ CAMHAL_LOGEA("Error while decoding JPEG");
+ }
+ }
+ else if ( DEFAULT_PIXEL_FORMAT == V4L2_PIX_FMT_YUYV )
+ {
+ y_uv[0] = (void*) lframe->mYuv[0];
+ //y_uv[1] = (void*) lframe->mYuv[1];
+ //y_uv[1] = (void*) (lframe->mYuv[0] + height*stride);
+ convertYUV422ToNV12Tiler ( (unsigned char*)fp, (unsigned char*)y_uv[0], width, height);
+ CAMHAL_LOGVB("##...index= %d.;camera buffer= 0x%x; y= 0x%x; UV= 0x%x.",index, buffer, y_uv[0], y_uv[1] );
#ifdef SAVE_RAW_FRAMES
- unsigned char* nv12_buff = (unsigned char*) malloc(width*height*3/2);
- //Convert yuv422i to yuv420sp(NV12) & dump the frame to a file
- convertYUV422ToNV12 ( (unsigned char*)fp, nv12_buff, width, height);
- saveFile( nv12_buff, ((width*height)*3/2) );
- free (nv12_buff);
+ unsigned char* nv12_buff = (unsigned char*) malloc(width*height*3/2);
+ //Convert yuv422i to yuv420sp(NV12) & dump the frame to a file
+ convertYUV422ToNV12 ( (unsigned char*)fp, nv12_buff, width, height);
+ saveFile( nv12_buff, ((width*height)*3/2) );
+ free (nv12_buff);
#endif
+ }
frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC;
frame.mBuffer = buffer;
diff --git a/camera/V4LCameraAdapter/V4LCapabilities.cpp b/camera/V4LCameraAdapter/V4LCapabilities.cpp
index 575f943..4912e5a 100644..100755
--- a/camera/V4LCameraAdapter/V4LCapabilities.cpp
+++ b/camera/V4LCameraAdapter/V4LCapabilities.cpp
@@ -262,7 +262,7 @@ status_t V4LCameraAdapter::getCaps(const int sensorId, CameraProperties::Propert
frmSizeEnum.index = i;
//Check for frame sizes for default pixel format
//TODO: Check for frame sizes for all supported pixel formats
- frmSizeEnum.pixel_format = V4L2_PIX_FMT_YUYV;
+ frmSizeEnum.pixel_format = DEFAULT_PIXEL_FORMAT;
status = ioctl (handle, VIDIOC_ENUM_FRAMESIZES, &frmSizeEnum);
if (status == NO_ERROR) {
int width;
@@ -308,7 +308,7 @@ status_t V4LCameraAdapter::getCaps(const int sensorId, CameraProperties::Propert
for ( i = 0; status == NO_ERROR; i++) {
frmIvalEnum.index = i;
//Check for supported frame rates for the default pixel format.
- frmIvalEnum.pixel_format = V4L2_PIX_FMT_YUYV;
+ frmIvalEnum.pixel_format = DEFAULT_PIXEL_FORMAT;
frmIvalEnum.width = caps.tPreviewRes[j].width;
frmIvalEnum.height = caps.tPreviewRes[j].height;
diff --git a/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h b/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h
index bc99a6c..e9c910c 100644..100755
--- a/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h
+++ b/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h
@@ -24,11 +24,14 @@
#include "CameraHal.h"
#include "BaseCameraAdapter.h"
#include "DebugUtils.h"
+#include "Decoder_libjpeg.h"
namespace Ti {
namespace Camera {
-#define DEFAULT_PIXEL_FORMAT V4L2_PIX_FMT_YUYV
+//#define DEFAULT_PIXEL_FORMAT V4L2_PIX_FMT_YUYV
+#define DEFAULT_PIXEL_FORMAT V4L2_PIX_FMT_MJPEG
+#define DEFAULT_CAPTURE_FORMAT V4L2_PIX_FMT_YUYV
#define NB_BUFFER 10
#define DEVICE "/dev/videoxx"
@@ -153,7 +156,7 @@ private:
//Used for calculation of the average frame rate during preview
status_t recalculateFPS();
- char * GetFrame(int &index);
+ char * GetFrame(int &index, int &filledLen);
int previewThread();
@@ -199,7 +202,7 @@ private:
int mPreviewBufferCountQueueable;
int mCaptureBufferCount;
int mCaptureBufferCountQueueable;
- android::KeyedVector<CameraBuffer *, int> mPreviewBufs;
+ CameraBuffer *mPreviewBufs[NB_BUFFER];
android::KeyedVector<CameraBuffer *, int> mCaptureBufs;
mutable android::Mutex mPreviewBufsLock;
mutable android::Mutex mCaptureBufsLock;
@@ -230,6 +233,9 @@ private:
int nQueued;
int nDequeued;
+ Decoder_libjpeg jpgdecoder;
+ unsigned char *jpeg_with_dht_buffer[NB_BUFFER];
+ unsigned int jpeg_with_dht_buffer_size;
};
} // namespace Camera