move c++ framereader to selfdrive/ui/replay (#21053)

old-commit-hash: bb5bcc7e49b8a1ae04e951ffc03848432edd8859
This commit is contained in:
Dean Lee
2021-05-28 07:00:11 +08:00
committed by GitHub
parent fa75ee24f2
commit a436b51e84
8 changed files with 5 additions and 36 deletions
-1
View File
@@ -1 +0,0 @@
cframereader.cpp
-8
View File
@@ -1,8 +0,0 @@
Import('env')
from sysconfig import get_paths
env['CPPPATH'] += [get_paths()['include']]
from Cython.Build import cythonize
cythonize("cframereader.pyx")
env.SharedLibrary(File('cframereader.so'), ['cframereader.cpp', 'framereader.cc'], LIBS=['avformat', 'avcodec', 'avutil', 'swscale'])
-20
View File
@@ -1,20 +0,0 @@
# distutils: language = c++
# cython: language_level=3
cdef extern from "framereader.h":
cdef cppclass CFrameReader "FrameReader":
CFrameReader(const char *)
char *get(int)
cdef class FrameReader():
cdef CFrameReader *fr
def __cinit__(self, fn):
self.fr = new CFrameReader(fn)
def __dealloc__(self):
del self.fr
def get(self, idx):
self.fr.get(idx)
-141
View File
@@ -1,141 +0,0 @@
#include "tools/clib/framereader.h"
#include <assert.h>
#include <unistd.h>
static 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;
}
FrameReader::FrameReader(const std::string &fn) : url(fn) {
int ret = av_lockmgr_register(ffmpeg_lockmgr_cb);
assert(ret >= 0);
avformat_network_init();
av_register_all();
}
FrameReader::~FrameReader() {
exit_ = true;
thread.join();
for (auto &f : frames) {
delete f->pkt;
if (f->picture) {
av_frame_free(&f->picture);
}
delete f;
}
avcodec_free_context(&pCodecCtx);
avformat_free_context(pFormatCtx);
sws_freeContext(sws_ctx);
avformat_network_deinit();
}
void FrameReader::process() {
if (avformat_open_input(&pFormatCtx, url.c_str(), NULL, NULL) != 0) {
fprintf(stderr, "error loading %s\n", url.c_str());
valid = false;
return;
}
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);
assert(pCodec != NULL);
pCodecCtx = avcodec_alloc_context3(pCodec);
int ret = avcodec_copy_context(pCodecCtx, pCodecCtxOrig);
assert(ret == 0);
ret = avcodec_open2(pCodecCtx, pCodec, NULL);
assert(ret >= 0);
width = pCodecCtxOrig->width;
height = pCodecCtxOrig->height;
sws_ctx = sws_getContext(width, height, AV_PIX_FMT_YUV420P,
width, height, AV_PIX_FMT_BGR24,
SWS_BILINEAR, NULL, NULL, NULL);
assert(sws_ctx != NULL);
do {
AVPacket *pkt = new AVPacket;
if (av_read_frame(pFormatCtx, pkt) < 0) {
delete pkt;
break;
}
Frame *frame = new Frame{.pkt = pkt};
frames.push_back(frame);
} while (true);
printf("framereader download done\n");
thread = std::thread(&FrameReader::decodeThread, this);
}
void FrameReader::decodeThread() {
while (!exit_) {
int gop = 0;
{
std::unique_lock lk(mutex);
cv_decode.wait(lk, [=] { return exit_ || decode_idx != -1; });
if (exit_) break;
gop = std::max(decode_idx - decode_idx % 15, 0);
decode_idx = -1;
}
for (int i = gop; i < std::min(gop + 15, (int)frames.size()); ++i) {
if (frames[i]->picture != nullptr) continue;
int frameFinished;
AVFrame *pFrame = av_frame_alloc();
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, frames[i]->pkt);
AVFrame *picture = toRGB(pFrame);
av_frame_free(&pFrame);
std::unique_lock lk(mutex);
frames[i]->picture = picture;
cv_frame.notify_all();
}
}
}
AVFrame *FrameReader::toRGB(AVFrame *pFrame) {
AVFrame *pFrameRGB = av_frame_alloc();
int numBytes = avpicture_get_size(AV_PIX_FMT_BGR24, pFrame->width, pFrame->height);
uint8_t *buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_BGR24, pFrame->width, pFrame->height);
sws_scale(sws_ctx, (uint8_t const *const *)pFrame->data,
pFrame->linesize, 0, pFrame->height,
pFrameRGB->data, pFrameRGB->linesize);
return pFrameRGB;
}
uint8_t *FrameReader::get(int idx) {
if (!valid || idx < 0 || idx >= frames.size()) return nullptr;
std::unique_lock lk(mutex);
decode_idx = idx;
cv_decode.notify_one();
Frame *frame = frames[idx];
if (!frame->picture) {
cv_frame.wait(lk, [=] { return exit_ || frame->picture != nullptr; });
}
return frame->picture ? frame->picture->data[0] : nullptr;
}
-53
View File
@@ -1,53 +0,0 @@
#pragma once
#include <unistd.h>
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
// independent of QT, needs ffmpeg
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
class FrameReader {
public:
FrameReader(const std::string &fn);
~FrameReader();
uint8_t *get(int idx);
AVFrame *toRGB(AVFrame *);
int getRGBSize() { return width*height*3; }
void process();
int width = 0, height = 0;
private:
void decodeThread();
struct Frame{
AVPacket *pkt;
AVFrame *picture;
};
std::vector<Frame*> frames;
AVFormatContext *pFormatCtx = NULL;
AVCodecContext *pCodecCtx = NULL;
struct SwsContext *sws_ctx = NULL;
std::mutex mutex;
std::condition_variable cv_decode;
std::condition_variable cv_frame;
int decode_idx = -1;
std::atomic<bool> exit_ = false;
std::thread thread;
bool valid = true;
std::string url;
};