VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gvviewerinput.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 // gvviewerinput.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gnet.h"
23 #include "gvviewerinput.h"
24 #include "geventloop.h"
25 #include "gassert.h"
26 #include "glog.h"
27 #include <string>
28 #include <stdexcept>
29 
30 Gv::ViewerInput::ViewerInput( ViewerInputHandler & input_handler , const ViewerInputConfig & input_config ,
31  const std::string & channel , int shmem_fd , int pipe_fd ) :
32  m_input_handler(input_handler) ,
33  m_scale(input_config.m_scale) ,
34  m_static(input_config.m_static) ,
35  m_first(true),
36  m_rate_limit(input_config.m_rate_limit) ,
37  m_rate_timer(*this,&ViewerInput::onRateTimeout,*this) ,
38  m_quiescent_timer(*this,&ViewerInput::onQuiescentTimeout,*this) ,
39  m_decoder_tmp(Gr::ImageData::Contiguous) ,
40  m_data_out(nullptr)
41 {
42  if( channel.empty() )
43  {
44  m_pipe.reset( new G::FatPipeReceiver(shmem_fd,pipe_fd) ) ;
45  m_fd = pipe_fd ;
46  }
47  else
48  {
49  m_quiescent_timer.startTimer( 2U ) ;
50  m_channel.reset( new G::PublisherSubscription(channel) ) ;
51  m_fd = m_channel->fd() ;
52  }
54 }
55 
57 {
59 }
60 
61 void Gv::ViewerInput::onException( std::exception & )
62 {
63  throw ;
64 }
65 
66 void Gv::ViewerInput::readEvent()
67 {
68  m_quiescent_timer.cancelTimer() ;
69  if( m_static && !m_first )
70  {
71  read( m_tmp ) ; // client only wants the first image -- clear the event and discard the data
72  }
73  else if( read(m_buffer) && decode() )
74  {
75  m_first = false ;
76  m_input_handler.onInput( m_type_out.dx() , m_type_out.dy() , m_type_out.channels() , m_data_out , m_type_out.size() ) ;
77  }
78 }
79 
80 bool Gv::ViewerInput::read( std::vector<char> & buffer )
81 {
82  G::EpochTime time( 0 ) ;
83  if( m_pipe.get() )
84  {
85  if( !m_pipe->receive( buffer , &m_type_in_str , &time ) )
86  throw Closed( "parent has gone away" ) ;
87  }
88  else
89  {
90  if( !m_channel->receive( buffer , &m_type_in_str , &time ) )
91  throw std::runtime_error( "publisher has gone away" ) ;
92  }
93 
94  m_type_in = Gr::ImageType( m_type_in_str ) ;
95 
96  if( buffer.empty() )
97  G_DEBUG( "Gv::ViewerInput::read: empty read" ) ; // eg. FatPipe::ping(), or select() race
98 
99  if( !m_type_in.valid() )
100  G_DEBUG( "Gv::ViewerInput::read: invalid type: [" << m_type_in_str << "]" ) ;
101 
102  bool ok = !buffer.empty() && m_type_in.valid() ;
103  if( ok )
104  G_DEBUG( "Gv::ViewerInput::read: got image: size=" << buffer.size() << " type=[" << m_type_in << "]" ) ;
105 
106  if( ok && m_rate_limit != G::EpochTime(0) )
107  {
108  G_DEBUG( "Gv::ViewerInput::read: rate limiting: dropping fd " << m_fd ) ;
110  m_rate_timer.startTimer( m_rate_limit.s , m_rate_limit.us ) ;
111  }
112  return ok ;
113 }
114 
115 void Gv::ViewerInput::onRateTimeout()
116 {
117  G_DEBUG( "Gv::ViewerInput::onRateTimeout: rate limiting: resuming fd " << m_fd ) ;
119 }
120 
121 void Gv::ViewerInput::onQuiescentTimeout()
122 {
123  G_ASSERT( m_channel.get() != nullptr ) ;
124  unsigned int age = m_channel->age() ;
125  std::ostringstream ss ;
126  if( age > 1U )
127  ss << ": idle for " << age << "s" ;
128  G_WARNING( "Gv::ViewerInput::onQuiescentTimeout: quiescent channel [" << m_channel->name() << "]" << ss.str() ) ;
129 }
130 
131 bool Gv::ViewerInput::decode()
132 {
133  try
134  {
135  m_decoder.setup( m_scale , false ) ;
136  m_data_out = &m_buffer[0] ;
137  m_type_out = m_decoder.decodeInPlace( m_type_in , m_data_out/*in-out*/ , m_buffer.size() , m_decoder_tmp ) ;
138  G_DEBUG( "Gv::ViewerInput::decode: type=[" << m_type_out << "]" ) ;
139  return true ;
140  }
141  catch( std::exception & e )
142  {
143  G_WARNING_ONCE( "Gv::ViewerInput::decode: viewer failed to decode image: "
144  "type=[" << m_type_in << "] size=" << m_buffer.size() << ": " << e.what() ) ;
145  G_LOG( "Gv::ViewerInput::decode: failed image decode: "
146  "type=[" << m_type_in << "] size=" << m_buffer.size() << ": " << e.what() ) ;
147  return false ;
148  }
149 }
150 
151 const char * Gv::ViewerInput::data() const
152 {
153  return &m_buffer[0] ;
154 }
155 
156 size_t Gv::ViewerInput::size() const
157 {
158  return m_buffer.size() ;
159 }
160 
162 {
163  return m_type_out.dx() ;
164 }
165 
167 {
168  return m_type_out.dy() ;
169 }
170 
172 {
173  return m_type_out.channels() ;
174 }
175 
177 {
178  return m_type_out ;
179 }
180 
181 // ==
182 
184 {
185 }
186 
187 /// \file gvviewerinput.cpp
A subsecond-resolution timestamp based on a time_t.
Definition: gdatetime.h:39
An input channel for images.
Definition: gvviewerinput.h:77
~ViewerInput()
Destructor.
A callback interface for Gv::ViewerInput.
Definition: gvviewerinput.h:48
An encapsulation of image type, including width, height and number of channels, with support for a st...
Definition: grimagetype.h:43
virtual ~ViewerInputHandler()
Destructor.
Gr::ImageType type() const
Returns the type for the decoded image.
virtual void dropRead(Descriptor fd)=0
Removes the given event source descriptor from the list of read sources.
An easy-to-use combination of a G::PublisherChannel object and a single G::PublisherSubscriber.
Definition: gpublisher.h:229
A class that encapsulates a network file descriptor and hides knowledge of its o/s-spefific error val...
Definition: gdescriptor.h:37
size_t size() const
Returns the data() size.
virtual void addRead(Descriptor fd, EventHandler &handler)=0
Adds the given event source descriptor and associated handler to the read list.
A structure to hold configuration for a Gv::ViewerInput object.
Definition: gvviewerinput.h:61
ViewerInput(ViewerInputHandler &, const ViewerInputConfig &, const std::string &channel, int shmem_fd, int pipe_fd)
Constructor.
A class to read a fat pipe in the child process.
Definition: gfatpipe.h:174
int channels() const
Returns the number of channels (one or three).
int dy() const
Returns the image height.
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
Definition: geventloop.cpp:43
const char * data() const
Returns the data as a standard luma or rgb-interleaved buffer.
int dx() const
Returns the image width.