2 #include "async_web_server_cpp/http_reply.hpp" 5 #define AV_CODEC_FLAG_GLOBAL_HEADER (1 << 22) 6 #define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER 21 boost::mutex *m =
new boost::mutex();
22 *mutex =
static_cast<void *
>(m);
27 boost::mutex *m =
static_cast<boost::mutex *
>(*mutex);
33 boost::mutex *m =
static_cast<boost::mutex *
>(*mutex);
39 boost::mutex *m =
static_cast<boost::mutex *
>(*mutex);
52 async_web_server_cpp::HttpConnectionPtr connection,
ros::NodeHandle& nh,
53 const std::string &format_name,
const std::string &codec_name,
54 const std::string &content_type) :
55 ImageTransportImageStreamer(request, connection, nh), output_format_(0), format_context_(0), codec_(0), codec_context_(0), video_stream_(
56 0), frame_(0), sws_context_(0), first_image_timestamp_(0), format_name_(
57 format_name), codec_name_(codec_name), content_type_(content_type), opt_(0), io_buffer_(0)
60 bitrate_ = request.get_query_param_value_or_default<
int>(
"bitrate", 100000);
61 qmin_ = request.get_query_param_value_or_default<
int>(
"qmin", 10);
62 qmax_ = request.get_query_param_value_or_default<
int>(
"qmax", 42);
63 gop_ = request.get_query_param_value_or_default<
int>(
"gop", 250);
75 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) 96 async_web_server_cpp::HttpConnectionPtr connection = *((async_web_server_cpp::HttpConnectionPtr*) opaque);
97 std::vector<uint8_t> encoded_frame;
98 encoded_frame.assign(buffer, buffer + buffer_size);
99 connection->write_and_clear(encoded_frame);
109 async_web_server_cpp::HttpReply::stock_reply(async_web_server_cpp::HttpReply::internal_server_error)(
request_,
112 throw std::runtime_error(
"Error allocating ffmpeg format context");
117 async_web_server_cpp::HttpReply::stock_reply(async_web_server_cpp::HttpReply::internal_server_error)(
request_,
120 throw std::runtime_error(
"Error looking up output format");
125 size_t io_buffer_size = 3 * 1024;
126 io_buffer_ =
new unsigned char[io_buffer_size];
130 async_web_server_cpp::HttpReply::stock_reply(async_web_server_cpp::HttpReply::internal_server_error)(
request_,
133 throw std::runtime_error(
"Error setting up IO context");
135 io_ctx->seekable = 0;
147 async_web_server_cpp::HttpReply::stock_reply(async_web_server_cpp::HttpReply::internal_server_error)(
request_,
150 throw std::runtime_error(
"Error looking up codec");
155 async_web_server_cpp::HttpReply::stock_reply(async_web_server_cpp::HttpReply::internal_server_error)(
request_,
158 throw std::runtime_error(
"Error creating video stream");
194 async_web_server_cpp::HttpReply::stock_reply(async_web_server_cpp::HttpReply::internal_server_error)(
request_,
197 throw std::runtime_error(
"Could not open video codec");
201 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) 202 frame_ = avcodec_alloc_frame();
204 frame_ = av_frame_alloc();
215 std::vector<uint8_t> header_buffer;
216 std::size_t header_size;
217 uint8_t *header_raw_buffer;
219 av_dict_set(&
format_context_->metadata,
"author",
"ROS web_video_server", 0);
223 async_web_server_cpp::HttpReply::builder(async_web_server_cpp::HttpReply::ok).header(
"Connection",
"close").header(
224 "Server",
"web_video_server").header(
"Cache-Control",
225 "no-cache, no-store, must-revalidate, pre-check=0, post-check=0, max-age=0").header(
226 "Pragma",
"no-cache").header(
"Expires",
"0").header(
"Max-Age",
"0").header(
"Trailer",
"Expires").header(
232 async_web_server_cpp::HttpReply::stock_reply(async_web_server_cpp::HttpReply::internal_server_error)(
request_,
235 throw std::runtime_error(
"Error openning dynamic buffer");
250 std::vector<uint8_t> encoded_frame;
251 #if (LIBAVUTIL_VERSION_MAJOR < 53) 252 PixelFormat input_coding_format = PIX_FMT_BGR24;
254 AVPixelFormat input_coding_format = AV_PIX_FMT_BGR24;
257 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) 258 AVPicture *raw_frame =
new AVPicture;
261 AVFrame *raw_frame = av_frame_alloc();
262 av_image_fill_arrays(raw_frame->data, raw_frame->linesize,
271 static int sws_flags = SWS_BICUBIC;
276 throw std::runtime_error(
"Could not initialize the conversion context");
282 (
const uint8_t *
const *)raw_frame->data, raw_frame->linesize, 0,
285 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) 288 av_frame_free(&raw_frame);
294 av_init_packet(&pkt);
296 #if (LIBAVCODEC_VERSION_MAJOR < 54) 298 pkt.data = (uint8_t*)av_malloc(buf_size);
300 got_packet = pkt.size > 0;
301 #elif (LIBAVCODEC_VERSION_MAJOR < 57) 306 throw std::runtime_error(
"Error encoding video frame");
313 throw std::runtime_error(
"Error encoding video frame");
317 throw std::runtime_error(
"Error retrieving encoded packet");
328 pkt.pts = (int64_t)(seconds / av_q2d(
video_stream_->time_base) * 0.95);
331 pkt.dts = AV_NOPTS_VALUE;
333 if (pkt.flags&AV_PKT_FLAG_KEY)
334 pkt.flags |= AV_PKT_FLAG_KEY;
340 throw std::runtime_error(
"Error when writing frame");
345 encoded_frame.clear();
347 #if LIBAVCODEC_VERSION_INT < 54 351 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) 352 av_free_packet(&pkt);
354 av_packet_unref(&pkt);
361 const std::string &content_type) :
367 async_web_server_cpp::HttpConnectionPtr connection,
376 std::stringstream ss;
377 ss <<
"<video src=\"/stream?";
379 ss <<
"\" autoplay=\"true\" preload=\"none\"></video>";
static int dispatch_output_packet(void *opaque, uint8_t *buffer, int buffer_size)
AVFormatContext * format_context_
std::string content_type_
const std::string content_type_
async_web_server_cpp::HttpConnectionPtr connection_
virtual void sendImage(const cv::Mat &, const ros::Time &time)
LibavStreamer(const async_web_server_cpp::HttpRequest &request, async_web_server_cpp::HttpConnectionPtr connection, ros::NodeHandle &nh, const std::string &format_name, const std::string &codec_name, const std::string &content_type)
std::string create_viewer(const async_web_server_cpp::HttpRequest &request)
boost::shared_ptr< ImageStreamer > create_streamer(const async_web_server_cpp::HttpRequest &request, async_web_server_cpp::HttpConnectionPtr connection, ros::NodeHandle &nh)
virtual void initialize(const cv::Mat &)
async_web_server_cpp::HttpRequest request_
#define CODEC_FLAG_GLOBAL_HEADER
boost::mutex encode_mutex_
struct SwsContext * sws_context_
virtual void initializeEncoder()
LibavStreamerType(const std::string &format_name, const std::string &codec_name, const std::string &content_type)
ros::Time first_image_timestamp_
const std::string format_name_
AVOutputFormat * output_format_
const std::string codec_name_
AVCodecContext * codec_context_
static int ffmpeg_boost_mutex_lock_manager(void **mutex, enum AVLockOp op)