2021-07-04 10:39:03 +00:00
|
|
|
#include "frame_buffer.h"
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <libavutil/avutil.h>
|
|
|
|
#include <libavformat/avformat.h>
|
|
|
|
|
|
|
|
#include "util/log.h"
|
|
|
|
|
|
|
|
bool
|
|
|
|
sc_frame_buffer_init(struct sc_frame_buffer *fb) {
|
|
|
|
fb->pending_frame = av_frame_alloc();
|
|
|
|
if (!fb->pending_frame) {
|
2021-11-24 21:06:11 +00:00
|
|
|
LOG_OOM();
|
2021-07-04 10:39:03 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fb->tmp_frame = av_frame_alloc();
|
|
|
|
if (!fb->tmp_frame) {
|
2021-11-24 21:06:11 +00:00
|
|
|
LOG_OOM();
|
2021-07-04 10:39:03 +00:00
|
|
|
av_frame_free(&fb->pending_frame);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ok = sc_mutex_init(&fb->mutex);
|
|
|
|
if (!ok) {
|
|
|
|
av_frame_free(&fb->pending_frame);
|
|
|
|
av_frame_free(&fb->tmp_frame);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// there is initially no frame, so consider it has already been consumed
|
|
|
|
fb->pending_frame_consumed = true;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sc_frame_buffer_destroy(struct sc_frame_buffer *fb) {
|
|
|
|
sc_mutex_destroy(&fb->mutex);
|
|
|
|
av_frame_free(&fb->pending_frame);
|
|
|
|
av_frame_free(&fb->tmp_frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
swap_frames(AVFrame **lhs, AVFrame **rhs) {
|
|
|
|
AVFrame *tmp = *lhs;
|
|
|
|
*lhs = *rhs;
|
|
|
|
*rhs = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
sc_frame_buffer_push(struct sc_frame_buffer *fb, const AVFrame *frame,
|
2022-01-27 17:59:41 +00:00
|
|
|
bool *previous_frame_skipped) {
|
2021-07-04 10:39:03 +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(fb->tmp_frame, frame);
|
|
|
|
if (r) {
|
|
|
|
LOGE("Could not ref frame: %d", r);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-01-27 14:30:09 +00:00
|
|
|
sc_mutex_lock(&fb->mutex);
|
|
|
|
|
2021-07-04 10:39:03 +00:00
|
|
|
// Now that av_frame_ref() succeeded, we can replace the previous
|
|
|
|
// pending_frame
|
|
|
|
swap_frames(&fb->pending_frame, &fb->tmp_frame);
|
|
|
|
av_frame_unref(fb->tmp_frame);
|
|
|
|
|
|
|
|
if (previous_frame_skipped) {
|
|
|
|
*previous_frame_skipped = !fb->pending_frame_consumed;
|
|
|
|
}
|
|
|
|
fb->pending_frame_consumed = false;
|
|
|
|
|
|
|
|
sc_mutex_unlock(&fb->mutex);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sc_frame_buffer_consume(struct sc_frame_buffer *fb, AVFrame *dst) {
|
|
|
|
sc_mutex_lock(&fb->mutex);
|
|
|
|
assert(!fb->pending_frame_consumed);
|
|
|
|
fb->pending_frame_consumed = true;
|
|
|
|
|
|
|
|
av_frame_move_ref(dst, fb->pending_frame);
|
|
|
|
// av_frame_move_ref() resets its source frame, so no need to call
|
|
|
|
// av_frame_unref()
|
|
|
|
|
|
|
|
sc_mutex_unlock(&fb->mutex);
|
|
|
|
}
|