UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
pbuf.c
Go to the documentation of this file.
1/*
2 * AUTHOR: N.Cihan Tas
3 * MODIFIED: Ladan Gharai
4 * Colin Perkins
5 * Martin Benes <martinbenesh@gmail.com>
6 * Lukas Hejtmanek <xhejtman@ics.muni.cz>
7 * Petr Holub <hopet@ics.muni.cz>
8 * Milos Liska <xliska@fi.muni.cz>
9 * Jiri Matela <matela@ics.muni.cz>
10 * Dalibor Matura <255899@mail.muni.cz>
11 * Ian Wesley-Smith <iwsmith@cct.lsu.edu>
12 *
13 * This file implements a linked list for the playout buffer.
14 *
15 * Copyright (c) 2003-2004 University of Southern California
16 * Copyright (c) 2003-2004 University of Glasgow
17 * Copyright (c) 2005-2023 CESNET z.s.p.o.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, is permitted provided that the following conditions
21 * are met:
22 *
23 * 1. Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 *
26 * 2. Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 *
30 * 3. All advertising materials mentioning features or use of this software
31 * must display the following acknowledgement:
32 *
33 * This product includes software developed by the University of Southern
34 * California Information Sciences Institute. This product also includes
35 * software developed by CESNET z.s.p.o.
36 *
37 * 4. Neither the name of the University, Institute, CESNET nor the names of
38 * its contributors may be used to endorse or promote products derived from
39 * this software without specific prior written permission.
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
42 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
43 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
44 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
45 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
46 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
47 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
50 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
51 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
52 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 *
54 */
55
56#include "config.h"
57#include "config_unix.h"
58#include "config_win32.h"
59
60#include <inttypes.h>
61
62#include "debug.h"
63#include "rtp/rtp.h"
64#include "rtp/rtp_callback.h"
65#include "rtp/ptime.h"
66#include "rtp/pbuf.h"
67#include "tv.h"
68#include "utils/color_out.h"
69#include "utils/macros.h"
70
71#define PBUF_MAGIC 0xcafebabe
72
73enum {
75 STAT_INT_MIN_DIVISOR = sizeof(unsigned long long) * CHAR_BIT,
76 WRAPAROUND_THRESHOLD = 900000, // 10 sec with 90 kHz clock
77};
79 "STATS_INTERVAL must be divisible by (sizeof(ull) * CHAR_BIT)");
80#define MOD_NAME "[Pbuf] "
81
82struct pbuf_node {
83 struct pbuf_node *nxt;
84 struct pbuf_node *prv;
85 uint32_t rtp_timestamp; /* RTP timestamp for the frame */
86 time_ns_t arrival_time; /* Arrival time of first packet in frame */
87 time_ns_t playout_time; /* Playout time for the frame */
88 time_ns_t deletion_time; /* Deletion time for the frame */
89 struct coded_data *cdata; /* */
90 int decoded; /* Non-zero if we've decoded this frame */
91 int mbit; /* determines if mbit of frame had been seen */
92 uint32_t magic; /* For debugging */
94};
95
96struct pbuf {
97 struct pbuf_node *frst;
98 struct pbuf_node *last;
99 long long int playout_delay_us;
100 volatile int *offset_ms;
101
102 // for statistics
104 unsigned long long packets[(1<<16) / sizeof(unsigned long long) / 8];
106 uint16_t last_seq;
107 int received_pkts, expected_pkts; // currently computed values
108 long long int received_pkts_cum, expected_pkts_cum; // cumulative values
110 int longest_gap; // longest loss
113 int dups; // duplicite packets
114};
115
116static void free_cdata(struct coded_data *head);
117static int frame_complete(struct pbuf_node *frame);
118
119/*********************************************************************************/
120
121static void pbuf_validate(struct pbuf *playout_buf)
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}
173
174struct pbuf *pbuf_init(volatile int *delay_ms)
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}
194
195void pbuf_destroy(struct pbuf *playout_buf) {
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}
230
236static void add_coded_unit(struct pbuf_node *node, rtp_packet * pkt)
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}
279
280static struct pbuf_node *create_new_pnode(rtp_packet * pkt, long long playout_delay_us)
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}
308
309enum {
310 NUMBER_WORD_BYTES = sizeof(unsigned long long),
313
314static int get_consecutive_zeros(unsigned long long int packets) __attribute__((const));
315static int get_consecutive_zeros(unsigned long long int packets)
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}
331
332static void compute_longest_gap(int *longest_gap, int *accumulated_loss, unsigned long long int packets)
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}
344
345static inline void pbuf_process_stats(struct pbuf *playout_buf, rtp_packet * pkt)
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}
419
420void pbuf_insert(struct pbuf *playout_buf, rtp_packet * pkt)
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}
485
486static void free_cdata(struct coded_data *head)
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}
497
498void pbuf_remove(struct pbuf *playout_buf, time_ns_t curr_time)
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}
539
540static int frame_complete(struct pbuf_node *frame)
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}
552
553int pbuf_is_empty(struct pbuf *playout_buf)
554{
555 if (playout_buf->frst == NULL)
556 return TRUE;
557 else
558 return FALSE;
559}
560
561int
562pbuf_decode(struct pbuf *playout_buf, time_ns_t curr_time,
563 decode_frame_t decode_func, void *data)
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}
596
597void pbuf_set_playout_delay(struct pbuf *playout_buf, double playout_delay)
598{
599 playout_buf->playout_delay_us = playout_delay * 1000 * 1000;
600}
601
#define UNUSED(x)
struct video_frame * frame
#define TERM_FG_RED
Definition color_out.h:50
#define TERM_FG_RESET
Definition color_out.h:59
#define TRUE
#define FALSE
static __device__ vec2 abs(const vec2 &v)
Definition cuda_dxt.cu:118
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define debug_msg(...)
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, "[pid/%d +%d %s] ", getpid(), LINE,...
Definition debug.h:92
#define MAX(a, b)
Definition macros.h:65
#define PBUF_MAGIC
Definition pbuf.c:71
@ NUMBER_WORD_BITS
Definition pbuf.c:311
@ NUMBER_WORD_BYTES
Definition pbuf.c:310
void pbuf_destroy(struct pbuf *playout_buf)
Definition pbuf.c:195
int pbuf_decode(struct pbuf *playout_buf, time_ns_t curr_time, decode_frame_t decode_func, void *data)
Definition pbuf.c:562
static void pbuf_validate(struct pbuf *playout_buf)
Definition pbuf.c:121
static struct pbuf_node * create_new_pnode(rtp_packet *pkt, long long playout_delay_us)
Definition pbuf.c:280
void pbuf_set_playout_delay(struct pbuf *playout_buf, double playout_delay)
Definition pbuf.c:597
static void free_cdata(struct coded_data *head)
Definition pbuf.c:486
static int get_consecutive_zeros(unsigned long long int packets) __attribute__((const))
Definition pbuf.c:315
static void add_coded_unit(struct pbuf_node *node, rtp_packet *pkt)
Definition pbuf.c:236
static void compute_longest_gap(int *longest_gap, int *accumulated_loss, unsigned long long int packets)
Definition pbuf.c:332
@ STAT_INT_MIN_DIVISOR
Definition pbuf.c:75
@ WRAPAROUND_THRESHOLD
Definition pbuf.c:76
@ DEFAULT_STATS_INTERVAL
Definition pbuf.c:74
#define MOD_NAME
Definition pbuf.c:80
int pbuf_is_empty(struct pbuf *playout_buf)
Definition pbuf.c:553
void pbuf_insert(struct pbuf *playout_buf, rtp_packet *pkt)
Definition pbuf.c:420
struct pbuf * pbuf_init(volatile int *delay_ms)
Definition pbuf.c:174
void pbuf_remove(struct pbuf *playout_buf, time_ns_t curr_time)
Definition pbuf.c:498
static int frame_complete(struct pbuf_node *frame)
Definition pbuf.c:540
static void pbuf_process_stats(struct pbuf *playout_buf, rtp_packet *pkt)
Definition pbuf.c:345
int decode_frame_t(struct coded_data *cdata, void *decode_data, struct pbuf_stats *stats)
Definition pbuf.h:110
rtp_packet
Definition rtp.h:126
struct __attribute__((packed))
Definition rtp.h:88
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 magic
Definition pbuf.c:92
int decoded
Definition pbuf.c:90
time_ns_t arrival_time
Definition pbuf.c:86
uint32_t rtp_timestamp
Definition pbuf.c:85
struct pbuf_node * nxt
Definition pbuf.c:83
time_ns_t playout_time
Definition pbuf.c:87
struct pbuf_node * prv
Definition pbuf.c:84
struct coded_data * cdata
Definition pbuf.c:89
time_ns_t deletion_time
Definition pbuf.c:88
bool completed
Definition pbuf.c:93
Definition pbuf.c:96
int out_of_order_pkts
Definition pbuf.c:111
uint32_t last_display_ts
Definition pbuf.c:109
struct pbuf_node * frst
Definition pbuf.c:97
int dups
Definition pbuf.c:113
long long int expected_pkts_cum
Definition pbuf.c:108
int stats_interval
Definition pbuf.c:103
int last_report_seq
Definition pbuf.c:105
int longest_gap
Definition pbuf.c:110
int expected_pkts
Definition pbuf.c:107
int max_out_of_order_dist
Definition pbuf.c:112
struct pbuf_node * last
Definition pbuf.c:98
int received_pkts
Definition pbuf.c:107
long long int received_pkts_cum
Definition pbuf.c:108
unsigned long long packets[(1<< 16)/sizeof(unsigned long long)/8]
Definition pbuf.c:104
long long int playout_delay_us
Definition pbuf.c:99
uint16_t last_seq
Definition pbuf.c:106
volatile int * offset_ms
Definition pbuf.c:100
long long time_ns_t
Definition tv.h:81
#define NS_IN_SEC
Definition tv.h:92
static time_ns_t get_time_in_ns()
Definition tv.h:101