10 #if defined(__GNUC__) // Needed for ffmpeg headers. Only allowed here when not 12 #define __STDC_CONSTANT_MACROS // Needed for having "UINT64_C" and so 15 #include <mrpt/config.h> 22 #define _MSC_STDINT_H_ // We already have pstdint.h in MRPT 23 #include <libavcodec/avcodec.h> 24 #include <libavformat/avformat.h> 25 #include <libavutil/imgutils.h> 26 #include <libswscale/swscale.h> 48 AVFormatContext* pFormatCtx{
nullptr};
50 #if LIBAVFORMAT_VERSION_MAJOR >= 58 51 AVCodecParameters* pCodecPars{
nullptr};
53 AVCodec* pCodec{
nullptr};
54 AVCodecContext* pCodecCtx{
nullptr};
55 AVFrame* pFrame{
nullptr};
56 AVFrame* pFrameRGB{
nullptr};
57 SwsContext* img_convert_ctx{
nullptr};
58 std::vector<uint8_t> buffer;
66 TFFMPEGContext m_state;
75 : m_impl(mrpt::make_impl<CFFMPEG_InputStream::Impl>())
78 #if LIBAVFORMAT_VERSION_MAJOR < 58 106 const TFFMPEGContext* ctx = &
m_impl->m_state;
107 return ctx->pFormatCtx !=
nullptr;
117 const std::string&
url,
bool grab_as_grayscale,
bool verbose)
122 TFFMPEGContext* ctx = &
m_impl->m_state;
128 if (avformat_open_input(&ctx->pFormatCtx,
url.c_str(),
nullptr,
nullptr) !=
131 ctx->pFormatCtx =
nullptr;
132 std::cerr <<
"[CFFMPEG_InputStream::openURL] Cannot open video: " <<
url 138 if (avformat_find_stream_info(ctx->pFormatCtx,
nullptr) < 0)
140 std::cerr <<
"[CFFMPEG_InputStream::openURL] Couldn't find stream " 149 av_dump_format(ctx->pFormatCtx, 0,
url.c_str(),
false);
153 ctx->videoStream = -1;
154 for (
unsigned int i = 0; i < ctx->pFormatCtx->nb_streams; i++)
156 #if LIBAVFORMAT_VERSION_MAJOR >= 58 157 auto codecType = ctx->pFormatCtx->streams[i]->codecpar->codec_type;
159 auto codecType = ctx->pFormatCtx->streams[i]->codec->codec_type;
161 if (codecType == AVMEDIA_TYPE_VIDEO)
163 ctx->videoStream = (int)i;
167 if (ctx->videoStream == -1)
170 <<
"[CFFMPEG_InputStream::openURL] Didn't find a video stream: " 176 #if LIBAVFORMAT_VERSION_MAJOR >= 58 177 ctx->pCodecPars = ctx->pFormatCtx->streams[ctx->videoStream]->codecpar;
179 ctx->pCodec = avcodec_find_decoder(ctx->pCodecPars->codec_id);
181 ctx->pCodecCtx = ctx->pFormatCtx->streams[ctx->videoStream]->codec;
183 ctx->pCodec = avcodec_find_decoder(ctx->pCodecCtx->codec_id);
185 if (ctx->pCodec ==
nullptr)
187 std::cerr <<
"[CFFMPEG_InputStream::openURL] Codec not found: " <<
url 192 #if LIBAVFORMAT_VERSION_MAJOR >= 58 193 ctx->pCodecCtx = avcodec_alloc_context3(
nullptr );
196 std::cerr <<
"[CFFMPEG_InputStream::openURL] Cannot alloc avcodec " 203 if (avcodec_parameters_to_context(
205 ctx->pFormatCtx->streams[ctx->videoStream]->codecpar))
207 std::cerr <<
"[CFFMPEG_InputStream::openURL] Failed " 208 "avcodec_parameters_to_context() for: " 214 ctx->pCodecCtx->codec_id = ctx->pCodec->id;
218 if (avcodec_open2(ctx->pCodecCtx, ctx->pCodec,
nullptr) < 0)
221 <<
"[CFFMPEG_InputStream::openURL] avcodec_open2() failed for: " 227 ctx->pFrame = av_frame_alloc();
229 ctx->pFrameRGB = av_frame_alloc();
231 if (ctx->pFrameRGB ==
nullptr || ctx->pFrame ==
nullptr)
233 std::cerr <<
"[CFFMPEG_InputStream::openURL] Could not alloc memory " 234 "for frame buffers: " 240 #if LIBAVFORMAT_VERSION_MAJOR >= 58 241 const auto width = ctx->pCodecPars->width, height = ctx->pCodecPars->height;
243 const auto width = ctx->pCodecCtx->width, height = ctx->pCodecCtx->height;
245 int numBytes = av_image_get_buffer_size(
250 std::cerr <<
"[CFFMPEG_InputStream::openURL] av_image_get_buffer_size " 252 << numBytes << std::endl;
256 ctx->buffer.resize(numBytes);
260 av_image_fill_arrays(
261 ctx->pFrameRGB->data, ctx->pFrameRGB->linesize, &ctx->buffer[0],
277 if (!this->
isOpen())
return;
279 TFFMPEGContext* ctx = &
m_impl->m_state;
284 avcodec_close(ctx->pCodecCtx);
285 ctx->pCodecCtx =
nullptr;
291 avformat_close_input(&ctx->pFormatCtx);
292 ctx->pFormatCtx =
nullptr;
300 av_frame_free(&ctx->pFrameRGB);
301 ctx->pFrameRGB =
nullptr;
305 av_frame_free(&ctx->pFrame);
306 ctx->pFrame =
nullptr;
309 if (ctx->img_convert_ctx)
311 sws_freeContext(ctx->img_convert_ctx);
312 ctx->img_convert_ctx =
nullptr;
324 if (!this->
isOpen())
return false;
326 TFFMPEGContext* ctx = &
m_impl->m_state;
330 #if LIBAVFORMAT_VERSION_MAJOR < 58 334 #if LIBAVFORMAT_VERSION_MAJOR >= 58 335 const auto width = ctx->pCodecPars->width, height = ctx->pCodecPars->height;
337 const auto width = ctx->pCodecCtx->width, height = ctx->pCodecCtx->height;
340 while (av_read_frame(ctx->pFormatCtx, &packet) >= 0)
343 if (packet.stream_index != ctx->videoStream)
345 av_packet_unref(&packet);
350 #if LIBAVFORMAT_VERSION_MAJOR >= 58 351 int ret = avcodec_send_packet(ctx->pCodecCtx, &packet);
354 std::cerr <<
"[CFFMPEG_InputStream] avcodec_send_packet error code=" 359 ret = avcodec_receive_frame(ctx->pCodecCtx, ctx->pFrame);
360 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
364 std::cerr <<
"[CFFMPEG_InputStream] avcodec_receive_frame " 371 avcodec_decode_video2(
372 ctx->pCodecCtx, ctx->pFrame, &frameFinished, &packet);
376 av_packet_unref(&packet);
381 ctx->img_convert_ctx = sws_getCachedContext(
382 ctx->img_convert_ctx, width, height, ctx->pCodecCtx->pix_fmt, width,
387 SWS_BICUBIC,
nullptr,
nullptr,
nullptr);
390 ctx->img_convert_ctx, ctx->pFrame->data, ctx->pFrame->linesize, 0,
391 height, ctx->pFrameRGB->data, ctx->pFrameRGB->linesize);
398 if (ctx->pFrameRGB->linesize[0] !=
406 av_packet_unref(&packet);
410 av_packet_unref(&packet);
425 if (!this->
isOpen())
return -1;
427 const TFFMPEGContext* ctx = &
m_impl->m_state;
429 if (!ctx->pCodecCtx)
return -1;
431 return static_cast<double>(ctx->pCodecCtx->time_base.den) /
432 ctx->pCodecCtx->time_base.num;
#define THROW_EXCEPTION(msg)
Contains classes for various device interfaces.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
A class for storing images as grayscale or RGB bitmaps.
void loadFromMemoryBuffer(unsigned int width, unsigned int height, bool color, unsigned char *rawpixels, bool swapRedBlue=false)
Reads the image from raw pixels buffer in memory.