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.
 
 
 
 
 
 

176 lines
4.2 KiB

#include "FrameReader.h"
#include <assert.h>
#include <unistd.h>
static int ffmpeg_lockmgr_cb(void **arg, enum AVLockOp op) {
pthread_mutex_t *mutex = (pthread_mutex_t *)*arg;
int err;
switch (op) {
case AV_LOCK_CREATE:
mutex = (pthread_mutex_t *)malloc(sizeof(*mutex));
if (!mutex)
return AVERROR(ENOMEM);
if ((err = pthread_mutex_init(mutex, NULL))) {
free(mutex);
return AVERROR(err);
}
*arg = mutex;
return 0;
case AV_LOCK_OBTAIN:
if ((err = pthread_mutex_lock(mutex)))
return AVERROR(err);
return 0;
case AV_LOCK_RELEASE:
if ((err = pthread_mutex_unlock(mutex)))
return AVERROR(err);
return 0;
case AV_LOCK_DESTROY:
if (mutex)
pthread_mutex_destroy(mutex);
free(mutex);
*arg = NULL;
return 0;
}
return 1;
}
FrameReader::FrameReader(const char *fn) {
int ret;
ret = av_lockmgr_register(ffmpeg_lockmgr_cb);
assert(ret >= 0);
avformat_network_init();
av_register_all();
snprintf(url, sizeof(url)-1,"%s",fn);
t = new std::thread([&]() { this->loaderThread(); });
}
void FrameReader::loaderThread() {
int ret;
if (avformat_open_input(&pFormatCtx, url, NULL, NULL) != 0) {
fprintf(stderr, "error loading %s\n", url);
valid = false;
return;
}
av_dump_format(pFormatCtx, 0, url, 0);
auto pCodecCtxOrig = pFormatCtx->streams[0]->codec;
auto pCodec = avcodec_find_decoder(pCodecCtxOrig->codec_id);
assert(pCodec != NULL);
pCodecCtx = avcodec_alloc_context3(pCodec);
ret = avcodec_copy_context(pCodecCtx, pCodecCtxOrig);
assert(ret == 0);
ret = avcodec_open2(pCodecCtx, pCodec, NULL);
assert(ret >= 0);
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);
AVPacket *pkt = (AVPacket *)malloc(sizeof(AVPacket));
assert(pkt != NULL);
bool first = true;
while (av_read_frame(pFormatCtx, pkt)>=0) {
//printf("%d pkt %d %d\n", pkts.size(), pkt->size, pkt->pos);
if (first) {
AVFrame *pFrame = av_frame_alloc();
int frameFinished;
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, pkt);
first = false;
}
pkts.push_back(pkt);
pkt = (AVPacket *)malloc(sizeof(AVPacket));
assert(pkt != NULL);
}
free(pkt);
printf("framereader download done\n");
joined = true;
// cache
while (1) {
GOPCache(to_cache.get());
}
}
void FrameReader::GOPCache(int idx) {
AVFrame *pFrame;
int gop = idx - idx%15;
mcache.lock();
bool has_gop = cache.find(gop) != cache.end();
mcache.unlock();
if (!has_gop) {
//printf("caching %d\n", gop);
for (int i = gop; i < gop+15; i++) {
if (i >= pkts.size()) break;
//printf("decode %d\n", i);
int frameFinished;
pFrame = av_frame_alloc();
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, pkts[i]);
uint8_t *dat = toRGB(pFrame)->data[0];
mcache.lock();
cache.insert(std::make_pair(i, dat));
mcache.unlock();
}
}
}
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) return NULL;
waitForReady();
// TODO: one line?
uint8_t *dat = NULL;
// lookahead
to_cache.put(idx);
to_cache.put(idx+15);
mcache.lock();
auto it = cache.find(idx);
if (it != cache.end()) {
dat = it->second;
}
mcache.unlock();
if (dat == NULL) {
to_cache.put_front(idx);
// lookahead
while (dat == NULL) {
// wait for frame
usleep(50*1000);
// check for frame
mcache.lock();
auto it = cache.find(idx);
if (it != cache.end()) dat = it->second;
mcache.unlock();
if (dat == NULL) {
printf(".");
fflush(stdout);
}
}
}
return dat;
}