@@ -50,7 +50,7 @@ LibavStreamer::LibavStreamer(const async_web_server_cpp::HttpRequest &request,
50
50
const std::string &content_type) :
51
51
ImageTransportImageStreamer (request, connection, nh), output_format_(0 ), format_context_(0 ), codec_(0 ), codec_context_(0 ), video_stream_(
52
52
0 ), frame_(0 ), sws_context_(0 ), first_image_timestamp_(0 ), format_name_(
53
- format_name), codec_name_(codec_name), content_type_(content_type)
53
+ format_name), codec_name_(codec_name), content_type_(content_type), opt_( 0 ), io_buffer_( 0 )
54
54
{
55
55
56
56
bitrate_ = request.get_query_param_value_or_default <int >(" bitrate" , 100000 );
@@ -75,12 +75,26 @@ LibavStreamer::~LibavStreamer()
75
75
av_frame_free (&frame_);
76
76
#endif
77
77
}
78
+ if (io_buffer_)
79
+ delete io_buffer_;
80
+ if (format_context_->pb )
81
+ av_free (format_context_->pb );
78
82
if (format_context_)
79
83
avformat_free_context (format_context_);
80
84
if (sws_context_)
81
85
sws_freeContext (sws_context_);
82
86
}
83
87
88
+ // output callback for ffmpeg IO context
89
+ static int dispatch_output_packet (void * opaque, uint8_t * buffer, int buffer_size)
90
+ {
91
+ async_web_server_cpp::HttpConnectionPtr connection = *((async_web_server_cpp::HttpConnectionPtr*) opaque);
92
+ std::vector<uint8_t > encoded_frame;
93
+ encoded_frame.assign (buffer, buffer + buffer_size);
94
+ connection->write_and_clear (encoded_frame);
95
+ return 0 ; // TODO: can this fail?
96
+ }
97
+
84
98
void LibavStreamer::initialize (const cv::Mat &img)
85
99
{
86
100
// Load format
@@ -102,6 +116,22 @@ void LibavStreamer::initialize(const cv::Mat &img)
102
116
}
103
117
format_context_->oformat = output_format_;
104
118
119
+ // Set up custom IO callback.
120
+ size_t io_buffer_size = 3 * 1024 ; // 3M seen elsewhere and adjudged good
121
+ io_buffer_ = new unsigned char [io_buffer_size];
122
+ AVIOContext* io_ctx = avio_alloc_context (io_buffer_, io_buffer_size, AVIO_FLAG_WRITE, &connection_, NULL , dispatch_output_packet, NULL );
123
+ if (!io_ctx)
124
+ {
125
+ async_web_server_cpp::HttpReply::stock_reply (async_web_server_cpp::HttpReply::internal_server_error)(request_,
126
+ connection_,
127
+ NULL , NULL );
128
+ throw std::runtime_error (" Error setting up IO context" );
129
+ }
130
+ io_ctx->seekable = 0 ; // no seeking, it's a stream
131
+ format_context_->pb = io_ctx;
132
+ output_format_->flags |= AVFMT_FLAG_CUSTOM_IO;
133
+ output_format_->flags |= AVFMT_NOFILE;
134
+
105
135
// Load codec
106
136
if (codec_name_.empty ()) // use default codec if none specified
107
137
codec_ = avcodec_find_encoder (output_format_->video_codec );
@@ -127,7 +157,7 @@ void LibavStreamer::initialize(const cv::Mat &img)
127
157
// Set options
128
158
avcodec_get_context_defaults3 (codec_context_, codec_);
129
159
130
- codec_context_->codec_id = output_format_-> video_codec ;
160
+ codec_context_->codec_id = codec_-> id ;
131
161
codec_context_->bit_rate = bitrate_;
132
162
133
163
codec_context_->width = output_width_;
@@ -171,7 +201,9 @@ void LibavStreamer::initialize(const cv::Mat &img)
171
201
av_image_alloc (frame_->data , frame_->linesize , output_width_, output_height_,
172
202
codec_context_->pix_fmt , 1 );
173
203
174
-
204
+ frame_->width = output_width_;
205
+ frame_->height = output_height_;
206
+ frame_->format = codec_context_->pix_fmt ;
175
207
output_format_->flags |= AVFMT_NOFILE;
176
208
177
209
// Generate header
@@ -182,24 +214,6 @@ void LibavStreamer::initialize(const cv::Mat &img)
182
214
av_dict_set (&format_context_->metadata , " author" , " ROS web_video_server" , 0 );
183
215
av_dict_set (&format_context_->metadata , " title" , topic_.c_str (), 0 );
184
216
185
- if (avio_open_dyn_buf (&format_context_->pb ) >= 0 )
186
- {
187
- if (avformat_write_header (format_context_, NULL ) < 0 )
188
- {
189
- async_web_server_cpp::HttpReply::stock_reply (async_web_server_cpp::HttpReply::internal_server_error)(request_,
190
- connection_,
191
- NULL , NULL );
192
- throw std::runtime_error (" Error openning dynamic buffer" );
193
- }
194
- header_size = avio_close_dyn_buf (format_context_->pb , &header_raw_buffer);
195
-
196
- // copy header buffer to vector
197
- header_buffer.resize (header_size);
198
- memcpy (&header_buffer[0 ], header_raw_buffer, header_size);
199
-
200
- av_free (header_raw_buffer);
201
- }
202
-
203
217
// Send response headers
204
218
async_web_server_cpp::HttpReply::builder (async_web_server_cpp::HttpReply::ok).header (" Connection" , " close" ).header (
205
219
" Server" , " web_video_server" ).header (" Cache-Control" ,
@@ -208,7 +222,13 @@ void LibavStreamer::initialize(const cv::Mat &img)
208
222
" Content-type" , content_type_).header (" Access-Control-Allow-Origin" , " *" ).write (connection_);
209
223
210
224
// Send video stream header
211
- connection_->write_and_clear (header_buffer);
225
+ if (avformat_write_header (format_context_, &opt_) < 0 )
226
+ {
227
+ async_web_server_cpp::HttpReply::stock_reply (async_web_server_cpp::HttpReply::internal_server_error)(request_,
228
+ connection_,
229
+ NULL , NULL );
230
+ throw std::runtime_error (" Error openning dynamic buffer" );
231
+ }
212
232
}
213
233
214
234
void LibavStreamer::initializeEncoder ()
@@ -235,7 +255,7 @@ void LibavStreamer::sendImage(const cv::Mat &img, const ros::Time &time)
235
255
#else
236
256
AVFrame *raw_frame = av_frame_alloc ();
237
257
av_image_fill_arrays (raw_frame->data , raw_frame->linesize ,
238
- img.data , input_coding_format, output_width_, output_height_, 0 );
258
+ img.data , input_coding_format, output_width_, output_height_, 1 );
239
259
#endif
240
260
241
261
@@ -310,18 +330,9 @@ void LibavStreamer::sendImage(const cv::Mat &img, const ros::Time &time)
310
330
311
331
pkt.stream_index = video_stream_->index ;
312
332
313
- if (avio_open_dyn_buf (& format_context_-> pb ) >= 0 )
333
+ if (av_write_frame ( format_context_, &pkt) )
314
334
{
315
- if (av_write_frame (format_context_, &pkt))
316
- {
317
- throw std::runtime_error (" Error when writing frame" );
318
- }
319
- size = avio_close_dyn_buf (format_context_->pb , &output_buf);
320
-
321
- encoded_frame.resize (size);
322
- memcpy (&encoded_frame[0 ], output_buf, size);
323
-
324
- av_free (output_buf);
335
+ throw std::runtime_error (" Error when writing frame" );
325
336
}
326
337
}
327
338
else
0 commit comments