[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