diff --git a/selfdrive/ui/replay/framereader.cc b/selfdrive/ui/replay/framereader.cc index 51a99cea63..bfdc6ee386 100644 --- a/selfdrive/ui/replay/framereader.cc +++ b/selfdrive/ui/replay/framereader.cc @@ -1,30 +1,10 @@ #include "selfdrive/ui/replay/framereader.h" -#include #include -#include #include namespace { -int ffmpeg_lockmgr_cb(void **arg, enum AVLockOp op) { - std::mutex *mutex = (std::mutex *)*arg; - switch (op) { - case AV_LOCK_CREATE: - mutex = new std::mutex(); - break; - case AV_LOCK_OBTAIN: - mutex->lock(); - break; - case AV_LOCK_RELEASE: - mutex->unlock(); - case AV_LOCK_DESTROY: - delete mutex; - break; - } - return 0; -} - int readFunction(void *opaque, uint8_t *buf, int buf_size) { auto &iss = *reinterpret_cast(opaque); iss.read(reinterpret_cast(buf), buf_size); @@ -34,12 +14,6 @@ int readFunction(void *opaque, uint8_t *buf, int buf_size) { } // namespace FrameReader::FrameReader(bool local_cache, int chunk_size, int retries) : FileReader(local_cache, chunk_size, retries) { - static std::once_flag once_flag; - std::call_once(once_flag, [] { - av_lockmgr_register(ffmpeg_lockmgr_cb); - av_register_all(); - }); - pFormatCtx_ = avformat_alloc_context(); av_frame_ = av_frame_alloc(); rgb_frame_ = av_frame_alloc(); @@ -50,6 +24,7 @@ FrameReader::~FrameReader() { for (auto &f : frames_) { av_free_packet(&f.pkt); } + if (pCodecCtx_) avcodec_free_context(&pCodecCtx_); if (pFormatCtx_) avformat_close_input(&pFormatCtx_); if (av_frame_) av_frame_free(&av_frame_); @@ -75,22 +50,22 @@ bool FrameReader::load(const std::string &url, std::atomic *abort) { pFormatCtx_->pb = avio_ctx_; pFormatCtx_->probesize = 10 * 1024 * 1024; // 10MB - int err = avformat_open_input(&pFormatCtx_, url.c_str(), NULL, NULL); - if (err != 0) { + int ret = avformat_open_input(&pFormatCtx_, url.c_str(), NULL, NULL); + if (ret != 0) { char err_str[1024] = {0}; - av_strerror(err, err_str, std::size(err_str)); + av_strerror(ret, err_str, std::size(err_str)); printf("Error loading video - %s - %s\n", err_str, url.c_str()); return false; } avformat_find_stream_info(pFormatCtx_, NULL); // av_dump_format(pFormatCtx_, 0, url.c_str(), 0); - auto pCodecCtxOrig = pFormatCtx_->streams[0]->codec; - auto pCodec = avcodec_find_decoder(pCodecCtxOrig->codec_id); + AVStream *video = pFormatCtx_->streams[0]; + auto pCodec = avcodec_find_decoder(video->codec->codec_id); if (!pCodec) return false; pCodecCtx_ = avcodec_alloc_context3(pCodec); - int ret = avcodec_copy_context(pCodecCtx_, pCodecCtxOrig); + ret = avcodec_parameters_to_context(pCodecCtx_, video->codecpar); if (ret != 0) return false; // pCodecCtx_->thread_count = 0; @@ -98,14 +73,14 @@ bool FrameReader::load(const std::string &url, std::atomic *abort) { ret = avcodec_open2(pCodecCtx_, pCodec, NULL); if (ret < 0) return false; - width = (pCodecCtxOrig->width + 3) & ~3; - height = pCodecCtxOrig->height; - rgb_sws_ctx_ = sws_getContext(pCodecCtxOrig->width, pCodecCtxOrig->height, AV_PIX_FMT_YUV420P, + width = (pCodecCtx_->width + 3) & ~3; + height = pCodecCtx_->height; + rgb_sws_ctx_ = sws_getContext(pCodecCtx_->width, pCodecCtx_->height, AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_BGR24, SWS_FAST_BILINEAR, NULL, NULL, NULL); if (!rgb_sws_ctx_) return false; - yuv_sws_ctx_ = sws_getContext(pCodecCtxOrig->width, pCodecCtxOrig->height, AV_PIX_FMT_YUV420P, + yuv_sws_ctx_ = sws_getContext(pCodecCtx_->width, pCodecCtx_->height, AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL); if (!yuv_sws_ctx_) return false; @@ -113,10 +88,10 @@ bool FrameReader::load(const std::string &url, std::atomic *abort) { frames_.reserve(60 * 20); // 20fps, one minute while (!(abort && *abort)) { Frame &frame = frames_.emplace_back(); - err = av_read_frame(pFormatCtx_, &frame.pkt); - if (err < 0) { + ret = av_read_frame(pFormatCtx_, &frame.pkt); + if (ret < 0) { frames_.pop_back(); - valid_ = (err == AVERROR_EOF); + valid_ = (ret == AVERROR_EOF); break; } // some stream seems to contian no keyframes @@ -150,17 +125,27 @@ bool FrameReader::decode(int idx, uint8_t *rgb, uint8_t *yuv) { for (int i = from_idx; i <= idx; ++i) { Frame &frame = frames_[i]; if ((!frame.decoded || i == idx) && !frame.failed) { - avcodec_decode_video2(pCodecCtx_, av_frame_, &frame.decoded, &(frame.pkt)); + frame.decoded = decodeFrame(&frame.pkt); frame.failed = !frame.decoded; if (frame.decoded && i == idx) { - return decodeFrame(av_frame_, rgb, yuv); + return copyBuffers(av_frame_, rgb, yuv); } } } return false; } -bool FrameReader::decodeFrame(AVFrame *f, uint8_t *rgb, uint8_t *yuv) { +bool FrameReader::decodeFrame(AVPacket *pkt) { + int ret = avcodec_send_packet(pCodecCtx_, pkt); + if (ret < 0) { + printf("Error sending a packet for decoding\n"); + return false; + } + ret = avcodec_receive_frame(pCodecCtx_, av_frame_); + return ret == 0; +} + +bool FrameReader::copyBuffers(AVFrame *f, uint8_t *rgb, uint8_t *yuv) { // images is going to be written to output buffers, no alignment (align = 1) if (yuv) { av_image_fill_arrays(yuv_frame_->data, yuv_frame_->linesize, yuv, AV_PIX_FMT_YUV420P, width, height, 1); diff --git a/selfdrive/ui/replay/framereader.h b/selfdrive/ui/replay/framereader.h index 2d42e135fe..1b552cd1b8 100644 --- a/selfdrive/ui/replay/framereader.h +++ b/selfdrive/ui/replay/framereader.h @@ -2,6 +2,7 @@ #include #include + #include "selfdrive/ui/replay/filereader.h" extern "C" { @@ -26,7 +27,8 @@ public: private: bool decode(int idx, uint8_t *rgb, uint8_t *yuv); - bool decodeFrame(AVFrame *f, uint8_t *rgb, uint8_t *yuv); + bool decodeFrame(AVPacket *pkt); + bool copyBuffers(AVFrame *f, uint8_t *rgb, uint8_t *yuv); struct Frame { AVPacket pkt = {};