2019-03-02 14:16:55 +00:00
|
|
|
#include "video_buffer.h"
|
|
|
|
|
2019-11-27 20:11:40 +00:00
|
|
|
#include <assert.h>
|
2019-03-02 14:16:55 +00:00
|
|
|
#include <libavutil/avutil.h>
|
|
|
|
#include <libavformat/avformat.h>
|
|
|
|
|
2019-11-24 10:53:00 +00:00
|
|
|
#include "util/log.h"
|
2019-03-02 14:16:55 +00:00
|
|
|
|
2019-03-02 22:52:22 +00:00
|
|
|
bool
|
2021-04-11 13:01:05 +00:00
|
|
|
video_buffer_init(struct video_buffer *vb) {
|
2021-02-01 08:38:11 +00:00
|
|
|
vb->pending_frame = av_frame_alloc();
|
|
|
|
if (!vb->pending_frame) {
|
2021-04-11 13:01:05 +00:00
|
|
|
return false;
|
2021-02-01 08:38:11 +00:00
|
|
|
}
|
|
|
|
|
2021-04-11 13:01:05 +00:00
|
|
|
vb->tmp_frame = av_frame_alloc();
|
|
|
|
if (!vb->tmp_frame) {
|
|
|
|
av_frame_free(&vb->pending_frame);
|
|
|
|
return false;
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2021-01-31 17:24:35 +00:00
|
|
|
bool ok = sc_mutex_init(&vb->mutex);
|
|
|
|
if (!ok) {
|
2021-04-11 13:01:05 +00:00
|
|
|
av_frame_free(&vb->pending_frame);
|
|
|
|
av_frame_free(&vb->tmp_frame);
|
|
|
|
return false;
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2021-02-19 20:16:57 +00:00
|
|
|
// there is initially no frame, so consider it has already been consumed
|
2021-02-01 08:38:11 +00:00
|
|
|
vb->pending_frame_consumed = true;
|
2019-03-02 14:16:55 +00:00
|
|
|
|
2021-02-19 21:02:36 +00:00
|
|
|
// The callbacks must be set by the consumer via
|
|
|
|
// video_buffer_set_consumer_callbacks()
|
|
|
|
vb->cbs = NULL;
|
|
|
|
|
2019-03-02 22:52:22 +00:00
|
|
|
return true;
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2019-03-02 19:09:56 +00:00
|
|
|
void
|
|
|
|
video_buffer_destroy(struct video_buffer *vb) {
|
2021-01-31 17:24:35 +00:00
|
|
|
sc_mutex_destroy(&vb->mutex);
|
2021-02-01 08:38:11 +00:00
|
|
|
av_frame_free(&vb->pending_frame);
|
2021-04-11 13:01:05 +00:00
|
|
|
av_frame_free(&vb->tmp_frame);
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2021-02-21 16:22:25 +00:00
|
|
|
static inline void
|
|
|
|
swap_frames(AVFrame **lhs, AVFrame **rhs) {
|
|
|
|
AVFrame *tmp = *lhs;
|
|
|
|
*lhs = *rhs;
|
|
|
|
*rhs = tmp;
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2021-02-19 21:02:36 +00:00
|
|
|
void
|
|
|
|
video_buffer_set_consumer_callbacks(struct video_buffer *vb,
|
|
|
|
const struct video_buffer_callbacks *cbs,
|
|
|
|
void *cbs_userdata) {
|
|
|
|
assert(!vb->cbs); // must be set only once
|
|
|
|
assert(cbs);
|
|
|
|
assert(cbs->on_frame_available);
|
|
|
|
vb->cbs = cbs;
|
|
|
|
vb->cbs_userdata = cbs_userdata;
|
|
|
|
}
|
|
|
|
|
2021-04-11 13:01:05 +00:00
|
|
|
bool
|
|
|
|
video_buffer_push(struct video_buffer *vb, const AVFrame *frame) {
|
2021-02-19 21:02:36 +00:00
|
|
|
assert(vb->cbs);
|
|
|
|
|
2021-01-31 17:24:35 +00:00
|
|
|
sc_mutex_lock(&vb->mutex);
|
2019-03-02 14:16:55 +00:00
|
|
|
|
2021-04-11 13:01:05 +00:00
|
|
|
// Use a temporary frame to preserve pending_frame in case of error.
|
|
|
|
// tmp_frame is an empty frame, no need to call av_frame_unref() beforehand.
|
|
|
|
int r = av_frame_ref(vb->tmp_frame, frame);
|
|
|
|
if (r) {
|
|
|
|
LOGE("Could not ref frame: %d", r);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that av_frame_ref() succeeded, we can replace the previous
|
|
|
|
// pending_frame
|
|
|
|
swap_frames(&vb->pending_frame, &vb->tmp_frame);
|
|
|
|
av_frame_unref(vb->tmp_frame);
|
2019-03-02 14:16:55 +00:00
|
|
|
|
2021-02-19 21:02:36 +00:00
|
|
|
bool skipped = !vb->pending_frame_consumed;
|
2021-02-01 08:38:11 +00:00
|
|
|
vb->pending_frame_consumed = false;
|
2019-03-02 14:16:55 +00:00
|
|
|
|
2021-01-31 17:24:35 +00:00
|
|
|
sc_mutex_unlock(&vb->mutex);
|
2021-02-19 21:02:36 +00:00
|
|
|
|
2021-02-23 18:59:43 +00:00
|
|
|
if (skipped) {
|
|
|
|
if (vb->cbs->on_frame_skipped)
|
|
|
|
vb->cbs->on_frame_skipped(vb, vb->cbs_userdata);
|
|
|
|
} else {
|
2021-02-19 21:02:36 +00:00
|
|
|
vb->cbs->on_frame_available(vb, vb->cbs_userdata);
|
|
|
|
}
|
2021-04-11 13:01:05 +00:00
|
|
|
|
|
|
|
return true;
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2021-04-11 13:01:05 +00:00
|
|
|
void
|
|
|
|
video_buffer_consume(struct video_buffer *vb, AVFrame *dst) {
|
2021-02-01 08:38:11 +00:00
|
|
|
sc_mutex_lock(&vb->mutex);
|
|
|
|
assert(!vb->pending_frame_consumed);
|
|
|
|
vb->pending_frame_consumed = true;
|
|
|
|
|
2021-04-11 13:01:05 +00:00
|
|
|
av_frame_move_ref(dst, vb->pending_frame);
|
|
|
|
// av_frame_move_ref() resets its source frame, so no need to call
|
|
|
|
// av_frame_unref()
|
2021-02-01 08:38:11 +00:00
|
|
|
|
|
|
|
sc_mutex_unlock(&vb->mutex);
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|