Use VecDeque in video_buffer

The packets queued for buffering were wrapped in a dynamically allocated
structure with a "next" field.

To avoid this additional layer of allocation and indirection, use a
VecDeque.
This commit is contained in:
Romain Vimont 2023-03-01 22:21:43 +01:00
parent efc15744da
commit f25a67f342
2 changed files with 32 additions and 36 deletions

View file

@ -10,35 +10,26 @@
#define SC_BUFFERING_NDEBUG // comment to debug #define SC_BUFFERING_NDEBUG // comment to debug
static struct sc_video_buffer_frame * static bool
sc_video_buffer_frame_new(const AVFrame *frame) { sc_video_buffer_frame_init(struct sc_video_buffer_frame *vb_frame,
struct sc_video_buffer_frame *vb_frame = malloc(sizeof(*vb_frame)); const AVFrame *frame) {
if (!vb_frame) {
LOG_OOM();
return NULL;
}
vb_frame->frame = av_frame_alloc(); vb_frame->frame = av_frame_alloc();
if (!vb_frame->frame) { if (!vb_frame->frame) {
LOG_OOM(); return false;
free(vb_frame);
return NULL;
} }
if (av_frame_ref(vb_frame->frame, frame)) { if (av_frame_ref(vb_frame->frame, frame)) {
av_frame_free(&vb_frame->frame); av_frame_free(&vb_frame->frame);
free(vb_frame); return false;
return NULL;
} }
return vb_frame; return true;
} }
static void static void
sc_video_buffer_frame_delete(struct sc_video_buffer_frame *vb_frame) { sc_video_buffer_frame_destroy(struct sc_video_buffer_frame *vb_frame) {
av_frame_unref(vb_frame->frame); av_frame_unref(vb_frame->frame);
av_frame_free(&vb_frame->frame); av_frame_free(&vb_frame->frame);
free(vb_frame);
} }
static bool static bool
@ -62,7 +53,7 @@ run_buffering(void *data) {
for (;;) { for (;;) {
sc_mutex_lock(&vb->b.mutex); sc_mutex_lock(&vb->b.mutex);
while (!vb->b.stopped && sc_queue_is_empty(&vb->b.queue)) { while (!vb->b.stopped && sc_vecdeque_is_empty(&vb->b.queue)) {
sc_cond_wait(&vb->b.queue_cond, &vb->b.mutex); sc_cond_wait(&vb->b.queue_cond, &vb->b.mutex);
} }
@ -71,12 +62,11 @@ run_buffering(void *data) {
goto stopped; goto stopped;
} }
struct sc_video_buffer_frame *vb_frame; struct sc_video_buffer_frame vb_frame = sc_vecdeque_pop(&vb->b.queue);
sc_queue_take(&vb->b.queue, next, &vb_frame);
sc_tick max_deadline = sc_tick_now() + vb->buffering_time; sc_tick max_deadline = sc_tick_now() + vb->buffering_time;
// PTS (written by the server) are expressed in microseconds // PTS (written by the server) are expressed in microseconds
sc_tick pts = SC_TICK_TO_US(vb_frame->frame->pts); sc_tick pts = SC_TICK_TO_US(vb_frame.frame->pts);
bool timed_out = false; bool timed_out = false;
while (!vb->b.stopped && !timed_out) { while (!vb->b.stopped && !timed_out) {
@ -91,7 +81,7 @@ run_buffering(void *data) {
} }
if (vb->b.stopped) { if (vb->b.stopped) {
sc_video_buffer_frame_delete(vb_frame); sc_video_buffer_frame_destroy(&vb_frame);
sc_mutex_unlock(&vb->b.mutex); sc_mutex_unlock(&vb->b.mutex);
goto stopped; goto stopped;
} }
@ -100,20 +90,19 @@ run_buffering(void *data) {
#ifndef SC_BUFFERING_NDEBUG #ifndef SC_BUFFERING_NDEBUG
LOGD("Buffering: %" PRItick ";%" PRItick ";%" PRItick, LOGD("Buffering: %" PRItick ";%" PRItick ";%" PRItick,
pts, vb_frame->push_date, sc_tick_now()); pts, vb_frame.push_date, sc_tick_now());
#endif #endif
sc_video_buffer_offer(vb, vb_frame->frame); sc_video_buffer_offer(vb, vb_frame.frame);
sc_video_buffer_frame_delete(vb_frame); sc_video_buffer_frame_destroy(&vb_frame);
} }
stopped: stopped:
// Flush queue // Flush queue
while (!sc_queue_is_empty(&vb->b.queue)) { while (!sc_vecdeque_is_empty(&vb->b.queue)) {
struct sc_video_buffer_frame *vb_frame; struct sc_video_buffer_frame *p = sc_vecdeque_popref(&vb->b.queue);
sc_queue_take(&vb->b.queue, next, &vb_frame); sc_video_buffer_frame_destroy(p);
sc_video_buffer_frame_delete(vb_frame);
} }
LOGD("Buffering thread ended"); LOGD("Buffering thread ended");
@ -154,7 +143,7 @@ sc_video_buffer_init(struct sc_video_buffer *vb, sc_tick buffering_time,
} }
sc_clock_init(&vb->b.clock); sc_clock_init(&vb->b.clock);
sc_queue_init(&vb->b.queue); sc_vecdeque_init(&vb->b.queue);
} }
assert(cbs); assert(cbs);
@ -230,17 +219,25 @@ sc_video_buffer_push(struct sc_video_buffer *vb, const AVFrame *frame) {
return sc_video_buffer_offer(vb, frame); return sc_video_buffer_offer(vb, frame);
} }
struct sc_video_buffer_frame *vb_frame = sc_video_buffer_frame_new(frame); struct sc_video_buffer_frame vb_frame;
if (!vb_frame) { bool ok = sc_video_buffer_frame_init(&vb_frame, frame);
if (!ok) {
sc_mutex_unlock(&vb->b.mutex); sc_mutex_unlock(&vb->b.mutex);
LOG_OOM(); LOG_OOM();
return false; return false;
} }
#ifndef SC_BUFFERING_NDEBUG #ifndef SC_BUFFERING_NDEBUG
vb_frame->push_date = sc_tick_now(); vb_frame.push_date = sc_tick_now();
#endif #endif
sc_queue_push(&vb->b.queue, next, vb_frame);
ok = sc_vecdeque_push(&vb->b.queue, vb_frame);
if (!ok) {
sc_mutex_unlock(&vb->b.mutex);
LOG_OOM();
return false;
}
sc_cond_signal(&vb->b.queue_cond); sc_cond_signal(&vb->b.queue_cond);
sc_mutex_unlock(&vb->b.mutex); sc_mutex_unlock(&vb->b.mutex);

View file

@ -7,22 +7,21 @@
#include "clock.h" #include "clock.h"
#include "frame_buffer.h" #include "frame_buffer.h"
#include "util/queue.h"
#include "util/thread.h" #include "util/thread.h"
#include "util/tick.h" #include "util/tick.h"
#include "util/vecdeque.h"
// forward declarations // forward declarations
typedef struct AVFrame AVFrame; typedef struct AVFrame AVFrame;
struct sc_video_buffer_frame { struct sc_video_buffer_frame {
AVFrame *frame; AVFrame *frame;
struct sc_video_buffer_frame *next;
#ifndef NDEBUG #ifndef NDEBUG
sc_tick push_date; sc_tick push_date;
#endif #endif
}; };
struct sc_video_buffer_frame_queue SC_QUEUE(struct sc_video_buffer_frame); struct sc_video_buffer_frame_queue SC_VECDEQUE(struct sc_video_buffer_frame);
struct sc_video_buffer { struct sc_video_buffer {
struct sc_frame_buffer fb; struct sc_frame_buffer fb;