[NUT-devel] [nut]: r271 - in trunk/libnut: demuxer.c priv.h
ods15
subversion at mplayerhq.hu
Sat Dec 23 11:36:53 CET 2006
Author: ods15
Date: Sat Dec 23 11:36:52 2006
New Revision: 271
Modified:
trunk/libnut/demuxer.c
trunk/libnut/priv.h
Log:
queue syncpoints to a linked list to avoid CPU cache trashing during playback
Modified: trunk/libnut/demuxer.c
==============================================================================
--- trunk/libnut/demuxer.c (original)
+++ trunk/libnut/demuxer.c Sat Dec 23 11:36:52 2006
@@ -409,6 +409,30 @@
return err;
}
+static void add_existing_syncpoint(nut_context_t * nut, syncpoint_t sp, uint64_t * pts, uint64_t * eor, int i) {
+ syncpoint_list_t * sl = &nut->syncpoints;
+ int j;
+ int pts_cache = nut->dopts.cache_syncpoints & 1;
+
+ assert(sl->s[i].pos <= sp.pos && sp.pos < sl->s[i].pos + 16); // code sanity
+
+ assert(!sl->s[i].pts || sl->s[i].pts == sp.pts);
+ assert(!sl->s[i].back_ptr || sl->s[i].back_ptr == sp.back_ptr);
+ sl->s[i].pos = sp.pos;
+ sl->s[i].pts = sp.pts;
+ sl->s[i].back_ptr = sp.back_ptr;
+ if (pts_cache && sp.pts_valid) {
+ for (j = 0; j < nut->stream_count; j++) {
+ assert(!sl->s[i].pts_valid || sl->pts[i * nut->stream_count + j] == pts[j]);
+ assert(!sl->s[i].pts_valid || sl->eor[i * nut->stream_count + j] == eor[j]);
+ sl->pts[i * nut->stream_count + j] = pts[j];
+ sl->eor[i * nut->stream_count + j] = eor[j];
+ }
+ sl->s[i].pts_valid = 1;
+ }
+ if (sp.pts_valid && i) sl->s[i-1].seen_next = 1;
+}
+
static int add_syncpoint(nut_context_t * nut, syncpoint_t sp, uint64_t * pts, uint64_t * eor, int * out) {
syncpoint_list_t * sl = &nut->syncpoints;
int i, j, err = 0;
@@ -419,21 +443,7 @@
for (i = sl->len; i--; ) { // more often than not, we're adding at end of list
if (sl->s[i].pos > sp.pos) continue;
if (sp.pos < sl->s[i].pos + 16) { // syncpoint already in list
- assert(!sl->s[i].pts || sl->s[i].pts == sp.pts);
- assert(!sl->s[i].back_ptr || sl->s[i].back_ptr == sp.back_ptr);
- sl->s[i].pos = sp.pos;
- sl->s[i].pts = sp.pts;
- sl->s[i].back_ptr = sp.back_ptr;
- if (pts_cache && sp.pts_valid) {
- for (j = 0; j < nut->stream_count; j++) {
- assert(!sl->s[i].pts_valid || sl->pts[i * nut->stream_count + j] == pts[j]);
- assert(!sl->s[i].pts_valid || sl->eor[i * nut->stream_count + j] == eor[j]);
- sl->pts[i * nut->stream_count + j] = pts[j];
- sl->eor[i * nut->stream_count + j] = eor[j];
- }
- sl->s[i].pts_valid = 1;
- }
- if (sp.pts_valid && i) sl->s[i-1].seen_next = 1;
+ add_existing_syncpoint(nut, sp, pts, eor, i);
if (out) *out = i;
return 0;
}
@@ -470,6 +480,62 @@
return err;
}
+static int queue_add_syncpoint(nut_context_t * nut, syncpoint_t sp, uint64_t * pts, uint64_t * eor) {
+ syncpoint_list_t * sl = &nut->syncpoints;
+ syncpoint_linked_t * s;
+ size_t malloc_size;
+ int pts_cache = nut->dopts.cache_syncpoints & 1;
+ int err = 0;
+ int i = sl->cached_pos;
+
+ if (i >= sl->len) i = sl->len - 1;
+
+ while (sl->s[i].pos > sp.pos && i) i--;
+ while (sl->s[i+1].pos <= sp.pos && i < sl->len-1) i++;
+ // Result: sl->s[i].pos <= sp.pos < sl->s[i+1].pos
+ sl->cached_pos = i;
+
+ if (sl->s[i].pos <= sp.pos && sp.pos < sl->s[i].pos + 16) { // syncpoint already in list
+ add_existing_syncpoint(nut, sp, pts, eor, i);
+ return 0;
+ }
+
+ malloc_size = sizeof(syncpoint_linked_t) - sizeof(uint64_t);
+ if (pts_cache && sp.pts_valid) {
+ assert(pts && eor); // code sanity check
+ malloc_size += (nut->stream_count*2) * sizeof(uint64_t);
+ }
+
+ SAFE_CALLOC(nut->alloc, s, 1, malloc_size);
+
+ s->s = sp;
+ if (pts_cache && sp.pts_valid) {
+ for (i = 0; i < nut->stream_count; i++) {
+ s->pts_eor[i] = pts[i];
+ s->pts_eor[i+nut->stream_count] = eor[i];
+ }
+ }
+
+ s->prev = sl->linked;
+ sl->linked = s;
+err_out:
+ return err;
+}
+
+static int flush_syncpoint_queue(nut_context_t * nut) {
+ syncpoint_list_t * sl = &nut->syncpoints;
+ int err = 0;
+ while (sl->linked) {
+ syncpoint_linked_t * s = sl->linked;
+ CHECK(add_syncpoint(nut, s->s, s->pts_eor, s->pts_eor + nut->stream_count, NULL));
+ sl->linked = s->prev;
+ nut->alloc->free(s);
+ }
+err_out:
+ return err;
+}
+
+
static void set_global_pts(nut_context_t * nut, uint64_t pts) {
int i;
TO_PTS(timestamp, pts)
@@ -510,7 +576,10 @@
nut->sc[i].last_key = 0;
nut->sc[i].eor = 0;
}
- CHECK(add_syncpoint(nut, s, pts, eor, NULL));
+ if (nut->dopts.cache_syncpoints & 2) // during seeking, syncpoints go into cache immediately
+ CHECK(add_syncpoint(nut, s, pts, eor, NULL));
+ else // otherwise, queue to a linked list to avoid CPU cache trashing during playback
+ CHECK(queue_add_syncpoint(nut, s, pts, eor));
}
err_out:
return err;
@@ -844,6 +913,8 @@
ERROR(!(nut->dopts.cache_syncpoints & 1) || !sl->len, -1);
+ flush_syncpoint_queue(nut);
+
if (i) i--;
else {
for (i = 0; i < sl->len; i++) if (sl->s[i].pos+15 > pos) break;
@@ -1351,6 +1422,7 @@
for (i = 0; i < nut->stream_count; i++) nut->sc[i].state.pts = (uint64_t)(time_pos / TO_TB(i).nom * TO_TB(i).den);
nut->seek_time_pos = time_pos;
nut->dopts.cache_syncpoints |= 2;
+ flush_syncpoint_queue(nut);
} else {
time_pos = nut->seek_time_pos;
}
@@ -1436,6 +1508,8 @@
nut->syncpoints.s = NULL;
nut->syncpoints.pts = NULL;
nut->syncpoints.eor = NULL;
+ nut->syncpoints.cached_pos = 0;
+ nut->syncpoints.linked = NULL;
nut->sc = NULL;
nut->tb = NULL;
@@ -1490,6 +1564,11 @@
nut->alloc->free(nut->syncpoints.s);
nut->alloc->free(nut->syncpoints.pts);
nut->alloc->free(nut->syncpoints.eor);
+ while (nut->syncpoints.linked) {
+ syncpoint_linked_t * s = nut->syncpoints.linked;
+ nut->syncpoints.linked = s->prev;
+ nut->alloc->free(s);
+ }
nut->alloc->free(nut->sc);
nut->alloc->free(nut->tmp_buffer); // the caller's allocated stream list
nut->alloc->free(nut->info);
Modified: trunk/libnut/priv.h
==============================================================================
--- trunk/libnut/priv.h (original)
+++ trunk/libnut/priv.h Sat Dec 23 11:36:52 2006
@@ -75,12 +75,21 @@
unsigned int pts_valid:1;
} syncpoint_t;
+typedef struct syncpoint_linked_s syncpoint_linked_t;
+struct syncpoint_linked_s {
+ syncpoint_linked_t * prev;
+ syncpoint_t s;
+ uint64_t pts_eor[1];
+};
+
typedef struct {
int len;
int alloc_len;
syncpoint_t * s;
uint64_t * pts; // each elem is stream_count items, +1 to real pts, 0 means there is no key
uint64_t * eor; // same as pts, is the pts of last eor in syncpoint region _IF_ eor is set by syncpoint.
+ int cached_pos;
+ syncpoint_linked_t * linked; // entires are entered in reverse order for speed, points to END of list
} syncpoint_list_t;
typedef struct {
More information about the NUT-devel
mailing list