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-02-19 20:16:57 +00:00
|
|
|
video_buffer_init(struct video_buffer *vb, bool wait_consumer) {
|
|
|
|
vb->producer_frame = av_frame_alloc();
|
|
|
|
if (!vb->producer_frame) {
|
2019-03-02 14:16:55 +00:00
|
|
|
goto error_0;
|
|
|
|
}
|
|
|
|
|
2021-02-01 08:38:11 +00:00
|
|
|
vb->pending_frame = av_frame_alloc();
|
|
|
|
if (!vb->pending_frame) {
|
|
|
|
goto error_1;
|
|
|
|
}
|
|
|
|
|
2021-02-19 20:16:57 +00:00
|
|
|
vb->consumer_frame = av_frame_alloc();
|
|
|
|
if (!vb->consumer_frame) {
|
2021-02-01 08:38:11 +00:00
|
|
|
goto error_2;
|
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-02-01 08:38:11 +00:00
|
|
|
goto error_3;
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2021-02-19 20:16:57 +00:00
|
|
|
vb->wait_consumer = wait_consumer;
|
|
|
|
if (wait_consumer) {
|
2021-02-01 08:38:11 +00:00
|
|
|
ok = sc_cond_init(&vb->pending_frame_consumed_cond);
|
2021-01-31 17:24:35 +00:00
|
|
|
if (!ok) {
|
|
|
|
sc_mutex_destroy(&vb->mutex);
|
2019-06-05 17:02:50 +00:00
|
|
|
goto error_2;
|
|
|
|
}
|
2021-02-19 20:16:57 +00:00
|
|
|
// interrupted is not used if wait_consumer is disabled since offering
|
|
|
|
// a frame will never block
|
2019-06-05 17:02:50 +00:00
|
|
|
vb->interrupted = 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
|
|
|
|
2019-03-02 22:52:22 +00:00
|
|
|
return true;
|
2019-03-02 14:16:55 +00:00
|
|
|
|
2021-02-01 08:38:11 +00:00
|
|
|
error_3:
|
2021-02-19 20:16:57 +00:00
|
|
|
av_frame_free(&vb->consumer_frame);
|
2021-02-01 08:38:11 +00:00
|
|
|
error_2:
|
|
|
|
av_frame_free(&vb->pending_frame);
|
2019-03-02 14:16:55 +00:00
|
|
|
error_1:
|
2021-02-19 20:16:57 +00:00
|
|
|
av_frame_free(&vb->producer_frame);
|
2019-03-02 14:16:55 +00:00
|
|
|
error_0:
|
2019-03-02 22:52:22 +00:00
|
|
|
return false;
|
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-02-19 20:16:57 +00:00
|
|
|
if (vb->wait_consumer) {
|
2021-02-01 08:38:11 +00:00
|
|
|
sc_cond_destroy(&vb->pending_frame_consumed_cond);
|
2019-06-05 17:02:50 +00:00
|
|
|
}
|
2021-01-31 17:24:35 +00:00
|
|
|
sc_mutex_destroy(&vb->mutex);
|
2021-02-19 20:16:57 +00:00
|
|
|
av_frame_free(&vb->consumer_frame);
|
2021-02-01 08:38:11 +00:00
|
|
|
av_frame_free(&vb->pending_frame);
|
2021-02-19 20:16:57 +00:00
|
|
|
av_frame_free(&vb->producer_frame);
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2019-03-02 19:09:56 +00:00
|
|
|
static void
|
2021-02-19 20:16:57 +00:00
|
|
|
video_buffer_swap_producer_frame(struct video_buffer *vb) {
|
2021-01-31 17:56:50 +00:00
|
|
|
sc_mutex_assert(&vb->mutex);
|
2021-02-19 20:16:57 +00:00
|
|
|
AVFrame *tmp = vb->producer_frame;
|
|
|
|
vb->producer_frame = vb->pending_frame;
|
2021-02-01 08:38:11 +00:00
|
|
|
vb->pending_frame = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-02-19 20:16:57 +00:00
|
|
|
video_buffer_swap_consumer_frame(struct video_buffer *vb) {
|
2021-02-01 08:38:11 +00:00
|
|
|
sc_mutex_assert(&vb->mutex);
|
2021-02-19 20:16:57 +00:00
|
|
|
AVFrame *tmp = vb->consumer_frame;
|
|
|
|
vb->consumer_frame = vb->pending_frame;
|
2021-02-01 08:38:11 +00:00
|
|
|
vb->pending_frame = tmp;
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2019-03-02 23:26:48 +00:00
|
|
|
void
|
2021-02-19 20:16:57 +00:00
|
|
|
video_buffer_producer_offer_frame(struct video_buffer *vb,
|
|
|
|
bool *previous_frame_skipped) {
|
2021-01-31 17:24:35 +00:00
|
|
|
sc_mutex_lock(&vb->mutex);
|
2021-02-19 20:16:57 +00:00
|
|
|
if (vb->wait_consumer) {
|
2019-06-05 17:02:50 +00:00
|
|
|
// wait for the current (expired) frame to be consumed
|
2021-02-01 08:38:11 +00:00
|
|
|
while (!vb->pending_frame_consumed && !vb->interrupted) {
|
|
|
|
sc_cond_wait(&vb->pending_frame_consumed_cond, &vb->mutex);
|
2019-06-05 17:02:50 +00:00
|
|
|
}
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2021-02-19 20:16:57 +00:00
|
|
|
video_buffer_swap_producer_frame(vb);
|
2019-03-02 14:16:55 +00:00
|
|
|
|
2021-02-01 08:38:11 +00:00
|
|
|
*previous_frame_skipped = !vb->pending_frame_consumed;
|
|
|
|
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);
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2019-03-02 19:09:56 +00:00
|
|
|
const AVFrame *
|
2021-02-19 20:16:57 +00:00
|
|
|
video_buffer_consumer_take_frame(struct video_buffer *vb) {
|
2021-02-01 08:38:11 +00:00
|
|
|
sc_mutex_lock(&vb->mutex);
|
|
|
|
assert(!vb->pending_frame_consumed);
|
|
|
|
vb->pending_frame_consumed = true;
|
|
|
|
|
2021-02-19 20:16:57 +00:00
|
|
|
video_buffer_swap_consumer_frame(vb);
|
2021-02-01 08:38:11 +00:00
|
|
|
|
2021-02-19 20:16:57 +00:00
|
|
|
if (vb->wait_consumer) {
|
2019-06-05 17:02:50 +00:00
|
|
|
// unblock video_buffer_offer_decoded_frame()
|
2021-02-01 08:38:11 +00:00
|
|
|
sc_cond_signal(&vb->pending_frame_consumed_cond);
|
2019-06-05 17:02:50 +00:00
|
|
|
}
|
2021-02-01 08:38:11 +00:00
|
|
|
sc_mutex_unlock(&vb->mutex);
|
|
|
|
|
2021-02-19 20:16:57 +00:00
|
|
|
// consumer_frame is only written from this thread, no need to lock
|
|
|
|
return vb->consumer_frame;
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
2019-03-02 19:09:56 +00:00
|
|
|
void
|
|
|
|
video_buffer_interrupt(struct video_buffer *vb) {
|
2021-02-19 20:16:57 +00:00
|
|
|
if (vb->wait_consumer) {
|
2021-01-31 17:24:35 +00:00
|
|
|
sc_mutex_lock(&vb->mutex);
|
2019-06-05 17:02:50 +00:00
|
|
|
vb->interrupted = true;
|
2021-01-31 17:24:35 +00:00
|
|
|
sc_mutex_unlock(&vb->mutex);
|
2019-06-05 17:02:50 +00:00
|
|
|
// wake up blocking wait
|
2021-02-01 08:38:11 +00:00
|
|
|
sc_cond_signal(&vb->pending_frame_consumed_cond);
|
2019-06-05 17:02:50 +00:00
|
|
|
}
|
2019-03-02 14:16:55 +00:00
|
|
|
}
|