VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gvcapturebuffer.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gvcapturebuffer.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gvcapturebuffer.h"
23 #include <stdexcept>
24 #include <sys/mman.h> // munmap
25 #include <stdlib.h>
26 
27 namespace
28 {
29  void * memalign_( void **aligned_p , size_t page , size_t n )
30  {
31  // roll our own for portability
32  void * p = malloc( n + page + 1 ) ;
33  char *pp = reinterpret_cast<char*>(p) ;
34  while( (reinterpret_cast<unsigned long>(pp) % page) != 0 )
35  pp++ ;
36  *aligned_p = pp ;
37  return p ; // free()able
38  }
39 }
40 
42  m_format(nullptr) ,
43  m_freeme(nullptr) ,
44  m_start(nullptr) ,
45  m_length(length) ,
46  m_unmap(0)
47 {
48  // "read" i/o -- malloc(), with free() in dtor
49  m_freeme = m_start = malloc( length ) ;
50  if( m_start == nullptr )
51  throw std::runtime_error( "out of memory" ) ;
52 }
53 
54 Gv::CaptureBuffer::CaptureBuffer( size_t length , void * p , int (*unmap)(void*,size_t) ) :
55  m_format(nullptr) ,
56  m_freeme(nullptr) ,
57  m_start(p) ,
58  m_length(length) ,
59  m_unmap(unmap)
60 {
61  // "mmap" i/o -- no-op, with munmap() in dtor
62  G_ASSERT( p != nullptr ) ;
63 }
64 
65 Gv::CaptureBuffer::CaptureBuffer( size_t page_size , size_t buffer_size ) :
66  m_format(nullptr) ,
67  m_length(size4(buffer_size)) ,
68  m_unmap(0)
69 {
70  // "userptr" i/o -- aligned malloc(), with free() in dtor
71  m_freeme = memalign_( &m_start , page_size , buffer_size ) ;
72  if( m_start == nullptr )
73  throw std::runtime_error( "out of memory" ) ;
74 }
75 
77 {
78  if( m_freeme )
79  {
80  free( m_freeme ) ;
81  }
82  else // mmap
83  {
84  G_IGNORE_RETURN( int , (*m_unmap)( m_start, m_length ) ) ;
85  }
86 }
87 
89 {
90  m_format = &f ;
91  m_scale = s ;
92  checkFormat() ;
93 }
94 
95 void Gv::CaptureBuffer::checkFormat() const
96 {
97  // sanity check the format vs. the buffer size
98  G_ASSERT( m_scale.m_dx > 0U && m_scale.m_dy > 1U ) ;
99  const size_t x_1 = m_scale.m_dx - 1U ;
100  const size_t y_1 = m_scale.m_dy - 1U ;
101  const size_t offset_0 = m_format->component(0).offset(x_1,y_1,m_scale) ;
102  const size_t offset_1 = m_format->component(1).offset(x_1,y_1,m_scale) ;
103  const size_t offset_2 = m_format->component(2).offset(x_1,y_1,m_scale) ;
104  const size_t max_offset = std::max(offset_0,std::max(offset_1,offset_2)) ;
105  G_ASSERT( max_offset < size() ) ;
106  //G_ASSERT( (size()-max_offset) < 4 ) ; // too strong for libv4l
107  if( max_offset >= size() )
108  throw std::runtime_error( "pixelformat inconsistent with capture buffer size" ) ;
109 }
110 
112 {
113  if( m_format->is_simple() && m_scale.is_simple(data.dx(),data.dy()) && data.channels() == 3 ) // optimisation
114  {
115  G_ASSERT( data.rowsize() == m_scale.m_linesize ) ;
116  const size_t rowsize = data.rowsize() ;
117  const unsigned char * p_in = begin() ;
118  for( size_t y = 0U ; y < m_scale.m_dy ; y++ , p_in += rowsize )
119  {
120  std::memcpy( data.row(y) , p_in , rowsize ) ;
121  }
122  }
123  else
124  {
125  for( size_t y = 0U ; y < m_scale.m_dy ; y++ )
126  {
127  CaptureBufferIterator bp = row( y ) ;
128  for( size_t x = 0U ; x < m_scale.m_dx ; x++ , ++bp )
129  {
130  typedef Gr::ColourSpace::triple<unsigned char> triple_t ;
131  const triple_t & rgb = *bp ;
132  data.rgb( x , y , rgb.r() , rgb.g() , rgb.b() ) ;
133  }
134  }
135  }
136 }
137 
138 void Gv::CaptureBuffer::copy( int dx , int dy , unsigned char * p_out , size_t n_out ) const
139 {
140  G_ASSERT( p_out != nullptr && dx > 0 && dy > 0 && n_out > 0U ) ;
141  G_ASSERT( n_out == (size_t(dx)*size_t(dy)*size_t(3U)) ) ;
142  if( p_out == nullptr || n_out != (size_t(dx)*size_t(dy)*size_t(3U)) )
143  throw std::runtime_error( "capture buffer size mismatch" ) ;
144 
145  if( m_format->is_simple() && m_scale.is_simple(dx,dy) ) // optimisation
146  {
147  G_ASSERT( n_out == size() ) ;
148  std::memcpy( p_out , begin() , std::min(n_out,size()) ) ;
149  }
150  else
151  {
152  unsigned char * const p_end = p_out + n_out ;
153  for( int y = 0 ; y < dy ; y++ )
154  {
155  CaptureBufferIterator bp = row( y ) ;
156  if( (p_out+dx+dx+dx) > p_end ) break ; // just in case
157  for( int x = 0 ; x < dx ; x++ , ++bp )
158  {
159  typedef Gr::ColourSpace::triple<unsigned char> triple_t ;
160  triple_t rgb = *bp ;
161  *p_out++ = rgb.r() ;
162  *p_out++ = rgb.g() ;
163  *p_out++ = rgb.b() ;
164  }
165  }
166  }
167 }
168 
169 void Gv::CaptureBuffer::copy( int dx , int dy , char * p_out , size_t n ) const
170 {
171  copy( dx , dy , reinterpret_cast<unsigned char *>(p_out) , n ) ;
172 }
173 
174 // ==
175 
177  m_offset(0),
178  m_x_shift(0) ,
179  m_y_shift(0) ,
180  m_step(3),
181  m_depth(8),
182  m_mask(0xff),
183  m_shift(0),
184  m_type(c_byte) ,
185  m_linesize_shift(0) ,
186  m_simple(false)
187 {
188 }
189 
190 Gv::CaptureBufferComponent::CaptureBufferComponent( size_t offset_ , unsigned short x_shift_ , unsigned short y_shift_ ,
191  size_t step_ , unsigned short depth_ , unsigned short shift_ , Type type_ , short linesize_shift_ ) :
192  m_offset(offset_) ,
193  m_x_shift(x_shift_) ,
194  m_y_shift(y_shift_) ,
195  m_step(step_) ,
196  m_depth(depth_) ,
197  m_mask(0U) ,
198  m_shift(shift_) ,
199  m_type(type_) ,
200  m_linesize_shift(linesize_shift_) ,
201  m_simple(m_depth==8&&m_type==c_byte&&m_shift==0)
202 {
203  m_mask = (1U << m_depth) - 1U ;
204 }
205 
206 // ==
207 
208 Gv::CaptureBufferFormat::CaptureBufferFormat( unsigned int id_ , const char * name_ , Type type_ ) :
209  m_id(id_) ,
210  m_name(name_) ,
211  m_type(type_)
212 {
213 }
214 
215 Gv::CaptureBufferFormat::CaptureBufferFormat( unsigned int id_ , const char * name_ , Type type_ ,
216  const CaptureBufferComponent & c0 , const CaptureBufferComponent & c1 , const CaptureBufferComponent & c2 ) :
217  m_id(id_) ,
218  m_name(name_) ,
219  m_type(type_)
220 {
221  m_c[0] = c0 ;
222  m_c[1] = c1 ;
223  m_c[2] = c2 ;
224 }
225 
227 {
228  return m_type == rgb && m_c[0].is_simple(0) && m_c[1].is_simple(1) && m_c[2].is_simple(2) ;
229 }
230 
231 /// \file gvcapturebuffer.cpp
triple< unsigned char > rgb(triple< unsigned char > yuv) g__noexcept
A top-level function that calculates rgb from yuv with default implementation options.
size_t rowsize() const
Returns the row size, ie. dx()*channels().
int dx() const
Returns the width.
Definition: grimagedata.h:329
A holder for image data, having eight bits per sample and one or three channels.
Definition: grimagedata.h:46
A const iterator for a single row of Gv::CaptureBuffer pixels.
unsigned char * row(int y)
Returns a pointer to the y'th row.
Definition: grimagedata.h:368
CaptureBufferFormat(unsigned int id_=0, const char *name_="", Type type_=rgb)
Default constructor for an unusable, un-named rgb format.
A descriptor for a v4l pixel format.
CaptureBuffer(size_t length)
Constructor for a malloc()ed buffer suitable for "read()" i/o.
void setFormat(const CaptureBufferFormat &, const CaptureBufferScale &)
Used by the Gv::Capture class to imbue the buffer with a particular format description and scale...
~CaptureBuffer()
Destructor.
CaptureBufferComponent()
Default constructor for a simple step-three component.
int channels() const
Returns the number of channels (zero, one or three).
Definition: grimagedata.h:341
A structure holding capture buffer dimensions.
unsigned int rgb(int x, int y) const
Returns the colour of a pixel as rgb values packed into one integer.
Definition: grimagedata.h:411
void copyTo(Gr::ImageData &) const
Copies the image to a correctly-sized image data buffer.
bool is_simple() const
Returns true for a packed rgb format with 24 bits per pixel.
int dy() const
Returns the height.
Definition: grimagedata.h:335
void copy(int dx, int dy, char *p_out, size_t out_size) const
Copies the image to an rgb output buffer.
A descriptor for one colour component in a Gv::CaptureBufferFormat structure.