UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
pbuf.c File Reference
#include "config.h"
#include "config_unix.h"
#include "config_win32.h"
#include <inttypes.h>
#include "debug.h"
#include "rtp/rtp.h"
#include "rtp/rtp_callback.h"
#include "rtp/ptime.h"
#include "rtp/pbuf.h"
#include "tv.h"
#include "utils/color_out.h"
#include "utils/macros.h"
Include dependency graph for pbuf.c:

Go to the source code of this file.

Classes

struct  pbuf
 
struct  pbuf_node
 

Macros

#define MOD_NAME   "[Pbuf] "
 
#define PBUF_MAGIC   0xcafebabe
 

Enumerations

enum  { DEFAULT_STATS_INTERVAL = 128 , STAT_INT_MIN_DIVISOR = sizeof(unsigned long long) * CHAR_BIT , WRAPAROUND_THRESHOLD = 900000 }
 
enum  { NUMBER_WORD_BYTES = sizeof(unsigned long long) , NUMBER_WORD_BITS = NUMBER_WORD_BYTES * CHAR_BIT }
 

Functions

static void add_coded_unit (struct pbuf_node *node, rtp_packet *pkt)
 
static void compute_longest_gap (int *longest_gap, int *accumulated_loss, unsigned long long int packets)
 
static struct pbuf_node * create_new_pnode (rtp_packet *pkt, long long playout_delay_us)
 
static int frame_complete (struct pbuf_node *frame)
 
static void free_cdata (struct coded_data *head)
 
static int get_consecutive_zeros (unsigned long long int packets) __attribute__((const))
 
int pbuf_decode (struct pbuf *playout_buf, time_ns_t curr_time, decode_frame_t decode_func, void *data)
 
void pbuf_destroy (struct pbuf *playout_buf)
 
struct pbuf * pbuf_init (volatile int *delay_ms)
 
void pbuf_insert (struct pbuf *playout_buf, rtp_packet *pkt)
 
int pbuf_is_empty (struct pbuf *playout_buf)
 
static void pbuf_process_stats (struct pbuf *playout_buf, rtp_packet *pkt)
 
void pbuf_remove (struct pbuf *playout_buf, time_ns_t curr_time)
 
void pbuf_set_playout_delay (struct pbuf *playout_buf, double playout_delay)
 
static void pbuf_validate (struct pbuf *playout_buf)
 

Macro Definition Documentation

◆ MOD_NAME

#define MOD_NAME   "[Pbuf] "

Definition at line 80 of file pbuf.c.

Referenced by pbuf_insert(), and pbuf_process_stats().

◆ PBUF_MAGIC

#define PBUF_MAGIC   0xcafebabe

Definition at line 71 of file pbuf.c.

Referenced by create_new_pnode(), and pbuf_validate().

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
DEFAULT_STATS_INTERVAL 
STAT_INT_MIN_DIVISOR 
WRAPAROUND_THRESHOLD 

Definition at line 73 of file pbuf.c.

73 {
75 STAT_INT_MIN_DIVISOR = sizeof(unsigned long long) * CHAR_BIT,
76 WRAPAROUND_THRESHOLD = 900000, // 10 sec with 90 kHz clock
77};
@ STAT_INT_MIN_DIVISOR
Definition pbuf.c:75
@ WRAPAROUND_THRESHOLD
Definition pbuf.c:76
@ DEFAULT_STATS_INTERVAL
Definition pbuf.c:74

◆ anonymous enum

anonymous enum
Enumerator
NUMBER_WORD_BYTES 
NUMBER_WORD_BITS 

Definition at line 309 of file pbuf.c.

309 {
310 NUMBER_WORD_BYTES = sizeof(unsigned long long),
312};
@ NUMBER_WORD_BITS
Definition pbuf.c:311
@ NUMBER_WORD_BYTES
Definition pbuf.c:310

Function Documentation

◆ add_coded_unit()

static void add_coded_unit ( struct pbuf_node * node,
rtp_packet * pkt )
static

Add "pkt" to the frame represented by "node". The "node" has previously been created, and has some coded data already...

New arrivals are filed to the list in descending sequence number order

Definition at line 236 of file pbuf.c.

237{
238 assert(node->rtp_timestamp == pkt->ts);
239 assert(node->cdata != NULL);
240
241 struct coded_data *tmp = (struct coded_data *) malloc(sizeof(struct coded_data));
242 if (tmp == NULL) {
243 /* this is bad, out of memory, drop the packet... */
244 free(pkt);
245 return;
246 }
247
248 tmp->seqno = pkt->seq;
249 tmp->data = pkt;
250 node->mbit |= pkt->m;
251 if((int16_t)(tmp->seqno - node->cdata->seqno) > 0){
252 tmp->prv = NULL;
253 tmp->nxt = node->cdata;
254 node->cdata->prv = tmp;
255 node->cdata = tmp;
256 } else {
257 struct coded_data *curr = node->cdata;
258 struct coded_data *prv = NULL;
259 while (curr != NULL && ((int16_t)(tmp->seqno - curr->seqno) < 0)){
260 prv = curr;
261 curr = curr->nxt;
262 }
263 if (curr == NULL) {
264 tmp->nxt = NULL;
265 tmp->prv = prv;
266 prv->nxt = tmp;
267 }else if ((int16_t)(tmp->seqno - curr->seqno) > 0){
268 tmp->nxt = curr;
269 tmp->prv = curr->prv;
270 tmp->prv->nxt = tmp;
271 curr->prv = tmp;
272 } else {
273 /* this is bad, something went terribly wrong... */
274 free(pkt);
275 free(tmp);
276 }
277 }
278}
rtp_packet * data
Definition pbuf.h:75
struct coded_data * nxt
Definition pbuf.h:72
struct coded_data * prv
Definition pbuf.h:73
uint16_t seqno
Definition pbuf.h:74
int mbit
Definition pbuf.c:91
uint32_t rtp_timestamp
Definition pbuf.c:85
struct coded_data * cdata
Definition pbuf.c:89

References pbuf_node::cdata, coded_data::data, pbuf_node::mbit, coded_data::nxt, coded_data::prv, pbuf_node::rtp_timestamp, and coded_data::seqno.

Referenced by pbuf_insert().

◆ compute_longest_gap()

static void compute_longest_gap ( int * longest_gap,
int * accumulated_loss,
unsigned long long int packets )
static

Definition at line 332 of file pbuf.c.

333{
334 *longest_gap = MAX(*longest_gap, get_consecutive_zeros(packets));
335 // trailing_zeros counts pkts missing on the beginning of pkt group, leading the opposite
336 int leading_zeros = packets == 0 ? NUMBER_WORD_BITS : __builtin_clzll(packets);
337 int trailing_zeros = packets == 0 ? NUMBER_WORD_BITS : __builtin_ctzll(packets);
338 *accumulated_loss += trailing_zeros;
339 *longest_gap = MAX(*longest_gap, *accumulated_loss);
340 if (leading_zeros < NUMBER_WORD_BITS) { // at least one packet present, reset the counter
341 *accumulated_loss = leading_zeros;
342 }
343}
#define MAX(a, b)
Definition macros.h:65
static int get_consecutive_zeros(unsigned long long int packets) __attribute__((const))
Definition pbuf.c:315

References get_consecutive_zeros(), MAX, and NUMBER_WORD_BITS.

Referenced by pbuf_process_stats().

Here is the call graph for this function:

◆ create_new_pnode()

static struct pbuf_node * create_new_pnode ( rtp_packet * pkt,
long long playout_delay_us )
static

Definition at line 280 of file pbuf.c.

281{
282 struct pbuf_node *tmp = calloc(1, sizeof(struct pbuf_node));
283 if (tmp != NULL) {
284 tmp->magic = PBUF_MAGIC;
285 tmp->rtp_timestamp = pkt->ts;
286 tmp->mbit = pkt->m;
287 tmp->playout_time =
289 tmp->playout_time += playout_delay_us * 1000;
290 tmp->deletion_time = tmp->playout_time + playout_delay_us * 1000;
291
292 tmp->cdata = (struct coded_data *) malloc(sizeof(struct coded_data));
293 if (tmp->cdata != NULL) {
294 tmp->cdata->nxt = NULL;
295 tmp->cdata->prv = NULL;
296 tmp->cdata->seqno = pkt->seq;
297 tmp->cdata->data = pkt;
298 } else {
299 free(pkt);
300 free(tmp);
301 return NULL;
302 }
303 } else {
304 free(pkt);
305 }
306 return tmp;
307}
#define PBUF_MAGIC
Definition pbuf.c:71
uint32_t magic
Definition pbuf.c:92
time_ns_t arrival_time
Definition pbuf.c:86
time_ns_t playout_time
Definition pbuf.c:87
time_ns_t deletion_time
Definition pbuf.c:88
static time_ns_t get_time_in_ns()
Definition tv.h:101

References pbuf_node::arrival_time, pbuf_node::cdata, coded_data::data, pbuf_node::deletion_time, get_time_in_ns(), pbuf_node::magic, pbuf_node::mbit, coded_data::nxt, PBUF_MAGIC, pbuf_node::playout_time, coded_data::prv, pbuf_node::rtp_timestamp, and coded_data::seqno.

Referenced by pbuf_insert().

Here is the call graph for this function:

◆ frame_complete()

static int frame_complete ( struct pbuf_node * frame)
static

Definition at line 540 of file pbuf.c.

541{
542 /* Return non-zero if the list of coded_data represents a */
543 /* complete frame of video. This might have to be passed the */
544 /* seqnum of the last packet in the previous frame, too? */
545 /* i dont think that would reflect correctly of weather this */
546 /* frame is complete or not - however we should check for all */
547 /* the packtes of a frame being present - perhaps we should */
548 /* keep a bit vector in pbuf_node? LG. */
549
550 return (frame->mbit == 1 || frame->completed == true);
551}
struct video_frame * frame

References frame.

Referenced by pbuf_decode(), and pbuf_remove().

◆ free_cdata()

static void free_cdata ( struct coded_data * head)
static

Definition at line 486 of file pbuf.c.

487{
488 struct coded_data *tmp;
489
490 while (head != NULL) {
491 free(head->data);
492 tmp = head;
493 head = head->nxt;
494 free(tmp);
495 }
496}

References coded_data::data, and coded_data::nxt.

Referenced by pbuf_destroy(), and pbuf_remove().

◆ get_consecutive_zeros()

static int get_consecutive_zeros ( unsigned long long int packets) const
static

Definition at line 315 of file pbuf.c.

316{
317 if (packets == 0) {
318 return NUMBER_WORD_BITS;
319 }
320 if (packets == ULLONG_MAX) {
321 return 0;
322 }
323
324 int longest_gap = __builtin_clzll(packets);
325 while (packets != 0) {
326 longest_gap = MAX(longest_gap, __builtin_ctzll(packets));
327 packets >>= 1;
328 }
329 return longest_gap;
330}

References MAX, and NUMBER_WORD_BITS.

Referenced by compute_longest_gap().

◆ pbuf_decode()

int pbuf_decode ( struct pbuf * playout_buf,
time_ns_t curr_time,
decode_frame_t decode_func,
void * data )

Definition at line 562 of file pbuf.c.

564{
565 /* Find the first complete frame that has reached it's playout */
566 /* time, and decode it into the framebuffer. Mark the frame as */
567 /* decoded, but otherwise leave it in the playout buffer. */
568 struct pbuf_node *curr;
569
570 pbuf_validate(playout_buf);
571
572 curr = playout_buf->frst;
573 while (curr != NULL) {
574 if (!curr->decoded
575 && curr_time > curr->playout_time
576 ) {
577 if (frame_complete(curr)) {
578 struct pbuf_stats stats = { playout_buf->received_pkts_cum,
579 playout_buf->expected_pkts_cum };
580 int ret = decode_func(curr->cdata, data, &stats);
581 curr->decoded = 1;
582 return ret;
583 } else {
584 if (curr_time > curr->playout_time + 1 * NS_IN_SEC) {
585 curr->completed = true;
586 }
588 ("Unable to decode frame due to missing data (RTP TS=%u)\n",
589 curr->rtp_timestamp);
590 }
591 }
592 curr = curr->nxt;
593 }
594 return 0;
595}
#define debug_msg(...)
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, "[pid/%d +%d %s] ", getpid(), LINE,...
Definition debug.h:92
static void pbuf_validate(struct pbuf *playout_buf)
Definition pbuf.c:121
static int frame_complete(struct pbuf_node *frame)
Definition pbuf.c:540
int decoded
Definition pbuf.c:90
struct pbuf_node * nxt
Definition pbuf.c:83
bool completed
Definition pbuf.c:93
struct pbuf_node * frst
Definition pbuf.c:97
long long int expected_pkts_cum
Definition pbuf.c:108
long long int received_pkts_cum
Definition pbuf.c:108
#define NS_IN_SEC
Definition tv.h:92

References pbuf_node::cdata, pbuf_node::completed, debug_msg, pbuf_node::decoded, pbuf::expected_pkts_cum, frame_complete(), pbuf::frst, NS_IN_SEC, pbuf_node::nxt, pbuf_validate(), pbuf_node::playout_time, pbuf::received_pkts_cum, and pbuf_node::rtp_timestamp.

Referenced by audio_receiver_thread(), ultragrid_rtp_video_rxtx::receiver_loop(), and vidcap_rtsp_thread().

Here is the call graph for this function:

◆ pbuf_destroy()

void pbuf_destroy ( struct pbuf * playout_buf)

Definition at line 195 of file pbuf.c.

195 {
196 if (playout_buf) {
197 pbuf_validate(playout_buf);
198
199 if (playout_buf->received_pkts_cum) { // print only if relevant
200 log_msg(LOG_LEVEL_INFO, "Pbuf: total %lld/%lld packets received "
201 "(%.5lf%%).\n",
202 playout_buf->received_pkts_cum,
203 playout_buf->expected_pkts_cum,
204 (double) playout_buf->received_pkts_cum /
205 playout_buf->expected_pkts_cum * 100.0);
206 }
207
208 struct pbuf_node *curr = playout_buf->frst;
209 while (curr != NULL) {
210 struct pbuf_node *temp = curr->nxt;
211 if (curr == playout_buf->frst) {
212 playout_buf->frst = curr->nxt;
213 }
214 if (curr == playout_buf->last) {
215 playout_buf->last = curr->prv;
216 }
217 if (curr->nxt != NULL) {
218 curr->nxt->prv = curr->prv;
219 }
220 if (curr->prv != NULL) {
221 curr->prv->nxt = curr->nxt;
222 }
223 free_cdata(curr->cdata);
224 free(curr);
225 curr = temp;
226 }
227 free(playout_buf);
228 }
229}
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
static void free_cdata(struct coded_data *head)
Definition pbuf.c:486
struct pbuf_node * prv
Definition pbuf.c:84
struct pbuf_node * last
Definition pbuf.c:98

References pbuf_node::cdata, pbuf::expected_pkts_cum, free_cdata(), pbuf::frst, pbuf::last, LOG_LEVEL_INFO, log_msg(), pbuf_node::nxt, pbuf_validate(), pbuf_node::prv, and pbuf::received_pkts_cum.

Referenced by pdb_destroy_item().

Here is the call graph for this function:

◆ pbuf_init()

struct pbuf * pbuf_init ( volatile int * delay_ms)

Definition at line 174 of file pbuf.c.

175{
176 struct pbuf *playout_buf = NULL;
177
178 playout_buf = (struct pbuf *) calloc(1, sizeof(struct pbuf));
179 if (playout_buf != NULL) {
180 playout_buf->frst = NULL;
181 playout_buf->last = NULL;
182 /* Playout delay... should really be adaptive, based on the */
183 /* jitter, but we use a (conservative) fixed 32ms delay for */
184 /* now (2 video frames at 60fps). */
185 playout_buf->offset_ms = delay_ms;
186 playout_buf->playout_delay_us = 0.032 * 1000 * 1000;
187 playout_buf->last_report_seq = -1;
189 } else {
190 debug_msg("Failed to allocate memory for playout buffer\n");
191 }
192 return playout_buf;
193}
Definition pbuf.c:96
int stats_interval
Definition pbuf.c:103
int last_report_seq
Definition pbuf.c:105
long long int playout_delay_us
Definition pbuf.c:99
volatile int * offset_ms
Definition pbuf.c:100

References debug_msg, DEFAULT_STATS_INTERVAL, pbuf::frst, pbuf::last, pbuf::last_report_seq, pbuf::offset_ms, pbuf::playout_delay_us, and pbuf::stats_interval.

Referenced by pdb_create_item().

◆ pbuf_insert()

void pbuf_insert ( struct pbuf * playout_buf,
rtp_packet * pkt )

Definition at line 420 of file pbuf.c.

421{
422 struct pbuf_node *tmp;
423
424 pbuf_validate(playout_buf);
425 pbuf_process_stats(playout_buf, pkt);
426
427 if (playout_buf->frst == NULL && playout_buf->last == NULL) {
428 /* playout buffer is empty - add new frame */
429 playout_buf->frst = create_new_pnode(pkt, playout_buf->playout_delay_us + 1000 * (playout_buf->offset_ms ? *playout_buf->offset_ms : 0));
430 playout_buf->last = playout_buf->frst;
431 return;
432 }
433
434 if (playout_buf->last->rtp_timestamp == pkt->ts) {
435 if (playout_buf->last->decoded) {
436 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "Late data for already decoded frame!\n");
437 }
438 /* Packet belongs to last frame in playout_buf this is the */
439 /* most likely scenario - although... */
440 add_coded_unit(playout_buf->last, pkt);
441 } else {
442 if (playout_buf->last->rtp_timestamp < pkt->ts ||
443 playout_buf->last->rtp_timestamp - pkt->ts >
444 UINT32_MAX - WRAPAROUND_THRESHOLD) {
445 /* Packet belongs to a new frame... */
446 tmp = create_new_pnode(pkt, playout_buf->playout_delay_us + 1000 * (playout_buf->offset_ms ? *playout_buf->offset_ms : 0));
447 playout_buf->last->nxt = tmp;
448 playout_buf->last->completed = true;
449 tmp->prv = playout_buf->last;
450 playout_buf->last = tmp;
451 } else {
452 bool discard_pkt = false;
453 /* Packet belongs to a previous frame... */
454 if (playout_buf->frst->rtp_timestamp > pkt->ts ||
455 pkt->ts - playout_buf->frst->rtp_timestamp >
456 UINT32_MAX - WRAPAROUND_THRESHOLD) {
457 debug_msg("A very old packet - discarded\n");
458 discard_pkt = true;
459 } else {
461 ("A packet for a previous frame, but might still be useful\n");
462 struct pbuf_node *curr = playout_buf->last;
463 while(curr != playout_buf->frst && curr->rtp_timestamp > pkt->ts){
464 curr = curr->prv;
465 }
466 if (curr->rtp_timestamp == pkt->ts) {
467 /* Packet belongs to a previous existing frame... */
468 add_coded_unit(curr, pkt);
469 } else {
470 /* Packet belongs to a frame that is not present */
471 discard_pkt = true;
472 }
473 }
474 if (discard_pkt) {
475 if (pkt->m) {
477 ("Oops... dropped packet with M bit set\n");
478 }
479 free(pkt);
480 }
481 }
482 }
483 pbuf_validate(playout_buf);
484}
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
static struct pbuf_node * create_new_pnode(rtp_packet *pkt, long long playout_delay_us)
Definition pbuf.c:280
static void add_coded_unit(struct pbuf_node *node, rtp_packet *pkt)
Definition pbuf.c:236
#define MOD_NAME
Definition pbuf.c:80
static void pbuf_process_stats(struct pbuf *playout_buf, rtp_packet *pkt)
Definition pbuf.c:345

References add_coded_unit(), pbuf_node::completed, create_new_pnode(), debug_msg, pbuf_node::decoded, pbuf::frst, pbuf::last, LOG_LEVEL_VERBOSE, log_msg(), MOD_NAME, pbuf_node::nxt, pbuf::offset_ms, pbuf_process_stats(), pbuf_validate(), pbuf::playout_delay_us, pbuf_node::prv, pbuf_node::rtp_timestamp, and WRAPAROUND_THRESHOLD.

Referenced by rtp_recv_callback().

Here is the call graph for this function:

◆ pbuf_is_empty()

int pbuf_is_empty ( struct pbuf * playout_buf)

Definition at line 553 of file pbuf.c.

554{
555 if (playout_buf->frst == NULL)
556 return TRUE;
557 else
558 return FALSE;
559}
#define TRUE
#define FALSE

References FALSE, pbuf::frst, and TRUE.

Referenced by audio_receiver_thread(), and ultragrid_rtp_video_rxtx::receiver_loop().

◆ pbuf_process_stats()

static void pbuf_process_stats ( struct pbuf * playout_buf,
rtp_packet * pkt )
inlinestatic

Definition at line 345 of file pbuf.c.

346{
347 // collect statistics
348 if (playout_buf->last_report_seq == -1) { // init
349 playout_buf->last_seq = pkt->seq - 1;
350 playout_buf->last_report_seq = pkt->seq / playout_buf->stats_interval * playout_buf->stats_interval;
351 for (uint16_t i = playout_buf->last_report_seq; i != pkt->seq; ++i) {
352 unsigned long long current_bit = 1ull << (i % NUMBER_WORD_BITS);
353 playout_buf->packets[i / NUMBER_WORD_BITS] |= current_bit;
354 }
355 }
356 unsigned long long current_bit = 1ull << (pkt->seq % NUMBER_WORD_BITS);
357 if ((playout_buf->packets[pkt->seq / NUMBER_WORD_BITS] & ~current_bit) > current_bit) {
358 playout_buf->out_of_order_pkts += 1;
359 int dist = ((pkt->seq + (1<<16U)) - playout_buf->last_seq) % (1<<16U);
360 dist = dist < 1<<15U ? dist : abs(dist - (1<<16U));
361 playout_buf->max_out_of_order_dist = MAX(playout_buf->max_out_of_order_dist, dist);
362 }
363 playout_buf->last_seq = pkt->seq;
364 if (playout_buf->packets[pkt->seq / NUMBER_WORD_BITS] & current_bit) {
365 playout_buf->dups += 1;
366 }
367 playout_buf->packets[pkt->seq / NUMBER_WORD_BITS] |= current_bit;
368 uint16_t dist = (uint16_t) (pkt->seq - playout_buf->last_report_seq);
369 if (dist >= playout_buf->stats_interval * 2 && dist < 1U<<15U) {
370 uint16_t report_seq_until = (uint16_t) ((pkt->seq / playout_buf->stats_interval * playout_buf->stats_interval) - playout_buf->stats_interval); // sum up only up to current-playout_buf->stats_interval to be able to catch out-of-order packets
371 int accumulated_loss = 0;
372 for (uint16_t i = playout_buf->last_report_seq;
373 i != report_seq_until; i += NUMBER_WORD_BITS) {
374 playout_buf->expected_pkts += NUMBER_WORD_BITS;
375 playout_buf->received_pkts += __builtin_popcountll(playout_buf->packets[i / NUMBER_WORD_BITS]);
376 compute_longest_gap(&playout_buf->longest_gap, &accumulated_loss, playout_buf->packets[i / NUMBER_WORD_BITS]);
377 playout_buf->packets[i / NUMBER_WORD_BITS] = 0;
378 }
379
380 playout_buf->received_pkts_cum += playout_buf->received_pkts;
381 playout_buf->expected_pkts_cum += playout_buf->expected_pkts;
382
383 playout_buf->last_report_seq = report_seq_until;
384 }
385
386 // print statistics after 5 seconds
387 if ((pkt->ts - playout_buf->last_display_ts) > 90000 * 5 &&
388 playout_buf->expected_pkts > 0) {
389 // print stats
390 double loss_pct = (double) playout_buf->received_pkts /
391 playout_buf->expected_pkts * 100.0;
392 char oo_dups_str[1024];
393 oo_dups_str[0] = '\0';
394 if (playout_buf->out_of_order_pkts > 0) {
395 snprintf(oo_dups_str, sizeof oo_dups_str, ", reordered %d pkts (max dist %d)", playout_buf->out_of_order_pkts, playout_buf->max_out_of_order_dist);
396 }
397 if (playout_buf->dups > 0) {
398 snprintf(oo_dups_str + strlen(oo_dups_str), sizeof oo_dups_str - strlen(oo_dups_str), ", %d dups", playout_buf->dups);
399 }
400 log_msg(LOG_LEVEL_INFO, "SSRC 0x%08" PRIx32 ": %d/%d packets received (%s%.4f%%" TERM_FG_RESET "), %d lost, max loss %d%s\n",
401 pkt->ssrc, playout_buf->received_pkts, playout_buf->expected_pkts, (loss_pct < 100.0 ? TERM_FG_RED : ""), loss_pct,
402 playout_buf->expected_pkts - playout_buf->received_pkts, playout_buf->longest_gap, oo_dups_str);
403
404 if (playout_buf->max_out_of_order_dist >= playout_buf->stats_interval) {
406 if (new_val < 1U<<14U) {
407 playout_buf->stats_interval = new_val;
408 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "Adjusting stats interval to %zu\n", new_val);
409 }
410 }
411 playout_buf->expected_pkts = playout_buf->received_pkts = 0;
412 playout_buf->last_display_ts = pkt->ts;
413 playout_buf->longest_gap = 0;
414 playout_buf->out_of_order_pkts = 0;
415 playout_buf->max_out_of_order_dist = 0;
416 playout_buf->dups = 0;
417 }
418}
#define TERM_FG_RED
Definition color_out.h:50
#define TERM_FG_RESET
Definition color_out.h:59
static __device__ vec2 abs(const vec2 &v)
Definition cuda_dxt.cu:118
static void compute_longest_gap(int *longest_gap, int *accumulated_loss, unsigned long long int packets)
Definition pbuf.c:332
int out_of_order_pkts
Definition pbuf.c:111
uint32_t last_display_ts
Definition pbuf.c:109
int dups
Definition pbuf.c:113
int longest_gap
Definition pbuf.c:110
int expected_pkts
Definition pbuf.c:107
int max_out_of_order_dist
Definition pbuf.c:112
int received_pkts
Definition pbuf.c:107
unsigned long long packets[(1<< 16)/sizeof(unsigned long long)/8]
Definition pbuf.c:104
uint16_t last_seq
Definition pbuf.c:106

References abs(), compute_longest_gap(), pbuf::dups, pbuf::expected_pkts, pbuf::expected_pkts_cum, pbuf::last_display_ts, pbuf::last_report_seq, pbuf::last_seq, LOG_LEVEL_INFO, LOG_LEVEL_VERBOSE, log_msg(), pbuf::longest_gap, MAX, pbuf::max_out_of_order_dist, MOD_NAME, NUMBER_WORD_BITS, pbuf::out_of_order_pkts, pbuf::packets, pbuf::received_pkts, pbuf::received_pkts_cum, STAT_INT_MIN_DIVISOR, pbuf::stats_interval, TERM_FG_RED, and TERM_FG_RESET.

Referenced by pbuf_insert().

Here is the call graph for this function:

◆ pbuf_remove()

void pbuf_remove ( struct pbuf * playout_buf,
time_ns_t curr_time )

Definition at line 498 of file pbuf.c.

499{
500 /* Remove previously decoded frames that have passed their playout */
501 /* time from the playout buffer. Incomplete frames that have passed */
502 /* their playout time are also discarded. */
503
504 struct pbuf_node *curr, *temp;
505
506 pbuf_validate(playout_buf);
507
508 curr = playout_buf->frst;
509 while (curr != NULL) {
510 temp = curr->nxt;
511 if (curr_time > curr->deletion_time && frame_complete(curr)) {
512 if (curr == playout_buf->frst) {
513 playout_buf->frst = curr->nxt;
514 }
515 if (curr == playout_buf->last) {
516 playout_buf->last = curr->prv;
517 }
518 if (curr->nxt != NULL) {
519 curr->nxt->prv = curr->prv;
520 }
521 if (curr->prv != NULL) {
522 curr->prv->nxt = curr->nxt;
523 }
524 free_cdata(curr->cdata);
525 free(curr);
526 } else {
527 /* The playout buffer is stored in order, so once */
528 /* we see one packet that has not yet reached it's */
529 /* playout time, we can be sure none of the others */
530 /* will have done so... */
531 break;
532 }
533 curr = temp;
534 }
535
536 pbuf_validate(playout_buf);
537 return;
538}

References pbuf_node::cdata, pbuf_node::deletion_time, frame_complete(), free_cdata(), pbuf::frst, pbuf::last, pbuf_node::nxt, pbuf_validate(), and pbuf_node::prv.

Referenced by audio_receiver_thread(), ultragrid_rtp_video_rxtx::receiver_loop(), and vidcap_rtsp_thread().

Here is the call graph for this function:

◆ pbuf_set_playout_delay()

void pbuf_set_playout_delay ( struct pbuf * playout_buf,
double playout_delay )

Definition at line 597 of file pbuf.c.

598{
599 playout_buf->playout_delay_us = playout_delay * 1000 * 1000;
600}

References pbuf::playout_delay_us.

Referenced by audio_receiver_thread(), and ultragrid_rtp_video_rxtx::receiver_process_messages().

◆ pbuf_validate()

static void pbuf_validate ( struct pbuf * playout_buf)
static

Definition at line 121 of file pbuf.c.

122{
123 /* Run through the entire playout buffer, checking pointers, etc. */
124 /* Only used in debugging mode, since it's a lot of overhead [csp] */
125#ifdef NDEF
126 struct pbuf_node *cpb, *ppb;
127 struct coded_data *ccd, *pcd;
128
129 cpb = playout_buf->frst;
130 ppb = NULL;
131 while (cpb != NULL) {
132 assert(cpb->magic == PBUF_MAGIC);
133 assert(cpb->prv == ppb);
134 if (cpb->prv != NULL) {
135 assert(cpb->prv->nxt == cpb);
136 /* stored in RTP timestamp order */
137 assert(cpb->rtp_timestamp > ppb->rtp_timestamp);
138 /* stored in playout time order */
139 /* TODO: eventually check why is this assert always failng */
140 // assert(tv_gt(cpb->ptime, ppb->ptime));
141 }
142 if (cpb->nxt != NULL) {
143 assert(cpb->nxt->prv == cpb);
144 } else {
145 assert(cpb = playout_buf->last);
146 }
147 if (cpb->cdata != NULL) {
148 /* We have coded data... check all the pointers on that list too */
149 ccd = cpb->cdata;
150 pcd = NULL;
151 while (ccd != NULL) {
152 assert(ccd->prv == pcd);
153 if (ccd->prv != NULL) {
154 assert(ccd->prv->nxt == ccd);
155 /* list is descending - cant really check this now */
156 //assert(ccd->seqno < pcd->seqno);
157 assert(ccd->data != NULL);
158 }
159 if (ccd->nxt != NULL) {
160 assert(ccd->nxt->prv == ccd);
161 }
162 pcd = ccd;
163 ccd = ccd->nxt;
164 }
165 }
166 ppb = cpb;
167 cpb = cpb->nxt;
168 }
169#else
170 UNUSED(playout_buf);
171#endif
172}
#define UNUSED(x)

References pbuf_node::cdata, coded_data::data, pbuf::frst, pbuf::last, pbuf_node::magic, coded_data::nxt, pbuf_node::nxt, PBUF_MAGIC, coded_data::prv, pbuf_node::prv, pbuf_node::rtp_timestamp, and UNUSED.

Referenced by pbuf_decode(), pbuf_destroy(), pbuf_insert(), and pbuf_remove().