decoding_subscribers.hpp
Go to the documentation of this file.
1 #ifndef CODEC_IMAGE_TRANSPORT_DECODING_SUBSCRIBERS_HPP
2 #define CODEC_IMAGE_TRANSPORT_DECODING_SUBSCRIBERS_HPP
3 
4 #include <string>
5 
8 #include <ros/console.h>
9 #include <ros/exception.h>
10 #include <ros/node_handle.h>
11 #include <sensor_msgs/CompressedImage.h>
12 #include <sensor_msgs/Image.h>
14 
15 #include <boost/mpl/string.hpp>
16 #include <boost/shared_ptr.hpp>
17 
18 extern "C" {
19 #include <libavcodec/avcodec.h>
20 #include <libavutil/imgutils.h>
21 #include <libswscale/swscale.h>
22 }
23 
25 
26 template < AVCodecID CodecID, typename TransportName >
28  : public image_transport::SimpleSubscriberPlugin< sensor_msgs::CompressedImage > {
29 public:
31 
32  virtual ~DecodingSubscriber() {}
33 
34  virtual std::string getTransportName() const { return boost::mpl::c_str< TransportName >::value; }
35 
36 private:
37  virtual void subscribeImpl(ros::NodeHandle &nh, const std::string &base_topic,
38  uint32_t queue_size, const Callback &callback,
39  const ros::VoidPtr &tracked_object,
40  const image_transport::TransportHints &transport_hints) {
41  if (!decoder_ctx_) {
42  // init libavformat
43  avcodec_register_all();
44  av_log_set_level(AV_LOG_FATAL);
45 
46  // find a decoder
47  AVCodec *const decoder(avcodec_find_decoder(CodecID));
48  if (!decoder) {
49  throw ros::Exception("Cannot find a decoder");
50  }
51 
52  // allocate a decoder context
53  decoder_ctx_.reset(avcodec_alloc_context3(decoder), deleteAVCodecContext);
54  if (!decoder_ctx_) {
55  throw ros::Exception("Cannot allocate a decoder context");
56  }
57 
58  // open decoder
59  if (avcodec_open2(decoder_ctx_.get(), decoder, NULL) < 0) {
60  throw ros::Exception("Failed to open codec");
61  }
62  }
63 
64  Base::subscribeImpl(nh, base_topic, queue_size, callback, tracked_object, transport_hints);
65  }
66 
67  virtual void internalCallback(const sensor_msgs::CompressedImage::ConstPtr &message,
68  const Callback &user_cb) {
69  // set packet data from the input message
70  AVPacket packet;
71  av_init_packet(&packet);
72  packet.size = message->data.size();
73  packet.data = const_cast< uint8_t * >(&message->data[0]);
74 
75  while (packet.size > 0) {
76  // allocate a frame for decoded data
77  boost::shared_ptr< AVFrame > frame(av_frame_alloc(), deleteAVFrame);
78  if (!frame) {
79  ROS_ERROR("Cannot allocate frame");
80  return;
81  }
82 
83  // decode one frame
84  int got_frame;
85  const int len(avcodec_decode_video2(decoder_ctx_.get(), frame.get(), &got_frame, &packet));
86  if (len < 0) {
87  ROS_ERROR("Cannot decode a frame");
88  return;
89  }
90 
91  // toss the decoded frame to the user callback
92  if (got_frame > 0) {
93  // allocate output message
94  const sensor_msgs::ImagePtr out(new sensor_msgs::Image());
95  out->header = message->header;
96  out->height = frame->height;
97  out->width = frame->width;
98  out->encoding = sensor_msgs::image_encodings::BGR8;
99  out->step = 3 * frame->width;
100  out->data.resize(3 * frame->width * frame->height);
101 
102  // layout data by converting color spaces (YUV -> RGB)
104  sws_getContext(
105  // src formats
106  frame->width, frame->height,
107  toUndeprecated(static_cast< AVPixelFormat >(frame->format)),
108  // dst formats
109  frame->width, frame->height, AV_PIX_FMT_BGR24,
110  // flags & filters
111  SWS_FAST_BILINEAR, NULL, NULL, NULL),
112  sws_freeContext);
113  int stride(out->step);
114  uint8_t *dst(&out->data[0]);
115  sws_scale(convert_ctx.get(),
116  // src data
117  frame->data, frame->linesize, 0, frame->height,
118  // dst data
119  &dst, &stride);
120 
121  // exec user callback
122  user_cb(out);
123  }
124 
125  // consume data in the packet
126  packet.size -= len;
127  packet.data += len;
128  }
129  }
130 
131  // Deleter for auto free/close of libav objects
132  static void deleteAVFrame(AVFrame *frame) {
133  if (frame) {
134  av_frame_free(&frame);
135  }
136  }
137 
138  static void deleteAVCodecContext(AVCodecContext *ctx) {
139  if (ctx) {
140  avcodec_free_context(&ctx);
141  }
142  }
143 
144  // Workaround to avoid deprecated pixel format warning
145  static AVPixelFormat toUndeprecated(const AVPixelFormat format) {
146  switch (format) {
147  case AV_PIX_FMT_YUVJ420P:
148  return AV_PIX_FMT_YUV420P;
149  case AV_PIX_FMT_YUVJ411P:
150  return AV_PIX_FMT_YUV411P;
151  case AV_PIX_FMT_YUVJ422P:
152  return AV_PIX_FMT_YUV422P;
153  case AV_PIX_FMT_YUVJ440P:
154  return AV_PIX_FMT_YUV440P;
155  case AV_PIX_FMT_YUVJ444P:
156  return AV_PIX_FMT_YUV444P;
157  default:
158  return format;
159  }
160  }
161 
162 private:
164 
166 };
167 
170 
171 } // namespace decoding_image_transport
172 
173 #endif
static void deleteAVCodecContext(AVCodecContext *ctx)
DecodingSubscriber< AV_CODEC_ID_H264, boost::mpl::string< 'h', '2', '6', '4' > > H264Subscriber
boost::function< void(const sensor_msgs::ImageConstPtr &)> Callback
virtual void subscribeImpl(ros::NodeHandle &nh, const std::string &base_topic, uint32_t queue_size, const Callback &callback, const ros::VoidPtr &tracked_object, const image_transport::TransportHints &transport_hints)
virtual void internalCallback(const sensor_msgs::CompressedImage::ConstPtr &message, const Callback &user_cb)
static AVPixelFormat toUndeprecated(const AVPixelFormat format)
image_transport::SimpleSubscriberPlugin< sensor_msgs::CompressedImage > Base
boost::shared_ptr< AVCodecContext > decoder_ctx_
#define ROS_ERROR(...)
virtual void subscribeImpl(ros::NodeHandle &nh, const std::string &base_topic, uint32_t queue_size, const Callback &callback, const ros::VoidPtr &tracked_object, const TransportHints &transport_hints)


codec_image_transport
Author(s):
autogenerated on Mon Jun 10 2019 12:55:56