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  // repeat decoding until all data in the packet are consumed
77  while (packet.size > 0) {
78  // decode one frame
79  boost::shared_ptr< AVFrame > frame(av_frame_alloc(), deleteAVFrame);
80  int got_frame;
81  const int len(avcodec_decode_video2(decoder_ctx_.get(), frame.get(), &got_frame, &packet));
82  if (len < 0) {
83  ROS_ERROR("Cannot decode a frame");
84  return;
85  }
86 
87  // publish the decoded frame
88  if (got_frame > 0) {
89  // allocate output message
90  const sensor_msgs::ImagePtr out(new sensor_msgs::Image());
91  const int data_size(av_image_get_buffer_size(DstFormat, frame->width, frame->height, 1));
92  out->header.stamp = packet_iface_.getStamp();
93  out->height = frame->height;
94  out->width = frame->width;
95  out->encoding = *DstEncoding;
96  out->step = data_size / frame->height;
97  out->data.resize(data_size);
98 
99  // layout data by converting color spaces (YUV -> RGB)
101  sws_getContext(
102  // src formats
103  frame->width, frame->height,
104  toUndeprecated(static_cast< AVPixelFormat >(frame->format)),
105  // dst formats
106  frame->width, frame->height, DstFormat,
107  // flags & filters
108  SWS_FAST_BILINEAR, NULL, NULL, NULL),
109  sws_freeContext);
110  int stride(out->step);
111  uint8_t *dst(&out->data[0]);
112  sws_scale(convert_ctx.get(),
113  // src data
114  frame->data, frame->linesize, 0, frame->height,
115  // dst data
116  &dst, &stride);
117 
118  publisher_.publish(out);
119  }
120 
121  // consume data in the packet
122  packet.size -= len;
123  packet.data += len;
124  }
125  }
126 
127  virtual void stoppingImpl(const ros::Time &time) {
128  // nothing to do
129  }
130 
131 private:
132  // Deleter for auto free/close of libav objects
133  static void deleteAVFrame(AVFrame *frame) {
134  if (frame) {
135  av_frame_free(&frame);
136  }
137  }
138 
139  static void deleteAVCodecContext(AVCodecContext *ctx) {
140  if (ctx) {
141  avcodec_free_context(&ctx);
142  }
143  }
144 
145  // Workaround to avoid deprecated pixel format warning
146  static AVPixelFormat toUndeprecated(const AVPixelFormat format) {
147  switch (format) {
148  case AV_PIX_FMT_YUVJ420P:
149  return AV_PIX_FMT_YUV420P;
150  case AV_PIX_FMT_YUVJ411P:
151  return AV_PIX_FMT_YUV411P;
152  case AV_PIX_FMT_YUVJ422P:
153  return AV_PIX_FMT_YUV422P;
154  case AV_PIX_FMT_YUVJ440P:
155  return AV_PIX_FMT_YUV440P;
156  case AV_PIX_FMT_YUVJ444P:
157  return AV_PIX_FMT_YUV444P;
158  default:
159  return format;
160  }
161  }
162 
163 private:
166 };
167 
168 typedef DecodingController< AV_CODEC_ID_H264, AV_PIX_FMT_BGR24,
171 typedef DecodingController< AV_CODEC_ID_MJPEG, AV_PIX_FMT_BGR24,
174 
175 } // namespace usb_cam_controllers
176 
177 #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)
void publish(const sensor_msgs::Image &message) const
virtual void startingImpl(const ros::Time &time)
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 Jul 14 2020 03:12:08