decoding_controllers.hpp
Go to the documentation of this file.
1 #ifndef USB_CAM_CONTROLLERS_DECODING_CONTROLLERS
2 #define USB_CAM_CONTROLLERS_DECODING_CONTROLLERS
3 
4 #include <string>
5 
8 #include <ros/console.h>
9 #include <ros/duration.h>
10 #include <ros/node_handle.h>
11 #include <ros/time.h>
12 #include <sensor_msgs/Image.h>
16 
17 extern "C" {
18 #include <libavcodec/avcodec.h>
19 #include <libavutil/imgutils.h>
20 #include <libswscale/swscale.h>
21 }
22 
23 namespace usb_cam_controllers {
24 
25 template < AVCodecID CodecId, AVPixelFormat DstFormat, const std::string *DstEncoding >
27 public:
29 
30  virtual ~DecodingController() {}
31 
32 protected:
34  ros::NodeHandle &controller_nh) {
35  // init libavcodec
36  avcodec_register_all();
37  av_log_set_level(AV_LOG_FATAL);
38 
39  // find h264 decoder
40  AVCodec *const decoder(avcodec_find_decoder(CodecId));
41  if (!decoder) {
42  ROS_ERROR_STREAM("Cannot find the decoder (codec id: " << CodecId << ")");
43  return false;
44  }
45 
46  // allocate h264 decoder context
47  decoder_ctx_.reset(avcodec_alloc_context3(decoder), deleteAVCodecContext);
48  if (!decoder_ctx_) {
49  ROS_ERROR_STREAM("Cannot allocate a decoder context (codec id: " << CodecId << ")");
50  return false;
51  }
52 
53  // open decoder
54  if (avcodec_open2(decoder_ctx_.get(), decoder, NULL) < 0) {
55  ROS_ERROR_STREAM("Failed to open the codec (codec id: " << CodecId << ")");
56  return false;
57  }
58 
59  // init publisher for decoded images
60  publisher_ = image_transport::ImageTransport(controller_nh).advertise("image", 1);
61 
62  return true;
63  }
64 
65  virtual void startingImpl(const ros::Time &time) {
66  // nothing to do
67  }
68 
69  virtual void updateImpl(const ros::Time &time, const ros::Duration &period) {
70  // set packet data from the input message
71  AVPacket packet;
72  av_init_packet(&packet);
73  packet.size = packet_iface_.getLength();
74  packet.data = const_cast< uint8_t * >(packet_iface_.getStartAs< uint8_t >());
75 
76  // send the packet to the decoder
77  if (avcodec_send_packet(decoder_ctx_.get(), &packet) < 0) {
78  ROS_ERROR_STREAM("Cannot send a packet to decoder (codec id: " << CodecId << ")");
79  return;
80  }
81 
82  while (true) {
83  // allocate a frame for decoded data
84  boost::shared_ptr< AVFrame > frame(av_frame_alloc(), deleteAVFrame);
85  if (!frame) {
86  ROS_ERROR_STREAM("Cannot allocate a frame");
87  return;
88  }
89 
90  // receive the decoded data from the decoder
91  const int res(avcodec_receive_frame(decoder_ctx_.get(), frame.get()));
92  if (res == AVERROR(EAGAIN) || res == AVERROR_EOF) {
93  // no more frames in the packet
94  return;
95  } else if (res < 0) {
96  ROS_ERROR("Cannot receive a frame");
97  return;
98  }
99 
100  // allocate output message
101  const sensor_msgs::ImagePtr out(new sensor_msgs::Image());
102  const int data_size(av_image_get_buffer_size(DstFormat, frame->width, frame->height, 1));
103  out->header.stamp = packet_iface_.getStamp();
104  out->height = frame->height;
105  out->width = frame->width;
106  out->encoding = *DstEncoding;
107  out->step = data_size / frame->height;
108  out->data.resize(data_size);
109 
110  // layout data by converting color spaces
112  sws_getContext(
113  // src formats
114  frame->width, frame->height,
115  toUndeprecated(static_cast< AVPixelFormat >(frame->format)),
116  // dst formats
117  frame->width, frame->height, DstFormat,
118  // flags & filters
119  SWS_FAST_BILINEAR, NULL, NULL, NULL),
120  sws_freeContext);
121  int stride(out->step);
122  uint8_t *dst(&out->data[0]);
123  sws_scale(convert_ctx.get(),
124  // src data
125  frame->data, frame->linesize, 0, frame->height,
126  // dst data
127  &dst, &stride);
128 
129  publisher_.publish(out);
130  }
131  }
132 
133  virtual void stoppingImpl(const ros::Time &time) {
134  // nothing to do
135  }
136 
137 private:
138  // Deleter for auto free/close of libav objects
139  static void deleteAVFrame(AVFrame *frame) {
140  if (frame) {
141  av_frame_free(&frame);
142  }
143  }
144 
145  static void deleteAVCodecContext(AVCodecContext *ctx) {
146  if (ctx) {
147  avcodec_free_context(&ctx);
148  }
149  }
150 
151  // Workaround to avoid deprecated pixel format warning
152  static AVPixelFormat toUndeprecated(const AVPixelFormat format) {
153  switch (format) {
154  case AV_PIX_FMT_YUVJ420P:
155  return AV_PIX_FMT_YUV420P;
156  case AV_PIX_FMT_YUVJ411P:
157  return AV_PIX_FMT_YUV411P;
158  case AV_PIX_FMT_YUVJ422P:
159  return AV_PIX_FMT_YUV422P;
160  case AV_PIX_FMT_YUVJ440P:
161  return AV_PIX_FMT_YUV440P;
162  case AV_PIX_FMT_YUVJ444P:
163  return AV_PIX_FMT_YUV444P;
164  default:
165  return format;
166  }
167  }
168 
169 private:
172 };
173 
174 typedef DecodingController< AV_CODEC_ID_H264, AV_PIX_FMT_BGR24,
177 typedef DecodingController< AV_CODEC_ID_MJPEG, AV_PIX_FMT_BGR24,
180 
181 } // namespace usb_cam_controllers
182 
183 #endif
static AVPixelFormat toUndeprecated(const AVPixelFormat format)
boost::shared_ptr< AVCodecContext > decoder_ctx_
Publisher advertise(const std::string &base_topic, uint32_t queue_size, bool latch=false)
DecodingController< AV_CODEC_ID_MJPEG, AV_PIX_FMT_BGR24, &sensor_msgs::image_encodings::BGR8 > MjpegController
DecodingController< AV_CODEC_ID_H264, AV_PIX_FMT_BGR24, &sensor_msgs::image_encodings::BGR8 > H264Controller
static void deleteAVCodecContext(AVCodecContext *ctx)
virtual void startingImpl(const ros::Time &time)
void publish(const sensor_msgs::Image &message) const
virtual void stoppingImpl(const ros::Time &time)
virtual bool initImpl(usb_cam_hardware_interface::PacketInterface *hw, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh)
#define ROS_ERROR_STREAM(args)
usb_cam_hardware_interface::PacketHandle packet_iface_
#define ROS_ERROR(...)
virtual void updateImpl(const ros::Time &time, const ros::Duration &period)


usb_cam_controllers
Author(s):
autogenerated on Tue Mar 1 2022 00:01:15