From 953d973b69235a16bcb46c2f3a8045aa4132776e Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Thu, 6 Dec 2018 18:20:57 +0400 Subject: [PATCH 01/15] raw buffer: Added RaspiCamRawBuffer which is a client wrapper for MMAL buffers. --- src/private/raspicamrawbuffer_impl.cpp | 77 +++++++++++++++++ src/private/raspicamrawbuffer_impl.h | 106 +++++++++++++++++++++++ src/raspicamrawbuffer.cpp | 76 ++++++++++++++++ src/raspicamrawbuffer.h | 115 +++++++++++++++++++++++++ 4 files changed, 374 insertions(+) create mode 100644 src/private/raspicamrawbuffer_impl.cpp create mode 100644 src/private/raspicamrawbuffer_impl.h create mode 100644 src/raspicamrawbuffer.cpp create mode 100644 src/raspicamrawbuffer.h diff --git a/src/private/raspicamrawbuffer_impl.cpp b/src/private/raspicamrawbuffer_impl.cpp new file mode 100644 index 0000000..937abd4 --- /dev/null +++ b/src/private/raspicamrawbuffer_impl.cpp @@ -0,0 +1,77 @@ +// +// Created by Stepan Dyatkovskiy on 12/6/18. +// + +#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 { + RaspiCamRawBufferImpl::RaspiCamRawBufferImpl() + : _buffer(0), + _acquired(false) {} + + void RaspiCamRawBufferImpl::construct(const raspicam::_private::RaspiCamRawBufferImpl &src) { + _buffer = const_cast(src._buffer); + _acquired = true; + mmal_buffer_header_acquire(_buffer); + } + + void RaspiCamRawBufferImpl::dispose() { + if (_acquired) { + mmal_buffer_header_release(_buffer); + } + } + + RaspiCamRawBufferImpl::~RaspiCamRawBufferImpl() { + dispose(); + } + + RaspiCamRawBufferImpl::RaspiCamRawBufferImpl(const RaspiCamRawBufferImpl &src) { + construct(src); + } + + RaspiCamRawBufferImpl& RaspiCamRawBufferImpl::operator=(const RaspiCamRawBufferImpl &src) { + dispose(); + construct(src); + return *this; + } + + void RaspiCamRawBufferImpl::moveFrom(RaspiCamRawBufferImpl &src) { + _buffer = src._buffer; + _acquired = src._acquired; + + src._buffer = 0; + src._acquired = false; + } + + void RaspiCamRawBufferImpl::setMmalBufferHeader(MMAL_BUFFER_HEADER_T *buffer, bool acquire) { + _buffer = buffer; + + if (acquire) { + mmal_buffer_header_acquire(_buffer); + } + + _acquired = acquire; + } + + void* RaspiCamRawBufferImpl::getBuffer() { + return _buffer->data; + } + + void RaspiCamRawBufferImpl::lock() { + if (_buffer) { + mmal_buffer_header_mem_lock(_buffer); + } + } + + void RaspiCamRawBufferImpl::unlock() { + if (_buffer) { + mmal_buffer_header_mem_unlock(_buffer); + } + } + } +} diff --git a/src/private/raspicamrawbuffer_impl.h b/src/private/raspicamrawbuffer_impl.h new file mode 100644 index 0000000..2325bbb --- /dev/null +++ b/src/private/raspicamrawbuffer_impl.h @@ -0,0 +1,106 @@ +// +// Created by Stepan Dyatkovskiy on 12/6/18. +// + + +#ifndef RaspiCamRawBuffer_Impl_H +#define RaspiCamRawBuffer_Impl_H + +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: + + /** + * Constructs raw buffer reference wrapper object. + * Note here we don't count + * @param buffer + */ + explicit RaspiCamRawBufferImpl(); + + /** + * Disposes reference wrapper. + * If buffer has been acquired (reference been coutned for this wrapper), + * then buffer is released. + */ + ~RaspiCamRawBufferImpl(); + + /** + * Copy constructor. + * Copies reference to internal buffer, + * increases references counter of buffer to be copied. + * @param src buffer reference to be copied + */ + RaspiCamRawBufferImpl(const RaspiCamRawBufferImpl& 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 reference to this object. + */ + RaspiCamRawBufferImpl& operator=(const RaspiCamRawBufferImpl& 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(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, bool acquire = true); + + /** + * Get buffer contents + * @return buffer contents. + */ + void* getBuffer(); + + /** + * Lock buffer's memory. + */ + void lock(); + + /** + * Unlocks buffer's memory. + */ + void unlock(); + + private: + + void dispose(); + void construct(const RaspiCamRawBufferImpl& src); + + /** + * Buffer we're going to wrap by this impl object. + */ + MMAL_BUFFER_HEADER_T* _buffer; + + /** + * True if 'acquire' operation has been performed, and + * 'release' operation is required on wrapper dispose stage. + */ + bool _acquired; + }; + } +} + +#endif + + + diff --git a/src/raspicamrawbuffer.cpp b/src/raspicamrawbuffer.cpp new file mode 100644 index 0000000..f35d26c --- /dev/null +++ b/src/raspicamrawbuffer.cpp @@ -0,0 +1,76 @@ +/********************************************************** + 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 "raspicamrawbuffer.h" +#include "private/raspicamrawbuffer_impl.h" + +namespace raspicam { + + RaspiCamRawBuffer::RaspiCamRawBuffer() { + _impl = new _private::RaspiCamRawBufferImpl(); + } + + RaspiCamRawBuffer::~RaspiCamRawBuffer() { + delete _impl; + } + + RaspiCamRawBuffer::RaspiCamRawBuffer(const raspicam::RaspiCamRawBuffer &src) { + _impl = new _private::RaspiCamRawBufferImpl(*src._impl); + } + + RaspiCamRawBuffer& RaspiCamRawBuffer::operator=(const raspicam::RaspiCamRawBuffer &src) { + *_impl = *src._impl; + return *this; + } + + void RaspiCamRawBuffer::moveFrom(raspicam::RaspiCamRawBuffer &src) { + _impl->moveFrom(*src._impl); + } + + void *RaspiCamRawBuffer::getBuffer() { + 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..a2de7b2 --- /dev/null +++ b/src/raspicamrawbuffer.h @@ -0,0 +1,115 @@ +/********************************************************** + 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(); + + /** + * 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 + + + From 96dded516d5a7cf5838ce1a74a082a8c44f353fa Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Thu, 6 Dec 2018 18:27:00 +0400 Subject: [PATCH 02/15] private_impl: video_buffer_callback refactored, buffer processing has been moved into separate 'process_video_buffer'. --- src/private/private_impl.cpp | 108 ++++++++++++++++++----------------- src/private/private_impl.h | 4 +- 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/src/private/private_impl.cpp b/src/private/private_impl.cpp index 92a8530..c6e9c7b 100755 --- a/src/private/private_impl.cpp +++ b/src/private/private_impl.cpp @@ -41,6 +41,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "mmal/util/mmal_util.h" #include "mmal/util/mmal_util_params.h" #include "mmal/util/mmal_default_components.h" + using namespace std; namespace raspicam { namespace _private{ @@ -534,63 +535,19 @@ namespace raspicam { // 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 + bool processingRequired = + pData->wantToGrab || + pData->_userCallback; - // 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 { + if(buffer->length && processingRequired){ - 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; - } - } - - } + mmal_buffer_header_mem_lock ( buffer ); + process_video_buffer(pData, buffer); + mmal_buffer_header_mem_unlock ( buffer ); pData->wantToGrab =false; hasGrabbed=true; - mmal_buffer_header_mem_unlock ( buffer ); } } //pData->_mutex.unlock(); @@ -623,7 +580,56 @@ 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; + } + + 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; diff --git a/src/private/private_impl.h b/src/private/private_impl.h index 43e30d8..2c539c1 100755 --- a/src/private/private_impl.h +++ b/src/private/private_impl.h @@ -261,6 +261,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 +304,6 @@ namespace raspicam { bool _isCapturing; bool _rgb_bgr_fixed; - - }; } } From a0cf04a70c3e857036e2b4cf9b5fd1484b6f9ad4 Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Thu, 6 Dec 2018 18:34:41 +0400 Subject: [PATCH 03/15] CMakeLists, small refactoring: public_hdrs_base and srcs_base initialization has been multilined. Now if you will add new values to these variables, you will see more readable changesets with diff tools. --- src/CMakeLists.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3ccf7a7..e841ae9 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,9 +2,19 @@ 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 +) + +SET(srcs_base + raspicam.cpp + raspicam_still.cpp + private/private_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() From 6e05d5375861dd4b8fcf7c6903198427046682b7 Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Thu, 6 Dec 2018 18:36:47 +0400 Subject: [PATCH 04/15] CMakeLists.txt: Added RaspiCamRawBuffer related classes. --- src/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e841ae9..14f558d 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,12 +5,15 @@ SET(private_still_hdrs_base "private_still/private_still_types.h private/privat 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 ) From eb8e0d99a4596cfb39169a2358e8e176e0c4f7ff Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Thu, 6 Dec 2018 18:38:52 +0400 Subject: [PATCH 05/15] RaspiCamRawBuffer: added setRawBufferCallback to Raspicam class. --- src/private/private_impl.cpp | 26 ++++++++++++++++++++++---- src/private/private_impl.h | 11 +++++++++++ src/raspicam.cpp | 5 +++++ src/raspicam.h | 9 +++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/private/private_impl.cpp b/src/private/private_impl.cpp index c6e9c7b..e7a557c 100755 --- a/src/private/private_impl.cpp +++ b/src/private/private_impl.cpp @@ -41,6 +41,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #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 { @@ -151,6 +153,12 @@ namespace raspicam { callback_data._userCallback = userCallback; } + void Private_Impl::setRawBufferCallback(void (* userCallback)(const raspicam::RaspiCamRawBuffer &, void *), + void *data) { + callback_data._userCallbackData = data; + callback_data._userRawBufferCallback = userCallback; + } + void Private_Impl::release() { if ( !_isOpened ) return; @@ -538,13 +546,23 @@ namespace raspicam { bool processingRequired = pData->wantToGrab || - pData->_userCallback; + pData->_userCallback || + pData->_userRawBufferCallback; if(buffer->length && processingRequired){ - mmal_buffer_header_mem_lock ( buffer ); - process_video_buffer(pData, buffer); - mmal_buffer_header_mem_unlock ( buffer ); + if (pData->_userRawBufferCallback) { + RaspiCamRawBuffer rawBuffer; + + // Setup buffer but don't acquire it, + // for it is already acquired and to be released a bit below. + rawBuffer.accessImpl()->setMmalBufferHeader(buffer, false); + pData->_userRawBufferCallback(rawBuffer, 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; diff --git a/src/private/private_impl.h b/src/private/private_impl.h index 2c539c1..054a44b 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,7 @@ namespace raspicam { /* User define callback interface */ void (*_userCallback)(void*) = 0; + void (*_userRawBufferCallback)(const RaspiCamRawBuffer&, void*) = 0; void* _userCallbackData; }; @@ -115,6 +118,14 @@ 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. + */ + void setRawBufferCallback(void (*userCallback)(const RaspiCamRawBuffer&, void*) , void* data=0); + /**Grabs the next frame and keeps it in internal buffer. Blocks until next frame arrives */ bool grab(); diff --git a/src/raspicam.cpp b/src/raspicam.cpp index 229f4f8..2c8c8d1 100755 --- a/src/raspicam.cpp +++ b/src/raspicam.cpp @@ -58,6 +58,11 @@ namespace raspicam { _impl->setUserCallback(userCallback, data); } + void RaspiCam::setRawBufferCallback(void (* userCallback)(const raspicam::RaspiCamRawBuffer &, void *), + void *data) { + _impl->setRawBufferCallback(userCallback, data); + } + bool RaspiCam::isOpened() const {return _impl->isOpened();} bool RaspiCam::grab() { diff --git a/src/raspicam.h b/src/raspicam.h index ff7555e..7f23fbf 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,14 @@ 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. + */ + void setRawBufferCallback(void (*userCallback)(const RaspiCamRawBuffer&, void*) , void* data=0); + /**indicates if camera is open */ bool isOpened() const ; From 0a9a00b0c7ee917b39e213d4828903e66290d72c Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Thu, 6 Dec 2018 20:36:58 +0400 Subject: [PATCH 06/15] RaspiCamRawBuffer: added const implementation of getBuffer. --- src/private/raspicamrawbuffer_impl.cpp | 4 ++++ src/private/raspicamrawbuffer_impl.h | 6 ++++++ src/raspicamrawbuffer.cpp | 4 ++++ src/raspicamrawbuffer.h | 6 ++++++ 4 files changed, 20 insertions(+) diff --git a/src/private/raspicamrawbuffer_impl.cpp b/src/private/raspicamrawbuffer_impl.cpp index 937abd4..70e2d1f 100644 --- a/src/private/raspicamrawbuffer_impl.cpp +++ b/src/private/raspicamrawbuffer_impl.cpp @@ -62,6 +62,10 @@ namespace raspicam { return _buffer->data; } + const void* RaspiCamRawBufferImpl::getBuffer() const { + return _buffer->data; + } + void RaspiCamRawBufferImpl::lock() { if (_buffer) { mmal_buffer_header_mem_lock(_buffer); diff --git a/src/private/raspicamrawbuffer_impl.h b/src/private/raspicamrawbuffer_impl.h index 2325bbb..5a592a4 100644 --- a/src/private/raspicamrawbuffer_impl.h +++ b/src/private/raspicamrawbuffer_impl.h @@ -71,6 +71,12 @@ namespace raspicam { */ void* getBuffer(); + /** + * Get buffer contents + * @return buffer contents. + */ + const void* getBuffer() const; + /** * Lock buffer's memory. */ diff --git a/src/raspicamrawbuffer.cpp b/src/raspicamrawbuffer.cpp index f35d26c..c73dd3a 100644 --- a/src/raspicamrawbuffer.cpp +++ b/src/raspicamrawbuffer.cpp @@ -65,6 +65,10 @@ namespace raspicam { return _impl->getBuffer(); } + const void *RaspiCamRawBuffer::getBuffer() const { + return _impl->getBuffer(); + } + void RaspiCamRawBuffer::lock() { _impl->lock(); } diff --git a/src/raspicamrawbuffer.h b/src/raspicamrawbuffer.h index a2de7b2..3fbc3f3 100644 --- a/src/raspicamrawbuffer.h +++ b/src/raspicamrawbuffer.h @@ -86,6 +86,12 @@ namespace raspicam { */ void* getBuffer(); + /** + * Get buffer contents, constant implementation. + * @return buffer contents. + */ + const void* getBuffer() const; + /** * Lock buffer's memory. */ From 1536b38160e083f39e1e650bdc6ea8b80d4bcd5f Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Thu, 6 Dec 2018 20:48:21 +0400 Subject: [PATCH 07/15] RaspiCamRawBuffer: additional amount of buffers is required when we need to use buffers asyncronously on client side. So this commit adds some amount of buffers to recommended buffers for camera component. --- src/private/private_impl.cpp | 9 ++++++++- src/private/private_impl.h | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/private/private_impl.cpp b/src/private/private_impl.cpp index e7a557c..5c09ae2 100755 --- a/src/private/private_impl.cpp +++ b/src/private/private_impl.cpp @@ -51,6 +51,7 @@ namespace raspicam { #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 Private_Impl::Private_Impl() { @@ -157,6 +158,7 @@ namespace raspicam { void *data) { callback_data._userCallbackData = data; callback_data._userRawBufferCallback = userCallback; + callback_data._numRawBuffersUsedByClient = NUM_RAW_BUFFERS_USED_BY_CLIENT_DEFAULT; } void Private_Impl::release() { @@ -355,7 +357,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" ); diff --git a/src/private/private_impl.h b/src/private/private_impl.h index 054a44b..feb9948 100755 --- a/src/private/private_impl.h +++ b/src/private/private_impl.h @@ -83,7 +83,10 @@ namespace raspicam { /* User define callback interface */ void (*_userCallback)(void*) = 0; + void (*_userRawBufferCallback)(const RaspiCamRawBuffer&, void*) = 0; + uint32_t _numRawBuffersUsedByClient; + void* _userCallbackData; }; From b64412b761ff4a4a77e6ee9a3cff541cf4e5c9f1 Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Thu, 6 Dec 2018 21:17:42 +0400 Subject: [PATCH 08/15] RaspiCamRawBuffer, getBuffer: fixed case when _buffer is NULL --- src/private/raspicamrawbuffer_impl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/private/raspicamrawbuffer_impl.cpp b/src/private/raspicamrawbuffer_impl.cpp index 70e2d1f..69b0970 100644 --- a/src/private/raspicamrawbuffer_impl.cpp +++ b/src/private/raspicamrawbuffer_impl.cpp @@ -59,11 +59,11 @@ namespace raspicam { } void* RaspiCamRawBufferImpl::getBuffer() { - return _buffer->data; + return _buffer ? _buffer->data : 0; } const void* RaspiCamRawBufferImpl::getBuffer() const { - return _buffer->data; + return _buffer ? _buffer->data : 0; } void RaspiCamRawBufferImpl::lock() { From 067ed0d46a626ce32ced3f5b0e56c89489a22f9b Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Thu, 6 Dec 2018 22:19:48 +0400 Subject: [PATCH 09/15] RaspiCamRawBuffer: fixed copy of NULL buffer. --- src/private/raspicamrawbuffer_impl.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/private/raspicamrawbuffer_impl.cpp b/src/private/raspicamrawbuffer_impl.cpp index 69b0970..e154cbc 100644 --- a/src/private/raspicamrawbuffer_impl.cpp +++ b/src/private/raspicamrawbuffer_impl.cpp @@ -16,8 +16,12 @@ namespace raspicam { void RaspiCamRawBufferImpl::construct(const raspicam::_private::RaspiCamRawBufferImpl &src) { _buffer = const_cast(src._buffer); - _acquired = true; - mmal_buffer_header_acquire(_buffer); + if (_buffer) { + _acquired = true; + mmal_buffer_header_acquire(_buffer); + } else { + _acquired = false; + } } void RaspiCamRawBufferImpl::dispose() { From ff1d69ba64d006face671b1814c3e324e88834af Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Thu, 6 Dec 2018 22:20:29 +0400 Subject: [PATCH 10/15] CMakeLists.txt: Fixed compiler identification, added Clang support. --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 From 33a30dd900c9598861517cfa89331337fa7adf70 Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Fri, 7 Dec 2018 14:24:43 +0400 Subject: [PATCH 11/15] RaspiCamRawBuffer: refactored, so now it uses shared_ptr as a buffer header holder, with custom deleter which releases buffer. --- src/private/private_impl.cpp | 70 ++++++++++++--------- src/private/raspicamrawbuffer_impl.cpp | 86 ++++++++++---------------- src/private/raspicamrawbuffer_impl.h | 59 +++++------------- src/raspicamrawbuffer.cpp | 37 +++++++++++ 4 files changed, 125 insertions(+), 127 deletions(-) diff --git a/src/private/private_impl.cpp b/src/private/private_impl.cpp index 5c09ae2..6fb1e16 100755 --- a/src/private/private_impl.cpp +++ b/src/private/private_impl.cpp @@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************/ #include "private_impl.h" +#include #include #include #include "mmal/util/mmal_util.h" @@ -134,7 +135,13 @@ namespace raspicam { } // 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, just part, + // by some weird reason mmal uses only one buffer, and ignores the rest. + // So we provide mmal with buffers we need, and keep the rest in pool + // Then during a callback, we then may borrow buffer for a while, + // replacing it by one from pool. + int num = camera_video_port->buffer_num_recommended; int q; for ( q=0; qqueue ); @@ -549,36 +556,38 @@ namespace raspicam { bool hasGrabbed=false; // pData->_mutex.lock(); std::unique_lock lck ( pData->_mutex ); - if ( pData ) { - - bool processingRequired = - pData->wantToGrab || - pData->_userCallback || - pData->_userRawBufferCallback; - - if(buffer->length && processingRequired){ - - if (pData->_userRawBufferCallback) { - RaspiCamRawBuffer rawBuffer; - - // Setup buffer but don't acquire it, - // for it is already acquired and to be released a bit below. - rawBuffer.accessImpl()->setMmalBufferHeader(buffer, false); - pData->_userRawBufferCallback(rawBuffer, 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; + // 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; + } } + // 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; @@ -587,9 +596,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) diff --git a/src/private/raspicamrawbuffer_impl.cpp b/src/private/raspicamrawbuffer_impl.cpp index e154cbc..b3c5fe0 100644 --- a/src/private/raspicamrawbuffer_impl.cpp +++ b/src/private/raspicamrawbuffer_impl.cpp @@ -2,6 +2,8 @@ // Created by Stepan Dyatkovskiy on 12/6/18. // +#include + #include "mmal/util/mmal_util.h" #include "mmal/util/mmal_util_params.h" #include "mmal/util/mmal_default_components.h" @@ -10,76 +12,54 @@ namespace raspicam { namespace _private { - RaspiCamRawBufferImpl::RaspiCamRawBufferImpl() - : _buffer(0), - _acquired(false) {} - - void RaspiCamRawBufferImpl::construct(const raspicam::_private::RaspiCamRawBufferImpl &src) { - _buffer = const_cast(src._buffer); - if (_buffer) { - _acquired = true; - mmal_buffer_header_acquire(_buffer); - } else { - _acquired = false; - } - } - - void RaspiCamRawBufferImpl::dispose() { - if (_acquired) { - mmal_buffer_header_release(_buffer); - } - } - - RaspiCamRawBufferImpl::~RaspiCamRawBufferImpl() { - dispose(); - } - - RaspiCamRawBufferImpl::RaspiCamRawBufferImpl(const RaspiCamRawBufferImpl &src) { - construct(src); - } - - RaspiCamRawBufferImpl& RaspiCamRawBufferImpl::operator=(const RaspiCamRawBufferImpl &src) { - dispose(); - construct(src); - return *this; - } void RaspiCamRawBufferImpl::moveFrom(RaspiCamRawBufferImpl &src) { - _buffer = src._buffer; - _acquired = src._acquired; - - src._buffer = 0; - src._acquired = false; + _buffer.reset(0); + _buffer.swap(src._buffer); } - void RaspiCamRawBufferImpl::setMmalBufferHeader(MMAL_BUFFER_HEADER_T *buffer, bool acquire) { - _buffer = buffer; - - if (acquire) { - mmal_buffer_header_acquire(_buffer); - } + void RaspiCamRawBufferImpl::setMmalBufferHeader(MMAL_BUFFER_HEADER_T *buffer) { + _buffer = std::shared_ptr(buffer, Deleter()); - _acquired = acquire; +#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->data : 0; + return _buffer ? _buffer.get()->data : 0; } const void* RaspiCamRawBufferImpl::getBuffer() const { - return _buffer ? _buffer->data : 0; + return _buffer ? _buffer.get()->data : 0; } void RaspiCamRawBufferImpl::lock() { - if (_buffer) { - mmal_buffer_header_mem_lock(_buffer); - } + if (_buffer) + mmal_buffer_header_mem_lock(_buffer.get()); } void RaspiCamRawBufferImpl::unlock() { - if (_buffer) { - mmal_buffer_header_mem_unlock(_buffer); - } + 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 index 5a592a4..312e0e3 100644 --- a/src/private/raspicamrawbuffer_impl.h +++ b/src/private/raspicamrawbuffer_impl.h @@ -6,6 +6,13 @@ #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 { @@ -18,38 +25,6 @@ namespace raspicam { class RaspiCamRawBufferImpl { public: - /** - * Constructs raw buffer reference wrapper object. - * Note here we don't count - * @param buffer - */ - explicit RaspiCamRawBufferImpl(); - - /** - * Disposes reference wrapper. - * If buffer has been acquired (reference been coutned for this wrapper), - * then buffer is released. - */ - ~RaspiCamRawBufferImpl(); - - /** - * Copy constructor. - * Copies reference to internal buffer, - * increases references counter of buffer to be copied. - * @param src buffer reference to be copied - */ - RaspiCamRawBufferImpl(const RaspiCamRawBufferImpl& 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 reference to this object. - */ - RaspiCamRawBufferImpl& operator=(const RaspiCamRawBufferImpl& src); - /** * Move contents * Moves reference from source to current reference holder. @@ -63,7 +38,7 @@ namespace raspicam { * @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, bool acquire = true); + void setMmalBufferHeader(MMAL_BUFFER_HEADER_T *buffer); /** * Get buffer contents @@ -87,21 +62,15 @@ namespace raspicam { */ void unlock(); - private: + long getUseCount() const; - void dispose(); - void construct(const RaspiCamRawBufferImpl& src); + private: - /** - * Buffer we're going to wrap by this impl object. - */ - MMAL_BUFFER_HEADER_T* _buffer; + struct Deleter { + void operator()(MMAL_BUFFER_HEADER_T* _buffer) const; + }; - /** - * True if 'acquire' operation has been performed, and - * 'release' operation is required on wrapper dispose stage. - */ - bool _acquired; + std::shared_ptr _buffer; }; } } diff --git a/src/raspicamrawbuffer.cpp b/src/raspicamrawbuffer.cpp index c73dd3a..98cfc10 100644 --- a/src/raspicamrawbuffer.cpp +++ b/src/raspicamrawbuffer.cpp @@ -35,6 +35,8 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************/ +#include + #include "raspicamrawbuffer.h" #include "private/raspicamrawbuffer_impl.h" @@ -45,19 +47,54 @@ namespace raspicam { } 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); } From a8c2850c66cd3fd9b9a8e77058eb3004ba02d699 Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Fri, 7 Dec 2018 23:13:42 +0400 Subject: [PATCH 12/15] RaspiCamRawBuffer: added zero-copy mode. But still doesn't works right. Target texture seems to be filled by zeroes. --- src/private/private_impl.cpp | 38 +++++++++++++++++++++++++++++++----- src/private/private_impl.h | 12 +++++++++++- src/private/private_types.h | 5 +++++ src/raspicam.cpp | 8 +++++--- src/raspicam.h | 13 ++++++++++-- 5 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/private/private_impl.cpp b/src/private/private_impl.cpp index 6fb1e16..69fd38b 100755 --- a/src/private/private_impl.cpp +++ b/src/private/private_impl.cpp @@ -99,7 +99,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 @@ -161,11 +161,14 @@ namespace raspicam { callback_data._userCallback = userCallback; } - void Private_Impl::setRawBufferCallback(void (* userCallback)(const raspicam::RaspiCamRawBuffer &, void *), - void *data) { + 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() { @@ -329,8 +332,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; @@ -340,6 +349,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" ); diff --git a/src/private/private_impl.h b/src/private/private_impl.h index feb9948..76874ba 100755 --- a/src/private/private_impl.h +++ b/src/private/private_impl.h @@ -108,6 +108,7 @@ namespace raspicam { { return _isOpened; } + /**Starts camera capture */ bool startCapture(); @@ -126,8 +127,17 @@ namespace raspicam { * 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); + 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 */ 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/raspicam.cpp b/src/raspicam.cpp index 2c8c8d1..33a0e1e 100755 --- a/src/raspicam.cpp +++ b/src/raspicam.cpp @@ -58,9 +58,11 @@ namespace raspicam { _impl->setUserCallback(userCallback, data); } - void RaspiCam::setRawBufferCallback(void (* userCallback)(const raspicam::RaspiCamRawBuffer &, void *), - void *data) { - _impl->setRawBufferCallback(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();} diff --git a/src/raspicam.h b/src/raspicam.h index 7f23fbf..0245c3a 100755 --- a/src/raspicam.h +++ b/src/raspicam.h @@ -76,8 +76,17 @@ namespace raspicam { * obtained. * @param userCallback callback function * @param data user data you want to pass into callback. - */ - void setRawBufferCallback(void (*userCallback)(const RaspiCamRawBuffer&, void*) , void* data=0); + * @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 */ From 239b474f7a2611f1485ed7f9b3cd41afbc763159 Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Fri, 7 Dec 2018 23:16:35 +0400 Subject: [PATCH 13/15] Raspicam: added camera contents port selection. --- src/private/private_impl.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/private/private_impl.cpp b/src/private/private_impl.cpp index 69fd38b..c87bfba 100755 --- a/src/private/private_impl.cpp +++ b/src/private/private_impl.cpp @@ -48,12 +48,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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() { camera_video_port = NULL; @@ -109,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 @@ -128,11 +131,16 @@ 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 // Note: @@ -252,7 +260,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; @@ -278,7 +286,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, From 556da9614d0db122ce9cc11f91b811444b3ac48a Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Fri, 7 Dec 2018 23:40:56 +0400 Subject: [PATCH 14/15] Raspicam: added RGBA format --- src/private/private_impl.cpp | 6 ++++++ src/raspicamtypes.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/private/private_impl.cpp b/src/private/private_impl.cpp index c87bfba..024a52f 100755 --- a/src/private/private_impl.cpp +++ b/src/private/private_impl.cpp @@ -245,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; }; @@ -677,6 +679,8 @@ namespace raspicam { 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++) { @@ -957,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/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 }; From dbb31684c67a899c1ecf3bcf39acab50d794c887 Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Mon, 17 Dec 2018 12:49:37 +0400 Subject: [PATCH 15/15] RaspiCamRawBuffer: fixed related comments. --- src/private/private_impl.cpp | 10 +++--- src/private/raspicamrawbuffer_impl.cpp | 39 +++++++++++++++++++++-- src/private/raspicamrawbuffer_impl.h | 43 +++++++++++++++++++++----- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/src/private/private_impl.cpp b/src/private/private_impl.cpp index 024a52f..0d75234 100755 --- a/src/private/private_impl.cpp +++ b/src/private/private_impl.cpp @@ -144,11 +144,11 @@ namespace raspicam { // Send all the buffers to the video port // Note: - // We are not sending all buffers available, just part, + // 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 we need, and keep the rest in pool - // Then during a callback, we then may borrow buffer for a while, - // replacing it by one from pool. + // 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; q diff --git a/src/private/raspicamrawbuffer_impl.h b/src/private/raspicamrawbuffer_impl.h index 312e0e3..aac9c1b 100644 --- a/src/private/raspicamrawbuffer_impl.h +++ b/src/private/raspicamrawbuffer_impl.h @@ -1,7 +1,39 @@ -// -// Created by Stepan Dyatkovskiy on 12/6/18. -// - +/********************************************************** + 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 @@ -76,6 +108,3 @@ namespace raspicam { } #endif - - -