diff --git a/CMakeLists.txt b/CMakeLists.txt index 47b2fa3..2e933d9 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,7 +100,11 @@ set(EXTRA_EXE_LINKER_FLAGS "") set(EXTRA_EXE_LINKER_FLAGS_RELEASE "") set(EXTRA_EXE_LINKER_FLAGS_DEBUG "") -IF(CMAKE_COMPILER_IS_GNUCXX OR MINGW) +IF ((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR + (CMAKE_CXX_COMPILER_ID MATCHES "Clang") OR + MINGW + ) + set(ENABLE_PROFILING OFF CACHE BOOL "Enable profiling in the GCC compiler (Add flags: -g -pg)") set(USE_OMIT_FRAME_POINTER ON CACHE BOOL "Enable -fomit-frame-pointer for GCC") if(${CMAKE_SYSTEM_PROCESSOR} MATCHES arm*) # We can use only -O2 because the -O3 causes gcc crash diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3ccf7a7..14f558d 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,9 +2,22 @@ INCLUDE_DIRECTORIES(.) SET(private_hdrs_base "private/private_types.h private/private_impl.h exceptions.h private/threadcondition.h ") SET(private_still_hdrs_base "private_still/private_still_types.h private/private_still_impl.h") -SET(public_hdrs_base raspicamtypes.h raspicam.h) +SET(public_hdrs_base + raspicamtypes.h + raspicam.h + raspicamrawbuffer.h +) + +SET(srcs_base + raspicam.cpp + raspicam_still.cpp + raspicamrawbuffer.cpp + private/private_impl.cpp + private/raspicamrawbuffer_impl.cpp + private/threadcondition.cpp + private_still/private_still_impl.cpp +) -SET(srcs_base raspicam.cpp raspicam_still.cpp private/private_impl.cpp private/threadcondition.cpp private_still/private_still_impl.cpp) if(NOT( ${CMAKE_SYSTEM_PROCESSOR} MATCHES arm*) )#in a pc, adds fake dependencies to mmal functions to enable compilation SET(srcs_base ${srcs_base} private/fake_mmal_dependencies.cpp) endif() diff --git a/src/private/private_impl.cpp b/src/private/private_impl.cpp index 92a8530..0d75234 100755 --- a/src/private/private_impl.cpp +++ b/src/private/private_impl.cpp @@ -36,18 +36,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************/ #include "private_impl.h" +#include #include #include #include "mmal/util/mmal_util.h" #include "mmal/util/mmal_util_params.h" #include "mmal/util/mmal_default_components.h" +#include "raspicamrawbuffer.h" +#include "raspicamrawbuffer_impl.h" + using namespace std; namespace raspicam { namespace _private{ +#define MMAL_CAMERA_PREVIEW_PORT 0 #define MMAL_CAMERA_VIDEO_PORT 1 #define MMAL_CAMERA_CAPTURE_PORT 2 #define VIDEO_FRAME_RATE_DEN 1 #define VIDEO_OUTPUT_BUFFERS_NUM 3 +#define NUM_RAW_BUFFERS_USED_BY_CLIENT_DEFAULT 2 + +#define CAMERA_PORT MMAL_CAMERA_PREVIEW_PORT Private_Impl::Private_Impl() { @@ -94,7 +102,7 @@ namespace raspicam { State.awbg_red=1.0; State.awbg_blue=1.0; State.sensor_mode = 0; //do not set mode by default - + State.zeroCopyMode = false; } bool Private_Impl::open ( bool StartCapture ) { if ( _isOpened ) return false; //already opened @@ -104,7 +112,7 @@ namespace raspicam { return false; } commitParameters(); - camera_video_port = State.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; + camera_video_port = State.camera_component->output[CAMERA_PORT]; callback_data.pstate = &State; callback_data.inst = this; // assign data to use for callback @@ -123,14 +131,25 @@ namespace raspicam { return false; //already opened } - // start capture - if ( mmal_port_parameter_set_boolean ( camera_video_port, MMAL_PARAMETER_CAPTURE, 1 ) != MMAL_SUCCESS ) { - release(); - return false; + // Start capture. + // Note if camera port is a preview port, then capturing is active + // from the beginning. + if (CAMERA_PORT != MMAL_CAMERA_PREVIEW_PORT) { + if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { + release(); + return false; + } } + // Send all the buffers to the video port - int num = mmal_queue_length ( State.video_pool->queue ); + // Note: + // We are not sending all buffers available, + // by some weird reason mmal uses only one buffer, and ignores the rest. + // So we provide mmal with buffers it needs, and keep the rest in pool. + // During a video buffer callback, we then may borrow mmal's buffer + // for a while, replacing it by one from pool. + int num = camera_video_port->buffer_num_recommended; int q; for ( q=0; qqueue ); @@ -150,6 +169,16 @@ namespace raspicam { callback_data._userCallback = userCallback; } + void Private_Impl::setRawBufferCallback( + void (* userCallback)(const raspicam::RaspiCamRawBuffer &, void *), + void *data, + bool enableZeroCopyMode) { + callback_data._userCallbackData = data; + callback_data._userRawBufferCallback = userCallback; + callback_data._numRawBuffersUsedByClient = NUM_RAW_BUFFERS_USED_BY_CLIENT_DEFAULT; + State.zeroCopyMode = enableZeroCopyMode; + } + void Private_Impl::release() { if ( !_isOpened ) return; @@ -216,6 +245,8 @@ namespace raspicam { case RASPICAM_FORMAT_RGB: return 3*getWidth() *getHeight(); break; + case RASPICAM_FORMAT_RGBA: + return 4*getWidth() *getHeight(); default: return 0; }; @@ -231,7 +262,7 @@ namespace raspicam { */ void Private_Impl::destroy_camera_component ( RASPIVID_STATE *state ) { if ( state->video_pool ) - mmal_port_pool_destroy ( state->camera_component->output[MMAL_CAMERA_VIDEO_PORT], state->video_pool ); + mmal_port_pool_destroy ( state->camera_component->output[CAMERA_PORT], state->video_pool ); if ( state->camera_component ) { mmal_component_destroy ( state->camera_component ); state->camera_component = NULL; @@ -257,7 +288,7 @@ namespace raspicam { return 0; } - video_port = camera->output[MMAL_CAMERA_VIDEO_PORT]; + video_port = camera->output[CAMERA_PORT]; //set sensor mode if ( state->sensor_mode != 0 && mmal_port_parameter_set_uint32 ( camera->control, @@ -311,8 +342,14 @@ namespace raspicam { // Set the encode format on the video port format = video_port->format; - format->encoding_variant = convertFormat ( State.captureFtm ); - format->encoding = convertFormat ( State.captureFtm ); + if (!State.zeroCopyMode) { + format->encoding_variant = convertFormat(State.captureFtm); + format->encoding = convertFormat(State.captureFtm); + } else { + format->encoding = MMAL_ENCODING_OPAQUE; + format->encoding_variant = MMAL_ENCODING_I420; + } + format->es->video.width = VCOS_ALIGN_UP(state->width, 32); format->es->video.height = VCOS_ALIGN_UP(state->height, 16); format->es->video.crop.x = 0; @@ -322,6 +359,25 @@ namespace raspicam { format->es->video.frame_rate.num = state->framerate; format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN; + + if (state->zeroCopyMode) { + // Enable ZERO_COPY mode on the preview port which instructs MMAL to only + // pass the 4-byte opaque buffer handle instead of the contents of the opaque + // buffer. + // The opaque handle is resolved on VideoCore by the GL driver when the EGL + // image is created. + status = mmal_port_parameter_set_boolean( + video_port, + MMAL_PARAMETER_ZERO_COPY, + MMAL_TRUE + ); + if (status != MMAL_SUCCESS) + { + cerr << ( "Failed to enable zero copy on camera preview port" ); + return 0; + } + } + status = mmal_port_format_commit ( video_port ); if ( status ) { cerr<< ( "camera video format couldn't be set" ); @@ -346,7 +402,12 @@ namespace raspicam { //PR : create pool of message on video port MMAL_POOL_T *pool; video_port->buffer_size = video_port->buffer_size_recommended; - video_port->buffer_num = video_port->buffer_num_recommended; + + uint32_t buffersNum = video_port->buffer_num_recommended; + if (callback_data._userRawBufferCallback) { + buffersNum += callback_data._numRawBuffersUsedByClient; + } + video_port->buffer_num = buffersNum; pool = mmal_port_pool_create ( video_port, video_port->buffer_num, video_port->buffer_size ); if ( !pool ) { cerr<< ( "Failed to create buffer header pool for video output port" ); @@ -533,70 +594,38 @@ namespace raspicam { bool hasGrabbed=false; // pData->_mutex.lock(); std::unique_lock lck ( pData->_mutex ); - if ( pData ) { - if( buffer->length && - ( pData->_userCallback || pData->wantToGrab )){ - mmal_buffer_header_mem_lock ( buffer ); - - Private_Impl *self = pData->inst; - - int width = pData->pstate->width; - int height = pData->pstate->height; - RASPICAM_FORMAT fmt = pData->pstate->captureFtm; - bool encoded = false; // So far only unencoded formats can be configured - - // For unencoded formats, the buffer is padding to blocks - // TODO: According to picamera ('Under certain circumstances (non-resized, non-YUV, video-port captures), the resolution is rounded to 16x16 blocks instead of 32x16. Adjust your resolution rounding accordingly') - int bufferWidth = VCOS_ALIGN_UP(width, 32); - int bufferHeight = VCOS_ALIGN_UP(height, 16); - - if ( bufferWidth == width || encoded ) { - pData->_buffData.resize ( buffer->length ); - memcpy ( pData->_buffData.data,buffer->data,buffer->length ); - } - else { - - pData->_buffData.resize ( self->getImageTypeSize( fmt ) ); - - int bpp = 1; - if(fmt == RASPICAM_FORMAT_RGB || fmt == RASPICAM_FORMAT_BGR) { - bpp = 3; - } - - for(int i = 0; i < height; i++) { - memcpy ( pData->_buffData.data + i*width*bpp, buffer->data + i*bufferWidth*bpp, width*bpp); - } - if ( fmt == RASPICAM_FORMAT_YUV420 ) { - // Starting points in both buffers - uint8_t *outUV = pData->_buffData.data + width*height; - uint8_t *bufferUV = buffer->data + bufferHeight*bufferWidth; - - width /= 2; - height /= 2; - bufferWidth /= 2; - bufferHeight /= 2; - - for(int plane = 0; plane < 2; plane++) { - for(int i = 0; i < height; i++) { - memcpy ( outUV + i*width, bufferUV + i*bufferWidth, width ); - } - outUV += width*height; - bufferUV += bufferWidth*bufferHeight; - } + // Wrap _buffer object into RaspiCamRawBuffer. + // It uses a references counting, and if there are no references + // remains till destruction stage it releases internal buffer. + { + RaspiCamRawBuffer bufferSharedPtr; + bufferSharedPtr.accessImpl()->setMmalBufferHeader(buffer); + if (pData) { + + bool processingRequired = + pData->wantToGrab || + pData->_userCallback || + pData->_userRawBufferCallback; + + if (buffer->length && processingRequired) { + + if (pData->_userRawBufferCallback) { + pData->_userRawBufferCallback(bufferSharedPtr, pData->_userCallbackData); + } else { + mmal_buffer_header_mem_lock(buffer); + process_video_buffer(pData, buffer); + mmal_buffer_header_mem_unlock(buffer); } + pData->wantToGrab = false; + hasGrabbed = true; } - - pData->wantToGrab =false; - hasGrabbed=true; - mmal_buffer_header_mem_unlock ( buffer ); } + // If buffer is not used, it then is to be released + // by RaspiCamRawBuffer destructor. } - //pData->_mutex.unlock(); - // if ( hasGrabbed ) pData->Thcond.BroadCast(); //wake up waiting client - // release buffer back to the pool - mmal_buffer_header_release ( buffer ); + // and send one back to the port (if still open) if ( port->is_enabled ) { MMAL_STATUS_T status; @@ -605,9 +634,12 @@ namespace raspicam { if ( new_buffer ) status = mmal_port_send_buffer ( port, new_buffer ); + else { + cerr << "RaspiCam's buffer pool is empty." << endl; + } if ( !new_buffer || status != MMAL_SUCCESS ) - printf ( "Unable to return a buffer to the encoder port" ); + printf ( "Unable to return a buffer to the encoder port\n" ); } if ( pData->pstate->shutterSpeed!=0 && pData->pstate->rpc_exposureMode == RASPICAM_EXPOSURE_FIXEDFPS) @@ -623,7 +655,58 @@ namespace raspicam { } + void Private_Impl::process_video_buffer(Private_Impl::PORT_USERDATA *pData, + MMAL_BUFFER_HEADER_T *buffer) { + Private_Impl *self = pData->inst; + + int width = pData->pstate->width; + int height = pData->pstate->height; + RASPICAM_FORMAT fmt = pData->pstate->captureFtm; + bool encoded = false; // So far only unencoded formats can be configured + + // For unencoded formats, the buffer is padding to blocks + // TODO: According to picamera ('Under certain circumstances (non-resized, non-YUV, video-port captures), the resolution is rounded to 16x16 blocks instead of 32x16. Adjust your resolution rounding accordingly') + int bufferWidth = VCOS_ALIGN_UP(width, 32); + int bufferHeight = VCOS_ALIGN_UP(height, 16); + + if ( bufferWidth == width || encoded ) { + pData->_buffData.resize ( buffer->length ); + memcpy ( pData->_buffData.data,buffer->data,buffer->length ); + } else { + + pData->_buffData.resize ( self->getImageTypeSize( fmt ) ); + + int bpp = 1; + if(fmt == RASPICAM_FORMAT_RGB || fmt == RASPICAM_FORMAT_BGR) { + bpp = 3; + } else if (fmt == RASPICAM_FORMAT_RGBA) { + bpp = 4; + } + + for(int i = 0; i < height; i++) { + memcpy ( pData->_buffData.data + i*width*bpp, buffer->data + i*bufferWidth*bpp, width*bpp); + } + if ( fmt == RASPICAM_FORMAT_YUV420 ) { + // Starting points in both buffers + uint8_t *outUV = pData->_buffData.data + width*height; + uint8_t *bufferUV = buffer->data + bufferHeight*bufferWidth; + + width /= 2; + height /= 2; + bufferWidth /= 2; + bufferHeight /= 2; + + for(int plane = 0; plane < 2; plane++) { + for(int i = 0; i < height; i++) { + memcpy ( outUV + i*width, bufferUV + i*bufferWidth, width ); + } + outUV += width*height; + bufferUV += bufferWidth*bufferHeight; + } + } + } + } void Private_Impl::setWidth ( unsigned int width ) { State.width = width; @@ -878,6 +961,8 @@ namespace raspicam { int Private_Impl::convertFormat ( RASPICAM_FORMAT fmt ) { switch ( fmt ) { + case RASPICAM_FORMAT_RGBA: + return MMAL_ENCODING_RGBA; case RASPICAM_FORMAT_RGB: return _rgb_bgr_fixed ? MMAL_ENCODING_RGB24 : MMAL_ENCODING_BGR24; case RASPICAM_FORMAT_BGR: diff --git a/src/private/private_impl.h b/src/private/private_impl.h index 43e30d8..76874ba 100755 --- a/src/private/private_impl.h +++ b/src/private/private_impl.h @@ -44,7 +44,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "raspicamtypes.h" #include "private_types.h" #include "threadcondition.h" + namespace raspicam { + class RaspiCamRawBuffer; namespace _private { @@ -81,6 +83,10 @@ namespace raspicam { /* User define callback interface */ void (*_userCallback)(void*) = 0; + + void (*_userRawBufferCallback)(const RaspiCamRawBuffer&, void*) = 0; + uint32_t _numRawBuffersUsedByClient; + void* _userCallbackData; }; @@ -102,6 +108,7 @@ namespace raspicam { { return _isOpened; } + /**Starts camera capture */ bool startCapture(); @@ -115,6 +122,23 @@ namespace raspicam { */ void setUserCallback(void (*userCallback)(void*) , void* data = 0); + /** + * Specify callback which is called every time when new camera raw buffer is + * obtained. + * @param userCallback callback function + * @param data user data you want to pass into callback. + * @param enableZeroCopyMode + * Enable ZERO_COPY mode on the preview port which instructs MMAL to only + * pass the 4-byte opaque buffer handle instead of the contents of the opaque + * buffer. + * The opaque handle is resolved on VideoCore by the GL driver when the EGL + * image is created. + */ + void setRawBufferCallback( + void (*userCallback)(const RaspiCamRawBuffer&, void*) , + void* data=0, + bool enableZeroCopyMode = false); + /**Grabs the next frame and keeps it in internal buffer. Blocks until next frame arrives */ bool grab(); @@ -261,6 +285,8 @@ namespace raspicam { private: static void video_buffer_callback ( MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer ); static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer); + static void process_video_buffer(PORT_USERDATA *pData, MMAL_BUFFER_HEADER_T *buffer); + void setDefaultStateParams(); MMAL_COMPONENT_T *create_camera_component ( RASPIVID_STATE *state ); void destroy_camera_component ( RASPIVID_STATE *state ); @@ -302,8 +328,6 @@ namespace raspicam { bool _isCapturing; bool _rgb_bgr_fixed; - - }; } } diff --git a/src/private/private_types.h b/src/private/private_types.h index c64333a..75698cc 100755 --- a/src/private/private_types.h +++ b/src/private/private_types.h @@ -62,6 +62,11 @@ namespace raspicam { int height; /// requested height of image int framerate; /// Requested frame rate (fps) /// the camera output or the encoder output (with compression artifacts) + + /// In this case MMAL will pass opaque buffer header only. + /// May be used with rawBufferCallback only. + bool zeroCopyMode; + MMAL_COMPONENT_T *camera_component; /// Pointer to the camera component MMAL_POOL_T *video_pool; /// Pointer to the pool of buffers used by encoder output port //camera params diff --git a/src/private/raspicamrawbuffer_impl.cpp b/src/private/raspicamrawbuffer_impl.cpp new file mode 100644 index 0000000..57515fe --- /dev/null +++ b/src/private/raspicamrawbuffer_impl.cpp @@ -0,0 +1,98 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University 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 BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA 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 + +#include "mmal/util/mmal_util.h" +#include "mmal/util/mmal_util_params.h" +#include "mmal/util/mmal_default_components.h" + +#include "raspicamrawbuffer_impl.h" + +namespace raspicam { + namespace _private { + + void RaspiCamRawBufferImpl::moveFrom(RaspiCamRawBufferImpl &src) { + _buffer.reset(0); + _buffer.swap(src._buffer); + } + + void RaspiCamRawBufferImpl::setMmalBufferHeader(MMAL_BUFFER_HEADER_T *buffer) { + _buffer = std::shared_ptr(buffer, Deleter()); + +#ifdef RASPICAM_RAW_BUFFER_ENABLE_TRACE + std::cout << std::hex + << "RaspiCam: buffer " << buffer << "->" << (void*)buffer->data + << " has been wrapped by RaspiCamRawBuffer." + << std::endl + << std::flush; +#endif + } + + void* RaspiCamRawBufferImpl::getBuffer() { + return _buffer ? _buffer.get()->data : 0; + } + + const void* RaspiCamRawBufferImpl::getBuffer() const { + return _buffer ? _buffer.get()->data : 0; + } + + void RaspiCamRawBufferImpl::lock() { + if (_buffer) + mmal_buffer_header_mem_lock(_buffer.get()); + } + + void RaspiCamRawBufferImpl::unlock() { + if (_buffer) + mmal_buffer_header_mem_unlock(_buffer.get()); + } + + void RaspiCamRawBufferImpl::Deleter::operator()(MMAL_BUFFER_HEADER_T *_buffer) const { +#ifdef RASPICAM_RAW_BUFFER_ENABLE_TRACE + std::cout << std::hex + << "RaspiCam: buffer " << _buffer << "->" << (void*)_buffer->data + << " has been released." << std::endl + << std::flush; +#endif + mmal_buffer_header_release(_buffer); + } + + long RaspiCamRawBufferImpl::getUseCount() const { + return _buffer.use_count(); + } + } +} diff --git a/src/private/raspicamrawbuffer_impl.h b/src/private/raspicamrawbuffer_impl.h new file mode 100644 index 0000000..aac9c1b --- /dev/null +++ b/src/private/raspicamrawbuffer_impl.h @@ -0,0 +1,110 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University 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 BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA 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. +****************************************************************/ + +#ifndef RaspiCamRawBuffer_Impl_H +#define RaspiCamRawBuffer_Impl_H + +#include + +#if 0 + // Enables detailed trace about buffer lifetime. + #define RASPICAM_RAW_BUFFER_ENABLE_TRACE +#endif + +struct MMAL_BUFFER_HEADER_T; + +namespace raspicam { + namespace _private { + + /** + * Raspberry Camera RAW buffer implementation. + * In fact this is a wrapper for MMAL buffer. + */ + class RaspiCamRawBufferImpl { + public: + + /** + * Move contents + * Moves reference from source to current reference holder. + * After move source refers to nullptr. + * @param src buffer reference to be moved. + */ + void moveFrom(RaspiCamRawBufferImpl& src); + + /** + * Setup MMAL buffer header. + * @param buffer MMAL buffer to be wrapped. + * @param acquire true if you want acquire/release to be called for this buffer. + */ + void setMmalBufferHeader(MMAL_BUFFER_HEADER_T *buffer); + + /** + * Get buffer contents + * @return buffer contents. + */ + void* getBuffer(); + + /** + * Get buffer contents + * @return buffer contents. + */ + const void* getBuffer() const; + + /** + * Lock buffer's memory. + */ + void lock(); + + /** + * Unlocks buffer's memory. + */ + void unlock(); + + long getUseCount() const; + + private: + + struct Deleter { + void operator()(MMAL_BUFFER_HEADER_T* _buffer) const; + }; + + std::shared_ptr _buffer; + }; + } +} + +#endif diff --git a/src/raspicam.cpp b/src/raspicam.cpp index 229f4f8..33a0e1e 100755 --- a/src/raspicam.cpp +++ b/src/raspicam.cpp @@ -58,6 +58,13 @@ namespace raspicam { _impl->setUserCallback(userCallback, data); } + void RaspiCam::setRawBufferCallback( + void (* userCallback)(const raspicam::RaspiCamRawBuffer &, void *), + void *data, + bool enableZeroCopyMode) { + _impl->setRawBufferCallback(userCallback, data, enableZeroCopyMode); + } + bool RaspiCam::isOpened() const {return _impl->isOpened();} bool RaspiCam::grab() { diff --git a/src/raspicam.h b/src/raspicam.h index ff7555e..0245c3a 100755 --- a/src/raspicam.h +++ b/src/raspicam.h @@ -47,6 +47,7 @@ namespace raspicam { } /**Base class that do all the hard work */ + class RaspiCamRawBuffer; class RaspiCam { public: @@ -70,6 +71,23 @@ namespace raspicam { */ void setUserCallback(void (*userCallback)(void*) , void* data=0); + /** + * Specify callback which is called every time when new camera raw buffer is + * obtained. + * @param userCallback callback function + * @param data user data you want to pass into callback. + * @param enableZeroCopyMode + * Enable ZERO_COPY mode on the preview port which instructs MMAL to only + * pass the 4-byte opaque buffer handle instead of the contents of the opaque + * buffer. + * The opaque handle is resolved on VideoCore by the GL driver when the EGL + * image is created. + */ + void setRawBufferCallback( + void (*userCallback)(const RaspiCamRawBuffer&, void*) , + void* data=0, + bool enableZeroCopyMode = false); + /**indicates if camera is open */ bool isOpened() const ; diff --git a/src/raspicamrawbuffer.cpp b/src/raspicamrawbuffer.cpp new file mode 100644 index 0000000..98cfc10 --- /dev/null +++ b/src/raspicamrawbuffer.cpp @@ -0,0 +1,117 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University 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 BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA 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 + +#include "raspicamrawbuffer.h" +#include "private/raspicamrawbuffer_impl.h" + +namespace raspicam { + + RaspiCamRawBuffer::RaspiCamRawBuffer() { + _impl = new _private::RaspiCamRawBufferImpl(); + } + + RaspiCamRawBuffer::~RaspiCamRawBuffer() { +#ifdef RASPICAM_RAW_BUFFER_ENABLE_TRACE + std::cout << std::hex + << "RaspiCam: buffer " << _impl->getBuffer() + << " use is to be removed [" << _impl->getUseCount() << "] by destructor" + << std::endl + << std::flush; +#endif + delete _impl; + } + + RaspiCamRawBuffer::RaspiCamRawBuffer(const raspicam::RaspiCamRawBuffer &src) { + _impl = new _private::RaspiCamRawBufferImpl(*src._impl); +#ifdef RASPICAM_RAW_BUFFER_ENABLE_TRACE + std::cout << std::hex + << "RaspiCam: buffer " << _impl->getBuffer() + << " added use [" << _impl->getUseCount() << "] by copy constructor" + << std::endl + << std::flush; +#endif + } + + RaspiCamRawBuffer& RaspiCamRawBuffer::operator=(const raspicam::RaspiCamRawBuffer &src) { +#ifdef RASPICAM_RAW_BUFFER_ENABLE_TRACE + std::cout << std::hex + << "RaspiCam: buffer " << _impl->getBuffer() + << " use is to be removed [" << _impl->getUseCount() << "] by assignment" + << std::endl + << std::flush; +#endif + *_impl = *src._impl; +#ifdef RASPICAM_RAW_BUFFER_ENABLE_TRACE + std::cout << std::hex + << "RaspiCam: buffer " << _impl->getBuffer() + << " added use [" << _impl->getUseCount() << "] by assignment" + << std::endl + << std::flush; +#endif + return *this; + } + + void RaspiCamRawBuffer::moveFrom(raspicam::RaspiCamRawBuffer &src) { +#ifdef RASPICAM_RAW_BUFFER_ENABLE_TRACE + std::cout << std::hex + << "RaspiCam: buffer " << _impl->getBuffer() + << " use is to be removed [" << _impl->getUseCount() << "] by moveFrom method" + << std::endl + << std::flush; +#endif + _impl->moveFrom(*src._impl); + } + + void *RaspiCamRawBuffer::getBuffer() { + return _impl->getBuffer(); + } + + const void *RaspiCamRawBuffer::getBuffer() const { + return _impl->getBuffer(); + } + + void RaspiCamRawBuffer::lock() { + _impl->lock(); + } + + void RaspiCamRawBuffer::unlock() { + _impl->unlock(); + } + +} diff --git a/src/raspicamrawbuffer.h b/src/raspicamrawbuffer.h new file mode 100644 index 0000000..3fbc3f3 --- /dev/null +++ b/src/raspicamrawbuffer.h @@ -0,0 +1,121 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University 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 BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA 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. +****************************************************************/ + +#ifndef RaspiCamRawBuffer_H +#define RaspiCamRawBuffer_H + +namespace raspicam { + namespace _private { + class RaspiCamRawBufferImpl; + } + + /** + * Raw internal buffer representation. + * Provides user with contents of exactly the buffer, + * camera sensor data has been saved into. + */ + class RaspiCamRawBuffer { + + public: + RaspiCamRawBuffer(); + ~RaspiCamRawBuffer(); + + /** + * Copy constructor. + * Copies reference to internal buffer, + * increases references counter of buffer to be copied. + * @param src buffer reference to be copied + */ + RaspiCamRawBuffer(const RaspiCamRawBuffer& src); + + /** + * Assignment operator. + * Copies references to internal buffer, + * increases references counter of buffer to be copied, + * decreases reference counter of buffer to be overwritten. + * @param src buffer reference to be copied + * @return + */ + RaspiCamRawBuffer& operator=(const RaspiCamRawBuffer& src); + + /** + * Move contents + * Moves reference from source to current reference holder. + * After move source refers to nullptr. + * @param src buffer reference to be moved. + */ + void moveFrom(RaspiCamRawBuffer& src); + + /** + * Get buffer contents + * @return buffer contents. + */ + void* getBuffer(); + + /** + * Get buffer contents, constant implementation. + * @return buffer contents. + */ + const void* getBuffer() const; + + /** + * Lock buffer's memory. + */ + void lock(); + + /** + * Unlocks buffer's memory. + */ + void unlock(); + + /** + * Access to implementation object. + * @return non-const pointer to implementation object. + */ + _private::RaspiCamRawBufferImpl* accessImpl() { + return _impl; + } + + private: + _private::RaspiCamRawBufferImpl* _impl; + }; +} + +#endif + + + diff --git a/src/raspicamtypes.h b/src/raspicamtypes.h index 543061f..e400920 100755 --- a/src/raspicamtypes.h +++ b/src/raspicamtypes.h @@ -47,6 +47,7 @@ namespace raspicam { RASPICAM_FORMAT_GRAY, RASPICAM_FORMAT_BGR, RASPICAM_FORMAT_RGB, + RASPICAM_FORMAT_RGBA, RASPICAM_FORMAT_IGNORE //do not use };