openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
3.7 KiB

#include "tools/clib/framereader.h"
5 years ago
#include <assert.h>
#include <unistd.h>
static int ffmpeg_lockmgr_cb(void **arg, enum AVLockOp op) {
std::mutex *mutex = (std::mutex *)*arg;
5 years ago
switch (op) {
case AV_LOCK_CREATE:
mutex = new std::mutex();
break;
5 years ago
case AV_LOCK_OBTAIN:
mutex->lock();
break;
5 years ago
case AV_LOCK_RELEASE:
mutex->unlock();
5 years ago
case AV_LOCK_DESTROY:
delete mutex;
break;
5 years ago
}
return 0;
5 years ago
}
FrameReader::FrameReader(const std::string &fn) : url(fn) {
int ret = av_lockmgr_register(ffmpeg_lockmgr_cb);
5 years ago
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();
}
5 years ago
void FrameReader::process() {
if (avformat_open_input(&pFormatCtx, url.c_str(), NULL, NULL) != 0) {
fprintf(stderr, "error loading %s\n", url.c_str());
5 years ago
valid = false;
return;
}
avformat_find_stream_info(pFormatCtx, NULL);
av_dump_format(pFormatCtx, 0, url.c_str(), 0);
5 years ago
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);
5 years ago
assert(ret == 0);
ret = avcodec_open2(pCodecCtx, pCodec, NULL);
assert(ret >= 0);
width = pCodecCtxOrig->width;
height = pCodecCtxOrig->height;
5 years ago
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;
5 years ago
}
Frame *frame = new Frame{.pkt = pkt};
frames.push_back(frame);
} while (true);
5 years ago
printf("framereader download done\n");
thread = std::thread(&FrameReader::decodeThread, this);
5 years ago
}
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;
5 years ago
gop = std::max(decode_idx - decode_idx % 15, 0);
decode_idx = -1;
}
5 years ago
for (int i = gop; i < std::min(gop + 15, (int)frames.size()); ++i) {
if (frames[i]->picture != nullptr) continue;
5 years ago
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();
5 years ago
}
}
}
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));
5 years ago
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);
5 years ago
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; });
5 years ago
}
return frame->picture ? frame->picture->data[0] : nullptr;
5 years ago
}